From 7081ebf561353d5d5dc8f8c445b870baa241db54 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Tue, 26 Nov 2024 11:32:26 -0800 Subject: [PATCH 01/72] PKG -- [transport-http] Create SubscriptionManager and subscribe function (#2019) --- package-lock.json | 105 +++--- packages/transport-http/package.json | 14 +- packages/transport-http/src/index.ts | 17 + packages/transport-http/src/sdk-send-http.ts | 16 - .../src/{ => send}/combine-urls.test.ts | 0 .../src/{ => send}/combine-urls.ts | 0 .../connect-subscribe-events.test.ts | 0 .../{ => send}/connect-subscribe-events.ts | 0 .../src/{ => send}/connect-ws.test.ts | 2 +- .../src/{ => send}/connect-ws.ts | 2 +- .../src/{ => send}/http-request.js | 0 .../src/{ => send}/http-request.test.js | 0 .../src/{ => send}/send-execute-script.js | 0 .../{ => send}/send-execute-script.test.js | 0 .../src/{ => send}/send-get-account.js | 0 .../src/{ => send}/send-get-account.test.js | 0 .../src/{ => send}/send-get-block-header.js | 0 .../{ => send}/send-get-block-header.test.js | 0 .../src/{ => send}/send-get-block.js | 0 .../src/{ => send}/send-get-block.test.js | 0 .../src/{ => send}/send-get-collection.js | 0 .../{ => send}/send-get-collection.test.js | 0 .../src/{ => send}/send-get-events.js | 0 .../src/{ => send}/send-get-events.test.js | 0 .../{ => send}/send-get-network-parameters.js | 0 .../send-get-network-parameters.test.js | 0 .../send-get-node-version-info.test.ts | 0 .../{ => send}/send-get-node-version-info.ts | 0 .../{ => send}/send-get-transaction-status.js | 0 .../send-get-transaction-status.test.js | 0 .../src/{ => send}/send-get-transaction.js | 0 .../{ => send}/send-get-transaction.test.js | 0 .../src/{ => send}/send-http.ts | 2 +- .../src/{ => send}/send-ping.test.ts | 0 .../src/{ => send}/send-ping.ts | 0 .../src/{ => send}/send-transaction.js | 0 .../src/{ => send}/send-transaction.test.js | 0 .../transport-http/src/{ => send}/utils.js | 0 .../transport-http/src/subscribe/models.ts | 66 ++++ .../transport-http/src/subscribe/subscribe.ts | 34 ++ .../subscribe/subscription-manager.test.ts | 260 ++++++++++++++ .../src/subscribe/subscription-manager.ts | 317 ++++++++++++++++++ .../src/{ => subscribe}/websocket.ts | 5 +- packages/transport-http/src/transport.ts | 8 + packages/typedefs/src/index.ts | 1 + packages/typedefs/src/sdk-transport/index.ts | 10 + .../typedefs/src/sdk-transport/requests.ts | 85 +++++ .../src/sdk-transport/subscriptions.ts | 37 ++ 48 files changed, 912 insertions(+), 69 deletions(-) create mode 100644 packages/transport-http/src/index.ts delete mode 100644 packages/transport-http/src/sdk-send-http.ts rename packages/transport-http/src/{ => send}/combine-urls.test.ts (100%) rename packages/transport-http/src/{ => send}/combine-urls.ts (100%) rename packages/transport-http/src/{ => send}/connect-subscribe-events.test.ts (100%) rename packages/transport-http/src/{ => send}/connect-subscribe-events.ts (100%) rename packages/transport-http/src/{ => send}/connect-ws.test.ts (99%) rename packages/transport-http/src/{ => send}/connect-ws.ts (98%) rename packages/transport-http/src/{ => send}/http-request.js (100%) rename packages/transport-http/src/{ => send}/http-request.test.js (100%) rename packages/transport-http/src/{ => send}/send-execute-script.js (100%) rename packages/transport-http/src/{ => send}/send-execute-script.test.js (100%) rename packages/transport-http/src/{ => send}/send-get-account.js (100%) rename packages/transport-http/src/{ => send}/send-get-account.test.js (100%) rename packages/transport-http/src/{ => send}/send-get-block-header.js (100%) rename packages/transport-http/src/{ => send}/send-get-block-header.test.js (100%) rename packages/transport-http/src/{ => send}/send-get-block.js (100%) rename packages/transport-http/src/{ => send}/send-get-block.test.js (100%) rename packages/transport-http/src/{ => send}/send-get-collection.js (100%) rename packages/transport-http/src/{ => send}/send-get-collection.test.js (100%) rename packages/transport-http/src/{ => send}/send-get-events.js (100%) rename packages/transport-http/src/{ => send}/send-get-events.test.js (100%) rename packages/transport-http/src/{ => send}/send-get-network-parameters.js (100%) rename packages/transport-http/src/{ => send}/send-get-network-parameters.test.js (100%) rename packages/transport-http/src/{ => send}/send-get-node-version-info.test.ts (100%) rename packages/transport-http/src/{ => send}/send-get-node-version-info.ts (100%) rename packages/transport-http/src/{ => send}/send-get-transaction-status.js (100%) rename packages/transport-http/src/{ => send}/send-get-transaction-status.test.js (100%) rename packages/transport-http/src/{ => send}/send-get-transaction.js (100%) rename packages/transport-http/src/{ => send}/send-get-transaction.test.js (100%) rename packages/transport-http/src/{ => send}/send-http.ts (98%) rename packages/transport-http/src/{ => send}/send-ping.test.ts (100%) rename packages/transport-http/src/{ => send}/send-ping.ts (100%) rename packages/transport-http/src/{ => send}/send-transaction.js (100%) rename packages/transport-http/src/{ => send}/send-transaction.test.js (100%) rename packages/transport-http/src/{ => send}/utils.js (100%) create mode 100644 packages/transport-http/src/subscribe/models.ts create mode 100644 packages/transport-http/src/subscribe/subscribe.ts create mode 100644 packages/transport-http/src/subscribe/subscription-manager.test.ts create mode 100644 packages/transport-http/src/subscribe/subscription-manager.ts rename packages/transport-http/src/{ => subscribe}/websocket.ts (58%) create mode 100644 packages/transport-http/src/transport.ts create mode 100644 packages/typedefs/src/sdk-transport/index.ts create mode 100644 packages/typedefs/src/sdk-transport/requests.ts create mode 100644 packages/typedefs/src/sdk-transport/subscriptions.ts diff --git a/package-lock.json b/package-lock.json index 641745064..066cef7fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18893,6 +18893,16 @@ "node": ">=8" } }, + "node_modules/jest-websocket-mock": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/jest-websocket-mock/-/jest-websocket-mock-2.5.0.tgz", + "integrity": "sha512-a+UJGfowNIWvtIKIQBHoEWIUqRxxQHFx4CXT+R5KxxKBtEQ5rS3pPOV/5299sHzqbmeCzxxY5qE4+yfXePePig==", + "dev": true, + "dependencies": { + "jest-diff": "^29.2.0", + "mock-socket": "^9.3.0" + } + }, "node_modules/jest-worker": { "version": "29.7.0", "dev": true, @@ -21658,6 +21668,15 @@ "ufo": "^1.5.4" } }, + "node_modules/mock-socket": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz", + "integrity": "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/modify-values": { "version": "1.0.1", "dev": true, @@ -29023,7 +29042,7 @@ }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", @@ -29048,16 +29067,16 @@ }, "packages/fcl": { "name": "@onflow/fcl", - "version": "1.13.0-alpha.6", + "version": "1.13.0-alpha.7", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.1-alpha.0", - "@onflow/fcl-core": "1.13.0-alpha.4", - "@onflow/fcl-wc": "5.4.1-alpha.4", + "@onflow/fcl-core": "1.13.0-alpha.5", + "@onflow/fcl-wc": "5.5.0-alpha.5", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3-alpha.0", - "@onflow/sdk": "1.5.4-alpha.1", + "@onflow/sdk": "1.5.4-alpha.2", "@onflow/types": "1.4.1-alpha.0", "@onflow/util-actor": "1.3.4-alpha.0", "@onflow/util-address": "1.2.3-alpha.0", @@ -29074,8 +29093,8 @@ "sha3": "^2.1.4" }, "devDependencies": { - "@onflow/fcl-bundle": "1.5.1-alpha.0", - "@onflow/typedefs": "1.4.0-alpha.1", + "@onflow/fcl-bundle": "1.6.0-alpha.1", + "@onflow/typedefs": "1.4.0-alpha.2", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -29088,7 +29107,7 @@ }, "packages/fcl-bundle": { "name": "@onflow/fcl-bundle", - "version": "1.5.1-alpha.0", + "version": "1.6.0-alpha.1", "license": "Apache-2.0", "dependencies": { "@babel/plugin-transform-runtime": "^7.25.7", @@ -29122,7 +29141,7 @@ }, "packages/fcl-core": { "name": "@onflow/fcl-core", - "version": "1.13.0-alpha.4", + "version": "1.13.0-alpha.5", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -29130,7 +29149,7 @@ "@onflow/config": "1.5.1-alpha.0", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3-alpha.0", - "@onflow/sdk": "1.5.4-alpha.1", + "@onflow/sdk": "1.5.4-alpha.2", "@onflow/transport-http": "1.10.3-alpha.0", "@onflow/types": "1.4.1-alpha.0", "@onflow/util-actor": "1.3.4-alpha.0", @@ -29144,8 +29163,8 @@ "cross-fetch": "^3.1.8" }, "devDependencies": { - "@onflow/fcl-bundle": "1.5.1-alpha.0", - "@onflow/typedefs": "1.4.0-alpha.1", + "@onflow/fcl-bundle": "1.6.0-alpha.1", + "@onflow/typedefs": "1.4.0-alpha.2", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -29170,15 +29189,15 @@ }, "packages/fcl-react-native": { "name": "@onflow/fcl-react-native", - "version": "1.9.7-alpha.4", + "version": "1.9.7-alpha.5", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.1-alpha.0", - "@onflow/fcl-core": "1.13.0-alpha.4", + "@onflow/fcl-core": "1.13.0-alpha.5", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3-alpha.0", - "@onflow/sdk": "1.5.4-alpha.1", + "@onflow/sdk": "1.5.4-alpha.2", "@onflow/types": "1.4.1-alpha.0", "@onflow/util-actor": "1.3.4-alpha.0", "@onflow/util-address": "1.2.3-alpha.0", @@ -29190,8 +29209,8 @@ "cross-fetch": "^3.1.8" }, "devDependencies": { - "@onflow/fcl-bundle": "1.5.1-alpha.0", - "@onflow/typedefs": "1.4.0-alpha.1", + "@onflow/fcl-bundle": "1.6.0-alpha.1", + "@onflow/typedefs": "1.4.0-alpha.2", "@types/estree": "^1.0.6", "@types/node": "^18.19.57", "eslint": "^8.57.1", @@ -29222,7 +29241,7 @@ }, "packages/fcl-wc": { "name": "@onflow/fcl-wc", - "version": "5.4.1-alpha.4", + "version": "5.5.0-alpha.5", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -29241,8 +29260,8 @@ "devDependencies": { "@babel/plugin-transform-react-jsx": "^7.25.9", "@babel/preset-typescript": "^7.25.7", - "@onflow/fcl-bundle": "1.5.1-alpha.0", - "@onflow/typedefs": "^1.4.0-alpha.1", + "@onflow/fcl-bundle": "1.6.0-alpha.1", + "@onflow/typedefs": "^1.4.0-alpha.2", "autoprefixer": "^10.4.20", "eslint": "^8.57.1", "eslint-plugin-jsdoc": "^46.10.1", @@ -29250,7 +29269,7 @@ "jest-preset-preact": "^4.1.1" }, "peerDependencies": { - "@onflow/fcl-core": "1.13.0-alpha.4" + "@onflow/fcl-core": "1.13.0-alpha.5" } }, "packages/fcl/node_modules/typescript": { @@ -29322,7 +29341,7 @@ }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -29333,14 +29352,14 @@ }, "packages/sdk": { "name": "@onflow/sdk", - "version": "1.5.4-alpha.1", + "version": "1.5.4-alpha.2", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.1-alpha.0", "@onflow/rlp": "1.2.3-alpha.0", "@onflow/transport-http": "1.10.3-alpha.0", - "@onflow/typedefs": "1.4.0-alpha.1", + "@onflow/typedefs": "1.4.0-alpha.2", "@onflow/util-actor": "1.3.4-alpha.0", "@onflow/util-address": "1.2.3-alpha.0", "@onflow/util-invariant": "1.2.4-alpha.0", @@ -29352,7 +29371,7 @@ "uuid": "^9.0.1" }, "devDependencies": { - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "@types/uuid": "^9.0.8", "eslint": "^8.57.1", "eslint-plugin-jsdoc": "^46.10.1", @@ -29387,8 +29406,8 @@ "@onflow/util-template": "1.2.3-alpha.0" }, "devDependencies": { - "@onflow/fcl-bundle": "1.5.1-alpha.0", - "@onflow/sdk": "1.5.4-alpha.1", + "@onflow/fcl-bundle": "1.6.0-alpha.1", + "@onflow/sdk": "1.5.4-alpha.2", "jest": "^29.7.0" } }, @@ -29409,22 +29428,24 @@ "ws": "^8.18.0" }, "devDependencies": { - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "@onflow/rlp": "1.2.3-alpha.0", - "@onflow/sdk": "1.5.4-alpha.1", + "@onflow/sdk": "1.5.4-alpha.2", "@onflow/types": "1.4.1-alpha.0", - "jest": "^29.7.0" + "jest": "^29.7.0", + "jest-websocket-mock": "^2.5.0", + "mock-socket": "^9.3.1" } }, "packages/typedefs": { "name": "@onflow/typedefs", - "version": "1.4.0-alpha.1", + "version": "1.4.0-alpha.2", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7" }, "devDependencies": { - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "@types/node": "^18.19.57", "eslint": "^8.57.1", "eslint-plugin-jsdoc": "^46.10.1", @@ -29455,7 +29476,7 @@ }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -29474,7 +29495,7 @@ }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -29492,7 +29513,7 @@ }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "@onflow/types": "1.4.1-alpha.0", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -29527,7 +29548,7 @@ }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "@onflow/types": "1.4.1-alpha.0", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -29560,7 +29581,7 @@ }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "@onflow/types": "1.4.1-alpha.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", @@ -29579,7 +29600,7 @@ }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -29605,7 +29626,7 @@ }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -29622,7 +29643,7 @@ "@babel/runtime": "^7.25.7" }, "devDependencies": { - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "jest": "^29.7.0" } }, @@ -29636,7 +29657,7 @@ }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -29654,7 +29675,7 @@ }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", - "@onflow/fcl-bundle": "1.5.1-alpha.0", + "@onflow/fcl-bundle": "1.6.0-alpha.1", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", diff --git a/packages/transport-http/package.json b/packages/transport-http/package.json index 4cca54899..49a31549e 100644 --- a/packages/transport-http/package.json +++ b/packages/transport-http/package.json @@ -17,13 +17,15 @@ "@onflow/rlp": "1.2.3-alpha.0", "@onflow/sdk": "1.5.4-alpha.2", "@onflow/types": "1.4.1-alpha.0", - "jest": "^29.7.0" + "jest": "^29.7.0", + "jest-websocket-mock": "^2.5.0", + "mock-socket": "^9.3.1" }, - "source": "src/sdk-send-http.ts", - "main": "dist/sdk-send-http.js", - "module": "dist/sdk-send-http.module.js", - "unpkg": "dist/sdk-send-http.umd.js", - "types": "types/sdk-send-http.d.ts", + "source": "src/index.ts", + "main": "dist/index.js", + "module": "dist/index.module.js", + "unpkg": "dist/index.umd.js", + "types": "types/index.d.ts", "scripts": { "alpha": "npm publish --tag alpha", "prepublishOnly": "npm test && npm run build", diff --git a/packages/transport-http/src/index.ts b/packages/transport-http/src/index.ts new file mode 100644 index 000000000..bbabf100b --- /dev/null +++ b/packages/transport-http/src/index.ts @@ -0,0 +1,17 @@ +export {sendExecuteScript} from "./send/send-execute-script" +export {sendGetAccount} from "./send/send-get-account" +export {sendGetBlockHeader} from "./send/send-get-block-header" +export {sendGetBlock} from "./send/send-get-block" +export {sendGetCollection} from "./send/send-get-collection" +export {sendGetEvents} from "./send/send-get-events" +export {sendGetTransaction} from "./send/send-get-transaction" +export {sendGetTransactionStatus} from "./send/send-get-transaction-status" +export {sendPing} from "./send/send-ping" +export {sendTransaction} from "./send/send-transaction" +export {sendGetNetworkParameters} from "./send/send-get-network-parameters" +export {sendGetNodeVersionInfo} from "./send/send-get-node-version-info" +export {connectSubscribeEvents} from "./send/connect-subscribe-events" +export {send} from "./send/send-http" +export {WebsocketError} from "./send/connect-ws" +export {HTTPRequestError} from "./send/http-request.js" +export {httpTransport} from "./transport" diff --git a/packages/transport-http/src/sdk-send-http.ts b/packages/transport-http/src/sdk-send-http.ts deleted file mode 100644 index 08a5f76df..000000000 --- a/packages/transport-http/src/sdk-send-http.ts +++ /dev/null @@ -1,16 +0,0 @@ -export {sendExecuteScript} from "./send-execute-script" -export {sendGetAccount} from "./send-get-account" -export {sendGetBlockHeader} from "./send-get-block-header" -export {sendGetBlock} from "./send-get-block" -export {sendGetCollection} from "./send-get-collection" -export {sendGetEvents} from "./send-get-events" -export {sendGetTransaction} from "./send-get-transaction" -export {sendGetTransactionStatus} from "./send-get-transaction-status" -export {sendPing} from "./send-ping" -export {sendTransaction} from "./send-transaction" -export {sendGetNetworkParameters} from "./send-get-network-parameters" -export {sendGetNodeVersionInfo} from "./send-get-node-version-info" -export {connectSubscribeEvents} from "./connect-subscribe-events" -export {send} from "./send-http" -export {WebsocketError} from "./connect-ws" -export {HTTPRequestError} from "./http-request.js" diff --git a/packages/transport-http/src/combine-urls.test.ts b/packages/transport-http/src/send/combine-urls.test.ts similarity index 100% rename from packages/transport-http/src/combine-urls.test.ts rename to packages/transport-http/src/send/combine-urls.test.ts diff --git a/packages/transport-http/src/combine-urls.ts b/packages/transport-http/src/send/combine-urls.ts similarity index 100% rename from packages/transport-http/src/combine-urls.ts rename to packages/transport-http/src/send/combine-urls.ts diff --git a/packages/transport-http/src/connect-subscribe-events.test.ts b/packages/transport-http/src/send/connect-subscribe-events.test.ts similarity index 100% rename from packages/transport-http/src/connect-subscribe-events.test.ts rename to packages/transport-http/src/send/connect-subscribe-events.test.ts diff --git a/packages/transport-http/src/connect-subscribe-events.ts b/packages/transport-http/src/send/connect-subscribe-events.ts similarity index 100% rename from packages/transport-http/src/connect-subscribe-events.ts rename to packages/transport-http/src/send/connect-subscribe-events.ts diff --git a/packages/transport-http/src/connect-ws.test.ts b/packages/transport-http/src/send/connect-ws.test.ts similarity index 99% rename from packages/transport-http/src/connect-ws.test.ts rename to packages/transport-http/src/send/connect-ws.test.ts index a7218e9a1..c2cc19948 100644 --- a/packages/transport-http/src/connect-ws.test.ts +++ b/packages/transport-http/src/send/connect-ws.test.ts @@ -1,5 +1,5 @@ import {buildConnectionUrl, connectWs} from "./connect-ws" -import * as WebSocketModule from "./websocket" +import * as WebSocketModule from "../subscribe/websocket" describe("connectWs", () => { describe("buildConnectionUrl", () => { diff --git a/packages/transport-http/src/connect-ws.ts b/packages/transport-http/src/send/connect-ws.ts similarity index 98% rename from packages/transport-http/src/connect-ws.ts rename to packages/transport-http/src/send/connect-ws.ts index b9f373791..a58d6c672 100644 --- a/packages/transport-http/src/connect-ws.ts +++ b/packages/transport-http/src/send/connect-ws.ts @@ -1,7 +1,7 @@ import {EventEmitter} from "events" import {safeParseJSON} from "./utils" import {StreamConnection} from "@onflow/typedefs" -import {WebSocket} from "./websocket" +import {WebSocket} from "../subscribe/websocket" export class WebsocketError extends Error { code?: number diff --git a/packages/transport-http/src/http-request.js b/packages/transport-http/src/send/http-request.js similarity index 100% rename from packages/transport-http/src/http-request.js rename to packages/transport-http/src/send/http-request.js diff --git a/packages/transport-http/src/http-request.test.js b/packages/transport-http/src/send/http-request.test.js similarity index 100% rename from packages/transport-http/src/http-request.test.js rename to packages/transport-http/src/send/http-request.test.js diff --git a/packages/transport-http/src/send-execute-script.js b/packages/transport-http/src/send/send-execute-script.js similarity index 100% rename from packages/transport-http/src/send-execute-script.js rename to packages/transport-http/src/send/send-execute-script.js diff --git a/packages/transport-http/src/send-execute-script.test.js b/packages/transport-http/src/send/send-execute-script.test.js similarity index 100% rename from packages/transport-http/src/send-execute-script.test.js rename to packages/transport-http/src/send/send-execute-script.test.js diff --git a/packages/transport-http/src/send-get-account.js b/packages/transport-http/src/send/send-get-account.js similarity index 100% rename from packages/transport-http/src/send-get-account.js rename to packages/transport-http/src/send/send-get-account.js diff --git a/packages/transport-http/src/send-get-account.test.js b/packages/transport-http/src/send/send-get-account.test.js similarity index 100% rename from packages/transport-http/src/send-get-account.test.js rename to packages/transport-http/src/send/send-get-account.test.js diff --git a/packages/transport-http/src/send-get-block-header.js b/packages/transport-http/src/send/send-get-block-header.js similarity index 100% rename from packages/transport-http/src/send-get-block-header.js rename to packages/transport-http/src/send/send-get-block-header.js diff --git a/packages/transport-http/src/send-get-block-header.test.js b/packages/transport-http/src/send/send-get-block-header.test.js similarity index 100% rename from packages/transport-http/src/send-get-block-header.test.js rename to packages/transport-http/src/send/send-get-block-header.test.js diff --git a/packages/transport-http/src/send-get-block.js b/packages/transport-http/src/send/send-get-block.js similarity index 100% rename from packages/transport-http/src/send-get-block.js rename to packages/transport-http/src/send/send-get-block.js diff --git a/packages/transport-http/src/send-get-block.test.js b/packages/transport-http/src/send/send-get-block.test.js similarity index 100% rename from packages/transport-http/src/send-get-block.test.js rename to packages/transport-http/src/send/send-get-block.test.js diff --git a/packages/transport-http/src/send-get-collection.js b/packages/transport-http/src/send/send-get-collection.js similarity index 100% rename from packages/transport-http/src/send-get-collection.js rename to packages/transport-http/src/send/send-get-collection.js diff --git a/packages/transport-http/src/send-get-collection.test.js b/packages/transport-http/src/send/send-get-collection.test.js similarity index 100% rename from packages/transport-http/src/send-get-collection.test.js rename to packages/transport-http/src/send/send-get-collection.test.js diff --git a/packages/transport-http/src/send-get-events.js b/packages/transport-http/src/send/send-get-events.js similarity index 100% rename from packages/transport-http/src/send-get-events.js rename to packages/transport-http/src/send/send-get-events.js diff --git a/packages/transport-http/src/send-get-events.test.js b/packages/transport-http/src/send/send-get-events.test.js similarity index 100% rename from packages/transport-http/src/send-get-events.test.js rename to packages/transport-http/src/send/send-get-events.test.js diff --git a/packages/transport-http/src/send-get-network-parameters.js b/packages/transport-http/src/send/send-get-network-parameters.js similarity index 100% rename from packages/transport-http/src/send-get-network-parameters.js rename to packages/transport-http/src/send/send-get-network-parameters.js diff --git a/packages/transport-http/src/send-get-network-parameters.test.js b/packages/transport-http/src/send/send-get-network-parameters.test.js similarity index 100% rename from packages/transport-http/src/send-get-network-parameters.test.js rename to packages/transport-http/src/send/send-get-network-parameters.test.js diff --git a/packages/transport-http/src/send-get-node-version-info.test.ts b/packages/transport-http/src/send/send-get-node-version-info.test.ts similarity index 100% rename from packages/transport-http/src/send-get-node-version-info.test.ts rename to packages/transport-http/src/send/send-get-node-version-info.test.ts diff --git a/packages/transport-http/src/send-get-node-version-info.ts b/packages/transport-http/src/send/send-get-node-version-info.ts similarity index 100% rename from packages/transport-http/src/send-get-node-version-info.ts rename to packages/transport-http/src/send/send-get-node-version-info.ts diff --git a/packages/transport-http/src/send-get-transaction-status.js b/packages/transport-http/src/send/send-get-transaction-status.js similarity index 100% rename from packages/transport-http/src/send-get-transaction-status.js rename to packages/transport-http/src/send/send-get-transaction-status.js diff --git a/packages/transport-http/src/send-get-transaction-status.test.js b/packages/transport-http/src/send/send-get-transaction-status.test.js similarity index 100% rename from packages/transport-http/src/send-get-transaction-status.test.js rename to packages/transport-http/src/send/send-get-transaction-status.test.js diff --git a/packages/transport-http/src/send-get-transaction.js b/packages/transport-http/src/send/send-get-transaction.js similarity index 100% rename from packages/transport-http/src/send-get-transaction.js rename to packages/transport-http/src/send/send-get-transaction.js diff --git a/packages/transport-http/src/send-get-transaction.test.js b/packages/transport-http/src/send/send-get-transaction.test.js similarity index 100% rename from packages/transport-http/src/send-get-transaction.test.js rename to packages/transport-http/src/send/send-get-transaction.test.js diff --git a/packages/transport-http/src/send-http.ts b/packages/transport-http/src/send/send-http.ts similarity index 98% rename from packages/transport-http/src/send-http.ts rename to packages/transport-http/src/send/send-http.ts index 3ea87d3f9..7589a7883 100644 --- a/packages/transport-http/src/send-http.ts +++ b/packages/transport-http/src/send/send-http.ts @@ -9,7 +9,7 @@ import {connectSubscribeEvents} from "./connect-subscribe-events.js" import {sendGetBlock} from "./send-get-block.js" import {sendGetBlockHeader} from "./send-get-block-header.js" import {sendGetCollection} from "./send-get-collection.js" -import {sendPing, ISendPingContext} from "./send-ping" +import {sendPing, ISendPingContext} from "./send-ping.js" import {sendGetNetworkParameters} from "./send-get-network-parameters.js" import {Interaction} from "@onflow/typedefs" import {sendGetNodeVersionInfo} from "./send-get-node-version-info.js" diff --git a/packages/transport-http/src/send-ping.test.ts b/packages/transport-http/src/send/send-ping.test.ts similarity index 100% rename from packages/transport-http/src/send-ping.test.ts rename to packages/transport-http/src/send/send-ping.test.ts diff --git a/packages/transport-http/src/send-ping.ts b/packages/transport-http/src/send/send-ping.ts similarity index 100% rename from packages/transport-http/src/send-ping.ts rename to packages/transport-http/src/send/send-ping.ts diff --git a/packages/transport-http/src/send-transaction.js b/packages/transport-http/src/send/send-transaction.js similarity index 100% rename from packages/transport-http/src/send-transaction.js rename to packages/transport-http/src/send/send-transaction.js diff --git a/packages/transport-http/src/send-transaction.test.js b/packages/transport-http/src/send/send-transaction.test.js similarity index 100% rename from packages/transport-http/src/send-transaction.test.js rename to packages/transport-http/src/send/send-transaction.test.js diff --git a/packages/transport-http/src/utils.js b/packages/transport-http/src/send/utils.js similarity index 100% rename from packages/transport-http/src/utils.js rename to packages/transport-http/src/send/utils.js diff --git a/packages/transport-http/src/subscribe/models.ts b/packages/transport-http/src/subscribe/models.ts new file mode 100644 index 000000000..48d6aad07 --- /dev/null +++ b/packages/transport-http/src/subscribe/models.ts @@ -0,0 +1,66 @@ +export enum Action { + LIST_SUBSCRIPTIONS = "list_subscriptions", + SUBSCRIBE = "subscribe", + UNSUBSCRIBE = "unsubscribe", +} +export interface BaseMessageRequest { + action: Action +} + +export interface BaseMessageResponse { + action?: Action + success: boolean + error_message?: string +} + +export interface ListSubscriptionsMessageRequest extends BaseMessageRequest { + action: Action.LIST_SUBSCRIPTIONS +} + +export interface ListSubscriptionsMessageResponse extends BaseMessageResponse { + action: Action.LIST_SUBSCRIPTIONS + subscriptions?: SubscriptionEntry[] +} + +export interface SubscribeMessageRequest extends BaseMessageRequest { + action: Action.SUBSCRIBE + topic: string + arguments: Record +} + +export interface SubscribeMessageResponse extends BaseMessageResponse { + action: Action.SUBSCRIBE + topic: string + id: string +} + +export interface UnsubscribeMessageRequest extends BaseMessageRequest { + action: Action.UNSUBSCRIBE + id: string +} + +export type UnsubscribeMessageResponse = BaseMessageResponse & { + action: Action.UNSUBSCRIBE + id: string +} + +export type SubscriptionEntry = { + id: string + topic: string + arguments: Record +} + +export type MessageRequest = + | ListSubscriptionsMessageRequest + | SubscribeMessageRequest + | UnsubscribeMessageRequest + +export type MessageResponse = + | ListSubscriptionsMessageResponse + | SubscribeMessageResponse + | UnsubscribeMessageResponse + +export type SubscriptionDataMessage = { + id: string + data: any +} diff --git a/packages/transport-http/src/subscribe/subscribe.ts b/packages/transport-http/src/subscribe/subscribe.ts new file mode 100644 index 000000000..50e3ae3d4 --- /dev/null +++ b/packages/transport-http/src/subscribe/subscribe.ts @@ -0,0 +1,34 @@ +import {SdkTransport} from "@onflow/typedefs" +import {SubscriptionManager} from "./subscription-manager" + +// Map of SubscriptionManager instances by access node URL +let subscriptionManagerMap: Map = new Map() + +export async function subscribe( + { + topic, + args, + onData, + onError, + }: { + topic: T + args: SdkTransport.SubscriptionArguments + onData: (data: SdkTransport.SubscriptionData) => void + onError: (error: Error) => void + }, + opts: {node: string} +): Promise { + const manager = + subscriptionManagerMap.get(opts.node) || + new SubscriptionManager({ + node: opts.node, + }) + subscriptionManagerMap.set(opts.node, manager) + + return manager.subscribe({ + topic, + args, + onData, + onError, + }) +} diff --git a/packages/transport-http/src/subscribe/subscription-manager.test.ts b/packages/transport-http/src/subscribe/subscription-manager.test.ts new file mode 100644 index 000000000..48d2b81cc --- /dev/null +++ b/packages/transport-http/src/subscribe/subscription-manager.test.ts @@ -0,0 +1,260 @@ +import WS from "jest-websocket-mock" +import {WebSocket as mockSocket} from "mock-socket" +import { + Action, + SubscribeMessageRequest, + SubscribeMessageResponse, + SubscriptionDataMessage, + UnsubscribeMessageRequest, +} from "./models" +import { + SubscriptionManager, + SubscriptionManagerConfig, +} from "./subscription-manager" +import {SdkTransport} from "@onflow/typedefs" + +jest.mock("./websocket", () => ({ + WebSocket: mockSocket, +})) + +describe("WsSubscriptionTransport", () => { + let mockWs: WS + beforeEach(() => { + mockWs = new WS("wss://localhost:8080") + }) + + afterEach(() => { + WS.clean() + }) + + test("does not connect to the socket when no subscriptions are made", async () => { + const config: SubscriptionManagerConfig = { + node: "wss://localhost:8080", + } + + new SubscriptionManager(config) + + await new Promise(resolve => setTimeout(resolve, 0)) + expect(mockWs.server.clients).toHaveLength(0) + }) + + test("disconnects from the socket when the last subscription is removed", async () => { + const config: SubscriptionManagerConfig = { + node: "wss://localhost:8080", + } + const streamController = new SubscriptionManager(config) + const topic = "topic" as SdkTransport.SubscriptionTopic + const args = {key: "value"} as any + const onData = jest.fn() + const onError = jest.fn() + + let serverPromise = (async () => { + await mockWs.connected + + const msg = (await mockWs.nextMessage) as string + const data = JSON.parse(msg) as SubscribeMessageRequest + expect(data).toEqual({ + action: "subscribe", + topic, + arguments: args, + }) + + const response: SubscribeMessageResponse = { + id: "id", + action: Action.SUBSCRIBE, + success: true, + topic, + } + mockWs.send(JSON.stringify(response)) + })() + + const [subscription] = await Promise.all([ + streamController.subscribe({ + topic, + args, + onData, + onError, + }), + serverPromise, + ]) + + expect(subscription).toBeDefined() + expect(subscription.unsubscribe).toBeInstanceOf(Function) + + subscription.unsubscribe() + await new Promise(resolve => setTimeout(resolve, 0)) + + await mockWs.closed + expect(mockWs.server.clients).toHaveLength(0) + }) + + test("subscribes, receives data, and unsubscribes", async () => { + const config: SubscriptionManagerConfig = { + node: "wss://localhost:8080", + } + const streamController = new SubscriptionManager(config) + const topic = "topic" as SdkTransport.SubscriptionTopic + const args = {key: "value"} as any + const onData = jest.fn() + const onError = jest.fn() + + let serverPromise = (async () => { + await mockWs.connected + + const msg = (await mockWs.nextMessage) as string + const data = JSON.parse(msg) as SubscribeMessageRequest + expect(data).toEqual({ + action: "subscribe", + topic, + arguments: args, + }) + + const response: SubscribeMessageResponse = { + id: "id", + action: Action.SUBSCRIBE, + success: true, + topic, + } + mockWs.send(JSON.stringify(response)) + })() + + const [subscription] = await Promise.all([ + streamController.subscribe({ + topic, + args, + onData, + onError, + }), + serverPromise, + ]) + + expect(subscription).toBeDefined() + expect(subscription.unsubscribe).toBeInstanceOf(Function) + + serverPromise = (async () => { + const data = { + id: "id", + data: {key: "value"}, + } as SubscriptionDataMessage + mockWs.send(JSON.stringify(data)) + })() + + await serverPromise + + expect(onData).toHaveBeenCalledTimes(1) + expect(onData).toHaveBeenCalledWith({key: "value"}) + expect(onError).toHaveBeenCalledTimes(0) + + serverPromise = (async () => { + const msg = (await mockWs.nextMessage) as string + const data = JSON.parse(msg) as UnsubscribeMessageRequest + expect(data).toEqual({ + action: "unsubscribe", + id: "id", + }) + })() + + subscription.unsubscribe() + await serverPromise + }) + + test("reconnects to stream on close", async () => { + const config: SubscriptionManagerConfig = { + node: "wss://localhost:8080", + } + const streamController = new SubscriptionManager(config) + const topic = "topic" as SdkTransport.SubscriptionTopic + const args = {key: "value"} as any + const onData = jest.fn() + const onError = jest.fn() + + let serverPromise = (async () => { + await mockWs.connected + + const msg = (await mockWs.nextMessage) as string + const data = JSON.parse(msg) as SubscribeMessageRequest + expect(data).toEqual({ + action: "subscribe", + topic, + arguments: args, + }) + + const response: SubscribeMessageResponse = { + id: "id1", + action: Action.SUBSCRIBE, + success: true, + topic, + } + mockWs.send(JSON.stringify(response)) + })() + + const [subscription] = await Promise.all([ + streamController.subscribe({ + topic, + args, + onData, + onError, + }), + serverPromise, + ]) + + expect(subscription).toBeDefined() + expect(subscription.unsubscribe).toBeInstanceOf(Function) + + serverPromise = (async () => { + const data = { + id: "id1", + data: {key: "value"}, + } as SubscriptionDataMessage + mockWs.send(JSON.stringify(data)) + })() + + await serverPromise + + expect(onData).toHaveBeenCalledTimes(1) + expect(onData).toHaveBeenCalledWith({key: "value"}) + expect(onError).toHaveBeenCalledTimes(0) + + // Close the connection and create a new one + mockWs.close() + mockWs = new WS("wss://localhost:8080") + + serverPromise = (async () => { + await mockWs.connected + + const msg = (await mockWs.nextMessage) as string + const data = JSON.parse(msg) as SubscribeMessageRequest + expect(data).toEqual({ + action: "subscribe", + topic, + arguments: args, + }) + + const response: SubscribeMessageResponse = { + id: "id2", + action: Action.SUBSCRIBE, + success: true, + topic, + } + mockWs.send(JSON.stringify(response)) + })() + + await serverPromise + + // Wait for client to register the new subscription + await new Promise(resolve => setTimeout(resolve, 0)) + + serverPromise = (async () => { + const data = { + id: "id2", + data: {key: "value2"}, + } as SubscriptionDataMessage + mockWs.send(JSON.stringify(data)) + })() + + await serverPromise + + expect(onData).toHaveBeenCalledTimes(2) + expect(onData.mock.calls[1]).toEqual([{key: "value2"}]) + }) +}) diff --git a/packages/transport-http/src/subscribe/subscription-manager.ts b/packages/transport-http/src/subscribe/subscription-manager.ts new file mode 100644 index 000000000..b7ea02436 --- /dev/null +++ b/packages/transport-http/src/subscribe/subscription-manager.ts @@ -0,0 +1,317 @@ +import { + Action, + MessageResponse, + SubscriptionDataMessage, + UnsubscribeMessageResponse, +} from "./models" +import { + SubscribeMessageRequest, + SubscribeMessageResponse, + UnsubscribeMessageRequest, +} from "./models" +import type {SdkTransport} from "@onflow/typedefs" +import {WebSocket} from "./websocket" +import * as logger from "@onflow/util-logger" + +const WS_OPEN = 1 + +type DeepRequired = Required<{ + [K in keyof T]: DeepRequired +}> + +interface SubscriptionInfo { + // Internal ID for the subscription + id: number + // Remote ID assigned by the server used for message routing and unsubscribing + remoteId?: string + // The topic of the subscription + topic: T + // The checkpoint to resume the subscription from + checkpoint: SdkTransport.SubscriptionArguments + // The callback to call when a data is received + onData: (data: any) => void + // The callback to call when an error occurs + onError: (error: Error) => void +} + +export interface SubscriptionManagerConfig { + /** + * The URL of the node to connect to + */ + node: string + /** + * Options for reconnecting to the server + */ + reconnectOptions?: { + /** + * The initial delay in milliseconds before reconnecting + * @default 500 + */ + initialReconnectDelay?: number + /** + * The maximum number of reconnection attempts + * @default 5 + */ + reconnectAttempts?: number + /** + * The maximum delay in milliseconds between reconnection attempts + * @default 5000 + */ + maxReconnectDelay?: number + } +} + +export class SubscriptionManager { + private counter = 0 + private subscriptions: SubscriptionInfo[] = [] + private socket: WebSocket | null = null + private config: DeepRequired + private reconnectAttempts = 0 + + constructor(config: SubscriptionManagerConfig) { + this.config = { + ...config, + reconnectOptions: { + initialReconnectDelay: 500, + reconnectAttempts: 5, + maxReconnectDelay: 5000, + ...config.reconnectOptions, + }, + } + } + + // Lazy connect to the socket when the first subscription is made + private async connect() { + return new Promise((resolve, reject) => { + // If the socket is already open, do nothing + if (this.socket?.readyState === WS_OPEN) { + return + } + + this.socket = new WebSocket(this.config.node) + this.socket.onmessage = event => { + const data = JSON.parse(event.data) as + | MessageResponse + | SubscriptionDataMessage + + if ("action" in data) { + // TODO, waiting for AN team to decide what to do here + } else { + const sub = this.subscriptions.find(sub => sub.remoteId === data.id) + if (!sub) return + + // Update the block height to checkpoint for disconnects + this.updateSubscriptionCheckpoint(sub, data) + + // Call the subscription callback + sub.onData(data.data) + } + } + this.socket.onclose = () => { + void this.reconnect() + } + this.socket.onerror = e => { + this.reconnect(e) + } + + this.socket.onopen = () => { + // Restore subscriptions + Promise.all( + this.subscriptions.map(async sub => { + const response = await this.sendSubscribe(sub) + sub.remoteId = response.id + }) + ) + .then(() => { + resolve() + }) + .catch(e => { + reject(new Error(`Failed to restore subscriptions: ${e}`)) + }) + } + }) + } + + private async reconnect(error?: any) { + // Clear the socket + this.socket = null + + // If there are no subscriptions, do nothing + if (this.subscriptions.length === 0) { + return + } + + // Clear all remote ids + this.subscriptions.forEach(sub => { + delete sub.remoteId + }) + + // Validate the number of reconnection attempts + if ( + this.reconnectAttempts >= this.config.reconnectOptions.reconnectAttempts + ) { + logger.log({ + level: logger.LEVELS.error, + title: "WebSocket Error", + message: `Failed to reconnect to the server after ${this.reconnectAttempts + 1} attempts: ${error}`, + }) + + this.subscriptions.forEach(sub => { + sub.onError( + new Error( + `Failed to reconnect to the server after ${this.reconnectAttempts + 1} attempts: ${error}` + ) + ) + }) + this.subscriptions = [] + this.reconnectAttempts = 0 + } else { + logger.log({ + level: logger.LEVELS.warn, + title: "WebSocket Error", + message: `WebSocket error, reconnecting in ${this.backoffInterval}ms: ${error}`, + }) + + // Delay the reconnection + await new Promise(resolve => setTimeout(resolve, this.backoffInterval)) + + // Try to reconnect + this.reconnectAttempts++ + await this.connect() + this.reconnectAttempts = 0 + } + } + + async subscribe(opts: { + topic: T + args: SdkTransport.SubscriptionArguments + onData: (data: SdkTransport.SubscriptionData) => void + onError: (error: Error) => void + }): Promise { + // Connect the socket if it's not already open + await this.connect() + + // Track the subscription locally + const sub: SubscriptionInfo = { + id: this.counter++, + topic: opts.topic, + checkpoint: opts.args, + onData: opts.onData, + onError: opts.onError, + } + this.subscriptions.push(sub) + + // Send the subscribe message + const response = await this.sendSubscribe(sub) + + if (!response.success) { + throw new Error( + `Failed to subscribe to topic ${sub.topic}, error message: ${response.error_message}` + ) + } + + // Update the subscription with the remote id + sub.remoteId = response.id + + return { + unsubscribe: () => this.unsubscribe(sub.id), + } + } + + private unsubscribe(id: number): void { + // Get the subscription + const sub = this.subscriptions.find(sub => sub.id === id) + if (!sub) return + + // Send the unsubscribe message + this.sendUnsubscribe(sub).catch(e => { + console.error( + `Failed to unsubscribe from topic ${sub.topic}, error: ${e}` + ) + }) + + // Remove the subscription + this.subscriptions = this.subscriptions.filter(sub => sub.id !== id) + + // Close the socket if there are no more subscriptions + if (this.subscriptions.length === 0) { + this.socket?.close() + } + } + + private async sendSubscribe( + sub: SubscriptionInfo + ) { + // Send the subscription message + const request: SubscribeMessageRequest = { + action: Action.SUBSCRIBE, + topic: sub.topic, + arguments: sub.checkpoint, + } + this.socket?.send(JSON.stringify(request)) + + const response: SubscribeMessageResponse = await this.waitForResponse() + + if (!response.success) { + throw new Error( + `Failed to subscribe to topic ${sub.topic}, error message: ${response.error_message}` + ) + } + + return response + } + + private async sendUnsubscribe( + sub: SubscriptionInfo + ) { + // Send the unsubscribe message if the subscription has a remote id + const {remoteId} = sub + if (remoteId) { + const request: UnsubscribeMessageRequest = { + action: Action.UNSUBSCRIBE, + id: remoteId, + } + this.socket?.send(JSON.stringify(request)) + + const response: UnsubscribeMessageResponse = await this.waitForResponse() + + if (!response.success) { + throw new Error( + `Failed to unsubscribe from topic ${sub.topic}, error message: ${response.error_message}` + ) + } + } + } + + private async waitForResponse(): Promise { + // TODO: NOOP, waiting for AN team to decide what to do here, this is a placeholder + return new Promise(resolve => { + this.socket?.addEventListener("message", event => { + const data = JSON.parse(event.data) as T + if (data.action) { + resolve(data) + } + }) + }) + } + + // Update the subscription checkpoint when a message is received + // These checkpoints are used to resume subscriptions after disconnects + private updateSubscriptionCheckpoint< + T extends SdkTransport.SubscriptionTopic = SdkTransport.SubscriptionTopic, + >(sub: SubscriptionInfo, message: SubscriptionDataMessage) { + // TODO: Will be implemented with each subscription topic + } + + /** + * Calculate the backoff interval for reconnection attempts + * @returns The backoff interval in milliseconds + */ + private get backoffInterval() { + return Math.min( + this.config.reconnectOptions.maxReconnectDelay, + this.config.reconnectOptions.initialReconnectDelay * + 2 ** this.reconnectAttempts + ) + } +} diff --git a/packages/transport-http/src/websocket.ts b/packages/transport-http/src/subscribe/websocket.ts similarity index 58% rename from packages/transport-http/src/websocket.ts rename to packages/transport-http/src/subscribe/websocket.ts index 370efcede..996c99553 100644 --- a/packages/transport-http/src/websocket.ts +++ b/packages/transport-http/src/subscribe/websocket.ts @@ -1,6 +1,7 @@ import _WebSocket from "isomorphic-ws" -export const WebSocket = _WebSocket as new ( +export const WebSocket = _WebSocket as (new ( url: string | URL, protocols?: string | string[] | undefined -) => WebSocket +) => WebSocket) & + WebSocket diff --git a/packages/transport-http/src/transport.ts b/packages/transport-http/src/transport.ts new file mode 100644 index 000000000..c0484d062 --- /dev/null +++ b/packages/transport-http/src/transport.ts @@ -0,0 +1,8 @@ +import {SdkTransport} from "@onflow/typedefs" +import {send} from "./send/send-http" +import {subscribe} from "./subscribe/subscribe" + +export const httpTransport: SdkTransport.Transport = { + send, + subscribe, +} diff --git a/packages/typedefs/src/index.ts b/packages/typedefs/src/index.ts index 4f4082674..b9d516de3 100644 --- a/packages/typedefs/src/index.ts +++ b/packages/typedefs/src/index.ts @@ -459,3 +459,4 @@ export type EventStream = StreamConnection<{ export * from "./interaction" export * from "./fvm-errors" +export * as SdkTransport from "./sdk-transport" diff --git a/packages/typedefs/src/sdk-transport/index.ts b/packages/typedefs/src/sdk-transport/index.ts new file mode 100644 index 000000000..915962252 --- /dev/null +++ b/packages/typedefs/src/sdk-transport/index.ts @@ -0,0 +1,10 @@ +import {SendFn} from "./requests" +import {SubscribeFn} from "./subscriptions" + +export type Transport = { + send: SendFn + subscribe: SubscribeFn +} + +export * from "./subscriptions" +export * from "./requests" diff --git a/packages/typedefs/src/sdk-transport/requests.ts b/packages/typedefs/src/sdk-transport/requests.ts new file mode 100644 index 000000000..07a0b0665 --- /dev/null +++ b/packages/typedefs/src/sdk-transport/requests.ts @@ -0,0 +1,85 @@ +import {Interaction} from "../interaction" + +interface InteractionModule { + isTransaction: (ix: Interaction) => boolean + isGetTransactionStatus: (ix: Interaction) => boolean + isGetTransaction: (ix: Interaction) => boolean + isScript: (ix: Interaction) => boolean + isGetAccount: (ix: Interaction) => boolean + isGetEvents: (ix: Interaction) => boolean + isGetBlock: (ix: Interaction) => boolean + isGetBlockHeader: (ix: Interaction) => boolean + isGetCollection: (ix: Interaction) => boolean + isPing: (ix: Interaction) => boolean + isGetNetworkParameters: (ix: Interaction) => boolean + isSubscribeEvents?: (ix: Interaction) => boolean + isGetNodeVersionInfo?: (ix: Interaction) => boolean +} +interface IContext { + ix: InteractionModule +} +interface IOptsCommon { + node?: string +} + +interface IOpts extends IOptsCommon { + sendTransaction?: ( + ix: Interaction, + context: IContext, + opts: IOptsCommon + ) => void + sendGetTransactionStatus?: ( + ix: Interaction, + context: IContext, + opts: IOptsCommon + ) => void + sendGetTransaction?: ( + ix: Interaction, + context: IContext, + opts: IOptsCommon + ) => void + sendExecuteScript?: ( + ix: Interaction, + context: IContext, + opts: IOptsCommon + ) => void + sendGetAccount?: ( + ix: Interaction, + context: IContext, + opts: IOptsCommon + ) => void + sendGetEvents?: ( + ix: Interaction, + context: IContext, + opts: IOptsCommon + ) => void + sendGetBlockHeader?: ( + ix: Interaction, + context: IContext, + opts: IOptsCommon + ) => void + sendGetCollection?: ( + ix: Interaction, + context: IContext, + opts: IOptsCommon + ) => void + sendPing?: (ix: Interaction, context: IContext, opts: IOptsCommon) => void + sendGetBlock?: (ix: Interaction, context: IContext, opts: IOptsCommon) => void + sendGetNetworkParameters?: ( + ix: Interaction, + context: IContext, + opts: IOptsCommon + ) => void + connectSubscribeEvents?: ( + ix: Interaction, + context: IContext, + opts: IOptsCommon + ) => void + sendGetNodeVersionInfo?: ( + ix: Interaction, + context: IContext, + opts: IOptsCommon + ) => void +} + +export type SendFn = (ix: Interaction, context: IContext, opts: IOpts) => void diff --git a/packages/typedefs/src/sdk-transport/subscriptions.ts b/packages/typedefs/src/sdk-transport/subscriptions.ts new file mode 100644 index 000000000..53240d183 --- /dev/null +++ b/packages/typedefs/src/sdk-transport/subscriptions.ts @@ -0,0 +1,37 @@ +type SchemaItem = { + args: TArgs + data: TData +} + +// TODO: PLACEHOLDER - Replace with actual subscription topics +export enum SubscriptionTopic { + PLACEHOLDER = "PLACEHOLDER", +} + +export type SubscriptionSchema = { + [SubscriptionTopic.PLACEHOLDER]: SchemaItem< + {}, + { + placeholder: string + } + > +} + +export type SubscriptionArguments = + SubscriptionSchema[T]["args"] +export type SubscriptionData = + SubscriptionSchema[T]["data"] + +export type Subscription = { + unsubscribe: () => void +} + +export type SubscribeFn = ( + params: { + topic: T + args: SubscriptionArguments + onData: (data: SubscriptionData) => void + onError: (error: Error) => void + }, + opts: {node: string} +) => Promise From ebe06708053f3aaa7328fe64b0892e5e810e5508 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Fri, 6 Dec 2024 14:51:09 -0800 Subject: [PATCH 02/72] PKG -- [sdk] Create SDK subscribe function (#2024) --- packages/sdk/src/account/account.js | 2 +- packages/sdk/src/block/block.js | 2 +- packages/sdk/src/contract.test.js | 2 +- .../node-version-info/node-version-info.ts | 2 +- packages/sdk/src/sdk.ts | 2 +- packages/sdk/src/send/send.js | 40 ------ .../sdk/src/transport/get-transport.test.ts | 127 ++++++++++++++++++ packages/sdk/src/transport/get-transport.ts | 54 ++++++++ packages/sdk/src/transport/index.ts | 3 + .../sdk/src/{ => transport}/send/send.test.js | 0 packages/sdk/src/transport/send/send.ts | 41 ++++++ .../transport/subscribe/raw-subscribe.test.ts | 47 +++++++ .../src/transport/subscribe/raw-subscribe.ts | 41 ++++++ .../src/transport/subscribe/subscribe.test.ts | 112 +++++++++++++++ .../sdk/src/transport/subscribe/subscribe.ts | 37 +++++ packages/sdk/src/transport/subscribe/types.ts | 8 ++ .../src/subscribe/handlers/types.ts | 50 +++++++ .../transport-http/src/subscribe/subscribe.ts | 18 ++- .../subscribe/subscription-manager.test.ts | 69 ++++++---- .../src/subscribe/subscription-manager.ts | 100 ++++++++------ 20 files changed, 642 insertions(+), 115 deletions(-) delete mode 100644 packages/sdk/src/send/send.js create mode 100644 packages/sdk/src/transport/get-transport.test.ts create mode 100644 packages/sdk/src/transport/get-transport.ts create mode 100644 packages/sdk/src/transport/index.ts rename packages/sdk/src/{ => transport}/send/send.test.js (100%) create mode 100644 packages/sdk/src/transport/send/send.ts create mode 100644 packages/sdk/src/transport/subscribe/raw-subscribe.test.ts create mode 100644 packages/sdk/src/transport/subscribe/raw-subscribe.ts create mode 100644 packages/sdk/src/transport/subscribe/subscribe.test.ts create mode 100644 packages/sdk/src/transport/subscribe/subscribe.ts create mode 100644 packages/sdk/src/transport/subscribe/types.ts create mode 100644 packages/transport-http/src/subscribe/handlers/types.ts diff --git a/packages/sdk/src/account/account.js b/packages/sdk/src/account/account.js index f3a2a75ed..59709f96a 100644 --- a/packages/sdk/src/account/account.js +++ b/packages/sdk/src/account/account.js @@ -3,7 +3,7 @@ import {atBlockId} from "../build/build-at-block-id.js" import {getAccount} from "../build/build-get-account.js" import {invariant} from "@onflow/util-invariant" import {decodeResponse as decode} from "../decode/decode.js" -import {send} from "../send/send.js" +import {send} from "../transport" /** * @typedef {import("@onflow/typedefs").Account} Account diff --git a/packages/sdk/src/block/block.js b/packages/sdk/src/block/block.js index 6cc92df8e..b039a9334 100644 --- a/packages/sdk/src/block/block.js +++ b/packages/sdk/src/block/block.js @@ -1,4 +1,4 @@ -import {send} from "../send/send.js" +import {send} from "../transport/send/send" import {getBlock} from "../build/build-get-block" import {atBlockHeight} from "../build/build-at-block-height.js" import {atBlockId} from "../build/build-at-block-id.js" diff --git a/packages/sdk/src/contract.test.js b/packages/sdk/src/contract.test.js index 40f95cea8..374257ef5 100644 --- a/packages/sdk/src/contract.test.js +++ b/packages/sdk/src/contract.test.js @@ -2,7 +2,7 @@ import * as root from "./sdk" import * as decode from "./decode/decode.js" import * as encode from "./encode/encode" import * as interaction from "./interaction/interaction" -import * as send from "./send/send.js" +import * as send from "./transport" import * as template from "@onflow/util-template" const interfaceContract = diff --git a/packages/sdk/src/node-version-info/node-version-info.ts b/packages/sdk/src/node-version-info/node-version-info.ts index c905a76cd..76d38e25f 100644 --- a/packages/sdk/src/node-version-info/node-version-info.ts +++ b/packages/sdk/src/node-version-info/node-version-info.ts @@ -1,4 +1,4 @@ -import {send} from "../send/send.js" +import {send} from "../transport/send/send" import {decodeResponse as decode} from "../decode/decode.js" import {getNodeVersionInfo} from "../build/build-get-node-version-info" import {NodeVersionInfo} from "@onflow/typedefs" diff --git a/packages/sdk/src/sdk.ts b/packages/sdk/src/sdk.ts index 9ea40de35..3f3b8550b 100644 --- a/packages/sdk/src/sdk.ts +++ b/packages/sdk/src/sdk.ts @@ -2,7 +2,7 @@ import * as logger from "@onflow/util-logger" // Base export {build} from "./build/build.js" export {resolve} from "./resolve/resolve.js" -export {send} from "./send/send.js" +export {send, subscribe, rawSubscribe} from "./transport" export {decode} from "./decode/sdk-decode.js" export { encodeTransactionPayload, diff --git a/packages/sdk/src/send/send.js b/packages/sdk/src/send/send.js deleted file mode 100644 index eab60a9e4..000000000 --- a/packages/sdk/src/send/send.js +++ /dev/null @@ -1,40 +0,0 @@ -import {Buffer} from "@onflow/rlp" -import {send as defaultSend} from "@onflow/transport-http" -import {initInteraction, pipe} from "../interaction/interaction" -import * as ixModule from "../interaction/interaction" -import {invariant} from "../build/build-invariant.js" -import {response} from "../response/response" -import {config} from "@onflow/config" -import {resolve as defaultResolve} from "../resolve/resolve.js" - -/** - * @description - Sends arbitrary scripts, transactions, and requests to Flow - * @param {Array. | Function} args - An array of functions that take interaction and return interaction - * @param {object} opts - Optional parameters - * @returns {Promise<*>} - A promise that resolves to a response - */ -export const send = async (args = [], opts = {}) => { - const sendFn = await config.first( - ["sdk.transport", "sdk.send"], - opts.send || defaultSend - ) - - invariant( - sendFn, - `Required value for sdk.transport is not defined in config. See: ${"https://github.com/onflow/fcl-js/blob/master/packages/sdk/CHANGELOG.md#0057-alpha1----2022-01-21"}` - ) - - const resolveFn = await config.first( - ["sdk.resolve"], - opts.resolve || defaultResolve - ) - - opts.node = opts.node || (await config().get("accessNode.api")) - - if (Array.isArray(args)) args = pipe(initInteraction(), args) - return sendFn( - await resolveFn(args), - {config, response, ix: ixModule, Buffer}, - opts - ) -} diff --git a/packages/sdk/src/transport/get-transport.test.ts b/packages/sdk/src/transport/get-transport.test.ts new file mode 100644 index 000000000..9e78b8d30 --- /dev/null +++ b/packages/sdk/src/transport/get-transport.test.ts @@ -0,0 +1,127 @@ +import {SdkTransport} from "@onflow/typedefs" +import {getTransport} from "./get-transport" +import {httpTransport} from "@onflow/transport-http" +import {config} from "@onflow/config" + +jest.mock("@onflow/transport-http", () => ({ + httpTransport: { + send: jest.fn(), + subscribe: jest.fn(), + } as jest.Mocked, +})) + +describe("getTransport", () => { + beforeEach(() => { + jest.resetAllMocks() + }) + + test("fallback to http transport", async () => { + const transport = await getTransport() + expect(transport).toBe(httpTransport) + }) + + test("override with custom transport", async () => { + const customTransport = { + send: jest.fn(), + subscribe: jest.fn(), + } as jest.Mocked + + const transport = await getTransport({transport: customTransport}) + expect(transport).toBe(customTransport) + }) + + test("override with custom send function", async () => { + const customSend = jest.fn() + + const transport = await getTransport({send: customSend}) + expect(transport).toEqual({ + send: customSend, + subscribe: expect.any(Function), + }) + }) + + test("override with both custom transport and send function", async () => { + await expect( + getTransport({ + send: jest.fn(), + transport: { + send: jest.fn(), + subscribe: jest.fn(), + }, + }) + ).rejects.toThrow( + /Cannot provide both "transport" and legacy "send" options/ + ) + }) + + test("transport from global config - sdk.transport", async () => { + const customTransport = { + send: jest.fn(), + subscribe: jest.fn(), + } as jest.Mocked + + const tranpsort = await config().overload( + { + "sdk.transport": customTransport, + }, + async () => { + return await getTransport() + } + ) + + expect(tranpsort).toBe(customTransport) + }) + + test("send function from global config - sdk.transport", async () => { + const customSend = jest.fn() + + const transport = await config().overload( + { + "sdk.transport": customSend, + }, + async () => { + return await getTransport() + } + ) + expect(transport).toEqual({ + send: customSend, + subscribe: expect.any(Function), + }) + }) + + test("send function from global config - sdk.send", async () => { + const customSend = jest.fn() + + const transport = await config().overload( + { + "sdk.send": customSend, + }, + async () => { + return await getTransport() + } + ) + + expect(transport).toEqual({ + send: customSend, + subscribe: expect.any(Function), + }) + }) + + test("custom transport has priority over global config", async () => { + const customTransport = { + send: jest.fn(), + subscribe: jest.fn(), + } as jest.Mocked + + const transport = await config().overload( + { + "sdk.transport": httpTransport, + }, + async () => { + return await getTransport({transport: customTransport}) + } + ) + + expect(transport).toBe(customTransport) + }) +}) diff --git a/packages/sdk/src/transport/get-transport.ts b/packages/sdk/src/transport/get-transport.ts new file mode 100644 index 000000000..635d6e054 --- /dev/null +++ b/packages/sdk/src/transport/get-transport.ts @@ -0,0 +1,54 @@ +import {config} from "@onflow/config" +import {httpTransport as defaultTransport} from "@onflow/transport-http" +import {SdkTransport} from "@onflow/typedefs" +import {invariant} from "@onflow/util-invariant" + +/** + * Get the SDK transport object, either from the provided override or from the global config. + * @param overrides - Override default configuration with custom transport or send function. + * @returns The SDK transport object. + */ +export async function getTransport( + override: { + send?: SdkTransport.SendFn + transport?: SdkTransport.Transport + } = {} +): Promise { + invariant( + override.send == null || override.transport == null, + `SDK Transport Error: Cannot provide both "transport" and legacy "send" options.` + ) + + const transportOrSend = + override.transport || + override.send || + (await config().first( + ["sdk.transport", "sdk.send"], + defaultTransport + )) + + // Backwards compatibility with legacy send function + if (!isTransportObject(transportOrSend)) { + return { + send: transportOrSend, + subscribe: () => { + throw new Error( + "Subscribe not supported with legacy send function transport, please provide a transport object." + ) + }, + } + } + + return transportOrSend +} + +function isTransportObject( + transport: any +): transport is SdkTransport.Transport { + return ( + transport.send !== undefined && + transport.subscribe !== undefined && + typeof transport.send === "function" && + typeof transport.subscribe === "function" + ) +} diff --git a/packages/sdk/src/transport/index.ts b/packages/sdk/src/transport/index.ts new file mode 100644 index 000000000..cf3d3ae64 --- /dev/null +++ b/packages/sdk/src/transport/index.ts @@ -0,0 +1,3 @@ +export {send} from "./send/send" +export {subscribe} from "./subscribe/subscribe" +export {rawSubscribe} from "./subscribe/raw-subscribe" diff --git a/packages/sdk/src/send/send.test.js b/packages/sdk/src/transport/send/send.test.js similarity index 100% rename from packages/sdk/src/send/send.test.js rename to packages/sdk/src/transport/send/send.test.js diff --git a/packages/sdk/src/transport/send/send.ts b/packages/sdk/src/transport/send/send.ts new file mode 100644 index 000000000..02ce8f1a6 --- /dev/null +++ b/packages/sdk/src/transport/send/send.ts @@ -0,0 +1,41 @@ +import {Buffer} from "@onflow/rlp" +import {initInteraction, pipe} from "../../interaction/interaction" +import * as ixModule from "../../interaction/interaction" +import {invariant} from "../../build/build-invariant" +import {response} from "../../response/response" +import {config} from "@onflow/config" +import {resolve as defaultResolve} from "../../resolve/resolve" +import {getTransport} from "../get-transport" + +/** + * @description - Sends arbitrary scripts, transactions, and requests to Flow + * @param args - An array of functions that take interaction and return interaction + * @param opts - Optional parameters + * @returns - A promise that resolves to a response + */ +export const send = async ( + args: Function | Function[] = [], + opts: any = {} +): Promise => { + const transport = await getTransport(opts) + const sendFn = transport.send.bind(transport) + + invariant( + sendFn, + `Required value for sdk.transport is not defined in config. See: ${"https://github.com/onflow/fcl-js/blob/master/packages/sdk/CHANGELOG.md#0057-alpha1----2022-01-21"}` + ) + + const resolveFn = await config.first( + ["sdk.resolve"], + opts.resolve || defaultResolve + ) + + opts.node = opts.node || (await config().get("accessNode.api")) + + if (Array.isArray(args)) args = pipe(initInteraction(), args as any) as any + return sendFn( + await resolveFn(args), + {config, response, ix: ixModule, Buffer} as any, + opts + ) +} diff --git a/packages/sdk/src/transport/subscribe/raw-subscribe.test.ts b/packages/sdk/src/transport/subscribe/raw-subscribe.test.ts new file mode 100644 index 000000000..bbf134730 --- /dev/null +++ b/packages/sdk/src/transport/subscribe/raw-subscribe.test.ts @@ -0,0 +1,47 @@ +import {config} from "@onflow/config" +import {rawSubscribe} from "./raw-subscribe" +import {SdkTransport} from "@onflow/typedefs" +import {getTransport} from "../get-transport" + +jest.mock("../get-transport") + +describe("subscribe", () => { + let mockTransport: jest.Mocked + let mockSub: jest.Mocked = { + unsubscribe: jest.fn(), + } + + beforeEach(() => { + jest.resetAllMocks() + + mockTransport = { + subscribe: jest.fn().mockReturnValue(mockSub), + send: jest.fn(), + } + jest.mocked(getTransport).mockResolvedValue(mockTransport) + }) + + test("subscribes to a topic and returns subscription from transport", async () => { + const topic = "topic" as SdkTransport.SubscriptionTopic + const args = {foo: "bar"} as SdkTransport.SubscriptionArguments + const onData = jest.fn() + const onError = jest.fn() + + const sub = await config().overload( + { + "accessNode.api": "http://localhost:8080", + }, + async () => { + return await rawSubscribe({topic, args, onData, onError}) + } + ) + + expect(mockTransport.subscribe).toHaveBeenCalledTimes(1) + expect(mockTransport.subscribe).toHaveBeenCalledWith( + {topic, args, onData: onData, onError}, + {node: "http://localhost:8080"} + ) + + expect(sub).toBe(mockSub) + }) +}) diff --git a/packages/sdk/src/transport/subscribe/raw-subscribe.ts b/packages/sdk/src/transport/subscribe/raw-subscribe.ts new file mode 100644 index 000000000..6956fc649 --- /dev/null +++ b/packages/sdk/src/transport/subscribe/raw-subscribe.ts @@ -0,0 +1,41 @@ +import {config} from "@onflow/config" +import {SdkTransport} from "@onflow/typedefs" +import {getTransport} from "../get-transport" +import {invariant} from "@onflow/util-invariant" +import {SubscribeParams} from "./types" + +/** + * Subscribe to a topic without decoding the data. + * @param params - The parameters for the subscription. + * @param opts - Additional options for the subscription. + * @returns A promise that resolves once the subscription is active. + */ +export async function rawSubscribe( + {topic, args, onData, onError}: SubscribeParams, + opts: { + node?: string + transport?: SdkTransport.Transport + } = {} +) { + const transport = await getTransport(opts) + const node = opts?.node || (await config().get("accessNode.api")) + + invariant( + !!node, + `SDK Send Error: Either opts.node or "accessNode.api" in config must be defined.` + ) + + // Subscribe using the resolved transport + return transport.subscribe( + { + topic, + args, + onData, + onError, + }, + { + node, + ...opts, + } + ) +} diff --git a/packages/sdk/src/transport/subscribe/subscribe.test.ts b/packages/sdk/src/transport/subscribe/subscribe.test.ts new file mode 100644 index 000000000..ad7be7950 --- /dev/null +++ b/packages/sdk/src/transport/subscribe/subscribe.test.ts @@ -0,0 +1,112 @@ +import {SdkTransport} from "@onflow/typedefs" +import {subscribe} from "./subscribe" +import {rawSubscribe} from "./raw-subscribe" + +jest.mock("./raw-subscribe") +const mockRawSubscribe = jest.mocked(rawSubscribe) + +describe("subscribe", () => { + let mockSub: jest.Mocked = { + unsubscribe: jest.fn(), + } + + beforeEach(() => { + jest.resetAllMocks() + mockRawSubscribe.mockResolvedValue(mockSub) + }) + + test("subscribes to a topic and returns a subscription", async () => { + const topic = "topic" as SdkTransport.SubscriptionTopic + const args = {foo: "bar"} as SdkTransport.SubscriptionArguments + const onData = jest.fn() + const onError = jest.fn() + + const sub = await subscribe({ + topic, + args, + onData, + onError, + }) + + expect(sub).toBe(mockSub) + expect(mockRawSubscribe).toHaveBeenCalledTimes(1) + expect(mockRawSubscribe).toHaveBeenCalledWith( + {topic, args, onData: expect.any(Function), onError}, + {} + ) + }) + + test("unsubscribes from a subscription", async () => { + const topic = "topic" as SdkTransport.SubscriptionTopic + const args = {foo: "bar"} as SdkTransport.SubscriptionArguments + const onData = jest.fn() + const onError = jest.fn() + + const sub = await subscribe({ + topic, + args, + onData, + onError, + }) + + sub.unsubscribe() + + expect(mockSub.unsubscribe).toHaveBeenCalledTimes(1) + }) + + test("subscribes to a topic with a node", async () => { + const topic = "topic" as SdkTransport.SubscriptionTopic + const args = {foo: "bar"} as SdkTransport.SubscriptionArguments + const onData = jest.fn() + const onError = jest.fn() + + const node = "http://localhost:8080" + + const sub = await subscribe( + { + topic, + args, + onData, + onError, + }, + {node} + ) + + expect(sub).toBe(mockSub) + expect(mockRawSubscribe).toHaveBeenCalledTimes(1) + expect(mockRawSubscribe).toHaveBeenCalledWith( + {topic, args, onData: expect.any(Function), onError}, + {node} + ) + }) + + test("subscribes to a topic with custom node and transport", async () => { + const topic = "topic" as SdkTransport.SubscriptionTopic + const args = {foo: "bar"} as SdkTransport.SubscriptionArguments + const onData = jest.fn() + const onError = jest.fn() + + const node = "http://localhost:8080" + const transport = { + send: jest.fn(), + subscribe: jest.fn().mockResolvedValue(mockSub), + } as jest.Mocked + + const sub = await subscribe( + { + topic, + args, + onData, + onError, + }, + {node, transport} + ) + + expect(sub).toBe(mockSub) + expect(mockRawSubscribe).toHaveBeenCalledTimes(1) + expect(mockRawSubscribe).toHaveBeenCalledWith( + {topic, args, onData: expect.any(Function), onError}, + {node, transport} + ) + }) +}) diff --git a/packages/sdk/src/transport/subscribe/subscribe.ts b/packages/sdk/src/transport/subscribe/subscribe.ts new file mode 100644 index 000000000..07112374d --- /dev/null +++ b/packages/sdk/src/transport/subscribe/subscribe.ts @@ -0,0 +1,37 @@ +import {SdkTransport} from "@onflow/typedefs" +import {rawSubscribe} from "./raw-subscribe" +import {decodeResponse} from "../../decode/decode" +import {SubscribeParams} from "./types" + +/** + * Subscribe to a topic and decode the data. + * @param params - The parameters for the subscription. + * @param opts - Additional options for the subscription. + * @returns A promise that resolves when the subscription is active. + */ +export async function subscribe( + {topic, args, onData, onError}: SubscribeParams, + opts: { + node?: string + transport?: SdkTransport.Transport + } = {} +): Promise { + const sub = await rawSubscribe( + { + topic, + args, + onData: data => { + decodeResponse(data) + .then(onData) + .catch(e => { + onError(new Error(`Failed to decode response: ${e.message}`)) + sub.unsubscribe() + }) + }, + onError, + }, + opts + ) + + return sub +} diff --git a/packages/sdk/src/transport/subscribe/types.ts b/packages/sdk/src/transport/subscribe/types.ts new file mode 100644 index 000000000..0069edf74 --- /dev/null +++ b/packages/sdk/src/transport/subscribe/types.ts @@ -0,0 +1,8 @@ +import {SdkTransport} from "@onflow/typedefs" + +export type SubscribeParams = { + topic: T + args: SdkTransport.SubscriptionArguments + onData: (data: SdkTransport.SubscriptionData) => void + onError: (error: Error) => void +} diff --git a/packages/transport-http/src/subscribe/handlers/types.ts b/packages/transport-http/src/subscribe/handlers/types.ts new file mode 100644 index 000000000..939b6c59f --- /dev/null +++ b/packages/transport-http/src/subscribe/handlers/types.ts @@ -0,0 +1,50 @@ +export interface SubscriptionHandler< + T extends { + Topic: string + Args: any + Data: any + ArgsDto: any + DataDto: any + }, +> { + readonly topic: T["Topic"] + createSubscriber( + initialArgs: T["Args"], + onData: (data: T["Data"]) => void, + onError: (error: Error) => void + ): DataSubscriber +} + +export interface DataSubscriber { + /** + * The callback to call when a data is received + */ + onData(data: DataDto): void + + /** + * The callback to call when an error is received + */ + onError(error: Error): void + + /** + * The arguments to connect or reconnect to the subscription + */ + argsToDto(args: Args): ArgsDto + + /** + * Get the arguments to connect or reconnect to the subscription + */ + get connectionArgs(): Args +} + +export function createSubscriptionHandler< + T extends { + Topic: string + Args: any + Data: any + ArgsDto: any + DataDto: any + }, +>(handler: SubscriptionHandler): SubscriptionHandler { + return handler +} diff --git a/packages/transport-http/src/subscribe/subscribe.ts b/packages/transport-http/src/subscribe/subscribe.ts index 50e3ae3d4..9f47a0f5d 100644 --- a/packages/transport-http/src/subscribe/subscribe.ts +++ b/packages/transport-http/src/subscribe/subscribe.ts @@ -1,8 +1,13 @@ import {SdkTransport} from "@onflow/typedefs" import {SubscriptionManager} from "./subscription-manager" +const SUBSCRIPTION_HANDLERS: any[] = [] + // Map of SubscriptionManager instances by access node URL -let subscriptionManagerMap: Map = new Map() +let subscriptionManagerMap: Map< + string, + SubscriptionManager +> = new Map() export async function subscribe( { @@ -18,16 +23,17 @@ export async function subscribe( }, opts: {node: string} ): Promise { + // Get the SubscriptionManager instance for the access node, or create a new one + const node = opts.node const manager = - subscriptionManagerMap.get(opts.node) || - new SubscriptionManager({ - node: opts.node, - }) - subscriptionManagerMap.set(opts.node, manager) + subscriptionManagerMap.get(node) || + new SubscriptionManager(SUBSCRIPTION_HANDLERS, {node}) + subscriptionManagerMap.set(node, manager) return manager.subscribe({ topic, args, + // @ts-ignore - TODO: This is temporary until we start implementing the handlers onData, onError, }) diff --git a/packages/transport-http/src/subscribe/subscription-manager.test.ts b/packages/transport-http/src/subscribe/subscription-manager.test.ts index 48d2b81cc..0d656ebb9 100644 --- a/packages/transport-http/src/subscribe/subscription-manager.test.ts +++ b/packages/transport-http/src/subscribe/subscription-manager.test.ts @@ -12,15 +12,34 @@ import { SubscriptionManagerConfig, } from "./subscription-manager" import {SdkTransport} from "@onflow/typedefs" +import {DataSubscriber, SubscriptionHandler} from "./handlers/types" jest.mock("./websocket", () => ({ WebSocket: mockSocket, })) -describe("WsSubscriptionTransport", () => { +describe("SubscriptionManager", () => { let mockWs: WS + let mockSubscriber: jest.Mocked> + let mockHandler: jest.Mocked> + const mockConnectionArgs = {mock: "connection args"} + beforeEach(() => { + jest.resetAllMocks() + mockWs = new WS("wss://localhost:8080") + mockSubscriber = { + onData: jest.fn(), + onError: jest.fn(), + argsToDto: jest.fn().mockReturnValue(mockConnectionArgs), + get connectionArgs() { + return mockConnectionArgs + }, + } + mockHandler = { + topic: "topic", + createSubscriber: jest.fn().mockReturnValue(mockSubscriber), + } }) afterEach(() => { @@ -28,11 +47,7 @@ describe("WsSubscriptionTransport", () => { }) test("does not connect to the socket when no subscriptions are made", async () => { - const config: SubscriptionManagerConfig = { - node: "wss://localhost:8080", - } - - new SubscriptionManager(config) + new SubscriptionManager([mockHandler], {node: "wss://localhost:8080"}) await new Promise(resolve => setTimeout(resolve, 0)) expect(mockWs.server.clients).toHaveLength(0) @@ -42,7 +57,7 @@ describe("WsSubscriptionTransport", () => { const config: SubscriptionManagerConfig = { node: "wss://localhost:8080", } - const streamController = new SubscriptionManager(config) + const subscriptionManager = new SubscriptionManager([mockHandler], config) const topic = "topic" as SdkTransport.SubscriptionTopic const args = {key: "value"} as any const onData = jest.fn() @@ -56,7 +71,7 @@ describe("WsSubscriptionTransport", () => { expect(data).toEqual({ action: "subscribe", topic, - arguments: args, + arguments: mockConnectionArgs, }) const response: SubscribeMessageResponse = { @@ -69,7 +84,7 @@ describe("WsSubscriptionTransport", () => { })() const [subscription] = await Promise.all([ - streamController.subscribe({ + subscriptionManager.subscribe({ topic, args, onData, @@ -92,7 +107,7 @@ describe("WsSubscriptionTransport", () => { const config: SubscriptionManagerConfig = { node: "wss://localhost:8080", } - const streamController = new SubscriptionManager(config) + const subscriptionManager = new SubscriptionManager([mockHandler], config) const topic = "topic" as SdkTransport.SubscriptionTopic const args = {key: "value"} as any const onData = jest.fn() @@ -106,7 +121,7 @@ describe("WsSubscriptionTransport", () => { expect(data).toEqual({ action: "subscribe", topic, - arguments: args, + arguments: mockConnectionArgs, }) const response: SubscribeMessageResponse = { @@ -119,7 +134,7 @@ describe("WsSubscriptionTransport", () => { })() const [subscription] = await Promise.all([ - streamController.subscribe({ + subscriptionManager.subscribe({ topic, args, onData, @@ -141,9 +156,9 @@ describe("WsSubscriptionTransport", () => { await serverPromise - expect(onData).toHaveBeenCalledTimes(1) - expect(onData).toHaveBeenCalledWith({key: "value"}) - expect(onError).toHaveBeenCalledTimes(0) + expect(mockSubscriber.onData).toHaveBeenCalledTimes(1) + expect(mockSubscriber.onData).toHaveBeenCalledWith({key: "value"}) + expect(mockSubscriber.onError).toHaveBeenCalledTimes(0) serverPromise = (async () => { const msg = (await mockWs.nextMessage) as string @@ -162,7 +177,7 @@ describe("WsSubscriptionTransport", () => { const config: SubscriptionManagerConfig = { node: "wss://localhost:8080", } - const streamController = new SubscriptionManager(config) + const subscriptionManager = new SubscriptionManager([mockHandler], config) const topic = "topic" as SdkTransport.SubscriptionTopic const args = {key: "value"} as any const onData = jest.fn() @@ -176,7 +191,7 @@ describe("WsSubscriptionTransport", () => { expect(data).toEqual({ action: "subscribe", topic, - arguments: args, + arguments: mockConnectionArgs, }) const response: SubscribeMessageResponse = { @@ -189,7 +204,7 @@ describe("WsSubscriptionTransport", () => { })() const [subscription] = await Promise.all([ - streamController.subscribe({ + subscriptionManager.subscribe({ topic, args, onData, @@ -200,6 +215,12 @@ describe("WsSubscriptionTransport", () => { expect(subscription).toBeDefined() expect(subscription.unsubscribe).toBeInstanceOf(Function) + expect(mockHandler.createSubscriber).toHaveBeenCalledTimes(1) + expect(mockHandler.createSubscriber).toHaveBeenCalledWith( + args, + onData, + onError + ) serverPromise = (async () => { const data = { @@ -211,9 +232,9 @@ describe("WsSubscriptionTransport", () => { await serverPromise - expect(onData).toHaveBeenCalledTimes(1) - expect(onData).toHaveBeenCalledWith({key: "value"}) - expect(onError).toHaveBeenCalledTimes(0) + expect(mockSubscriber.onData).toHaveBeenCalledTimes(1) + expect(mockSubscriber.onData).toHaveBeenCalledWith({key: "value"}) + expect(mockSubscriber.onError).toHaveBeenCalledTimes(0) // Close the connection and create a new one mockWs.close() @@ -227,7 +248,7 @@ describe("WsSubscriptionTransport", () => { expect(data).toEqual({ action: "subscribe", topic, - arguments: args, + arguments: mockConnectionArgs, }) const response: SubscribeMessageResponse = { @@ -254,7 +275,7 @@ describe("WsSubscriptionTransport", () => { await serverPromise - expect(onData).toHaveBeenCalledTimes(2) - expect(onData.mock.calls[1]).toEqual([{key: "value2"}]) + expect(mockSubscriber.onData).toHaveBeenCalledTimes(2) + expect(mockSubscriber.onData.mock.calls[1]).toEqual([{key: "value2"}]) }) }) diff --git a/packages/transport-http/src/subscribe/subscription-manager.ts b/packages/transport-http/src/subscribe/subscription-manager.ts index b7ea02436..cc9c3bf3e 100644 --- a/packages/transport-http/src/subscribe/subscription-manager.ts +++ b/packages/transport-http/src/subscribe/subscription-manager.ts @@ -9,8 +9,9 @@ import { SubscribeMessageResponse, UnsubscribeMessageRequest, } from "./models" -import type {SdkTransport} from "@onflow/typedefs" +import {SdkTransport} from "@onflow/typedefs" import {WebSocket} from "./websocket" +import {DataSubscriber, SubscriptionHandler} from "./handlers/types" import * as logger from "@onflow/util-logger" const WS_OPEN = 1 @@ -19,19 +20,17 @@ type DeepRequired = Required<{ [K in keyof T]: DeepRequired }> -interface SubscriptionInfo { +type InferHandler = T extends SubscriptionHandler ? H : never + +interface SubscriptionInfo { // Internal ID for the subscription id: number // Remote ID assigned by the server used for message routing and unsubscribing remoteId?: string // The topic of the subscription - topic: T - // The checkpoint to resume the subscription from - checkpoint: SdkTransport.SubscriptionArguments - // The callback to call when a data is received - onData: (data: any) => void - // The callback to call when an error occurs - onError: (error: Error) => void + topic: string + // Data provider for the subscription + subscriber: DataSubscriber } export interface SubscriptionManagerConfig { @@ -61,14 +60,15 @@ export interface SubscriptionManagerConfig { } } -export class SubscriptionManager { +export class SubscriptionManager[]> { private counter = 0 - private subscriptions: SubscriptionInfo[] = [] private socket: WebSocket | null = null + private subscriptions: SubscriptionInfo[] = [] private config: DeepRequired private reconnectAttempts = 0 + private handlers: Record> - constructor(config: SubscriptionManagerConfig) { + constructor(handlers: Handlers, config: SubscriptionManagerConfig) { this.config = { ...config, reconnectOptions: { @@ -78,6 +78,15 @@ export class SubscriptionManager { ...config.reconnectOptions, }, } + + // Map data providers by topic + this.handlers = handlers.reduce( + (acc, handler) => { + acc[handler.topic] = handler + return acc + }, + {} as Record> + ) } // Lazy connect to the socket when the first subscription is made @@ -90,21 +99,15 @@ export class SubscriptionManager { this.socket = new WebSocket(this.config.node) this.socket.onmessage = event => { - const data = JSON.parse(event.data) as + const message = JSON.parse(event.data) as | MessageResponse | SubscriptionDataMessage - if ("action" in data) { + if ("action" in message) { // TODO, waiting for AN team to decide what to do here } else { - const sub = this.subscriptions.find(sub => sub.remoteId === data.id) - if (!sub) return - // Update the block height to checkpoint for disconnects - this.updateSubscriptionCheckpoint(sub, data) - - // Call the subscription callback - sub.onData(data.data) + this.handleSubscriptionData(message) } } this.socket.onclose = () => { @@ -157,7 +160,7 @@ export class SubscriptionManager { }) this.subscriptions.forEach(sub => { - sub.onError( + sub.subscriber.onError( new Error( `Failed to reconnect to the server after ${this.reconnectAttempts + 1} attempts: ${error}` ) @@ -182,22 +185,28 @@ export class SubscriptionManager { } } - async subscribe(opts: { - topic: T - args: SdkTransport.SubscriptionArguments - onData: (data: SdkTransport.SubscriptionData) => void + async subscribe(opts: { + topic: InferHandler["Topic"] + args: InferHandler["Args"] + onData: (data: InferHandler["Data"]) => void onError: (error: Error) => void }): Promise { // Connect the socket if it's not already open await this.connect() + // Get the data provider for the topic + const topicHandler = this.getHandler(opts.topic) + const subscriber = topicHandler.createSubscriber( + opts.args, + opts.onData, + opts.onError + ) + // Track the subscription locally - const sub: SubscriptionInfo = { + const sub: SubscriptionInfo = { id: this.counter++, topic: opts.topic, - checkpoint: opts.args, - onData: opts.onData, - onError: opts.onError, + subscriber: subscriber, } this.subscriptions.push(sub) @@ -239,14 +248,12 @@ export class SubscriptionManager { } } - private async sendSubscribe( - sub: SubscriptionInfo - ) { + private async sendSubscribe(sub: SubscriptionInfo) { // Send the subscription message const request: SubscribeMessageRequest = { action: Action.SUBSCRIBE, topic: sub.topic, - arguments: sub.checkpoint, + arguments: sub.subscriber.connectionArgs, } this.socket?.send(JSON.stringify(request)) @@ -261,9 +268,7 @@ export class SubscriptionManager { return response } - private async sendUnsubscribe( - sub: SubscriptionInfo - ) { + private async sendUnsubscribe(sub: SubscriptionInfo) { // Send the unsubscribe message if the subscription has a remote id const {remoteId} = sub if (remoteId) { @@ -297,10 +302,25 @@ export class SubscriptionManager { // Update the subscription checkpoint when a message is received // These checkpoints are used to resume subscriptions after disconnects - private updateSubscriptionCheckpoint< + private handleSubscriptionData< T extends SdkTransport.SubscriptionTopic = SdkTransport.SubscriptionTopic, - >(sub: SubscriptionInfo, message: SubscriptionDataMessage) { - // TODO: Will be implemented with each subscription topic + >(message: SubscriptionDataMessage) { + // Get the subscription + const sub = this.subscriptions.find(sub => sub.remoteId === message.id) + if (!sub) { + throw new Error(`No subscription found for id ${message.id}`) + } + + // Send data to the subscriber + sub.subscriber.onData(message.data) + } + + private getHandler(topic: string) { + const handler = this.handlers[topic] + if (!handler) { + throw new Error(`No handler found for topic ${topic}`) + } + return handler } /** From 5a6cde2397d966a2b392199d638ff37a58f277af Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Fri, 14 Mar 2025 14:40:12 -0700 Subject: [PATCH 03/72] Update to latest streaming API changes (#2202) --- .../src/subscribe/handlers/types.ts | 11 +- .../transport-http/src/subscribe/models.ts | 27 ++- .../subscribe/subscription-manager.test.ts | 64 +++--- .../src/subscribe/subscription-manager.ts | 212 +++++++++--------- tsconfig.json | 2 + 5 files changed, 159 insertions(+), 157 deletions(-) diff --git a/packages/transport-http/src/subscribe/handlers/types.ts b/packages/transport-http/src/subscribe/handlers/types.ts index 939b6c59f..bbda38e85 100644 --- a/packages/transport-http/src/subscribe/handlers/types.ts +++ b/packages/transport-http/src/subscribe/handlers/types.ts @@ -12,10 +12,10 @@ export interface SubscriptionHandler< initialArgs: T["Args"], onData: (data: T["Data"]) => void, onError: (error: Error) => void - ): DataSubscriber + ): DataSubscriber } -export interface DataSubscriber { +export interface DataSubscriber { /** * The callback to call when a data is received */ @@ -29,12 +29,7 @@ export interface DataSubscriber { /** * The arguments to connect or reconnect to the subscription */ - argsToDto(args: Args): ArgsDto - - /** - * Get the arguments to connect or reconnect to the subscription - */ - get connectionArgs(): Args + getConnectionArgs(): ArgsDto } export function createSubscriptionHandler< diff --git a/packages/transport-http/src/subscribe/models.ts b/packages/transport-http/src/subscribe/models.ts index 48d6aad07..99f99a860 100644 --- a/packages/transport-http/src/subscribe/models.ts +++ b/packages/transport-http/src/subscribe/models.ts @@ -5,12 +5,16 @@ export enum Action { } export interface BaseMessageRequest { action: Action + subscription_id: string } export interface BaseMessageResponse { action?: Action - success: boolean - error_message?: string + error?: { + code: number + message: string + } + subscription_id: string } export interface ListSubscriptionsMessageRequest extends BaseMessageRequest { @@ -31,12 +35,10 @@ export interface SubscribeMessageRequest extends BaseMessageRequest { export interface SubscribeMessageResponse extends BaseMessageResponse { action: Action.SUBSCRIBE topic: string - id: string } export interface UnsubscribeMessageRequest extends BaseMessageRequest { action: Action.UNSUBSCRIBE - id: string } export type UnsubscribeMessageResponse = BaseMessageResponse & { @@ -61,6 +63,19 @@ export type MessageResponse = | UnsubscribeMessageResponse export type SubscriptionDataMessage = { - id: string - data: any + subscription_id: string + payload: any +} +export class SocketError extends Error { + code: number + + private constructor(code: number, message: string) { + super(message) + this.name = "SocketError" + this.code = code + } + + static fromMessage(error: {code: number; message: string}) { + return new SocketError(error.code, error.message) + } } diff --git a/packages/transport-http/src/subscribe/subscription-manager.test.ts b/packages/transport-http/src/subscribe/subscription-manager.test.ts index 0d656ebb9..9815b24a9 100644 --- a/packages/transport-http/src/subscribe/subscription-manager.test.ts +++ b/packages/transport-http/src/subscribe/subscription-manager.test.ts @@ -5,7 +5,6 @@ import { SubscribeMessageRequest, SubscribeMessageResponse, SubscriptionDataMessage, - UnsubscribeMessageRequest, } from "./models" import { SubscriptionManager, @@ -20,7 +19,7 @@ jest.mock("./websocket", () => ({ describe("SubscriptionManager", () => { let mockWs: WS - let mockSubscriber: jest.Mocked> + let mockSubscriber: jest.Mocked> let mockHandler: jest.Mocked> const mockConnectionArgs = {mock: "connection args"} @@ -31,10 +30,7 @@ describe("SubscriptionManager", () => { mockSubscriber = { onData: jest.fn(), onError: jest.fn(), - argsToDto: jest.fn().mockReturnValue(mockConnectionArgs), - get connectionArgs() { - return mockConnectionArgs - }, + getConnectionArgs: jest.fn().mockReturnValue(mockConnectionArgs), } mockHandler = { topic: "topic", @@ -70,14 +66,14 @@ describe("SubscriptionManager", () => { const data = JSON.parse(msg) as SubscribeMessageRequest expect(data).toEqual({ action: "subscribe", + subscription_id: "0", topic, arguments: mockConnectionArgs, }) const response: SubscribeMessageResponse = { - id: "id", + subscription_id: "0", action: Action.SUBSCRIBE, - success: true, topic, } mockWs.send(JSON.stringify(response)) @@ -120,14 +116,14 @@ describe("SubscriptionManager", () => { const data = JSON.parse(msg) as SubscribeMessageRequest expect(data).toEqual({ action: "subscribe", + subscription_id: "0", topic, arguments: mockConnectionArgs, }) const response: SubscribeMessageResponse = { - id: "id", + subscription_id: "0", action: Action.SUBSCRIBE, - success: true, topic, } mockWs.send(JSON.stringify(response)) @@ -148,8 +144,8 @@ describe("SubscriptionManager", () => { serverPromise = (async () => { const data = { - id: "id", - data: {key: "value"}, + subscription_id: "0", + payload: {key: "value"}, } as SubscriptionDataMessage mockWs.send(JSON.stringify(data)) })() @@ -157,20 +153,16 @@ describe("SubscriptionManager", () => { await serverPromise expect(mockSubscriber.onData).toHaveBeenCalledTimes(1) - expect(mockSubscriber.onData).toHaveBeenCalledWith({key: "value"}) + expect(mockSubscriber.onData).toHaveBeenCalledWith({ + key: "value", + }) expect(mockSubscriber.onError).toHaveBeenCalledTimes(0) - serverPromise = (async () => { - const msg = (await mockWs.nextMessage) as string - const data = JSON.parse(msg) as UnsubscribeMessageRequest - expect(data).toEqual({ - action: "unsubscribe", - id: "id", - }) - })() - + // Unsubscribe from the only subscription subscription.unsubscribe() - await serverPromise + + // Connection should be closed as there are no more subscriptions + await mockWs.closed }) test("reconnects to stream on close", async () => { @@ -190,14 +182,14 @@ describe("SubscriptionManager", () => { const data = JSON.parse(msg) as SubscribeMessageRequest expect(data).toEqual({ action: "subscribe", + subscription_id: "0", topic, arguments: mockConnectionArgs, }) const response: SubscribeMessageResponse = { - id: "id1", + subscription_id: "0", action: Action.SUBSCRIBE, - success: true, topic, } mockWs.send(JSON.stringify(response)) @@ -224,8 +216,8 @@ describe("SubscriptionManager", () => { serverPromise = (async () => { const data = { - id: "id1", - data: {key: "value"}, + subscription_id: "0", + payload: {key: "value"}, } as SubscriptionDataMessage mockWs.send(JSON.stringify(data)) })() @@ -233,7 +225,9 @@ describe("SubscriptionManager", () => { await serverPromise expect(mockSubscriber.onData).toHaveBeenCalledTimes(1) - expect(mockSubscriber.onData).toHaveBeenCalledWith({key: "value"}) + expect(mockSubscriber.onData).toHaveBeenCalledWith({ + key: "value", + }) expect(mockSubscriber.onError).toHaveBeenCalledTimes(0) // Close the connection and create a new one @@ -246,15 +240,15 @@ describe("SubscriptionManager", () => { const msg = (await mockWs.nextMessage) as string const data = JSON.parse(msg) as SubscribeMessageRequest expect(data).toEqual({ + subscription_id: "0", action: "subscribe", topic, arguments: mockConnectionArgs, }) const response: SubscribeMessageResponse = { - id: "id2", + subscription_id: "0", action: Action.SUBSCRIBE, - success: true, topic, } mockWs.send(JSON.stringify(response)) @@ -267,8 +261,8 @@ describe("SubscriptionManager", () => { serverPromise = (async () => { const data = { - id: "id2", - data: {key: "value2"}, + subscription_id: "0", + payload: {key: "value2"}, } as SubscriptionDataMessage mockWs.send(JSON.stringify(data)) })() @@ -276,6 +270,10 @@ describe("SubscriptionManager", () => { await serverPromise expect(mockSubscriber.onData).toHaveBeenCalledTimes(2) - expect(mockSubscriber.onData.mock.calls[1]).toEqual([{key: "value2"}]) + expect(mockSubscriber.onData.mock.calls[1]).toEqual([ + { + key: "value2", + }, + ]) }) }) diff --git a/packages/transport-http/src/subscribe/subscription-manager.ts b/packages/transport-http/src/subscribe/subscription-manager.ts index cc9c3bf3e..e0e5cc7e9 100644 --- a/packages/transport-http/src/subscribe/subscription-manager.ts +++ b/packages/transport-http/src/subscribe/subscription-manager.ts @@ -1,14 +1,11 @@ import { Action, + MessageRequest, MessageResponse, + SocketError, SubscriptionDataMessage, UnsubscribeMessageResponse, } from "./models" -import { - SubscribeMessageRequest, - SubscribeMessageResponse, - UnsubscribeMessageRequest, -} from "./models" import {SdkTransport} from "@onflow/typedefs" import {WebSocket} from "./websocket" import {DataSubscriber, SubscriptionHandler} from "./handlers/types" @@ -22,15 +19,13 @@ type DeepRequired = Required<{ type InferHandler = T extends SubscriptionHandler ? H : never -interface SubscriptionInfo { - // Internal ID for the subscription - id: number - // Remote ID assigned by the server used for message routing and unsubscribing - remoteId?: string +interface SubscriptionInfo { + // ID for the subscription + id: string // The topic of the subscription topic: string // Data provider for the subscription - subscriber: DataSubscriber + subscriber: DataSubscriber } export interface SubscriptionManagerConfig { @@ -66,7 +61,7 @@ export class SubscriptionManager[]> { private subscriptions: SubscriptionInfo[] = [] private config: DeepRequired private reconnectAttempts = 0 - private handlers: Record> + private handlers: SubscriptionHandler[] constructor(handlers: Handlers, config: SubscriptionManagerConfig) { this.config = { @@ -78,51 +73,47 @@ export class SubscriptionManager[]> { ...config.reconnectOptions, }, } - - // Map data providers by topic - this.handlers = handlers.reduce( - (acc, handler) => { - acc[handler.topic] = handler - return acc - }, - {} as Record> - ) + this.handlers = handlers } // Lazy connect to the socket when the first subscription is made private async connect() { return new Promise((resolve, reject) => { // If the socket is already open, do nothing - if (this.socket?.readyState === WS_OPEN) { + if (this.socket?.readyState === WS_OPEN || this.socket) { + resolve() return } this.socket = new WebSocket(this.config.node) - this.socket.onmessage = event => { + this.socket.addEventListener("message", event => { const message = JSON.parse(event.data) as | MessageResponse | SubscriptionDataMessage - if ("action" in message) { - // TODO, waiting for AN team to decide what to do here - } else { - // Update the block height to checkpoint for disconnects - this.handleSubscriptionData(message) + // Error message + if ("action" in message && message.error) { + this.handleSocketError(SocketError.fromMessage(message.error)) + return } - } - this.socket.onclose = () => { - void this.reconnect() - } - this.socket.onerror = e => { - this.reconnect(e) - } - this.socket.onopen = () => { + const sub = this.subscriptions.find( + sub => sub.id === message.subscription_id + ) + if (sub) { + if (!("action" in message) && message.subscription_id === sub.id) { + sub.subscriber.onData(message.payload) + } + } + }) + this.socket.addEventListener("close", () => { + void this.handleSocketError(new Error("WebSocket closed")) + }) + this.socket.addEventListener("open", () => { // Restore subscriptions Promise.all( this.subscriptions.map(async sub => { - const response = await this.sendSubscribe(sub) - sub.remoteId = response.id + await this.sendSubscribe(sub) }) ) .then(() => { @@ -131,11 +122,11 @@ export class SubscriptionManager[]> { .catch(e => { reject(new Error(`Failed to restore subscriptions: ${e}`)) }) - } + }) }) } - private async reconnect(error?: any) { + private async handleSocketError(error: any) { // Clear the socket this.socket = null @@ -144,11 +135,6 @@ export class SubscriptionManager[]> { return } - // Clear all remote ids - this.subscriptions.forEach(sub => { - delete sub.remoteId - }) - // Validate the number of reconnection attempts if ( this.reconnectAttempts >= this.config.reconnectOptions.reconnectAttempts @@ -204,119 +190,125 @@ export class SubscriptionManager[]> { // Track the subscription locally const sub: SubscriptionInfo = { - id: this.counter++, + id: String(this.counter++), topic: opts.topic, subscriber: subscriber, } this.subscriptions.push(sub) // Send the subscribe message - const response = await this.sendSubscribe(sub) - - if (!response.success) { - throw new Error( - `Failed to subscribe to topic ${sub.topic}, error message: ${response.error_message}` - ) + try { + const response = await this.sendSubscribe(sub) + if (response.error) { + throw new Error(`Failed to subscribe to topic ${sub.topic}`, { + cause: SocketError.fromMessage(response.error), + }) + } + } catch (e) { + // Unsubscribe if there was an error + this.unsubscribe(sub.id) + throw e } - // Update the subscription with the remote id - sub.remoteId = response.id - return { - unsubscribe: () => this.unsubscribe(sub.id), + unsubscribe: () => { + this.unsubscribe(sub.id) + }, } } - private unsubscribe(id: number): void { + private unsubscribe(id: string): void { // Get the subscription const sub = this.subscriptions.find(sub => sub.id === id) if (!sub) return - // Send the unsubscribe message - this.sendUnsubscribe(sub).catch(e => { - console.error( - `Failed to unsubscribe from topic ${sub.topic}, error: ${e}` - ) - }) - // Remove the subscription this.subscriptions = this.subscriptions.filter(sub => sub.id !== id) // Close the socket if there are no more subscriptions if (this.subscriptions.length === 0) { this.socket?.close() + return } + + // Otherwise, the unsubscribe message + this.sendUnsubscribe(sub).catch(e => { + console.error(`Error while unsubscribing from topic: ${e}`) + }) } private async sendSubscribe(sub: SubscriptionInfo) { // Send the subscription message - const request: SubscribeMessageRequest = { + const request: MessageRequest = { action: Action.SUBSCRIBE, topic: sub.topic, - arguments: sub.subscriber.connectionArgs, + arguments: sub.subscriber.getConnectionArgs(), + subscription_id: String(sub.id), } - this.socket?.send(JSON.stringify(request)) - - const response: SubscribeMessageResponse = await this.waitForResponse() - if (!response.success) { - throw new Error( - `Failed to subscribe to topic ${sub.topic}, error message: ${response.error_message}` - ) + const response = await this.request(request) + if (response.error) { + throw new Error(`Failed to subscribe to topic ${sub.topic}`, { + cause: SocketError.fromMessage(response.error), + }) } - return response } private async sendUnsubscribe(sub: SubscriptionInfo) { // Send the unsubscribe message if the subscription has a remote id - const {remoteId} = sub - if (remoteId) { - const request: UnsubscribeMessageRequest = { - action: Action.UNSUBSCRIBE, - id: remoteId, + const request: MessageRequest = { + action: Action.UNSUBSCRIBE, + subscription_id: sub.id, + } + this.socket?.send(JSON.stringify(request)) + + const response: UnsubscribeMessageResponse = (await this.request( + request + )) as UnsubscribeMessageResponse + if (response.error) { + throw new Error(`Failed to unsubscribe from topic ${sub.topic}`, { + cause: SocketError.fromMessage(response.error), + }) + } + + return response + } + + private async request(request: MessageRequest): Promise { + return new Promise((resolve, reject) => { + if (!this.socket) { + reject(new Error("WebSocket is not connected")) + return } - this.socket?.send(JSON.stringify(request)) - const response: UnsubscribeMessageResponse = await this.waitForResponse() + // Bind event listeners + this.socket.addEventListener("error", onError) + this.socket.addEventListener("message", onMessage) + this.socket.addEventListener("close", onClose) - if (!response.success) { - throw new Error( - `Failed to unsubscribe from topic ${sub.topic}, error message: ${response.error_message}` - ) + // Send the request + this.socket.send(JSON.stringify(request)) + + function onError(e: WebSocketEventMap["error"]) { + reject(new Error(`WebSocket error: ${e}`)) } - } - } - private async waitForResponse(): Promise { - // TODO: NOOP, waiting for AN team to decide what to do here, this is a placeholder - return new Promise(resolve => { - this.socket?.addEventListener("message", event => { - const data = JSON.parse(event.data) as T - if (data.action) { + function onClose() { + reject(new Error("WebSocket closed")) + } + + function onMessage(event: MessageEvent) { + const data = JSON.parse(event.data) as MessageResponse + if (data.subscription_id === request.subscription_id) { resolve(data) } - }) + } }) } - // Update the subscription checkpoint when a message is received - // These checkpoints are used to resume subscriptions after disconnects - private handleSubscriptionData< - T extends SdkTransport.SubscriptionTopic = SdkTransport.SubscriptionTopic, - >(message: SubscriptionDataMessage) { - // Get the subscription - const sub = this.subscriptions.find(sub => sub.remoteId === message.id) - if (!sub) { - throw new Error(`No subscription found for id ${message.id}`) - } - - // Send data to the subscriber - sub.subscriber.onData(message.data) - } - private getHandler(topic: string) { - const handler = this.handlers[topic] + const handler = this.handlers.find(handler => handler.topic === topic) if (!handler) { throw new Error(`No handler found for topic ${topic}`) } diff --git a/tsconfig.json b/tsconfig.json index e7b5d0a60..b78084255 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,6 +5,8 @@ "moduleResolution": "Bundler", "module": "ESNext", "target": "ES2015", + // Useful for error cause + "lib": ["ES2015", "WebWorker", "DOM", "ES2022.Error"], "types": ["node", "jest"], // Tells TypeScript to read JS files, as // normally they are ignored as source files From c932ba902f1fc3826e35504719647a3fadf1ae50 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Fri, 14 Mar 2025 15:56:03 -0700 Subject: [PATCH 04/72] PKG -- [transport-http] Add Blocks DataProvider (#2033) --- .../src/subscribe/handlers/blocks.ts | 107 ++++++++++++++++++ .../transport-http/src/subscribe/subscribe.ts | 3 +- packages/typedefs/src/index.ts | 6 +- .../src/sdk-transport/subscriptions.ts | 18 ++- 4 files changed, 123 insertions(+), 11 deletions(-) create mode 100644 packages/transport-http/src/subscribe/handlers/blocks.ts diff --git a/packages/transport-http/src/subscribe/handlers/blocks.ts b/packages/transport-http/src/subscribe/handlers/blocks.ts new file mode 100644 index 000000000..83cce9c94 --- /dev/null +++ b/packages/transport-http/src/subscribe/handlers/blocks.ts @@ -0,0 +1,107 @@ +import {SdkTransport} from "@onflow/typedefs" +import {createSubscriptionHandler} from "./types" + +type BlocksArgs = + SdkTransport.SubscriptionArguments + +type BlocksData = + SdkTransport.SubscriptionData + +type BlocksDataDto = { + header: { + id: string + parent_id: string + height: string + timestamp: string + } + payload: { + collection_guarantees: { + collection_id: string + signer_indices: string[] + }[] + block_seals: { + block_id: string + result_id: string + }[] + } +} + +type BlocksArgsDto = {block_status: "finalized" | "sealed"} & ( + | { + start_block_id?: string + } + | { + start_block_height?: string + } +) + +export const blocksHandler = createSubscriptionHandler<{ + Topic: SdkTransport.SubscriptionTopic.BLOCKS + Args: BlocksArgs + Data: BlocksData + ArgsDto: BlocksArgsDto + DataDto: BlocksDataDto +}>({ + topic: SdkTransport.SubscriptionTopic.BLOCKS, + createSubscriber: (initialArgs, onData, onError) => { + let resumeArgs: BlocksArgs = { + ...initialArgs, + } + + return { + onData(data: BlocksDataDto) { + // Parse the raw data + const parsedData: BlocksData = { + block: { + id: data.header.id, + parentId: data.header.parent_id, + height: Number(data.header.height), + timestamp: data.header.timestamp, + collectionGuarantees: data.payload.collection_guarantees.map( + guarantee => ({ + collectionId: guarantee.collection_id, + signerIds: guarantee.signer_indices, + }) + ), + blockSeals: data.payload.block_seals.map(seal => ({ + blockId: seal.block_id, + executionReceiptId: seal.result_id, + })), + }, + } + + // Update the resume args + resumeArgs = { + blockStatus: resumeArgs.blockStatus, + startBlockHeight: Number(BigInt(data.header.height) + BigInt(1)), + } + + onData(parsedData) + }, + onError(error: Error) { + onError(error) + }, + getConnectionArgs() { + let encodedArgs: BlocksArgsDto = { + block_status: resumeArgs.blockStatus, + } + + if ("startBlockHeight" in resumeArgs) { + return { + ...encodedArgs, + start_block_height: String(resumeArgs.startBlockHeight), + } + } + + if ("startBlockId" in resumeArgs) { + return { + ...encodedArgs, + start_block_id: resumeArgs.startBlockId, + } + } + + return encodedArgs + }, + } + }, +}) diff --git a/packages/transport-http/src/subscribe/subscribe.ts b/packages/transport-http/src/subscribe/subscribe.ts index 9f47a0f5d..3daf07823 100644 --- a/packages/transport-http/src/subscribe/subscribe.ts +++ b/packages/transport-http/src/subscribe/subscribe.ts @@ -1,7 +1,8 @@ import {SdkTransport} from "@onflow/typedefs" import {SubscriptionManager} from "./subscription-manager" +import {blocksHandler} from "./handlers/blocks" -const SUBSCRIPTION_HANDLERS: any[] = [] +const SUBSCRIPTION_HANDLERS = [blocksHandler] // Map of SubscriptionManager instances by access node URL let subscriptionManagerMap: Map< diff --git a/packages/typedefs/src/index.ts b/packages/typedefs/src/index.ts index b9d516de3..4f92c10f9 100644 --- a/packages/typedefs/src/index.ts +++ b/packages/typedefs/src/index.ts @@ -99,10 +99,6 @@ export type Block = { * - The details of which nodes executed and sealed the blocks */ blockSeals: Array - /** - * - The cryptographic signature of the block - */ - signatures: Array } export type CollectionGuarantee = { /** @@ -112,7 +108,7 @@ export type CollectionGuarantee = { /** * - The signer ids of the block */ - signerIds: Array + signerIds: Array } export type BlockSeal = { /** diff --git a/packages/typedefs/src/sdk-transport/subscriptions.ts b/packages/typedefs/src/sdk-transport/subscriptions.ts index 53240d183..c188cf8be 100644 --- a/packages/typedefs/src/sdk-transport/subscriptions.ts +++ b/packages/typedefs/src/sdk-transport/subscriptions.ts @@ -1,18 +1,26 @@ +import {Block} from ".." + type SchemaItem = { args: TArgs data: TData } -// TODO: PLACEHOLDER - Replace with actual subscription topics export enum SubscriptionTopic { - PLACEHOLDER = "PLACEHOLDER", + BLOCKS = "blocks", } export type SubscriptionSchema = { - [SubscriptionTopic.PLACEHOLDER]: SchemaItem< - {}, + [SubscriptionTopic.BLOCKS]: SchemaItem< + | { + blockStatus: "finalized" | "sealed" + startBlockId?: string + } + | { + blockStatus: "finalized" | "sealed" + startBlockHeight?: number + }, { - placeholder: string + block: Block } > } From 095156161af700668b43e676793730d40555239c Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Mon, 17 Mar 2025 12:36:02 -0700 Subject: [PATCH 05/72] PKG -- [transport-http] Add BlockDigests DataProvider (#2034) --- packages/sdk/src/decode/decode.js | 2 + packages/sdk/src/integration.test.ts | 68 +++++++++++++++++ .../src/subscribe/handlers/block-digests.ts | 76 +++++++++++++++++++ .../src/subscribe/handlers/blocks.ts | 15 +--- .../src/subscribe/handlers/types.ts | 10 +++ .../transport-http/src/subscribe/subscribe.ts | 3 +- packages/typedefs/src/index.ts | 17 +++++ .../src/sdk-transport/subscriptions.ts | 44 ++++++----- 8 files changed, 205 insertions(+), 30 deletions(-) create mode 100644 packages/sdk/src/integration.test.ts create mode 100644 packages/transport-http/src/subscribe/handlers/block-digests.ts diff --git a/packages/sdk/src/decode/decode.js b/packages/sdk/src/decode/decode.js index 1d211e23c..e91977c4c 100644 --- a/packages/sdk/src/decode/decode.js +++ b/packages/sdk/src/decode/decode.js @@ -208,6 +208,8 @@ export const decodeResponse = async (response, customDecoders = {}) => { return response.block } else if (response.blockHeader) { return response.blockHeader + } else if (response.blockDigest) { + return response.blockDigest } else if (response.latestBlock) { latestBlockDeprecationNotice() return response.latestBlock diff --git a/packages/sdk/src/integration.test.ts b/packages/sdk/src/integration.test.ts new file mode 100644 index 000000000..94c9bdd03 --- /dev/null +++ b/packages/sdk/src/integration.test.ts @@ -0,0 +1,68 @@ +import {SdkTransport} from "@onflow/typedefs" +import {subscribe} from "./sdk" +import {on} from "events" + +jest.setTimeout(30000) + +test("subscribe blocks", async () => { + const test = await subscribe( + { + topic: SdkTransport.SubscriptionTopic.BLOCKS, + args: {blockStatus: "sealed"}, + onData: data => { + console.log(data) + }, + onError: error => { + console.error(error) + }, + }, + { + node: "ws://92.253.238.247/v1/ws", + } + ) + + await new Promise(resolve => setTimeout(resolve, 10000)) + + test.unsubscribe() + + await new Promise(resolve => setTimeout(resolve, 5000)) +}) + +test("subscribe block digests", async () => { + const onData = jest.fn() + const onError = jest.fn() + + const test = await subscribe( + { + topic: SdkTransport.SubscriptionTopic.BLOCK_DIGESTS, + args: {blockStatus: "sealed"}, + onData, + onError, + }, + { + node: "ws://92.253.238.247/v1/ws", + } + ) + + await new Promise(resolve => setTimeout(resolve, 10000)) + + // Check that we received data and that it is in the correct format + onData.mock.calls.forEach(([data]) => { + expect(data).toMatchObject({ + id: expect.any(String), + height: expect.any(Number), + timestamp: expect.any(String), + }) + }) + expect(onError).not.toHaveBeenCalled() + + onData.mockClear() + onError.mockClear() + + test.unsubscribe() + + await new Promise(resolve => setTimeout(resolve, 5000)) + + expect(onData).not.toHaveBeenCalled() + expect(onError).not.toHaveBeenCalled() +}) diff --git a/packages/transport-http/src/subscribe/handlers/block-digests.ts b/packages/transport-http/src/subscribe/handlers/block-digests.ts new file mode 100644 index 000000000..0cf9a05d0 --- /dev/null +++ b/packages/transport-http/src/subscribe/handlers/block-digests.ts @@ -0,0 +1,76 @@ +import {SdkTransport} from "@onflow/typedefs" +import {BlockArgsDto, createSubscriptionHandler} from "./types" + +type BlockDigestsArgs = + SdkTransport.SubscriptionArguments + +type BlockDigestsData = + SdkTransport.SubscriptionData + +type BlockDigestsDataDto = { + block_id: string + height: string + timestamp: string +} + +type BlockDigestsArgsDto = BlockArgsDto + +export const blockDigestsHandler = createSubscriptionHandler<{ + Topic: SdkTransport.SubscriptionTopic.BLOCK_DIGESTS + Args: BlockDigestsArgs + Data: BlockDigestsData + ArgsDto: BlockDigestsArgsDto + DataDto: BlockDigestsDataDto +}>({ + topic: SdkTransport.SubscriptionTopic.BLOCK_DIGESTS, + createSubscriber: (initialArgs, onData, onError) => { + let resumeArgs: BlockDigestsArgs = { + ...initialArgs, + } + + return { + onData(data: BlockDigestsDataDto) { + // Parse the raw data + const parsedData: BlockDigestsData = { + blockDigest: { + id: data.block_id, + height: Number(data.height), + timestamp: data.timestamp, + }, + } + + // Update the resume args + resumeArgs = { + blockStatus: resumeArgs.blockStatus, + startBlockId: String(BigInt(data.height) + BigInt(1)), + } + + onData(parsedData) + }, + onError(error: Error) { + onError(error) + }, + getConnectionArgs() { + let encodedArgs: BlockDigestsArgsDto = { + block_status: resumeArgs.blockStatus, + } + + if ("startBlockHeight" in resumeArgs) { + return { + ...encodedArgs, + start_block_height: resumeArgs.startBlockHeight, + } + } + + if ("startBlockId" in resumeArgs) { + return { + ...encodedArgs, + start_block_id: resumeArgs.startBlockId, + } + } + + return encodedArgs + }, + } + }, +}) diff --git a/packages/transport-http/src/subscribe/handlers/blocks.ts b/packages/transport-http/src/subscribe/handlers/blocks.ts index 83cce9c94..669d78cb2 100644 --- a/packages/transport-http/src/subscribe/handlers/blocks.ts +++ b/packages/transport-http/src/subscribe/handlers/blocks.ts @@ -1,5 +1,5 @@ import {SdkTransport} from "@onflow/typedefs" -import {createSubscriptionHandler} from "./types" +import {createSubscriptionHandler, BlockArgsDto} from "./types" type BlocksArgs = SdkTransport.SubscriptionArguments @@ -26,20 +26,11 @@ type BlocksDataDto = { } } -type BlocksArgsDto = {block_status: "finalized" | "sealed"} & ( - | { - start_block_id?: string - } - | { - start_block_height?: string - } -) - export const blocksHandler = createSubscriptionHandler<{ Topic: SdkTransport.SubscriptionTopic.BLOCKS Args: BlocksArgs Data: BlocksData - ArgsDto: BlocksArgsDto + ArgsDto: BlockArgsDto DataDto: BlocksDataDto }>({ topic: SdkTransport.SubscriptionTopic.BLOCKS, @@ -82,7 +73,7 @@ export const blocksHandler = createSubscriptionHandler<{ onError(error) }, getConnectionArgs() { - let encodedArgs: BlocksArgsDto = { + let encodedArgs: BlockArgsDto = { block_status: resumeArgs.blockStatus, } diff --git a/packages/transport-http/src/subscribe/handlers/types.ts b/packages/transport-http/src/subscribe/handlers/types.ts index bbda38e85..1ca01167f 100644 --- a/packages/transport-http/src/subscribe/handlers/types.ts +++ b/packages/transport-http/src/subscribe/handlers/types.ts @@ -43,3 +43,13 @@ export function createSubscriptionHandler< >(handler: SubscriptionHandler): SubscriptionHandler { return handler } + +export type BlockArgsDto = + | { + block_status?: "finalized" | "sealed" + start_block_id?: string + } + | { + block_status?: "finalized" | "sealed" + start_block_height?: number + } diff --git a/packages/transport-http/src/subscribe/subscribe.ts b/packages/transport-http/src/subscribe/subscribe.ts index 3daf07823..cebf511bd 100644 --- a/packages/transport-http/src/subscribe/subscribe.ts +++ b/packages/transport-http/src/subscribe/subscribe.ts @@ -1,8 +1,9 @@ import {SdkTransport} from "@onflow/typedefs" import {SubscriptionManager} from "./subscription-manager" import {blocksHandler} from "./handlers/blocks" +import {blockDigestsHandler} from "./handlers/block-digests" -const SUBSCRIPTION_HANDLERS = [blocksHandler] +const SUBSCRIPTION_HANDLERS = [blocksHandler, blockDigestsHandler] // Map of SubscriptionManager instances by access node URL let subscriptionManagerMap: Map< diff --git a/packages/typedefs/src/index.ts b/packages/typedefs/src/index.ts index 4f92c10f9..8a6728d8e 100644 --- a/packages/typedefs/src/index.ts +++ b/packages/typedefs/src/index.ts @@ -120,6 +120,23 @@ export type BlockSeal = { */ executionReceiptId: string } +/** + * BlockDigest holds lightweight block information which includes only block id, block height and block timestamp. + */ +export type BlockDigest = { + /** + * - The id of the block + */ + id: string + /** + * - The height of the block + */ + height: number + /** + * - Timestamp of the block + */ + timestamp: string +} export type CompositeSignature = { /** * - A type identifier used internally by FCL diff --git a/packages/typedefs/src/sdk-transport/subscriptions.ts b/packages/typedefs/src/sdk-transport/subscriptions.ts index c188cf8be..3cc176e7a 100644 --- a/packages/typedefs/src/sdk-transport/subscriptions.ts +++ b/packages/typedefs/src/sdk-transport/subscriptions.ts @@ -1,28 +1,38 @@ -import {Block} from ".." +import {Block, BlockDigest} from ".." -type SchemaItem = { - args: TArgs - data: TData +export type SubscriptionSchema = { + [SubscriptionTopic.BLOCKS]: SchemaItem< + BlockArgs, + { + block: Block + } + > + [SubscriptionTopic.BLOCK_DIGESTS]: SchemaItem< + BlockArgs, + { + blockDigest: BlockDigest + } + > } export enum SubscriptionTopic { BLOCKS = "blocks", + BLOCK_DIGESTS = "block_digests", } -export type SubscriptionSchema = { - [SubscriptionTopic.BLOCKS]: SchemaItem< - | { - blockStatus: "finalized" | "sealed" - startBlockId?: string - } - | { - blockStatus: "finalized" | "sealed" - startBlockHeight?: number - }, - { - block: Block +type BlockArgs = + | { + blockStatus: "finalized" | "sealed" + startBlockId?: string } - > + | { + blockStatus: "finalized" | "sealed" + startBlockHeight?: number + } + +type SchemaItem = { + args: TArgs + data: TData } export type SubscriptionArguments = From 694cd76807b7ca4441d1f8425ac4f8426cbc18fa Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Mon, 17 Mar 2025 15:18:46 -0700 Subject: [PATCH 06/72] PKG -- [transport-http] Add BlockHeaders DataProvider (#2035) --- .changeset/spicy-fishes-drum.md | 5 ++ .../transport-http/src/send/send-get-block.js | 1 + .../src/subscribe/handlers/block-headers.ts | 80 +++++++++++++++++++ .../src/subscribe/handlers/blocks.ts | 2 + .../src/subscribe/handlers/types.ts | 2 +- .../transport-http/src/subscribe/subscribe.ts | 7 +- packages/typedefs/src/index.ts | 31 +++++++ .../src/sdk-transport/subscriptions.ts | 9 ++- 8 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 .changeset/spicy-fishes-drum.md create mode 100644 packages/transport-http/src/subscribe/handlers/block-headers.ts diff --git a/.changeset/spicy-fishes-drum.md b/.changeset/spicy-fishes-drum.md new file mode 100644 index 000000000..94376ec18 --- /dev/null +++ b/.changeset/spicy-fishes-drum.md @@ -0,0 +1,5 @@ +--- +"@onflow/transport-http": patch +--- + +Add `parentVoterSignature` field to GetBlock request diff --git a/packages/transport-http/src/send/send-get-block.js b/packages/transport-http/src/send/send-get-block.js index ac931a604..62d00b17f 100644 --- a/packages/transport-http/src/send/send-get-block.js +++ b/packages/transport-http/src/send/send-get-block.js @@ -52,6 +52,7 @@ function constructResponse(ix, context, res) { parentId: block.header.parent_id, height: Number(block.header.height), timestamp: block.header.timestamp, + parentVoterSignature: block.header.parent_voter_signature, collectionGuarantees: block.payload.collection_guarantees.map( collectionGuarantee => ({ collectionId: collectionGuarantee.collection_id, diff --git a/packages/transport-http/src/subscribe/handlers/block-headers.ts b/packages/transport-http/src/subscribe/handlers/block-headers.ts new file mode 100644 index 000000000..bf9d51bde --- /dev/null +++ b/packages/transport-http/src/subscribe/handlers/block-headers.ts @@ -0,0 +1,80 @@ +import {SdkTransport} from "@onflow/typedefs" +import {BlockArgsDto, createSubscriptionHandler} from "./types" + +type BlockHeadersArgs = + SdkTransport.SubscriptionArguments + +type BlockHeadersData = + SdkTransport.SubscriptionData + +type BlockHeadersArgsDto = BlockArgsDto + +type BlockHeadersDataDto = { + id: string + parent_id: string + height: string + timestamp: string + parent_voter_signature: string +} + +export const blockHeadersHandler = createSubscriptionHandler<{ + Topic: SdkTransport.SubscriptionTopic.BLOCK_HEADERS + Args: BlockHeadersArgs + Data: BlockHeadersData + ArgsDto: BlockHeadersArgsDto + DataDto: BlockHeadersDataDto +}>({ + topic: SdkTransport.SubscriptionTopic.BLOCK_HEADERS, + createSubscriber: (initialArgs, onData, onError) => { + let resumeArgs: BlockHeadersArgs = { + ...initialArgs, + } + + return { + onData(data: BlockHeadersDataDto) { + // Parse the raw data + const parsedData: BlockHeadersData = { + blockHeader: { + id: data.id, + parentId: data.parent_id, + height: Number(data.height), + timestamp: data.timestamp, + parentVoterSignature: data.parent_voter_signature, + }, + } + + // Update the resume args + resumeArgs = { + blockStatus: resumeArgs.blockStatus, + startBlockHeight: Number(BigInt(data.height) + BigInt(1)), + } + + onData(parsedData) + }, + onError(error: Error) { + onError(error) + }, + getConnectionArgs() { + let encodedArgs: BlockHeadersArgsDto = { + block_status: resumeArgs.blockStatus, + } + + if ("startBlockHeight" in resumeArgs) { + return { + ...encodedArgs, + start_block_height: resumeArgs.startBlockHeight, + } + } + + if ("startBlockId" in resumeArgs) { + return { + ...encodedArgs, + start_block_id: resumeArgs.startBlockId, + } + } + + return encodedArgs + }, + } + }, +}) diff --git a/packages/transport-http/src/subscribe/handlers/blocks.ts b/packages/transport-http/src/subscribe/handlers/blocks.ts index 669d78cb2..c552ebd16 100644 --- a/packages/transport-http/src/subscribe/handlers/blocks.ts +++ b/packages/transport-http/src/subscribe/handlers/blocks.ts @@ -13,6 +13,7 @@ type BlocksDataDto = { parent_id: string height: string timestamp: string + parent_voter_signature: string } payload: { collection_guarantees: { @@ -48,6 +49,7 @@ export const blocksHandler = createSubscriptionHandler<{ parentId: data.header.parent_id, height: Number(data.header.height), timestamp: data.header.timestamp, + parentVoterSignature: data.header.parent_voter_signature, collectionGuarantees: data.payload.collection_guarantees.map( guarantee => ({ collectionId: guarantee.collection_id, diff --git a/packages/transport-http/src/subscribe/handlers/types.ts b/packages/transport-http/src/subscribe/handlers/types.ts index 1ca01167f..8606780bb 100644 --- a/packages/transport-http/src/subscribe/handlers/types.ts +++ b/packages/transport-http/src/subscribe/handlers/types.ts @@ -27,7 +27,7 @@ export interface DataSubscriber { onError(error: Error): void /** - * The arguments to connect or reconnect to the subscription + * Get the arguments to connect or reconnect to the subscription */ getConnectionArgs(): ArgsDto } diff --git a/packages/transport-http/src/subscribe/subscribe.ts b/packages/transport-http/src/subscribe/subscribe.ts index cebf511bd..792d8062a 100644 --- a/packages/transport-http/src/subscribe/subscribe.ts +++ b/packages/transport-http/src/subscribe/subscribe.ts @@ -1,9 +1,14 @@ import {SdkTransport} from "@onflow/typedefs" import {SubscriptionManager} from "./subscription-manager" import {blocksHandler} from "./handlers/blocks" +import {blockHeadersHandler} from "./handlers/block-headers" import {blockDigestsHandler} from "./handlers/block-digests" -const SUBSCRIPTION_HANDLERS = [blocksHandler, blockDigestsHandler] +const SUBSCRIPTION_HANDLERS = [ + blocksHandler, + blockDigestsHandler, + blockHeadersHandler, +] // Map of SubscriptionManager instances by access node URL let subscriptionManagerMap: Map< diff --git a/packages/typedefs/src/index.ts b/packages/typedefs/src/index.ts index 8a6728d8e..02b06f0fb 100644 --- a/packages/typedefs/src/index.ts +++ b/packages/typedefs/src/index.ts @@ -91,6 +91,10 @@ export type Block = { * - Time related fields */ timestamp: string + /** + * - The parent voter signature of the block + */ + parentVoterSignature: string /** * - Contains the ids of collections included in the block */ @@ -137,6 +141,33 @@ export type BlockDigest = { */ timestamp: string } +/** + * Header contains all meta-data for a block, as well as a hash representing + * the combined payload of the entire block. It is what consensus nodes agree + * on after validating the contents against the payload hash. + */ +export type BlockHeader = { + /** + * - The id of the block + */ + id: string + /** + * - The id of the parent block + */ + parentId: string + /** + * - The height of the block + */ + height: number + /** + * - The timestamp of the block + */ + timestamp: string + /** + * - The parent voter signature of the block + */ + parentVoterSignature: string +} export type CompositeSignature = { /** * - A type identifier used internally by FCL diff --git a/packages/typedefs/src/sdk-transport/subscriptions.ts b/packages/typedefs/src/sdk-transport/subscriptions.ts index 3cc176e7a..033171879 100644 --- a/packages/typedefs/src/sdk-transport/subscriptions.ts +++ b/packages/typedefs/src/sdk-transport/subscriptions.ts @@ -1,4 +1,4 @@ -import {Block, BlockDigest} from ".." +import {Block, BlockDigest, BlockHeader} from ".." export type SubscriptionSchema = { [SubscriptionTopic.BLOCKS]: SchemaItem< @@ -13,11 +13,18 @@ export type SubscriptionSchema = { blockDigest: BlockDigest } > + [SubscriptionTopic.BLOCK_HEADERS]: SchemaItem< + BlockArgs, + { + blockHeader: BlockHeader + } + > } export enum SubscriptionTopic { BLOCKS = "blocks", BLOCK_DIGESTS = "block_digests", + BLOCK_HEADERS = "block_headers", } type BlockArgs = From 53f606ce3dae37f8ea48734dfcf1ffd93a7f2523 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Fri, 21 Mar 2025 10:21:04 -0700 Subject: [PATCH 07/72] PKG -- [transport-http] Add TransactionStatuses DataProvider (#2041) --- package-lock.json | 3 + packages/sdk/src/integration.test.ts | 68 -------------- packages/transport-http/package.json | 1 + .../handlers/transaction-statuses.ts | 93 +++++++++++++++++++ .../transport-http/src/subscribe/subscribe.ts | 2 + packages/typedefs/src/index.ts | 4 - .../src/sdk-transport/subscriptions.ts | 32 ++++++- 7 files changed, 130 insertions(+), 73 deletions(-) delete mode 100644 packages/sdk/src/integration.test.ts create mode 100644 packages/transport-http/src/subscribe/handlers/transaction-statuses.ts diff --git a/package-lock.json b/package-lock.json index e2c0ac964..36ad49073 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11166,6 +11166,8 @@ }, "node_modules/buffer": { "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "funding": [ { "type": "github", @@ -29199,6 +29201,7 @@ "@onflow/util-logger": "1.3.3", "@onflow/util-template": "1.2.3", "abort-controller": "^3.0.0", + "buffer": "^6.0.3", "cross-fetch": "^4.0.0", "events": "^3.3.0", "isomorphic-ws": "^5.0.0", diff --git a/packages/sdk/src/integration.test.ts b/packages/sdk/src/integration.test.ts deleted file mode 100644 index 94c9bdd03..000000000 --- a/packages/sdk/src/integration.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import {SdkTransport} from "@onflow/typedefs" -import {subscribe} from "./sdk" -import {on} from "events" - -jest.setTimeout(30000) - -test("subscribe blocks", async () => { - const test = await subscribe( - { - topic: SdkTransport.SubscriptionTopic.BLOCKS, - args: {blockStatus: "sealed"}, - onData: data => { - console.log(data) - }, - onError: error => { - console.error(error) - }, - }, - { - node: "ws://92.253.238.247/v1/ws", - } - ) - - await new Promise(resolve => setTimeout(resolve, 10000)) - - test.unsubscribe() - - await new Promise(resolve => setTimeout(resolve, 5000)) -}) - -test("subscribe block digests", async () => { - const onData = jest.fn() - const onError = jest.fn() - - const test = await subscribe( - { - topic: SdkTransport.SubscriptionTopic.BLOCK_DIGESTS, - args: {blockStatus: "sealed"}, - onData, - onError, - }, - { - node: "ws://92.253.238.247/v1/ws", - } - ) - - await new Promise(resolve => setTimeout(resolve, 10000)) - - // Check that we received data and that it is in the correct format - onData.mock.calls.forEach(([data]) => { - expect(data).toMatchObject({ - id: expect.any(String), - height: expect.any(Number), - timestamp: expect.any(String), - }) - }) - expect(onError).not.toHaveBeenCalled() - - onData.mockClear() - onError.mockClear() - - test.unsubscribe() - - await new Promise(resolve => setTimeout(resolve, 5000)) - - expect(onData).not.toHaveBeenCalled() - expect(onError).not.toHaveBeenCalled() -}) diff --git a/packages/transport-http/package.json b/packages/transport-http/package.json index 11f73d46f..6c1da04c4 100644 --- a/packages/transport-http/package.json +++ b/packages/transport-http/package.json @@ -41,6 +41,7 @@ "@onflow/util-logger": "1.3.3", "@onflow/util-template": "1.2.3", "abort-controller": "^3.0.0", + "buffer": "^6.0.3", "cross-fetch": "^4.0.0", "events": "^3.3.0", "isomorphic-ws": "^5.0.0", diff --git a/packages/transport-http/src/subscribe/handlers/transaction-statuses.ts b/packages/transport-http/src/subscribe/handlers/transaction-statuses.ts new file mode 100644 index 000000000..35a9a072c --- /dev/null +++ b/packages/transport-http/src/subscribe/handlers/transaction-statuses.ts @@ -0,0 +1,93 @@ +import {SdkTransport} from "@onflow/typedefs" +import {createSubscriptionHandler} from "./types" +import {Buffer} from "buffer" + +const STATUS_MAP = { + UNKNOWN: 0, + PENDING: 1, + FINALIZED: 2, + EXECUTED: 3, + SEALED: 4, + EXPIRED: 5, +} + +type TransactionStatusesArgs = + SdkTransport.SubscriptionArguments + +type TransactionStatusesData = + SdkTransport.SubscriptionData + +type TransactionStatusesArgsDto = { + tx_id: string +} + +type TransactionStatusesDataDto = { + transaction_result: { + block_id: string + collection_id: string + execution: string + status: string + status_code: 0 | 1 + error_message: string + computation_used: string + events: { + type: string + transaction_id: string + transaction_index: string + event_index: string + payload: string + }[] + } +} + +export const transactionStatusesHandler = createSubscriptionHandler<{ + Topic: SdkTransport.SubscriptionTopic.TRANSACTION_STATUSES + Args: TransactionStatusesArgs + Data: TransactionStatusesData + ArgsDto: TransactionStatusesArgsDto + DataDto: TransactionStatusesDataDto +}>({ + topic: SdkTransport.SubscriptionTopic.TRANSACTION_STATUSES, + createSubscriber: (initialArgs, onData, onError) => { + let resumeArgs: TransactionStatusesArgs = { + ...initialArgs, + } + + return { + onData(data: TransactionStatusesDataDto) { + // Parse the raw data + const parsedData: TransactionStatusesData = { + transactionStatus: { + blockId: data.transaction_result.block_id, + status: + STATUS_MAP[ + data.transaction_result.status.toUpperCase() as keyof typeof STATUS_MAP + ], + statusString: data.transaction_result.status.toUpperCase(), + statusCode: data.transaction_result.status_code, + errorMessage: data.transaction_result.error_message, + events: data.transaction_result.events.map(event => ({ + type: event.type, + transactionId: event.transaction_id, + transactionIndex: Number(event.transaction_index), + eventIndex: Number(event.event_index), + payload: JSON.parse( + Buffer.from(event.payload, "base64").toString() + ), + })), + }, + } + + onData(parsedData) + }, + onError(error: Error) { + onError(error) + }, + getConnectionArgs() { + return { + tx_id: resumeArgs.transactionId, + } + }, + } + }, +}) diff --git a/packages/transport-http/src/subscribe/subscribe.ts b/packages/transport-http/src/subscribe/subscribe.ts index 792d8062a..743e6697f 100644 --- a/packages/transport-http/src/subscribe/subscribe.ts +++ b/packages/transport-http/src/subscribe/subscribe.ts @@ -3,11 +3,13 @@ import {SubscriptionManager} from "./subscription-manager" import {blocksHandler} from "./handlers/blocks" import {blockHeadersHandler} from "./handlers/block-headers" import {blockDigestsHandler} from "./handlers/block-digests" +import {transactionStatusesHandler} from "./handlers/transaction-statuses" const SUBSCRIPTION_HANDLERS = [ blocksHandler, blockDigestsHandler, blockHeadersHandler, + transactionStatusesHandler, ] // Map of SubscriptionManager instances by access node URL diff --git a/packages/typedefs/src/index.ts b/packages/typedefs/src/index.ts index f6e0028eb..f2f541db9 100644 --- a/packages/typedefs/src/index.ts +++ b/packages/typedefs/src/index.ts @@ -343,10 +343,6 @@ export type Transaction = { * - The ID of the key in the account used by the proposer of this transaction. */ keyId: number - /** - * - The address of the proposer of this transaction. - */ - address: string /** * - Address of the payer of the transaction. */ diff --git a/packages/typedefs/src/sdk-transport/subscriptions.ts b/packages/typedefs/src/sdk-transport/subscriptions.ts index 033171879..1fae76ef9 100644 --- a/packages/typedefs/src/sdk-transport/subscriptions.ts +++ b/packages/typedefs/src/sdk-transport/subscriptions.ts @@ -1,4 +1,10 @@ -import {Block, BlockDigest, BlockHeader} from ".." +import { + Block, + BlockDigest, + BlockHeader, + Transaction, + TransactionExecutionStatus, +} from ".." export type SubscriptionSchema = { [SubscriptionTopic.BLOCKS]: SchemaItem< @@ -13,6 +19,21 @@ export type SubscriptionSchema = { blockDigest: BlockDigest } > + [SubscriptionTopic.TRANSACTION_STATUSES]: SchemaItem< + { + transactionId: string + }, + { + transactionStatus: { + blockId: string + status: TransactionExecutionStatus + statusString: string + statusCode: 0 | 1 + errorMessage: string + events: Array + } + } + > [SubscriptionTopic.BLOCK_HEADERS]: SchemaItem< BlockArgs, { @@ -24,6 +45,7 @@ export type SubscriptionSchema = { export enum SubscriptionTopic { BLOCKS = "blocks", BLOCK_DIGESTS = "block_digests", + TRANSACTION_STATUSES = "transaction_statuses", BLOCK_HEADERS = "block_headers", } @@ -60,3 +82,11 @@ export type SubscribeFn = ( }, opts: {node: string} ) => Promise + +type RawEvent = { + type: string + transactionId: string + transactionIndex: number + eventIndex: number + payload: any +} From 4cd015ae55d0dd571ecf313c433b54480ec49ce2 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Fri, 21 Mar 2025 10:27:41 -0700 Subject: [PATCH 08/72] PKG -- [transport-http] Add Events DataProvider (#2037) --- .../src/subscribe/handlers/events.ts | 105 ++++++++++++++++++ .../transport-http/src/subscribe/subscribe.ts | 4 +- .../src/sdk-transport/subscriptions.ts | 20 +++- 3 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 packages/transport-http/src/subscribe/handlers/events.ts diff --git a/packages/transport-http/src/subscribe/handlers/events.ts b/packages/transport-http/src/subscribe/handlers/events.ts new file mode 100644 index 000000000..46ba6e3a4 --- /dev/null +++ b/packages/transport-http/src/subscribe/handlers/events.ts @@ -0,0 +1,105 @@ +import {SdkTransport} from "@onflow/typedefs" +import {createSubscriptionHandler} from "./types" + +type EventsArgs = + SdkTransport.SubscriptionArguments + +type EventsData = + SdkTransport.SubscriptionData + +export type EventsArgsDto = ( + | { + start_block_id: string + } + | { + start_block_height: number + } + | {} +) & { + event_types?: string[] + addresses?: string[] + contracts?: string[] +} + +type EventsDataDto = { + block_id: string + block_height: string + block_timestamp: string + events: { + type: string + transaction_id: string + transaction_index: string + event_index: string + payload: string + }[] +} + +export const eventsHandler = createSubscriptionHandler<{ + Topic: SdkTransport.SubscriptionTopic.EVENTS + Args: EventsArgs + Data: EventsData + ArgsDto: EventsArgsDto + DataDto: EventsDataDto +}>({ + topic: SdkTransport.SubscriptionTopic.EVENTS, + createSubscriber: (initialArgs, onData, onError) => { + let resumeArgs: EventsArgs = { + ...initialArgs, + } + + return { + onData(rawData: EventsDataDto) { + for (const event of rawData.events) { + // Parse the raw data + const result: EventsData = { + event: { + blockId: rawData.block_id, + blockHeight: Number(rawData.block_height), + blockTimestamp: rawData.block_timestamp, + type: event.type, + transactionId: event.transaction_id, + transactionIndex: Number(event.transaction_index), + eventIndex: Number(event.event_index), + payload: event.payload, + }, + } + + // Update the resume args + resumeArgs = { + ...resumeArgs, + startHeight: result.event.blockHeight + 1, + startBlockId: undefined, + } + + onData(result) + } + }, + onError(error: Error) { + onError(error) + }, + getConnectionArgs() { + let encodedArgs: EventsArgsDto = { + event_types: resumeArgs.eventTypes, + addresses: resumeArgs.addresses, + contracts: resumeArgs.contracts, + } + + if ("startBlockHeight" in resumeArgs) { + return { + ...encodedArgs, + start_block_height: resumeArgs.startBlockHeight, + } + } + + if ("startBlockId" in resumeArgs) { + return { + ...encodedArgs, + start_block_id: resumeArgs.startBlockId, + } + } + + return encodedArgs + }, + } + }, +}) diff --git a/packages/transport-http/src/subscribe/subscribe.ts b/packages/transport-http/src/subscribe/subscribe.ts index 743e6697f..a292237d0 100644 --- a/packages/transport-http/src/subscribe/subscribe.ts +++ b/packages/transport-http/src/subscribe/subscribe.ts @@ -3,12 +3,14 @@ import {SubscriptionManager} from "./subscription-manager" import {blocksHandler} from "./handlers/blocks" import {blockHeadersHandler} from "./handlers/block-headers" import {blockDigestsHandler} from "./handlers/block-digests" +import {eventsHandler} from "./handlers/events" import {transactionStatusesHandler} from "./handlers/transaction-statuses" const SUBSCRIPTION_HANDLERS = [ blocksHandler, - blockDigestsHandler, blockHeadersHandler, + blockDigestsHandler, + eventsHandler, transactionStatusesHandler, ] diff --git a/packages/typedefs/src/sdk-transport/subscriptions.ts b/packages/typedefs/src/sdk-transport/subscriptions.ts index 1fae76ef9..ed3039c5a 100644 --- a/packages/typedefs/src/sdk-transport/subscriptions.ts +++ b/packages/typedefs/src/sdk-transport/subscriptions.ts @@ -2,7 +2,8 @@ import { Block, BlockDigest, BlockHeader, - Transaction, + Event, + EventFilter, TransactionExecutionStatus, } from ".." @@ -13,6 +14,12 @@ export type SubscriptionSchema = { block: Block } > + [SubscriptionTopic.BLOCK_HEADERS]: SchemaItem< + BlockArgs, + { + blockHeader: BlockHeader + } + > [SubscriptionTopic.BLOCK_DIGESTS]: SchemaItem< BlockArgs, { @@ -34,19 +41,22 @@ export type SubscriptionSchema = { } } > - [SubscriptionTopic.BLOCK_HEADERS]: SchemaItem< - BlockArgs, + [SubscriptionTopic.EVENTS]: SchemaItem< + EventFilter, { - blockHeader: BlockHeader + event: Omit & { + payload: string + } } > } export enum SubscriptionTopic { BLOCKS = "blocks", + BLOCK_HEADERS = "block_headers", BLOCK_DIGESTS = "block_digests", TRANSACTION_STATUSES = "transaction_statuses", - BLOCK_HEADERS = "block_headers", + EVENTS = "events", } type BlockArgs = From 8d29381b19db5ff86a2a26c20e536d8e954528c9 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Mon, 24 Mar 2025 19:01:32 -0600 Subject: [PATCH 09/72] PKG -- [fcl] Expose new streaming endpoints (#2038) --- packages/fcl-core/src/fcl-core.ts | 4 ++++ packages/fcl-react-native/src/fcl-react-native.ts | 4 ++++ packages/fcl/src/fcl.ts | 3 +++ 3 files changed, 11 insertions(+) diff --git a/packages/fcl-core/src/fcl-core.ts b/packages/fcl-core/src/fcl-core.ts index 6055cafd0..afd25df4b 100644 --- a/packages/fcl-core/src/fcl-core.ts +++ b/packages/fcl-core/src/fcl-core.ts @@ -69,6 +69,10 @@ export {params, param} from "@onflow/sdk" export {validator} from "@onflow/sdk" export {invariant} from "@onflow/sdk" +// Subscriptions +export {subscribe} from "@onflow/sdk" +export {rawSubscribe} from "@onflow/sdk" + import {watchForChainIdChanges} from "./utils" // Set chain id default on access node change diff --git a/packages/fcl-react-native/src/fcl-react-native.ts b/packages/fcl-react-native/src/fcl-react-native.ts index fc1328af4..9cf87a27a 100644 --- a/packages/fcl-react-native/src/fcl-react-native.ts +++ b/packages/fcl-react-native/src/fcl-react-native.ts @@ -108,3 +108,7 @@ initServiceRegistry({coreStrategies}) setIsReactNative(true) export {useServiceDiscovery, ServiceDiscovery} + +// Subscriptions +export {subscribe} from "@onflow/fcl-core" +export {rawSubscribe} from "@onflow/fcl-core" diff --git a/packages/fcl/src/fcl.ts b/packages/fcl/src/fcl.ts index 16b424bae..0125cf825 100644 --- a/packages/fcl/src/fcl.ts +++ b/packages/fcl/src/fcl.ts @@ -111,3 +111,6 @@ initServiceRegistry({coreStrategies}) initFclWcLoader() export {LOCAL_STORAGE, SESSION_STORAGE} from "./utils/web" + +// Subscriptions +export {subscribe, rawSubscribe} from "@onflow/fcl-core" From 0af28af9a1cb5cd06626fc46f269f38d0bf86a2b Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Tue, 25 Mar 2025 08:32:57 -0600 Subject: [PATCH 10/72] PKG -- [transport-http] Add AccountStatuses DataProvider (#2036) --- .../subscribe/handlers/account-statuses.ts | 125 ++++++++++++++++++ .../transport-http/src/subscribe/subscribe.ts | 7 +- packages/typedefs/src/index.ts | 1 + .../src/sdk-transport/subscriptions.ts | 18 +++ 4 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 packages/transport-http/src/subscribe/handlers/account-statuses.ts diff --git a/packages/transport-http/src/subscribe/handlers/account-statuses.ts b/packages/transport-http/src/subscribe/handlers/account-statuses.ts new file mode 100644 index 000000000..29391ce73 --- /dev/null +++ b/packages/transport-http/src/subscribe/handlers/account-statuses.ts @@ -0,0 +1,125 @@ +import {SdkTransport} from "@onflow/typedefs" +import {createSubscriptionHandler} from "./types" + +type AccountStatusesArgs = + SdkTransport.SubscriptionArguments + +type AccountStatusesData = + SdkTransport.SubscriptionData + +type AccountStatusesArgsDto = { + start_block_id?: string + start_block_height?: number + event_types?: string[] + addresses?: string[] + account_addresses?: string[] +} + +type AccountStatusesDataDto = { + block_id: string + block_height: string + block_timestamp: string + account_events: { + [address: string]: { + type: string + transaction_id: string + transaction_index: string + event_index: string + payload: string + }[] + } + message_index: string +} + +export const accountStatusesHandler = createSubscriptionHandler<{ + Topic: SdkTransport.SubscriptionTopic.ACCOUNT_STATUSES + Args: SdkTransport.SubscriptionArguments + Data: SdkTransport.SubscriptionData + ArgsDto: AccountStatusesArgsDto + DataDto: AccountStatusesDataDto +}>({ + topic: SdkTransport.SubscriptionTopic.ACCOUNT_STATUSES, + createSubscriber: (initialArgs, onData, onError) => { + let resumeArgs: AccountStatusesArgs = { + ...initialArgs, + } + + return { + onData(rawData: AccountStatusesDataDto) { + const data: AccountStatusesData[] = [] + for (const [address, events] of Object.entries( + rawData.account_events + )) { + for (const event of events) { + // Parse the raw data + const parsedData: AccountStatusesData = { + accountStatus: { + accountAddress: address, + blockId: rawData.block_id, + blockHeight: Number(rawData.block_height), + blockTimestamp: rawData.block_timestamp, + type: event.type, + transactionId: event.transaction_id, + transactionIndex: Number(event.transaction_index), + eventIndex: Number(event.event_index), + payload: event.payload, + }, + } + + // Update the resume args + resumeArgs = { + ...resumeArgs, + startBlockHeight: Number( + BigInt(rawData.block_height) + BigInt(1) + ), + startBlockId: undefined, + } + + data.push(parsedData) + } + + // Sort the messages by increasing message index + data.sort((a, b) => { + const txIndexDiff = + a.accountStatus.transactionIndex - + b.accountStatus.transactionIndex + if (txIndexDiff !== 0) return txIndexDiff + + return a.accountStatus.eventIndex - b.accountStatus.eventIndex + }) + + // Emit the messages + for (const message of data) { + onData(message) + } + } + }, + onError(error: Error) { + onError(error) + }, + getConnectionArgs() { + let encodedArgs: AccountStatusesArgsDto = { + event_types: resumeArgs.eventTypes, + addresses: resumeArgs.addresses, + account_addresses: resumeArgs.accountAddresses, + } + + if ("startBlockHeight" in resumeArgs) { + return { + ...encodedArgs, + start_block_height: resumeArgs.startBlockHeight, + } + } + + if ("startBlockId" in resumeArgs) { + return { + ...encodedArgs, + start_block_id: resumeArgs.startBlockId, + } + } + + return encodedArgs + }, + } + }, +}) diff --git a/packages/transport-http/src/subscribe/subscribe.ts b/packages/transport-http/src/subscribe/subscribe.ts index a292237d0..3a7206b50 100644 --- a/packages/transport-http/src/subscribe/subscribe.ts +++ b/packages/transport-http/src/subscribe/subscribe.ts @@ -3,15 +3,17 @@ import {SubscriptionManager} from "./subscription-manager" import {blocksHandler} from "./handlers/blocks" import {blockHeadersHandler} from "./handlers/block-headers" import {blockDigestsHandler} from "./handlers/block-digests" -import {eventsHandler} from "./handlers/events" +import {accountStatusesHandler} from "./handlers/account-statuses" import {transactionStatusesHandler} from "./handlers/transaction-statuses" +import {eventsHandler} from "./handlers/events" const SUBSCRIPTION_HANDLERS = [ blocksHandler, blockHeadersHandler, blockDigestsHandler, - eventsHandler, + accountStatusesHandler, transactionStatusesHandler, + eventsHandler, ] // Map of SubscriptionManager instances by access node URL @@ -44,7 +46,6 @@ export async function subscribe( return manager.subscribe({ topic, args, - // @ts-ignore - TODO: This is temporary until we start implementing the handlers onData, onError, }) diff --git a/packages/typedefs/src/index.ts b/packages/typedefs/src/index.ts index f2f541db9..f1af56cea 100644 --- a/packages/typedefs/src/index.ts +++ b/packages/typedefs/src/index.ts @@ -464,6 +464,7 @@ export type NodeVersionInfo = { */ nodeRootBlockHeight: number } + export interface StreamConnection { on( channel: C, diff --git a/packages/typedefs/src/sdk-transport/subscriptions.ts b/packages/typedefs/src/sdk-transport/subscriptions.ts index ed3039c5a..37fe2a785 100644 --- a/packages/typedefs/src/sdk-transport/subscriptions.ts +++ b/packages/typedefs/src/sdk-transport/subscriptions.ts @@ -26,6 +26,15 @@ export type SubscriptionSchema = { blockDigest: BlockDigest } > + [SubscriptionTopic.ACCOUNT_STATUSES]: SchemaItem< + AccountStatusesArgs, + { + accountStatus: Omit & { + payload: string + accountAddress: string + } + } + > [SubscriptionTopic.TRANSACTION_STATUSES]: SchemaItem< { transactionId: string @@ -55,6 +64,7 @@ export enum SubscriptionTopic { BLOCKS = "blocks", BLOCK_HEADERS = "block_headers", BLOCK_DIGESTS = "block_digests", + ACCOUNT_STATUSES = "account_statuses", TRANSACTION_STATUSES = "transaction_statuses", EVENTS = "events", } @@ -69,6 +79,14 @@ type BlockArgs = startBlockHeight?: number } +type AccountStatusesArgs = { + startBlockId?: string + startBlockHeight?: number + eventTypes?: string[] + addresses?: string[] + accountAddresses?: string[] +} + type SchemaItem = { args: TArgs data: TData From edfd7d677e8aecba1debaa27efb7c5512f299089 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Wed, 26 Mar 2025 09:06:33 -0600 Subject: [PATCH 11/72] Switch to synchronous subscriptions with callback-based error reporting (#2242) --- .../transport/subscribe/raw-subscribe.test.ts | 62 +++++-- .../src/transport/subscribe/raw-subscribe.ts | 55 ++++-- .../src/transport/subscribe/subscribe.test.ts | 2 +- .../sdk/src/transport/subscribe/subscribe.ts | 8 +- .../transport-http/src/subscribe/subscribe.ts | 4 +- .../subscribe/subscription-manager.test.ts | 87 +++++++--- .../src/subscribe/subscription-manager.ts | 163 ++++++++++-------- .../src/sdk-transport/subscriptions.ts | 2 +- 8 files changed, 245 insertions(+), 138 deletions(-) diff --git a/packages/sdk/src/transport/subscribe/raw-subscribe.test.ts b/packages/sdk/src/transport/subscribe/raw-subscribe.test.ts index bbf134730..efe403e54 100644 --- a/packages/sdk/src/transport/subscribe/raw-subscribe.test.ts +++ b/packages/sdk/src/transport/subscribe/raw-subscribe.test.ts @@ -6,22 +6,20 @@ import {getTransport} from "../get-transport" jest.mock("../get-transport") describe("subscribe", () => { - let mockTransport: jest.Mocked - let mockSub: jest.Mocked = { - unsubscribe: jest.fn(), - } - beforeEach(() => { jest.resetAllMocks() + }) - mockTransport = { + test("subscribes to a topic and returns subscription from transport", async () => { + const mockSub: jest.Mocked = { + unsubscribe: jest.fn(), + } + const mockTransport = { subscribe: jest.fn().mockReturnValue(mockSub), send: jest.fn(), } jest.mocked(getTransport).mockResolvedValue(mockTransport) - }) - test("subscribes to a topic and returns subscription from transport", async () => { const topic = "topic" as SdkTransport.SubscriptionTopic const args = {foo: "bar"} as SdkTransport.SubscriptionArguments const onData = jest.fn() @@ -31,8 +29,8 @@ describe("subscribe", () => { { "accessNode.api": "http://localhost:8080", }, - async () => { - return await rawSubscribe({topic, args, onData, onError}) + () => { + return rawSubscribe({topic, args, onData, onError}) } ) @@ -42,6 +40,48 @@ describe("subscribe", () => { {node: "http://localhost:8080"} ) - expect(sub).toBe(mockSub) + // Ensure that unsubscribe calls the transport's unsubscribe method + sub.unsubscribe() + await new Promise(setImmediate) + expect(mockSub.unsubscribe).toHaveBeenCalledTimes(1) + }) + + test("reports error from getTransport", async () => { + jest.mocked(getTransport).mockRejectedValue(new Error("Test Error")) + + const topic = "topic" as SdkTransport.SubscriptionTopic + const args = {foo: "bar"} as SdkTransport.SubscriptionArguments + const onData = jest.fn() + const onError = jest.fn() + + await config().overload( + { + "accessNode.api": "http://localhost:8080", + }, + () => { + return rawSubscribe({topic, args, onData, onError}) + } + ) + + expect(onError).toHaveBeenCalledTimes(1) + expect(onError).toHaveBeenCalledWith(new Error("Test Error")) + }) + + test("reports error if accessNode.api is not defined", async () => { + const topic = "topic" as SdkTransport.SubscriptionTopic + const args = {foo: "bar"} as SdkTransport.SubscriptionArguments + const onData = jest.fn() + const onError = jest.fn() + + await config().overload({}, () => { + return rawSubscribe({topic, args, onData, onError}) + }) + + expect(onError).toHaveBeenCalledTimes(1) + expect(onError).toHaveBeenCalledWith( + new Error( + `INVARIANT SDK Send Error: Either opts.node or "accessNode.api" in config must be defined.` + ) + ) }) }) diff --git a/packages/sdk/src/transport/subscribe/raw-subscribe.ts b/packages/sdk/src/transport/subscribe/raw-subscribe.ts index 6956fc649..452d126c8 100644 --- a/packages/sdk/src/transport/subscribe/raw-subscribe.ts +++ b/packages/sdk/src/transport/subscribe/raw-subscribe.ts @@ -10,32 +10,49 @@ import {SubscribeParams} from "./types" * @param opts - Additional options for the subscription. * @returns A promise that resolves once the subscription is active. */ -export async function rawSubscribe( +export function rawSubscribe( {topic, args, onData, onError}: SubscribeParams, opts: { node?: string transport?: SdkTransport.Transport } = {} ) { - const transport = await getTransport(opts) - const node = opts?.node || (await config().get("accessNode.api")) + async function subscribe() { + let transport: SdkTransport.Transport + let node: string - invariant( - !!node, - `SDK Send Error: Either opts.node or "accessNode.api" in config must be defined.` - ) + try { + transport = await getTransport(opts) + node = opts?.node || (await config().get("accessNode.api")) - // Subscribe using the resolved transport - return transport.subscribe( - { - topic, - args, - onData, - onError, - }, - { - node, - ...opts, + invariant( + !!node, + `SDK Send Error: Either opts.node or "accessNode.api" in config must be defined.` + ) + } catch (e) { + onError(e instanceof Error ? e : new Error(String(e))) + return } - ) + + // Subscribe using the resolved transport + return transport.subscribe( + { + topic, + args, + onData, + onError, + }, + { + node, + ...opts, + } + ) + } + + let subscriptionPromise = subscribe() + return { + unsubscribe: () => { + subscriptionPromise.then(sub => sub?.unsubscribe?.()) + }, + } } diff --git a/packages/sdk/src/transport/subscribe/subscribe.test.ts b/packages/sdk/src/transport/subscribe/subscribe.test.ts index ad7be7950..25de066c6 100644 --- a/packages/sdk/src/transport/subscribe/subscribe.test.ts +++ b/packages/sdk/src/transport/subscribe/subscribe.test.ts @@ -12,7 +12,7 @@ describe("subscribe", () => { beforeEach(() => { jest.resetAllMocks() - mockRawSubscribe.mockResolvedValue(mockSub) + mockRawSubscribe.mockReturnValue(mockSub) }) test("subscribes to a topic and returns a subscription", async () => { diff --git a/packages/sdk/src/transport/subscribe/subscribe.ts b/packages/sdk/src/transport/subscribe/subscribe.ts index 07112374d..c2cbca418 100644 --- a/packages/sdk/src/transport/subscribe/subscribe.ts +++ b/packages/sdk/src/transport/subscribe/subscribe.ts @@ -9,14 +9,14 @@ import {SubscribeParams} from "./types" * @param opts - Additional options for the subscription. * @returns A promise that resolves when the subscription is active. */ -export async function subscribe( +export function subscribe( {topic, args, onData, onError}: SubscribeParams, opts: { node?: string transport?: SdkTransport.Transport } = {} -): Promise { - const sub = await rawSubscribe( +): SdkTransport.Subscription { + const sub = rawSubscribe( { topic, args, @@ -25,7 +25,7 @@ export async function subscribe( .then(onData) .catch(e => { onError(new Error(`Failed to decode response: ${e.message}`)) - sub.unsubscribe() + sub?.unsubscribe?.() }) }, onError, diff --git a/packages/transport-http/src/subscribe/subscribe.ts b/packages/transport-http/src/subscribe/subscribe.ts index 3a7206b50..8d1f1e36f 100644 --- a/packages/transport-http/src/subscribe/subscribe.ts +++ b/packages/transport-http/src/subscribe/subscribe.ts @@ -22,7 +22,7 @@ let subscriptionManagerMap: Map< SubscriptionManager > = new Map() -export async function subscribe( +export function subscribe( { topic, args, @@ -35,7 +35,7 @@ export async function subscribe( onError: (error: Error) => void }, opts: {node: string} -): Promise { +): SdkTransport.Subscription { // Get the SubscriptionManager instance for the access node, or create a new one const node = opts.node const manager = diff --git a/packages/transport-http/src/subscribe/subscription-manager.test.ts b/packages/transport-http/src/subscribe/subscription-manager.test.ts index 9815b24a9..255522b01 100644 --- a/packages/transport-http/src/subscribe/subscription-manager.test.ts +++ b/packages/transport-http/src/subscribe/subscription-manager.test.ts @@ -79,15 +79,14 @@ describe("SubscriptionManager", () => { mockWs.send(JSON.stringify(response)) })() - const [subscription] = await Promise.all([ - subscriptionManager.subscribe({ - topic, - args, - onData, - onError, - }), - serverPromise, - ]) + const subscription = subscriptionManager.subscribe({ + topic, + args, + onData, + onError, + }) + + await serverPromise expect(subscription).toBeDefined() expect(subscription.unsubscribe).toBeInstanceOf(Function) @@ -129,15 +128,14 @@ describe("SubscriptionManager", () => { mockWs.send(JSON.stringify(response)) })() - const [subscription] = await Promise.all([ - subscriptionManager.subscribe({ - topic, - args, - onData, - onError, - }), - serverPromise, - ]) + const subscription = subscriptionManager.subscribe({ + topic, + args, + onData, + onError, + }) + + await serverPromise expect(subscription).toBeDefined() expect(subscription.unsubscribe).toBeInstanceOf(Function) @@ -195,15 +193,14 @@ describe("SubscriptionManager", () => { mockWs.send(JSON.stringify(response)) })() - const [subscription] = await Promise.all([ - subscriptionManager.subscribe({ - topic, - args, - onData, - onError, - }), - serverPromise, - ]) + const subscription = subscriptionManager.subscribe({ + topic, + args, + onData, + onError, + }) + + await serverPromise expect(subscription).toBeDefined() expect(subscription.unsubscribe).toBeInstanceOf(Function) @@ -276,4 +273,40 @@ describe("SubscriptionManager", () => { }, ]) }) + + test("reports error connecting to socket", async () => { + const config: SubscriptionManagerConfig = { + node: "wss://localhost:8080", + reconnectOptions: { + reconnectAttempts: 1, + initialReconnectDelay: 1, + maxReconnectDelay: 1, + }, + } + const subscriptionManager = new SubscriptionManager([mockHandler], config) + const topic = "topic" as SdkTransport.SubscriptionTopic + const args = {key: "value"} as any + const onData = jest.fn() + const onError = jest.fn() + + mockWs.error({ + code: 1006, + reason: "Connection failed", + wasClean: false, + }) + + subscriptionManager.subscribe({ + topic, + args, + onData, + onError, + }) + + await new Promise(resolve => setTimeout(resolve, 1000)) + + expect(mockSubscriber.onError).toHaveBeenCalledTimes(1) + expect(mockSubscriber.onError).toHaveBeenCalledWith( + new Error("WebSocket closed") + ) + }) }) diff --git a/packages/transport-http/src/subscribe/subscription-manager.ts b/packages/transport-http/src/subscribe/subscription-manager.ts index e0e5cc7e9..b600c9f98 100644 --- a/packages/transport-http/src/subscribe/subscription-manager.ts +++ b/packages/transport-http/src/subscribe/subscription-manager.ts @@ -76,11 +76,91 @@ export class SubscriptionManager[]> { this.handlers = handlers } + subscribe(opts: { + topic: InferHandler["Topic"] + args: InferHandler["Args"] + onData: (data: InferHandler["Data"]) => void + onError: (error: Error) => void + }): SdkTransport.Subscription { + const idPromise = this._subscribe(opts) + + return { + unsubscribe: () => { + // Unsubscribe when the ID is available + idPromise.then(id => id && this.unsubscribe(id)) + }, + } + } + + private async _subscribe(opts: { + topic: InferHandler["Topic"] + args: InferHandler["Args"] + onData: (data: InferHandler["Data"]) => void + onError: (error: Error) => void + }): Promise { + // Get the data provider for the topic + const topicHandler = this.getHandler(opts.topic) + const subscriber = topicHandler.createSubscriber( + opts.args, + opts.onData, + opts.onError + ) + + let sub: SubscriptionInfo | null = null + try { + // Connect the socket if it's not already open + await this.connect() + + // Track the subscription locally + sub = { + id: String(this.counter++), + topic: opts.topic, + subscriber: subscriber, + } + this.subscriptions.push(sub) + + // Send the subscribe message + const response = await this.sendSubscribe(sub) + if (response.error) { + throw new Error(`Failed to subscribe to topic ${sub.topic}`, { + cause: SocketError.fromMessage(response.error), + }) + } + } catch (e) { + // Unsubscribe if there was an error + subscriber.onError(e instanceof Error ? e : new Error(String(e))) + if (sub) this.unsubscribe(sub.id) + return null + } + + return sub.id + } + + private unsubscribe(id: string): void { + // Get the subscription + const sub = this.subscriptions.find(sub => sub.id === id) + if (!sub) return + + // Remove the subscription + this.subscriptions = this.subscriptions.filter(sub => sub.id !== id) + + // Close the socket if there are no more subscriptions + if (this.subscriptions.length === 0) { + this.socket?.close() + return + } + + // Otherwise, the unsubscribe message + this.sendUnsubscribe(sub).catch(e => { + console.error(`Error while unsubscribing from topic: ${e}`) + }) + } + // Lazy connect to the socket when the first subscription is made private async connect() { return new Promise((resolve, reject) => { // If the socket is already open, do nothing - if (this.socket?.readyState === WS_OPEN || this.socket) { + if (this.socket?.readyState === WS_OPEN) { resolve() return } @@ -107,7 +187,13 @@ export class SubscriptionManager[]> { } }) this.socket.addEventListener("close", () => { - void this.handleSocketError(new Error("WebSocket closed")) + this.handleSocketError(new Error("WebSocket closed")) + .then(() => { + resolve() + }) + .catch(e => { + reject(e) + }) }) this.socket.addEventListener("open", () => { // Restore subscriptions @@ -130,11 +216,6 @@ export class SubscriptionManager[]> { // Clear the socket this.socket = null - // If there are no subscriptions, do nothing - if (this.subscriptions.length === 0) { - return - } - // Validate the number of reconnection attempts if ( this.reconnectAttempts >= this.config.reconnectOptions.reconnectAttempts @@ -154,6 +235,8 @@ export class SubscriptionManager[]> { }) this.subscriptions = [] this.reconnectAttempts = 0 + + throw error } else { logger.log({ level: logger.LEVELS.warn, @@ -171,72 +254,6 @@ export class SubscriptionManager[]> { } } - async subscribe(opts: { - topic: InferHandler["Topic"] - args: InferHandler["Args"] - onData: (data: InferHandler["Data"]) => void - onError: (error: Error) => void - }): Promise { - // Connect the socket if it's not already open - await this.connect() - - // Get the data provider for the topic - const topicHandler = this.getHandler(opts.topic) - const subscriber = topicHandler.createSubscriber( - opts.args, - opts.onData, - opts.onError - ) - - // Track the subscription locally - const sub: SubscriptionInfo = { - id: String(this.counter++), - topic: opts.topic, - subscriber: subscriber, - } - this.subscriptions.push(sub) - - // Send the subscribe message - try { - const response = await this.sendSubscribe(sub) - if (response.error) { - throw new Error(`Failed to subscribe to topic ${sub.topic}`, { - cause: SocketError.fromMessage(response.error), - }) - } - } catch (e) { - // Unsubscribe if there was an error - this.unsubscribe(sub.id) - throw e - } - - return { - unsubscribe: () => { - this.unsubscribe(sub.id) - }, - } - } - - private unsubscribe(id: string): void { - // Get the subscription - const sub = this.subscriptions.find(sub => sub.id === id) - if (!sub) return - - // Remove the subscription - this.subscriptions = this.subscriptions.filter(sub => sub.id !== id) - - // Close the socket if there are no more subscriptions - if (this.subscriptions.length === 0) { - this.socket?.close() - return - } - - // Otherwise, the unsubscribe message - this.sendUnsubscribe(sub).catch(e => { - console.error(`Error while unsubscribing from topic: ${e}`) - }) - } - private async sendSubscribe(sub: SubscriptionInfo) { // Send the subscription message const request: MessageRequest = { diff --git a/packages/typedefs/src/sdk-transport/subscriptions.ts b/packages/typedefs/src/sdk-transport/subscriptions.ts index 37fe2a785..a2f1b796f 100644 --- a/packages/typedefs/src/sdk-transport/subscriptions.ts +++ b/packages/typedefs/src/sdk-transport/subscriptions.ts @@ -109,7 +109,7 @@ export type SubscribeFn = ( onError: (error: Error) => void }, opts: {node: string} -) => Promise +) => Subscription type RawEvent = { type: string From 3606bde4cb0498fba9cc627cf1067aade69666d2 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Wed, 26 Mar 2025 12:41:32 -0600 Subject: [PATCH 12/72] Switch `fcl.events` to use new event streaming method (#2241) --- packages/fcl-core/src/events/index.test.ts | 103 ++++++++++++------ packages/fcl-core/src/events/index.ts | 81 ++++++-------- packages/sdk/src/sdk.ts | 7 +- packages/sdk/src/transport/get-transport.ts | 5 +- packages/sdk/src/transport/index.ts | 1 + .../sdk/src/transport/subscribe/errors.ts | 8 ++ 6 files changed, 120 insertions(+), 85 deletions(-) create mode 100644 packages/sdk/src/transport/subscribe/errors.ts diff --git a/packages/fcl-core/src/events/index.test.ts b/packages/fcl-core/src/events/index.test.ts index a339a852c..5b66c96d2 100644 --- a/packages/fcl-core/src/events/index.test.ts +++ b/packages/fcl-core/src/events/index.test.ts @@ -1,62 +1,75 @@ -import {EventStream} from "@onflow/typedefs" +import {SdkTransport} from "@onflow/typedefs" import {events} from "." -import {send, decode, subscribeEvents} from "@onflow/sdk" +import {subscribe, SubscriptionsNotSupportedError} from "@onflow/sdk" +import {events as legacyEvents} from "./legacy-events" jest.mock("@onflow/sdk") +jest.mock("./legacy-events") describe("events", () => { - let sendSpy - let decodeSpy - let subscribeEventsSpy - let mockEventsStream: EventStream + let mockSubscription: jest.Mocked + let mockLegacySubscribeObject: jest.Mocked<{subscribe: () => void}> + let mockLegacyUnsubscribe: jest.MockedFunction<() => void> beforeEach(() => { - mockEventsStream = { - on: jest.fn(() => mockEventsStream), - off: jest.fn(() => mockEventsStream), - close: jest.fn(), + mockSubscription = { + unsubscribe: jest.fn(), + } + mockLegacyUnsubscribe = jest.fn() + mockLegacySubscribeObject = { + subscribe: jest.fn().mockReturnValue(mockLegacyUnsubscribe), } - sendSpy = jest.mocked(send) - decodeSpy = jest.mocked(decode) - subscribeEventsSpy = jest.mocked(subscribeEvents) - - sendSpy.mockReturnValue(Promise.resolve(mockEventsStream)) - decodeSpy.mockImplementation(async x => x) - subscribeEventsSpy.mockImplementation(async x => x) + jest.mocked(subscribe).mockReturnValue(mockSubscription) + jest.mocked(legacyEvents).mockReturnValue(mockLegacySubscribeObject) }) afterEach(() => { jest.clearAllMocks() }) - test("subscribe should call send with the subscribeEvents ix", () => { + test("subscribe should call subscribe with the correct arguments", () => { const filter = {eventTypes: ["A"]} + events(filter).subscribe(() => {}) - expect(sendSpy).toHaveBeenCalledWith([subscribeEvents(filter)]) + + expect(subscribe).toHaveBeenCalledWith({ + topic: "events", + args: filter, + onData: expect.any(Function), + onError: expect.any(Function), + }) }) test("should work with a string", () => { events("A").subscribe(() => {}) - expect(sendSpy).toHaveBeenCalledWith([subscribeEvents({eventTypes: ["A"]})]) + expect(subscribe).toHaveBeenCalledWith({ + topic: "events", + args: {eventTypes: ["A"]}, + onData: expect.any(Function), + onError: expect.any(Function), + }) }) test("should work with empty args", () => { events().subscribe(() => {}) - expect(sendSpy).toHaveBeenCalledWith([subscribeEvents({})]) + expect(subscribe).toHaveBeenCalledWith({ + topic: "events", + args: {}, + onData: expect.any(Function), + onError: expect.any(Function), + }) }) test("subscribe should pipe the events to the callback", async () => { const filter = {eventTypes: ["A"]} const callback = jest.fn() - const mockEvents = [{type: "A"}, {type: "B"}] + const mockEvents = [{type: "A"}, {type: "B"}] as any[] - mockEventsStream.on.mockImplementation((event, cb) => { - if (event === "events") { - cb(mockEvents) - } - return mockEventsStream + jest.mocked(subscribe).mockImplementation(({onData}) => { + mockEvents.forEach(event => onData(event)) + return mockSubscription }) events(filter).subscribe(callback) @@ -74,11 +87,9 @@ describe("events", () => { const mockError = new Error("mock error") - mockEventsStream.on.mockImplementation((event, cb) => { - if (event === "error") { - cb(mockError) - } - return mockEventsStream + jest.mocked(subscribe).mockImplementation(({onError}) => { + onError(mockError) + return mockSubscription }) events(filter).subscribe(callback) @@ -86,4 +97,32 @@ describe("events", () => { expect(callback.mock.calls).toEqual([[null, mockError]]) }) + + test("fallback to legacy polling if subscriptions are not supported", async () => { + const filter = "A" + const callback = jest.fn() + + const mockError = new SubscriptionsNotSupportedError() + + jest.mocked(subscribe).mockImplementation(({onError}) => { + onError(mockError) + return mockSubscription + }) + + const unsubscribe = events(filter).subscribe(callback) + await new Promise(resolve => setTimeout(resolve, 0)) + + // Check that the callback was called + expect(callback).toHaveBeenCalledTimes(0) + expect(subscribe).toHaveBeenCalledTimes(1) + + // Check that legacy polling was called + expect(legacyEvents).toHaveBeenCalledWith(filter) + expect(mockLegacySubscribeObject.subscribe).toHaveBeenCalledWith(callback) + + // Unsubscribe + unsubscribe() + expect(mockSubscription.unsubscribe).toHaveBeenCalledTimes(1) + expect(mockLegacyUnsubscribe).toHaveBeenCalledTimes(1) + }) }) diff --git a/packages/fcl-core/src/events/index.ts b/packages/fcl-core/src/events/index.ts index b6b9e1bbf..0d0274854 100644 --- a/packages/fcl-core/src/events/index.ts +++ b/packages/fcl-core/src/events/index.ts @@ -1,6 +1,7 @@ -import {send, decode, subscribeEvents} from "@onflow/sdk" -import {Event, EventFilter, EventStream} from "@onflow/typedefs" +import {subscribe} from "@onflow/sdk" +import {Event, EventFilter, SdkTransport} from "@onflow/typedefs" import {events as legacyEvents} from "./legacy-events" +import {SubscriptionsNotSupportedError} from "@onflow/sdk" /** * @description - Subscribe to events @@ -23,59 +24,41 @@ export function events(filterOrType?: EventFilter | string) { subscribe: ( callback: (events: Event | null, error: Error | null) => void ) => { - const streamPromise: Promise = send([ - subscribeEvents(filter), - ]).then(decode) - - // If the subscribe fails, fallback to legacy events - const legacySubscriptionPromise = streamPromise - .then(() => null) - .catch(e => { - // Only fallback to legacy events if the error is specifcally about the unsupported feature - if ( - e.message !== - "SDK Send Error: subscribeEvents is not supported by this transport." - ) { - throw e + let unsubscribeFnLegacy = () => {} + const {unsubscribe: unsubscribeFn} = subscribe({ + topic: SdkTransport.SubscriptionTopic.EVENTS, + args: filter, + onData: (data: any) => { + callback(data, null) + }, + onError: (error: Error) => { + // If subscriptions are not supported, fallback to legacy polling, otherwise return the error + if (error instanceof SubscriptionsNotSupportedError) { + fallbackLegacyPolling() + } else { + callback(null, error) } + }, + }) - if (typeof filterOrType !== "string") { - throw new Error( - "GRPC fcl.events fallback only supports string (type) filters" - ) - } - return legacyEvents(filterOrType).subscribe(callback) - }) + function fallbackLegacyPolling() { + console.warn( + "Failed to subscribe to events using real-time streaming (are you using the deprecated GRPC transport?), falling back to legacy polling." + ) - // Subscribe to the stream using the callback - function onEvents(data: Event[]) { - data.forEach(event => callback(event, null)) - } - function onError(error: Error) { - callback(null, error) - } - - // If using legacy events, don't subscribe to the stream - legacySubscriptionPromise.then(legacySubscription => { - if (!legacySubscription) { - streamPromise - .then(stream => stream.on("events", onEvents).on("error", onError)) - .catch(error => { - streamPromise.then(stream => stream.close()) - onError(error) - }) + if (typeof filterOrType !== "string") { + throw new Error( + "Legacy fcl.events fallback only supports string filters (single event type)" + ) } - }) + const unsubscribe = legacyEvents(filterOrType).subscribe(callback) + unsubscribeFnLegacy = unsubscribe + } - // Unsubscribe will call terminate the legacy subscription or close the stream + // Return an unsubscribe function return () => { - legacySubscriptionPromise.then(legacySubscription => { - if (legacySubscription) { - legacySubscription() - } else { - streamPromise.then(stream => stream.close()) - } - }) + unsubscribeFn() + unsubscribeFnLegacy() } }, } diff --git a/packages/sdk/src/sdk.ts b/packages/sdk/src/sdk.ts index 03d58fea1..81fa55444 100644 --- a/packages/sdk/src/sdk.ts +++ b/packages/sdk/src/sdk.ts @@ -2,7 +2,12 @@ import * as logger from "@onflow/util-logger" // Base export {build} from "./build/build.js" export {resolve} from "./resolve/resolve.js" -export {send, subscribe, rawSubscribe} from "./transport" +export { + send, + subscribe, + rawSubscribe, + SubscriptionsNotSupportedError, +} from "./transport" export {decode} from "./decode/sdk-decode.js" export { encodeTransactionPayload, diff --git a/packages/sdk/src/transport/get-transport.ts b/packages/sdk/src/transport/get-transport.ts index 635d6e054..972d52571 100644 --- a/packages/sdk/src/transport/get-transport.ts +++ b/packages/sdk/src/transport/get-transport.ts @@ -2,6 +2,7 @@ import {config} from "@onflow/config" import {httpTransport as defaultTransport} from "@onflow/transport-http" import {SdkTransport} from "@onflow/typedefs" import {invariant} from "@onflow/util-invariant" +import {SubscriptionsNotSupportedError} from "./subscribe/errors" /** * Get the SDK transport object, either from the provided override or from the global config. @@ -32,9 +33,7 @@ export async function getTransport( return { send: transportOrSend, subscribe: () => { - throw new Error( - "Subscribe not supported with legacy send function transport, please provide a transport object." - ) + throw new SubscriptionsNotSupportedError() }, } } diff --git a/packages/sdk/src/transport/index.ts b/packages/sdk/src/transport/index.ts index cf3d3ae64..fd152bdfa 100644 --- a/packages/sdk/src/transport/index.ts +++ b/packages/sdk/src/transport/index.ts @@ -1,3 +1,4 @@ export {send} from "./send/send" export {subscribe} from "./subscribe/subscribe" export {rawSubscribe} from "./subscribe/raw-subscribe" +export {SubscriptionsNotSupportedError} from "./subscribe/errors" diff --git a/packages/sdk/src/transport/subscribe/errors.ts b/packages/sdk/src/transport/subscribe/errors.ts new file mode 100644 index 000000000..c48b38587 --- /dev/null +++ b/packages/sdk/src/transport/subscribe/errors.ts @@ -0,0 +1,8 @@ +export class SubscriptionsNotSupportedError extends Error { + constructor() { + super( + `The current transport does not support subscriptions. If you have provided a custom transport (e.g. via \`sdk.transport\` configuration), ensure that it implements the subscribe method.` + ) + this.name = "SubscriptionsNotSupportedError" + } +} From d7153e05e1becc9e78e15da4a7d7ac28e1a1b089 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Wed, 26 Mar 2025 13:22:05 -0600 Subject: [PATCH 13/72] Fix resume args for `events` & `account_statuses` (#2249) --- .../src/subscribe/handlers/account-statuses.ts | 16 +++++++--------- .../src/subscribe/handlers/events.ts | 14 +++++++------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/packages/transport-http/src/subscribe/handlers/account-statuses.ts b/packages/transport-http/src/subscribe/handlers/account-statuses.ts index 29391ce73..cef3f2f11 100644 --- a/packages/transport-http/src/subscribe/handlers/account-statuses.ts +++ b/packages/transport-http/src/subscribe/handlers/account-statuses.ts @@ -66,15 +66,6 @@ export const accountStatusesHandler = createSubscriptionHandler<{ }, } - // Update the resume args - resumeArgs = { - ...resumeArgs, - startBlockHeight: Number( - BigInt(rawData.block_height) + BigInt(1) - ), - startBlockId: undefined, - } - data.push(parsedData) } @@ -92,6 +83,13 @@ export const accountStatusesHandler = createSubscriptionHandler<{ for (const message of data) { onData(message) } + + // Update the resume args + resumeArgs = { + ...resumeArgs, + startBlockHeight: Number(BigInt(rawData.block_height) + BigInt(1)), + startBlockId: undefined, + } } }, onError(error: Error) { diff --git a/packages/transport-http/src/subscribe/handlers/events.ts b/packages/transport-http/src/subscribe/handlers/events.ts index 46ba6e3a4..a63abce42 100644 --- a/packages/transport-http/src/subscribe/handlers/events.ts +++ b/packages/transport-http/src/subscribe/handlers/events.ts @@ -64,15 +64,15 @@ export const eventsHandler = createSubscriptionHandler<{ }, } - // Update the resume args - resumeArgs = { - ...resumeArgs, - startHeight: result.event.blockHeight + 1, - startBlockId: undefined, - } - onData(result) } + + // Update the resume args + resumeArgs = { + ...resumeArgs, + startHeight: Number(BigInt(rawData.block_height) + BigInt(1)), + startBlockId: undefined, + } }, onError(error: Error) { onError(error) From fb384394f20d8292feca1aece3b0b968d051ba11 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Thu, 27 Mar 2025 17:51:34 -0600 Subject: [PATCH 14/72] Cleanup subscriptions types & align with decoded representation (#2256) --- packages/fcl-core/src/events/index.test.ts | 4 +- packages/fcl-core/src/events/index.ts | 6 +- packages/sdk/src/transport/index.ts | 1 + .../transport/subscribe/raw-subscribe.test.ts | 20 +-- .../src/transport/subscribe/raw-subscribe.ts | 8 +- .../src/transport/subscribe/subscribe.test.ts | 25 ++-- .../sdk/src/transport/subscribe/subscribe.ts | 6 +- packages/sdk/src/transport/subscribe/types.ts | 44 ++++++- .../subscribe/handlers/account-statuses.ts | 20 +-- .../src/subscribe/handlers/block-digests.ts | 16 ++- .../src/subscribe/handlers/block-headers.ts | 16 ++- .../src/subscribe/handlers/blocks.ts | 16 ++- .../src/subscribe/handlers/events.ts | 16 ++- .../handlers/transaction-statuses.ts | 14 +- .../transport-http/src/subscribe/subscribe.ts | 17 ++- .../subscribe/subscription-manager.test.ts | 10 +- .../src/subscribe/subscription-manager.ts | 4 +- packages/typedefs/src/index.ts | 7 + packages/typedefs/src/sdk-transport/index.ts | 8 +- .../sdk-transport/{requests.ts => send.ts} | 0 .../typedefs/src/sdk-transport/subscribe.ts | 16 +++ .../src/sdk-transport/subscriptions.ts | 120 ------------------ packages/typedefs/src/subscriptions.ts | 112 ++++++++++++++++ 23 files changed, 294 insertions(+), 212 deletions(-) rename packages/typedefs/src/sdk-transport/{requests.ts => send.ts} (100%) create mode 100644 packages/typedefs/src/sdk-transport/subscribe.ts delete mode 100644 packages/typedefs/src/sdk-transport/subscriptions.ts create mode 100644 packages/typedefs/src/subscriptions.ts diff --git a/packages/fcl-core/src/events/index.test.ts b/packages/fcl-core/src/events/index.test.ts index 5b66c96d2..b0d207e6d 100644 --- a/packages/fcl-core/src/events/index.test.ts +++ b/packages/fcl-core/src/events/index.test.ts @@ -1,4 +1,4 @@ -import {SdkTransport} from "@onflow/typedefs" +import {Subscription} from "@onflow/typedefs" import {events} from "." import {subscribe, SubscriptionsNotSupportedError} from "@onflow/sdk" import {events as legacyEvents} from "./legacy-events" @@ -7,7 +7,7 @@ jest.mock("@onflow/sdk") jest.mock("./legacy-events") describe("events", () => { - let mockSubscription: jest.Mocked + let mockSubscription: jest.Mocked let mockLegacySubscribeObject: jest.Mocked<{subscribe: () => void}> let mockLegacyUnsubscribe: jest.MockedFunction<() => void> diff --git a/packages/fcl-core/src/events/index.ts b/packages/fcl-core/src/events/index.ts index 0d0274854..49e790fed 100644 --- a/packages/fcl-core/src/events/index.ts +++ b/packages/fcl-core/src/events/index.ts @@ -1,5 +1,5 @@ import {subscribe} from "@onflow/sdk" -import {Event, EventFilter, SdkTransport} from "@onflow/typedefs" +import {Event, EventFilter, SubscriptionTopic} from "@onflow/typedefs" import {events as legacyEvents} from "./legacy-events" import {SubscriptionsNotSupportedError} from "@onflow/sdk" @@ -26,9 +26,9 @@ export function events(filterOrType?: EventFilter | string) { ) => { let unsubscribeFnLegacy = () => {} const {unsubscribe: unsubscribeFn} = subscribe({ - topic: SdkTransport.SubscriptionTopic.EVENTS, + topic: SubscriptionTopic.EVENTS, args: filter, - onData: (data: any) => { + onData: data => { callback(data, null) }, onError: (error: Error) => { diff --git a/packages/sdk/src/transport/index.ts b/packages/sdk/src/transport/index.ts index fd152bdfa..3c22c862e 100644 --- a/packages/sdk/src/transport/index.ts +++ b/packages/sdk/src/transport/index.ts @@ -2,3 +2,4 @@ export {send} from "./send/send" export {subscribe} from "./subscribe/subscribe" export {rawSubscribe} from "./subscribe/raw-subscribe" export {SubscriptionsNotSupportedError} from "./subscribe/errors" +export * from "./subscribe/types" diff --git a/packages/sdk/src/transport/subscribe/raw-subscribe.test.ts b/packages/sdk/src/transport/subscribe/raw-subscribe.test.ts index efe403e54..75e26b02f 100644 --- a/packages/sdk/src/transport/subscribe/raw-subscribe.test.ts +++ b/packages/sdk/src/transport/subscribe/raw-subscribe.test.ts @@ -1,6 +1,10 @@ import {config} from "@onflow/config" import {rawSubscribe} from "./raw-subscribe" -import {SdkTransport} from "@onflow/typedefs" +import { + Subscription, + SubscriptionArgs, + SubscriptionTopic, +} from "@onflow/typedefs" import {getTransport} from "../get-transport" jest.mock("../get-transport") @@ -11,7 +15,7 @@ describe("subscribe", () => { }) test("subscribes to a topic and returns subscription from transport", async () => { - const mockSub: jest.Mocked = { + const mockSub: jest.Mocked = { unsubscribe: jest.fn(), } const mockTransport = { @@ -20,8 +24,8 @@ describe("subscribe", () => { } jest.mocked(getTransport).mockResolvedValue(mockTransport) - const topic = "topic" as SdkTransport.SubscriptionTopic - const args = {foo: "bar"} as SdkTransport.SubscriptionArguments + const topic = "topic" as SubscriptionTopic + const args = {foo: "bar"} as SubscriptionArgs const onData = jest.fn() const onError = jest.fn() @@ -49,8 +53,8 @@ describe("subscribe", () => { test("reports error from getTransport", async () => { jest.mocked(getTransport).mockRejectedValue(new Error("Test Error")) - const topic = "topic" as SdkTransport.SubscriptionTopic - const args = {foo: "bar"} as SdkTransport.SubscriptionArguments + const topic = "topic" as SubscriptionTopic + const args = {foo: "bar"} as SubscriptionArgs const onData = jest.fn() const onError = jest.fn() @@ -68,8 +72,8 @@ describe("subscribe", () => { }) test("reports error if accessNode.api is not defined", async () => { - const topic = "topic" as SdkTransport.SubscriptionTopic - const args = {foo: "bar"} as SdkTransport.SubscriptionArguments + const topic = "topic" as SubscriptionTopic + const args = {foo: "bar"} as SubscriptionArgs const onData = jest.fn() const onError = jest.fn() diff --git a/packages/sdk/src/transport/subscribe/raw-subscribe.ts b/packages/sdk/src/transport/subscribe/raw-subscribe.ts index 452d126c8..8a4929038 100644 --- a/packages/sdk/src/transport/subscribe/raw-subscribe.ts +++ b/packages/sdk/src/transport/subscribe/raw-subscribe.ts @@ -1,8 +1,8 @@ import {config} from "@onflow/config" -import {SdkTransport} from "@onflow/typedefs" +import {SdkTransport, SubscriptionTopic} from "@onflow/typedefs" import {getTransport} from "../get-transport" import {invariant} from "@onflow/util-invariant" -import {SubscribeParams} from "./types" +import {RawSubscribeParams} from "./types" /** * Subscribe to a topic without decoding the data. @@ -10,8 +10,8 @@ import {SubscribeParams} from "./types" * @param opts - Additional options for the subscription. * @returns A promise that resolves once the subscription is active. */ -export function rawSubscribe( - {topic, args, onData, onError}: SubscribeParams, +export function rawSubscribe( + {topic, args, onData, onError}: RawSubscribeParams, opts: { node?: string transport?: SdkTransport.Transport diff --git a/packages/sdk/src/transport/subscribe/subscribe.test.ts b/packages/sdk/src/transport/subscribe/subscribe.test.ts index 25de066c6..3e8358782 100644 --- a/packages/sdk/src/transport/subscribe/subscribe.test.ts +++ b/packages/sdk/src/transport/subscribe/subscribe.test.ts @@ -1,4 +1,9 @@ -import {SdkTransport} from "@onflow/typedefs" +import { + Subscription, + SubscriptionArgs, + SubscriptionTopic, + SdkTransport, +} from "@onflow/typedefs" import {subscribe} from "./subscribe" import {rawSubscribe} from "./raw-subscribe" @@ -6,7 +11,7 @@ jest.mock("./raw-subscribe") const mockRawSubscribe = jest.mocked(rawSubscribe) describe("subscribe", () => { - let mockSub: jest.Mocked = { + let mockSub: jest.Mocked = { unsubscribe: jest.fn(), } @@ -16,8 +21,8 @@ describe("subscribe", () => { }) test("subscribes to a topic and returns a subscription", async () => { - const topic = "topic" as SdkTransport.SubscriptionTopic - const args = {foo: "bar"} as SdkTransport.SubscriptionArguments + const topic = "topic" as SubscriptionTopic + const args = {foo: "bar"} as SubscriptionArgs const onData = jest.fn() const onError = jest.fn() @@ -37,8 +42,8 @@ describe("subscribe", () => { }) test("unsubscribes from a subscription", async () => { - const topic = "topic" as SdkTransport.SubscriptionTopic - const args = {foo: "bar"} as SdkTransport.SubscriptionArguments + const topic = "topic" as SubscriptionTopic + const args = {foo: "bar"} as SubscriptionArgs const onData = jest.fn() const onError = jest.fn() @@ -55,8 +60,8 @@ describe("subscribe", () => { }) test("subscribes to a topic with a node", async () => { - const topic = "topic" as SdkTransport.SubscriptionTopic - const args = {foo: "bar"} as SdkTransport.SubscriptionArguments + const topic = "topic" as SubscriptionTopic + const args = {foo: "bar"} as SubscriptionArgs const onData = jest.fn() const onError = jest.fn() @@ -81,8 +86,8 @@ describe("subscribe", () => { }) test("subscribes to a topic with custom node and transport", async () => { - const topic = "topic" as SdkTransport.SubscriptionTopic - const args = {foo: "bar"} as SdkTransport.SubscriptionArguments + const topic = "topic" as SubscriptionTopic + const args = {foo: "bar"} as SubscriptionArgs const onData = jest.fn() const onError = jest.fn() diff --git a/packages/sdk/src/transport/subscribe/subscribe.ts b/packages/sdk/src/transport/subscribe/subscribe.ts index c2cbca418..5fbedec93 100644 --- a/packages/sdk/src/transport/subscribe/subscribe.ts +++ b/packages/sdk/src/transport/subscribe/subscribe.ts @@ -1,4 +1,4 @@ -import {SdkTransport} from "@onflow/typedefs" +import {SdkTransport, Subscription, SubscriptionTopic} from "@onflow/typedefs" import {rawSubscribe} from "./raw-subscribe" import {decodeResponse} from "../../decode/decode" import {SubscribeParams} from "./types" @@ -9,13 +9,13 @@ import {SubscribeParams} from "./types" * @param opts - Additional options for the subscription. * @returns A promise that resolves when the subscription is active. */ -export function subscribe( +export function subscribe( {topic, args, onData, onError}: SubscribeParams, opts: { node?: string transport?: SdkTransport.Transport } = {} -): SdkTransport.Subscription { +): Subscription { const sub = rawSubscribe( { topic, diff --git a/packages/sdk/src/transport/subscribe/types.ts b/packages/sdk/src/transport/subscribe/types.ts index 0069edf74..d228c8e2b 100644 --- a/packages/sdk/src/transport/subscribe/types.ts +++ b/packages/sdk/src/transport/subscribe/types.ts @@ -1,8 +1,44 @@ -import {SdkTransport} from "@onflow/typedefs" +import { + SubscriptionTopic, + SubscriptionData, + SubscriptionArgs, + RawSubscriptionData, +} from "@onflow/typedefs" -export type SubscribeParams = { +export type SubscribeParams = { + /** + * The topic to subscribe to. + */ topic: T - args: SdkTransport.SubscriptionArguments - onData: (data: SdkTransport.SubscriptionData) => void + /** + * The arguments for the subscription. + */ + args: SubscriptionArgs + /** + * The callback to call when data is received. + */ + onData: (data: SubscriptionData) => void + /** + * The callback to call when a fatal error occurs. + */ + onError: (error: Error) => void +} + +export type RawSubscribeParams = { + /** + * The topic to subscribe to. + */ + topic: T + /** + * The arguments for the subscription. + */ + args: SubscriptionArgs + /** + * The callback to call when data is received. + */ + onData: (data: RawSubscriptionData) => void + /** + * The callback to call when a fatal error occurs. + */ onError: (error: Error) => void } diff --git a/packages/transport-http/src/subscribe/handlers/account-statuses.ts b/packages/transport-http/src/subscribe/handlers/account-statuses.ts index cef3f2f11..1d4ca8779 100644 --- a/packages/transport-http/src/subscribe/handlers/account-statuses.ts +++ b/packages/transport-http/src/subscribe/handlers/account-statuses.ts @@ -1,11 +1,15 @@ -import {SdkTransport} from "@onflow/typedefs" +import { + RawSubscriptionData, + SubscriptionArgs, + SubscriptionData, + SubscriptionTopic, +} from "@onflow/typedefs" import {createSubscriptionHandler} from "./types" -type AccountStatusesArgs = - SdkTransport.SubscriptionArguments +type AccountStatusesArgs = SubscriptionArgs type AccountStatusesData = - SdkTransport.SubscriptionData + RawSubscriptionData type AccountStatusesArgsDto = { start_block_id?: string @@ -32,13 +36,13 @@ type AccountStatusesDataDto = { } export const accountStatusesHandler = createSubscriptionHandler<{ - Topic: SdkTransport.SubscriptionTopic.ACCOUNT_STATUSES - Args: SdkTransport.SubscriptionArguments - Data: SdkTransport.SubscriptionData + Topic: SubscriptionTopic.ACCOUNT_STATUSES + Args: AccountStatusesArgs + Data: AccountStatusesData ArgsDto: AccountStatusesArgsDto DataDto: AccountStatusesDataDto }>({ - topic: SdkTransport.SubscriptionTopic.ACCOUNT_STATUSES, + topic: SubscriptionTopic.ACCOUNT_STATUSES, createSubscriber: (initialArgs, onData, onError) => { let resumeArgs: AccountStatusesArgs = { ...initialArgs, diff --git a/packages/transport-http/src/subscribe/handlers/block-digests.ts b/packages/transport-http/src/subscribe/handlers/block-digests.ts index 0cf9a05d0..2b0a176cc 100644 --- a/packages/transport-http/src/subscribe/handlers/block-digests.ts +++ b/packages/transport-http/src/subscribe/handlers/block-digests.ts @@ -1,11 +1,13 @@ -import {SdkTransport} from "@onflow/typedefs" +import { + SubscriptionTopic, + SubscriptionArgs, + RawSubscriptionData, +} from "@onflow/typedefs" import {BlockArgsDto, createSubscriptionHandler} from "./types" -type BlockDigestsArgs = - SdkTransport.SubscriptionArguments +type BlockDigestsArgs = SubscriptionArgs -type BlockDigestsData = - SdkTransport.SubscriptionData +type BlockDigestsData = RawSubscriptionData type BlockDigestsDataDto = { block_id: string @@ -16,13 +18,13 @@ type BlockDigestsDataDto = { type BlockDigestsArgsDto = BlockArgsDto export const blockDigestsHandler = createSubscriptionHandler<{ - Topic: SdkTransport.SubscriptionTopic.BLOCK_DIGESTS + Topic: SubscriptionTopic.BLOCK_DIGESTS Args: BlockDigestsArgs Data: BlockDigestsData ArgsDto: BlockDigestsArgsDto DataDto: BlockDigestsDataDto }>({ - topic: SdkTransport.SubscriptionTopic.BLOCK_DIGESTS, + topic: SubscriptionTopic.BLOCK_DIGESTS, createSubscriber: (initialArgs, onData, onError) => { let resumeArgs: BlockDigestsArgs = { ...initialArgs, diff --git a/packages/transport-http/src/subscribe/handlers/block-headers.ts b/packages/transport-http/src/subscribe/handlers/block-headers.ts index bf9d51bde..a05fb5d27 100644 --- a/packages/transport-http/src/subscribe/handlers/block-headers.ts +++ b/packages/transport-http/src/subscribe/handlers/block-headers.ts @@ -1,11 +1,13 @@ -import {SdkTransport} from "@onflow/typedefs" +import { + SubscriptionArgs, + RawSubscriptionData, + SubscriptionTopic, +} from "@onflow/typedefs" import {BlockArgsDto, createSubscriptionHandler} from "./types" -type BlockHeadersArgs = - SdkTransport.SubscriptionArguments +type BlockHeadersArgs = SubscriptionArgs -type BlockHeadersData = - SdkTransport.SubscriptionData +type BlockHeadersData = RawSubscriptionData type BlockHeadersArgsDto = BlockArgsDto @@ -18,13 +20,13 @@ type BlockHeadersDataDto = { } export const blockHeadersHandler = createSubscriptionHandler<{ - Topic: SdkTransport.SubscriptionTopic.BLOCK_HEADERS + Topic: SubscriptionTopic.BLOCK_HEADERS Args: BlockHeadersArgs Data: BlockHeadersData ArgsDto: BlockHeadersArgsDto DataDto: BlockHeadersDataDto }>({ - topic: SdkTransport.SubscriptionTopic.BLOCK_HEADERS, + topic: SubscriptionTopic.BLOCK_HEADERS, createSubscriber: (initialArgs, onData, onError) => { let resumeArgs: BlockHeadersArgs = { ...initialArgs, diff --git a/packages/transport-http/src/subscribe/handlers/blocks.ts b/packages/transport-http/src/subscribe/handlers/blocks.ts index c552ebd16..8b0032443 100644 --- a/packages/transport-http/src/subscribe/handlers/blocks.ts +++ b/packages/transport-http/src/subscribe/handlers/blocks.ts @@ -1,11 +1,13 @@ -import {SdkTransport} from "@onflow/typedefs" +import { + RawSubscriptionData, + SubscriptionArgs, + SubscriptionTopic, +} from "@onflow/typedefs" import {createSubscriptionHandler, BlockArgsDto} from "./types" -type BlocksArgs = - SdkTransport.SubscriptionArguments +type BlocksArgs = SubscriptionArgs -type BlocksData = - SdkTransport.SubscriptionData +type BlocksData = RawSubscriptionData type BlocksDataDto = { header: { @@ -28,13 +30,13 @@ type BlocksDataDto = { } export const blocksHandler = createSubscriptionHandler<{ - Topic: SdkTransport.SubscriptionTopic.BLOCKS + Topic: SubscriptionTopic.BLOCKS Args: BlocksArgs Data: BlocksData ArgsDto: BlockArgsDto DataDto: BlocksDataDto }>({ - topic: SdkTransport.SubscriptionTopic.BLOCKS, + topic: SubscriptionTopic.BLOCKS, createSubscriber: (initialArgs, onData, onError) => { let resumeArgs: BlocksArgs = { ...initialArgs, diff --git a/packages/transport-http/src/subscribe/handlers/events.ts b/packages/transport-http/src/subscribe/handlers/events.ts index a63abce42..c460c4133 100644 --- a/packages/transport-http/src/subscribe/handlers/events.ts +++ b/packages/transport-http/src/subscribe/handlers/events.ts @@ -1,11 +1,13 @@ -import {SdkTransport} from "@onflow/typedefs" +import { + SubscriptionTopic, + SubscriptionArgs, + RawSubscriptionData, +} from "@onflow/typedefs" import {createSubscriptionHandler} from "./types" -type EventsArgs = - SdkTransport.SubscriptionArguments +type EventsArgs = SubscriptionArgs -type EventsData = - SdkTransport.SubscriptionData +type EventsData = RawSubscriptionData export type EventsArgsDto = ( | { @@ -35,13 +37,13 @@ type EventsDataDto = { } export const eventsHandler = createSubscriptionHandler<{ - Topic: SdkTransport.SubscriptionTopic.EVENTS + Topic: SubscriptionTopic.EVENTS Args: EventsArgs Data: EventsData ArgsDto: EventsArgsDto DataDto: EventsDataDto }>({ - topic: SdkTransport.SubscriptionTopic.EVENTS, + topic: SubscriptionTopic.EVENTS, createSubscriber: (initialArgs, onData, onError) => { let resumeArgs: EventsArgs = { ...initialArgs, diff --git a/packages/transport-http/src/subscribe/handlers/transaction-statuses.ts b/packages/transport-http/src/subscribe/handlers/transaction-statuses.ts index 35a9a072c..2bd654344 100644 --- a/packages/transport-http/src/subscribe/handlers/transaction-statuses.ts +++ b/packages/transport-http/src/subscribe/handlers/transaction-statuses.ts @@ -1,4 +1,8 @@ -import {SdkTransport} from "@onflow/typedefs" +import { + RawSubscriptionData, + SubscriptionArgs, + SubscriptionTopic, +} from "@onflow/typedefs" import {createSubscriptionHandler} from "./types" import {Buffer} from "buffer" @@ -12,10 +16,10 @@ const STATUS_MAP = { } type TransactionStatusesArgs = - SdkTransport.SubscriptionArguments + SubscriptionArgs type TransactionStatusesData = - SdkTransport.SubscriptionData + RawSubscriptionData type TransactionStatusesArgsDto = { tx_id: string @@ -41,13 +45,13 @@ type TransactionStatusesDataDto = { } export const transactionStatusesHandler = createSubscriptionHandler<{ - Topic: SdkTransport.SubscriptionTopic.TRANSACTION_STATUSES + Topic: SubscriptionTopic.TRANSACTION_STATUSES Args: TransactionStatusesArgs Data: TransactionStatusesData ArgsDto: TransactionStatusesArgsDto DataDto: TransactionStatusesDataDto }>({ - topic: SdkTransport.SubscriptionTopic.TRANSACTION_STATUSES, + topic: SubscriptionTopic.TRANSACTION_STATUSES, createSubscriber: (initialArgs, onData, onError) => { let resumeArgs: TransactionStatusesArgs = { ...initialArgs, diff --git a/packages/transport-http/src/subscribe/subscribe.ts b/packages/transport-http/src/subscribe/subscribe.ts index 8d1f1e36f..145a15a38 100644 --- a/packages/transport-http/src/subscribe/subscribe.ts +++ b/packages/transport-http/src/subscribe/subscribe.ts @@ -1,4 +1,9 @@ -import {SdkTransport} from "@onflow/typedefs" +import { + SubscriptionTopic, + SubscriptionArgs, + Subscription, + RawSubscriptionData, +} from "@onflow/typedefs" import {SubscriptionManager} from "./subscription-manager" import {blocksHandler} from "./handlers/blocks" import {blockHeadersHandler} from "./handlers/block-headers" @@ -22,7 +27,7 @@ let subscriptionManagerMap: Map< SubscriptionManager > = new Map() -export function subscribe( +export function subscribe( { topic, args, @@ -30,12 +35,12 @@ export function subscribe( onError, }: { topic: T - args: SdkTransport.SubscriptionArguments - onData: (data: SdkTransport.SubscriptionData) => void + args: SubscriptionArgs + onData: (data: RawSubscriptionData) => void onError: (error: Error) => void }, opts: {node: string} -): SdkTransport.Subscription { +): Subscription { // Get the SubscriptionManager instance for the access node, or create a new one const node = opts.node const manager = @@ -46,7 +51,7 @@ export function subscribe( return manager.subscribe({ topic, args, - onData, + onData: onData as any, onError, }) } diff --git a/packages/transport-http/src/subscribe/subscription-manager.test.ts b/packages/transport-http/src/subscribe/subscription-manager.test.ts index 255522b01..b25871096 100644 --- a/packages/transport-http/src/subscribe/subscription-manager.test.ts +++ b/packages/transport-http/src/subscribe/subscription-manager.test.ts @@ -10,7 +10,7 @@ import { SubscriptionManager, SubscriptionManagerConfig, } from "./subscription-manager" -import {SdkTransport} from "@onflow/typedefs" +import {SubscriptionTopic} from "@onflow/typedefs" import {DataSubscriber, SubscriptionHandler} from "./handlers/types" jest.mock("./websocket", () => ({ @@ -54,7 +54,7 @@ describe("SubscriptionManager", () => { node: "wss://localhost:8080", } const subscriptionManager = new SubscriptionManager([mockHandler], config) - const topic = "topic" as SdkTransport.SubscriptionTopic + const topic = "topic" as SubscriptionTopic const args = {key: "value"} as any const onData = jest.fn() const onError = jest.fn() @@ -103,7 +103,7 @@ describe("SubscriptionManager", () => { node: "wss://localhost:8080", } const subscriptionManager = new SubscriptionManager([mockHandler], config) - const topic = "topic" as SdkTransport.SubscriptionTopic + const topic = "topic" as SubscriptionTopic const args = {key: "value"} as any const onData = jest.fn() const onError = jest.fn() @@ -168,7 +168,7 @@ describe("SubscriptionManager", () => { node: "wss://localhost:8080", } const subscriptionManager = new SubscriptionManager([mockHandler], config) - const topic = "topic" as SdkTransport.SubscriptionTopic + const topic = "topic" as SubscriptionTopic const args = {key: "value"} as any const onData = jest.fn() const onError = jest.fn() @@ -284,7 +284,7 @@ describe("SubscriptionManager", () => { }, } const subscriptionManager = new SubscriptionManager([mockHandler], config) - const topic = "topic" as SdkTransport.SubscriptionTopic + const topic = "topic" as SubscriptionTopic const args = {key: "value"} as any const onData = jest.fn() const onError = jest.fn() diff --git a/packages/transport-http/src/subscribe/subscription-manager.ts b/packages/transport-http/src/subscribe/subscription-manager.ts index b600c9f98..b0a7879a5 100644 --- a/packages/transport-http/src/subscribe/subscription-manager.ts +++ b/packages/transport-http/src/subscribe/subscription-manager.ts @@ -6,7 +6,7 @@ import { SubscriptionDataMessage, UnsubscribeMessageResponse, } from "./models" -import {SdkTransport} from "@onflow/typedefs" +import {Subscription} from "@onflow/typedefs" import {WebSocket} from "./websocket" import {DataSubscriber, SubscriptionHandler} from "./handlers/types" import * as logger from "@onflow/util-logger" @@ -81,7 +81,7 @@ export class SubscriptionManager[]> { args: InferHandler["Args"] onData: (data: InferHandler["Data"]) => void onError: (error: Error) => void - }): SdkTransport.Subscription { + }): Subscription { const idPromise = this._subscribe(opts) return { diff --git a/packages/typedefs/src/index.ts b/packages/typedefs/src/index.ts index f1af56cea..bae33c885 100644 --- a/packages/typedefs/src/index.ts +++ b/packages/typedefs/src/index.ts @@ -504,3 +504,10 @@ export type EventStream = StreamConnection<{ export * from "./interaction" export * from "./fvm-errors" export * as SdkTransport from "./sdk-transport" +export { + type SubscriptionArgs, + type SubscriptionData, + type RawSubscriptionData, + type Subscription, + SubscriptionTopic, +} from "./subscriptions" diff --git a/packages/typedefs/src/sdk-transport/index.ts b/packages/typedefs/src/sdk-transport/index.ts index 915962252..befd842cf 100644 --- a/packages/typedefs/src/sdk-transport/index.ts +++ b/packages/typedefs/src/sdk-transport/index.ts @@ -1,10 +1,10 @@ -import {SendFn} from "./requests" -import {SubscribeFn} from "./subscriptions" +import {SendFn} from "./send" +import {SubscribeFn} from "./subscribe" export type Transport = { send: SendFn subscribe: SubscribeFn } -export * from "./subscriptions" -export * from "./requests" +export * from "./subscribe" +export * from "./send" diff --git a/packages/typedefs/src/sdk-transport/requests.ts b/packages/typedefs/src/sdk-transport/send.ts similarity index 100% rename from packages/typedefs/src/sdk-transport/requests.ts rename to packages/typedefs/src/sdk-transport/send.ts diff --git a/packages/typedefs/src/sdk-transport/subscribe.ts b/packages/typedefs/src/sdk-transport/subscribe.ts new file mode 100644 index 000000000..3856bad0c --- /dev/null +++ b/packages/typedefs/src/sdk-transport/subscribe.ts @@ -0,0 +1,16 @@ +import { + RawSubscriptionData, + Subscription, + SubscriptionArgs, + SubscriptionTopic, +} from "../subscriptions" + +export type SubscribeFn = ( + params: { + topic: T + args: SubscriptionArgs + onData: (data: RawSubscriptionData) => void + onError: (error: Error) => void + }, + opts: {node: string} +) => Subscription diff --git a/packages/typedefs/src/sdk-transport/subscriptions.ts b/packages/typedefs/src/sdk-transport/subscriptions.ts deleted file mode 100644 index a2f1b796f..000000000 --- a/packages/typedefs/src/sdk-transport/subscriptions.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { - Block, - BlockDigest, - BlockHeader, - Event, - EventFilter, - TransactionExecutionStatus, -} from ".." - -export type SubscriptionSchema = { - [SubscriptionTopic.BLOCKS]: SchemaItem< - BlockArgs, - { - block: Block - } - > - [SubscriptionTopic.BLOCK_HEADERS]: SchemaItem< - BlockArgs, - { - blockHeader: BlockHeader - } - > - [SubscriptionTopic.BLOCK_DIGESTS]: SchemaItem< - BlockArgs, - { - blockDigest: BlockDigest - } - > - [SubscriptionTopic.ACCOUNT_STATUSES]: SchemaItem< - AccountStatusesArgs, - { - accountStatus: Omit & { - payload: string - accountAddress: string - } - } - > - [SubscriptionTopic.TRANSACTION_STATUSES]: SchemaItem< - { - transactionId: string - }, - { - transactionStatus: { - blockId: string - status: TransactionExecutionStatus - statusString: string - statusCode: 0 | 1 - errorMessage: string - events: Array - } - } - > - [SubscriptionTopic.EVENTS]: SchemaItem< - EventFilter, - { - event: Omit & { - payload: string - } - } - > -} - -export enum SubscriptionTopic { - BLOCKS = "blocks", - BLOCK_HEADERS = "block_headers", - BLOCK_DIGESTS = "block_digests", - ACCOUNT_STATUSES = "account_statuses", - TRANSACTION_STATUSES = "transaction_statuses", - EVENTS = "events", -} - -type BlockArgs = - | { - blockStatus: "finalized" | "sealed" - startBlockId?: string - } - | { - blockStatus: "finalized" | "sealed" - startBlockHeight?: number - } - -type AccountStatusesArgs = { - startBlockId?: string - startBlockHeight?: number - eventTypes?: string[] - addresses?: string[] - accountAddresses?: string[] -} - -type SchemaItem = { - args: TArgs - data: TData -} - -export type SubscriptionArguments = - SubscriptionSchema[T]["args"] -export type SubscriptionData = - SubscriptionSchema[T]["data"] - -export type Subscription = { - unsubscribe: () => void -} - -export type SubscribeFn = ( - params: { - topic: T - args: SubscriptionArguments - onData: (data: SubscriptionData) => void - onError: (error: Error) => void - }, - opts: {node: string} -) => Subscription - -type RawEvent = { - type: string - transactionId: string - transactionIndex: number - eventIndex: number - payload: any -} diff --git a/packages/typedefs/src/subscriptions.ts b/packages/typedefs/src/subscriptions.ts new file mode 100644 index 000000000..642cc2dab --- /dev/null +++ b/packages/typedefs/src/subscriptions.ts @@ -0,0 +1,112 @@ +import { + Block, + BlockDigest, + BlockHeader, + Event, + EventFilter, + TransactionExecutionStatus, + TransactionStatus, +} from "." + +export enum SubscriptionTopic { + BLOCKS = "blocks", + BLOCK_HEADERS = "block_headers", + BLOCK_DIGESTS = "block_digests", + ACCOUNT_STATUSES = "account_statuses", + TRANSACTION_STATUSES = "transaction_statuses", + EVENTS = "events", +} + +export type SubscriptionData = + SubscriptionDataMap[T] + +export type RawSubscriptionData = + RawSubscriptionDataMap[T] + +export type SubscriptionArgs = + SubscriptionArgsMap[T] + +export type Subscription = { + unsubscribe: () => void +} + +type SubscriptionArgsMap = { + [SubscriptionTopic.BLOCKS]: BlockArgs + [SubscriptionTopic.BLOCK_HEADERS]: BlockArgs + [SubscriptionTopic.BLOCK_DIGESTS]: BlockArgs + [SubscriptionTopic.ACCOUNT_STATUSES]: AccountStatusesArgs + [SubscriptionTopic.TRANSACTION_STATUSES]: { + transactionId: string + } + [SubscriptionTopic.EVENTS]: EventFilter +} + +type SubscriptionDataMap = { + [SubscriptionTopic.EVENTS]: Event + [SubscriptionTopic.BLOCKS]: Block + [SubscriptionTopic.BLOCK_HEADERS]: BlockHeader + [SubscriptionTopic.BLOCK_DIGESTS]: BlockHeader + [SubscriptionTopic.ACCOUNT_STATUSES]: Omit & { + accountAddress: string + } + [SubscriptionTopic.TRANSACTION_STATUSES]: TransactionStatus +} + +type RawSubscriptionDataMap = { + [SubscriptionTopic.EVENTS]: { + event: Omit & { + payload: string + } + } + [SubscriptionTopic.BLOCKS]: { + block: Block + } + [SubscriptionTopic.BLOCK_HEADERS]: { + blockHeader: BlockHeader + } + [SubscriptionTopic.BLOCK_DIGESTS]: { + blockDigest: BlockDigest + } + [SubscriptionTopic.ACCOUNT_STATUSES]: { + accountStatus: Omit & { + payload: string + accountAddress: string + } + } + [SubscriptionTopic.TRANSACTION_STATUSES]: { + transactionStatus: { + blockId: string + status: TransactionExecutionStatus + statusString: string + statusCode: 0 | 1 + errorMessage: string + events: Array + } + } +} + +type BlockArgs = + | { + blockStatus: "finalized" | "sealed" + startBlockId?: string + } + | { + blockStatus: "finalized" | "sealed" + startBlockHeight?: number + } + +type AccountStatusesArgs = { + startBlockId?: string + startBlockHeight?: number + eventTypes?: string[] + addresses?: string[] + accountAddresses?: string[] +} + +type RawEvent = { + type: string + transactionId: string + transactionIndex: number + eventIndex: number + payload: any +} From 981c120aea6d81b0e467e90827d3be9f9bfb3f0c Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Tue, 1 Apr 2025 14:39:52 -0600 Subject: [PATCH 15/72] Fix endpoint for WS subscriptions (#2277) --- .../src/subscribe/subscribe.test.ts | 58 +++++++++++++++++++ .../transport-http/src/subscribe/subscribe.ts | 13 ++++- .../src/{send => utils}/combine-urls.test.ts | 0 .../src/{send => utils}/combine-urls.ts | 0 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 packages/transport-http/src/subscribe/subscribe.test.ts rename packages/transport-http/src/{send => utils}/combine-urls.test.ts (100%) rename packages/transport-http/src/{send => utils}/combine-urls.ts (100%) diff --git a/packages/transport-http/src/subscribe/subscribe.test.ts b/packages/transport-http/src/subscribe/subscribe.test.ts new file mode 100644 index 000000000..ee486b52a --- /dev/null +++ b/packages/transport-http/src/subscribe/subscribe.test.ts @@ -0,0 +1,58 @@ +import {SubscriptionTopic} from "@onflow/typedefs" +import {subscribe} from "./subscribe" +import {SubscriptionManager} from "./subscription-manager" + +jest.mock("./subscription-manager", () => ({ + SubscriptionManager: jest.fn().mockImplementation(() => { + subscribe: jest.fn().mockReturnValue({unsubscribe: jest.fn()}) + }) as any, +})) + +describe("subscribe", () => { + beforeEach(() => { + jest.resetAllMocks() + }) + + test("subscribes to a topic with correct arguments", () => { + jest.mocked(SubscriptionManager).mockImplementation( + () => + ({ + subscribe: jest.fn().mockReturnValue({unsubscribe: jest.fn()}), + }) as any + ) + + const onData = jest.fn() + const onError = jest.fn() + + const sub = subscribe( + { + topic: SubscriptionTopic.BLOCKS, + args: {blockStatus: "sealed"}, + onData, + onError, + }, + { + node: "wss://localhost:8080", + } + ) + + expect(SubscriptionManager).toHaveBeenCalledTimes(1) + expect(SubscriptionManager).toHaveBeenCalledWith(expect.any(Array), { + node: "wss://localhost:8080/v1/ws", + }) + const instance = jest.mocked(SubscriptionManager).mock.results[0].value + + expect(instance.subscribe).toHaveBeenCalledTimes(1) + expect(instance.subscribe).toHaveBeenCalledWith({ + topic: SubscriptionTopic.BLOCKS, + args: {blockStatus: "sealed"}, + onData, + onError, + }) + + const mockSub = instance.subscribe.mock.results[0].value + + expect(sub).toBeDefined() + expect(sub).toBe(mockSub) + }) +}) diff --git a/packages/transport-http/src/subscribe/subscribe.ts b/packages/transport-http/src/subscribe/subscribe.ts index 145a15a38..e31be2ef6 100644 --- a/packages/transport-http/src/subscribe/subscribe.ts +++ b/packages/transport-http/src/subscribe/subscribe.ts @@ -11,6 +11,7 @@ import {blockDigestsHandler} from "./handlers/block-digests" import {accountStatusesHandler} from "./handlers/account-statuses" import {transactionStatusesHandler} from "./handlers/transaction-statuses" import {eventsHandler} from "./handlers/events" +import {combineURLs} from "../utils/combine-urls" const SUBSCRIPTION_HANDLERS = [ blocksHandler, @@ -42,7 +43,7 @@ export function subscribe( opts: {node: string} ): Subscription { // Get the SubscriptionManager instance for the access node, or create a new one - const node = opts.node + const node = getWsUrl(opts.node) const manager = subscriptionManagerMap.get(node) || new SubscriptionManager(SUBSCRIPTION_HANDLERS, {node}) @@ -55,3 +56,13 @@ export function subscribe( onError, }) } + +function getWsUrl(node: string) { + const url = new URL(combineURLs(node, "/v1/ws")) + if (url.protocol === "https:") { + url.protocol = "wss:" + } else if (url.protocol === "http:") { + url.protocol = "ws:" + } + return url.toString() +} diff --git a/packages/transport-http/src/send/combine-urls.test.ts b/packages/transport-http/src/utils/combine-urls.test.ts similarity index 100% rename from packages/transport-http/src/send/combine-urls.test.ts rename to packages/transport-http/src/utils/combine-urls.test.ts diff --git a/packages/transport-http/src/send/combine-urls.ts b/packages/transport-http/src/utils/combine-urls.ts similarity index 100% rename from packages/transport-http/src/send/combine-urls.ts rename to packages/transport-http/src/utils/combine-urls.ts From 9f31a85af65a6f682b4d7b5c1a0c68210c6bce0e Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Wed, 2 Apr 2025 17:43:27 -0600 Subject: [PATCH 16/72] Replace `fcl.tx` with realtime streaming (#2258) --- .../fcl-core/src/transaction/constants.ts | 1 + packages/fcl-core/src/transaction/index.ts | 2 + .../{index.js => legacy-polling.js} | 41 +--- ...saction.test.js => legacy-polling.test.js} | 2 +- .../src/transaction/transaction.test.ts | 161 +++++++++++++ .../fcl-core/src/transaction/transaction.ts | 224 ++++++++++++++++++ packages/fcl-core/src/transaction/types.ts | 1 + packages/fcl-core/src/transaction/utils.ts | 33 +++ .../transport-http/src/send/http-request.js | 2 +- 9 files changed, 437 insertions(+), 30 deletions(-) create mode 100644 packages/fcl-core/src/transaction/constants.ts create mode 100644 packages/fcl-core/src/transaction/index.ts rename packages/fcl-core/src/transaction/{index.js => legacy-polling.js} (87%) rename packages/fcl-core/src/transaction/{transaction.test.js => legacy-polling.test.js} (98%) create mode 100644 packages/fcl-core/src/transaction/transaction.test.ts create mode 100644 packages/fcl-core/src/transaction/transaction.ts create mode 100644 packages/fcl-core/src/transaction/types.ts create mode 100644 packages/fcl-core/src/transaction/utils.ts diff --git a/packages/fcl-core/src/transaction/constants.ts b/packages/fcl-core/src/transaction/constants.ts new file mode 100644 index 000000000..2973ab48e --- /dev/null +++ b/packages/fcl-core/src/transaction/constants.ts @@ -0,0 +1 @@ +export const TXID_REGEXP = /^[0-9a-fA-F]{64}$/ diff --git a/packages/fcl-core/src/transaction/index.ts b/packages/fcl-core/src/transaction/index.ts new file mode 100644 index 000000000..1f99b5f21 --- /dev/null +++ b/packages/fcl-core/src/transaction/index.ts @@ -0,0 +1,2 @@ +export {TransactionError} from "./transaction-error" +export {transaction} from "./transaction" diff --git a/packages/fcl-core/src/transaction/index.js b/packages/fcl-core/src/transaction/legacy-polling.js similarity index 87% rename from packages/fcl-core/src/transaction/index.js rename to packages/fcl-core/src/transaction/legacy-polling.js index d0d7baaf3..83d7181a5 100644 --- a/packages/fcl-core/src/transaction/index.js +++ b/packages/fcl-core/src/transaction/legacy-polling.js @@ -13,8 +13,20 @@ import {send as fclSend, decode, getTransactionStatus} from "@onflow/sdk" import {HTTPRequestError} from "@onflow/transport-http" import {grpc} from "@improbable-eng/grpc-web" import {TransactionError} from "./transaction-error" +import { + scoped, + isDiff, + isUnknown, + isPending, + isFinalized, + isExecuted, + isSealed, + isExpired, +} from "./utils" +import {TXID_REGEXP} from "./constants" -const TXID_REGEXP = /^[0-9a-fA-F]{64}$/ +const POLL = "POLL" +const TIMEOUT = "TIMEOUT" /** * @typedef {import("@onflow/typedefs").Transaction} Transaction @@ -24,24 +36,10 @@ const TXID_REGEXP = /^[0-9a-fA-F]{64}$/ * @typedef {import("@onflow/typedefs").TransactionStatus} TransactionStatus */ -const POLL = "POLL" -const TIMEOUT = "TIMEOUT" - const fetchTxStatus = async transactionId => { return fclSend([getTransactionStatus(transactionId)]).then(decode) } -const isExpired = tx => tx.status === 5 -const isSealed = tx => tx.status >= 4 -const isExecuted = tx => tx.status >= 3 -const isFinalized = tx => tx.status >= 2 -const isPending = tx => tx.status >= 1 -const isUnknown = tx => tx.status >= 0 - -const isDiff = (cur, next) => { - return JSON.stringify(cur) !== JSON.stringify(next) -} - const makeHandlers = (opts = {}) => ({ [INIT]: async ctx => { setTimeout(() => ctx.sendSelf(TIMEOUT), opts.txNotFoundTimeout) @@ -94,25 +92,12 @@ const makeHandlers = (opts = {}) => ({ }, }) -const scoped = transactionId => { - if (typeof transactionId === "object") - transactionId = transactionId.transactionId - if (transactionId == null) throw new Error("transactionId required") - return transactionId -} - const spawnTransaction = (opts = {}) => transactionId => { return spawn(makeHandlers(opts), scoped(transactionId)) } -/** - * @callback SubscriptionCallback - * @param {TransactionStatus} txStatus - * @returns {void} - */ - /** * Provides methods for interacting with a transaction * diff --git a/packages/fcl-core/src/transaction/transaction.test.js b/packages/fcl-core/src/transaction/legacy-polling.test.js similarity index 98% rename from packages/fcl-core/src/transaction/transaction.test.js rename to packages/fcl-core/src/transaction/legacy-polling.test.js index 5c7ab94f7..cdf5ff646 100644 --- a/packages/fcl-core/src/transaction/transaction.test.js +++ b/packages/fcl-core/src/transaction/legacy-polling.test.js @@ -1,5 +1,5 @@ import {HTTPRequestError} from "@onflow/transport-http" -import {transaction} from "./index.js" +import {transaction} from "./legacy-polling" import {config} from "@onflow/config" describe("transaction", () => { diff --git a/packages/fcl-core/src/transaction/transaction.test.ts b/packages/fcl-core/src/transaction/transaction.test.ts new file mode 100644 index 000000000..316d1438a --- /dev/null +++ b/packages/fcl-core/src/transaction/transaction.test.ts @@ -0,0 +1,161 @@ +import {subscribe} from "@onflow/sdk" +import {SubscriptionsNotSupportedError} from "@onflow/sdk" +import {SubscriptionTopic, TransactionExecutionStatus} from "@onflow/typedefs" +import {transaction} from "./transaction" +import {transaction as legacyTransaction} from "./legacy-polling" + +jest.mock("@onflow/sdk") +jest.mock("./legacy-polling") + +describe("transaction", () => { + beforeEach(() => { + jest.clearAllMocks() + + jest.mocked(subscribe).mockReturnValue({ + unsubscribe: jest.fn(), + }) + + jest.mocked(legacyTransaction).mockReturnValue({ + subscribe: jest.fn(), + onceExecuted: jest.fn(), + onceSealed: jest.fn(), + onceFinalized: jest.fn(), + snapshot: jest.fn(), + }) + }) + + test("should throw an error if transactionId is not a 64 byte hash string", () => { + const {transaction} = require("./transaction") + + const actual = () => transaction("invalid-transaction-id") + expect(actual).toThrow("Invalid transactionId") + }) + + test("subscribe should report transaction status", async () => { + const txId = + "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" + const callback = jest.fn() + const unsubscribe = transaction(txId).subscribe(callback) + + // Expect the subscribe method to be called with the correct parameters + const subscribeParams = jest.mocked(subscribe).mock + .calls[0][0] as Parameters< + typeof subscribe + >[0] + + expect(subscribeParams).toStrictEqual({ + topic: SubscriptionTopic.TRANSACTION_STATUSES, + args: {transactionId: txId}, + onData: expect.any(Function), + onError: expect.any(Function), + }) + + // Mock the observable to emit a PENDING status + subscribeParams.onData({ + status: TransactionExecutionStatus.PENDING, + blockId: "", + statusCode: 0, + errorMessage: "", + events: [], + statusString: "PENDING", + }) + + // Mock the observable to emit a SEALED status + subscribeParams.onData({ + status: TransactionExecutionStatus.SEALED, + blockId: "", + statusCode: 0, + errorMessage: "", + events: [], + statusString: "SEALED", + }) + + // Expect all subscription data to be reported + expect(callback.mock.calls).toStrictEqual([ + [ + { + blockId: "", + status: TransactionExecutionStatus.UNKNOWN, + statusString: "", + statusCode: 0, + errorMessage: "", + events: [], + }, + ], + [ + { + status: TransactionExecutionStatus.PENDING, + blockId: "", + statusCode: 0, + errorMessage: "", + events: [], + statusString: "PENDING", + }, + ], + [ + { + status: TransactionExecutionStatus.SEALED, + blockId: "", + statusCode: 0, + errorMessage: "", + events: [], + statusString: "SEALED", + }, + ], + ]) + + unsubscribe() + }) + + test("subscribe should report an error if the transactionId is invalid", async () => { + const txId = "INVALID_TRANSACTION_ID" + + expect(() => transaction(txId)).toThrow("Invalid transactionId") + }) + + test("subscribe should fallback to polling if real-time streaming is not supported", async () => { + const txId = + "2234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" + const onData = jest.fn() + const onError = jest.fn() + const unsubscribe = transaction(txId).subscribe(onData, onError) + + // Expect the subscribe method to be called with the correct parameters + const subscribeParams = jest.mocked(subscribe).mock + .calls[0][0] as Parameters< + typeof subscribe + >[0] + + expect(subscribeParams).toStrictEqual({ + topic: SubscriptionTopic.TRANSACTION_STATUSES, + args: {transactionId: txId}, + onData: expect.any(Function), + onError: expect.any(Function), + }) + + // Mock the observable to emit an error + subscribeParams.onError(new SubscriptionsNotSupportedError()) + + // Expect the error to be reported + expect(onData.mock.calls).toStrictEqual([ + [ + { + blockId: "", + status: TransactionExecutionStatus.UNKNOWN, + statusString: "", + statusCode: 0, + errorMessage: "", + events: [], + }, + ], + ]) + expect(onError).not.toHaveBeenCalled() + + expect(legacyTransaction).toHaveBeenCalledWith(txId, { + pollRate: 1000, + txNotFoundTimeout: 12500, + }) + + unsubscribe() + }) +}) diff --git a/packages/fcl-core/src/transaction/transaction.ts b/packages/fcl-core/src/transaction/transaction.ts new file mode 100644 index 000000000..69b491084 --- /dev/null +++ b/packages/fcl-core/src/transaction/transaction.ts @@ -0,0 +1,224 @@ +import "../default-config" +import { + SubscriptionTopic, + TransactionExecutionStatus, + TransactionStatus, +} from "@onflow/typedefs" +import { + isDiff, + isExecuted, + isExpired, + isFinalized, + isPending, + isSealed, + scoped, +} from "./utils" +import {TXID_REGEXP} from "./constants" +import { + isUnknown, + subscribe as sdkSubscribe, + SubscriptionsNotSupportedError, +} from "@onflow/sdk" +import {TransactionError} from "./transaction-error" +import {transaction as legacyTransaction} from "./legacy-polling" + +// Map of transaction observables +// Used for shared global singleton to prevent duplicate subscriptions +const registry = new Map>() + +/** + * Provides methods for interacting with a transaction + * + * @param transactionId - The transaction ID + * @param opts - Optional parameters + * @param opts.pollRate - Polling rate in milliseconds + * @param opts.txNotFoundTimeout - Timeout in milliseconds for ignoring transaction not found errors (do not modify unless you know what you are doing) + * @throws {Error} If transactionId is not a 64 byte hash string + */ +export function transaction( + transactionId: string, + opts: { + pollRate?: number + txNotFoundTimeout?: number + } = {txNotFoundTimeout: 12500, pollRate: 1000} +): { + snapshot: () => Promise + subscribe: ( + onData: (txStatus: TransactionStatus) => void, + onError?: (err: Error) => void + ) => () => void + onceFinalized: () => Promise + onceExecuted: () => Promise + onceSealed: () => Promise +} { + // Validate transactionId as 64 byte hash + if (!TXID_REGEXP.test(scoped(transactionId))) + throw new Error("Invalid transactionId") + + function getObservable() { + let observable = registry.get(transactionId) + if (!observable) { + observable = createObservable(transactionId, opts) + registry.set(transactionId, observable) + } + return observable + } + + function snapshot() { + return Promise.resolve(getObservable().value) + } + + function subscribe( + onData: (txStatus: TransactionStatus) => void, + onError?: (err: Error) => void + ) { + const observable = getObservable() + const {unsubscribe} = observable.subscribe(onData, onError) + return () => unsubscribe() + } + + function once(predicate: (txStatus: TransactionStatus) => boolean) { + return function innerOnce(opts = {suppress: false}) { + const suppress = opts.suppress || false + return new Promise((resolve, reject) => { + const unsub = subscribe((( + txStatus?: TransactionStatus, + error?: Error + ) => { + if ((error || txStatus?.statusCode) && !suppress) { + if (error != null) { + reject(error) + unsub() + } else if (txStatus?.statusCode === 1) { + const transactionError = TransactionError.fromErrorMessage( + txStatus.errorMessage + ) + reject(transactionError) + unsub() + } + return + } + + if (predicate(txStatus!)) { + resolve(txStatus!) + unsub() + } + }) as any) + }) as Promise + } + } + + return { + snapshot, + subscribe, + onceFinalized: once(isFinalized), + onceExecuted: once(isExecuted), + onceSealed: once(isSealed), + } +} + +transaction.isUnknown = isUnknown +transaction.isPending = isPending +transaction.isFinalized = isFinalized +transaction.isExecuted = isExecuted +transaction.isSealed = isSealed +transaction.isExpired = isExpired + +/** + * Creates an observable for a transaction + */ +function createObservable( + txId: string, + opts: {pollRate?: number; txNotFoundTimeout?: number} +) { + const observers = new Set<{ + onData: (txStatus: TransactionStatus) => void + onError: (err: Error) => void + }>() + let value: TransactionStatus = { + blockId: "", + status: TransactionExecutionStatus.UNKNOWN, + statusCode: 0, + errorMessage: "", + events: [], + statusString: "", + } + + // Subscribe to transaction status updates + sdkSubscribe({ + topic: SubscriptionTopic.TRANSACTION_STATUSES, + args: {transactionId: txId}, + onData: txStatus => { + if (isDiff(value, txStatus)) { + value = txStatus + next(txStatus) + } + }, + onError: (err: Error) => { + if (err instanceof SubscriptionsNotSupportedError) { + fallbackLegacyPolling() + } else { + error(err) + } + }, + }) + + function fallbackLegacyPolling() { + console.warn( + "Failed to subscribe to transaction status updates using real-time streaming (are you using the deprecated GRPC transport?), falling back to polling." + ) + + // Poll for transaction status updates + legacyTransaction(txId, opts).subscribe( + (txStatus?: TransactionStatus, err?: Error) => { + if (err) { + error(err) + } else if (txStatus) { + value = txStatus + next(txStatus) + } + } + ) + } + + function next(txStatus: TransactionStatus) { + for (const observer of observers) { + try { + observer.onData(txStatus) + } catch (error) { + console.error("Error in transaction observer", error) + } + } + } + + function error(err: Error) { + for (const observer of observers) { + try { + observer.onError(err) + } catch (error) { + console.error("Error in transaction observer", error) + } + } + } + + return { + subscribe( + onData: (status: TransactionStatus) => void, + onError?: (error: Error) => void + ) { + const observer = { + onData, + onError: onError || (() => {}), + } + observers.add(observer) + onData(value) + + return { + unsubscribe: () => observers.delete(observer), + } + }, + get value() { + return value + }, + } +} diff --git a/packages/fcl-core/src/transaction/types.ts b/packages/fcl-core/src/transaction/types.ts new file mode 100644 index 000000000..d2a6b34f7 --- /dev/null +++ b/packages/fcl-core/src/transaction/types.ts @@ -0,0 +1 @@ +import {TransactionStatus} from "@onflow/typedefs" diff --git a/packages/fcl-core/src/transaction/utils.ts b/packages/fcl-core/src/transaction/utils.ts new file mode 100644 index 000000000..3cbe31cd6 --- /dev/null +++ b/packages/fcl-core/src/transaction/utils.ts @@ -0,0 +1,33 @@ +import {TransactionStatus} from "@onflow/typedefs" + +export const isExpired = (tx: TransactionStatus) => tx.status === 5 +export const isSealed = (tx: TransactionStatus) => tx.status >= 4 +export const isExecuted = (tx: TransactionStatus) => tx.status >= 3 +export const isFinalized = (tx: TransactionStatus) => tx.status >= 2 +export const isPending = (tx: TransactionStatus) => tx.status >= 1 +export const isUnknown = (tx: TransactionStatus) => tx.status >= 0 + +export const deepEqual = (a: any, b: any): boolean => { + if (a === b) return true + if (typeof a !== "object" || typeof b !== "object") return false + if (Object.keys(a).length !== Object.keys(b).length) return false + for (const key in a) if (!deepEqual(a[key], b[key])) return false + return true +} + +export const isDiff = (a: any, b: any): boolean => { + return !deepEqual(a, b) +} + +export const scoped = ( + transactionId: + | string + | { + transactionId: string + } +) => { + if (typeof transactionId === "object") + transactionId = transactionId.transactionId + if (transactionId == null) throw new Error("transactionId required") + return transactionId +} diff --git a/packages/transport-http/src/send/http-request.js b/packages/transport-http/src/send/http-request.js index e76129969..4797306ea 100644 --- a/packages/transport-http/src/send/http-request.js +++ b/packages/transport-http/src/send/http-request.js @@ -1,7 +1,7 @@ import * as logger from "@onflow/util-logger" import fetchTransport from "cross-fetch" import {safeParseJSON} from "./utils" -import {combineURLs} from "./combine-urls" +import {combineURLs} from "../utils/combine-urls" const AbortController = globalThis.AbortController || require("abort-controller") From 93a6b13fe49acad9042b3b6b69a2ddcf324a7f92 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Thu, 3 Apr 2025 13:06:45 -0600 Subject: [PATCH 17/72] Reorganize subscriptions types (#2301) --- .../sdk/src/transport/get-transport.test.ts | 8 ++-- packages/sdk/src/transport/get-transport.ts | 12 +++--- .../src/transport/subscribe/raw-subscribe.ts | 4 +- .../src/transport/subscribe/subscribe.test.ts | 2 +- .../sdk/src/transport/subscribe/subscribe.ts | 2 +- packages/transport-http/src/transport.ts | 2 +- packages/typedefs/src/index.ts | 8 +++- packages/typedefs/src/sdk-transport/index.ts | 10 ----- .../typedefs/src/sdk-transport/subscribe.ts | 16 -------- packages/typedefs/src/subscriptions.ts | 39 ++++++++++--------- .../{sdk-transport/send.ts => transport.ts} | 25 +++++++++++- 11 files changed, 64 insertions(+), 64 deletions(-) delete mode 100644 packages/typedefs/src/sdk-transport/index.ts delete mode 100644 packages/typedefs/src/sdk-transport/subscribe.ts rename packages/typedefs/src/{sdk-transport/send.ts => transport.ts} (79%) diff --git a/packages/sdk/src/transport/get-transport.test.ts b/packages/sdk/src/transport/get-transport.test.ts index 9e78b8d30..91268505a 100644 --- a/packages/sdk/src/transport/get-transport.test.ts +++ b/packages/sdk/src/transport/get-transport.test.ts @@ -7,7 +7,7 @@ jest.mock("@onflow/transport-http", () => ({ httpTransport: { send: jest.fn(), subscribe: jest.fn(), - } as jest.Mocked, + } as jest.Mocked, })) describe("getTransport", () => { @@ -24,7 +24,7 @@ describe("getTransport", () => { const customTransport = { send: jest.fn(), subscribe: jest.fn(), - } as jest.Mocked + } as jest.Mocked const transport = await getTransport({transport: customTransport}) expect(transport).toBe(customTransport) @@ -58,7 +58,7 @@ describe("getTransport", () => { const customTransport = { send: jest.fn(), subscribe: jest.fn(), - } as jest.Mocked + } as jest.Mocked const tranpsort = await config().overload( { @@ -111,7 +111,7 @@ describe("getTransport", () => { const customTransport = { send: jest.fn(), subscribe: jest.fn(), - } as jest.Mocked + } as jest.Mocked const transport = await config().overload( { diff --git a/packages/sdk/src/transport/get-transport.ts b/packages/sdk/src/transport/get-transport.ts index 972d52571..f08a2345f 100644 --- a/packages/sdk/src/transport/get-transport.ts +++ b/packages/sdk/src/transport/get-transport.ts @@ -11,10 +11,10 @@ import {SubscriptionsNotSupportedError} from "./subscribe/errors" */ export async function getTransport( override: { - send?: SdkTransport.SendFn - transport?: SdkTransport.Transport + send?: SdkTransport["send"] + transport?: SdkTransport } = {} -): Promise { +): Promise { invariant( override.send == null || override.transport == null, `SDK Transport Error: Cannot provide both "transport" and legacy "send" options.` @@ -23,7 +23,7 @@ export async function getTransport( const transportOrSend = override.transport || override.send || - (await config().first( + (await config().first( ["sdk.transport", "sdk.send"], defaultTransport )) @@ -41,9 +41,7 @@ export async function getTransport( return transportOrSend } -function isTransportObject( - transport: any -): transport is SdkTransport.Transport { +function isTransportObject(transport: any): transport is SdkTransport { return ( transport.send !== undefined && transport.subscribe !== undefined && diff --git a/packages/sdk/src/transport/subscribe/raw-subscribe.ts b/packages/sdk/src/transport/subscribe/raw-subscribe.ts index 8a4929038..f02a4f8d9 100644 --- a/packages/sdk/src/transport/subscribe/raw-subscribe.ts +++ b/packages/sdk/src/transport/subscribe/raw-subscribe.ts @@ -14,11 +14,11 @@ export function rawSubscribe( {topic, args, onData, onError}: RawSubscribeParams, opts: { node?: string - transport?: SdkTransport.Transport + transport?: SdkTransport } = {} ) { async function subscribe() { - let transport: SdkTransport.Transport + let transport: SdkTransport let node: string try { diff --git a/packages/sdk/src/transport/subscribe/subscribe.test.ts b/packages/sdk/src/transport/subscribe/subscribe.test.ts index 3e8358782..8ec15cc1a 100644 --- a/packages/sdk/src/transport/subscribe/subscribe.test.ts +++ b/packages/sdk/src/transport/subscribe/subscribe.test.ts @@ -95,7 +95,7 @@ describe("subscribe", () => { const transport = { send: jest.fn(), subscribe: jest.fn().mockResolvedValue(mockSub), - } as jest.Mocked + } as jest.Mocked const sub = await subscribe( { diff --git a/packages/sdk/src/transport/subscribe/subscribe.ts b/packages/sdk/src/transport/subscribe/subscribe.ts index 5fbedec93..0325b572d 100644 --- a/packages/sdk/src/transport/subscribe/subscribe.ts +++ b/packages/sdk/src/transport/subscribe/subscribe.ts @@ -13,7 +13,7 @@ export function subscribe( {topic, args, onData, onError}: SubscribeParams, opts: { node?: string - transport?: SdkTransport.Transport + transport?: SdkTransport } = {} ): Subscription { const sub = rawSubscribe( diff --git a/packages/transport-http/src/transport.ts b/packages/transport-http/src/transport.ts index c0484d062..b06380d89 100644 --- a/packages/transport-http/src/transport.ts +++ b/packages/transport-http/src/transport.ts @@ -2,7 +2,7 @@ import {SdkTransport} from "@onflow/typedefs" import {send} from "./send/send-http" import {subscribe} from "./subscribe/subscribe" -export const httpTransport: SdkTransport.Transport = { +export const httpTransport: SdkTransport = { send, subscribe, } diff --git a/packages/typedefs/src/index.ts b/packages/typedefs/src/index.ts index bae33c885..94c59ccae 100644 --- a/packages/typedefs/src/index.ts +++ b/packages/typedefs/src/index.ts @@ -254,6 +254,12 @@ export type Event = { */ data: any } +export type AccountStatusEvent = Event & { + /** + * - The address of the account which the event is associated with. + */ + accountAddress: string +} export type Key = { /** * - Sequence number of key used by the proposer of this transaction @@ -503,7 +509,7 @@ export type EventStream = StreamConnection<{ export * from "./interaction" export * from "./fvm-errors" -export * as SdkTransport from "./sdk-transport" +export {type SdkTransport} from "./transport" export { type SubscriptionArgs, type SubscriptionData, diff --git a/packages/typedefs/src/sdk-transport/index.ts b/packages/typedefs/src/sdk-transport/index.ts deleted file mode 100644 index befd842cf..000000000 --- a/packages/typedefs/src/sdk-transport/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {SendFn} from "./send" -import {SubscribeFn} from "./subscribe" - -export type Transport = { - send: SendFn - subscribe: SubscribeFn -} - -export * from "./subscribe" -export * from "./send" diff --git a/packages/typedefs/src/sdk-transport/subscribe.ts b/packages/typedefs/src/sdk-transport/subscribe.ts deleted file mode 100644 index 3856bad0c..000000000 --- a/packages/typedefs/src/sdk-transport/subscribe.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { - RawSubscriptionData, - Subscription, - SubscriptionArgs, - SubscriptionTopic, -} from "../subscriptions" - -export type SubscribeFn = ( - params: { - topic: T - args: SubscriptionArgs - onData: (data: RawSubscriptionData) => void - onError: (error: Error) => void - }, - opts: {node: string} -) => Subscription diff --git a/packages/typedefs/src/subscriptions.ts b/packages/typedefs/src/subscriptions.ts index 642cc2dab..1b7af33d1 100644 --- a/packages/typedefs/src/subscriptions.ts +++ b/packages/typedefs/src/subscriptions.ts @@ -1,4 +1,5 @@ import { + AccountStatusEvent, Block, BlockDigest, BlockHeader, @@ -31,14 +32,12 @@ export type Subscription = { } type SubscriptionArgsMap = { - [SubscriptionTopic.BLOCKS]: BlockArgs - [SubscriptionTopic.BLOCK_HEADERS]: BlockArgs - [SubscriptionTopic.BLOCK_DIGESTS]: BlockArgs - [SubscriptionTopic.ACCOUNT_STATUSES]: AccountStatusesArgs - [SubscriptionTopic.TRANSACTION_STATUSES]: { - transactionId: string - } - [SubscriptionTopic.EVENTS]: EventFilter + [SubscriptionTopic.BLOCKS]: BlockSubscriptionArgs + [SubscriptionTopic.BLOCK_HEADERS]: BlockSubscriptionArgs + [SubscriptionTopic.BLOCK_DIGESTS]: BlockSubscriptionArgs + [SubscriptionTopic.ACCOUNT_STATUSES]: AccountStatusSubscriptionArgs + [SubscriptionTopic.TRANSACTION_STATUSES]: TransactionStatusSubscriptionArgs + [SubscriptionTopic.EVENTS]: EventSubscriptionArgs } type SubscriptionDataMap = { @@ -46,9 +45,7 @@ type SubscriptionDataMap = { [SubscriptionTopic.BLOCKS]: Block [SubscriptionTopic.BLOCK_HEADERS]: BlockHeader [SubscriptionTopic.BLOCK_DIGESTS]: BlockHeader - [SubscriptionTopic.ACCOUNT_STATUSES]: Omit & { - accountAddress: string - } + [SubscriptionTopic.ACCOUNT_STATUSES]: AccountStatusEvent [SubscriptionTopic.TRANSACTION_STATUSES]: TransactionStatus } @@ -80,12 +77,18 @@ type RawSubscriptionDataMap = { statusString: string statusCode: 0 | 1 errorMessage: string - events: Array + events: { + type: string + transactionId: string + transactionIndex: number + eventIndex: number + payload: string + }[] } } } -type BlockArgs = +type BlockSubscriptionArgs = | { blockStatus: "finalized" | "sealed" startBlockId?: string @@ -95,7 +98,7 @@ type BlockArgs = startBlockHeight?: number } -type AccountStatusesArgs = { +type AccountStatusSubscriptionArgs = { startBlockId?: string startBlockHeight?: number eventTypes?: string[] @@ -103,10 +106,8 @@ type AccountStatusesArgs = { accountAddresses?: string[] } -type RawEvent = { - type: string +type TransactionStatusSubscriptionArgs = { transactionId: string - transactionIndex: number - eventIndex: number - payload: any } + +type EventSubscriptionArgs = EventFilter diff --git a/packages/typedefs/src/sdk-transport/send.ts b/packages/typedefs/src/transport.ts similarity index 79% rename from packages/typedefs/src/sdk-transport/send.ts rename to packages/typedefs/src/transport.ts index 07a0b0665..b48fa7b5f 100644 --- a/packages/typedefs/src/sdk-transport/send.ts +++ b/packages/typedefs/src/transport.ts @@ -1,4 +1,10 @@ -import {Interaction} from "../interaction" +import {Interaction} from "./interaction" +import { + RawSubscriptionData, + Subscription, + SubscriptionArgs, + SubscriptionTopic, +} from "./subscriptions" interface InteractionModule { isTransaction: (ix: Interaction) => boolean @@ -82,4 +88,19 @@ interface IOpts extends IOptsCommon { ) => void } -export type SendFn = (ix: Interaction, context: IContext, opts: IOpts) => void +type SubscribeFn = ( + params: { + topic: T + args: SubscriptionArgs + onData: (data: RawSubscriptionData) => void + onError: (error: Error) => void + }, + opts: {node: string} +) => Subscription + +type SendFn = (ix: Interaction, context: IContext, opts: IOpts) => void + +export type SdkTransport = { + send: SendFn + subscribe: SubscribeFn +} From fa403b28989e9fd4e2e07f1edff2e7c2aff0d466 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Thu, 3 Apr 2025 15:33:28 -0600 Subject: [PATCH 18/72] Add legacy `fcl.events` fallback for emulator (#2287) --- packages/fcl-core/src/events/index.test.ts | 113 ++++++++++++++---- packages/fcl-core/src/events/index.ts | 92 ++++++++++---- packages/fcl-core/src/events/legacy-events.js | 2 +- 3 files changed, 157 insertions(+), 50 deletions(-) diff --git a/packages/fcl-core/src/events/index.test.ts b/packages/fcl-core/src/events/index.test.ts index b0d207e6d..4fec5e20d 100644 --- a/packages/fcl-core/src/events/index.test.ts +++ b/packages/fcl-core/src/events/index.test.ts @@ -2,9 +2,11 @@ import {Subscription} from "@onflow/typedefs" import {events} from "." import {subscribe, SubscriptionsNotSupportedError} from "@onflow/sdk" import {events as legacyEvents} from "./legacy-events" +import {getChainId} from "../utils" jest.mock("@onflow/sdk") jest.mock("./legacy-events") +jest.mock("../utils") describe("events", () => { let mockSubscription: jest.Mocked @@ -28,11 +30,14 @@ describe("events", () => { jest.clearAllMocks() }) - test("subscribe should call subscribe with the correct arguments", () => { + test("subscribe should call subscribe with the correct arguments", async () => { const filter = {eventTypes: ["A"]} events(filter).subscribe(() => {}) + // Flush the event loop + await new Promise(resolve => setTimeout(resolve, 0)) + expect(subscribe).toHaveBeenCalledWith({ topic: "events", args: filter, @@ -41,8 +46,12 @@ describe("events", () => { }) }) - test("should work with a string", () => { + test("should work with a string", async () => { events("A").subscribe(() => {}) + + // Flush the event loop + await new Promise(resolve => setTimeout(resolve, 0)) + expect(subscribe).toHaveBeenCalledWith({ topic: "events", args: {eventTypes: ["A"]}, @@ -51,8 +60,12 @@ describe("events", () => { }) }) - test("should work with empty args", () => { + test("should work with empty args", async () => { events().subscribe(() => {}) + + // Flush the event loop + await new Promise(resolve => setTimeout(resolve, 0)) + expect(subscribe).toHaveBeenCalledWith({ topic: "events", args: {}, @@ -63,7 +76,8 @@ describe("events", () => { test("subscribe should pipe the events to the callback", async () => { const filter = {eventTypes: ["A"]} - const callback = jest.fn() + const onData = jest.fn() + const onError = jest.fn() const mockEvents = [{type: "A"}, {type: "B"}] as any[] @@ -72,57 +86,108 @@ describe("events", () => { return mockSubscription }) - events(filter).subscribe(callback) + events(filter).subscribe(onData, onError) + + // Flush the event loop await new Promise(resolve => setTimeout(resolve, 0)) - expect(callback.mock.calls).toEqual([ - [mockEvents[0], null], - [mockEvents[1], null], - ]) + expect(onData.mock.calls).toEqual([[{type: "A"}], [{type: "B"}]]) + expect(onError).not.toHaveBeenCalled() }) test("subscribe should pipe the errors to the callback", async () => { const filter = {eventTypes: ["A"]} - const callback = jest.fn() + const onData = jest.fn() + const onError = jest.fn() const mockError = new Error("mock error") - jest.mocked(subscribe).mockImplementation(({onError}) => { - onError(mockError) + jest.mocked(subscribe).mockImplementation(({onError: _onError}) => { + _onError(mockError) return mockSubscription }) - events(filter).subscribe(callback) + events(filter).subscribe(onData, onError) + + // Flush the event loop await new Promise(resolve => setTimeout(resolve, 0)) - expect(callback.mock.calls).toEqual([[null, mockError]]) + expect(onData).not.toHaveBeenCalled() + expect(onError).toHaveBeenCalledTimes(1) + expect(onError).toHaveBeenCalledWith(mockError) }) test("fallback to legacy polling if subscriptions are not supported", async () => { const filter = "A" - const callback = jest.fn() + const onData = jest.fn() + const onError = jest.fn() - const mockError = new SubscriptionsNotSupportedError() + const mockNotSupportedError = new SubscriptionsNotSupportedError() - jest.mocked(subscribe).mockImplementation(({onError}) => { - onError(mockError) + jest.mocked(subscribe).mockImplementation(({onError: _onError}) => { + _onError(mockNotSupportedError) return mockSubscription }) - const unsubscribe = events(filter).subscribe(callback) + const unsubscribe = events(filter).subscribe(onData, onError) + + // Flush the event loop await new Promise(resolve => setTimeout(resolve, 0)) - // Check that the callback was called - expect(callback).toHaveBeenCalledTimes(0) - expect(subscribe).toHaveBeenCalledTimes(1) + // Check that the error did not propagate to the onError callback + expect(onData).not.toHaveBeenCalled() + expect(onError).not.toHaveBeenCalled() + + // Check that the legacy subscribe was called + expect(mockLegacySubscribeObject.subscribe).toHaveBeenCalledTimes(1) + expect(mockLegacyUnsubscribe).not.toHaveBeenCalled() - // Check that legacy polling was called + // Check that the legacy events were called with the correct filter expect(legacyEvents).toHaveBeenCalledWith(filter) - expect(mockLegacySubscribeObject.subscribe).toHaveBeenCalledWith(callback) + expect(mockLegacySubscribeObject.subscribe).toHaveBeenCalledWith( + expect.any(Function) + ) + + // Mock the legacy subscribe to call the onData callback + const legacyOnData = ( + mockLegacySubscribeObject.subscribe.mock.calls as any + )[0][0] as jest.Mock + const mockLegacyEvents = [{type: "A"}, {type: "B"}] as any[] + mockLegacyEvents.forEach(event => legacyOnData(event)) + + // Flush the event loop + await new Promise(resolve => setTimeout(resolve, 0)) + + // Check that the onData callback was called with the legacy events + expect(onData.mock.calls).toEqual([[{type: "A"}], [{type: "B"}]]) + expect(onError).not.toHaveBeenCalled() + expect(mockLegacyUnsubscribe).not.toHaveBeenCalled() // Unsubscribe unsubscribe() + + // Flush the event loop + await new Promise(resolve => setTimeout(resolve, 0)) + expect(mockSubscription.unsubscribe).toHaveBeenCalledTimes(1) expect(mockLegacyUnsubscribe).toHaveBeenCalledTimes(1) }) + + test("emulator should fallback to legacy polling", async () => { + const filter = "A" + const onData = jest.fn() + const onError = jest.fn() + + jest.mocked(getChainId).mockResolvedValue("local") + + events(filter).subscribe(onData, onError) + + // Flush the event loop + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(legacyEvents).toHaveBeenCalledWith(filter) + expect(mockLegacySubscribeObject.subscribe).toHaveBeenCalledWith( + expect.any(Function) + ) + }) }) diff --git a/packages/fcl-core/src/events/index.ts b/packages/fcl-core/src/events/index.ts index 49e790fed..cfd9ad603 100644 --- a/packages/fcl-core/src/events/index.ts +++ b/packages/fcl-core/src/events/index.ts @@ -2,6 +2,9 @@ import {subscribe} from "@onflow/sdk" import {Event, EventFilter, SubscriptionTopic} from "@onflow/typedefs" import {events as legacyEvents} from "./legacy-events" import {SubscriptionsNotSupportedError} from "@onflow/sdk" +import {getChainId} from "../utils" + +const FLOW_EMULATOR = "local" /** * @description - Subscribe to events @@ -22,43 +25,82 @@ export function events(filterOrType?: EventFilter | string) { return { subscribe: ( - callback: (events: Event | null, error: Error | null) => void - ) => { + onData: (event: Event) => void, + onError: (error: Error) => void = (error: Error) => { + console.error("Unhandled error in event subscription:", error) + } + ): (() => void) => { + let unsubscribeFn = () => {} let unsubscribeFnLegacy = () => {} - const {unsubscribe: unsubscribeFn} = subscribe({ - topic: SubscriptionTopic.EVENTS, - args: filter, - onData: data => { - callback(data, null) - }, - onError: (error: Error) => { - // If subscriptions are not supported, fallback to legacy polling, otherwise return the error - if (error instanceof SubscriptionsNotSupportedError) { - fallbackLegacyPolling() - } else { - callback(null, error) - } - }, - }) - function fallbackLegacyPolling() { - console.warn( - "Failed to subscribe to events using real-time streaming (are you using the deprecated GRPC transport?), falling back to legacy polling." - ) + // Subscribe to the event stream + function subscribeEventStream() { + const {unsubscribe} = subscribe({ + topic: SubscriptionTopic.EVENTS, + args: filter, + onData: event => { + // Emit the event + onData(event) + }, + onError: (error: Error) => { + // If subscriptions are not supported, fallback to legacy polling, otherwise return the error + if (error instanceof SubscriptionsNotSupportedError) { + console.warn( + "Failed to subscribe to events using real-time streaming (are you using the deprecated GRPC transport?), falling back to legacy polling." + ) + fallbackLegacyPolling() + } else { + onError(error) + } + }, + }) + unsubscribeFn = unsubscribe + } + // Fallback to legacy polling if real-time streaming is not supported + function fallbackLegacyPolling() { if (typeof filterOrType !== "string") { throw new Error( "Legacy fcl.events fallback only supports string filters (single event type)" ) } - const unsubscribe = legacyEvents(filterOrType).subscribe(callback) - unsubscribeFnLegacy = unsubscribe + unsubscribeFnLegacy = legacyEvents(filterOrType).subscribe( + (event: Event, error?: Error) => { + if (error) { + onError(error) + } else { + onData(event) + } + } + ) + } + + async function subscribeToEvents() { + const network = await getChainId() + + // As of Flow CLI v2.2.8, WebSocket subscriptions are not supported on the Flow emulator + // This conditional will be removed when WebSocket subscriptions are supported in this environment + if (network === FLOW_EMULATOR) { + console.warn( + "Events are not supported on the Flow emulator, falling back to legacy polling." + ) + fallbackLegacyPolling() + } else { + subscribeEventStream() + } } + // Subscribe to events + const initPromise = subscribeToEvents().catch(error => { + onError(error) + }) + // Return an unsubscribe function return () => { - unsubscribeFn() - unsubscribeFnLegacy() + initPromise.finally(() => { + unsubscribeFn() + unsubscribeFnLegacy() + }) } }, } diff --git a/packages/fcl-core/src/events/legacy-events.js b/packages/fcl-core/src/events/legacy-events.js index a4412fbc9..0a7fba8b7 100644 --- a/packages/fcl-core/src/events/legacy-events.js +++ b/packages/fcl-core/src/events/legacy-events.js @@ -33,7 +33,7 @@ const HANDLERS = { const data = await send([ getEventsAtBlockHeightRange(ctx.self(), hwm.height + 1, next.height), ]).then(decode) - for (let d of data) ctx.broadcast(UPDATED, d.data) + for (let d of data) ctx.broadcast(UPDATED, d) } ctx.put(TICK, await scheduleTick(ctx)) } From 55e3c89cb8596d3a5570cd9539e395b128fa2208 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Thu, 3 Apr 2025 15:54:40 -0600 Subject: [PATCH 19/72] Add emulator fallback for fcl.tx (#2294) --- .../src/transaction/transaction.test.ts | 84 +++++++++++++++++++ .../fcl-core/src/transaction/transaction.ts | 65 +++++++++----- 2 files changed, 128 insertions(+), 21 deletions(-) diff --git a/packages/fcl-core/src/transaction/transaction.test.ts b/packages/fcl-core/src/transaction/transaction.test.ts index 316d1438a..83bf251b1 100644 --- a/packages/fcl-core/src/transaction/transaction.test.ts +++ b/packages/fcl-core/src/transaction/transaction.test.ts @@ -3,9 +3,11 @@ import {SubscriptionsNotSupportedError} from "@onflow/sdk" import {SubscriptionTopic, TransactionExecutionStatus} from "@onflow/typedefs" import {transaction} from "./transaction" import {transaction as legacyTransaction} from "./legacy-polling" +import {getChainId} from "../utils" jest.mock("@onflow/sdk") jest.mock("./legacy-polling") +jest.mock("../utils") describe("transaction", () => { beforeEach(() => { @@ -22,6 +24,8 @@ describe("transaction", () => { onceFinalized: jest.fn(), snapshot: jest.fn(), }) + + jest.mocked(getChainId).mockResolvedValue("mainnet") }) test("should throw an error if transactionId is not a 64 byte hash string", () => { @@ -37,6 +41,9 @@ describe("transaction", () => { const callback = jest.fn() const unsubscribe = transaction(txId).subscribe(callback) + // Flush the event loop + await new Promise(resolve => setTimeout(resolve, 0)) + // Expect the subscribe method to be called with the correct parameters const subscribeParams = jest.mocked(subscribe).mock .calls[0][0] as Parameters< @@ -120,6 +127,9 @@ describe("transaction", () => { const onError = jest.fn() const unsubscribe = transaction(txId).subscribe(onData, onError) + // Flush the event loop + await new Promise(resolve => setTimeout(resolve, 0)) + // Expect the subscribe method to be called with the correct parameters const subscribeParams = jest.mocked(subscribe).mock .calls[0][0] as Parameters< @@ -158,4 +168,78 @@ describe("transaction", () => { unsubscribe() }) + + test("should fall back to legacy polling if the Flow emulator is detected", async () => { + jest.mocked(getChainId).mockResolvedValue("local") + + const txId = + "3234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" + const onData = jest.fn() + const onError = jest.fn() + const unsubscribe = transaction(txId).subscribe(onData, onError) + + // Flush the event loop + await new Promise(resolve => setTimeout(resolve, 0)) + + // Expect legacy polling to be called + expect(subscribe).not.toHaveBeenCalled() + expect(legacyTransaction).toHaveBeenCalledWith(txId, { + pollRate: 1000, + txNotFoundTimeout: 12500, + }) + + // Expect the legacy subscribe method to be called with the correct parameters + const legacySubscribe = + jest.mocked(legacyTransaction).mock.results[0].value.subscribe + expect(legacySubscribe).toHaveBeenCalledTimes(1) + expect(legacySubscribe).toHaveBeenCalledWith(expect.any(Function)) + + // Get the callback function + const legacyCallback = legacySubscribe.mock.calls[0][0] + + // Mock the observable to emit a PENDING status + legacyCallback( + { + blockId: "", + status: TransactionExecutionStatus.PENDING, + statusString: "PENDING", + statusCode: 0, + errorMessage: "", + events: [], + }, + null + ) + + // Expect the error to be reported + expect(onData.mock.calls).toStrictEqual([ + [ + { + blockId: "", + status: TransactionExecutionStatus.UNKNOWN, + statusString: "", + statusCode: 0, + errorMessage: "", + events: [], + }, + ], + [ + { + blockId: "", + status: TransactionExecutionStatus.PENDING, + statusString: "PENDING", + statusCode: 0, + errorMessage: "", + events: [], + }, + ], + ]) + expect(onError).not.toHaveBeenCalled() + + expect(legacyTransaction).toHaveBeenCalledWith(txId, { + pollRate: 1000, + txNotFoundTimeout: 12500, + }) + + unsubscribe() + }) }) diff --git a/packages/fcl-core/src/transaction/transaction.ts b/packages/fcl-core/src/transaction/transaction.ts index 69b491084..791013040 100644 --- a/packages/fcl-core/src/transaction/transaction.ts +++ b/packages/fcl-core/src/transaction/transaction.ts @@ -21,6 +21,9 @@ import { } from "@onflow/sdk" import {TransactionError} from "./transaction-error" import {transaction as legacyTransaction} from "./legacy-polling" +import {getChainId} from "../utils" + +const FLOW_EMULATOR = "local" // Map of transaction observables // Used for shared global singleton to prevent duplicate subscriptions @@ -144,30 +147,50 @@ function createObservable( statusString: "", } + // Initialize the subscription + init().catch(error) + + async function init() { + const flowNetwork = await getChainId() + + // As of Flow CLI v2.2.8, WebSocket subscriptions are not supported on the Flow emulator + // This conditional will be removed when WebSocket subscriptions are supported in this environment + if (flowNetwork === FLOW_EMULATOR) { + console.warn( + "Events are not supported on the Flow emulator, falling back to legacy polling." + ) + fallbackLegacyPolling() + } else { + subscribeTransactionStatuses() + } + } + // Subscribe to transaction status updates - sdkSubscribe({ - topic: SubscriptionTopic.TRANSACTION_STATUSES, - args: {transactionId: txId}, - onData: txStatus => { - if (isDiff(value, txStatus)) { - value = txStatus - next(txStatus) - } - }, - onError: (err: Error) => { - if (err instanceof SubscriptionsNotSupportedError) { - fallbackLegacyPolling() - } else { - error(err) - } - }, - }) + function subscribeTransactionStatuses() { + // Subscribe to transaction status updates + sdkSubscribe({ + topic: SubscriptionTopic.TRANSACTION_STATUSES, + args: {transactionId: txId}, + onData: txStatus => { + if (isDiff(value, txStatus)) { + value = txStatus + next(txStatus) + } + }, + onError: (err: Error) => { + if (err instanceof SubscriptionsNotSupportedError) { + console.warn( + "Failed to subscribe to transaction status updates using real-time streaming (are you using the deprecated GRPC transport?), falling back to polling." + ) + fallbackLegacyPolling() + } else { + error(err) + } + }, + }) + } function fallbackLegacyPolling() { - console.warn( - "Failed to subscribe to transaction status updates using real-time streaming (are you using the deprecated GRPC transport?), falling back to polling." - ) - // Poll for transaction status updates legacyTransaction(txId, opts).subscribe( (txStatus?: TransactionStatus, err?: Error) => { From 5775384e8a9cd3a73ec4b2870d09a918ab6094ca Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Mon, 7 Apr 2025 12:17:52 -0600 Subject: [PATCH 20/72] Fix resume args type check not checking if value is falsy (#2309) --- .../transport-http/src/subscribe/handlers/account-statuses.ts | 4 ++-- .../transport-http/src/subscribe/handlers/block-digests.ts | 4 ++-- .../transport-http/src/subscribe/handlers/block-headers.ts | 4 ++-- packages/transport-http/src/subscribe/handlers/blocks.ts | 4 ++-- packages/transport-http/src/subscribe/handlers/events.ts | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/transport-http/src/subscribe/handlers/account-statuses.ts b/packages/transport-http/src/subscribe/handlers/account-statuses.ts index 1d4ca8779..ec4c3e764 100644 --- a/packages/transport-http/src/subscribe/handlers/account-statuses.ts +++ b/packages/transport-http/src/subscribe/handlers/account-statuses.ts @@ -106,14 +106,14 @@ export const accountStatusesHandler = createSubscriptionHandler<{ account_addresses: resumeArgs.accountAddresses, } - if ("startBlockHeight" in resumeArgs) { + if ("startBlockHeight" in resumeArgs && resumeArgs.startBlockHeight) { return { ...encodedArgs, start_block_height: resumeArgs.startBlockHeight, } } - if ("startBlockId" in resumeArgs) { + if ("startBlockId" in resumeArgs && resumeArgs.startBlockId) { return { ...encodedArgs, start_block_id: resumeArgs.startBlockId, diff --git a/packages/transport-http/src/subscribe/handlers/block-digests.ts b/packages/transport-http/src/subscribe/handlers/block-digests.ts index 2b0a176cc..a29573bbe 100644 --- a/packages/transport-http/src/subscribe/handlers/block-digests.ts +++ b/packages/transport-http/src/subscribe/handlers/block-digests.ts @@ -57,14 +57,14 @@ export const blockDigestsHandler = createSubscriptionHandler<{ block_status: resumeArgs.blockStatus, } - if ("startBlockHeight" in resumeArgs) { + if ("startBlockHeight" in resumeArgs && resumeArgs.startBlockHeight) { return { ...encodedArgs, start_block_height: resumeArgs.startBlockHeight, } } - if ("startBlockId" in resumeArgs) { + if ("startBlockId" in resumeArgs && resumeArgs.startBlockId) { return { ...encodedArgs, start_block_id: resumeArgs.startBlockId, diff --git a/packages/transport-http/src/subscribe/handlers/block-headers.ts b/packages/transport-http/src/subscribe/handlers/block-headers.ts index a05fb5d27..0f24a2b74 100644 --- a/packages/transport-http/src/subscribe/handlers/block-headers.ts +++ b/packages/transport-http/src/subscribe/handlers/block-headers.ts @@ -61,14 +61,14 @@ export const blockHeadersHandler = createSubscriptionHandler<{ block_status: resumeArgs.blockStatus, } - if ("startBlockHeight" in resumeArgs) { + if ("startBlockHeight" in resumeArgs && resumeArgs.startBlockHeight) { return { ...encodedArgs, start_block_height: resumeArgs.startBlockHeight, } } - if ("startBlockId" in resumeArgs) { + if ("startBlockId" in resumeArgs && resumeArgs.startBlockId) { return { ...encodedArgs, start_block_id: resumeArgs.startBlockId, diff --git a/packages/transport-http/src/subscribe/handlers/blocks.ts b/packages/transport-http/src/subscribe/handlers/blocks.ts index 8b0032443..793bfce94 100644 --- a/packages/transport-http/src/subscribe/handlers/blocks.ts +++ b/packages/transport-http/src/subscribe/handlers/blocks.ts @@ -81,14 +81,14 @@ export const blocksHandler = createSubscriptionHandler<{ block_status: resumeArgs.blockStatus, } - if ("startBlockHeight" in resumeArgs) { + if ("startBlockHeight" in resumeArgs && resumeArgs.startBlockHeight) { return { ...encodedArgs, start_block_height: String(resumeArgs.startBlockHeight), } } - if ("startBlockId" in resumeArgs) { + if ("startBlockId" in resumeArgs && resumeArgs.startBlockId) { return { ...encodedArgs, start_block_id: resumeArgs.startBlockId, diff --git a/packages/transport-http/src/subscribe/handlers/events.ts b/packages/transport-http/src/subscribe/handlers/events.ts index c460c4133..031d0deea 100644 --- a/packages/transport-http/src/subscribe/handlers/events.ts +++ b/packages/transport-http/src/subscribe/handlers/events.ts @@ -86,14 +86,14 @@ export const eventsHandler = createSubscriptionHandler<{ contracts: resumeArgs.contracts, } - if ("startBlockHeight" in resumeArgs) { + if ("startBlockHeight" in resumeArgs && resumeArgs.startBlockHeight) { return { ...encodedArgs, start_block_height: resumeArgs.startBlockHeight, } } - if ("startBlockId" in resumeArgs) { + if ("startBlockId" in resumeArgs && resumeArgs.startBlockId) { return { ...encodedArgs, start_block_id: resumeArgs.startBlockId, From e31ad2b7f7134cbd5ed2bdc2f70c30861c559446 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Tue, 15 Apr 2025 00:45:51 -0600 Subject: [PATCH 21/72] Add missing decoders (#2320) --- packages/sdk/src/decode/decode.js | 12 +++ packages/sdk/src/decode/decode.test.js | 101 ++++++++++++------ .../__snapshots__/response.test.ts.snap | 3 + packages/sdk/src/response/response.ts | 3 + 4 files changed, 87 insertions(+), 32 deletions(-) diff --git a/packages/sdk/src/decode/decode.js b/packages/sdk/src/decode/decode.js index e91977c4c..9d7f9f0b9 100644 --- a/packages/sdk/src/decode/decode.js +++ b/packages/sdk/src/decode/decode.js @@ -202,6 +202,18 @@ export const decodeResponse = async (response, customDecoders = {}) => { } }) ) + } else if (response.event) { + const {payload, ...rest} = response.event + return { + ...rest, + data: await decode(payload, customDecoders), + } + } else if (response.accountStatusEvent) { + const {payload, ...rest} = response.accountStatusEvent + return { + ...rest, + data: await decode(payload, customDecoders), + } } else if (response.account) { return response.account } else if (response.block) { diff --git a/packages/sdk/src/decode/decode.test.js b/packages/sdk/src/decode/decode.test.js index 14dad1988..9ba5f8d7d 100644 --- a/packages/sdk/src/decode/decode.test.js +++ b/packages/sdk/src/decode/decode.test.js @@ -1376,41 +1376,78 @@ describe("decode GetEvents tests", () => { }) }) -describe("decode GetTransactionStatus tests", () => { - it("decodes a GetEvents response correctly", async () => { - const getTransactionStatusResponse = { - transactionStatus: { - status: 4, - statusCode: 1, - errorMessage: null, - events: [ - { - type: "LilBUBTheMagicalSpaceCat.LandedOnMars", - transactionId: "my-fun-and-very-special-txn-id", - transactionIndex: 123456, - eventIndex: 7891011, - payload: { - type: "String", - value: "Thanks for reviewing these tests!", - }, - }, - ], +describe("decode single event tests", () => { + it("decodes a single event response correctly", async () => { + const eventResponse = { + event: { + blockHeight: 123, + blockId: "abc123", + blockTimestamp: new Date(123).toISOString(), + eventIndex: 123, + transactionId: "abc-123", + transactionIndex: 123, + type: "MyFunAndCoolEvent", + payload: {type: "String", value: "foo"}, }, } - expect(await decodeResponse(getTransactionStatusResponse)).toStrictEqual({ - status: 4, - statusCode: 1, - errorMessage: null, - events: [ - { - type: "LilBUBTheMagicalSpaceCat.LandedOnMars", - transactionId: "my-fun-and-very-special-txn-id", - transactionIndex: 123456, - eventIndex: 7891011, - data: "Thanks for reviewing these tests!", - }, - ], + expect(await decodeResponse(eventResponse)).toStrictEqual({ + blockHeight: 123, + blockId: "abc123", + blockTimestamp: new Date(123).toISOString(), + eventIndex: 123, + transactionId: "abc-123", + transactionIndex: 123, + type: "MyFunAndCoolEvent", + data: "foo", + }) + }) +}) + +describe("decode account status event tests", () => { + it("decodes an account status response correctly", async () => { + const accountStatusResponse = { + accountStatusEvent: { + accountAddress: "0x123", + blockHeight: 123, + blockId: "abc123", + blockTimestamp: new Date(123).toISOString(), + eventIndex: 123, + transactionId: "abc-123", + transactionIndex: 123, + type: "flow.AccountKeyAdded", + payload: {type: "String", value: "foo"}, + }, + } + + expect(await decodeResponse(accountStatusResponse)).toStrictEqual({ + accountAddress: "0x123", + blockHeight: 123, + blockId: "abc123", + blockTimestamp: new Date(123).toISOString(), + eventIndex: 123, + transactionId: "abc-123", + transactionIndex: 123, + type: "flow.AccountKeyAdded", + data: "foo", + }) + }) +}) + +describe("decode block digest tests", () => { + it("decodes a block digest response correctly", async () => { + const blockDigestResponse = { + blockDigest: { + id: "abc123", + height: 123, + timestamp: new Date(123).toISOString(), + }, + } + + expect(await decodeResponse(blockDigestResponse)).toStrictEqual({ + id: "abc123", + height: 123, + timestamp: new Date(123).toISOString(), }) }) }) diff --git a/packages/sdk/src/response/__snapshots__/response.test.ts.snap b/packages/sdk/src/response/__snapshots__/response.test.ts.snap index fb409075f..98a58a12a 100644 --- a/packages/sdk/src/response/__snapshots__/response.test.ts.snap +++ b/packages/sdk/src/response/__snapshots__/response.test.ts.snap @@ -3,10 +3,13 @@ exports[`Response - Snapshot 1`] = ` { "account": null, + "accountStatusEvent": null, "block": null, + "blockDigest": null, "blockHeader": null, "collection": null, "encodedData": null, + "event": null, "events": null, "heartbeat": null, "latestBlock": null, diff --git a/packages/sdk/src/response/response.ts b/packages/sdk/src/response/response.ts index feed56a9d..f79e1e744 100644 --- a/packages/sdk/src/response/response.ts +++ b/packages/sdk/src/response/response.ts @@ -5,9 +5,12 @@ const DEFAULT_RESPONSE = { transactionId: null, encodedData: null, events: null, + event: null, + accountStatusEvent: null, account: null, block: null, blockHeader: null, + blockDigest: null, latestBlock: null, collection: null, networkParameters: null, From a9e42f8fcf95b9a710c223dc5042c95bfedae446 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Wed, 23 Apr 2025 17:22:44 +0000 Subject: [PATCH 22/72] Improve WebSocket Lifecycle Management (#2312) --- .../src/subscribe/subscription-manager.ts | 100 +++++++++++++----- 1 file changed, 74 insertions(+), 26 deletions(-) diff --git a/packages/transport-http/src/subscribe/subscription-manager.ts b/packages/transport-http/src/subscribe/subscription-manager.ts index b0a7879a5..256c73df0 100644 --- a/packages/transport-http/src/subscribe/subscription-manager.ts +++ b/packages/transport-http/src/subscribe/subscription-manager.ts @@ -62,6 +62,8 @@ export class SubscriptionManager[]> { private config: DeepRequired private reconnectAttempts = 0 private handlers: SubscriptionHandler[] + private connectPromise: Promise | null = null + private closeConnection: (() => void) | null = null constructor(handlers: Handlers, config: SubscriptionManagerConfig) { this.config = { @@ -146,7 +148,7 @@ export class SubscriptionManager[]> { // Close the socket if there are no more subscriptions if (this.subscriptions.length === 0) { - this.socket?.close() + this.closeConnection?.() return } @@ -158,7 +160,10 @@ export class SubscriptionManager[]> { // Lazy connect to the socket when the first subscription is made private async connect() { - return new Promise((resolve, reject) => { + if (this.connectPromise) { + return this.connectPromise + } + this.connectPromise = new Promise((resolve, reject) => { // If the socket is already open, do nothing if (this.socket?.readyState === WS_OPEN) { resolve() @@ -166,14 +171,27 @@ export class SubscriptionManager[]> { } this.socket = new WebSocket(this.config.node) - this.socket.addEventListener("message", event => { + const onMessage = (event: MessageEvent) => { const message = JSON.parse(event.data) as | MessageResponse | SubscriptionDataMessage // Error message if ("action" in message && message.error) { - this.handleSocketError(SocketError.fromMessage(message.error)) + const sub = this.subscriptions.find( + sub => sub.id === message.subscription_id + ) + if (sub) { + sub.subscriber.onError( + new Error( + `Failed to subscribe to topic ${sub.topic}: ${message.error.message}` + ) + ) + // Remove the subscription + this.subscriptions = this.subscriptions.filter( + sub => sub.id !== message.subscription_id + ) + } return } @@ -185,8 +203,8 @@ export class SubscriptionManager[]> { sub.subscriber.onData(message.payload) } } - }) - this.socket.addEventListener("close", () => { + } + const onClose = () => { this.handleSocketError(new Error("WebSocket closed")) .then(() => { resolve() @@ -194,31 +212,37 @@ export class SubscriptionManager[]> { .catch(e => { reject(e) }) - }) - this.socket.addEventListener("open", () => { - // Restore subscriptions - Promise.all( - this.subscriptions.map(async sub => { - await this.sendSubscribe(sub) - }) - ) - .then(() => { - resolve() - }) - .catch(e => { - reject(new Error(`Failed to restore subscriptions: ${e}`)) - }) - }) + } + const onOpen = () => { + resolve() + } + + this.socket.addEventListener("message", onMessage) + this.socket.addEventListener("close", onClose) + this.socket.addEventListener("open", onOpen) + + this.closeConnection = () => { + this.socket?.removeEventListener("message", onMessage) + this.socket?.removeEventListener("close", onClose) + this.socket?.removeEventListener("open", onOpen) + + this.socket?.close() + this.socket = null + this.closeConnection = null + this.connectPromise = null + } }) + + return this.connectPromise } private async handleSocketError(error: any) { - // Clear the socket - this.socket = null + // Cleanup the connection + this.closeConnection?.() // Validate the number of reconnection attempts if ( - this.reconnectAttempts >= this.config.reconnectOptions.reconnectAttempts + ++this.reconnectAttempts >= this.config.reconnectOptions.reconnectAttempts ) { logger.log({ level: logger.LEVELS.error, @@ -248,8 +272,21 @@ export class SubscriptionManager[]> { await new Promise(resolve => setTimeout(resolve, this.backoffInterval)) // Try to reconnect - this.reconnectAttempts++ await this.connect() + + // Restore subscriptions + await Promise.all( + this.subscriptions.map(async sub => { + await this.sendSubscribe(sub).catch(e => { + sub.subscriber.onError( + new Error(`Failed to restore subscription: ${e}`) + ) + // Remove the subscription + this.subscriptions = this.subscriptions.filter(s => s.id !== sub.id) + }) + }) + ) + this.reconnectAttempts = 0 } } @@ -293,12 +330,21 @@ export class SubscriptionManager[]> { } private async request(request: MessageRequest): Promise { - return new Promise((resolve, reject) => { + let cleanup = () => {} + + return await new Promise((resolve, reject) => { if (!this.socket) { reject(new Error("WebSocket is not connected")) return } + // Set the cleanup function to remove the event listeners + cleanup = () => { + this.socket?.removeEventListener("error", onError) + this.socket?.removeEventListener("message", onMessage) + this.socket?.removeEventListener("close", onClose) + } + // Bind event listeners this.socket.addEventListener("error", onError) this.socket.addEventListener("message", onMessage) @@ -321,6 +367,8 @@ export class SubscriptionManager[]> { resolve(data) } } + }).finally(() => { + cleanup() }) } From b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Wed, 23 Apr 2025 18:10:57 -0700 Subject: [PATCH 23/72] Add changesets --- .changeset/breezy-gifts-sit.md | 5 +++++ .changeset/mean-walls-hear.md | 12 ++++++++++++ .changeset/sharp-suns-refuse.md | 22 ++++++++++++++++++++++ .changeset/shy-cars-beam.md | 5 +++++ .changeset/sixty-pandas-retire.md | 18 ++++++++++++++++++ 5 files changed, 62 insertions(+) create mode 100644 .changeset/breezy-gifts-sit.md create mode 100644 .changeset/mean-walls-hear.md create mode 100644 .changeset/sharp-suns-refuse.md create mode 100644 .changeset/shy-cars-beam.md create mode 100644 .changeset/sixty-pandas-retire.md diff --git a/.changeset/breezy-gifts-sit.md b/.changeset/breezy-gifts-sit.md new file mode 100644 index 000000000..a1cd27be4 --- /dev/null +++ b/.changeset/breezy-gifts-sit.md @@ -0,0 +1,5 @@ +--- +"@onflow/typedefs": minor +--- + +Add typedefs for streaming API \ No newline at end of file diff --git a/.changeset/mean-walls-hear.md b/.changeset/mean-walls-hear.md new file mode 100644 index 000000000..ede2b65c7 --- /dev/null +++ b/.changeset/mean-walls-hear.md @@ -0,0 +1,12 @@ +--- +"@onflow/transport-http": minor +--- + +Add support for new WebSocket streaming methods. The following topics are now available: + +- `blocks` +- `block_headers` +- `block_digests` +- `transaction_statues` +- `events` +- `account_statuses` diff --git a/.changeset/sharp-suns-refuse.md b/.changeset/sharp-suns-refuse.md new file mode 100644 index 000000000..55fa8ea3b --- /dev/null +++ b/.changeset/sharp-suns-refuse.md @@ -0,0 +1,22 @@ +--- +"@onflow/fcl-react-native": minor +"@onflow/fcl-core": minor +"@onflow/fcl": minor +--- + +Add real-time streaming methods `subscribe` and `rawSubscribe`. + +These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. + +The following topics are now available: + +- `blocks` +- `block_headers` +- `block_digests` +- `transaction_statues` +- `events` +- `account_statuses` + +Developers using `fcl.tx` and `fcl.events` will not need to make any changes to their existing app to realize the latency improvements of this change and will automatically benefit by upgrading to this version. + +Please see the [Flow Developer Documentation](https://developers.flow.com/clients/fcl-js/) for more details on how to use these new methods. \ No newline at end of file diff --git a/.changeset/shy-cars-beam.md b/.changeset/shy-cars-beam.md new file mode 100644 index 000000000..25a1954cc --- /dev/null +++ b/.changeset/shy-cars-beam.md @@ -0,0 +1,5 @@ +--- +"@onflow/transport-http": minor +--- + +Expose the `httpTransport` as a named export from `@onflow/transport-http` package. This follows the new object-style export for SDK transports and adds streaming support. \ No newline at end of file diff --git a/.changeset/sixty-pandas-retire.md b/.changeset/sixty-pandas-retire.md new file mode 100644 index 000000000..842caef5e --- /dev/null +++ b/.changeset/sixty-pandas-retire.md @@ -0,0 +1,18 @@ +--- +"@onflow/sdk": minor +--- + +Add real-time streaming methods `subscribe` and `rawSubscribe`. + +These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. + +The following topics are now available: + +- `blocks` +- `block_headers` +- `block_digests` +- `transaction_statues` +- `events` +- `account_statuses` + +Please see the [Flow Developer Documentation](https://developers.flow.com/clients/fcl-js/) for more details on how to use these new methods. \ No newline at end of file From 9ff3504341a89d6505c766bafb12a5430a544f64 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Thu, 24 Apr 2025 08:14:36 -0700 Subject: [PATCH 24/72] Fix Account Status Decoding --- .../src/subscribe/handlers/account-statuses.ts | 18 +++++++++--------- packages/typedefs/src/index.ts | 2 +- packages/typedefs/src/subscriptions.ts | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/transport-http/src/subscribe/handlers/account-statuses.ts b/packages/transport-http/src/subscribe/handlers/account-statuses.ts index ec4c3e764..41fe5e601 100644 --- a/packages/transport-http/src/subscribe/handlers/account-statuses.ts +++ b/packages/transport-http/src/subscribe/handlers/account-statuses.ts @@ -21,8 +21,7 @@ type AccountStatusesArgsDto = { type AccountStatusesDataDto = { block_id: string - block_height: string - block_timestamp: string + height: string account_events: { [address: string]: { type: string @@ -57,11 +56,10 @@ export const accountStatusesHandler = createSubscriptionHandler<{ for (const event of events) { // Parse the raw data const parsedData: AccountStatusesData = { - accountStatus: { + accountStatusEvent: { accountAddress: address, blockId: rawData.block_id, - blockHeight: Number(rawData.block_height), - blockTimestamp: rawData.block_timestamp, + blockHeight: Number(rawData.height), type: event.type, transactionId: event.transaction_id, transactionIndex: Number(event.transaction_index), @@ -76,11 +74,13 @@ export const accountStatusesHandler = createSubscriptionHandler<{ // Sort the messages by increasing message index data.sort((a, b) => { const txIndexDiff = - a.accountStatus.transactionIndex - - b.accountStatus.transactionIndex + a.accountStatusEvent.transactionIndex - + b.accountStatusEvent.transactionIndex if (txIndexDiff !== 0) return txIndexDiff - return a.accountStatus.eventIndex - b.accountStatus.eventIndex + return ( + a.accountStatusEvent.eventIndex - b.accountStatusEvent.eventIndex + ) }) // Emit the messages @@ -91,7 +91,7 @@ export const accountStatusesHandler = createSubscriptionHandler<{ // Update the resume args resumeArgs = { ...resumeArgs, - startBlockHeight: Number(BigInt(rawData.block_height) + BigInt(1)), + startBlockHeight: Number(BigInt(rawData.height) + BigInt(1)), startBlockId: undefined, } } diff --git a/packages/typedefs/src/index.ts b/packages/typedefs/src/index.ts index 94c59ccae..c001678cb 100644 --- a/packages/typedefs/src/index.ts +++ b/packages/typedefs/src/index.ts @@ -254,7 +254,7 @@ export type Event = { */ data: any } -export type AccountStatusEvent = Event & { +export type AccountStatusEvent = Omit & { /** * - The address of the account which the event is associated with. */ diff --git a/packages/typedefs/src/subscriptions.ts b/packages/typedefs/src/subscriptions.ts index 1b7af33d1..291aa395e 100644 --- a/packages/typedefs/src/subscriptions.ts +++ b/packages/typedefs/src/subscriptions.ts @@ -65,7 +65,7 @@ type RawSubscriptionDataMap = { blockDigest: BlockDigest } [SubscriptionTopic.ACCOUNT_STATUSES]: { - accountStatus: Omit & { + accountStatusEvent: Omit & { payload: string accountAddress: string } From 2446dbee70b25780e31cf8d0b45db7acac6281d6 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Wed, 30 Apr 2025 18:42:44 +0000 Subject: [PATCH 25/72] Add `useIsCadenceWalletConnected` hook (#2326) --- .changeset/ten-pumas-serve.md | 5 + package-lock.json | 998 +----------------- packages/fcl-rainbowkit-adapter/package.json | 7 +- .../src/use-is-cadence-wallet-connected.ts | 38 + 4 files changed, 95 insertions(+), 953 deletions(-) create mode 100644 .changeset/ten-pumas-serve.md create mode 100644 packages/fcl-rainbowkit-adapter/src/use-is-cadence-wallet-connected.ts diff --git a/.changeset/ten-pumas-serve.md b/.changeset/ten-pumas-serve.md new file mode 100644 index 000000000..5e108aa59 --- /dev/null +++ b/.changeset/ten-pumas-serve.md @@ -0,0 +1,5 @@ +--- +"@onflow/fcl-rainbowkit-adapter": minor +--- + +Add `useIsCadenceWalletConnected` hook diff --git a/package-lock.json b/package-lock.json index 759b6223c..5a24b1881 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,8 +38,6 @@ }, "node_modules/@adraffy/ens-normalize": { "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz", - "integrity": "sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==", "license": "MIT" }, "node_modules/@alloc/quick-lru": { @@ -77,8 +75,6 @@ }, "node_modules/@babel/compat-data": { "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -114,8 +110,6 @@ }, "node_modules/@babel/generator": { "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", - "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", "license": "MIT", "dependencies": { "@babel/parser": "^7.27.0", @@ -140,8 +134,6 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz", - "integrity": "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==", "license": "MIT", "dependencies": { "@babel/compat-data": "^7.26.8", @@ -156,8 +148,6 @@ }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.0.tgz", - "integrity": "sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg==", "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", @@ -177,8 +167,6 @@ }, "node_modules/@babel/helper-create-regexp-features-plugin": { "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.0.tgz", - "integrity": "sha512-fO8l08T76v48BhpNRW/nQ0MxfnSdoSKUJBMjubOAYffsVuGG5qOfMq7N6Es7UJvi7Y8goXXo07EfcHZXDPuELQ==", "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", @@ -194,8 +182,6 @@ }, "node_modules/@babel/helper-define-polyfill-provider": { "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.4.tgz", - "integrity": "sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw==", "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", @@ -221,8 +207,6 @@ }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", - "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.9", @@ -245,8 +229,6 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.9", @@ -262,8 +244,6 @@ }, "node_modules/@babel/helper-optimise-call-expression": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", - "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", "license": "MIT", "dependencies": { "@babel/types": "^7.25.9" @@ -274,8 +254,6 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -283,8 +261,6 @@ }, "node_modules/@babel/helper-remap-async-to-generator": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", - "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", @@ -300,8 +276,6 @@ }, "node_modules/@babel/helper-replace-supers": { "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", - "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", "license": "MIT", "dependencies": { "@babel/helper-member-expression-to-functions": "^7.25.9", @@ -317,8 +291,6 @@ }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", - "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.9", @@ -344,8 +316,6 @@ }, "node_modules/@babel/helper-validator-option": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -353,8 +323,6 @@ }, "node_modules/@babel/helper-wrap-function": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", - "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", "license": "MIT", "dependencies": { "@babel/template": "^7.25.9", @@ -392,8 +360,6 @@ }, "node_modules/@babel/parser": { "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", "license": "MIT", "dependencies": { "@babel/types": "^7.27.0" @@ -407,8 +373,6 @@ }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", - "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", @@ -423,8 +387,6 @@ }, "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", - "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -438,8 +400,6 @@ }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", - "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -453,8 +413,6 @@ }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", - "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", @@ -470,8 +428,6 @@ }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", - "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", @@ -749,8 +705,6 @@ }, "node_modules/@babel/plugin-syntax-import-assertions": { "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", - "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -764,8 +718,6 @@ }, "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", - "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -929,8 +881,6 @@ }, "node_modules/@babel/plugin-transform-arrow-functions": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", - "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -944,8 +894,6 @@ }, "node_modules/@babel/plugin-transform-async-generator-functions": { "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.26.8.tgz", - "integrity": "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.26.5", @@ -961,8 +909,6 @@ }, "node_modules/@babel/plugin-transform-async-to-generator": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", - "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.9", @@ -978,8 +924,6 @@ }, "node_modules/@babel/plugin-transform-block-scoped-functions": { "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz", - "integrity": "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" @@ -993,8 +937,6 @@ }, "node_modules/@babel/plugin-transform-block-scoping": { "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.0.tgz", - "integrity": "sha512-u1jGphZ8uDI2Pj/HJj6YQ6XQLZCNjOlprjxB5SVz6rq2T6SwAR+CdrWK0CP7F+9rDVMXdB0+r6Am5G5aobOjAQ==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" @@ -1008,8 +950,6 @@ }, "node_modules/@babel/plugin-transform-class-properties": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", - "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", @@ -1024,8 +964,6 @@ }, "node_modules/@babel/plugin-transform-class-static-block": { "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", - "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", @@ -1040,8 +978,6 @@ }, "node_modules/@babel/plugin-transform-classes": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", - "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", @@ -1060,8 +996,6 @@ }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", - "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", @@ -1076,8 +1010,6 @@ }, "node_modules/@babel/plugin-transform-destructuring": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", - "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1091,8 +1023,6 @@ }, "node_modules/@babel/plugin-transform-dotall-regex": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", - "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", @@ -1107,8 +1037,6 @@ }, "node_modules/@babel/plugin-transform-duplicate-keys": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", - "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1122,8 +1050,6 @@ }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", - "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", @@ -1138,8 +1064,6 @@ }, "node_modules/@babel/plugin-transform-dynamic-import": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", - "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1153,8 +1077,6 @@ }, "node_modules/@babel/plugin-transform-exponentiation-operator": { "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", - "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1168,8 +1090,6 @@ }, "node_modules/@babel/plugin-transform-export-namespace-from": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", - "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1198,8 +1118,6 @@ }, "node_modules/@babel/plugin-transform-for-of": { "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.26.9.tgz", - "integrity": "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.26.5", @@ -1214,8 +1132,6 @@ }, "node_modules/@babel/plugin-transform-function-name": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", - "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.25.9", @@ -1231,8 +1147,6 @@ }, "node_modules/@babel/plugin-transform-json-strings": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", - "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1246,8 +1160,6 @@ }, "node_modules/@babel/plugin-transform-literals": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", - "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1261,8 +1173,6 @@ }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", - "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1276,8 +1186,6 @@ }, "node_modules/@babel/plugin-transform-member-expression-literals": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", - "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1291,8 +1199,6 @@ }, "node_modules/@babel/plugin-transform-modules-amd": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", - "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.25.9", @@ -1307,8 +1213,6 @@ }, "node_modules/@babel/plugin-transform-modules-commonjs": { "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", - "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.26.0", @@ -1323,8 +1227,6 @@ }, "node_modules/@babel/plugin-transform-modules-systemjs": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", - "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.25.9", @@ -1341,8 +1243,6 @@ }, "node_modules/@babel/plugin-transform-modules-umd": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", - "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.25.9", @@ -1357,8 +1257,6 @@ }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", - "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", @@ -1373,8 +1271,6 @@ }, "node_modules/@babel/plugin-transform-new-target": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", - "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1388,8 +1284,6 @@ }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { "version": "7.26.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz", - "integrity": "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" @@ -1403,8 +1297,6 @@ }, "node_modules/@babel/plugin-transform-numeric-separator": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", - "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1418,8 +1310,6 @@ }, "node_modules/@babel/plugin-transform-object-rest-spread": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", - "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.25.9", @@ -1435,8 +1325,6 @@ }, "node_modules/@babel/plugin-transform-object-super": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", - "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", @@ -1451,8 +1339,6 @@ }, "node_modules/@babel/plugin-transform-optional-catch-binding": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", - "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1466,8 +1352,6 @@ }, "node_modules/@babel/plugin-transform-optional-chaining": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", - "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", @@ -1482,8 +1366,6 @@ }, "node_modules/@babel/plugin-transform-parameters": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", - "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1497,8 +1379,6 @@ }, "node_modules/@babel/plugin-transform-private-methods": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", - "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", @@ -1513,8 +1393,6 @@ }, "node_modules/@babel/plugin-transform-private-property-in-object": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", - "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", @@ -1530,8 +1408,6 @@ }, "node_modules/@babel/plugin-transform-property-literals": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", - "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1545,8 +1421,6 @@ }, "node_modules/@babel/plugin-transform-react-display-name": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz", - "integrity": "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1577,8 +1451,6 @@ }, "node_modules/@babel/plugin-transform-react-jsx-development": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz", - "integrity": "sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==", "license": "MIT", "dependencies": { "@babel/plugin-transform-react-jsx": "^7.25.9" @@ -1620,8 +1492,6 @@ }, "node_modules/@babel/plugin-transform-react-pure-annotations": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.9.tgz", - "integrity": "sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==", "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", @@ -1636,8 +1506,6 @@ }, "node_modules/@babel/plugin-transform-regenerator": { "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.0.tgz", - "integrity": "sha512-LX/vCajUJQDqE7Aum/ELUMZAY19+cDpghxrnyt5I1tV6X5PyC86AOoWXWFYFeIvauyeSA6/ktn4tQVn/3ZifsA==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.26.5", @@ -1652,8 +1520,6 @@ }, "node_modules/@babel/plugin-transform-regexp-modifiers": { "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", - "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", @@ -1668,8 +1534,6 @@ }, "node_modules/@babel/plugin-transform-reserved-words": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", - "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1701,8 +1565,6 @@ }, "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", - "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1716,8 +1578,6 @@ }, "node_modules/@babel/plugin-transform-spread": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", - "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", @@ -1732,8 +1592,6 @@ }, "node_modules/@babel/plugin-transform-sticky-regex": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", - "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1747,8 +1605,6 @@ }, "node_modules/@babel/plugin-transform-template-literals": { "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz", - "integrity": "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" @@ -1762,8 +1618,6 @@ }, "node_modules/@babel/plugin-transform-typeof-symbol": { "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.0.tgz", - "integrity": "sha512-+LLkxA9rKJpNoGsbLnAgOCdESl73vwYn+V6b+5wHbrE7OGKVDPHIQvbFSzqE6rwqaCw2RE+zdJrlLkcf8YOA0w==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" @@ -1794,8 +1648,6 @@ }, "node_modules/@babel/plugin-transform-unicode-escapes": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", - "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" @@ -1809,8 +1661,6 @@ }, "node_modules/@babel/plugin-transform-unicode-property-regex": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", - "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", @@ -1825,8 +1675,6 @@ }, "node_modules/@babel/plugin-transform-unicode-regex": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", - "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", @@ -1841,8 +1689,6 @@ }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", - "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", @@ -1857,8 +1703,6 @@ }, "node_modules/@babel/preset-env": { "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.9.tgz", - "integrity": "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ==", "license": "MIT", "dependencies": { "@babel/compat-data": "^7.26.8", @@ -1940,8 +1784,6 @@ }, "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { "version": "0.11.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", - "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.3", @@ -1981,8 +1823,6 @@ }, "node_modules/@babel/preset-react": { "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.26.3.tgz", - "integrity": "sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", @@ -2074,8 +1914,6 @@ }, "node_modules/@babel/template": { "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", - "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", @@ -2088,8 +1926,6 @@ }, "node_modules/@babel/traverse": { "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", - "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", @@ -2106,8 +1942,6 @@ }, "node_modules/@babel/types": { "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -2144,8 +1978,6 @@ }, "node_modules/@changesets/apply-release-plan/node_modules/@changesets/types": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", - "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", "dev": true, "license": "MIT" }, @@ -2165,8 +1997,6 @@ }, "node_modules/@changesets/apply-release-plan/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -2191,15 +2021,11 @@ }, "node_modules/@changesets/assemble-release-plan/node_modules/@changesets/types": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", - "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", "dev": true, "license": "MIT" }, "node_modules/@changesets/assemble-release-plan/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -2219,8 +2045,6 @@ }, "node_modules/@changesets/changelog-git/node_modules/@changesets/types": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", - "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", "dev": true, "license": "MIT" }, @@ -2274,15 +2098,11 @@ }, "node_modules/@changesets/cli/node_modules/@changesets/types": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", - "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", "dev": true, "license": "MIT" }, "node_modules/@changesets/cli/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -2308,8 +2128,6 @@ }, "node_modules/@changesets/config/node_modules/@changesets/types": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", - "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", "dev": true, "license": "MIT" }, @@ -2334,15 +2152,11 @@ }, "node_modules/@changesets/get-dependents-graph/node_modules/@changesets/types": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", - "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", "dev": true, "license": "MIT" }, "node_modules/@changesets/get-dependents-graph/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -2376,8 +2190,6 @@ }, "node_modules/@changesets/get-release-plan/node_modules/@changesets/types": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", - "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", "dev": true, "license": "MIT" }, @@ -2417,8 +2229,6 @@ }, "node_modules/@changesets/parse/node_modules/@changesets/types": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", - "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", "dev": true, "license": "MIT" }, @@ -2435,8 +2245,6 @@ }, "node_modules/@changesets/pre/node_modules/@changesets/types": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", - "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", "dev": true, "license": "MIT" }, @@ -2456,8 +2264,6 @@ }, "node_modules/@changesets/read/node_modules/@changesets/types": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", - "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", "dev": true, "license": "MIT" }, @@ -2472,8 +2278,6 @@ }, "node_modules/@changesets/should-skip-package/node_modules/@changesets/types": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", - "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", "dev": true, "license": "MIT" }, @@ -2495,8 +2299,6 @@ }, "node_modules/@changesets/write/node_modules/@changesets/types": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", - "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", "dev": true, "license": "MIT" }, @@ -2516,8 +2318,6 @@ }, "node_modules/@coinbase/wallet-sdk": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@coinbase/wallet-sdk/-/wallet-sdk-4.3.0.tgz", - "integrity": "sha512-T3+SNmiCw4HzDm4we9wCHCxlP0pqCiwKe4sOwPH3YAK2KSKjxPRydKu6UQJrdONFVLG7ujXvbd/6ZqmvJb8rkw==", "license": "Apache-2.0", "dependencies": { "@noble/hashes": "^1.4.0", @@ -2528,8 +2328,6 @@ }, "node_modules/@coinbase/wallet-sdk/node_modules/clsx": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", "license": "MIT", "engines": { "node": ">=6" @@ -2537,8 +2335,6 @@ }, "node_modules/@coinbase/wallet-sdk/node_modules/eventemitter3": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "license": "MIT" }, "node_modules/@discoveryjs/json-ext": { @@ -2551,8 +2347,6 @@ }, "node_modules/@ecies/ciphers": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@ecies/ciphers/-/ciphers-0.2.3.tgz", - "integrity": "sha512-tapn6XhOueMwht3E2UzY0ZZjYokdaw9XtL9kEyjhQ/Fb9vL9xTFbOaI+fV0AWvTpYu4BNloC6getKW6NtSg4mA==", "license": "MIT", "engines": { "bun": ">=1", @@ -2574,8 +2368,6 @@ }, "node_modules/@emnapi/core/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, @@ -2589,8 +2381,6 @@ }, "node_modules/@emnapi/runtime/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, @@ -2604,15 +2394,11 @@ }, "node_modules/@emnapi/wasi-threads/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, "node_modules/@emotion/hash": { "version": "0.9.2", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", - "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", "license": "MIT", "peer": true }, @@ -2744,8 +2530,6 @@ }, "node_modules/@ethereumjs/common": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-3.2.0.tgz", - "integrity": "sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==", "license": "MIT", "dependencies": { "@ethereumjs/util": "^8.1.0", @@ -2754,8 +2538,6 @@ }, "node_modules/@ethereumjs/rlp": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", - "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", "license": "MPL-2.0", "bin": { "rlp": "bin/rlp" @@ -2766,8 +2548,6 @@ }, "node_modules/@ethereumjs/tx": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-4.2.0.tgz", - "integrity": "sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==", "license": "MPL-2.0", "dependencies": { "@ethereumjs/common": "^3.2.0", @@ -2781,8 +2561,6 @@ }, "node_modules/@ethereumjs/util": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", - "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", "license": "MPL-2.0", "dependencies": { "@ethereumjs/rlp": "^4.0.1", @@ -2795,8 +2573,6 @@ }, "node_modules/@ethersproject/abstract-provider": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz", - "integrity": "sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==", "funding": [ { "type": "individual", @@ -2820,8 +2596,6 @@ }, "node_modules/@ethersproject/abstract-provider/node_modules/@ethersproject/transactions": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz", - "integrity": "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==", "funding": [ { "type": "individual", @@ -2847,8 +2621,6 @@ }, "node_modules/@ethersproject/abstract-signer": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz", - "integrity": "sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==", "funding": [ { "type": "individual", @@ -2870,8 +2642,6 @@ }, "node_modules/@ethersproject/address": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.8.0.tgz", - "integrity": "sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==", "funding": [ { "type": "individual", @@ -2893,8 +2663,6 @@ }, "node_modules/@ethersproject/base64": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.8.0.tgz", - "integrity": "sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==", "funding": [ { "type": "individual", @@ -2912,8 +2680,6 @@ }, "node_modules/@ethersproject/bignumber": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz", - "integrity": "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==", "funding": [ { "type": "individual", @@ -2937,8 +2703,6 @@ }, "node_modules/@ethersproject/bytes": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", - "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", "funding": [ { "type": "individual", @@ -2956,8 +2720,6 @@ }, "node_modules/@ethersproject/constants": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", - "integrity": "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==", "funding": [ { "type": "individual", @@ -2975,8 +2737,6 @@ }, "node_modules/@ethersproject/hash": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.8.0.tgz", - "integrity": "sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==", "funding": [ { "type": "individual", @@ -3002,8 +2762,6 @@ }, "node_modules/@ethersproject/keccak256": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz", - "integrity": "sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==", "funding": [ { "type": "individual", @@ -3022,8 +2780,6 @@ }, "node_modules/@ethersproject/logger": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", - "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", "funding": [ { "type": "individual", @@ -3038,8 +2794,6 @@ }, "node_modules/@ethersproject/networks": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", - "integrity": "sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==", "funding": [ { "type": "individual", @@ -3057,8 +2811,6 @@ }, "node_modules/@ethersproject/properties": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", - "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", "funding": [ { "type": "individual", @@ -3076,8 +2828,6 @@ }, "node_modules/@ethersproject/rlp": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.8.0.tgz", - "integrity": "sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==", "funding": [ { "type": "individual", @@ -3096,8 +2846,6 @@ }, "node_modules/@ethersproject/signing-key": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", - "integrity": "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==", "funding": [ { "type": "individual", @@ -3120,14 +2868,10 @@ }, "node_modules/@ethersproject/signing-key/node_modules/bn.js": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", "license": "MIT" }, "node_modules/@ethersproject/strings": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz", - "integrity": "sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==", "funding": [ { "type": "individual", @@ -3147,8 +2891,6 @@ }, "node_modules/@ethersproject/web": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.8.0.tgz", - "integrity": "sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==", "funding": [ { "type": "individual", @@ -3362,8 +3104,6 @@ }, "node_modules/@expo/cli/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "peer": true, "bin": { @@ -3584,8 +3324,6 @@ }, "node_modules/@expo/config-plugins/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "peer": true, "bin": { @@ -3660,8 +3398,6 @@ }, "node_modules/@expo/config/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "peer": true, "bin": { @@ -3733,8 +3469,6 @@ }, "node_modules/@expo/devcert/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD", "peer": true }, @@ -3797,8 +3531,6 @@ }, "node_modules/@expo/env/node_modules/dotenv": { "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "license": "BSD-2-Clause", "peer": true, "engines": { @@ -3940,8 +3672,6 @@ }, "node_modules/@expo/image-utils/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "peer": true, "bin": { @@ -4365,8 +4095,6 @@ }, "node_modules/@expo/prebuild-config/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "peer": true, "bin": { @@ -5613,8 +5341,6 @@ }, "node_modules/@lerna/create/node_modules/fs-extra": { "version": "11.3.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", "dev": true, "license": "MIT", "dependencies": { @@ -5796,8 +5522,6 @@ }, "node_modules/@lerna/create/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -5961,8 +5685,6 @@ }, "node_modules/@metamask/eth-json-rpc-provider": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@metamask/eth-json-rpc-provider/-/eth-json-rpc-provider-1.0.1.tgz", - "integrity": "sha512-whiUMPlAOrVGmX8aKYVPvlKyG4CpQXiNNyt74vE1xb5sPvmx5oA7B/kOi/JdBvhGQq97U1/AVdXEdk2zkP8qyA==", "dependencies": { "@metamask/json-rpc-engine": "^7.0.0", "@metamask/safe-event-emitter": "^3.0.0", @@ -5974,8 +5696,6 @@ }, "node_modules/@metamask/eth-json-rpc-provider/node_modules/@metamask/json-rpc-engine": { "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@metamask/json-rpc-engine/-/json-rpc-engine-7.3.3.tgz", - "integrity": "sha512-dwZPq8wx9yV3IX2caLi9q9xZBw2XeIoYqdyihDDDpuHVCEiqadJLwqM3zy+uwf6F1QYQ65A8aOMQg1Uw7LMLNg==", "license": "ISC", "dependencies": { "@metamask/rpc-errors": "^6.2.1", @@ -5988,8 +5708,6 @@ }, "node_modules/@metamask/eth-json-rpc-provider/node_modules/@metamask/json-rpc-engine/node_modules/@metamask/utils": { "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-8.5.0.tgz", - "integrity": "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==", "license": "ISC", "dependencies": { "@ethereumjs/tx": "^4.2.0", @@ -6008,8 +5726,6 @@ }, "node_modules/@metamask/eth-json-rpc-provider/node_modules/@metamask/utils": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-5.0.2.tgz", - "integrity": "sha512-yfmE79bRQtnMzarnKfX7AEJBwFTxvTyw3nBQlu/5rmGXrjAeAMltoGxO62TFurxrQAFMNa/fEjIHNvungZp0+g==", "license": "ISC", "dependencies": { "@ethereumjs/tx": "^4.1.2", @@ -6024,8 +5740,6 @@ }, "node_modules/@metamask/eth-json-rpc-provider/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6036,8 +5750,6 @@ }, "node_modules/@metamask/json-rpc-engine": { "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@metamask/json-rpc-engine/-/json-rpc-engine-8.0.2.tgz", - "integrity": "sha512-IoQPmql8q7ABLruW7i4EYVHWUbF74yrp63bRuXV5Zf9BQwcn5H9Ww1eLtROYvI1bUXwOiHZ6qT5CWTrDc/t/AA==", "license": "ISC", "dependencies": { "@metamask/rpc-errors": "^6.2.1", @@ -6050,8 +5762,6 @@ }, "node_modules/@metamask/json-rpc-middleware-stream": { "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@metamask/json-rpc-middleware-stream/-/json-rpc-middleware-stream-7.0.2.tgz", - "integrity": "sha512-yUdzsJK04Ev98Ck4D7lmRNQ8FPioXYhEUZOMS01LXW8qTvPGiRVXmVltj2p4wrLkh0vW7u6nv0mNl5xzC5Qmfg==", "license": "ISC", "dependencies": { "@metamask/json-rpc-engine": "^8.0.2", @@ -6065,8 +5775,6 @@ }, "node_modules/@metamask/object-multiplex": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@metamask/object-multiplex/-/object-multiplex-2.1.0.tgz", - "integrity": "sha512-4vKIiv0DQxljcXwfpnbsXcfa5glMj5Zg9mqn4xpIWqkv6uJ2ma5/GtUfLFSxhlxnR8asRMv8dDmWya1Tc1sDFA==", "license": "ISC", "dependencies": { "once": "^1.4.0", @@ -6078,8 +5786,6 @@ }, "node_modules/@metamask/onboarding": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@metamask/onboarding/-/onboarding-1.0.1.tgz", - "integrity": "sha512-FqHhAsCI+Vacx2qa5mAFcWNSrTcVGMNjzxVgaX8ECSny/BJ9/vgXP9V7WF/8vb9DltPeQkxr+Fnfmm6GHfmdTQ==", "license": "MIT", "dependencies": { "bowser": "^2.9.0" @@ -6087,8 +5793,6 @@ }, "node_modules/@metamask/providers": { "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@metamask/providers/-/providers-16.1.0.tgz", - "integrity": "sha512-znVCvux30+3SaUwcUGaSf+pUckzT5ukPRpcBmy+muBLC0yaWnBcvDqGfcsw6CBIenUdFrVoAFa8B6jsuCY/a+g==", "license": "MIT", "dependencies": { "@metamask/json-rpc-engine": "^8.0.1", @@ -6110,8 +5814,6 @@ }, "node_modules/@metamask/providers/node_modules/is-stream": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "license": "MIT", "engines": { "node": ">=8" @@ -6122,8 +5824,6 @@ }, "node_modules/@metamask/rpc-errors": { "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@metamask/rpc-errors/-/rpc-errors-6.4.0.tgz", - "integrity": "sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg==", "license": "MIT", "dependencies": { "@metamask/utils": "^9.0.0", @@ -6135,8 +5835,6 @@ }, "node_modules/@metamask/rpc-errors/node_modules/@metamask/utils": { "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-9.3.0.tgz", - "integrity": "sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==", "license": "ISC", "dependencies": { "@ethereumjs/tx": "^4.2.0", @@ -6155,8 +5853,6 @@ }, "node_modules/@metamask/rpc-errors/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6167,8 +5863,6 @@ }, "node_modules/@metamask/safe-event-emitter": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-3.1.2.tgz", - "integrity": "sha512-5yb2gMI1BDm0JybZezeoX/3XhPDOtTbcFvpTXM9kxsoZjPZFh4XciqRbpD6N86HYZqWDhEaKUDuOyR0sQHEjMA==", "license": "ISC", "engines": { "node": ">=12.0.0" @@ -6176,8 +5870,6 @@ }, "node_modules/@metamask/sdk": { "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@metamask/sdk/-/sdk-0.32.0.tgz", - "integrity": "sha512-WmGAlP1oBuD9hk4CsdlG1WJFuPtYJY+dnTHJMeCyohTWD2GgkcLMUUuvu9lO1/NVzuOoSi1OrnjbuY1O/1NZ1g==", "dependencies": { "@babel/runtime": "^7.26.0", "@metamask/onboarding": "^1.0.1", @@ -6202,16 +5894,12 @@ }, "node_modules/@metamask/sdk-install-modal-web": { "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@metamask/sdk-install-modal-web/-/sdk-install-modal-web-0.32.0.tgz", - "integrity": "sha512-TFoktj0JgfWnQaL3yFkApqNwcaqJ+dw4xcnrJueMP3aXkSNev2Ido+WVNOg4IIMxnmOrfAC9t0UJ0u/dC9MjOQ==", "dependencies": { "@paulmillr/qr": "^0.2.1" } }, "node_modules/@metamask/sdk/node_modules/@metamask/sdk-communication-layer": { "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@metamask/sdk-communication-layer/-/sdk-communication-layer-0.32.0.tgz", - "integrity": "sha512-dmj/KFjMi1fsdZGIOtbhxdg3amxhKL/A5BqSU4uh/SyDKPub/OT+x5pX8bGjpTL1WPWY/Q0OIlvFyX3VWnT06Q==", "dependencies": { "bufferutil": "^4.0.8", "date-fns": "^2.29.3", @@ -6229,8 +5917,6 @@ }, "node_modules/@metamask/sdk/node_modules/cross-fetch": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", - "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", "license": "MIT", "dependencies": { "node-fetch": "^2.7.0" @@ -6238,14 +5924,10 @@ }, "node_modules/@metamask/sdk/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/@metamask/sdk/node_modules/util": { "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -6257,8 +5939,6 @@ }, "node_modules/@metamask/sdk/node_modules/uuid": { "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "license": "MIT", "bin": { "uuid": "dist/bin/uuid" @@ -6266,8 +5946,6 @@ }, "node_modules/@metamask/superstruct": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@metamask/superstruct/-/superstruct-3.2.1.tgz", - "integrity": "sha512-fLgJnDOXFmuVlB38rUN5SmU7hAFQcCjrg3Vrxz67KTY7YHFnSNEKvX4avmEBdOI0yTCxZjwMCFEqsC8k2+Wd3g==", "license": "MIT", "engines": { "node": ">=16.0.0" @@ -6275,8 +5953,6 @@ }, "node_modules/@metamask/utils": { "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-8.5.0.tgz", - "integrity": "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==", "license": "ISC", "dependencies": { "@ethereumjs/tx": "^4.2.0", @@ -6295,8 +5971,6 @@ }, "node_modules/@metamask/utils/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6317,8 +5991,6 @@ }, "node_modules/@motionone/animation/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/@motionone/dom": { @@ -6335,8 +6007,6 @@ }, "node_modules/@motionone/dom/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/@motionone/easing": { @@ -6349,8 +6019,6 @@ }, "node_modules/@motionone/easing/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/@motionone/generators": { @@ -6364,8 +6032,6 @@ }, "node_modules/@motionone/generators/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/@motionone/svelte": { @@ -6378,8 +6044,6 @@ }, "node_modules/@motionone/svelte/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/@motionone/types": { @@ -6397,8 +6061,6 @@ }, "node_modules/@motionone/utils/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/@motionone/vue": { @@ -6411,8 +6073,6 @@ }, "node_modules/@motionone/vue/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/@napi-rs/wasm-runtime": { @@ -6504,8 +6164,6 @@ }, "node_modules/@npmcli/agent/node_modules/agent-base": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "dev": true, "license": "MIT", "engines": { @@ -6526,8 +6184,6 @@ }, "node_modules/@npmcli/agent/node_modules/https-proxy-agent": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, "license": "MIT", "dependencies": { @@ -6626,8 +6282,6 @@ }, "node_modules/@npmcli/arborist/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -6649,8 +6303,6 @@ }, "node_modules/@npmcli/fs/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6701,8 +6353,6 @@ }, "node_modules/@npmcli/git/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -6805,8 +6455,6 @@ }, "node_modules/@npmcli/metavuln-calculator/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -6884,8 +6532,6 @@ }, "node_modules/@npmcli/package-json/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -7007,8 +6653,6 @@ }, "node_modules/@nrwl/tao/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, @@ -7033,8 +6677,6 @@ }, "node_modules/@nx/devkit/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -7054,8 +6696,6 @@ }, "node_modules/@nx/devkit/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, @@ -7511,9 +7151,6 @@ }, "node_modules/@paulmillr/qr": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@paulmillr/qr/-/qr-0.2.1.tgz", - "integrity": "sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==", - "deprecated": "The package is now available as \"qr\": npm install qr", "license": "(MIT OR Apache-2.0)", "funding": { "url": "https://paulmillr.com/funding/" @@ -7529,8 +7166,6 @@ }, "node_modules/@rainbow-me/rainbowkit": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@rainbow-me/rainbowkit/-/rainbowkit-2.2.4.tgz", - "integrity": "sha512-LUYBcB5bzLf6/BMdnW3dEFHVqoPkTGcFN3u6WamaIHXuqD9HT+HVAeNlcYvKENBXldN2zNBs1Bt3k8Oy7y5bTw==", "license": "MIT", "peer": true, "dependencies": { @@ -7555,8 +7190,6 @@ }, "node_modules/@rainbow-me/rainbowkit/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==", "license": "MIT", "peer": true, "dependencies": { @@ -7571,8 +7204,6 @@ }, "node_modules/@rainbow-me/rainbowkit/node_modules/cliui": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "license": "ISC", "peer": true, "dependencies": { @@ -7583,8 +7214,6 @@ }, "node_modules/@rainbow-me/rainbowkit/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==", "license": "MIT", "peer": true, "dependencies": { @@ -7596,15 +7225,11 @@ }, "node_modules/@rainbow-me/rainbowkit/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==", "license": "MIT", "peer": true }, "node_modules/@rainbow-me/rainbowkit/node_modules/pngjs": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", - "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", "license": "MIT", "peer": true, "engines": { @@ -7613,8 +7238,6 @@ }, "node_modules/@rainbow-me/rainbowkit/node_modules/qrcode": { "version": "1.5.4", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", - "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", "license": "MIT", "peer": true, "dependencies": { @@ -7631,8 +7254,6 @@ }, "node_modules/@rainbow-me/rainbowkit/node_modules/wrap-ansi": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "license": "MIT", "peer": true, "dependencies": { @@ -7646,15 +7267,11 @@ }, "node_modules/@rainbow-me/rainbowkit/node_modules/y18n": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "license": "ISC", "peer": true }, "node_modules/@rainbow-me/rainbowkit/node_modules/yargs": { "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "license": "MIT", "peer": true, "dependencies": { @@ -7676,8 +7293,6 @@ }, "node_modules/@rainbow-me/rainbowkit/node_modules/yargs-parser": { "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "license": "ISC", "peer": true, "dependencies": { @@ -7690,8 +7305,6 @@ }, "node_modules/@react-native-async-storage/async-storage": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.1.2.tgz", - "integrity": "sha512-dvlNq4AlGWC+ehtH12p65+17V0Dx7IecOWl6WanF2ja38O1Dcjjvn7jVzkUHJ5oWkQBlyASurTPlTHgKXyYiow==", "license": "MIT", "peer": true, "dependencies": { @@ -8174,8 +7787,6 @@ }, "node_modules/@react-native-community/cli-doctor/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "peer": true, "bin": { @@ -9058,8 +8669,6 @@ }, "node_modules/@react-native-community/cli-tools/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "peer": true, "bin": { @@ -9219,8 +8828,6 @@ }, "node_modules/@react-native-community/cli/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "peer": true, "bin": { @@ -9605,8 +9212,6 @@ }, "node_modules/@rollup/pluginutils": { "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", - "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -9627,8 +9232,6 @@ }, "node_modules/@rollup/pluginutils/node_modules/picomatch": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "license": "MIT", "engines": { "node": ">=12" @@ -9779,9 +9382,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz", - "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.1.tgz", + "integrity": "sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==", "cpu": [ "x64" ], @@ -9845,8 +9448,6 @@ }, "node_modules/@safe-global/safe-apps-provider": { "version": "0.18.5", - "resolved": "https://registry.npmjs.org/@safe-global/safe-apps-provider/-/safe-apps-provider-0.18.5.tgz", - "integrity": "sha512-9v9wjBi3TwLsEJ3C2ujYoexp3pFJ0omDLH/GX91e2QB+uwCKTBYyhxFSrTQ9qzoyQd+bfsk4gjOGW87QcJhf7g==", "license": "MIT", "dependencies": { "@safe-global/safe-apps-sdk": "^9.1.0", @@ -9855,8 +9456,6 @@ }, "node_modules/@safe-global/safe-apps-sdk": { "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@safe-global/safe-apps-sdk/-/safe-apps-sdk-9.1.0.tgz", - "integrity": "sha512-N5p/ulfnnA2Pi2M3YeWjULeWbjo7ei22JwU/IXnhoHzKq3pYCN6ynL9mJBOlvDVv892EgLPCWCOwQk/uBT2v0Q==", "license": "MIT", "dependencies": { "@safe-global/safe-gateway-typescript-sdk": "^3.5.3", @@ -9865,8 +9464,6 @@ }, "node_modules/@safe-global/safe-gateway-typescript-sdk": { "version": "3.23.1", - "resolved": "https://registry.npmjs.org/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.23.1.tgz", - "integrity": "sha512-6ORQfwtEJYpalCeVO21L4XXGSdbEMfyp2hEv6cP82afKXSwvse6d3sdelgaPWUxHIsFRkWvHDdzh8IyyKHZKxw==", "license": "MIT", "engines": { "node": ">=16" @@ -9874,8 +9471,6 @@ }, "node_modules/@scure/base": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.4.tgz", - "integrity": "sha512-5Yy9czTO47mqz+/J8GM6GIId4umdCk1wc1q8rKERQulIoc8VP9pzDcghv10Tl2E7R96ZUx/PhND3ESYUQX8NuQ==", "license": "MIT", "funding": { "url": "https://paulmillr.com/funding/" @@ -9883,8 +9478,6 @@ }, "node_modules/@scure/bip32": { "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.2.tgz", - "integrity": "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==", "license": "MIT", "dependencies": { "@noble/curves": "~1.8.1", @@ -9897,8 +9490,6 @@ }, "node_modules/@scure/bip39": { "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.4.tgz", - "integrity": "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==", "license": "MIT", "dependencies": { "@noble/hashes": "~1.7.1", @@ -10032,14 +9623,10 @@ }, "node_modules/@socket.io/component-emitter": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "license": "MIT" }, "node_modules/@tanstack/query-core": { "version": "5.74.4", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.74.4.tgz", - "integrity": "sha512-YuG0A0+3i9b2Gfo9fkmNnkUWh5+5cFhWBN0pJAHkHilTx6A0nv8kepkk4T4GRt4e5ahbtFj2eTtkiPcVU1xO4A==", "license": "MIT", "funding": { "type": "github", @@ -10048,8 +9635,6 @@ }, "node_modules/@tanstack/react-query": { "version": "5.74.4", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.74.4.tgz", - "integrity": "sha512-mAbxw60d4ffQ4qmRYfkO1xzRBPUEf/72Dgo3qqea0J66nIKuDTLEqQt0ku++SDFlMGMnB6uKDnEG1xD/TDse4Q==", "license": "MIT", "dependencies": { "@tanstack/query-core": "5.74.4" @@ -10064,8 +9649,6 @@ }, "node_modules/@testing-library/dom": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", - "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.10.4", @@ -10083,8 +9666,6 @@ }, "node_modules/@testing-library/dom/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==", "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -10098,8 +9679,6 @@ }, "node_modules/@testing-library/dom/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -10114,8 +9693,6 @@ }, "node_modules/@testing-library/dom/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==", "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -10126,14 +9703,10 @@ }, "node_modules/@testing-library/dom/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==", "license": "MIT" }, "node_modules/@testing-library/dom/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==", "license": "MIT", "engines": { "node": ">=8" @@ -10141,8 +9714,6 @@ }, "node_modules/@testing-library/dom/node_modules/pretty-format": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1", @@ -10155,8 +9726,6 @@ }, "node_modules/@testing-library/dom/node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "license": "MIT", "engines": { "node": ">=10" @@ -10167,14 +9736,10 @@ }, "node_modules/@testing-library/dom/node_modules/react-is": { "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "license": "MIT" }, "node_modules/@testing-library/dom/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==", "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -10185,8 +9750,6 @@ }, "node_modules/@testing-library/react": { "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz", - "integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5" @@ -10269,15 +9832,11 @@ }, "node_modules/@tybys/wasm-util/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, "node_modules/@types/aria-query": { "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "license": "MIT" }, "node_modules/@types/babel__core": { @@ -10319,8 +9878,6 @@ }, "node_modules/@types/debug": { "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", "license": "MIT", "dependencies": { "@types/ms": "*" @@ -10392,14 +9949,10 @@ }, "node_modules/@types/ms": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "license": "MIT" }, "node_modules/@types/node": { "version": "18.19.86", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.86.tgz", - "integrity": "sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ==", "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -10418,10 +9971,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/prop-types": { + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/react": { "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz", - "integrity": "sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -10430,8 +9988,6 @@ }, "node_modules/@types/react-dom": { "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.2.tgz", - "integrity": "sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==", "devOptional": true, "license": "MIT", "peerDependencies": { @@ -10442,6 +9998,13 @@ "version": "1.20.2", "license": "MIT" }, + "node_modules/@types/scheduler": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/semver": { "version": "7.5.8", "dev": true, @@ -10512,8 +10075,6 @@ }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -10633,8 +10194,6 @@ }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -10670,8 +10229,6 @@ }, "node_modules/@typescript-eslint/utils/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -10728,8 +10285,6 @@ }, "node_modules/@vanilla-extract/css": { "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@vanilla-extract/css/-/css-1.15.5.tgz", - "integrity": "sha512-N1nQebRWnXvlcmu9fXKVUs145EVwmWtMD95bpiEKtvehHDpUhmO1l2bauS7FGYKbi3dU1IurJbGpQhBclTr1ng==", "license": "MIT", "peer": true, "dependencies": { @@ -10749,15 +10304,11 @@ }, "node_modules/@vanilla-extract/css/node_modules/lru-cache": { "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "license": "ISC", "peer": true }, "node_modules/@vanilla-extract/dynamic": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@vanilla-extract/dynamic/-/dynamic-2.1.2.tgz", - "integrity": "sha512-9BGMciD8rO1hdSPIAh1ntsG4LPD3IYKhywR7VOmmz9OO4Lx1hlwkSg3E6X07ujFx7YuBfx0GDQnApG9ESHvB2A==", "license": "MIT", "peer": true, "dependencies": { @@ -10766,15 +10317,11 @@ }, "node_modules/@vanilla-extract/private": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@vanilla-extract/private/-/private-1.0.6.tgz", - "integrity": "sha512-ytsG/JLweEjw7DBuZ/0JCN4WAQgM9erfSTdS1NQY778hFQSZ6cfCDEZZ0sgVm4k54uNz6ImKB33AYvSR//fjxw==", "license": "MIT", "peer": true }, "node_modules/@vanilla-extract/sprinkles": { "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@vanilla-extract/sprinkles/-/sprinkles-1.6.3.tgz", - "integrity": "sha512-oCHlQeYOBIJIA2yWy2GnY5wE2A7hGHDyJplJo4lb+KEIBcJWRnDJDg8ywDwQS5VfWJrBBO3drzYZPFpWQjAMiQ==", "license": "MIT", "peer": true, "peerDependencies": { @@ -10783,8 +10330,6 @@ }, "node_modules/@wagmi/connectors": { "version": "5.7.12", - "resolved": "https://registry.npmjs.org/@wagmi/connectors/-/connectors-5.7.12.tgz", - "integrity": "sha512-pLFuZ1PsLkNyY11mx0+IOrMM7xACWCBRxaulfX17osqixkDFeOAyqFGBjh/XxkvRyrDJUdO4F+QHEeSoOiPpgg==", "license": "MIT", "dependencies": { "@coinbase/wallet-sdk": "4.3.0", @@ -10810,8 +10355,6 @@ }, "node_modules/@wagmi/core": { "version": "2.16.7", - "resolved": "https://registry.npmjs.org/@wagmi/core/-/core-2.16.7.tgz", - "integrity": "sha512-Kpgrw6OXV0VBhDs4toQVKQ0NK5yUO6uxEqnvRGjNjbO85d93Gbfsp5BlxSLeWq6iVMSBFSitdl5i9W7b1miq1g==", "license": "MIT", "dependencies": { "eventemitter3": "5.0.1", @@ -10837,14 +10380,10 @@ }, "node_modules/@wagmi/core/node_modules/eventemitter3": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "license": "MIT" }, "node_modules/@walletconnect/core": { "version": "2.19.2", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.19.2.tgz", - "integrity": "sha512-iu0mgLj51AXcKpdNj8+4EdNNBd/mkNjLEhZn6UMc/r7BM9WbmpPMEydA39WeRLbdLO4kbpmq4wTbiskI1rg+HA==", "license": "Apache-2.0", "dependencies": { "@walletconnect/heartbeat": "1.2.2", @@ -10871,8 +10410,6 @@ }, "node_modules/@walletconnect/core/node_modules/@react-native-async-storage/async-storage": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.24.0.tgz", - "integrity": "sha512-W4/vbwUOYOjco0x3toB8QCr7EjIP6nE9G7o8PMguvvjYT5Awg09lyV4enACRx4s++PPulBiBSjL0KTFx2u0Z/g==", "license": "MIT", "optional": true, "peer": true, @@ -10885,8 +10422,6 @@ }, "node_modules/@walletconnect/core/node_modules/@walletconnect/keyvaluestorage": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", - "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", "license": "MIT", "dependencies": { "@walletconnect/safe-json": "^1.0.1", @@ -10911,8 +10446,6 @@ }, "node_modules/@walletconnect/ethereum-provider": { "version": "2.19.2", - "resolved": "https://registry.npmjs.org/@walletconnect/ethereum-provider/-/ethereum-provider-2.19.2.tgz", - "integrity": "sha512-NzPzNcjMLqow6ha2nssB1ciMD0cdHZesYcHSQKjCi9waIDMov9Fr2yEJccbiVFE3cxek7f9dCPsoZez2q8ihvg==", "license": "Apache-2.0", "dependencies": { "@walletconnect/jsonrpc-http-connection": "1.0.8", @@ -10930,8 +10463,6 @@ }, "node_modules/@walletconnect/ethereum-provider/node_modules/@react-native-async-storage/async-storage": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.24.0.tgz", - "integrity": "sha512-W4/vbwUOYOjco0x3toB8QCr7EjIP6nE9G7o8PMguvvjYT5Awg09lyV4enACRx4s++PPulBiBSjL0KTFx2u0Z/g==", "license": "MIT", "optional": true, "peer": true, @@ -10944,8 +10475,6 @@ }, "node_modules/@walletconnect/ethereum-provider/node_modules/@walletconnect/keyvaluestorage": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", - "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", "license": "MIT", "dependencies": { "@walletconnect/safe-json": "^1.0.1", @@ -10980,8 +10509,6 @@ }, "node_modules/@walletconnect/jsonrpc-http-connection": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-http-connection/-/jsonrpc-http-connection-1.0.8.tgz", - "integrity": "sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==", "license": "MIT", "dependencies": { "@walletconnect/jsonrpc-utils": "^1.0.6", @@ -11018,8 +10545,6 @@ }, "node_modules/@walletconnect/jsonrpc-ws-connection": { "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.16.tgz", - "integrity": "sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q==", "license": "MIT", "dependencies": { "@walletconnect/jsonrpc-utils": "^1.0.6", @@ -11030,8 +10555,6 @@ }, "node_modules/@walletconnect/jsonrpc-ws-connection/node_modules/ws": { "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "license": "MIT", "engines": { "node": ">=8.3.0" @@ -11091,8 +10614,6 @@ }, "node_modules/@walletconnect/relay-auth": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@walletconnect/relay-auth/-/relay-auth-1.1.0.tgz", - "integrity": "sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==", "license": "MIT", "dependencies": { "@noble/curves": "1.8.0", @@ -11104,8 +10625,6 @@ }, "node_modules/@walletconnect/relay-auth/node_modules/@noble/curves": { "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.0.tgz", - "integrity": "sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==", "license": "MIT", "dependencies": { "@noble/hashes": "1.7.0" @@ -11119,8 +10638,6 @@ }, "node_modules/@walletconnect/relay-auth/node_modules/@noble/hashes": { "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.0.tgz", - "integrity": "sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==", "license": "MIT", "engines": { "node": "^14.21.3 || >=16" @@ -11138,8 +10655,6 @@ }, "node_modules/@walletconnect/sign-client": { "version": "2.19.2", - "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.19.2.tgz", - "integrity": "sha512-a/K5PRIFPCjfHq5xx3WYKHAAF8Ft2I1LtxloyibqiQOoUtNLfKgFB1r8sdMvXM7/PADNPe4iAw4uSE6PrARrfg==", "license": "Apache-2.0", "dependencies": { "@walletconnect/core": "2.19.2", @@ -11162,8 +10677,6 @@ }, "node_modules/@walletconnect/types": { "version": "2.19.2", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.19.2.tgz", - "integrity": "sha512-/LZWhkVCUN+fcTgQUxArxhn2R8DF+LSd/6Wh9FnpjeK/Sdupx1EPS8okWG6WPAqq2f404PRoNAfQytQ82Xdl3g==", "license": "Apache-2.0", "dependencies": { "@walletconnect/events": "1.0.1", @@ -11176,8 +10689,6 @@ }, "node_modules/@walletconnect/types/node_modules/@react-native-async-storage/async-storage": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.24.0.tgz", - "integrity": "sha512-W4/vbwUOYOjco0x3toB8QCr7EjIP6nE9G7o8PMguvvjYT5Awg09lyV4enACRx4s++PPulBiBSjL0KTFx2u0Z/g==", "license": "MIT", "optional": true, "peer": true, @@ -11190,8 +10701,6 @@ }, "node_modules/@walletconnect/types/node_modules/@walletconnect/keyvaluestorage": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", - "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", "license": "MIT", "dependencies": { "@walletconnect/safe-json": "^1.0.1", @@ -11209,8 +10718,6 @@ }, "node_modules/@walletconnect/universal-provider": { "version": "2.19.2", - "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.19.2.tgz", - "integrity": "sha512-LkKg+EjcSUpPUhhvRANgkjPL38wJPIWumAYD8OK/g4OFuJ4W3lS/XTCKthABQfFqmiNbNbVllmywiyE44KdpQg==", "license": "Apache-2.0", "dependencies": { "@walletconnect/events": "1.0.1", @@ -11229,8 +10736,6 @@ }, "node_modules/@walletconnect/universal-provider/node_modules/@react-native-async-storage/async-storage": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.24.0.tgz", - "integrity": "sha512-W4/vbwUOYOjco0x3toB8QCr7EjIP6nE9G7o8PMguvvjYT5Awg09lyV4enACRx4s++PPulBiBSjL0KTFx2u0Z/g==", "license": "MIT", "optional": true, "peer": true, @@ -11243,8 +10748,6 @@ }, "node_modules/@walletconnect/universal-provider/node_modules/@walletconnect/keyvaluestorage": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", - "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", "license": "MIT", "dependencies": { "@walletconnect/safe-json": "^1.0.1", @@ -11262,8 +10765,6 @@ }, "node_modules/@walletconnect/utils": { "version": "2.19.2", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.19.2.tgz", - "integrity": "sha512-VU5CcUF4sZDg8a2/ov29OJzT3KfLuZqJUM0GemW30dlipI5fkpb0VPenZK7TcdLPXc1LN+Q+7eyTqHRoAu/BIA==", "license": "Apache-2.0", "dependencies": { "@noble/ciphers": "1.2.1", @@ -11287,8 +10788,6 @@ }, "node_modules/@walletconnect/utils/node_modules/@react-native-async-storage/async-storage": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.24.0.tgz", - "integrity": "sha512-W4/vbwUOYOjco0x3toB8QCr7EjIP6nE9G7o8PMguvvjYT5Awg09lyV4enACRx4s++PPulBiBSjL0KTFx2u0Z/g==", "license": "MIT", "optional": true, "peer": true, @@ -11301,8 +10800,6 @@ }, "node_modules/@walletconnect/utils/node_modules/@walletconnect/keyvaluestorage": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", - "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", "license": "MIT", "dependencies": { "@walletconnect/safe-json": "^1.0.1", @@ -11565,8 +11062,6 @@ }, "node_modules/@yarnpkg/parsers/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, @@ -11601,8 +11096,6 @@ }, "node_modules/abitype": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.8.tgz", - "integrity": "sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/wevm" @@ -11876,8 +11369,6 @@ }, "node_modules/aria-query": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "license": "Apache-2.0", "dependencies": { "dequal": "^2.0.3" @@ -11965,8 +11456,6 @@ }, "node_modules/ast-types/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD", "peer": true }, @@ -11989,8 +11478,6 @@ }, "node_modules/async-mutex": { "version": "0.2.6", - "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.2.6.tgz", - "integrity": "sha512-Hs4R+4SPgamu6rSGW8C7cV9gaWUKEHykfzCCvIRuaVv636Ju10ZdeUbvb4TBEW0INuq2DHZqXbK4Nd3yG4RaRw==", "license": "MIT", "dependencies": { "tslib": "^2.0.0" @@ -11998,8 +11485,6 @@ }, "node_modules/async-mutex/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/asynckit": { @@ -12082,8 +11567,6 @@ }, "node_modules/axios/node_modules/form-data": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", "dev": true, "license": "MIT", "dependencies": { @@ -12549,8 +12032,6 @@ }, "node_modules/base-x": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", - "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==", "license": "MIT" }, "node_modules/base64-js": { @@ -12686,8 +12167,6 @@ }, "node_modules/bn.js": { "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", "license": "MIT" }, "node_modules/boolbase": { @@ -12696,8 +12175,6 @@ }, "node_modules/bowser": { "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", "license": "MIT" }, "node_modules/bplist-creator": { @@ -12710,8 +12187,6 @@ }, "node_modules/bplist-parser": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz", - "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==", "license": "MIT", "peer": true, "dependencies": { @@ -12748,8 +12223,6 @@ }, "node_modules/browserslist": { "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", "funding": [ { "type": "opencollective", @@ -12791,8 +12264,6 @@ }, "node_modules/bs58": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", - "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", "license": "MIT", "dependencies": { "base-x": "^5.0.0" @@ -13071,8 +12542,6 @@ }, "node_modules/caniuse-lite": { "version": "1.0.30001715", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001715.tgz", - "integrity": "sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==", "funding": [ { "type": "opencollective", @@ -13092,8 +12561,6 @@ "node_modules/cbw-sdk": { "name": "@coinbase/wallet-sdk", "version": "3.9.3", - "resolved": "https://registry.npmjs.org/@coinbase/wallet-sdk/-/wallet-sdk-3.9.3.tgz", - "integrity": "sha512-N/A2DRIf0Y3PHc1XAMvbBUu4zisna6qAdqABMZwBMNEfWrXpAwx16pZGkYCLGE+Rvv1edbcB2LYDRnACNcmCiw==", "license": "Apache-2.0", "dependencies": { "bn.js": "^5.2.1", @@ -13109,14 +12576,10 @@ }, "node_modules/cbw-sdk/node_modules/bn.js": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", "license": "MIT" }, "node_modules/cbw-sdk/node_modules/clsx": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", "license": "MIT", "engines": { "node": ">=6" @@ -13124,8 +12587,6 @@ }, "node_modules/cbw-sdk/node_modules/eventemitter3": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "license": "MIT" }, "node_modules/chalk": { @@ -13324,8 +12785,6 @@ }, "node_modules/clsx": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "license": "MIT", "peer": true, "engines": { @@ -13620,8 +13079,6 @@ }, "node_modules/conventional-changelog-core/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -13666,8 +13123,6 @@ }, "node_modules/conventional-changelog-writer/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -13732,14 +13187,10 @@ }, "node_modules/cookie-es": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.2.tgz", - "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", "license": "MIT" }, "node_modules/core-js-compat": { "version": "3.41.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz", - "integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==", "license": "MIT", "dependencies": { "browserslist": "^4.24.4" @@ -13796,8 +13247,6 @@ }, "node_modules/crc-32": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "license": "Apache-2.0", "bin": { "crc32": "bin/crc32.njs" @@ -13892,8 +13341,6 @@ }, "node_modules/cross-fetch": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", - "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", "license": "MIT", "dependencies": { "node-fetch": "^2.7.0" @@ -13913,8 +13360,6 @@ }, "node_modules/crossws": { "version": "0.3.4", - "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.4.tgz", - "integrity": "sha512-uj0O1ETYX1Bh6uSgktfPvwDiPYGQ3aI4qVsaC/LWpkIzGj1nUYm5FK3K+t11oOlpN01lGbprFCH4wBlKdJjVgw==", "license": "MIT", "dependencies": { "uncrypto": "^0.1.3" @@ -14108,8 +13553,6 @@ }, "node_modules/csstype": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, "node_modules/dag-map": { @@ -14193,8 +13636,6 @@ }, "node_modules/date-fns": { "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.21.0" @@ -14304,8 +13745,6 @@ }, "node_modules/deep-object-diff": { "version": "1.1.9", - "resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.9.tgz", - "integrity": "sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==", "license": "MIT", "peer": true }, @@ -14385,8 +13824,6 @@ }, "node_modules/defu": { "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", "license": "MIT" }, "node_modules/del": { @@ -14459,8 +13896,6 @@ }, "node_modules/dequal": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "license": "MIT", "engines": { "node": ">=6" @@ -14468,8 +13903,6 @@ }, "node_modules/destr": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", - "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", "license": "MIT" }, "node_modules/destroy": { @@ -14514,8 +13947,6 @@ }, "node_modules/detect-node-es": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", "license": "MIT", "peer": true }, @@ -14562,8 +13993,6 @@ }, "node_modules/dom-accessibility-api": { "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "license": "MIT" }, "node_modules/dom-serializer": { @@ -14665,8 +14094,6 @@ }, "node_modules/dotenv-expand/node_modules/dotenv": { "version": "16.5.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", - "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -14708,8 +14135,6 @@ }, "node_modules/eciesjs": { "version": "0.4.14", - "resolved": "https://registry.npmjs.org/eciesjs/-/eciesjs-0.4.14.tgz", - "integrity": "sha512-eJAgf9pdv214Hn98FlUzclRMYWF7WfoLlkS9nWMTm1qcCwn6Ad4EGD9lr9HXMBfSrZhYQujRE+p0adPRkctC6A==", "license": "MIT", "dependencies": { "@ecies/ciphers": "^0.2.2", @@ -14744,8 +14169,6 @@ }, "node_modules/electron-to-chromium": { "version": "1.5.140", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.140.tgz", - "integrity": "sha512-o82Rj+ONp4Ip7Cl1r7lrqx/pXhbp/lh9DpKcMNscFJdh8ebyRofnc7Sh01B4jx403RI0oqTBvlZ7OBIZLMr2+Q==", "license": "ISC" }, "node_modules/elliptic": { @@ -14816,8 +14239,6 @@ }, "node_modules/engine.io-client": { "version": "6.6.3", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz", - "integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==", "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", @@ -14829,8 +14250,6 @@ }, "node_modules/engine.io-client/node_modules/ws": { "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -14850,8 +14269,6 @@ }, "node_modules/engine.io-parser": { "version": "5.2.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", - "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -14871,8 +14288,6 @@ }, "node_modules/enquirer": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", "dev": true, "license": "MIT", "dependencies": { @@ -15046,8 +14461,6 @@ }, "node_modules/es-set-tostringtag": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -15077,8 +14490,6 @@ }, "node_modules/es-toolkit": { "version": "1.33.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.33.0.tgz", - "integrity": "sha512-X13Q/ZSc+vsO1q600bvNK4bxgXMkHcf//RxCmYDaRY5DAcT+eoXjY5hoAPGMdRnWQjvyLEcyauG3b6hz76LNqg==", "license": "MIT", "workspaces": [ "docs", @@ -15213,8 +14624,6 @@ }, "node_modules/eslint-plugin-jsdoc/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -15521,8 +14930,6 @@ }, "node_modules/eth-block-tracker": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-7.1.0.tgz", - "integrity": "sha512-8YdplnuE1IK4xfqpf4iU7oBxnOYAc35934o083G8ao+8WM8QQtt/mVlAY6yIAdY1eMeLqg4Z//PZjJGmWGPMRg==", "license": "MIT", "dependencies": { "@metamask/eth-json-rpc-provider": "^1.0.0", @@ -15537,8 +14944,6 @@ }, "node_modules/eth-block-tracker/node_modules/@metamask/utils": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-5.0.2.tgz", - "integrity": "sha512-yfmE79bRQtnMzarnKfX7AEJBwFTxvTyw3nBQlu/5rmGXrjAeAMltoGxO62TFurxrQAFMNa/fEjIHNvungZp0+g==", "license": "ISC", "dependencies": { "@ethereumjs/tx": "^4.1.2", @@ -15553,8 +14958,6 @@ }, "node_modules/eth-block-tracker/node_modules/pify": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "license": "MIT", "engines": { "node": ">=4" @@ -15562,8 +14965,6 @@ }, "node_modules/eth-block-tracker/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -15574,8 +14975,6 @@ }, "node_modules/eth-json-rpc-filters": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/eth-json-rpc-filters/-/eth-json-rpc-filters-6.0.1.tgz", - "integrity": "sha512-ITJTvqoCw6OVMLs7pI8f4gG92n/St6x80ACtHodeS+IXmO0w+t1T5OOzfSt7KLSMLRkVUoexV7tztLgDxg+iig==", "license": "ISC", "dependencies": { "@metamask/safe-event-emitter": "^3.0.0", @@ -15590,8 +14989,6 @@ }, "node_modules/eth-query": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/eth-query/-/eth-query-2.1.2.tgz", - "integrity": "sha512-srES0ZcvwkR/wd5OQBRA1bIJMww1skfGS0s8wlwK3/oNP4+wnds60krvu5R1QbpRQjMmpG5OMIWro5s7gvDPsA==", "license": "ISC", "dependencies": { "json-rpc-random-id": "^1.0.0", @@ -15600,8 +14997,6 @@ }, "node_modules/eth-rpc-errors": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz", - "integrity": "sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==", "license": "MIT", "dependencies": { "fast-safe-stringify": "^2.0.6" @@ -15609,8 +15004,6 @@ }, "node_modules/ethereum-cryptography": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", "license": "MIT", "dependencies": { "@noble/curves": "1.4.2", @@ -15621,8 +15014,6 @@ }, "node_modules/ethereum-cryptography/node_modules/@noble/curves": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", "license": "MIT", "dependencies": { "@noble/hashes": "1.4.0" @@ -15633,8 +15024,6 @@ }, "node_modules/ethereum-cryptography/node_modules/@noble/hashes": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", "license": "MIT", "engines": { "node": ">= 16" @@ -15645,8 +15034,6 @@ }, "node_modules/ethereum-cryptography/node_modules/@scure/base": { "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", "license": "MIT", "funding": { "url": "https://paulmillr.com/funding/" @@ -15654,8 +15041,6 @@ }, "node_modules/ethereum-cryptography/node_modules/@scure/bip32": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", "license": "MIT", "dependencies": { "@noble/curves": "~1.4.0", @@ -15668,8 +15053,6 @@ }, "node_modules/ethereum-cryptography/node_modules/@scure/bip39": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", "license": "MIT", "dependencies": { "@noble/hashes": "~1.4.0", @@ -15688,8 +15071,6 @@ }, "node_modules/eventemitter2": { "version": "6.4.9", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", - "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", "license": "MIT" }, "node_modules/eventemitter3": { @@ -15887,8 +15268,6 @@ }, "node_modules/expo-linking": { "version": "7.0.5", - "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-7.0.5.tgz", - "integrity": "sha512-3KptlJtcYDPWohk0MfJU75MJFh2ybavbtcSd84zEPfw9s1q3hjimw3sXnH03ZxP54kiEWldvKmmnGcVffBDB1g==", "license": "MIT", "peer": true, "dependencies": { @@ -15902,8 +15281,6 @@ }, "node_modules/expo-linking/node_modules/@babel/code-frame": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", "license": "MIT", "peer": true, "dependencies": { @@ -15912,8 +15289,6 @@ }, "node_modules/expo-linking/node_modules/@expo/config": { "version": "10.0.11", - "resolved": "https://registry.npmjs.org/@expo/config/-/config-10.0.11.tgz", - "integrity": "sha512-nociJ4zr/NmbVfMNe9j/+zRlt7wz/siISu7PjdWE4WE+elEGxWWxsGzltdJG0llzrM+khx8qUiFK5aiVcdMBww==", "license": "MIT", "peer": true, "dependencies": { @@ -15934,8 +15309,6 @@ }, "node_modules/expo-linking/node_modules/@expo/config-plugins": { "version": "9.0.17", - "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-9.0.17.tgz", - "integrity": "sha512-m24F1COquwOm7PBl5wRbkT9P9DviCXe0D7S7nQsolfbhdCWuvMkfXeoWmgjtdhy7sDlOyIgBrAdnB6MfsWKqIg==", "license": "MIT", "peer": true, "dependencies": { @@ -15957,15 +15330,11 @@ }, "node_modules/expo-linking/node_modules/@expo/config-types": { "version": "52.0.5", - "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-52.0.5.tgz", - "integrity": "sha512-AMDeuDLHXXqd8W+0zSjIt7f37vUd/BP8p43k68NHpyAvQO+z8mbQZm3cNQVAMySeayK2XoPigAFB1JF2NFajaA==", "license": "MIT", "peer": true }, "node_modules/expo-linking/node_modules/@expo/env": { "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@expo/env/-/env-0.4.2.tgz", - "integrity": "sha512-TgbCgvSk0Kq0e2fLoqHwEBL4M0ztFjnBEz0YCDm5boc1nvkV1VMuIMteVdeBwnTh8Z0oPJTwHCD49vhMEt1I6A==", "license": "MIT", "peer": true, "dependencies": { @@ -15978,8 +15347,6 @@ }, "node_modules/expo-linking/node_modules/@expo/json-file": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-9.0.2.tgz", - "integrity": "sha512-yAznIUrybOIWp3Uax7yRflB0xsEpvIwIEqIjao9SGi2Gaa+N0OamWfe0fnXBSWF+2zzF4VvqwT4W5zwelchfgw==", "license": "MIT", "peer": true, "dependencies": { @@ -15990,8 +15357,6 @@ }, "node_modules/expo-linking/node_modules/@expo/plist": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.2.2.tgz", - "integrity": "sha512-ZZGvTO6vEWq02UAPs3LIdja+HRO18+LRI5QuDl6Hs3Ps7KX7xU6Y6kjahWKY37Rx2YjNpX07dGpBFzzC+vKa2g==", "license": "MIT", "peer": true, "dependencies": { @@ -16002,8 +15367,6 @@ }, "node_modules/expo-linking/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==", "license": "MIT", "peer": true, "dependencies": { @@ -16018,8 +15381,6 @@ }, "node_modules/expo-linking/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", "peer": true, "dependencies": { @@ -16035,8 +15396,6 @@ }, "node_modules/expo-linking/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==", "license": "MIT", "peer": true, "dependencies": { @@ -16048,15 +15407,11 @@ }, "node_modules/expo-linking/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==", "license": "MIT", "peer": true }, "node_modules/expo-linking/node_modules/commander": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "license": "MIT", "peer": true, "engines": { @@ -16065,8 +15420,6 @@ }, "node_modules/expo-linking/node_modules/dotenv": { "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "license": "BSD-2-Clause", "peer": true, "engines": { @@ -16078,8 +15431,6 @@ }, "node_modules/expo-linking/node_modules/expo-constants": { "version": "17.0.8", - "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-17.0.8.tgz", - "integrity": "sha512-XfWRyQAf1yUNgWZ1TnE8pFBMqGmFP5Gb+SFSgszxDdOoheB/NI5D4p7q86kI2fvGyfTrxAe+D+74nZkfsGvUlg==", "license": "MIT", "peer": true, "dependencies": { @@ -16093,8 +15444,6 @@ }, "node_modules/expo-linking/node_modules/glob": { "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "license": "ISC", "peer": true, "dependencies": { @@ -16114,8 +15463,6 @@ }, "node_modules/expo-linking/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==", "license": "MIT", "peer": true, "engines": { @@ -16124,15 +15471,11 @@ }, "node_modules/expo-linking/node_modules/lines-and-columns": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "license": "MIT", "peer": true }, "node_modules/expo-linking/node_modules/minimatch": { "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "license": "ISC", "peer": true, "dependencies": { @@ -16147,8 +15490,6 @@ }, "node_modules/expo-linking/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "peer": true, "bin": { @@ -16160,8 +15501,6 @@ }, "node_modules/expo-linking/node_modules/sucrase": { "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", "license": "MIT", "peer": true, "dependencies": { @@ -16183,8 +15522,6 @@ }, "node_modules/expo-linking/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==", "license": "MIT", "peer": true, "dependencies": { @@ -16375,8 +15712,6 @@ }, "node_modules/expo-web-browser": { "version": "14.0.2", - "resolved": "https://registry.npmjs.org/expo-web-browser/-/expo-web-browser-14.0.2.tgz", - "integrity": "sha512-Hncv2yojhTpHbP6SGWARBFdl7P6wBHc1O8IKaNsH0a/IEakq887o1eRhLxZ5IwztPQyRDhpqHdgJ+BjWolOnwA==", "license": "MIT", "peer": true, "peerDependencies": { @@ -16396,8 +15731,6 @@ }, "node_modules/extension-port-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/extension-port-stream/-/extension-port-stream-3.0.0.tgz", - "integrity": "sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw==", "license": "ISC", "dependencies": { "readable-stream": "^3.6.2 || ^4.4.2", @@ -16426,8 +15759,6 @@ }, "node_modules/fast-glob": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -16469,8 +15800,6 @@ }, "node_modules/fast-safe-stringify": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", "license": "MIT" }, "node_modules/fast-xml-parser": { @@ -16797,8 +16126,6 @@ }, "node_modules/flow-parser": { "version": "0.206.0", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.206.0.tgz", - "integrity": "sha512-HVzoK3r6Vsg+lKvlIZzaWNBVai+FXTX1wdYhz/wVlH13tb/gOdLXmlTqy6odmTBhT5UoWUbq0k8263Qhr9d88w==", "license": "MIT", "peer": true, "engines": { @@ -16862,8 +16189,6 @@ }, "node_modules/form-data": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.3.tgz", - "integrity": "sha512-q5YBMeWy6E2Un0nMGWMgI65MAKtaylxfNJGJxpGh45YDciZB4epbWpaAfImil6CPAPTYB4sh0URQNDRIZG5F2w==", "license": "MIT", "peer": true, "dependencies": { @@ -17032,8 +16357,6 @@ }, "node_modules/get-nonce": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", - "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", "license": "MIT", "peer": true, "engines": { @@ -17244,8 +16567,6 @@ }, "node_modules/git-semver-tags/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -17418,15 +16739,11 @@ }, "node_modules/graphql-tag/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD", "peer": true }, "node_modules/h3": { "version": "1.15.1", - "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.1.tgz", - "integrity": "sha512-+ORaOBttdUm1E2Uu/obAyCguiI7MbBvsLTndc3gyK3zU+SYLoZXlyCP9Xgy0gikkGufFLTZXCXD6+4BsufnmHA==", "license": "MIT", "dependencies": { "cookie-es": "^1.2.2", @@ -17724,8 +17041,6 @@ }, "node_modules/idb-keyval": { "version": "6.2.1", - "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz", - "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==", "license": "Apache-2.0" }, "node_modules/identity-obj-proxy": { @@ -17801,8 +17116,6 @@ }, "node_modules/import-fresh": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", "dependencies": { @@ -17836,8 +17149,6 @@ }, "node_modules/import-local": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, "license": "MIT", "dependencies": { @@ -17917,8 +17228,6 @@ }, "node_modules/init-package-json/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -18143,8 +17452,6 @@ }, "node_modules/iron-webcrypto": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", - "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/brc-dd" @@ -18152,8 +17459,6 @@ }, "node_modules/is-arguments": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -18263,8 +17568,6 @@ }, "node_modules/is-core-module": { "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -18350,8 +17653,6 @@ }, "node_modules/is-generator-function": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", - "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -18700,8 +18001,6 @@ }, "node_modules/isows": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.6.tgz", - "integrity": "sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==", "funding": [ { "type": "github", @@ -18738,8 +18037,6 @@ }, "node_modules/istanbul-lib-instrument/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -20206,8 +19503,6 @@ }, "node_modules/jest-snapshot/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -20438,8 +19733,6 @@ }, "node_modules/jest-watch-typeahead/node_modules/chalk": { "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", "dev": true, "license": "MIT", "engines": { @@ -20451,8 +19744,6 @@ }, "node_modules/jest-watch-typeahead/node_modules/char-regex": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.2.tgz", - "integrity": "sha512-cbGOjAptfM2LVmWhwRFHEKTPkLwNddVmuqYZQt895yXwAsWsXObCG+YN4DGQ/JBtT4GP1a1lPPdio2z413LmTg==", "dev": true, "license": "MIT", "engines": { @@ -20624,8 +19915,6 @@ }, "node_modules/jiti": { "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "license": "MIT", "bin": { "jiti": "bin/jiti.js" @@ -20832,8 +20121,6 @@ }, "node_modules/jsdom/node_modules/form-data": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", "dev": true, "license": "MIT", "dependencies": { @@ -20875,8 +20162,6 @@ }, "node_modules/json-rpc-engine": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz", - "integrity": "sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==", "license": "ISC", "dependencies": { "@metamask/safe-event-emitter": "^2.0.0", @@ -20888,14 +20173,10 @@ }, "node_modules/json-rpc-engine/node_modules/@metamask/safe-event-emitter": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz", - "integrity": "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==", "license": "ISC" }, "node_modules/json-rpc-random-id": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz", - "integrity": "sha512-RJ9YYNCkhVDBuP4zN5BBtYAzEl03yq/jIIsyif0JY9qyJuQQZNeDK7anAPKKlyEtLSj2s8h6hNh2F8zO5q7ScA==", "license": "ISC" }, "node_modules/json-schema-deref-sync": { @@ -20996,8 +20277,6 @@ }, "node_modules/keccak": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", - "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -21011,8 +20290,6 @@ }, "node_modules/keccak/node_modules/node-addon-api": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", "license": "MIT" }, "node_modules/keyv": { @@ -21218,8 +20495,6 @@ }, "node_modules/lerna/node_modules/fs-extra": { "version": "11.3.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", "dev": true, "license": "MIT", "dependencies": { @@ -21412,8 +20687,6 @@ }, "node_modules/lerna/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -21551,8 +20824,6 @@ }, "node_modules/libnpmaccess/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -21582,8 +20853,6 @@ }, "node_modules/libnpmpublish/node_modules/ci-info": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz", - "integrity": "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==", "dev": true, "funding": [ { @@ -21612,8 +20881,6 @@ }, "node_modules/libnpmpublish/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -21691,8 +20958,6 @@ }, "node_modules/lilconfig": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "license": "MIT", "engines": { "node": ">=14" @@ -21939,7 +21204,6 @@ "node_modules/loose-envify": { "version": "1.4.0", "license": "MIT", - "peer": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -21956,8 +21220,6 @@ }, "node_modules/lz-string": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "license": "MIT", "bin": { "lz-string": "bin/bin.js" @@ -21986,8 +21248,6 @@ }, "node_modules/make-dir/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -22056,8 +21316,6 @@ }, "node_modules/md5": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", - "integrity": "sha512-PlGG4z5mBANDGCKsYQe0CaUYHdZYZt8ZPZLmEt+Urf0W4GlpTX4HescwHU+dc9+Z/G/vZKYZYFrwgm9VxK6QOQ==", "license": "BSD-3-Clause", "peer": true, "dependencies": { @@ -22091,8 +21349,6 @@ }, "node_modules/media-query-parser": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/media-query-parser/-/media-query-parser-2.0.2.tgz", - "integrity": "sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w==", "license": "MIT", "peer": true, "dependencies": { @@ -22241,8 +21497,6 @@ }, "node_modules/meow/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -23101,8 +22355,6 @@ }, "node_modules/micro-ftch": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", - "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", "license": "MIT" }, "node_modules/micromatch": { @@ -23361,8 +22613,6 @@ }, "node_modules/mipd": { "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mipd/-/mipd-0.0.7.tgz", - "integrity": "sha512-aAPZPNDQ3uMTdKbuO2YmAw2TxLHO0moa4YKAyETM/DTj5FloZo+a+8tU+iv4GmW+sOxKLSRwcSFuczk+Cpt6fg==", "funding": [ { "type": "github", @@ -23392,8 +22642,6 @@ }, "node_modules/modern-ahocorasick": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/modern-ahocorasick/-/modern-ahocorasick-1.1.0.tgz", - "integrity": "sha512-sEKPVl2rM+MNVkGQt3ChdmD8YsigmXdn5NifZn6jiwn9LRJpWm8F3guhaqrJT/JOat6pwpbXEk6kv+b9DMIjsQ==", "license": "MIT", "peer": true }, @@ -23599,8 +22847,6 @@ }, "node_modules/node-fetch-native": { "version": "1.6.6", - "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz", - "integrity": "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==", "license": "MIT" }, "node_modules/node-fetch/node_modules/tr46": { @@ -23702,8 +22948,6 @@ }, "node_modules/node-gyp/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -23738,14 +22982,10 @@ }, "node_modules/node-mock-http": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.0.tgz", - "integrity": "sha512-0uGYQ1WQL1M5kKvGRXWQ3uZCHtLTO8hln3oBjIusM75WoesZ909uQJs/Hb946i2SS+Gsrhkaa6iAO17jRIv6DQ==", "license": "MIT" }, "node_modules/node-releases": { "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "license": "MIT" }, "node_modules/node-stream-zip": { @@ -23789,8 +23029,6 @@ }, "node_modules/normalize-package-data/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -23839,8 +23077,6 @@ }, "node_modules/npm-install-checks/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -23953,8 +23189,6 @@ }, "node_modules/npm-pick-manifest/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -23998,8 +23232,6 @@ }, "node_modules/npm-registry-fetch/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -24231,8 +23463,6 @@ }, "node_modules/nx/node_modules/dotenv": { "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -24299,8 +23529,6 @@ }, "node_modules/nx/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -24331,8 +23559,6 @@ }, "node_modules/nx/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, @@ -24346,8 +23572,6 @@ }, "node_modules/obj-multiplex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/obj-multiplex/-/obj-multiplex-1.0.0.tgz", - "integrity": "sha512-0GNJAOsHoBHeNTvl5Vt6IWnpUEcc3uSRxzBri7EDyIcMgYvnY2JL2qdeV5zTMjWQX5OHcD5amcW2HFfDh0gjIA==", "license": "ISC", "dependencies": { "end-of-stream": "^1.4.0", @@ -24357,14 +23581,10 @@ }, "node_modules/obj-multiplex/node_modules/isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "license": "MIT" }, "node_modules/obj-multiplex/node_modules/readable-stream": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", @@ -24428,8 +23648,6 @@ }, "node_modules/ofetch": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.4.1.tgz", - "integrity": "sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==", "license": "MIT", "dependencies": { "destr": "^2.0.3", @@ -24619,8 +23837,6 @@ }, "node_modules/ox": { "version": "0.6.7", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.7.tgz", - "integrity": "sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==", "funding": [ { "type": "github", @@ -24648,8 +23864,6 @@ }, "node_modules/ox/node_modules/eventemitter3": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "license": "MIT" }, "node_modules/p-filter": { @@ -24841,8 +24055,6 @@ }, "node_modules/pacote/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -25137,8 +24349,6 @@ }, "node_modules/pony-cause": { "version": "2.1.11", - "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.11.tgz", - "integrity": "sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==", "license": "0BSD", "engines": { "node": ">=12.0.0" @@ -25217,8 +24427,6 @@ }, "node_modules/postcss-cli/node_modules/fs-extra": { "version": "11.3.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -25231,8 +24439,6 @@ }, "node_modules/postcss-cli/node_modules/globby": { "version": "14.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", - "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^2.1.0", @@ -25251,8 +24457,6 @@ }, "node_modules/postcss-cli/node_modules/ignore": { "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.3.tgz", - "integrity": "sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==", "license": "MIT", "engines": { "node": ">= 4" @@ -25270,8 +24474,6 @@ }, "node_modules/postcss-cli/node_modules/path-type": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", - "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", "license": "MIT", "engines": { "node": ">=18" @@ -25848,8 +25050,6 @@ }, "node_modules/preact": { "version": "10.26.5", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.26.5.tgz", - "integrity": "sha512-fmpDkgfGU6JYux9teDWLhj9mKN55tyepwYbxHgQuIxbWQzgFg5vk7Mrrtfx7xRxq798ynkY4DDDxZr235Kk+4w==", "license": "MIT", "funding": { "type": "opencollective", @@ -25858,8 +25058,6 @@ }, "node_modules/preact-render-to-string": { "version": "6.5.13", - "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.13.tgz", - "integrity": "sha512-iGPd+hKPMFKsfpR2vL4kJ6ZPcFIoWZEcBf0Dpm3zOpdVvj77aY8RlLiQji5OMrngEyaxGogeakTb54uS2FvA6w==", "dev": true, "license": "MIT", "peer": true, @@ -25877,8 +25075,6 @@ }, "node_modules/prettier": { "version": "3.5.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "license": "MIT", "bin": { @@ -26361,8 +25557,6 @@ }, "node_modules/radix3": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", - "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", "license": "MIT" }, "node_modules/randombytes": { @@ -26405,7 +25599,6 @@ "node_modules/react": { "version": "18.2.0", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -26444,8 +25637,6 @@ }, "node_modules/react-dom": { "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "license": "MIT", "peer": true, "dependencies": { @@ -26458,8 +25649,6 @@ }, "node_modules/react-dom/node_modules/scheduler": { "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "license": "MIT", "peer": true, "dependencies": { @@ -26690,8 +25879,6 @@ }, "node_modules/react-remove-scroll": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz", - "integrity": "sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==", "license": "MIT", "peer": true, "dependencies": { @@ -26716,8 +25903,6 @@ }, "node_modules/react-remove-scroll-bar": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", - "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", "license": "MIT", "peer": true, "dependencies": { @@ -26739,15 +25924,11 @@ }, "node_modules/react-remove-scroll-bar/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD", "peer": true }, "node_modules/react-remove-scroll/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD", "peer": true }, @@ -26765,8 +25946,6 @@ }, "node_modules/react-style-singleton": { "version": "2.2.3", - "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", - "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", "license": "MIT", "peer": true, "dependencies": { @@ -26788,8 +25967,6 @@ }, "node_modules/react-style-singleton/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD", "peer": true }, @@ -27099,8 +26276,6 @@ }, "node_modules/recast/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD", "peer": true }, @@ -27129,14 +26304,10 @@ }, "node_modules/regenerate": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "license": "MIT" }, "node_modules/regenerate-unicode-properties": { "version": "10.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", - "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "license": "MIT", "dependencies": { "regenerate": "^1.4.2" @@ -27151,8 +26322,6 @@ }, "node_modules/regenerator-transform": { "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.4" @@ -27177,8 +26346,6 @@ }, "node_modules/regexpu-core": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", - "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", "license": "MIT", "dependencies": { "regenerate": "^1.4.2", @@ -27194,14 +26361,10 @@ }, "node_modules/regjsgen": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", "license": "MIT" }, "node_modules/regjsparser": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", - "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", "license": "BSD-2-Clause", "dependencies": { "jsesc": "~3.0.2" @@ -27261,8 +26424,6 @@ }, "node_modules/resolve": { "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "license": "MIT", "dependencies": { "is-core-module": "^2.16.0", @@ -27299,8 +26460,6 @@ }, "node_modules/resolve-workspace-root": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-workspace-root/-/resolve-workspace-root-2.0.0.tgz", - "integrity": "sha512-IsaBUZETJD5WsI11Wt8PKHwaIe45or6pwNc8yflvLJ4DWtImK9kuLoH5kUva/2Mmx/RdIyr4aONNSa2v9LTJsw==", "license": "MIT", "peer": true }, @@ -27603,8 +26762,6 @@ }, "node_modules/rollup-plugin-typescript2/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -27615,8 +26772,6 @@ }, "node_modules/rollup-plugin-typescript2/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/rollup-plugin-typescript2/node_modules/universalify": { @@ -27639,8 +26794,6 @@ }, "node_modules/rollup-preserve-directives": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/rollup-preserve-directives/-/rollup-preserve-directives-1.1.3.tgz", - "integrity": "sha512-oXqxd6ZzkoQej8Qt0k+S/yvO2+S4CEVEVv2g85oL15o0cjAKTKEuo2MzyA8FcsBBXbtytBzBMFAbhvQg4YyPUQ==", "license": "MIT", "dependencies": { "magic-string": "^0.30.5" @@ -27701,8 +26854,6 @@ }, "node_modules/rxjs/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, @@ -28040,8 +27191,6 @@ }, "node_modules/sha.js": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "license": "(MIT AND BSD-3-Clause)", "dependencies": { "inherits": "^2.0.1", @@ -28195,8 +27344,6 @@ }, "node_modules/socket.io-client": { "version": "4.8.1", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz", - "integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==", "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", @@ -28210,8 +27357,6 @@ }, "node_modules/socket.io-parser": { "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", @@ -28249,8 +27394,6 @@ }, "node_modules/socks-proxy-agent/node_modules/agent-base": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "dev": true, "license": "MIT", "engines": { @@ -28468,8 +27611,6 @@ }, "node_modules/string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" @@ -28760,8 +27901,6 @@ }, "node_modules/superstruct": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.4.tgz", - "integrity": "sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==", "license": "MIT", "engines": { "node": ">=14.0.0" @@ -28920,8 +28059,6 @@ }, "node_modules/tailwindcss/node_modules/postcss-load-config/node_modules/lilconfig": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "license": "MIT", "engines": { "node": ">=14" @@ -29469,8 +28606,6 @@ }, "node_modules/ts-jest/node_modules/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -29652,8 +28787,6 @@ }, "node_modules/typescript": { "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -29690,8 +28823,6 @@ }, "node_modules/ufo": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", - "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", "license": "MIT" }, "node_modules/uglify-es": { @@ -29749,8 +28880,6 @@ }, "node_modules/uncrypto": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", - "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", "license": "MIT" }, "node_modules/undici-types": { @@ -29764,8 +28893,6 @@ }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", - "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "license": "MIT", "engines": { "node": ">=4" @@ -29773,8 +28900,6 @@ }, "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", @@ -29786,8 +28911,6 @@ }, "node_modules/unicode-match-property-value-ecmascript": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", - "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "license": "MIT", "engines": { "node": ">=4" @@ -29795,8 +28918,6 @@ }, "node_modules/unicode-property-aliases-ecmascript": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "license": "MIT", "engines": { "node": ">=4" @@ -29804,8 +28925,6 @@ }, "node_modules/unicorn-magic": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", "license": "MIT", "engines": { "node": ">=18" @@ -29867,8 +28986,6 @@ }, "node_modules/unstorage": { "version": "1.15.0", - "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.15.0.tgz", - "integrity": "sha512-m40eHdGY/gA6xAPqo8eaxqXgBuzQTlAKfmB1iF7oCKXE1HfwHwzDJBywK+qQGn52dta+bPlZluPF7++yR3p/bg==", "license": "MIT", "dependencies": { "anymatch": "^3.1.3", @@ -29959,8 +29076,6 @@ }, "node_modules/unstorage/node_modules/chokidar": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "license": "MIT", "dependencies": { "readdirp": "^4.0.1" @@ -29974,14 +29089,10 @@ }, "node_modules/unstorage/node_modules/lru-cache": { "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "license": "ISC" }, "node_modules/unstorage/node_modules/readdirp": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "license": "MIT", "engines": { "node": ">= 14.18.0" @@ -30052,8 +29163,6 @@ }, "node_modules/use-callback-ref": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", - "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", "license": "MIT", "peer": true, "dependencies": { @@ -30074,15 +29183,11 @@ }, "node_modules/use-callback-ref/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD", "peer": true }, "node_modules/use-sidecar": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", - "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", "license": "MIT", "peer": true, "dependencies": { @@ -30104,8 +29209,6 @@ }, "node_modules/use-sidecar/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD", "peer": true }, @@ -30246,8 +29349,6 @@ }, "node_modules/viem": { "version": "2.23.2", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.23.2.tgz", - "integrity": "sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==", "funding": [ { "type": "github", @@ -30292,8 +29393,6 @@ }, "node_modules/wagmi": { "version": "2.14.16", - "resolved": "https://registry.npmjs.org/wagmi/-/wagmi-2.14.16.tgz", - "integrity": "sha512-njOPvB8L0+jt3m1FTJiVF44T1u+kcjLtVWKvwI0mZnIesZTQZ/xDF0M/NHj3Uljyn3qJw3pyHjJe31NC+VVHMA==", "license": "MIT", "dependencies": { "@wagmi/connectors": "5.7.12", @@ -30348,8 +29447,6 @@ }, "node_modules/webextension-polyfill": { "version": "0.10.0", - "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", - "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==", "license": "MPL-2.0" }, "node_modules/webidl-conversions": { @@ -30847,8 +29944,6 @@ }, "node_modules/ws": { "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -30929,8 +30024,6 @@ }, "node_modules/xmlhttprequest-ssl": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", - "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", "engines": { "node": ">=0.4.0" } @@ -30955,8 +30048,6 @@ }, "node_modules/yaml": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", - "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -31019,8 +30110,6 @@ }, "node_modules/zustand": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.0.tgz", - "integrity": "sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ==", "license": "MIT", "engines": { "node": ">=12.20.0" @@ -31083,13 +30172,13 @@ }, "packages/fcl": { "name": "@onflow/fcl", - "version": "1.16.0", + "version": "1.16.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", "@onflow/fcl-core": "1.17.0", - "@onflow/fcl-wc": "6.0.0", + "@onflow/fcl-wc": "6.0.1", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", "@onflow/sdk": "1.8.0", @@ -31194,8 +30283,6 @@ }, "packages/fcl-core/node_modules/cross-fetch": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", - "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", "license": "MIT", "dependencies": { "node-fetch": "^2.7.0" @@ -31215,14 +30302,14 @@ }, "packages/fcl-ethereum-provider": { "name": "@onflow/fcl-ethereum-provider", - "version": "0.0.2", + "version": "0.0.3", "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.0", + "@onflow/fcl-wc": "6.0.1", "@onflow/rlp": "^1.2.3", "@walletconnect/ethereum-provider": "^2.18.0", "@walletconnect/jsonrpc-http-connection": "^1.0.8", @@ -31243,24 +30330,25 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.16.0" + "@onflow/fcl": "1.16.1" } }, "packages/fcl-rainbowkit-adapter": { "name": "@onflow/fcl-rainbowkit-adapter", - "version": "0.0.2", + "version": "0.0.3", "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.2", - "@onflow/fcl-wagmi-adapter": "0.0.2", + "@onflow/fcl-ethereum-provider": "0.0.3", + "@onflow/fcl-wagmi-adapter": "0.0.3", "@onflow/rlp": "^1.2.3", "@wagmi/core": "^2.16.3", "@walletconnect/jsonrpc-http-connection": "^1.0.8", "@walletconnect/jsonrpc-provider": "^1.0.14", "mipd": "^0.0.7", + "react": "17.x || 18.x || 19.x", "viem": "^2.22.21", "wagmi": "^2.14.11" }, @@ -31269,6 +30357,7 @@ "@onflow/fcl-bundle": "1.7.0", "@onflow/typedefs": "^1.4.0", "@types/jest": "^29.5.13", + "@types/react": "^16.0.0", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", "eslint": "^8.57.1", @@ -31276,8 +30365,21 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.16.0", - "@rainbow-me/rainbowkit": "^2.2.3" + "@onflow/fcl": "1.16.1", + "@rainbow-me/rainbowkit": "^2.2.3", + "react": "17.x || 18.x || 19.x" + } + }, + "packages/fcl-rainbowkit-adapter/node_modules/@types/react": { + "version": "16.14.63", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.63.tgz", + "integrity": "sha512-s83gano0fRBVEw3ejdLpjgvU83F0LIeeuXqdxfPZF/Sc2bhr60tEqCK1zZ+aLirBwRSD6V5zCtOsEjcwKow3JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "^0.16", + "csstype": "^3.0.2" } }, "packages/fcl-react-native": { @@ -31322,8 +30424,6 @@ }, "packages/fcl-react-native/node_modules/cross-fetch": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", - "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", "license": "MIT", "dependencies": { "node-fetch": "^2.7.0" @@ -31343,13 +30443,13 @@ }, "packages/fcl-wagmi-adapter": { "name": "@onflow/fcl-wagmi-adapter", - "version": "0.0.2", + "version": "0.0.3", "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.2", + "@onflow/fcl-ethereum-provider": "0.0.3", "@onflow/rlp": "^1.2.3", "@walletconnect/jsonrpc-http-connection": "^1.0.8", "@walletconnect/jsonrpc-provider": "^1.0.14", @@ -31371,13 +30471,13 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.16.0", + "@onflow/fcl": "1.16.1", "@wagmi/core": "^2.16.3" } }, "packages/fcl-wc": { "name": "@onflow/fcl-wc", - "version": "6.0.0", + "version": "6.0.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -31412,8 +30512,6 @@ }, "packages/fcl/node_modules/cross-fetch": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", - "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", "license": "MIT", "dependencies": { "node-fetch": "^2.7.0" @@ -31433,7 +30531,7 @@ }, "packages/kit": { "name": "@onflow/kit", - "version": "0.0.1", + "version": "0.0.2", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -31616,8 +30714,6 @@ }, "packages/transport-http/node_modules/cross-fetch": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", - "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", "license": "MIT", "dependencies": { "node-fetch": "^2.7.0" diff --git a/packages/fcl-rainbowkit-adapter/package.json b/packages/fcl-rainbowkit-adapter/package.json index ff4a3b28e..ea3337f56 100644 --- a/packages/fcl-rainbowkit-adapter/package.json +++ b/packages/fcl-rainbowkit-adapter/package.json @@ -21,7 +21,8 @@ "@typescript-eslint/parser": "^6.21.0", "eslint": "^8.57.1", "eslint-plugin-jsdoc": "^46.10.1", - "jest": "^29.7.0" + "jest": "^29.7.0", + "@types/react": "^16.0.0" }, "source": "src/index.ts", "main": "dist/index.js", @@ -46,11 +47,13 @@ "@walletconnect/jsonrpc-http-connection": "^1.0.8", "@walletconnect/jsonrpc-provider": "^1.0.14", "mipd": "^0.0.7", + "react": "17.x || 18.x || 19.x", "viem": "^2.22.21", "wagmi": "^2.14.11" }, "peerDependencies": { "@onflow/fcl": "1.16.1", - "@rainbow-me/rainbowkit": "^2.2.3" + "@rainbow-me/rainbowkit": "^2.2.3", + "react": "17.x || 18.x || 19.x" } } diff --git a/packages/fcl-rainbowkit-adapter/src/use-is-cadence-wallet-connected.ts b/packages/fcl-rainbowkit-adapter/src/use-is-cadence-wallet-connected.ts new file mode 100644 index 000000000..457d406c0 --- /dev/null +++ b/packages/fcl-rainbowkit-adapter/src/use-is-cadence-wallet-connected.ts @@ -0,0 +1,38 @@ +import * as fcl from "@onflow/fcl" +import {CurrentUser} from "@onflow/typedefs" +import {Config, getAccount, watchAccount} from "@wagmi/core" +import {useEffect, useState} from "react" + +export async function useIsCadenceWalletConnected(config: Config) { + const [wagmiAccount, setWagmiAccount] = useState(() => getAccount(config)) + const [fclAccount, setFclAccount] = useState(() => null) + + useEffect(() => { + const unsub = watchAccount(config, { + onChange: account => { + const isCadenceWallet = account?.address !== undefined + setWagmiAccount(getAccount(config)) + }, + }) + + return () => { + unsub() + } + }, [config]) + + useEffect(() => { + const unsubscribe = fcl.currentUser().subscribe((user: CurrentUser) => { + setFclAccount(user) + }) + + return () => { + unsubscribe() + } + }) + + return ( + fclAccount?.addr !== undefined && + fclAccount?.loggedIn === true && + wagmiAccount.isConnected + ) +} From f86b71357696826a5ad7b8e578de76ecebcd2e29 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Wed, 7 May 2025 01:51:18 +0000 Subject: [PATCH 26/72] Expose origin in `onMessageFromFCL` callback (#2384) --- .changeset/tiny-buses-wash.md | 7 + package-lock.json | 1170 ++++++++++++++++- .../src/wallet-utils/on-message-from-fcl.js | 4 +- 3 files changed, 1135 insertions(+), 46 deletions(-) create mode 100644 .changeset/tiny-buses-wash.md diff --git a/.changeset/tiny-buses-wash.md b/.changeset/tiny-buses-wash.md new file mode 100644 index 000000000..dd8eca851 --- /dev/null +++ b/.changeset/tiny-buses-wash.md @@ -0,0 +1,7 @@ +--- +"@onflow/fcl-core": minor +"@onflow/fcl": minor +"@onflow/fcl-react-native": minor +--- + +Include origin information in `onMessageFromFcl` function diff --git a/package-lock.json b/package-lock.json index 5a24b1881..6e492b6e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9034,6 +9034,781 @@ "react-native": "*" } }, + "node_modules/@reown/appkit": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@reown/appkit/-/appkit-1.7.3.tgz", + "integrity": "sha512-aA/UIwi/dVzxEB62xlw3qxHa3RK1YcPMjNxoGj/fHNCqL2qWmbcOXT7coCUa9RG7/Bh26FZ3vdVT2v71j6hebQ==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.7.3", + "@reown/appkit-controllers": "1.7.3", + "@reown/appkit-polyfills": "1.7.3", + "@reown/appkit-scaffold-ui": "1.7.3", + "@reown/appkit-ui": "1.7.3", + "@reown/appkit-utils": "1.7.3", + "@reown/appkit-wallet": "1.7.3", + "@walletconnect/types": "2.19.2", + "@walletconnect/universal-provider": "2.19.2", + "bs58": "6.0.0", + "valtio": "1.13.2", + "viem": ">=2.23.11" + } + }, + "node_modules/@reown/appkit-common": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@reown/appkit-common/-/appkit-common-1.7.3.tgz", + "integrity": "sha512-wKTr6N3z8ly17cc51xBEVkZK4zAd8J1m7RubgsdQ1olFY9YJGe61RYoNv9yFjt6tUVeYT+z7iMUwPhX2PziefQ==", + "license": "Apache-2.0", + "dependencies": { + "big.js": "6.2.2", + "dayjs": "1.11.13", + "viem": ">=2.23.11" + } + }, + "node_modules/@reown/appkit-common/node_modules/@noble/curves": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", + "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.2" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-common/node_modules/@noble/hashes": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", + "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-common/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/@reown/appkit-common/node_modules/ox": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", + "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.10.1", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0", + "@scure/bip32": "^1.5.0", + "@scure/bip39": "^1.4.0", + "abitype": "^1.0.6", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-common/node_modules/viem": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.29.0.tgz", + "integrity": "sha512-N6GeIuuay/spDyw+5FbSuNIkVN0da+jGOjdlC0bdatIN+N0jtOf9Zfj0pbXgpIJGwnM9ocxzTRt0HZVbHBdL2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.2", + "@noble/hashes": "1.7.2", + "@scure/bip32": "1.6.2", + "@scure/bip39": "1.5.4", + "abitype": "1.0.8", + "isows": "1.0.6", + "ox": "0.6.9", + "ws": "8.18.1" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-common/node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-controllers": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@reown/appkit-controllers/-/appkit-controllers-1.7.3.tgz", + "integrity": "sha512-aqAcX/nZe0gwqjncyCkVrAk3lEw0qZ9xGrdLOmA207RreO4J0Vxu8OJXCBn4C2AUI2OpBxCPah+vyuKTUJTeHQ==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.7.3", + "@reown/appkit-wallet": "1.7.3", + "@walletconnect/universal-provider": "2.19.2", + "valtio": "1.13.2", + "viem": ">=2.23.11" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/@noble/curves": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", + "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.2" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/@noble/hashes": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", + "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/@reown/appkit-controllers/node_modules/ox": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", + "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.10.1", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0", + "@scure/bip32": "^1.5.0", + "@scure/bip39": "^1.4.0", + "abitype": "^1.0.6", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-controllers/node_modules/proxy-compare": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.6.0.tgz", + "integrity": "sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==", + "license": "MIT" + }, + "node_modules/@reown/appkit-controllers/node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/valtio": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.13.2.tgz", + "integrity": "sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==", + "license": "MIT", + "dependencies": { + "derive-valtio": "0.1.0", + "proxy-compare": "2.6.0", + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-controllers/node_modules/viem": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.29.0.tgz", + "integrity": "sha512-N6GeIuuay/spDyw+5FbSuNIkVN0da+jGOjdlC0bdatIN+N0jtOf9Zfj0pbXgpIJGwnM9ocxzTRt0HZVbHBdL2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.2", + "@noble/hashes": "1.7.2", + "@scure/bip32": "1.6.2", + "@scure/bip39": "1.5.4", + "abitype": "1.0.8", + "isows": "1.0.6", + "ox": "0.6.9", + "ws": "8.18.1" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-controllers/node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-polyfills": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@reown/appkit-polyfills/-/appkit-polyfills-1.7.3.tgz", + "integrity": "sha512-vQUiAyI7WiNTUV4iNwv27iigdeg8JJTEo6ftUowIrKZ2/gtE2YdMtGpavuztT/qrXhrIlTjDGp5CIyv9WOTu4g==", + "license": "Apache-2.0", + "dependencies": { + "buffer": "6.0.3" + } + }, + "node_modules/@reown/appkit-scaffold-ui": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@reown/appkit-scaffold-ui/-/appkit-scaffold-ui-1.7.3.tgz", + "integrity": "sha512-ssB15fcjmoKQ+VfoCo7JIIK66a4SXFpCH8uK1CsMmXmKIKqPN54ohLo291fniV6mKtnJxh5Xm68slGtGrO3bmA==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.7.3", + "@reown/appkit-controllers": "1.7.3", + "@reown/appkit-ui": "1.7.3", + "@reown/appkit-utils": "1.7.3", + "@reown/appkit-wallet": "1.7.3", + "lit": "3.1.0" + } + }, + "node_modules/@reown/appkit-scaffold-ui/node_modules/@lit/reactive-element": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.0.tgz", + "integrity": "sha512-L2qyoZSQClcBmq0qajBVbhYEcG6iK0XfLn66ifLe/RfC0/ihpc+pl0Wdn8bJ8o+hj38cG0fGXRgSS20MuXn7qA==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.2.0" + } + }, + "node_modules/@reown/appkit-scaffold-ui/node_modules/lit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.0.tgz", + "integrity": "sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^2.0.0", + "lit-element": "^4.0.0", + "lit-html": "^3.1.0" + } + }, + "node_modules/@reown/appkit-scaffold-ui/node_modules/lit-element": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.0.tgz", + "integrity": "sha512-MGrXJVAI5x+Bfth/pU9Kst1iWID6GHDLEzFEnyULB/sFiRLgkd8NPK/PeeXxktA3T6EIIaq8U3KcbTU5XFcP2Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.2.0", + "@lit/reactive-element": "^2.1.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/@reown/appkit-scaffold-ui/node_modules/lit-html": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.0.tgz", + "integrity": "sha512-RHoswrFAxY2d8Cf2mm4OZ1DgzCoBKUKSPvA1fhtSELxUERq2aQQ2h05pO9j81gS1o7RIRJ+CePLogfyahwmynw==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/@reown/appkit-ui": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@reown/appkit-ui/-/appkit-ui-1.7.3.tgz", + "integrity": "sha512-zKmFIjLp0X24pF9KtPtSHmdsh/RjEWIvz+faIbPGm4tQbwcxdg9A35HeoP0rMgKYx49SX51LgPwVXne2gYacqQ==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.7.3", + "@reown/appkit-controllers": "1.7.3", + "@reown/appkit-wallet": "1.7.3", + "lit": "3.1.0", + "qrcode": "1.5.3" + } + }, + "node_modules/@reown/appkit-ui/node_modules/@lit/reactive-element": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.0.tgz", + "integrity": "sha512-L2qyoZSQClcBmq0qajBVbhYEcG6iK0XfLn66ifLe/RfC0/ihpc+pl0Wdn8bJ8o+hj38cG0fGXRgSS20MuXn7qA==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.2.0" + } + }, + "node_modules/@reown/appkit-ui/node_modules/lit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.0.tgz", + "integrity": "sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^2.0.0", + "lit-element": "^4.0.0", + "lit-html": "^3.1.0" + } + }, + "node_modules/@reown/appkit-ui/node_modules/lit-element": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.0.tgz", + "integrity": "sha512-MGrXJVAI5x+Bfth/pU9Kst1iWID6GHDLEzFEnyULB/sFiRLgkd8NPK/PeeXxktA3T6EIIaq8U3KcbTU5XFcP2Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.2.0", + "@lit/reactive-element": "^2.1.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/@reown/appkit-ui/node_modules/lit-html": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.0.tgz", + "integrity": "sha512-RHoswrFAxY2d8Cf2mm4OZ1DgzCoBKUKSPvA1fhtSELxUERq2aQQ2h05pO9j81gS1o7RIRJ+CePLogfyahwmynw==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/@reown/appkit-utils": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@reown/appkit-utils/-/appkit-utils-1.7.3.tgz", + "integrity": "sha512-8/MNhmfri+2uu8WzBhZ5jm5llofOIa1dyXDXRC/hfrmGmCFJdrQKPpuqOFYoimo2s2g70pK4PYefvOKgZOWzgg==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.7.3", + "@reown/appkit-controllers": "1.7.3", + "@reown/appkit-polyfills": "1.7.3", + "@reown/appkit-wallet": "1.7.3", + "@walletconnect/logger": "2.1.2", + "@walletconnect/universal-provider": "2.19.2", + "valtio": "1.13.2", + "viem": ">=2.23.11" + }, + "peerDependencies": { + "valtio": "1.13.2" + } + }, + "node_modules/@reown/appkit-utils/node_modules/@noble/curves": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", + "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.2" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-utils/node_modules/@noble/hashes": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", + "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-utils/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/@reown/appkit-utils/node_modules/ox": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", + "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.10.1", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0", + "@scure/bip32": "^1.5.0", + "@scure/bip39": "^1.4.0", + "abitype": "^1.0.6", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-utils/node_modules/proxy-compare": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.6.0.tgz", + "integrity": "sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==", + "license": "MIT" + }, + "node_modules/@reown/appkit-utils/node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@reown/appkit-utils/node_modules/valtio": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.13.2.tgz", + "integrity": "sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==", + "license": "MIT", + "dependencies": { + "derive-valtio": "0.1.0", + "proxy-compare": "2.6.0", + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-utils/node_modules/viem": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.29.0.tgz", + "integrity": "sha512-N6GeIuuay/spDyw+5FbSuNIkVN0da+jGOjdlC0bdatIN+N0jtOf9Zfj0pbXgpIJGwnM9ocxzTRt0HZVbHBdL2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.2", + "@noble/hashes": "1.7.2", + "@scure/bip32": "1.6.2", + "@scure/bip39": "1.5.4", + "abitype": "1.0.8", + "isows": "1.0.6", + "ox": "0.6.9", + "ws": "8.18.1" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-utils/node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-wallet": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@reown/appkit-wallet/-/appkit-wallet-1.7.3.tgz", + "integrity": "sha512-D0pExd0QUE71ursQPp3pq/0iFrz2oz87tOyFifrPANvH5X0RQCYn/34/kXr+BFVQzNFfCBDlYP+CniNA/S0KiQ==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.7.3", + "@reown/appkit-polyfills": "1.7.3", + "@walletconnect/logger": "2.1.2", + "zod": "3.22.4" + } + }, + "node_modules/@reown/appkit-wallet/node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@reown/appkit/node_modules/@noble/curves": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", + "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.2" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit/node_modules/@noble/hashes": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", + "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/@reown/appkit/node_modules/ox": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", + "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.10.1", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0", + "@scure/bip32": "^1.5.0", + "@scure/bip39": "^1.4.0", + "abitype": "^1.0.6", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@reown/appkit/node_modules/proxy-compare": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.6.0.tgz", + "integrity": "sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==", + "license": "MIT" + }, + "node_modules/@reown/appkit/node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@reown/appkit/node_modules/valtio": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.13.2.tgz", + "integrity": "sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==", + "license": "MIT", + "dependencies": { + "derive-valtio": "0.1.0", + "proxy-compare": "2.6.0", + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/@reown/appkit/node_modules/viem": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.29.0.tgz", + "integrity": "sha512-N6GeIuuay/spDyw+5FbSuNIkVN0da+jGOjdlC0bdatIN+N0jtOf9Zfj0pbXgpIJGwnM9ocxzTRt0HZVbHBdL2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.2", + "@noble/hashes": "1.7.2", + "@scure/bip32": "1.6.2", + "@scure/bip39": "1.5.4", + "abitype": "1.0.8", + "isows": "1.0.6", + "ox": "0.6.9", + "ws": "8.18.1" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@reown/appkit/node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@rnx-kit/chromium-edge-launcher": { "version": "1.0.0", "license": "Apache-2.0", @@ -10815,29 +11590,6 @@ } } }, - "node_modules/@walletconnect/utils/node_modules/query-string": { - "version": "7.1.3", - "license": "MIT", - "dependencies": { - "decode-uri-component": "^0.2.2", - "filter-obj": "^1.1.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@walletconnect/utils/node_modules/strict-uri-encode": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/@walletconnect/window-getters": { "version": "1.0.1", "license": "MIT", @@ -12084,7 +12836,20 @@ "license": "Unlicense", "peer": true, "engines": { - "node": ">=0.6" + "node": ">=0.6" + } + }, + "node_modules/big.js": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz", + "integrity": "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" } }, "node_modules/bin-links": { @@ -13658,8 +14423,7 @@ }, "node_modules/dayjs": { "version": "1.11.13", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/debug": { "version": "4.3.7", @@ -13901,6 +14665,15 @@ "node": ">=6" } }, + "node_modules/derive-valtio": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/derive-valtio/-/derive-valtio-0.1.0.tgz", + "integrity": "sha512-OCg2UsLbXK7GmmpzMXhYkdO64vhJ1ROUUGaTFyHjVwEdMEcTTRj7W1TxLbSBxdY8QLBPCcp66MTyaSy0RpO17A==", + "license": "MIT", + "peerDependencies": { + "valtio": "*" + } + }, "node_modules/destr": { "version": "2.0.5", "license": "MIT" @@ -25512,6 +26285,24 @@ "node": ">=6" } }, + "node_modules/query-string": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", + "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", + "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.2.2", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/querystringify": { "version": "2.2.0", "dev": true, @@ -27609,6 +28400,15 @@ "version": "1.0.3", "license": "MIT" }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "license": "MIT", @@ -30311,12 +31111,12 @@ "@noble/hashes": "^1.7.1", "@onflow/fcl-wc": "6.0.1", "@onflow/rlp": "^1.2.3", - "@walletconnect/ethereum-provider": "^2.18.0", + "@walletconnect/ethereum-provider": "^2.20.2", "@walletconnect/jsonrpc-http-connection": "^1.0.8", "@walletconnect/jsonrpc-provider": "^1.0.14", "@walletconnect/types": "^2.18.0", - "@walletconnect/universal-provider": "^2.18.0", - "@walletconnect/utils": "^2.18.0" + "@walletconnect/universal-provider": "^2.20.2", + "@walletconnect/utils": "^2.20.2" }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", @@ -30333,9 +31133,165 @@ "@onflow/fcl": "1.16.1" } }, + "packages/fcl-ethereum-provider/node_modules/@react-native-async-storage/async-storage": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.24.0.tgz", + "integrity": "sha512-W4/vbwUOYOjco0x3toB8QCr7EjIP6nE9G7o8PMguvvjYT5Awg09lyV4enACRx4s++PPulBiBSjL0KTFx2u0Z/g==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "merge-options": "^3.0.4" + }, + "peerDependencies": { + "react-native": "^0.0.0-0 || >=0.60 <1.0" + } + }, + "packages/fcl-ethereum-provider/node_modules/@walletconnect/core": { + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.20.2.tgz", + "integrity": "sha512-48XnarxQQrpJ0KZJOjit56DxuzfVRYUdL8XVMvUh/ZNUiX2FB5w6YuljUUeTLfYOf04Et6qhVGEUkmX3W+9/8w==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/jsonrpc-ws-connection": "1.0.16", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.20.2", + "@walletconnect/utils": "2.20.2", + "@walletconnect/window-getters": "1.0.1", + "es-toolkit": "1.33.0", + "events": "3.3.0", + "uint8arrays": "3.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "packages/fcl-ethereum-provider/node_modules/@walletconnect/ethereum-provider": { + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/@walletconnect/ethereum-provider/-/ethereum-provider-2.20.2.tgz", + "integrity": "sha512-fGNJtytHuBWZcmMXRIG1djlfEiPMvPJ0R3JlfJjAx2VfVN+O+1xdF6QSWcZxFizviIUFJV+f1zWt0V2VVD61Rg==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit": "1.7.3", + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/sign-client": "2.20.2", + "@walletconnect/types": "2.20.2", + "@walletconnect/universal-provider": "2.20.2", + "@walletconnect/utils": "2.20.2", + "events": "3.3.0" + } + }, + "packages/fcl-ethereum-provider/node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "packages/fcl-ethereum-provider/node_modules/@walletconnect/sign-client": { + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.20.2.tgz", + "integrity": "sha512-KyeDToypZ1OjCbij4Jx0cAg46bMwZ6zCKt0HzCkqENcex3Zchs7xBp9r8GtfEMGw+PUnXwqrhzmLBH0x/43oIQ==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/core": "2.20.2", + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/logger": "2.1.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.20.2", + "@walletconnect/utils": "2.20.2", + "events": "3.3.0" + } + }, + "packages/fcl-ethereum-provider/node_modules/@walletconnect/types": { + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.20.2.tgz", + "integrity": "sha512-XPPbJM/mGU05i6jUxhC3yI/YvhSF6TYJQ5SXTWM53lVe6hs6ukvlEhPctu9ZBTGwGFhwPXIjtK/eWx+v4WY5iw==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "events": "3.3.0" + } + }, + "packages/fcl-ethereum-provider/node_modules/@walletconnect/universal-provider": { + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.20.2.tgz", + "integrity": "sha512-6uVu1E88tioaXEEJCbJKwCIQlOHif1nmfY092BznZEnBn2lli5ICzQh2bxtUDNmNNLKsMDI3FV1fODFeWMVJTQ==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/sign-client": "2.20.2", + "@walletconnect/types": "2.20.2", + "@walletconnect/utils": "2.20.2", + "es-toolkit": "1.33.0", + "events": "3.3.0" + } + }, + "packages/fcl-ethereum-provider/node_modules/@walletconnect/utils": { + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.20.2.tgz", + "integrity": "sha512-2uRUDvpYSIJFYcr1WIuiFy6CEszLF030o6W8aDMkGk9/MfAZYEJQHMJcjWyaNMPHLJT0POR5lPaqkYOpuyPIQQ==", + "license": "Apache-2.0", + "dependencies": { + "@noble/ciphers": "1.2.1", + "@noble/curves": "1.8.1", + "@noble/hashes": "1.7.1", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.20.2", + "@walletconnect/window-getters": "1.0.1", + "@walletconnect/window-metadata": "1.0.1", + "bs58": "6.0.0", + "detect-browser": "5.3.0", + "query-string": "7.1.3", + "uint8arrays": "3.1.0", + "viem": "2.23.2" + } + }, "packages/fcl-rainbowkit-adapter": { "name": "@onflow/fcl-rainbowkit-adapter", - "version": "0.0.3", + "version": "0.1.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -30345,8 +31301,6 @@ "@onflow/fcl-wagmi-adapter": "0.0.3", "@onflow/rlp": "^1.2.3", "@wagmi/core": "^2.16.3", - "@walletconnect/jsonrpc-http-connection": "^1.0.8", - "@walletconnect/jsonrpc-provider": "^1.0.14", "mipd": "^0.0.7", "react": "17.x || 18.x || 19.x", "viem": "^2.22.21", @@ -30451,12 +31405,6 @@ "@ethersproject/hash": "^5.7.0", "@onflow/fcl-ethereum-provider": "0.0.3", "@onflow/rlp": "^1.2.3", - "@walletconnect/jsonrpc-http-connection": "^1.0.8", - "@walletconnect/jsonrpc-provider": "^1.0.14", - "@walletconnect/modal": "^2.7.0", - "@walletconnect/types": "^2.18.0", - "@walletconnect/universal-provider": "^2.18.0", - "@walletconnect/utils": "^2.18.0", "viem": "^2.22.21" }, "devDependencies": { @@ -30484,13 +31432,10 @@ "@onflow/config": "1.5.2", "@onflow/util-invariant": "1.2.4", "@onflow/util-logger": "1.3.3", - "@walletconnect/ethereum-provider": "^2.18.0", "@walletconnect/modal": "^2.7.0", - "@walletconnect/modal-core": "^2.6.2", - "@walletconnect/sign-client": "^2.17.1", - "@walletconnect/types": "^2.8.1", - "@walletconnect/universal-provider": "^2.18.0", - "@walletconnect/utils": "^2.8.1", + "@walletconnect/types": "^2.20.2", + "@walletconnect/universal-provider": "^2.20.2", + "@walletconnect/utils": "^2.20.2", "postcss-cli": "^11.0.0", "preact": "^10.24.3", "tailwindcss": "^3.4.14" @@ -30510,6 +31455,143 @@ "@onflow/fcl-core": "1.17.0" } }, + "packages/fcl-wc/node_modules/@react-native-async-storage/async-storage": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.24.0.tgz", + "integrity": "sha512-W4/vbwUOYOjco0x3toB8QCr7EjIP6nE9G7o8PMguvvjYT5Awg09lyV4enACRx4s++PPulBiBSjL0KTFx2u0Z/g==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "merge-options": "^3.0.4" + }, + "peerDependencies": { + "react-native": "^0.0.0-0 || >=0.60 <1.0" + } + }, + "packages/fcl-wc/node_modules/@walletconnect/core": { + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.20.2.tgz", + "integrity": "sha512-48XnarxQQrpJ0KZJOjit56DxuzfVRYUdL8XVMvUh/ZNUiX2FB5w6YuljUUeTLfYOf04Et6qhVGEUkmX3W+9/8w==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/jsonrpc-ws-connection": "1.0.16", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.20.2", + "@walletconnect/utils": "2.20.2", + "@walletconnect/window-getters": "1.0.1", + "es-toolkit": "1.33.0", + "events": "3.3.0", + "uint8arrays": "3.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "packages/fcl-wc/node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "packages/fcl-wc/node_modules/@walletconnect/sign-client": { + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.20.2.tgz", + "integrity": "sha512-KyeDToypZ1OjCbij4Jx0cAg46bMwZ6zCKt0HzCkqENcex3Zchs7xBp9r8GtfEMGw+PUnXwqrhzmLBH0x/43oIQ==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/core": "2.20.2", + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/logger": "2.1.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.20.2", + "@walletconnect/utils": "2.20.2", + "events": "3.3.0" + } + }, + "packages/fcl-wc/node_modules/@walletconnect/types": { + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.20.2.tgz", + "integrity": "sha512-XPPbJM/mGU05i6jUxhC3yI/YvhSF6TYJQ5SXTWM53lVe6hs6ukvlEhPctu9ZBTGwGFhwPXIjtK/eWx+v4WY5iw==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "events": "3.3.0" + } + }, + "packages/fcl-wc/node_modules/@walletconnect/universal-provider": { + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.20.2.tgz", + "integrity": "sha512-6uVu1E88tioaXEEJCbJKwCIQlOHif1nmfY092BznZEnBn2lli5ICzQh2bxtUDNmNNLKsMDI3FV1fODFeWMVJTQ==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/sign-client": "2.20.2", + "@walletconnect/types": "2.20.2", + "@walletconnect/utils": "2.20.2", + "es-toolkit": "1.33.0", + "events": "3.3.0" + } + }, + "packages/fcl-wc/node_modules/@walletconnect/utils": { + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.20.2.tgz", + "integrity": "sha512-2uRUDvpYSIJFYcr1WIuiFy6CEszLF030o6W8aDMkGk9/MfAZYEJQHMJcjWyaNMPHLJT0POR5lPaqkYOpuyPIQQ==", + "license": "Apache-2.0", + "dependencies": { + "@noble/ciphers": "1.2.1", + "@noble/curves": "1.8.1", + "@noble/hashes": "1.7.1", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.20.2", + "@walletconnect/window-getters": "1.0.1", + "@walletconnect/window-metadata": "1.0.1", + "bs58": "6.0.0", + "detect-browser": "5.3.0", + "query-string": "7.1.3", + "uint8arrays": "3.1.0", + "viem": "2.23.2" + } + }, "packages/fcl/node_modules/cross-fetch": { "version": "4.1.0", "license": "MIT", diff --git a/packages/fcl-core/src/wallet-utils/on-message-from-fcl.js b/packages/fcl-core/src/wallet-utils/on-message-from-fcl.js index 04547a312..585269fe2 100644 --- a/packages/fcl-core/src/wallet-utils/on-message-from-fcl.js +++ b/packages/fcl-core/src/wallet-utils/on-message-from-fcl.js @@ -16,12 +16,12 @@ export const onMessageFromFCL = (messageType, cb = () => {}) => { } const internal = e => { - const {data} = e + const {data, origin} = e if (typeof data !== "object") return if (typeof data == null) return if (data.type !== messageType) return - cb(buildData(data)) + cb(buildData(data), {origin}) } window.addEventListener("message", internal) From 0feeae00d1ef089df36b381109802bb0b14bf89b Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Wed, 7 May 2025 14:45:55 +0000 Subject: [PATCH 27/72] Update and clean up WalletConnect dependencies (#2382) --- .changeset/few-eagles-explode.md | 6 ++++++ .changeset/rude-emus-happen.md | 6 ++++++ packages/fcl-ethereum-provider/package.json | 6 +++--- packages/fcl-rainbowkit-adapter/package.json | 2 -- packages/fcl-wagmi-adapter/package.json | 6 ------ packages/fcl-wc/jest.config.js | 1 + packages/fcl-wc/jest.setup.ts | 5 +++++ packages/fcl-wc/package.json | 9 +++------ packages/fcl-wc/src/fcl-wc.test.ts | 1 - packages/fcl-wc/src/service.ts | 3 +-- 10 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 .changeset/few-eagles-explode.md create mode 100644 .changeset/rude-emus-happen.md create mode 100644 packages/fcl-wc/jest.setup.ts diff --git a/.changeset/few-eagles-explode.md b/.changeset/few-eagles-explode.md new file mode 100644 index 000000000..e910411df --- /dev/null +++ b/.changeset/few-eagles-explode.md @@ -0,0 +1,6 @@ +--- +"@onflow/fcl-wc": patch +"@onflow/fcl-wagmi-adapter": patch +--- + +Remove unused WalletConnect dependencies diff --git a/.changeset/rude-emus-happen.md b/.changeset/rude-emus-happen.md new file mode 100644 index 000000000..ae3da49b3 --- /dev/null +++ b/.changeset/rude-emus-happen.md @@ -0,0 +1,6 @@ +--- +"@onflow/fcl-ethereum-provider": patch +"@onflow/fcl-wc": patch +--- + +Update WalletConnect packages diff --git a/packages/fcl-ethereum-provider/package.json b/packages/fcl-ethereum-provider/package.json index 62f88e334..5149ad13b 100644 --- a/packages/fcl-ethereum-provider/package.json +++ b/packages/fcl-ethereum-provider/package.json @@ -42,12 +42,12 @@ "@noble/hashes": "^1.7.1", "@onflow/fcl-wc": "6.0.1", "@onflow/rlp": "^1.2.3", - "@walletconnect/ethereum-provider": "^2.18.0", + "@walletconnect/ethereum-provider": "^2.20.2", "@walletconnect/jsonrpc-http-connection": "^1.0.8", "@walletconnect/jsonrpc-provider": "^1.0.14", "@walletconnect/types": "^2.18.0", - "@walletconnect/universal-provider": "^2.18.0", - "@walletconnect/utils": "^2.18.0" + "@walletconnect/universal-provider": "^2.20.2", + "@walletconnect/utils": "^2.20.2" }, "peerDependencies": { "@onflow/fcl": "1.16.1" diff --git a/packages/fcl-rainbowkit-adapter/package.json b/packages/fcl-rainbowkit-adapter/package.json index ea3337f56..547d63706 100644 --- a/packages/fcl-rainbowkit-adapter/package.json +++ b/packages/fcl-rainbowkit-adapter/package.json @@ -44,8 +44,6 @@ "@onflow/fcl-wagmi-adapter": "0.0.3", "@onflow/rlp": "^1.2.3", "@wagmi/core": "^2.16.3", - "@walletconnect/jsonrpc-http-connection": "^1.0.8", - "@walletconnect/jsonrpc-provider": "^1.0.14", "mipd": "^0.0.7", "react": "17.x || 18.x || 19.x", "viem": "^2.22.21", diff --git a/packages/fcl-wagmi-adapter/package.json b/packages/fcl-wagmi-adapter/package.json index 8befaad42..0cb0f6726 100644 --- a/packages/fcl-wagmi-adapter/package.json +++ b/packages/fcl-wagmi-adapter/package.json @@ -41,12 +41,6 @@ "@ethersproject/hash": "^5.7.0", "@onflow/fcl-ethereum-provider": "0.0.3", "@onflow/rlp": "^1.2.3", - "@walletconnect/jsonrpc-http-connection": "^1.0.8", - "@walletconnect/jsonrpc-provider": "^1.0.14", - "@walletconnect/modal": "^2.7.0", - "@walletconnect/types": "^2.18.0", - "@walletconnect/universal-provider": "^2.18.0", - "@walletconnect/utils": "^2.18.0", "viem": "^2.22.21" }, "peerDependencies": { diff --git a/packages/fcl-wc/jest.config.js b/packages/fcl-wc/jest.config.js index 706d02824..b4aebd7fc 100644 --- a/packages/fcl-wc/jest.config.js +++ b/packages/fcl-wc/jest.config.js @@ -5,6 +5,7 @@ const config = { "/src/mocks/file-mock.ts", "\\.(css|less)$": "/src/mocks/file-mock.ts", }, + setupFilesAfterEnv: ["/jest.setup.ts"], } module.exports = config diff --git a/packages/fcl-wc/jest.setup.ts b/packages/fcl-wc/jest.setup.ts new file mode 100644 index 000000000..ab8f7954d --- /dev/null +++ b/packages/fcl-wc/jest.setup.ts @@ -0,0 +1,5 @@ +// Polyfill TextEncoder / TextDecoder for Jest +import {TextEncoder, TextDecoder} from "util" + +global.TextEncoder = TextEncoder +global.TextDecoder = TextDecoder as any diff --git a/packages/fcl-wc/package.json b/packages/fcl-wc/package.json index 90d552d1a..34f105ff7 100644 --- a/packages/fcl-wc/package.json +++ b/packages/fcl-wc/package.json @@ -43,13 +43,10 @@ "@onflow/config": "1.5.2", "@onflow/util-invariant": "1.2.4", "@onflow/util-logger": "1.3.3", - "@walletconnect/ethereum-provider": "^2.18.0", "@walletconnect/modal": "^2.7.0", - "@walletconnect/modal-core": "^2.6.2", - "@walletconnect/sign-client": "^2.17.1", - "@walletconnect/types": "^2.8.1", - "@walletconnect/universal-provider": "^2.18.0", - "@walletconnect/utils": "^2.8.1", + "@walletconnect/types": "^2.20.2", + "@walletconnect/universal-provider": "^2.20.2", + "@walletconnect/utils": "^2.20.2", "postcss-cli": "^11.0.0", "preact": "^10.24.3", "tailwindcss": "^3.4.14" diff --git a/packages/fcl-wc/src/fcl-wc.test.ts b/packages/fcl-wc/src/fcl-wc.test.ts index 68cc18d4d..cd9726e9d 100644 --- a/packages/fcl-wc/src/fcl-wc.test.ts +++ b/packages/fcl-wc/src/fcl-wc.test.ts @@ -2,7 +2,6 @@ import {init} from "./fcl-wc" import * as fcl from "@onflow/fcl" jest.mock("@walletconnect/modal", () => {}) -jest.mock("@walletconnect/sign-client", () => {}) jest.mock("@walletconnect/utils", () => {}) jest.mock("@onflow/fcl", () => { diff --git a/packages/fcl-wc/src/service.ts b/packages/fcl-wc/src/service.ts index 66cebd920..b3950a150 100644 --- a/packages/fcl-wc/src/service.ts +++ b/packages/fcl-wc/src/service.ts @@ -15,7 +15,6 @@ import {CurrentUser, Service} from "@onflow/typedefs" import {SessionTypes} from "@walletconnect/types" import {UniversalProvider} from "@walletconnect/universal-provider" import {createStore} from "./store" -import {ModalCtrlState} from "@walletconnect/modal-core/dist/_types/src/types/controllerTypes" type WalletConnectModalType = import("@walletconnect/modal").WalletConnectModal @@ -244,7 +243,7 @@ function connectWc( // Subscribe to modal state changes const unsubscribeModal = walletConnectModal.subscribeModal( - (state: ModalCtrlState) => { + (state: {open: boolean}) => { if (state.open === false) { onClose?.() unsubscribeModal() From 094ed6dd38cae9ae39183f5ead8d59f9276f8f5d Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Thu, 8 May 2025 01:11:22 +0000 Subject: [PATCH 28/72] Deprecate manual `appIdentifier` in favour of window origin (#2378) --- .changeset/violet-snakes-invite.md | 5 +++ packages/fcl-core/TRANSITIONS.md | 15 ++++++++- packages/fcl-core/src/current-user/index.js | 34 +++++++++++++++++---- 3 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 .changeset/violet-snakes-invite.md diff --git a/.changeset/violet-snakes-invite.md b/.changeset/violet-snakes-invite.md new file mode 100644 index 000000000..8079d494f --- /dev/null +++ b/.changeset/violet-snakes-invite.md @@ -0,0 +1,5 @@ +--- +"@onflow/fcl-core": minor +--- + +Deprecate manual appIdentifier in favour of window origin diff --git a/packages/fcl-core/TRANSITIONS.md b/packages/fcl-core/TRANSITIONS.md index d910163b7..2c462905b 100644 --- a/packages/fcl-core/TRANSITIONS.md +++ b/packages/fcl-core/TRANSITIONS.md @@ -14,4 +14,17 @@ FCL currently falls back to `env` for the `flow.network` field but this will be FCL now has a built-in utility to get which flow network to use. Manual specification in config is no longer required -FCL currently falls back to `flow.network` in case of failure but this will be removed in a future update. \ No newline at end of file +FCL currently falls back to `flow.network` in case of failure but this will be removed in a future update. + +## 0003 Deprecate `appIdentifier` field in account proof resolver + +- **Date:** May 7th 2025 +- **Type:** Deprecation of `appIdentifier` in account proof resolver + +The `appIdentifier` field in the account proof resolver is deprecated. The `appIdentifier` field is no longer required to be passed in the account proof resolver. The `appIdentifier` field will be removed in a future update. + +FCL will manually set the `appIdentifier` field to the origin of the current page. This is done to prevent phishing attacks and allow wallets to verify the origin of the request to restrict the domain of account proof requests to only those associated with the application's trusted [RFC 6454](https://www.rfc-editor.org/rfc/rfc6454.html) origin. + +Application developers migrating to this new configuration should update their backend systems accordingly to validate against trusted origins instead of the arbitrary `appIdentifier` field. + +The previous configuration will remain backward-compatible, however, it is strongly recommended that all application and wallet developers migrate to this new scheme as soon as possible to offer the best security to users. \ No newline at end of file diff --git a/packages/fcl-core/src/current-user/index.js b/packages/fcl-core/src/current-user/index.js index c740bdd15..91e8e4795 100644 --- a/packages/fcl-core/src/current-user/index.js +++ b/packages/fcl-core/src/current-user/index.js @@ -125,13 +125,35 @@ async function getAccountProofData() { return } - const accountProofData = await accountProofDataResolver() - if (accountProofData == null) return + const accountProofData = {...(await accountProofDataResolver())} + + const origin = window?.location?.origin + + if (accountProofData.appIdentifier) { + if (origin) { + log.deprecate({ + pkg: "FCL", + subject: "appIdentifier in fcl.accountProof.resolver", + message: + "Manually set app identifiers in the account proof resolver function are now deprecated. These are now automatically set to the application origin URL by FCL", + transition: + "https://github.com/onflow/flow-js-sdk/blob/master/packages/fcl/TRANSITIONS.md#0002-deprecate-appIdentifier-field-in-account-proof-resolver", + }) + + invariant( + typeof accountProofData.appIdentifier === "string", + "appIdentifier must be a string" + ) + } + } else { + invariant( + origin, + "The appIdentifier (origin) could not be inferred from the window.location.origin. Please set the appIdentifier manually in the fcl.accountProof.resolver function." + ) + + accountProofData.appIdentifier = origin + } - invariant( - typeof accountProofData.appIdentifier === "string", - "appIdentifier must be a string" - ) invariant( /^[0-9a-f]+$/i.test(accountProofData.nonce), "Nonce must be a hex string" From e10f1db63a8a9cc86a56e312d7d7e3a2089d4a3a Mon Sep 17 00:00:00 2001 From: Michael Fabozzi <39808567+mfbz@users.noreply.github.com> Date: Thu, 8 May 2025 13:10:21 +0200 Subject: [PATCH 29/72] Updated types to interfaces and comments cleanup (#2393) * Updated types to interfaces and comments cleanup * Added changeset --------- Co-authored-by: mfbz --- .changeset/neat-apricots-decide.md | 5 + packages/typedefs/src/index.ts | 196 ++++++++++++++--------------- 2 files changed, 103 insertions(+), 98 deletions(-) create mode 100644 .changeset/neat-apricots-decide.md diff --git a/.changeset/neat-apricots-decide.md b/.changeset/neat-apricots-decide.md new file mode 100644 index 000000000..1060428c7 --- /dev/null +++ b/.changeset/neat-apricots-decide.md @@ -0,0 +1,5 @@ +--- +"@onflow/typedefs": minor +--- + +Changed typedefs types to interfaces for code standardization diff --git a/packages/typedefs/src/index.ts b/packages/typedefs/src/index.ts index 41064969d..c88613d21 100644 --- a/packages/typedefs/src/index.ts +++ b/packages/typedefs/src/index.ts @@ -1,61 +1,61 @@ -export type Account = { +export interface Account { /** - * - The address of the account + * The address of the account */ address: string /** - * - The FLOW balance of the account in 10^8 + * The FLOW balance of the account in 10^8 */ balance: number /** - * - The code of any Cadence contracts stored in the account + * The code of any Cadence contracts stored in the account */ code: number /** - * - Any contracts deployed to this account + * Any contracts deployed to this account */ contracts: Record /** - * - The keys associated with the account + * The keys associated with the account */ keys: Array } -export type AccountKey = { +export interface AccountKey { /** - * - The index of the key in the account + * The index of the key in the account */ index: number /** - * - The public key of the account key + * The public key of the account key */ publicKey: string /** - * - The signature algorithm used by the key + * The signature algorithm used by the key */ signAlgo: SignatureAlgorithm /** - * - The signature algorithm used by the key as a string + * The signature algorithm used by the key as a string */ signAlgoString: string /** - * - The hashing algorithm used by the key + * The hashing algorithm used by the key */ hashAlgo: HashAlgorithm /** - * - The hashing algorithm used by the key as a string + * The hashing algorithm used by the key as a string */ hashAlgoString: string /** - * - The sequence number of the key + * The sequence number of the key */ sequenceNumber: number /** - * - The weight of the key + * The weight of the key */ weight: number /** - * - Whether or not the key has been revoked + * Whether or not the key has been revoked */ revoked: boolean } @@ -74,279 +74,279 @@ export enum HashAlgorithm { KMAC128_BLS_BLS12_381 = 5, } -export type Block = { +export interface Block { /** - * - The id of the block + * The id of the block */ id: string /** - * - The id of the parent block + * The id of the parent block */ parentId: string /** - * - The height of the block + * The height of the block */ height: number /** - * - Time related fields + * Time related fields */ timestamp: string /** - * - Contains the ids of collections included in the block + * Contains the ids of collections included in the block */ collectionGuarantees: Array /** - * - The details of which nodes executed and sealed the blocks + * The details of which nodes executed and sealed the blocks */ blockSeals: Array /** - * - The cryptographic signature of the block + * The cryptographic signature of the block */ signatures: Array } -export type CollectionGuarantee = { +export interface CollectionGuarantee { /** - * - The id of the block + * The id of the block */ collectionId: string /** - * - The signer ids of the block + * The signer ids of the block */ signerIds: Array } -export type BlockSeal = { +export interface BlockSeal { /** - * - The id of the block + * The id of the block */ blockId: string /** - * - The execution receipt id of the block + * The execution receipt id of the block */ executionReceiptId: string } -export type CompositeSignature = { +export interface CompositeSignature { /** - * - A type identifier used internally by FCL + * A type identifier used internally by FCL */ f_type: string /** - * - FCL protocol version + * FCL protocol version */ f_vsn: string /** - * - Flow Address (sans prefix) + * Flow Address (sans prefix) */ addr: string /** - * - Key ID + * Key ID */ keyId: number /** - * - Signature as a hex string + * Signature as a hex string */ signature: string } -export type CurrentUser = { +export interface CurrentUser { /** - * - The public address of the current user + * The public address of the current user */ addr?: string /** - * - A wallet specified content identifier for user metadata + * A wallet specified content identifier for user metadata */ cid?: string /** - * - A wallet specified time-frame for a valid session + * A wallet specified time-frame for a valid session */ expiresAt?: number /** - * - A type identifier used internally by FCL + * A type identifier used internally by FCL */ f_type: string /** - * - FCL protocol version + * FCL protocol version */ f_vsn: string /** - * - Whether or not the current user is logged in + * Whether or not the current user is logged in */ loggedIn?: boolean /** - * - A list of trusted services that express ways of interacting with the current user's identity + * A list of trusted services that express ways of interacting with the current user's identity */ services: Array } -export type Event = { +export interface Event { /** - * - ID of the block that contains the event. + * ID of the block that contains the event. */ blockId: string /** - * - Height of the block that contains the event. + * Height of the block that contains the event. */ blockHeight: number /** - * - The timestamp of when the block was sealed in a DateString format. eg. '2021-06-25T13:42:04.227Z' + * The timestamp of when the block was sealed in a DateString format. eg. '2021-06-25T13:42:04.227Z' */ blockTimestamp: string /** - * - A string containing the event name. + * A string containing the event name. */ type: string /** - * - Can be used to query transaction information, eg. via a Flow block explorer. + * Can be used to query transaction information, eg. via a Flow block explorer. */ transactionId: string /** - * - Used to prevent replay attacks. + * Used to prevent replay attacks. */ transactionIndex: number /** - * - Used to prevent replay attacks. + * Used to prevent replay attacks. */ eventIndex: number /** - * - The data emitted from the event. + * The data emitted from the event. */ data: any } -export type Key = { +export interface Key { /** - * - Sequence number of key used by the proposer of this transaction + * Sequence number of key used by the proposer of this transaction */ sequenceNumber: number /** - * - The ID of the key in the account used by the proposer of this transaction + * The ID of the key in the account used by the proposer of this transaction */ keyId: number /** - * - The address of the proposer of this transaction + * The address of the proposer of this transaction */ address: string } -export type Service = { +export interface Service { /** - * - A type identifier used internally by FCL + * A type identifier used internally by FCL */ f_type: string /** - * - FCL protocol version + * FCL protocol version */ f_vsn: string /** - * - Service type + * Service type */ type: string /** - * - Service method + * Service method */ method: string /** - * - Service uid + * Service uid */ uid?: string /** - * - Service endpoint + * Service endpoint */ endpoint: string /** - * - Service provider object + * Service provider object */ provider: Provider params: Record } -export type Signature = { +export interface Signature { /** - * - Sequence number of the key used to perform this signature. + * Sequence number of the key used to perform this signature. */ sequenceNumber: string /** - * - ID of the key in the account used to perform this signature. + * ID of the key in the account used to perform this signature. */ keyId: number /** - * - The signature represented as a hex string. + * The signature represented as a hex string. */ signature: string } -export type Transaction = { +export interface Transaction { /** - * - The Cadence code used to execute this transaction. + * The Cadence code used to execute this transaction. */ script: string /** - * - The JSON-CDC encoded arguments passed in to the transaction. + * The JSON-CDC encoded arguments passed in to the transaction. */ args: Array /** - * - The reference block id for this transaction. + * The reference block id for this transaction. */ referenceBlockId: string /** - * - The gas limit for the transaction. + * The gas limit for the transaction. */ gasLimit: number /** - * - The key used by the proposer of this transaction. + * The key used by the proposer of this transaction. */ proposalKey: Key /** - * - Sequence number of the key used by the proposer of this transaction. + * Sequence number of the key used by the proposer of this transaction. */ sequenceNumber: string /** - * - The ID of the key in the account used by the proposer of this transaction. + * The ID of the key in the account used by the proposer of this transaction. */ keyId: number /** - * - The address of the proposer of this transaction. + * The address of the proposer of this transaction. */ address: string /** - * - Address of the payer of the transaction. + * Address of the payer of the transaction. */ payer: string /** - * - Address of the proposer of this transaction. + * Address of the proposer of this transaction. */ proposer: string /** - * - Array of addresses of authorizers of this transaction. + * Array of addresses of authorizers of this transaction. */ authorizers: Array /** - * - The payload signatures for the transaction. + * The payload signatures for the transaction. */ payloadSignatures: Array /** - * - The envelope signatures for the transaction. + * The envelope signatures for the transaction. */ envelopeSignatures: Array } -export type TransactionStatus = { +export interface TransactionStatus { /** - * - The ID of the Block the transaction is included in. + * The ID of the Block the transaction is included in. */ blockId: string /** - * - The execution status of the transaction + * The execution status of the transaction */ status: TransactionExecutionStatus /** - * - The status as as descriptive text (e.g. "FINALIZED"). + * The status as as descriptive text (e.g. "FINALIZED"). */ statusString: string /** - * - The result of the transaction, if executed (i.e. 0 for success, 1 for failure) + * The result of the transaction, if executed (i.e. 0 for success, 1 for failure) */ statusCode: 0 | 1 /** - * - The error message of the transaction. + * The error message of the transaction. */ errorMessage: string /** - * - The events for this result. + * The events for this result. */ events: Array } @@ -364,7 +364,7 @@ export enum TransactionExecutionStatus { /* * The Provider type describes a Wallet Provider associated with a specific Service. */ -export type Provider = { +export interface Provider { /** * The blockchain address of the Wallet provider. */ @@ -398,29 +398,29 @@ export type Provider = { */ is_installed?: boolean } -export type NodeVersionInfo = { +export interface NodeVersionInfo { /** - * - The semver version of the node. + * The semver version of the node. */ semver: string /** - * - The commit hash of the node. + * The commit hash of the node. */ commit: string /** - * - The spork id of the node. + * The spork id of the node. */ sporkId: string /** - * - The protocol version of the node. + * The protocol version of the node. */ protocolVersion: number /** - * - The spork root block height of the node. + * The spork root block height of the node. */ sporkRootBlockHeight: number /** - * - The node root block height of the node. + * The node root block height of the node. */ nodeRootBlockHeight: number } From 12d0d4f5ea8726e8419b0a8aebeb4a48803ff781 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 8 May 2025 09:54:21 -0700 Subject: [PATCH 30/72] Version Packages (#2371) --- .changeset/few-eagles-explode.md | 6 ------ .changeset/neat-apricots-decide.md | 5 ----- .changeset/rude-emus-happen.md | 6 ------ .changeset/ten-pumas-serve.md | 5 ----- .changeset/tiny-buses-wash.md | 7 ------- .changeset/violet-snakes-invite.md | 5 ----- packages/fcl-core/CHANGELOG.md | 13 +++++++++++++ packages/fcl-core/package.json | 6 +++--- packages/fcl-ethereum-provider/CHANGELOG.md | 10 ++++++++++ packages/fcl-ethereum-provider/package.json | 8 ++++---- packages/fcl-rainbowkit-adapter/CHANGELOG.md | 13 +++++++++++++ packages/fcl-rainbowkit-adapter/package.json | 10 +++++----- packages/fcl-react-native/CHANGELOG.md | 12 ++++++++++++ packages/fcl-react-native/package.json | 8 ++++---- packages/fcl-wagmi-adapter/CHANGELOG.md | 10 ++++++++++ packages/fcl-wagmi-adapter/package.json | 8 ++++---- packages/fcl-wc/CHANGELOG.md | 11 +++++++++++ packages/fcl-wc/package.json | 6 +++--- packages/fcl/CHANGELOG.md | 13 +++++++++++++ packages/fcl/package.json | 10 +++++----- packages/kit/CHANGELOG.md | 11 +++++++++++ packages/kit/package.json | 6 +++--- packages/sdk/CHANGELOG.md | 7 +++++++ packages/sdk/package.json | 4 ++-- packages/transport-grpc/package.json | 2 +- packages/transport-http/package.json | 2 +- packages/typedefs/CHANGELOG.md | 6 ++++++ packages/typedefs/package.json | 2 +- 28 files changed, 142 insertions(+), 70 deletions(-) delete mode 100644 .changeset/few-eagles-explode.md delete mode 100644 .changeset/neat-apricots-decide.md delete mode 100644 .changeset/rude-emus-happen.md delete mode 100644 .changeset/ten-pumas-serve.md delete mode 100644 .changeset/tiny-buses-wash.md delete mode 100644 .changeset/violet-snakes-invite.md diff --git a/.changeset/few-eagles-explode.md b/.changeset/few-eagles-explode.md deleted file mode 100644 index e910411df..000000000 --- a/.changeset/few-eagles-explode.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@onflow/fcl-wc": patch -"@onflow/fcl-wagmi-adapter": patch ---- - -Remove unused WalletConnect dependencies diff --git a/.changeset/neat-apricots-decide.md b/.changeset/neat-apricots-decide.md deleted file mode 100644 index 1060428c7..000000000 --- a/.changeset/neat-apricots-decide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/typedefs": minor ---- - -Changed typedefs types to interfaces for code standardization diff --git a/.changeset/rude-emus-happen.md b/.changeset/rude-emus-happen.md deleted file mode 100644 index ae3da49b3..000000000 --- a/.changeset/rude-emus-happen.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@onflow/fcl-ethereum-provider": patch -"@onflow/fcl-wc": patch ---- - -Update WalletConnect packages diff --git a/.changeset/ten-pumas-serve.md b/.changeset/ten-pumas-serve.md deleted file mode 100644 index 5e108aa59..000000000 --- a/.changeset/ten-pumas-serve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/fcl-rainbowkit-adapter": minor ---- - -Add `useIsCadenceWalletConnected` hook diff --git a/.changeset/tiny-buses-wash.md b/.changeset/tiny-buses-wash.md deleted file mode 100644 index dd8eca851..000000000 --- a/.changeset/tiny-buses-wash.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@onflow/fcl-core": minor -"@onflow/fcl": minor -"@onflow/fcl-react-native": minor ---- - -Include origin information in `onMessageFromFcl` function diff --git a/.changeset/violet-snakes-invite.md b/.changeset/violet-snakes-invite.md deleted file mode 100644 index 8079d494f..000000000 --- a/.changeset/violet-snakes-invite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/fcl-core": minor ---- - -Deprecate manual appIdentifier in favour of window origin diff --git a/packages/fcl-core/CHANGELOG.md b/packages/fcl-core/CHANGELOG.md index 267948675..2a05b6164 100644 --- a/packages/fcl-core/CHANGELOG.md +++ b/packages/fcl-core/CHANGELOG.md @@ -1,5 +1,18 @@ # @onflow/fcl +## 1.18.0 + +### Minor Changes + +- [#2384](https://github.com/onflow/fcl-js/pull/2384) [`f86b71357696826a5ad7b8e578de76ecebcd2e29`](https://github.com/onflow/fcl-js/commit/f86b71357696826a5ad7b8e578de76ecebcd2e29) Thanks [@jribbink](https://github.com/jribbink)! - Include origin information in `onMessageFromFcl` function + +- [#2378](https://github.com/onflow/fcl-js/pull/2378) [`094ed6dd38cae9ae39183f5ead8d59f9276f8f5d`](https://github.com/onflow/fcl-js/commit/094ed6dd38cae9ae39183f5ead8d59f9276f8f5d) Thanks [@jribbink](https://github.com/jribbink)! - Deprecate manual appIdentifier in favour of window origin + +### Patch Changes + +- Updated dependencies []: + - @onflow/sdk@1.8.1 + ## 1.17.0 ### Minor Changes diff --git a/packages/fcl-core/package.json b/packages/fcl-core/package.json index 008111c92..b26b2d2bb 100644 --- a/packages/fcl-core/package.json +++ b/packages/fcl-core/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-core", - "version": "1.17.0", + "version": "1.18.0", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", @@ -20,7 +20,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.4.1", + "@onflow/typedefs": "1.5.0", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -52,7 +52,7 @@ "@onflow/config": "1.5.2", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.0", + "@onflow/sdk": "1.8.1", "@onflow/transport-http": "1.12.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", diff --git a/packages/fcl-ethereum-provider/CHANGELOG.md b/packages/fcl-ethereum-provider/CHANGELOG.md index 303403efe..ca9312bdd 100644 --- a/packages/fcl-ethereum-provider/CHANGELOG.md +++ b/packages/fcl-ethereum-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @onflow/fcl-ethereum-provider +## 0.0.4 + +### Patch Changes + +- [#2382](https://github.com/onflow/fcl-js/pull/2382) [`0feeae00d1ef089df36b381109802bb0b14bf89b`](https://github.com/onflow/fcl-js/commit/0feeae00d1ef089df36b381109802bb0b14bf89b) Thanks [@jribbink](https://github.com/jribbink)! - Update WalletConnect packages + +- Updated dependencies [[`0feeae00d1ef089df36b381109802bb0b14bf89b`](https://github.com/onflow/fcl-js/commit/0feeae00d1ef089df36b381109802bb0b14bf89b), [`0feeae00d1ef089df36b381109802bb0b14bf89b`](https://github.com/onflow/fcl-js/commit/0feeae00d1ef089df36b381109802bb0b14bf89b), [`f86b71357696826a5ad7b8e578de76ecebcd2e29`](https://github.com/onflow/fcl-js/commit/f86b71357696826a5ad7b8e578de76ecebcd2e29)]: + - @onflow/fcl-wc@6.0.2 + - @onflow/fcl@1.17.0 + ## 0.0.3 ### Patch Changes diff --git a/packages/fcl-ethereum-provider/package.json b/packages/fcl-ethereum-provider/package.json index 5149ad13b..f23fd8f19 100644 --- a/packages/fcl-ethereum-provider/package.json +++ b/packages/fcl-ethereum-provider/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-ethereum-provider", - "version": "0.0.3", + "version": "0.0.4", "description": "Ethereum provider for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -15,7 +15,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.4.0", + "@onflow/typedefs": "^1.5.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -40,7 +40,7 @@ "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", "@noble/hashes": "^1.7.1", - "@onflow/fcl-wc": "6.0.1", + "@onflow/fcl-wc": "6.0.2", "@onflow/rlp": "^1.2.3", "@walletconnect/ethereum-provider": "^2.20.2", "@walletconnect/jsonrpc-http-connection": "^1.0.8", @@ -50,6 +50,6 @@ "@walletconnect/utils": "^2.20.2" }, "peerDependencies": { - "@onflow/fcl": "1.16.1" + "@onflow/fcl": "1.17.0" } } diff --git a/packages/fcl-rainbowkit-adapter/CHANGELOG.md b/packages/fcl-rainbowkit-adapter/CHANGELOG.md index 2a73a80d2..1eb8aedb0 100644 --- a/packages/fcl-rainbowkit-adapter/CHANGELOG.md +++ b/packages/fcl-rainbowkit-adapter/CHANGELOG.md @@ -1,5 +1,18 @@ # @onflow/fcl-rainbowkit-adapter +## 0.2.0 + +### Minor Changes + +- [#2326](https://github.com/onflow/fcl-js/pull/2326) [`2446dbee70b25780e31cf8d0b45db7acac6281d6`](https://github.com/onflow/fcl-js/commit/2446dbee70b25780e31cf8d0b45db7acac6281d6) Thanks [@jribbink](https://github.com/jribbink)! - Add `useIsCadenceWalletConnected` hook + +### Patch Changes + +- Updated dependencies [[`0feeae00d1ef089df36b381109802bb0b14bf89b`](https://github.com/onflow/fcl-js/commit/0feeae00d1ef089df36b381109802bb0b14bf89b), [`0feeae00d1ef089df36b381109802bb0b14bf89b`](https://github.com/onflow/fcl-js/commit/0feeae00d1ef089df36b381109802bb0b14bf89b), [`f86b71357696826a5ad7b8e578de76ecebcd2e29`](https://github.com/onflow/fcl-js/commit/f86b71357696826a5ad7b8e578de76ecebcd2e29)]: + - @onflow/fcl-wagmi-adapter@0.0.4 + - @onflow/fcl-ethereum-provider@0.0.4 + - @onflow/fcl@1.17.0 + ## 0.1.0 ### Minor Changes diff --git a/packages/fcl-rainbowkit-adapter/package.json b/packages/fcl-rainbowkit-adapter/package.json index 547d63706..9be86d943 100644 --- a/packages/fcl-rainbowkit-adapter/package.json +++ b/packages/fcl-rainbowkit-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-rainbowkit-adapter", - "version": "0.1.0", + "version": "0.2.0", "description": "Rainbowkit adapter for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -15,7 +15,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.4.0", + "@onflow/typedefs": "^1.5.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -40,8 +40,8 @@ "@babel/runtime": "^7.25.7", "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", - "@onflow/fcl-ethereum-provider": "0.0.3", - "@onflow/fcl-wagmi-adapter": "0.0.3", + "@onflow/fcl-ethereum-provider": "0.0.4", + "@onflow/fcl-wagmi-adapter": "0.0.4", "@onflow/rlp": "^1.2.3", "@wagmi/core": "^2.16.3", "mipd": "^0.0.7", @@ -50,7 +50,7 @@ "wagmi": "^2.14.11" }, "peerDependencies": { - "@onflow/fcl": "1.16.1", + "@onflow/fcl": "1.17.0", "@rainbow-me/rainbowkit": "^2.2.3", "react": "17.x || 18.x || 19.x" } diff --git a/packages/fcl-react-native/CHANGELOG.md b/packages/fcl-react-native/CHANGELOG.md index 54edd3b0a..561a0f354 100644 --- a/packages/fcl-react-native/CHANGELOG.md +++ b/packages/fcl-react-native/CHANGELOG.md @@ -1,5 +1,17 @@ # @onflow/fcl-react-native +## 1.11.0 + +### Minor Changes + +- [#2384](https://github.com/onflow/fcl-js/pull/2384) [`f86b71357696826a5ad7b8e578de76ecebcd2e29`](https://github.com/onflow/fcl-js/commit/f86b71357696826a5ad7b8e578de76ecebcd2e29) Thanks [@jribbink](https://github.com/jribbink)! - Include origin information in `onMessageFromFcl` function + +### Patch Changes + +- Updated dependencies [[`f86b71357696826a5ad7b8e578de76ecebcd2e29`](https://github.com/onflow/fcl-js/commit/f86b71357696826a5ad7b8e578de76ecebcd2e29), [`094ed6dd38cae9ae39183f5ead8d59f9276f8f5d`](https://github.com/onflow/fcl-js/commit/094ed6dd38cae9ae39183f5ead8d59f9276f8f5d)]: + - @onflow/fcl-core@1.18.0 + - @onflow/sdk@1.8.1 + ## 1.10.1 ### Patch Changes diff --git a/packages/fcl-react-native/package.json b/packages/fcl-react-native/package.json index ffdd9e2c9..42aefd1ac 100644 --- a/packages/fcl-react-native/package.json +++ b/packages/fcl-react-native/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-react-native", - "version": "1.10.1", + "version": "1.11.0", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", @@ -20,7 +20,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.4.1", + "@onflow/typedefs": "1.5.0", "@types/estree": "^1.0.6", "@types/node": "^18.19.57", "eslint": "^8.57.1", @@ -48,10 +48,10 @@ "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.17.0", + "@onflow/fcl-core": "1.18.0", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.0", + "@onflow/sdk": "1.8.1", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", diff --git a/packages/fcl-wagmi-adapter/CHANGELOG.md b/packages/fcl-wagmi-adapter/CHANGELOG.md index 1928e73b0..b125e9ff0 100644 --- a/packages/fcl-wagmi-adapter/CHANGELOG.md +++ b/packages/fcl-wagmi-adapter/CHANGELOG.md @@ -1,5 +1,15 @@ # @onflow/fcl-wagmi-adapter +## 0.0.4 + +### Patch Changes + +- [#2382](https://github.com/onflow/fcl-js/pull/2382) [`0feeae00d1ef089df36b381109802bb0b14bf89b`](https://github.com/onflow/fcl-js/commit/0feeae00d1ef089df36b381109802bb0b14bf89b) Thanks [@jribbink](https://github.com/jribbink)! - Remove unused WalletConnect dependencies + +- Updated dependencies [[`0feeae00d1ef089df36b381109802bb0b14bf89b`](https://github.com/onflow/fcl-js/commit/0feeae00d1ef089df36b381109802bb0b14bf89b), [`f86b71357696826a5ad7b8e578de76ecebcd2e29`](https://github.com/onflow/fcl-js/commit/f86b71357696826a5ad7b8e578de76ecebcd2e29)]: + - @onflow/fcl-ethereum-provider@0.0.4 + - @onflow/fcl@1.17.0 + ## 0.0.3 ### Patch Changes diff --git a/packages/fcl-wagmi-adapter/package.json b/packages/fcl-wagmi-adapter/package.json index 0cb0f6726..552f8e736 100644 --- a/packages/fcl-wagmi-adapter/package.json +++ b/packages/fcl-wagmi-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-wagmi-adapter", - "version": "0.0.3", + "version": "0.0.4", "description": "Wagmi adapter for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -15,7 +15,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.4.0", + "@onflow/typedefs": "^1.5.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -39,12 +39,12 @@ "@babel/runtime": "^7.25.7", "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", - "@onflow/fcl-ethereum-provider": "0.0.3", + "@onflow/fcl-ethereum-provider": "0.0.4", "@onflow/rlp": "^1.2.3", "viem": "^2.22.21" }, "peerDependencies": { - "@onflow/fcl": "1.16.1", + "@onflow/fcl": "1.17.0", "@wagmi/core": "^2.16.3" } } diff --git a/packages/fcl-wc/CHANGELOG.md b/packages/fcl-wc/CHANGELOG.md index d51f38f94..ba2011daf 100644 --- a/packages/fcl-wc/CHANGELOG.md +++ b/packages/fcl-wc/CHANGELOG.md @@ -1,5 +1,16 @@ # @onflow/fcl-wc +## 6.0.2 + +### Patch Changes + +- [#2382](https://github.com/onflow/fcl-js/pull/2382) [`0feeae00d1ef089df36b381109802bb0b14bf89b`](https://github.com/onflow/fcl-js/commit/0feeae00d1ef089df36b381109802bb0b14bf89b) Thanks [@jribbink](https://github.com/jribbink)! - Remove unused WalletConnect dependencies + +- [#2382](https://github.com/onflow/fcl-js/pull/2382) [`0feeae00d1ef089df36b381109802bb0b14bf89b`](https://github.com/onflow/fcl-js/commit/0feeae00d1ef089df36b381109802bb0b14bf89b) Thanks [@jribbink](https://github.com/jribbink)! - Update WalletConnect packages + +- Updated dependencies [[`f86b71357696826a5ad7b8e578de76ecebcd2e29`](https://github.com/onflow/fcl-js/commit/f86b71357696826a5ad7b8e578de76ecebcd2e29), [`094ed6dd38cae9ae39183f5ead8d59f9276f8f5d`](https://github.com/onflow/fcl-js/commit/094ed6dd38cae9ae39183f5ead8d59f9276f8f5d)]: + - @onflow/fcl-core@1.18.0 + ## 6.0.1 ### Patch Changes diff --git a/packages/fcl-wc/package.json b/packages/fcl-wc/package.json index 34f105ff7..ed6fb9832 100644 --- a/packages/fcl-wc/package.json +++ b/packages/fcl-wc/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-wc", - "version": "6.0.1", + "version": "6.0.2", "description": "WalletConnect adapter for FCL", "license": "Apache-2.0", "author": "Flow Foundation", @@ -31,7 +31,7 @@ "@babel/plugin-transform-react-jsx": "^7.25.9", "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.4.1", + "@onflow/typedefs": "1.5.0", "autoprefixer": "^10.4.20", "eslint": "^8.57.1", "eslint-plugin-jsdoc": "^46.10.1", @@ -52,6 +52,6 @@ "tailwindcss": "^3.4.14" }, "peerDependencies": { - "@onflow/fcl-core": "1.17.0" + "@onflow/fcl-core": "1.18.0" } } diff --git a/packages/fcl/CHANGELOG.md b/packages/fcl/CHANGELOG.md index db4df55f3..c32b860f6 100644 --- a/packages/fcl/CHANGELOG.md +++ b/packages/fcl/CHANGELOG.md @@ -1,5 +1,18 @@ # @onflow/fcl +## 1.17.0 + +### Minor Changes + +- [#2384](https://github.com/onflow/fcl-js/pull/2384) [`f86b71357696826a5ad7b8e578de76ecebcd2e29`](https://github.com/onflow/fcl-js/commit/f86b71357696826a5ad7b8e578de76ecebcd2e29) Thanks [@jribbink](https://github.com/jribbink)! - Include origin information in `onMessageFromFcl` function + +### Patch Changes + +- Updated dependencies [[`0feeae00d1ef089df36b381109802bb0b14bf89b`](https://github.com/onflow/fcl-js/commit/0feeae00d1ef089df36b381109802bb0b14bf89b), [`0feeae00d1ef089df36b381109802bb0b14bf89b`](https://github.com/onflow/fcl-js/commit/0feeae00d1ef089df36b381109802bb0b14bf89b), [`f86b71357696826a5ad7b8e578de76ecebcd2e29`](https://github.com/onflow/fcl-js/commit/f86b71357696826a5ad7b8e578de76ecebcd2e29), [`094ed6dd38cae9ae39183f5ead8d59f9276f8f5d`](https://github.com/onflow/fcl-js/commit/094ed6dd38cae9ae39183f5ead8d59f9276f8f5d)]: + - @onflow/fcl-wc@6.0.2 + - @onflow/fcl-core@1.18.0 + - @onflow/sdk@1.8.1 + ## 1.16.1 ### Patch Changes diff --git a/packages/fcl/package.json b/packages/fcl/package.json index 21172beac..d0ec3d507 100644 --- a/packages/fcl/package.json +++ b/packages/fcl/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl", - "version": "1.16.1", + "version": "1.17.0", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", @@ -20,7 +20,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.4.1", + "@onflow/typedefs": "1.5.0", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -49,11 +49,11 @@ "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.17.0", - "@onflow/fcl-wc": "6.0.1", + "@onflow/fcl-core": "1.18.0", + "@onflow/fcl-wc": "6.0.2", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.0", + "@onflow/sdk": "1.8.1", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", diff --git a/packages/kit/CHANGELOG.md b/packages/kit/CHANGELOG.md index 6a5006293..8663147de 100644 --- a/packages/kit/CHANGELOG.md +++ b/packages/kit/CHANGELOG.md @@ -1,5 +1,16 @@ # @onflow/kit +## 0.1.0 + +### Minor Changes + +- [#2384](https://github.com/onflow/fcl-js/pull/2365) [`24e2a5c160531b6973a4137e569ce127a9e7e590`](https://github.com/onflow/fcl-js/commit/24e2a5c160531b6973a4137e569ce127a9e7e590) Thanks [@chasefleming](https://github.com/chasefleming)! - Add `useFlowRevertibleRandom` hook + +### Patch Changes + +- Updated dependencies [[`f86b71357696826a5ad7b8e578de76ecebcd2e29`](https://github.com/onflow/fcl-js/commit/f86b71357696826a5ad7b8e578de76ecebcd2e29)]: + - @onflow/fcl@1.17.0 + ## 0.0.2 ### Patch Changes diff --git a/packages/kit/package.json b/packages/kit/package.json index ec7d8bf55..c2e06c84c 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/kit", - "version": "0.0.2", + "version": "0.1.0", "description": "React library for interacting with the Flow blockchain", "license": "Apache-2.0", "author": "Flow Foundation", @@ -30,7 +30,7 @@ "@babel/preset-react": "^7.26.3", "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.4.0", + "@onflow/typedefs": "^1.5.0", "@testing-library/dom": "^10.4.0", "@types/jest": "^29.5.13", "@types/react": "^19.0.10", @@ -48,7 +48,7 @@ "@testing-library/react": "^16.2.0" }, "peerDependencies": { - "@onflow/fcl": ">=1.16.0", + "@onflow/fcl": ">=1.17.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index 61fbafde4..cbe9d0a4d 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -1,5 +1,12 @@ # @onflow/sdk +## 1.8.1 + +### Patch Changes + +- Updated dependencies [[`e10f1db63a8a9cc86a56e312d7d7e3a2089d4a3a`](https://github.com/onflow/fcl-js/commit/e10f1db63a8a9cc86a56e312d7d7e3a2089d4a3a)]: + - @onflow/typedefs@1.5.0 + ## 1.8.0 ### Minor Changes diff --git a/packages/sdk/package.json b/packages/sdk/package.json index a27c0994c..f4997dca4 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/sdk", - "version": "1.8.0", + "version": "1.8.1", "description": "Flow SDK", "license": "Apache-2.0", "author": "Flow Foundation", @@ -44,7 +44,7 @@ "@onflow/config": "1.5.2", "@onflow/rlp": "1.2.3", "@onflow/transport-http": "1.12.0", - "@onflow/typedefs": "1.4.1", + "@onflow/typedefs": "1.5.0", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", "@onflow/util-invariant": "1.2.4", diff --git a/packages/transport-grpc/package.json b/packages/transport-grpc/package.json index ff77809d6..ade4e838b 100644 --- a/packages/transport-grpc/package.json +++ b/packages/transport-grpc/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/sdk": "1.8.0", + "@onflow/sdk": "1.8.1", "jest": "^29.7.0" }, "source": "src/sdk-send-grpc.js", diff --git a/packages/transport-http/package.json b/packages/transport-http/package.json index 5269c371b..c71605aa9 100644 --- a/packages/transport-http/package.json +++ b/packages/transport-http/package.json @@ -15,7 +15,7 @@ "devDependencies": { "@onflow/fcl-bundle": "1.7.0", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.0", + "@onflow/sdk": "1.8.1", "@onflow/types": "1.4.1", "jest": "^29.7.0" }, diff --git a/packages/typedefs/CHANGELOG.md b/packages/typedefs/CHANGELOG.md index 2b5a161ad..1550bcadf 100644 --- a/packages/typedefs/CHANGELOG.md +++ b/packages/typedefs/CHANGELOG.md @@ -1,5 +1,11 @@ # @onflow/typedefs +## 1.5.0 + +### Minor Changes + +- [#2393](https://github.com/onflow/fcl-js/pull/2393) [`e10f1db63a8a9cc86a56e312d7d7e3a2089d4a3a`](https://github.com/onflow/fcl-js/commit/e10f1db63a8a9cc86a56e312d7d7e3a2089d4a3a) Thanks [@mfbz](https://github.com/mfbz)! - Changed typedefs types to interfaces for code standardization + ## 1.4.1 ### Patch Changes diff --git a/packages/typedefs/package.json b/packages/typedefs/package.json index d74f1049e..c9b8037f9 100644 --- a/packages/typedefs/package.json +++ b/packages/typedefs/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/typedefs", - "version": "1.4.1", + "version": "1.5.0", "description": "Flow JS Type Defs", "license": "Apache-2.0", "author": "Flow Foundation", From 9595af75eeffb0c91f9bb94b70fb0adf4db40eec Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Thu, 8 May 2025 20:29:24 +0000 Subject: [PATCH 31/72] Add `useFlowChainId` hook (#2367) --- .changeset/odd-seals-glow.md | 5 + packages/kit/src/__mocks__/fcl.ts | 1 + packages/kit/src/hooks/useFlowChainId.test.ts | 109 ++++++++++++++++++ packages/kit/src/hooks/useFlowChainId.ts | 32 +++++ 4 files changed, 147 insertions(+) create mode 100644 .changeset/odd-seals-glow.md create mode 100644 packages/kit/src/hooks/useFlowChainId.test.ts create mode 100644 packages/kit/src/hooks/useFlowChainId.ts diff --git a/.changeset/odd-seals-glow.md b/.changeset/odd-seals-glow.md new file mode 100644 index 000000000..9031d447c --- /dev/null +++ b/.changeset/odd-seals-glow.md @@ -0,0 +1,5 @@ +--- +"@onflow/kit": minor +--- + +Add `useFlowChainId` hook to the `@onflow/kit` package. diff --git a/packages/kit/src/__mocks__/fcl.ts b/packages/kit/src/__mocks__/fcl.ts index 98d580fa9..430746ed1 100644 --- a/packages/kit/src/__mocks__/fcl.ts +++ b/packages/kit/src/__mocks__/fcl.ts @@ -38,6 +38,7 @@ export default { unauthenticate: jest.fn().mockImplementation(() => { currentUserState = defaultUser }), + getChainId: jest.fn().mockResolvedValue("mainnet"), TransactionError: { fromErrorMessage: (errorMessage: string) => { diff --git a/packages/kit/src/hooks/useFlowChainId.test.ts b/packages/kit/src/hooks/useFlowChainId.test.ts new file mode 100644 index 000000000..244629c70 --- /dev/null +++ b/packages/kit/src/hooks/useFlowChainId.test.ts @@ -0,0 +1,109 @@ +import {renderHook, act, waitFor} from "@testing-library/react" +import * as fcl from "@onflow/fcl" +import {FlowProvider} from "../provider" +import {useFlowChainId} from "./useFlowChainId" + +jest.mock("@onflow/fcl", () => require("../__mocks__/fcl").default) + +describe("useFlowChainId", () => { + const mockChainId = "mainnet" + + afterEach(() => { + jest.clearAllMocks() + }) + + test("fetches the chain ID successfully", async () => { + const getChainIdMock = jest.mocked(fcl.getChainId) + getChainIdMock.mockResolvedValueOnce(mockChainId) + + let hookResult: any + + await act(async () => { + const {result} = renderHook(() => useFlowChainId(), { + wrapper: FlowProvider, + }) + hookResult = result + }) + + expect(hookResult.current.data).toBeNull() + + // Wait for the hook to finish loading + await waitFor(() => expect(hookResult.current.isLoading).toBe(false)) + + // After update, the data should be available + expect(hookResult.current.data).toEqual(mockChainId) + expect(hookResult.current.error).toBeNull() + expect(getChainIdMock).toHaveBeenCalledTimes(1) + }) + + test("handles error when fetching chain ID fails", async () => { + const testError = new Error("Failed to fetch chain ID") + const getChainIdMock = jest.mocked(fcl.getChainId) + getChainIdMock.mockRejectedValueOnce(testError) + + let hookResult: any + + await act(async () => { + const {result} = renderHook(() => useFlowChainId(), { + wrapper: FlowProvider, + }) + hookResult = result + }) + + await waitFor(() => expect(hookResult.current.isLoading).toBe(false)) + + expect(hookResult.current.data).toBeNull() + expect(hookResult.current.error).toEqual(testError) + expect(getChainIdMock).toHaveBeenCalledTimes(1) + }) + + test("refetch function works correctly", async () => { + const getChainIdMock = jest.mocked(fcl.getChainId) + getChainIdMock.mockResolvedValueOnce(mockChainId) + + let hookResult: any + + await act(async () => { + const {result} = renderHook(() => useFlowChainId(), { + wrapper: FlowProvider, + }) + hookResult = result + }) + + await waitFor(() => expect(hookResult.current.data).toEqual(mockChainId)) + + const newChainId = "testnet" + getChainIdMock.mockResolvedValueOnce(newChainId) + + act(() => { + hookResult.current.refetch() + }) + + await waitFor(() => expect(hookResult.current.data).toEqual(newChainId)) + + expect(fcl.getChainId).toHaveBeenCalledTimes(2) + }) + + test("respects custom query options", async () => { + const getChainIdMock = jest.mocked(fcl.getChainId) + getChainIdMock.mockResolvedValueOnce(mockChainId) + + const customOptions = { + enabled: false, + staleTime: 1000, + } + + let hookResult: any + + await act(async () => { + const {result} = renderHook(() => useFlowChainId(customOptions), { + wrapper: FlowProvider, + }) + hookResult = result + }) + + // Since enabled is false, the query should not run + expect(getChainIdMock).not.toHaveBeenCalled() + expect(hookResult.current.data).toBeNull() + }) +}) diff --git a/packages/kit/src/hooks/useFlowChainId.ts b/packages/kit/src/hooks/useFlowChainId.ts new file mode 100644 index 000000000..b554f9d4f --- /dev/null +++ b/packages/kit/src/hooks/useFlowChainId.ts @@ -0,0 +1,32 @@ +import * as fcl from "@onflow/fcl" +import {useQuery, UseQueryOptions, UseQueryResult} from "@tanstack/react-query" +import {useFlowQueryClient} from "../provider/FlowQueryClient" +import {useCallback} from "react" +import {useFlowConfig} from "./useFlowConfig" + +/** + * Gets the Flow chain ID. + */ +export function useFlowChainId( + queryOptions: Omit< + UseQueryOptions, + "queryKey" | "queryFn" + > = {} +): UseQueryResult { + const queryClient = useFlowQueryClient() + const config = useFlowConfig() + + const fetchChainId = useCallback(async () => { + return await fcl.getChainId() + }, [config]) + + return useQuery( + { + queryKey: ["flowChainId"], + queryFn: fetchChainId, + initialData: null, + ...queryOptions, + }, + queryClient + ) +} From aa93da385697e56e20af00e87efb2cc324dbc587 Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Fri, 9 May 2025 10:32:52 -0700 Subject: [PATCH 32/72] Rename `useFlowTransaction` to `useFlowTransactionStatus` (#2413) * Rename tx hook to tx status hook * Fix import --------- Co-authored-by: Chase Fleming <1666730+chasefleming@users.noreply.github.com> --- packages/kit/src/hooks/index.ts | 2 +- ...st.ts => useFlowTransactionStatus.test.ts} | 22 ++++++++++++------- ...saction.ts => useFlowTransactionStatus.ts} | 10 ++++----- 3 files changed, 20 insertions(+), 14 deletions(-) rename packages/kit/src/hooks/{useFlowTransaction.test.ts => useFlowTransactionStatus.test.ts} (81%) rename packages/kit/src/hooks/{useFlowTransaction.ts => useFlowTransactionStatus.ts} (82%) diff --git a/packages/kit/src/hooks/index.ts b/packages/kit/src/hooks/index.ts index de93baa0f..adab19cdb 100644 --- a/packages/kit/src/hooks/index.ts +++ b/packages/kit/src/hooks/index.ts @@ -6,4 +6,4 @@ export {useFlowEvents} from "./useFlowEvents" export {useFlowMutate} from "./useFlowMutate" export {useFlowQuery} from "./useFlowQuery" export {useFlowRevertibleRandom} from "./useFlowRevertibleRandom" -export {useFlowTransaction} from "./useFlowTransaction" +export {useFlowTransactionStatus} from "./useFlowTransactionStatus" diff --git a/packages/kit/src/hooks/useFlowTransaction.test.ts b/packages/kit/src/hooks/useFlowTransactionStatus.test.ts similarity index 81% rename from packages/kit/src/hooks/useFlowTransaction.test.ts rename to packages/kit/src/hooks/useFlowTransactionStatus.test.ts index 4d2d4730f..df84454b8 100644 --- a/packages/kit/src/hooks/useFlowTransaction.test.ts +++ b/packages/kit/src/hooks/useFlowTransactionStatus.test.ts @@ -1,13 +1,13 @@ import {renderHook, act} from "@testing-library/react" import * as fcl from "@onflow/fcl" -import {useFlowTransaction} from "./useFlowTransaction" +import {useFlowTransactionStatus} from "./useFlowTransactionStatus" import {TransactionStatus} from "@onflow/typedefs" import {FlowProvider} from "../provider" import {defaultTxStatus, errorTxStatus} from "../__mocks__/tx" jest.mock("@onflow/fcl", () => require("../__mocks__/fcl").default) -describe("useFlowTransaction", () => { +describe("useFlowTransactionStatus", () => { afterEach(() => { jest.clearAllMocks() }) @@ -26,9 +26,12 @@ describe("useFlowTransaction", () => { subscribe: subscribeMock, } as unknown as ReturnType) - const {result} = renderHook(() => useFlowTransaction({id: "mockTxId"}), { - wrapper: FlowProvider, - }) + const {result} = renderHook( + () => useFlowTransactionStatus({id: "mockTxId"}), + { + wrapper: FlowProvider, + } + ) act(() => { subscribeCallback(defaultTxStatus) @@ -52,9 +55,12 @@ describe("useFlowTransaction", () => { subscribe: subscribeMock, } as unknown as ReturnType) - const {result} = renderHook(() => useFlowTransaction({id: "mockTxId"}), { - wrapper: FlowProvider, - }) + const {result} = renderHook( + () => useFlowTransactionStatus({id: "mockTxId"}), + { + wrapper: FlowProvider, + } + ) act(() => { subscribeCallback(errorTxStatus) diff --git a/packages/kit/src/hooks/useFlowTransaction.ts b/packages/kit/src/hooks/useFlowTransactionStatus.ts similarity index 82% rename from packages/kit/src/hooks/useFlowTransaction.ts rename to packages/kit/src/hooks/useFlowTransactionStatus.ts index 25ce2d10c..1181842da 100644 --- a/packages/kit/src/hooks/useFlowTransaction.ts +++ b/packages/kit/src/hooks/useFlowTransactionStatus.ts @@ -2,12 +2,12 @@ import {useState, useEffect} from "react" import * as fcl from "@onflow/fcl" import {TransactionStatus} from "@onflow/typedefs" -export interface UseFlowTransactionArgs { +export interface UseFlowTransactionStatusArgs { /** The Flow transaction ID to monitor */ id: string } -export interface UseFlowTransactionResult { +export interface UseFlowTransactionStatusResult { /** Latest transaction status, or null before any update */ transactionStatus: TransactionStatus | null /** Any error encountered during status updates */ @@ -18,11 +18,11 @@ export interface UseFlowTransactionResult { * Subscribes to status updates for a given Flow transaction ID. * * @param args.id - The Flow transaction ID to watch - * @returns {UseFlowTransactionResult} + * @returns {UseFlowTransactionStatusResult} */ -export function useFlowTransaction({ +export function useFlowTransactionStatus({ id, -}: UseFlowTransactionArgs): UseFlowTransactionResult { +}: UseFlowTransactionStatusArgs): UseFlowTransactionStatusResult { const [transactionStatus, setTransactionStatus] = useState(null) const [error, setError] = useState(null) From 605f66c7a78f9ff1474a18b70298956b92f90bc1 Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Fri, 9 May 2025 11:36:21 -0700 Subject: [PATCH 33/72] Add changeset (#2414) * Add changeset * Update moody-ligers-rule.md * Update .changeset/moody-ligers-rule.md Co-authored-by: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> --------- Co-authored-by: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Co-authored-by: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> --- .changeset/moody-ligers-rule.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/moody-ligers-rule.md diff --git a/.changeset/moody-ligers-rule.md b/.changeset/moody-ligers-rule.md new file mode 100644 index 000000000..2b30cfef4 --- /dev/null +++ b/.changeset/moody-ligers-rule.md @@ -0,0 +1,5 @@ +--- +"@onflow/kit": minor +--- + +**BREAKING**: Rename `useFlowTransaction` as `useFlowTransactionStatus` From 8bc6b3727dce0b24aea2c2f0e553ea87c0ee5295 Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Fri, 9 May 2025 13:36:34 -0700 Subject: [PATCH 34/72] Add comment about renaming (#2416) Co-authored-by: Chase Fleming <1666730+chasefleming@users.noreply.github.com> --- packages/kit/src/hooks/useFlowTransactionStatus.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/kit/src/hooks/useFlowTransactionStatus.ts b/packages/kit/src/hooks/useFlowTransactionStatus.ts index 1181842da..376803843 100644 --- a/packages/kit/src/hooks/useFlowTransactionStatus.ts +++ b/packages/kit/src/hooks/useFlowTransactionStatus.ts @@ -17,6 +17,9 @@ export interface UseFlowTransactionStatusResult { /** * Subscribes to status updates for a given Flow transaction ID. * + * @remarks + * This hook was previously named `useFlowTransaction`. + * * @param args.id - The Flow transaction ID to watch * @returns {UseFlowTransactionStatusResult} */ From 8608416f4d26e40d3bfa464da7e988c8beb35336 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Fri, 9 May 2025 23:45:09 +0000 Subject: [PATCH 35/72] Fix `useFlowRevertibleRandom` range (#2417) --- .changeset/forty-trees-report.md | 5 +++++ packages/kit/src/hooks/useFlowRevertibleRandom.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/forty-trees-report.md diff --git a/.changeset/forty-trees-report.md b/.changeset/forty-trees-report.md new file mode 100644 index 000000000..4598252b2 --- /dev/null +++ b/.changeset/forty-trees-report.md @@ -0,0 +1,5 @@ +--- +"@onflow/kit": patch +--- + +Fix `useFlowRevertibleRandom` range diff --git a/packages/kit/src/hooks/useFlowRevertibleRandom.ts b/packages/kit/src/hooks/useFlowRevertibleRandom.ts index 973fc488d..85dc471dd 100644 --- a/packages/kit/src/hooks/useFlowRevertibleRandom.ts +++ b/packages/kit/src/hooks/useFlowRevertibleRandom.ts @@ -83,7 +83,7 @@ export function useFlowRevertibleRandom({ for i in InclusiveRange(0, count - 1) { results.append(RevertibleRandomResult( blockHeight: currentHeight, - value: revertibleRandom(modulo: max - min + 1) + value: min + revertibleRandom(modulo: max - min + 1) )) } return results From f498aa9fdb0739aef8905593bdbd05af9db3267a Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Mon, 12 May 2025 15:37:55 -0700 Subject: [PATCH 36/72] Update readme with `useFlowRevertibleRandom` hook (#2419) Co-authored-by: Chase Fleming <1666730+chasefleming@users.noreply.github.com> --- .changeset/fast-lobsters-train.md | 5 +++++ packages/kit/README.md | 1 + 2 files changed, 6 insertions(+) create mode 100644 .changeset/fast-lobsters-train.md diff --git a/.changeset/fast-lobsters-train.md b/.changeset/fast-lobsters-train.md new file mode 100644 index 000000000..f7a3c5baf --- /dev/null +++ b/.changeset/fast-lobsters-train.md @@ -0,0 +1,5 @@ +--- +"@onflow/kit": patch +--- + +Update readme with `useFlowRevertibleRandom` hook diff --git a/packages/kit/README.md b/packages/kit/README.md index 8e9821e7d..1440cdbce 100644 --- a/packages/kit/README.md +++ b/packages/kit/README.md @@ -39,6 +39,7 @@ import flowJson from "../flow.json" - `useFlowConfig` - `useFlowEvents` - `useFlowQuery` +- `useFlowRevertibleRandom` - `useFlowMutate` - `useFlowTransaction` From eca4617c2d4d10d85bad0324f6c6064489c3d1c3 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Mon, 12 May 2025 23:05:04 +0000 Subject: [PATCH 37/72] Add `useCrossVmBatchTransaction` function (#2368) --- .changeset/good-books-call.md | 5 + package-lock.json | 340 ++++++++---------- packages/kit/package.json | 3 +- packages/kit/src/__mocks__/fcl.ts | 3 +- packages/kit/src/hooks/index.ts | 1 + .../hooks/useCrossVmBatchTransaction.test.ts | 240 +++++++++++++ .../src/hooks/useCrossVmBatchTransaction.ts | 283 +++++++++++++++ 7 files changed, 688 insertions(+), 187 deletions(-) create mode 100644 .changeset/good-books-call.md create mode 100644 packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts create mode 100644 packages/kit/src/hooks/useCrossVmBatchTransaction.ts diff --git a/.changeset/good-books-call.md b/.changeset/good-books-call.md new file mode 100644 index 000000000..deea1ec01 --- /dev/null +++ b/.changeset/good-books-call.md @@ -0,0 +1,5 @@ +--- +"@onflow/kit": minor +--- + +Add `useCrossVmBatchTransaction` function diff --git a/package-lock.json b/package-lock.json index 6e492b6e6..631979b0e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9036,8 +9036,6 @@ }, "node_modules/@reown/appkit": { "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@reown/appkit/-/appkit-1.7.3.tgz", - "integrity": "sha512-aA/UIwi/dVzxEB62xlw3qxHa3RK1YcPMjNxoGj/fHNCqL2qWmbcOXT7coCUa9RG7/Bh26FZ3vdVT2v71j6hebQ==", "license": "Apache-2.0", "dependencies": { "@reown/appkit-common": "1.7.3", @@ -9056,8 +9054,6 @@ }, "node_modules/@reown/appkit-common": { "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@reown/appkit-common/-/appkit-common-1.7.3.tgz", - "integrity": "sha512-wKTr6N3z8ly17cc51xBEVkZK4zAd8J1m7RubgsdQ1olFY9YJGe61RYoNv9yFjt6tUVeYT+z7iMUwPhX2PziefQ==", "license": "Apache-2.0", "dependencies": { "big.js": "6.2.2", @@ -9067,8 +9063,6 @@ }, "node_modules/@reown/appkit-common/node_modules/@noble/curves": { "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", - "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", "license": "MIT", "dependencies": { "@noble/hashes": "1.7.2" @@ -9082,8 +9076,6 @@ }, "node_modules/@reown/appkit-common/node_modules/@noble/hashes": { "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", - "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", "license": "MIT", "engines": { "node": "^14.21.3 || >=16" @@ -9094,14 +9086,10 @@ }, "node_modules/@reown/appkit-common/node_modules/eventemitter3": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "license": "MIT" }, "node_modules/@reown/appkit-common/node_modules/ox": { "version": "0.6.9", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", - "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", "funding": [ { "type": "github", @@ -9129,8 +9117,6 @@ }, "node_modules/@reown/appkit-common/node_modules/viem": { "version": "2.29.0", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.29.0.tgz", - "integrity": "sha512-N6GeIuuay/spDyw+5FbSuNIkVN0da+jGOjdlC0bdatIN+N0jtOf9Zfj0pbXgpIJGwnM9ocxzTRt0HZVbHBdL2Q==", "funding": [ { "type": "github", @@ -9159,8 +9145,6 @@ }, "node_modules/@reown/appkit-common/node_modules/ws": { "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -9180,8 +9164,6 @@ }, "node_modules/@reown/appkit-controllers": { "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@reown/appkit-controllers/-/appkit-controllers-1.7.3.tgz", - "integrity": "sha512-aqAcX/nZe0gwqjncyCkVrAk3lEw0qZ9xGrdLOmA207RreO4J0Vxu8OJXCBn4C2AUI2OpBxCPah+vyuKTUJTeHQ==", "license": "Apache-2.0", "dependencies": { "@reown/appkit-common": "1.7.3", @@ -9193,8 +9175,6 @@ }, "node_modules/@reown/appkit-controllers/node_modules/@noble/curves": { "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", - "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", "license": "MIT", "dependencies": { "@noble/hashes": "1.7.2" @@ -9208,8 +9188,6 @@ }, "node_modules/@reown/appkit-controllers/node_modules/@noble/hashes": { "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", - "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", "license": "MIT", "engines": { "node": "^14.21.3 || >=16" @@ -9220,14 +9198,10 @@ }, "node_modules/@reown/appkit-controllers/node_modules/eventemitter3": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "license": "MIT" }, "node_modules/@reown/appkit-controllers/node_modules/ox": { "version": "0.6.9", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", - "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", "funding": [ { "type": "github", @@ -9255,14 +9229,10 @@ }, "node_modules/@reown/appkit-controllers/node_modules/proxy-compare": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.6.0.tgz", - "integrity": "sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==", "license": "MIT" }, "node_modules/@reown/appkit-controllers/node_modules/use-sync-external-store": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" @@ -9270,8 +9240,6 @@ }, "node_modules/@reown/appkit-controllers/node_modules/valtio": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.13.2.tgz", - "integrity": "sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==", "license": "MIT", "dependencies": { "derive-valtio": "0.1.0", @@ -9296,8 +9264,6 @@ }, "node_modules/@reown/appkit-controllers/node_modules/viem": { "version": "2.29.0", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.29.0.tgz", - "integrity": "sha512-N6GeIuuay/spDyw+5FbSuNIkVN0da+jGOjdlC0bdatIN+N0jtOf9Zfj0pbXgpIJGwnM9ocxzTRt0HZVbHBdL2Q==", "funding": [ { "type": "github", @@ -9326,8 +9292,6 @@ }, "node_modules/@reown/appkit-controllers/node_modules/ws": { "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -9347,8 +9311,6 @@ }, "node_modules/@reown/appkit-polyfills": { "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@reown/appkit-polyfills/-/appkit-polyfills-1.7.3.tgz", - "integrity": "sha512-vQUiAyI7WiNTUV4iNwv27iigdeg8JJTEo6ftUowIrKZ2/gtE2YdMtGpavuztT/qrXhrIlTjDGp5CIyv9WOTu4g==", "license": "Apache-2.0", "dependencies": { "buffer": "6.0.3" @@ -9356,8 +9318,6 @@ }, "node_modules/@reown/appkit-scaffold-ui": { "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@reown/appkit-scaffold-ui/-/appkit-scaffold-ui-1.7.3.tgz", - "integrity": "sha512-ssB15fcjmoKQ+VfoCo7JIIK66a4SXFpCH8uK1CsMmXmKIKqPN54ohLo291fniV6mKtnJxh5Xm68slGtGrO3bmA==", "license": "Apache-2.0", "dependencies": { "@reown/appkit-common": "1.7.3", @@ -9370,8 +9330,6 @@ }, "node_modules/@reown/appkit-scaffold-ui/node_modules/@lit/reactive-element": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.0.tgz", - "integrity": "sha512-L2qyoZSQClcBmq0qajBVbhYEcG6iK0XfLn66ifLe/RfC0/ihpc+pl0Wdn8bJ8o+hj38cG0fGXRgSS20MuXn7qA==", "license": "BSD-3-Clause", "dependencies": { "@lit-labs/ssr-dom-shim": "^1.2.0" @@ -9379,8 +9337,6 @@ }, "node_modules/@reown/appkit-scaffold-ui/node_modules/lit": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.0.tgz", - "integrity": "sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w==", "license": "BSD-3-Clause", "dependencies": { "@lit/reactive-element": "^2.0.0", @@ -9390,8 +9346,6 @@ }, "node_modules/@reown/appkit-scaffold-ui/node_modules/lit-element": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.0.tgz", - "integrity": "sha512-MGrXJVAI5x+Bfth/pU9Kst1iWID6GHDLEzFEnyULB/sFiRLgkd8NPK/PeeXxktA3T6EIIaq8U3KcbTU5XFcP2Q==", "license": "BSD-3-Clause", "dependencies": { "@lit-labs/ssr-dom-shim": "^1.2.0", @@ -9401,8 +9355,6 @@ }, "node_modules/@reown/appkit-scaffold-ui/node_modules/lit-html": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.0.tgz", - "integrity": "sha512-RHoswrFAxY2d8Cf2mm4OZ1DgzCoBKUKSPvA1fhtSELxUERq2aQQ2h05pO9j81gS1o7RIRJ+CePLogfyahwmynw==", "license": "BSD-3-Clause", "dependencies": { "@types/trusted-types": "^2.0.2" @@ -9410,8 +9362,6 @@ }, "node_modules/@reown/appkit-ui": { "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@reown/appkit-ui/-/appkit-ui-1.7.3.tgz", - "integrity": "sha512-zKmFIjLp0X24pF9KtPtSHmdsh/RjEWIvz+faIbPGm4tQbwcxdg9A35HeoP0rMgKYx49SX51LgPwVXne2gYacqQ==", "license": "Apache-2.0", "dependencies": { "@reown/appkit-common": "1.7.3", @@ -9423,8 +9373,6 @@ }, "node_modules/@reown/appkit-ui/node_modules/@lit/reactive-element": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.0.tgz", - "integrity": "sha512-L2qyoZSQClcBmq0qajBVbhYEcG6iK0XfLn66ifLe/RfC0/ihpc+pl0Wdn8bJ8o+hj38cG0fGXRgSS20MuXn7qA==", "license": "BSD-3-Clause", "dependencies": { "@lit-labs/ssr-dom-shim": "^1.2.0" @@ -9432,8 +9380,6 @@ }, "node_modules/@reown/appkit-ui/node_modules/lit": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.0.tgz", - "integrity": "sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w==", "license": "BSD-3-Clause", "dependencies": { "@lit/reactive-element": "^2.0.0", @@ -9443,8 +9389,6 @@ }, "node_modules/@reown/appkit-ui/node_modules/lit-element": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.0.tgz", - "integrity": "sha512-MGrXJVAI5x+Bfth/pU9Kst1iWID6GHDLEzFEnyULB/sFiRLgkd8NPK/PeeXxktA3T6EIIaq8U3KcbTU5XFcP2Q==", "license": "BSD-3-Clause", "dependencies": { "@lit-labs/ssr-dom-shim": "^1.2.0", @@ -9454,8 +9398,6 @@ }, "node_modules/@reown/appkit-ui/node_modules/lit-html": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.0.tgz", - "integrity": "sha512-RHoswrFAxY2d8Cf2mm4OZ1DgzCoBKUKSPvA1fhtSELxUERq2aQQ2h05pO9j81gS1o7RIRJ+CePLogfyahwmynw==", "license": "BSD-3-Clause", "dependencies": { "@types/trusted-types": "^2.0.2" @@ -9463,8 +9405,6 @@ }, "node_modules/@reown/appkit-utils": { "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@reown/appkit-utils/-/appkit-utils-1.7.3.tgz", - "integrity": "sha512-8/MNhmfri+2uu8WzBhZ5jm5llofOIa1dyXDXRC/hfrmGmCFJdrQKPpuqOFYoimo2s2g70pK4PYefvOKgZOWzgg==", "license": "Apache-2.0", "dependencies": { "@reown/appkit-common": "1.7.3", @@ -9482,8 +9422,6 @@ }, "node_modules/@reown/appkit-utils/node_modules/@noble/curves": { "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", - "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", "license": "MIT", "dependencies": { "@noble/hashes": "1.7.2" @@ -9497,8 +9435,6 @@ }, "node_modules/@reown/appkit-utils/node_modules/@noble/hashes": { "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", - "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", "license": "MIT", "engines": { "node": "^14.21.3 || >=16" @@ -9509,14 +9445,10 @@ }, "node_modules/@reown/appkit-utils/node_modules/eventemitter3": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "license": "MIT" }, "node_modules/@reown/appkit-utils/node_modules/ox": { "version": "0.6.9", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", - "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", "funding": [ { "type": "github", @@ -9544,14 +9476,10 @@ }, "node_modules/@reown/appkit-utils/node_modules/proxy-compare": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.6.0.tgz", - "integrity": "sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==", "license": "MIT" }, "node_modules/@reown/appkit-utils/node_modules/use-sync-external-store": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" @@ -9559,8 +9487,6 @@ }, "node_modules/@reown/appkit-utils/node_modules/valtio": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.13.2.tgz", - "integrity": "sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==", "license": "MIT", "dependencies": { "derive-valtio": "0.1.0", @@ -9585,8 +9511,6 @@ }, "node_modules/@reown/appkit-utils/node_modules/viem": { "version": "2.29.0", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.29.0.tgz", - "integrity": "sha512-N6GeIuuay/spDyw+5FbSuNIkVN0da+jGOjdlC0bdatIN+N0jtOf9Zfj0pbXgpIJGwnM9ocxzTRt0HZVbHBdL2Q==", "funding": [ { "type": "github", @@ -9615,8 +9539,6 @@ }, "node_modules/@reown/appkit-utils/node_modules/ws": { "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -9636,8 +9558,6 @@ }, "node_modules/@reown/appkit-wallet": { "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@reown/appkit-wallet/-/appkit-wallet-1.7.3.tgz", - "integrity": "sha512-D0pExd0QUE71ursQPp3pq/0iFrz2oz87tOyFifrPANvH5X0RQCYn/34/kXr+BFVQzNFfCBDlYP+CniNA/S0KiQ==", "license": "Apache-2.0", "dependencies": { "@reown/appkit-common": "1.7.3", @@ -9648,8 +9568,6 @@ }, "node_modules/@reown/appkit-wallet/node_modules/zod": { "version": "3.22.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", - "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -9657,8 +9575,6 @@ }, "node_modules/@reown/appkit/node_modules/@noble/curves": { "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", - "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", "license": "MIT", "dependencies": { "@noble/hashes": "1.7.2" @@ -9672,8 +9588,6 @@ }, "node_modules/@reown/appkit/node_modules/@noble/hashes": { "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", - "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", "license": "MIT", "engines": { "node": "^14.21.3 || >=16" @@ -9684,14 +9598,10 @@ }, "node_modules/@reown/appkit/node_modules/eventemitter3": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "license": "MIT" }, "node_modules/@reown/appkit/node_modules/ox": { "version": "0.6.9", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", - "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", "funding": [ { "type": "github", @@ -9719,14 +9629,10 @@ }, "node_modules/@reown/appkit/node_modules/proxy-compare": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.6.0.tgz", - "integrity": "sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==", "license": "MIT" }, "node_modules/@reown/appkit/node_modules/use-sync-external-store": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" @@ -9734,8 +9640,6 @@ }, "node_modules/@reown/appkit/node_modules/valtio": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.13.2.tgz", - "integrity": "sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==", "license": "MIT", "dependencies": { "derive-valtio": "0.1.0", @@ -9760,8 +9664,6 @@ }, "node_modules/@reown/appkit/node_modules/viem": { "version": "2.29.0", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.29.0.tgz", - "integrity": "sha512-N6GeIuuay/spDyw+5FbSuNIkVN0da+jGOjdlC0bdatIN+N0jtOf9Zfj0pbXgpIJGwnM9ocxzTRt0HZVbHBdL2Q==", "funding": [ { "type": "github", @@ -9790,8 +9692,6 @@ }, "node_modules/@reown/appkit/node_modules/ws": { "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -10157,9 +10057,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.1.tgz", - "integrity": "sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==", + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.2.tgz", + "integrity": "sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==", "cpu": [ "x64" ], @@ -10748,8 +10648,6 @@ }, "node_modules/@types/prop-types": { "version": "15.7.14", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", - "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", "dev": true, "license": "MIT" }, @@ -10775,8 +10673,6 @@ }, "node_modules/@types/scheduler": { "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", "dev": true, "license": "MIT" }, @@ -11848,6 +11744,8 @@ }, "node_modules/abitype": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.8.tgz", + "integrity": "sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/wevm" @@ -12841,8 +12739,6 @@ }, "node_modules/big.js": { "version": "6.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz", - "integrity": "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==", "license": "MIT", "engines": { "node": "*" @@ -14667,8 +14563,6 @@ }, "node_modules/derive-valtio": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/derive-valtio/-/derive-valtio-0.1.0.tgz", - "integrity": "sha512-OCg2UsLbXK7GmmpzMXhYkdO64vhJ1ROUUGaTFyHjVwEdMEcTTRj7W1TxLbSBxdY8QLBPCcp66MTyaSy0RpO17A==", "license": "MIT", "peerDependencies": { "valtio": "*" @@ -26287,8 +26181,6 @@ }, "node_modules/query-string": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", - "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", "license": "MIT", "dependencies": { "decode-uri-component": "^0.2.2", @@ -28402,8 +28294,6 @@ }, "node_modules/strict-uri-encode": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", - "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", "license": "MIT", "engines": { "node": ">=4" @@ -30972,16 +30862,16 @@ }, "packages/fcl": { "name": "@onflow/fcl", - "version": "1.16.1", + "version": "1.17.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.17.0", - "@onflow/fcl-wc": "6.0.1", + "@onflow/fcl-core": "1.18.0", + "@onflow/fcl-wc": "6.0.2", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.0", + "@onflow/sdk": "1.8.1", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", @@ -30999,7 +30889,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.4.1", + "@onflow/typedefs": "1.5.0", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -31047,7 +30937,7 @@ }, "packages/fcl-core": { "name": "@onflow/fcl-core", - "version": "1.17.0", + "version": "1.18.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -31055,7 +30945,7 @@ "@onflow/config": "1.5.2", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.0", + "@onflow/sdk": "1.8.1", "@onflow/transport-http": "1.12.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", @@ -31070,7 +30960,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.4.1", + "@onflow/typedefs": "1.5.0", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -31102,14 +30992,14 @@ }, "packages/fcl-ethereum-provider": { "name": "@onflow/fcl-ethereum-provider", - "version": "0.0.3", + "version": "0.0.4", "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.1", + "@onflow/fcl-wc": "6.0.2", "@onflow/rlp": "^1.2.3", "@walletconnect/ethereum-provider": "^2.20.2", "@walletconnect/jsonrpc-http-connection": "^1.0.8", @@ -31121,7 +31011,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.4.0", + "@onflow/typedefs": "^1.5.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -31130,13 +31020,11 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.16.1" + "@onflow/fcl": "1.17.0" } }, "packages/fcl-ethereum-provider/node_modules/@react-native-async-storage/async-storage": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.24.0.tgz", - "integrity": "sha512-W4/vbwUOYOjco0x3toB8QCr7EjIP6nE9G7o8PMguvvjYT5Awg09lyV4enACRx4s++PPulBiBSjL0KTFx2u0Z/g==", "license": "MIT", "optional": true, "peer": true, @@ -31149,8 +31037,6 @@ }, "packages/fcl-ethereum-provider/node_modules/@walletconnect/core": { "version": "2.20.2", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.20.2.tgz", - "integrity": "sha512-48XnarxQQrpJ0KZJOjit56DxuzfVRYUdL8XVMvUh/ZNUiX2FB5w6YuljUUeTLfYOf04Et6qhVGEUkmX3W+9/8w==", "license": "Apache-2.0", "dependencies": { "@walletconnect/heartbeat": "1.2.2", @@ -31177,8 +31063,6 @@ }, "packages/fcl-ethereum-provider/node_modules/@walletconnect/ethereum-provider": { "version": "2.20.2", - "resolved": "https://registry.npmjs.org/@walletconnect/ethereum-provider/-/ethereum-provider-2.20.2.tgz", - "integrity": "sha512-fGNJtytHuBWZcmMXRIG1djlfEiPMvPJ0R3JlfJjAx2VfVN+O+1xdF6QSWcZxFizviIUFJV+f1zWt0V2VVD61Rg==", "license": "Apache-2.0", "dependencies": { "@reown/appkit": "1.7.3", @@ -31196,8 +31080,6 @@ }, "packages/fcl-ethereum-provider/node_modules/@walletconnect/keyvaluestorage": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", - "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", "license": "MIT", "dependencies": { "@walletconnect/safe-json": "^1.0.1", @@ -31215,8 +31097,6 @@ }, "packages/fcl-ethereum-provider/node_modules/@walletconnect/sign-client": { "version": "2.20.2", - "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.20.2.tgz", - "integrity": "sha512-KyeDToypZ1OjCbij4Jx0cAg46bMwZ6zCKt0HzCkqENcex3Zchs7xBp9r8GtfEMGw+PUnXwqrhzmLBH0x/43oIQ==", "license": "Apache-2.0", "dependencies": { "@walletconnect/core": "2.20.2", @@ -31232,8 +31112,6 @@ }, "packages/fcl-ethereum-provider/node_modules/@walletconnect/types": { "version": "2.20.2", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.20.2.tgz", - "integrity": "sha512-XPPbJM/mGU05i6jUxhC3yI/YvhSF6TYJQ5SXTWM53lVe6hs6ukvlEhPctu9ZBTGwGFhwPXIjtK/eWx+v4WY5iw==", "license": "Apache-2.0", "dependencies": { "@walletconnect/events": "1.0.1", @@ -31246,8 +31124,6 @@ }, "packages/fcl-ethereum-provider/node_modules/@walletconnect/universal-provider": { "version": "2.20.2", - "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.20.2.tgz", - "integrity": "sha512-6uVu1E88tioaXEEJCbJKwCIQlOHif1nmfY092BznZEnBn2lli5ICzQh2bxtUDNmNNLKsMDI3FV1fODFeWMVJTQ==", "license": "Apache-2.0", "dependencies": { "@walletconnect/events": "1.0.1", @@ -31266,8 +31142,6 @@ }, "packages/fcl-ethereum-provider/node_modules/@walletconnect/utils": { "version": "2.20.2", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.20.2.tgz", - "integrity": "sha512-2uRUDvpYSIJFYcr1WIuiFy6CEszLF030o6W8aDMkGk9/MfAZYEJQHMJcjWyaNMPHLJT0POR5lPaqkYOpuyPIQQ==", "license": "Apache-2.0", "dependencies": { "@noble/ciphers": "1.2.1", @@ -31291,14 +31165,14 @@ }, "packages/fcl-rainbowkit-adapter": { "name": "@onflow/fcl-rainbowkit-adapter", - "version": "0.1.0", + "version": "0.2.0", "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.3", - "@onflow/fcl-wagmi-adapter": "0.0.3", + "@onflow/fcl-ethereum-provider": "0.0.4", + "@onflow/fcl-wagmi-adapter": "0.0.4", "@onflow/rlp": "^1.2.3", "@wagmi/core": "^2.16.3", "mipd": "^0.0.7", @@ -31309,7 +31183,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.4.0", + "@onflow/typedefs": "^1.5.0", "@types/jest": "^29.5.13", "@types/react": "^16.0.0", "@typescript-eslint/eslint-plugin": "^6.21.0", @@ -31319,15 +31193,13 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.16.1", + "@onflow/fcl": "1.17.0", "@rainbow-me/rainbowkit": "^2.2.3", "react": "17.x || 18.x || 19.x" } }, "packages/fcl-rainbowkit-adapter/node_modules/@types/react": { "version": "16.14.63", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.63.tgz", - "integrity": "sha512-s83gano0fRBVEw3ejdLpjgvU83F0LIeeuXqdxfPZF/Sc2bhr60tEqCK1zZ+aLirBwRSD6V5zCtOsEjcwKow3JQ==", "dev": true, "license": "MIT", "dependencies": { @@ -31338,15 +31210,15 @@ }, "packages/fcl-react-native": { "name": "@onflow/fcl-react-native", - "version": "1.10.1", + "version": "1.11.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.17.0", + "@onflow/fcl-core": "1.18.0", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.0", + "@onflow/sdk": "1.8.1", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", @@ -31359,7 +31231,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.4.1", + "@onflow/typedefs": "1.5.0", "@types/estree": "^1.0.6", "@types/node": "^18.19.57", "eslint": "^8.57.1", @@ -31397,20 +31269,20 @@ }, "packages/fcl-wagmi-adapter": { "name": "@onflow/fcl-wagmi-adapter", - "version": "0.0.3", + "version": "0.0.4", "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.3", + "@onflow/fcl-ethereum-provider": "0.0.4", "@onflow/rlp": "^1.2.3", "viem": "^2.22.21" }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.4.0", + "@onflow/typedefs": "^1.5.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -31419,13 +31291,13 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.16.1", + "@onflow/fcl": "1.17.0", "@wagmi/core": "^2.16.3" } }, "packages/fcl-wc": { "name": "@onflow/fcl-wc", - "version": "6.0.1", + "version": "6.0.2", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -31444,7 +31316,7 @@ "@babel/plugin-transform-react-jsx": "^7.25.9", "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.4.1", + "@onflow/typedefs": "1.5.0", "autoprefixer": "^10.4.20", "eslint": "^8.57.1", "eslint-plugin-jsdoc": "^46.10.1", @@ -31452,13 +31324,11 @@ "jest-preset-preact": "^4.1.1" }, "peerDependencies": { - "@onflow/fcl-core": "1.17.0" + "@onflow/fcl-core": "1.18.0" } }, "packages/fcl-wc/node_modules/@react-native-async-storage/async-storage": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.24.0.tgz", - "integrity": "sha512-W4/vbwUOYOjco0x3toB8QCr7EjIP6nE9G7o8PMguvvjYT5Awg09lyV4enACRx4s++PPulBiBSjL0KTFx2u0Z/g==", "license": "MIT", "optional": true, "peer": true, @@ -31471,8 +31341,6 @@ }, "packages/fcl-wc/node_modules/@walletconnect/core": { "version": "2.20.2", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.20.2.tgz", - "integrity": "sha512-48XnarxQQrpJ0KZJOjit56DxuzfVRYUdL8XVMvUh/ZNUiX2FB5w6YuljUUeTLfYOf04Et6qhVGEUkmX3W+9/8w==", "license": "Apache-2.0", "dependencies": { "@walletconnect/heartbeat": "1.2.2", @@ -31499,8 +31367,6 @@ }, "packages/fcl-wc/node_modules/@walletconnect/keyvaluestorage": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", - "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", "license": "MIT", "dependencies": { "@walletconnect/safe-json": "^1.0.1", @@ -31518,8 +31384,6 @@ }, "packages/fcl-wc/node_modules/@walletconnect/sign-client": { "version": "2.20.2", - "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.20.2.tgz", - "integrity": "sha512-KyeDToypZ1OjCbij4Jx0cAg46bMwZ6zCKt0HzCkqENcex3Zchs7xBp9r8GtfEMGw+PUnXwqrhzmLBH0x/43oIQ==", "license": "Apache-2.0", "dependencies": { "@walletconnect/core": "2.20.2", @@ -31535,8 +31399,6 @@ }, "packages/fcl-wc/node_modules/@walletconnect/types": { "version": "2.20.2", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.20.2.tgz", - "integrity": "sha512-XPPbJM/mGU05i6jUxhC3yI/YvhSF6TYJQ5SXTWM53lVe6hs6ukvlEhPctu9ZBTGwGFhwPXIjtK/eWx+v4WY5iw==", "license": "Apache-2.0", "dependencies": { "@walletconnect/events": "1.0.1", @@ -31549,8 +31411,6 @@ }, "packages/fcl-wc/node_modules/@walletconnect/universal-provider": { "version": "2.20.2", - "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.20.2.tgz", - "integrity": "sha512-6uVu1E88tioaXEEJCbJKwCIQlOHif1nmfY092BznZEnBn2lli5ICzQh2bxtUDNmNNLKsMDI3FV1fODFeWMVJTQ==", "license": "Apache-2.0", "dependencies": { "@walletconnect/events": "1.0.1", @@ -31569,8 +31429,6 @@ }, "packages/fcl-wc/node_modules/@walletconnect/utils": { "version": "2.20.2", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.20.2.tgz", - "integrity": "sha512-2uRUDvpYSIJFYcr1WIuiFy6CEszLF030o6W8aDMkGk9/MfAZYEJQHMJcjWyaNMPHLJT0POR5lPaqkYOpuyPIQQ==", "license": "Apache-2.0", "dependencies": { "@noble/ciphers": "1.2.1", @@ -31613,19 +31471,20 @@ }, "packages/kit": { "name": "@onflow/kit", - "version": "0.0.2", + "version": "0.1.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@tanstack/react-query": "^5.67.3", - "@testing-library/react": "^16.2.0" + "@testing-library/react": "^16.2.0", + "viem": "^2.28.1" }, "devDependencies": { "@babel/preset-env": "^7.26.9", "@babel/preset-react": "^7.26.3", "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.4.0", + "@onflow/typedefs": "^1.5.0", "@testing-library/dom": "^10.4.0", "@types/jest": "^29.5.13", "@types/react": "^19.0.10", @@ -31638,11 +31497,124 @@ "jest-environment-jsdom": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": ">=1.16.0", + "@onflow/fcl": ">=1.17.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, + "packages/kit/node_modules/@noble/curves": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", + "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.2" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "packages/kit/node_modules/@noble/hashes": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", + "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "packages/kit/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "packages/kit/node_modules/ox": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", + "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.10.1", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0", + "@scure/bip32": "^1.5.0", + "@scure/bip39": "^1.4.0", + "abitype": "^1.0.6", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/kit/node_modules/viem": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.29.1.tgz", + "integrity": "sha512-mhLn0vDdsxZ4taB7XYgnIVNvXASm60KyPAkvw4k8uNCQ+HLH+5jUgKvLg4AP3y6VJxsgiVPwqUt0dJANDF5DZA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.2", + "@noble/hashes": "1.7.2", + "@scure/bip32": "1.6.2", + "@scure/bip39": "1.5.4", + "abitype": "1.0.8", + "isows": "1.0.6", + "ox": "0.6.9", + "ws": "8.18.1" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/kit/node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "packages/protobuf": { "name": "@onflow/protobuf", "version": "1.3.1", @@ -31711,14 +31683,14 @@ }, "packages/sdk": { "name": "@onflow/sdk", - "version": "1.8.0", + "version": "1.8.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", "@onflow/rlp": "1.2.3", "@onflow/transport-http": "1.12.0", - "@onflow/typedefs": "1.4.1", + "@onflow/typedefs": "1.5.0", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", "@onflow/util-invariant": "1.2.4", @@ -31766,7 +31738,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/sdk": "1.8.0", + "@onflow/sdk": "1.8.1", "jest": "^29.7.0" } }, @@ -31789,7 +31761,7 @@ "devDependencies": { "@onflow/fcl-bundle": "1.7.0", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.0", + "@onflow/sdk": "1.8.1", "@onflow/types": "1.4.1", "jest": "^29.7.0" } @@ -31803,7 +31775,7 @@ }, "packages/typedefs": { "name": "@onflow/typedefs", - "version": "1.4.1", + "version": "1.5.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7" diff --git a/packages/kit/package.json b/packages/kit/package.json index c2e06c84c..3d0f7c6ae 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -45,7 +45,8 @@ "dependencies": { "@babel/runtime": "^7.25.7", "@tanstack/react-query": "^5.67.3", - "@testing-library/react": "^16.2.0" + "@testing-library/react": "^16.2.0", + "viem": "^2.28.1" }, "peerDependencies": { "@onflow/fcl": ">=1.17.0", diff --git a/packages/kit/src/__mocks__/fcl.ts b/packages/kit/src/__mocks__/fcl.ts index 430746ed1..a2c5e317a 100644 --- a/packages/kit/src/__mocks__/fcl.ts +++ b/packages/kit/src/__mocks__/fcl.ts @@ -1,4 +1,3 @@ -import * as actualFcl from "@onflow/fcl" import {authenticatedUser, defaultUser} from "./user" const sharedSubscribe = jest.fn(callback => { @@ -12,7 +11,7 @@ const sharedSubscribe = jest.fn(callback => { let currentUserState = defaultUser export default { - ...actualFcl, + ...jest.requireActual("@onflow/fcl"), account: jest.fn(), block: jest.fn(), events: jest.fn(), diff --git a/packages/kit/src/hooks/index.ts b/packages/kit/src/hooks/index.ts index adab19cdb..597e5ddca 100644 --- a/packages/kit/src/hooks/index.ts +++ b/packages/kit/src/hooks/index.ts @@ -6,4 +6,5 @@ export {useFlowEvents} from "./useFlowEvents" export {useFlowMutate} from "./useFlowMutate" export {useFlowQuery} from "./useFlowQuery" export {useFlowRevertibleRandom} from "./useFlowRevertibleRandom" +export {useCrossVmBatchTransaction} from "./useCrossVmBatchTransaction" export {useFlowTransactionStatus} from "./useFlowTransactionStatus" diff --git a/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts b/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts new file mode 100644 index 000000000..c9ec48eee --- /dev/null +++ b/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts @@ -0,0 +1,240 @@ +import {renderHook, act, waitFor} from "@testing-library/react" +import * as fcl from "@onflow/fcl" +import {FlowProvider} from "../provider" +import { + encodeCalls, + getCadenceBatchTransaction, + useCrossVmBatchTransaction, +} from "./useCrossVmBatchTransaction" +import {useFlowChainId} from "./useFlowChainId" + +jest.mock("@onflow/fcl", () => require("../__mocks__/fcl").default) +jest.mock("viem", () => ({ + encodeFunctionData: jest.fn(), + bytesToHex: jest.fn(x => `0x${x}`), +})) +jest.mock("./useFlowChainId", () => ({ + useFlowChainId: jest.fn(), +})) + +describe("useBatchEvmTransaction", () => { + const mockCalls = [ + { + address: "0x123", + abi: [{type: "function", name: "test"}], + functionName: "test", + args: [1, 2], + gasLimit: BigInt(100000), + value: BigInt(0), + }, + ] + + const mockTxId = "0x123" + const mockTxResult = { + events: [ + { + type: "TransactionExecuted", + data: { + hash: ["1", "2", "3"], + errorCode: "0", + errorMessage: "", + }, + }, + ], + } + + beforeEach(() => { + jest.clearAllMocks() + jest.mocked(useFlowChainId).mockReturnValue({ + data: "mainnet", + isLoading: false, + } as any) + }) + + describe("encodeCalls", () => { + it("should encode calls correctly", () => { + const result = encodeCalls(mockCalls as any) + + expect(result).toEqual([ + [ + {key: "to", value: "0x123"}, + {key: "data", value: ""}, + {key: "gasLimit", value: "100000"}, + {key: "value", value: "0"}, + ], + ]) + }) + }) + + describe("getCadenceBatchTransaction", () => { + it("should return correct cadence for mainnet", () => { + const result = getCadenceBatchTransaction("mainnet") + expect(result).toContain("import EVM from 0xe467b9dd11fa00df") + }) + + it("should return correct cadence for testnet", () => { + const result = getCadenceBatchTransaction("testnet") + expect(result).toContain("import EVM from 0x8c5303eaa26202d6") + }) + + it("should return correct cadence for local", () => { + const result = getCadenceBatchTransaction("local") + expect(result).toContain("import EVM from 0xf8d6e0586b0a20c0") + }) + + it("should throw error for unsupported chain", () => { + expect(() => getCadenceBatchTransaction("unsupported")).toThrow( + "Unsupported chain: unsupported" + ) + }) + }) + + describe("useCrossVmBatchTransaction", () => { + test("should handle successful transaction", async () => { + jest.mocked(fcl.mutate).mockResolvedValue(mockTxId) + jest.mocked(fcl.tx).mockReturnValue({ + onceExecuted: jest.fn().mockResolvedValue(mockTxResult), + } as any) + + let result: any + let rerender: any + await act(async () => { + ;({result, rerender} = renderHook(useCrossVmBatchTransaction, { + wrapper: FlowProvider, + })) + }) + + await act(async () => { + await result.current.sendBatchTransaction({calls: mockCalls}) + rerender() + }) + + await waitFor(() => result.current.isPending === false) + + expect(result.current.isError).toBe(false) + expect(result.current.data?.txId).toBe(mockTxId) + expect(result.current.data?.results).toHaveLength(1) + expect(result.current.data?.results[0].status).toBe("passed") + }) + + test("should handle failed transaction", async () => { + jest.mocked(fcl.mutate).mockResolvedValue(mockTxId) + jest.mocked(fcl.tx).mockReturnValue({ + onceExecuted: jest + .fn() + .mockRejectedValue(new Error("Transaction failed")), + } as any) + + let hookResult: any + + await act(async () => { + const {result} = renderHook(useCrossVmBatchTransaction, { + wrapper: FlowProvider, + }) + hookResult = result + }) + + await act(async () => { + await hookResult.current.sendBatchTransaction({calls: mockCalls}) + }) + + await waitFor(() => expect(hookResult.current.isPending).toBe(false)) + + expect(hookResult.current.isError).toBe(false) + expect(hookResult.current.data?.results[0].status).toBe("failed") + expect(hookResult.current.data?.results[0].errorMessage).toBe( + "Transaction reverted" + ) + }) + + test("should handle skipped calls", async () => { + jest.mocked(fcl.mutate).mockResolvedValue(mockTxId) + jest.mocked(fcl.tx).mockReturnValue({ + onceExecuted: jest.fn().mockResolvedValue({events: []}), + } as any) + + let hookResult: any + + await act(async () => { + const {result} = renderHook(() => useCrossVmBatchTransaction(), { + wrapper: FlowProvider, + }) + hookResult = result + }) + + await act(async () => { + await hookResult.current.sendBatchTransaction({calls: mockCalls}) + }) + + await waitFor(() => expect(hookResult.current.isPending).toBe(false)) + + expect(hookResult.current.data?.results[0].status).toBe("skipped") + }) + + it("should handle missing chain ID", async () => { + ;(useFlowChainId as jest.Mock).mockReturnValue({ + data: null, + isLoading: false, + }) + + let hookResult: any + + await act(async () => { + const {result} = renderHook(() => useCrossVmBatchTransaction(), { + wrapper: FlowProvider, + }) + hookResult = result + }) + + await act(async () => { + await hookResult.current.sendBatchTransaction({calls: mockCalls}) + }) + + await waitFor(() => expect(hookResult.current.isError).toBe(true)) + expect(hookResult.current.error?.message).toBe("No current chain found") + }) + + it("should handle loading chain ID", async () => { + ;(useFlowChainId as jest.Mock).mockReturnValue({ + data: null, + isLoading: true, + }) + + let hookResult: any + + await act(async () => { + const {result} = renderHook(() => useCrossVmBatchTransaction(), { + wrapper: FlowProvider, + }) + hookResult = result + }) + + await act(async () => { + await hookResult.current.sendBatchTransaction(mockCalls) + }) + + await waitFor(() => expect(hookResult.current.isError).toBe(true)) + expect(hookResult.current.error?.message).toBe("No current chain found") + }) + + it("should handle mutation error", async () => { + ;(fcl.mutate as jest.Mock).mockRejectedValue(new Error("Mutation failed")) + + let hookResult: any + + await act(async () => { + const {result} = renderHook(() => useCrossVmBatchTransaction(), { + wrapper: FlowProvider, + }) + hookResult = result + }) + + await act(async () => { + await hookResult.current.sendBatchTransaction({calls: mockCalls}) + }) + + await waitFor(() => expect(hookResult.current.isError).toBe(true)) + expect(hookResult.current.error?.message).toBe("Mutation failed") + }) + }) +}) diff --git a/packages/kit/src/hooks/useCrossVmBatchTransaction.ts b/packages/kit/src/hooks/useCrossVmBatchTransaction.ts new file mode 100644 index 000000000..89219309d --- /dev/null +++ b/packages/kit/src/hooks/useCrossVmBatchTransaction.ts @@ -0,0 +1,283 @@ +import * as fcl from "@onflow/fcl" +import {Abi, bytesToHex, encodeFunctionData} from "viem" +import { + UseMutateFunction, + useMutation, + UseMutationOptions, + UseMutationResult, +} from "@tanstack/react-query" +import {useFlowChainId} from "./useFlowChainId" +import {useFlowQueryClient} from "../provider/FlowQueryClient" + +interface useCrossVmBatchTransactionArgs { + mutation?: Omit< + UseMutationOptions< + { + txId: string + results: CallOutcome[] + }, + Error, + { + calls: EvmBatchCall[] + mustPass?: boolean + } + >, + "mutationFn" + > +} + +interface useCrossVmBatchTransactionResult + extends Omit< + UseMutationResult< + { + txId: string + results: CallOutcome[] + }, + Error + >, + "mutate" | "mutateAsync" + > { + sendBatchTransaction: UseMutateFunction< + { + txId: string + results: CallOutcome[] + }, + Error, + { + calls: EvmBatchCall[] + mustPass?: boolean + } + > + sendBatchTransactionAsync: (args: { + calls: EvmBatchCall[] + mustPass?: boolean + }) => Promise<{ + txId: string + results: CallOutcome[] + }> +} + +interface EvmBatchCall { + // The target EVM contract address (as a string) + address: string + // The contract ABI fragment + abi: Abi + // The name of the function to call + functionName: string + // The function arguments + args?: readonly unknown[] + // The gas limit for the call + gasLimit?: bigint + // The value to send with the call + value?: bigint +} +interface CallOutcome { + status: "passed" | "failed" | "skipped" + hash?: string + errorMessage?: string +} + +type EvmTransactionExecutedData = { + hash: string[] + index: string + type: string + payload: string[] + errorCode: string + errorMessage: string + gasConsumed: string + contractAddress: string + logs: string[] + blockHeight: string + returnedData: string[] + precompiledCalls: string[] + stateUpdateChecksum: string +} + +// Helper to encode our ca lls using viem. +// Returns an array of objects with keys "address" and "data" (hex-encoded string without the "0x" prefix). +export function encodeCalls( + calls: EvmBatchCall[] +): Array> { + return calls.map(call => { + const encodedData = encodeFunctionData({ + abi: call.abi, + functionName: call.functionName, + args: call.args, + }) + + return [ + {key: "to", value: call.address}, + {key: "data", value: fcl.sansPrefix(encodedData) ?? ""}, + {key: "gasLimit", value: call.gasLimit?.toString() ?? "15000000"}, + {key: "value", value: call.value?.toString() ?? "0"}, + ] + }) as any +} + +const EVM_CONTRACT_ADDRESSES = { + local: "0xf8d6e0586b0a20c0", + testnet: "0x8c5303eaa26202d6", + mainnet: "0xe467b9dd11fa00df", +} + +// Takes a chain id and returns the cadence tx with addresses set +export const getCadenceBatchTransaction = (chainId: string) => { + const evmAddress = + EVM_CONTRACT_ADDRESSES[chainId as keyof typeof EVM_CONTRACT_ADDRESSES] + if (!evmAddress) { + throw new Error(`Unsupported chain: ${chainId}`) + } + + return ` +import EVM from ${evmAddress} + +transaction(calls: [{String: AnyStruct}], mustPass: Bool) { + + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) & Account) { + let storagePath = /storage/evm + self.coa = signer.storage.borrow(from: storagePath) + ?? panic("No CadenceOwnedAccount (COA) found at ".concat(storagePath.toString())) + } + + execute { + for i, call in calls { + let to = call["to"] as! String + let data = call["data"] as! String + let gasLimit = call["gasLimit"] as! UInt64 + let value = call["value"] as! UInt + + let result = self.coa.call( + to: EVM.addressFromString(to), + data: data.decodeHex(), + gasLimit: gasLimit, + value: EVM.Balance(attoflow: value) + ) + + if mustPass { + assert( + result.status == EVM.Status.successful, + message: "Call index ".concat(i.toString()).concat(" to ").concat(to) + .concat(" with calldata ").concat(data).concat(" failed: ") + .concat(result.errorMessage) + ) + } + } + } +} +` +} + +/** + * Hook to send an EVM batch transaction using a Cadence-compatible wallet. This function will + * bundle multiple EVM calls into one atomic Cadence transaction and return both the Cadence + * transaction ID as well as the result of each EVM call. + * + * @returns The query mutation object used to send the transaction and get the result. + */ +export function useCrossVmBatchTransaction({ + mutation: mutationOptions = {}, +}: useCrossVmBatchTransactionArgs = {}): useCrossVmBatchTransactionResult { + const chainId = useFlowChainId() + const cadenceTx = chainId.data + ? getCadenceBatchTransaction(chainId.data) + : null + + const queryClient = useFlowQueryClient() + const mutation = useMutation( + { + mutationFn: async ({ + calls, + mustPass = true, + }: { + calls: EvmBatchCall[] + mustPass?: boolean + }) => { + if (!cadenceTx) { + throw new Error("No current chain found") + } + const encodedCalls = encodeCalls(calls) + + const txId = await fcl.mutate({ + cadence: cadenceTx, + args: (arg, t) => [ + arg( + encodedCalls, + t.Array( + t.Dictionary([ + {key: t.String, value: t.String}, + {key: t.String, value: t.String}, + {key: t.String, value: t.UInt64}, + {key: t.String, value: t.UInt}, + ] as any) + ) + ), + arg(mustPass, t.Bool), + ], + limit: 9999, + }) + + let txResult + try { + txResult = await fcl.tx(txId).onceExecuted() + } catch (txError) { + // If we land here, the transaction likely reverted. + // We can return partial or "failed" outcomes for all calls. + return { + txId, + results: calls.map(() => ({ + status: "failed" as const, + hash: undefined, + errorMessage: "Transaction reverted", + })), + } + } + + // Filter for TransactionExecuted events + const executedEvents = txResult.events.filter((e: any) => + e.type.includes("TransactionExecuted") + ) + + // Build a full outcomes array for every call. + // For any call index where no event exists, mark it as "skipped". + const results: CallOutcome[] = calls.map((_, index) => { + const eventData = executedEvents[index] + ?.data as EvmTransactionExecutedData + if (eventData) { + return { + hash: bytesToHex( + Uint8Array.from( + eventData.hash.map((x: string) => parseInt(x, 10)) + ) + ), + status: eventData.errorCode === "0" ? "passed" : "failed", + errorMessage: eventData.errorMessage, + } + } else { + return { + status: "skipped", + } + } + }) + + return {txId, results} + }, + retry: false, + ...mutationOptions, + }, + queryClient + ) + + const { + mutate: sendBatchTransaction, + mutateAsync: sendBatchTransactionAsync, + ...rest + } = mutation + + return { + sendBatchTransaction, + sendBatchTransactionAsync, + ...rest, + } +} From 4d3bb084c1442552d6a1de1f53435d1aa3f600b0 Mon Sep 17 00:00:00 2001 From: Michael Fabozzi <39808567+mfbz@users.noreply.github.com> Date: Tue, 13 May 2025 09:57:47 +0200 Subject: [PATCH 38/72] Refactored SDK package to TypeScript (#2352) * Added onflow/typedefs and onflow/types types into sdk package * Updated first part of files * Updated encode and decode folders * Updated send.js * Updated sdk resolve files * Fixed build problems * Updated wallet-utils folder * Moved typedefs and types back to their package * Fixed build * Refactored more js to ts files * Fixed tests * Added onflow/types re-export from sdk * Added missing onflow/types package to sdk * Updated readme with typescript examples * Fixed build error on type problem * Added changeset file * Cleaned up types and docs * Minor comments fix * Removed unused cast * Added suport to conditional interaction callbacks in build * After install update * Fixed build-transaction input params * Updated send function null check * Re-added resolve comments to two special functions * Added Voucher export from sdk * Improved input params for send function * Renamed InteractionCallback to InteractionBuilderFn * Improve with central function definition from interaction file * Improved atBlockId validator types * Strongly typed voucher intercept param * Improved signing function interface and minor refactoring * Refactored AcctFn function name * Refactored AccountFn name --------- Co-authored-by: mfbz --- .changeset/tame-pianos-doubt.md | 6 + packages/sdk/package.json | 1 + packages/sdk/readme.md | 444 +++++++++++------- packages/sdk/src/VERSION.js | 1 - packages/sdk/src/VERSION.ts | 3 + .../{account.test.js => account.test.ts} | 0 packages/sdk/src/account/account.ts | 57 ++- packages/sdk/src/block/block.js | 41 -- .../block.test.ts} | 0 packages/sdk/src/block/block.ts | 53 +++ ...events.test.js => build-arguments.test.ts} | 0 .../sdk/src/build/build-at-block-height.js | 23 - ....test.js => build-at-block-height.test.ts} | 6 +- .../sdk/src/build/build-at-block-height.ts | 24 + packages/sdk/src/build/build-at-block-id.js | 23 - ...k-id.test.js => build-at-block-id.test.ts} | 2 +- packages/sdk/src/build/build-at-block-id.ts | 32 ++ .../sdk/src/build/build-at-latest-block.js | 25 - ....test.js => build-at-latest-block.test.ts} | 0 .../sdk/src/build/build-at-latest-block.ts | 26 + .../sdk/src/build/build-authorizations.js | 14 - ...s.test.js => build-authorizations.test.ts} | 5 +- .../sdk/src/build/build-authorizations.ts | 48 ++ packages/sdk/src/build/build-get-account.js | 17 - ...ount.test.js => build-get-account.test.ts} | 2 +- packages/sdk/src/build/build-get-account.ts | 22 + .../sdk/src/build/build-get-block-header.js | 16 - ...test.js => build-get-block-header.test.ts} | 2 +- .../sdk/src/build/build-get-block-header.ts | 23 + packages/sdk/src/build/build-get-block.js | 16 - ...-block.test.js => build-get-block.test.ts} | 2 +- packages/sdk/src/build/build-get-block.ts | 23 + .../sdk/src/build/build-get-collection.js | 18 - ...n.test.js => build-get-collection.test.ts} | 2 +- .../sdk/src/build/build-get-collection.ts | 21 + .../build-get-events-at-block-height-range.js | 27 -- ...-get-events-at-block-height-range.test.ts} | 2 +- .../build-get-events-at-block-height-range.ts | 29 ++ .../build/build-get-events-at-block-ids.js | 20 - ... => build-get-events-at-block-ids.test.ts} | 2 +- .../build/build-get-events-at-block-ids.ts | 26 + packages/sdk/src/build/build-get-events.js | 23 - ...block.test.js => build-get-events.test.ts} | 0 packages/sdk/src/build/build-get-events.ts | 29 ++ .../sdk/src/build/build-get-latest-block.js | 19 - ...test.js => build-get-latest-block.test.ts} | 0 .../sdk/src/build/build-get-latest-block.ts | 31 ++ .../src/build/build-get-network-parameters.js | 10 - ...s => build-get-network-parameters.test.ts} | 2 +- .../src/build/build-get-network-parameters.ts | 19 + .../src/build/build-get-node-version-info.ts | 12 +- .../src/build/build-get-transaction-status.js | 17 - ...s => build-get-transaction-status.test.ts} | 2 +- .../src/build/build-get-transaction-status.ts | 24 + .../sdk/src/build/build-get-transaction.js | 17 - ....test.js => build-get-transaction.test.ts} | 2 +- .../sdk/src/build/build-get-transaction.ts | 21 + packages/sdk/src/build/build-limit.js | 6 - ...uild-limit.test.js => build-limit.test.ts} | 2 +- packages/sdk/src/build/build-limit.ts | 13 + packages/sdk/src/build/build-payer.js | 16 - ...uild-payer.test.js => build-payer.test.ts} | 4 +- packages/sdk/src/build/build-payer.ts | 22 + packages/sdk/src/build/build-ping.js | 5 - ...{build-ping.test.js => build-ping.test.ts} | 2 +- packages/sdk/src/build/build-ping.ts | 9 + packages/sdk/src/build/build-proposer.js | 6 - ...roposer.test.js => build-proposer.test.ts} | 4 +- packages/sdk/src/build/build-proposer.ts | 8 + packages/sdk/src/build/build-ref.js | 10 - .../{build-ref.test.js => build-ref.test.ts} | 2 +- packages/sdk/src/build/build-ref.ts | 15 + packages/sdk/src/build/build-script.js | 6 - ...ld-script.test.js => build-script.test.ts} | 2 +- packages/sdk/src/build/build-script.ts | 20 + .../sdk/src/build/build-subscribe-events.ts | 15 +- packages/sdk/src/build/build-transaction.js | 22 - ...tion.test.js => build-transaction.test.ts} | 2 +- packages/sdk/src/build/build-transaction.ts | 30 ++ packages/sdk/src/build/build-validator.js | 7 - .../build-validator.test.ts} | 0 packages/sdk/src/build/build-validator.ts | 12 + .../sdk/src/build/build-voucher-intercept.js | 5 - ...est.js => build-voucher-intercept.test.ts} | 0 .../sdk/src/build/build-voucher-intercept.ts | 13 + packages/sdk/src/build/build.js | 5 - .../build.test.ts} | 0 packages/sdk/src/build/build.ts | 17 + .../{contract.test.js => contract.test.ts} | 8 +- .../sdk/src/decode/{decode.js => decode.ts} | 202 ++++++-- .../decode/{sdk-decode.js => sdk-decode.ts} | 2 +- .../encode/{encode.test.js => encode.test.ts} | 0 .../sdk/src/interaction/interaction.test.ts | 18 +- packages/sdk/src/interaction/interaction.ts | 43 +- .../node-version-info/node-version-info.ts | 9 +- ...s.snap => resolve-signatures.test.ts.snap} | 9 +- ...ents.test.js => resolve-arguments.test.ts} | 8 +- ...olve-arguments.js => resolve-arguments.ts} | 22 +- ...adence.test.js => resolve-cadence.test.ts} | 4 +- ...{resolve-cadence.js => resolve-cadence.ts} | 27 +- ....test.js => resolve-compute-limit.test.ts} | 2 +- ...pute-limit.js => resolve-compute-limit.ts} | 5 +- ...js => resolve-final-normalization.test.ts} | 0 ...tion.js => resolve-final-normalization.ts} | 5 +- .../resolve-proposer-sequence-number.test.ts | 3 + ...js => resolve-proposer-sequence-number.ts} | 27 +- ...d.test.js => resolve-ref-block-id.test.ts} | 0 ...ef-block-id.js => resolve-ref-block-id.ts} | 15 +- ...res.test.js => resolve-signatures.test.ts} | 16 +- .../sdk/src/resolve/resolve-validators.js | 9 - .../src/resolve/resolve-validators.test.ts | 3 + .../sdk/src/resolve/resolve-validators.ts | 10 + .../src/resolve/resolve-voucher-intercept.js | 10 - ...t.js => resolve-voucher-intercept.test.ts} | 33 +- .../src/resolve/resolve-voucher-intercept.ts | 13 + .../src/resolve/{resolve.js => resolve.ts} | 87 ++-- packages/sdk/src/sdk.ts | 76 +-- packages/sdk/src/send/send.js | 40 -- .../src/send/{send.test.js => send.test.ts} | 0 packages/sdk/src/send/send.ts | 53 +++ .../sdk/src/test-utils/{index.js => index.ts} | 0 packages/sdk/src/test-utils/run.js | 5 - packages/sdk/src/test-utils/run.ts | 8 + ...gnable.test.js => encode-signable.test.ts} | 2 +- ...{encode-signable.js => encode-signable.ts} | 54 ++- packages/sdk/src/wallet-utils/index.js | 2 - packages/sdk/src/wallet-utils/index.ts | 2 + ...alidate-tx.test.js => validate-tx.test.ts} | 2 +- .../{validate-tx.js => validate-tx.ts} | 20 +- packages/typedefs/src/interaction.ts | 6 +- 130 files changed, 1537 insertions(+), 935 deletions(-) create mode 100644 .changeset/tame-pianos-doubt.md delete mode 100644 packages/sdk/src/VERSION.js create mode 100644 packages/sdk/src/VERSION.ts rename packages/sdk/src/account/{account.test.js => account.test.ts} (100%) delete mode 100644 packages/sdk/src/block/block.js rename packages/sdk/src/{build/build-arguments.test.js => block/block.test.ts} (100%) create mode 100644 packages/sdk/src/block/block.ts rename packages/sdk/src/build/{build-get-events.test.js => build-arguments.test.ts} (100%) delete mode 100644 packages/sdk/src/build/build-at-block-height.js rename packages/sdk/src/build/{build-at-block-height.test.js => build-at-block-height.test.ts} (60%) create mode 100644 packages/sdk/src/build/build-at-block-height.ts delete mode 100644 packages/sdk/src/build/build-at-block-id.js rename packages/sdk/src/build/{build-at-block-id.test.js => build-at-block-id.test.ts} (84%) create mode 100644 packages/sdk/src/build/build-at-block-id.ts delete mode 100644 packages/sdk/src/build/build-at-latest-block.js rename packages/sdk/src/build/{build-at-latest-block.test.js => build-at-latest-block.test.ts} (100%) create mode 100644 packages/sdk/src/build/build-at-latest-block.ts delete mode 100644 packages/sdk/src/build/build-authorizations.js rename packages/sdk/src/build/{build-authorizations.test.js => build-authorizations.test.ts} (85%) create mode 100644 packages/sdk/src/build/build-authorizations.ts delete mode 100644 packages/sdk/src/build/build-get-account.js rename packages/sdk/src/build/{build-get-account.test.js => build-get-account.test.ts} (92%) create mode 100644 packages/sdk/src/build/build-get-account.ts delete mode 100644 packages/sdk/src/build/build-get-block-header.js rename packages/sdk/src/build/{build-get-block-header.test.js => build-get-block-header.test.ts} (91%) create mode 100644 packages/sdk/src/build/build-get-block-header.ts delete mode 100644 packages/sdk/src/build/build-get-block.js rename packages/sdk/src/build/{build-get-block.test.js => build-get-block.test.ts} (92%) create mode 100644 packages/sdk/src/build/build-get-block.ts delete mode 100644 packages/sdk/src/build/build-get-collection.js rename packages/sdk/src/build/{build-get-collection.test.js => build-get-collection.test.ts} (86%) create mode 100644 packages/sdk/src/build/build-get-collection.ts delete mode 100644 packages/sdk/src/build/build-get-events-at-block-height-range.js rename packages/sdk/src/build/{build-get-events-at-block-height-range.test.js => build-get-events-at-block-height-range.test.ts} (96%) create mode 100644 packages/sdk/src/build/build-get-events-at-block-height-range.ts delete mode 100644 packages/sdk/src/build/build-get-events-at-block-ids.js rename packages/sdk/src/build/{build-get-events-at-block-ids.test.js => build-get-events-at-block-ids.test.ts} (98%) create mode 100644 packages/sdk/src/build/build-get-events-at-block-ids.ts delete mode 100644 packages/sdk/src/build/build-get-events.js rename packages/sdk/src/build/{build-get-latest-block.test.js => build-get-events.test.ts} (100%) create mode 100644 packages/sdk/src/build/build-get-events.ts delete mode 100644 packages/sdk/src/build/build-get-latest-block.js rename packages/sdk/src/build/{build-validator.test.js => build-get-latest-block.test.ts} (100%) create mode 100644 packages/sdk/src/build/build-get-latest-block.ts delete mode 100644 packages/sdk/src/build/build-get-network-parameters.js rename packages/sdk/src/build/{build-get-network-parameters.test.js => build-get-network-parameters.test.ts} (98%) create mode 100644 packages/sdk/src/build/build-get-network-parameters.ts delete mode 100644 packages/sdk/src/build/build-get-transaction-status.js rename packages/sdk/src/build/{build-get-transaction-status.test.js => build-get-transaction-status.test.ts} (98%) create mode 100644 packages/sdk/src/build/build-get-transaction-status.ts delete mode 100644 packages/sdk/src/build/build-get-transaction.js rename packages/sdk/src/build/{build-get-transaction.test.js => build-get-transaction.test.ts} (86%) create mode 100644 packages/sdk/src/build/build-get-transaction.ts delete mode 100644 packages/sdk/src/build/build-limit.js rename packages/sdk/src/build/{build-limit.test.js => build-limit.test.ts} (87%) create mode 100644 packages/sdk/src/build/build-limit.ts delete mode 100644 packages/sdk/src/build/build-payer.js rename packages/sdk/src/build/{build-payer.test.js => build-payer.test.ts} (82%) create mode 100644 packages/sdk/src/build/build-payer.ts delete mode 100644 packages/sdk/src/build/build-ping.js rename packages/sdk/src/build/{build-ping.test.js => build-ping.test.ts} (85%) create mode 100644 packages/sdk/src/build/build-ping.ts delete mode 100644 packages/sdk/src/build/build-proposer.js rename packages/sdk/src/build/{build-proposer.test.js => build-proposer.test.ts} (81%) create mode 100644 packages/sdk/src/build/build-proposer.ts delete mode 100644 packages/sdk/src/build/build-ref.js rename packages/sdk/src/build/{build-ref.test.js => build-ref.test.ts} (88%) create mode 100644 packages/sdk/src/build/build-ref.ts delete mode 100644 packages/sdk/src/build/build-script.js rename packages/sdk/src/build/{build-script.test.js => build-script.test.ts} (89%) create mode 100644 packages/sdk/src/build/build-script.ts delete mode 100644 packages/sdk/src/build/build-transaction.js rename packages/sdk/src/build/{build-transaction.test.js => build-transaction.test.ts} (88%) create mode 100644 packages/sdk/src/build/build-transaction.ts delete mode 100644 packages/sdk/src/build/build-validator.js rename packages/sdk/src/{resolve/resolve-final-normalization.test.js => build/build-validator.test.ts} (100%) create mode 100644 packages/sdk/src/build/build-validator.ts delete mode 100644 packages/sdk/src/build/build-voucher-intercept.js rename packages/sdk/src/build/{build-voucher-intercept.test.js => build-voucher-intercept.test.ts} (100%) create mode 100644 packages/sdk/src/build/build-voucher-intercept.ts delete mode 100644 packages/sdk/src/build/build.js rename packages/sdk/src/{resolve/resolve-proposer-sequence-number.test.js => build/build.test.ts} (100%) create mode 100644 packages/sdk/src/build/build.ts rename packages/sdk/src/{contract.test.js => contract.test.ts} (89%) rename packages/sdk/src/decode/{decode.js => decode.ts} (59%) rename packages/sdk/src/decode/{sdk-decode.js => sdk-decode.ts} (86%) rename packages/sdk/src/encode/{encode.test.js => encode.test.ts} (100%) rename packages/sdk/src/resolve/__snapshots__/{resolve-signatures.test.js.snap => resolve-signatures.test.ts.snap} (95%) rename packages/sdk/src/resolve/{resolve-arguments.test.js => resolve-arguments.test.ts} (93%) rename packages/sdk/src/resolve/{resolve-arguments.js => resolve-arguments.ts} (63%) rename packages/sdk/src/resolve/{resolve-cadence.test.js => resolve-cadence.test.ts} (97%) rename packages/sdk/src/resolve/{resolve-cadence.js => resolve-cadence.ts} (69%) rename packages/sdk/src/resolve/{resolve-compute-limit.test.js => resolve-compute-limit.test.ts} (95%) rename packages/sdk/src/resolve/{resolve-compute-limit.js => resolve-compute-limit.ts} (84%) rename packages/sdk/src/resolve/{resolve-validators.test.js => resolve-final-normalization.test.ts} (100%) rename packages/sdk/src/resolve/{resolve-final-normalization.js => resolve-final-normalization.ts} (55%) create mode 100644 packages/sdk/src/resolve/resolve-proposer-sequence-number.test.ts rename packages/sdk/src/resolve/{resolve-proposer-sequence-number.js => resolve-proposer-sequence-number.ts} (60%) rename packages/sdk/src/resolve/{resolve-ref-block-id.test.js => resolve-ref-block-id.test.ts} (100%) rename packages/sdk/src/resolve/{resolve-ref-block-id.js => resolve-ref-block-id.ts} (72%) rename packages/sdk/src/resolve/{resolve-signatures.test.js => resolve-signatures.test.ts} (85%) delete mode 100644 packages/sdk/src/resolve/resolve-validators.js create mode 100644 packages/sdk/src/resolve/resolve-validators.test.ts create mode 100644 packages/sdk/src/resolve/resolve-validators.ts delete mode 100644 packages/sdk/src/resolve/resolve-voucher-intercept.js rename packages/sdk/src/resolve/{resolve-voucher-intercept.test.js => resolve-voucher-intercept.test.ts} (76%) create mode 100644 packages/sdk/src/resolve/resolve-voucher-intercept.ts rename packages/sdk/src/resolve/{resolve.js => resolve.ts} (52%) delete mode 100644 packages/sdk/src/send/send.js rename packages/sdk/src/send/{send.test.js => send.test.ts} (100%) create mode 100644 packages/sdk/src/send/send.ts rename packages/sdk/src/test-utils/{index.js => index.ts} (100%) delete mode 100644 packages/sdk/src/test-utils/run.js create mode 100644 packages/sdk/src/test-utils/run.ts rename packages/sdk/src/wallet-utils/{encode-signable.test.js => encode-signable.test.ts} (98%) rename packages/sdk/src/wallet-utils/{encode-signable.js => encode-signable.ts} (64%) delete mode 100644 packages/sdk/src/wallet-utils/index.js create mode 100644 packages/sdk/src/wallet-utils/index.ts rename packages/sdk/src/wallet-utils/{validate-tx.test.js => validate-tx.test.ts} (97%) rename packages/sdk/src/wallet-utils/{validate-tx.js => validate-tx.ts} (58%) diff --git a/.changeset/tame-pianos-doubt.md b/.changeset/tame-pianos-doubt.md new file mode 100644 index 000000000..f4d0f2b54 --- /dev/null +++ b/.changeset/tame-pianos-doubt.md @@ -0,0 +1,6 @@ +--- +"@onflow/typedefs": minor +"@onflow/sdk": minor +--- + +Refactored onflow/sdk package to improve TypeScript support diff --git a/packages/sdk/package.json b/packages/sdk/package.json index f4997dca4..7778f340d 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -45,6 +45,7 @@ "@onflow/rlp": "1.2.3", "@onflow/transport-http": "1.12.0", "@onflow/typedefs": "1.5.0", + "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", "@onflow/util-invariant": "1.2.4", diff --git a/packages/sdk/readme.md b/packages/sdk/readme.md index dd52105e9..b34d3200e 100644 --- a/packages/sdk/readme.md +++ b/packages/sdk/readme.md @@ -23,13 +23,13 @@ npm install --save @onflow/sdk Welcome, we're glad you're here. -The Flow JS-SDK is a relatively low-level suite of tools that allow JavaScript applications to interact with the Flow Blockchain. +The Flow JS-SDK is a relatively low-level suite of tools that allow JavaScript and TypeScript applications to interact with the Flow Blockchain. In doing so, the Flow JS-SDK employs several concepts which empower developers to create, and operate upon what we call _Interactions_ that can be sent to the Flow Blockchain, and what we call _Responses_ that are returned from the Flow Blockchain. Interactions have a Type, which tells the Flow JS-SDK itself how to react to preparing, operating upon and sending this specific interaction. Types of Interactions include, Get Account, Execute Script, Execute Transaction, Get Events, Get Latest Block and Get Transaction Status. -Further in this document we will outline how to create such Interactions for use in your JavaScript applications, and how to deal with the Responses that the Flow Blockchain returns. +Further in this document we will outline how to create such Interactions for use in your TypeScript or JavaScript applications, and how to deal with the Responses that the Flow Blockchain returns. ## Phases @@ -45,9 +45,9 @@ Build is the phase of your use of the Flow JS-SDK where you _Build_ up a specifi The Flow JS-SDK exposes what we call a _build_ function, and a suite of _builder_ functions. The build function consumes as its argument an array of builder functions within it. Each builder function consumes information that you know, and that you want to place into the interaction. -Example 1 - : Building an Execute Script Interaction -```javascript +Example 1: Building an Execute Script Interaction + +```typescript import * as sdk from "@onflow/sdk" const interaction = await sdk.build([ @@ -61,13 +61,13 @@ const interaction = await sdk.build([ In Example 1, we're composing an Execute Script Interaction, because we have built an interaction and specified a Script Cadence code within it using the sdk.script builder. -Example 2 - : Building an Execute Get Account Interaction -```javascript +Example 2: Building an Execute Get Account Interaction + +```typescript import * as sdk from "@onflow/sdk" const interaction = await sdk.build([ - sdk.getAccount("123ABC456DEF") + sdk.getAccount("0x123ABC456DEF") ]) ``` @@ -87,21 +87,21 @@ The builders for the Proposer, Payer and each Authorizer consume an _authorizati The Address for an Authorization corresponds to the address for the Flow Account this authorization represents. The Signing Function is a function which can produce a Signature for a transaction on behalf of the specified account. The keyId represents the id of the key on the Account which needs to be used to produce the Signature for a transaction. An Authorization also optionally takes a sequence number, which is the sequence number for the key corresponding to the keyId of the Flow Account this authorization represents, if this authorization is for a proposer. (Again, more on this later. Observe how we choose not to provide this piece of information in Example 3, this decision will be explained later). -Example 3 - : Building a Transaction Interaction -```javascript +Example 3: Building a Transaction Interaction + +```typescript import * as sdk from "@onflow/sdk" -const signingFunction = (...) => { - ... - return signature +const signingFunction = (message) => { + // Signing logic would go here + return { signature: "generated-signature" } } const interaction = await sdk.build([ sdk.transaction`transaction() { prepare(acct: AuthAccount) {} execute { log("Hello, Flow!") } }`, - sdk.payer(sdk.authorization("f8d6e0586b0a20c7", signingFunction, 0)), - sdk.proposer(sdk.authorization("f8d6e0586b0a20c7", signingFunction, 0)), - sdk.authorizations([sdk.authorization("f8d6e0586b0a20c7", signingFunction, 0)]), + sdk.payer(sdk.authorization("0xf8d6e0586b0a20c7", signingFunction, 0)), + sdk.proposer(sdk.authorization("0xf8d6e0586b0a20c7", signingFunction, 0)), + sdk.authorizations([sdk.authorization("0xf8d6e0586b0a20c7", signingFunction, 0)]), ]) ``` @@ -115,11 +115,11 @@ Some things, however, we don't know. For example, when developing your dApp, you This is where the _Resolve_ phase comes in. Resolve takes your built interaction containing all the information you do know and does its best to get it into a position where it can be sent to the Flow Blockchain. The Flow JS-SDK comes with several _resolver_ functions that your dApp can use to do just this. -Example 4 - : Building an Execute Script Interaction -```javascript +Example 4: Building an Execute Script Interaction + +```typescript import * as sdk from "@onflow/sdk" -import * as types from "@onflow/types" +import { t } from "@onflow/sdk" const builtInteraction = await sdk.build([ sdk.script` @@ -127,7 +127,7 @@ const builtInteraction = await sdk.build([ return "Hello, Flow!" } `, - sdk.args([ sdk.arg("Hello, Flow", types.String) ]) + sdk.args([ sdk.arg("Hello, Flow", t.String) ]) ]) const resolvedInteraction = await sdk.pipe(builtInteraction, [ @@ -138,23 +138,22 @@ const resolvedInteraction = await sdk.pipe(builtInteraction, [ In Example 4 we Build an Execute Script Interaction by using the script builder to specify a Cadence script and the args and arg builders to specify some arguments to pass into the Cadence Script. To Resolve this built interaction, we pipe'd the built interaction through an array of resolvers. The resolveParams resolver encoded the Cadence script into a format the Flow Blockchain accepts, and the resolveArguments resolver prepared the arguments into the correct encoding that the Flow Blockchain accepts. -Example 5 - : Building a Transaction Interaction -```javascript +Example 5: Building a Transaction Interaction + +```typescript import * as sdk from "@onflow/sdk" -import * as types from "@onflow/types" -const signingFunction = (...) => { - ... - return signature +const signingFunction = (message) => { + // Signing logic would go here + return { signature: "generated-signature" } } const builtInteraction = await sdk.build([ sdk.transaction`transaction(msg: String) { prepare(acct: AuthAccount) {} execute { log(msg) } }`, sdk.args([sdk.arg("Hello, Flow!", types.String)]), - sdk.payer(sdk.authorization("f8d6e0586b0a20c7", signingFunction, 0)), - sdk.proposer(sdk.authorization("f8d6e0586b0a20c7", signingFunction, 0)), - sdk.authorizations([sdk.authorization("f8d6e0586b0a20c7", signingFunction, 0)]), + sdk.payer(sdk.authorization("0xf8d6e0586b0a20c7", signingFunction, 0)), + sdk.proposer(sdk.authorization("0xf8d6e0586b0a20c7", signingFunction, 0)), + sdk.authorizations([sdk.authorization("0xf8d6e0586b0a20c7", signingFunction, 0)]), ]) const resolvedInteraction = await sdk.pipe(builtInteraction, [ @@ -175,11 +174,11 @@ After the Transaction Interaction is built, we pipe it through a series of resol Once an Interaction has been _Built_ and, if necessary, _Resolved_ it can then be _Sent_ to the Flow Blockchain. Fortunately, sending to the Flow Blockchain is simple. The Flow JS-SDK exposes a Send function which consumes an Interaction and some configuration, and returns a data structure called a _Response_ (more on this later). -Example 6 - : Sending an Execute Script Interaction -```javascript +Example 6: Sending an Execute Script Interaction + +```typescript import * as sdk from "@onflow/sdk" -import * as types from "@onflow/types" +import { t } from "@onflow/sdk" const builtInteraction = await sdk.build([ sdk.script` @@ -187,7 +186,7 @@ const builtInteraction = await sdk.build([ return "Hello, Flow!" } `, - sdk.args([ sdk.arg("Hello, Flow", types.String) ]) + sdk.args([ sdk.arg("Hello, Flow", t.String) ]) ]) const resolvedInteraction = await sdk.pipe(builtInteraction, [ @@ -195,6 +194,7 @@ const resolvedInteraction = await sdk.pipe(builtInteraction, [ sdk.resolveArguments, ]) +// The response contains the raw result from the access node const response = await sdk.send(resolvedInteraction, { node: "my-access-node-url" }) ``` @@ -215,11 +215,11 @@ For the available Interaction types, decoding responses for them produces values - Decoding a Get Transaction Status interaction returns a JavaScript object of relevant information about the status of a transaction. - Decoding a Get Latest Block interaction returns a JavaScript object of relevant information of the Latest Block. -Example 7 - : Decoding an Execute Script Interaction -```javascript +Example 7: Decoding an Execute Script Interaction + +```typescript import * as sdk from "@onflow/sdk" -import * as types from "@onflow/types" +import { t } from "@onflow/sdk" const builtInteraction = await sdk.build([ sdk.script` @@ -227,7 +227,7 @@ const builtInteraction = await sdk.build([ return int1 + int2 } `, - sdk.args([ sdk.arg(1, types.Int), sdk.arg(2, types.Int) ]) + sdk.args([ sdk.arg(1, t.Int), sdk.arg(2, t.Int) ]) ]) const resolvedInteraction = await sdk.pipe(builtInteraction, [ @@ -239,8 +239,8 @@ const response = await sdk.send(resolvedInteraction, { node: "my-access-node-url const decoded = await sdk.decode(response) -assert(3 === decoded) -assert(typeof decoded === "number") +console.assert(3 === decoded) +console.assert(typeof decoded === "number") ``` In Example 7 we illustrate how intuitively the decoded value returned from calling decode on the response returned from this Execute Script interaction must be the JavaScript number 3. This is because the Execute Script interaction contains Cadence code, which when executed with the included script arguments, adds the Cadence Integer 1 and Cadence Integer 2 together to return the Cadence Integer 3. Since there is no native concept of a Cadence Integer of value 3 in JavaScript, when this response is decoded, we intuitively expect the decoded value to be the JavaScript number 3. @@ -253,11 +253,11 @@ Custom Decoders are a concept available in the Flow JS-SDK which allows develope Custom Decoders are declared by passing a configuration object of key value pairs into the decode function. The keys included in this object correspond to the Cadence type you wish to provide a custom decoder for, and the value must be an asynchronous function which returns your desired JavaScript value for the type. The keys in this object can optionally be regex values declared by writing a regular expression between two forward slashes (ie: "/my-regex-exp/"). -Example 8 - : Using a Custom Decoder to decode an Execute Script interaction. -```javascript +Example 8: Using a Custom Decoder to decode an Execute Script interaction. + +```typescript import * as sdk from "@onflow/sdk" -import * as types from "@onflow/types" +import { t } from "@onflow/sdk" const builtInteraction = await sdk.build([ sdk.script` @@ -275,7 +275,7 @@ const builtInteraction = await sdk.build([ return Point(x: x, y: y) } `, - sdk.args([ sdk.arg(123, types.Int), sdk.arg(456, types.Int) ]) + sdk.args([ sdk.arg(123, t.Int), sdk.arg(456, t.Int) ]) ]) const resolvedInteraction = await sdk.pipe(builtInteraction, [ @@ -285,20 +285,31 @@ const resolvedInteraction = await sdk.pipe(builtInteraction, [ const response = await sdk.send(resolvedInteraction, { node: "my-access-node-url" }) -class Point { - constructor({ x, y }) { - this.x = x - this.y = y - this.created_at = Date.now() +// Create a custom type that we'll convert our Point into +interface PointInterface { + x: number; + y: number; +} + +class Point implements PointInterface { + x: number; + y: number; + created_at: number; + + constructor({ x, y }: PointInterface) { + this.x = x; + this.y = y; + this.created_at = Date.now(); } } -const decoded = await sdk.decode(response, { - "/Point/": async point => new Point(point) +const decoded: Point = await sdk.decode(response, { + "/Point/": async (point: PointInterface) => new Point(point) }) -assert(3 === decoded) -assert(typeof decoded === "number") +console.assert(decoded.x === 123); +console.assert(decoded.y === 456); +console.assert(decoded instanceof Point); ``` In Example 8 we declare an Execute Script interaction with Cadence code that returns a Point Cadence struct. If no custom decoders were declared, the returned Cadence Point struct would by default be decoded into a JavaScript object with key value pairs for its x and y variables. However, in this example we declare a custom decoder onto the call to decode which includes a regular expression that will match to the Point struct and return a new instance of the Point class that is declared just above. @@ -309,15 +320,24 @@ In Example 8 we declare an Execute Script interaction with Cadence code that ret Building an interaction produces an unresolved interaction. For example, to build a transaction interaction you must call `sdk.build([...])`, and pass in the sequence of builders you want to use to compose that transaction interaction. The example below highlights one way to build a transaction interaction: -```javascript +```typescript import * as sdk from "@onflow/sdk" -import * as types from "@onflow/types" +import { t } from "@onflow/sdk" + +const signingFunction = (message) => { + // Signing logic would go here + return { signature: "generated-signature" } +} + +// Optional: define a specific sequence number +const seqNum: number = 42 + const builtTxIx = await sdk.build([ sdk.transaction`transaction(msg: String) { prepare(acct: AuthAccount) {} execute { log(msg) } }`, - sdk.args([sdk.arg("Hello, Flow!", types.String)]), - sdk.payer(sdk.authorization("01", signingFunction, 0)), - sdk.proposer(sdk.authorization("01", signingFunction, 0, seqNum)), - sdk.authorizations([sdk.authorization("01", signingFunction, 0)]), + sdk.args([sdk.arg("Hello, Flow!", t.String)]), + sdk.payer(sdk.authorization("0x01", signingFunction, 0)), + sdk.proposer(sdk.authorization("0x01", signingFunction, 0, seqNum)), + sdk.authorizations([sdk.authorization("0x01", signingFunction, 0)]), ]) ``` @@ -325,8 +345,9 @@ const builtTxIx = await sdk.build([ Once a transaction interaction is built, it's still not quite ready to be sent to the Access Node. To further prepare it to be ready to be sent to the Access Node, you must resolve it by piping it through a series of resolvers. Resolvers are functions that consume an interaction and attempt to fill in or prepare any missing pieces of it to get it ready to be sent to the Access API. The example below highlights one way to resolve a transaction interaction: -```javascript +```typescript import * as sdk from "@onflow/sdk" + const resolvedTxIx = await sdk.pipe(builtTxIx, [ sdk.resolve([ sdk.resolveArguments, @@ -336,16 +357,25 @@ const resolvedTxIx = await sdk.pipe(builtTxIx, [ sdk.resolveRefBlockId({ node: "http://localhost:8080" }), sdk.resolveSignatures ]) -) +]) ``` ### Example: Sending A Transaction Interaction Now that your transaction interaction is resolved, it can be sent to an Access Node! To send it to an Access Node, you must call `sdk.send(...)` with that interaction, and a configuration object. To specify which Access Node to send your request to, you specify it in the _node_ parameter of the config object. For example, the code below shows how to send your transaction interaction to the Flow Emulator running on _localhost:8080_: -```javascript +```typescript import * as sdk from "@onflow/sdk" -const response = await sdk.send(resolvedTxIx, { node: "http://localhost:8080" }) + +const options = { + node: "http://localhost:8080" +} + +const response = await sdk.send(resolvedTxIx, options) + +// You can then decode the response to get the transaction ID +const txId: string = await sdk.decode(response) +console.log("Transaction ID:", txId) ``` The SDK additionally supplies builders to construct interactions of many different types to interact with the Access Node's various APIs. @@ -356,23 +386,36 @@ Please reference the provided example project `react-simple` for example code. As an extension, it is possible to intercept the voucher before sending a transaction. To do this, use `sdk.voucherIntercept(...)`. This argument is an arbitrary async function that receives a voucher object containing information about the transaction before it is sent. Within this, you can call `sdk.voucherToTxId(voucher)` to get the txId. Furthermore, you can call any API to record this txId before sending the transaction. If an error is thrown in this, the transaction sending process will be aborted. -```javascript +```typescript import * as sdk from "@onflow/sdk" +import { t } from "@onflow/sdk" + +// Example function to send transaction hash to your backend API +async function sendHashToBackend(txId: string) { + // Your backend API call logic here + console.log(`Sending hash ${txId} to backend`); +} + +// Define signing function +const signingFunction = () => ({ signature: "generated-signature" }); +const seqNum: number = 42; // Optional: define a specific sequence number + const response = await sdk.send( await sdk.resolve( await sdk.build([ sdk.transaction`transaction(msg: String) { prepare(acct: AuthAccount) {} execute { log(msg) } }`, sdk.args([sdk.arg("Hello, Flow!", types.String)]), - sdk.payer(sdk.authorization("01", signingFunction, 0)), - sdk.proposer(sdk.authorization("01", signingFunction, 0, seqNum)), - sdk.authorizations([sdk.authorization("01", signingFunction, 0)]), - sdk.voucherIntercept(async voucher => { - const txId = sdk.voucherToTxId(voucher) + sdk.payer(sdk.authorization("0x01", signingFunction, 0)), + sdk.proposer(sdk.authorization("0x01", signingFunction, 0, seqNum)), + sdk.authorizations([sdk.authorization("0x01", signingFunction, 0)]), + sdk.voucherIntercept(async (voucher: any) => { + const txId: string = sdk.voucherToTxId(voucher) - // you can make an async to your backend to keep track of the hash + // You can make an async call to your backend to keep track of the hash await sendHashToBackend(txId) - // could throw an error here if you wanted which would halt the transaction. + // Could throw an error here if you wanted which would halt the transaction. + // if (someCondition) throw new Error("Transaction aborted due to condition"); }), ]) ), { node: "http://localhost:8080" }) @@ -380,102 +423,185 @@ const response = await sdk.send( ### GetAccount Usage -```javascript +```typescript import * as sdk from "@onflow/sdk" -const response = await sdk.send(await sdk.build([ - sdk.getAccount(addr) -]), { node: "http://localhost:8080" }) + +// Build and resolve the interaction +const interaction = await sdk.build([ + sdk.getAccount("0xf8d6e0586b0a20c7") +]) + +// Send the interaction to the Access Node +const response = await sdk.send(interaction, { node: "http://localhost:8080" }) +const account = await sdk.decode(response) +console.log("Account balance:", account.balance) ``` ### GetEvents Usage -```javascript +```typescript import * as sdk from "@onflow/sdk" -const response = await sdk.send(await sdk.build([ + +// Event type and block range +const eventType: string = "A.1654653399040a61.FlowToken.TokensDeposited" +const startBlock: number = 10000 +const endBlock: number = 10100 + +// Build and resolve the interaction +const interaction = await sdk.build([ sdk.getEvents(eventType, startBlock, endBlock), -]), { node: "http://localhost:8080" }) +]) + +// Send the interaction to the Access Node +const response = await sdk.send(interaction, { node: "http://localhost:8080" }) +const events = await sdk.decode(response) +console.log(`Got ${events.length} events`) ``` ### GetLatestBlock Usage -```javascript +```typescript import * as sdk from "@onflow/sdk" -const response = await sdk.send(await sdk.build([ - sdk.getLatestBlock() -]), { node: "http://localhost:8080" }) + +// Build the interaction, specify whether to get sealed blocks or not +const interaction = await sdk.build([ + sdk.getLatestBlock(true) // true for sealed blocks, false for unsealed +]) + +// Send the interaction to the Access Node +const response = await sdk.send(interaction, { node: "http://localhost:8080" }) +const block = await sdk.decode(response) +console.log(`Latest block height: ${block.height}`) ``` ### GetTransactionStatus Usage -```javascript +```typescript import * as sdk from "@onflow/sdk" -const response = await sdk.send(await sdk.build([ + +// Transaction ID to check +const txId: string = "9dda49b2f2b1b9bc12d5cabe09f8a8cb49828c9c449574c1f46f3b3a5e5c0cb0" + +// Build the interaction +const interaction = await sdk.build([ sdk.getTransactionStatus(txId) -]), { node: "http://localhost:8080" }) +]) + +// Send the interaction to the Access Node +const response = await sdk.send(interaction, { node: "http://localhost:8080" }) +const status = await sdk.decode(response) +console.log(`Transaction status: ${status.statusString}`) ``` ### Ping Usage -```javascript +```typescript import * as sdk from "@onflow/sdk" -const response = await sdk.send(await sdk.build([ + +// Build the interaction +const interaction = await sdk.build([ sdk.ping() -]), { node: "http://localhost:8080" }) +]) + +// Send the interaction to the Access Node +const response = await sdk.send(interaction, { node: "http://localhost:8080" }) +const pingResult = await sdk.decode(response) +console.log(`Ping result: ${pingResult.tag}`) // Should output: Ping result: PONG ``` ### Script Usage -```javascript +```typescript import * as sdk from "@onflow/sdk" -import * as types from "@onflow/types" -const response = await sdk.send(await sdk.pipe(await sdk.build([ - sdk.args([sdk.arg("Hello Flow!", types.String)]), +import { t } from "@onflow/sdk" + +// Build the script interaction +const builtInteraction = await sdk.build([ + sdk.args([sdk.arg("Hello Flow!", t.String)]), sdk.script` pub fun main(msg: String): Int { log(msg) return 7 } `, -]), [ - sdk.resolve([ - sdk.resolveArguments, - sdk.resolveParams, - ]), -]), { node: "http://localhost:8080" }) +]) + +// Resolve the interaction with required resolvers +const resolvedInteraction = await sdk.pipe(builtInteraction, [ + sdk.resolveArguments, + sdk.resolveParams, +]) + +// Send the interaction to the Access Node +const response = await sdk.send(resolvedInteraction, { node: "http://localhost:8080" }) +// Decode the response to get the result (a number in this case) +const result: number = await sdk.decode(response) +console.log(`Script returned: ${result}`) // Should output: Script returned: 7 ``` ### Transaction Usage -```javascript +```typescript import * as sdk from "@onflow/sdk" -import * as types from "@onflow/types" -const response = await sdk.send(await sdk.pipe(await sdk.build([ +import { t } from "@onflow/sdk" + +// Define a signing function +const signingFunction = () => ({ signature: "generated-signature" }) + +// Build the transaction interaction with all required components +const builtInteraction = await sdk.build([ sdk.transaction`transaction(msg: String) { prepare(acct: AuthAccount) {} execute { log(msg) } }`, - sdk.args([sdk.arg("Hello, Flow!", types.String)]), - sdk.payer(sdk.authorization("01", signingFunction, 0)), - sdk.proposer(sdk.authorization("01", signingFunction, 0)), - sdk.authorizations([sdk.authorization("01", signingFunction, 0)]), - sdk.voucherIntercept(async voucher => {}), // Optional -]), [ - sdk.resolve([ - sdk.resolveArguments, - sdk.resolveParams, - sdk.resolveAccounts, - sdk.resolveProposerSequenceNumber({ node: "http://localhost:8080" }), - sdk.resolveRefBlockId({ node: "http://localhost:8080" }), - sdk.resolveSignatures, - sdk.resolveVoucherIntercept, // Optional - ]), -]), { node: "http://localhost:8080" }) + sdk.args([sdk.arg("Hello, Flow!", t.String)]), + sdk.payer(sdk.authorization("0x01", signingFunction, 0)), + sdk.proposer(sdk.authorization("0x01", signingFunction, 0)), + sdk.authorizations([sdk.authorization("0x01", signingFunction, 0)]), + // Optional voucher intercept + sdk.voucherIntercept(async (voucher: any) => { + // Process the voucher before the transaction is sent + console.log("Processing voucher:", voucher) + }), +]) + +// Resolve the transaction with all required resolvers +const resolvedInteraction = await sdk.pipe(builtInteraction, [ + sdk.resolveArguments, + sdk.resolveParams, + sdk.resolveAccounts, + sdk.resolveProposerSequenceNumber({ node: "http://localhost:8080" }), + sdk.resolveRefBlockId({ node: "http://localhost:8080" }), + sdk.resolveSignatures, + // Optional resolver for voucher intercept + sdk.resolveVoucherIntercept, +]) + +// Send the transaction to the Access Node +const response = await sdk.send(resolvedInteraction, { node: "http://localhost:8080" }) + +// Decode the response to get the transaction ID +const txId: string = await sdk.decode(response) +console.log(`Transaction ID: ${txId}`) ``` ### Get Network Parameters Usage -``` javascript +```typescript import * as sdk from "@onflow/sdk" -const response = await sdk.send(await sdk.build([ + +// Build the interaction to get network parameters +const interaction = await sdk.build([ sdk.getNetworkParameters() -]), { node: "http://localhost:8080" }) +]) + +// Send the interaction to the Access Node +const response = await sdk.send(interaction, { node: "http://localhost:8080" }) + +// Decode the response to get network parameters +interface NetworkParameters { + chainId: string; +} + +const params: NetworkParameters = await sdk.decode(response) +console.log(`Chain ID: ${params.chainId}`) ``` ## Flow JS-SDK Exposes @@ -498,43 +624,43 @@ const response = await sdk.send(await sdk.build([ - [Builders](./src/build) - [`sdk.args` & `sdk.arg`](./src/build/build-arguments.ts) - - [`sdk.atBlockHeight`](./src/build/build-at-block-height.js) - - [`sdk.atBlockId`](./src/build/build-at-block-id.js) - - [`sdk.authorizations` & `authorization`](./src/build/build-authorizations.js) - - [`sdk.getAccount`](./src/build/build-get-account.js) - - [`sdk.getBlock`](./src/build/build-get-block.js) - - [`sdk.getBlockByHeight`](./src/build/build-get-block-by-height) - - [`sdk.getBlockById`](./src/build/build-get-block-by-id.js) - - [`sdk.getBlockHeader`](./src/build/build-get-block-header.js) - - [`sdk.getCollection`](./src/build/build-get-collection) - - [`sdk.getEvents`](./src/build/build-get-events.js) - - [`sdk.getEventsAtBlockHeightRange`](./src/build/build-get-events-at-block-height-range.js) - - [`sdk.getEventsAtBlockIds`](./src/build/build-get-events-at-block-ids.js) - - [`sdk.getLatestBlock`](./src/build/build-get-latest-block.js) - - [`sdk.getTransactionStatus`](./src/build/build-get-transaction-status.js) - - [`sdk.getTransaction`](./src/build/build-get-transaction.js) - - [`sdk.getNetworkParameters`](./src/build/build-get-network-parameters.js) - - [`sdk.invariant`](./src/build/build-invariant.js) - - [`sdk.limit`](./src/build/build-limit.js) - - [`sdk.payer`](./src/build/build-payer.js) - - [`sdk.ping`](./src/build/build-ping.js) - - [`sdk.voucherIntercept`](./src/build/build-voucher-intercept.js) - - [`sdk.proposer`](./src/build/build-proposer.js) - - [`sdk.ref`](./src/build/build-ref.js) - - [`sdk.script`](./src/build/build-script.js) - - [`sdk.transaction`](./src/build/build-transaction.js) - - [`sdk.validator`](./src/build/build-validator.js) + - [`sdk.atBlockHeight`](./src/build/build-at-block-height.ts) + - [`sdk.atBlockId`](./src/build/build-at-block-id.ts) + - [`sdk.authorizations` & `authorization`](./src/build/build-authorizations.ts) + - [`sdk.getAccount`](./src/build/build-get-account.ts) + - [`sdk.getBlock`](./src/build/build-get-block.ts) + - [`sdk.getBlockByHeight`](./src/build/build-get-block-by-height.ts) + - [`sdk.getBlockById`](./src/build/build-get-block-by-id.ts) + - [`sdk.getBlockHeader`](./src/build/build-get-block-header.ts) + - [`sdk.getCollection`](./src/build/build-get-collection.ts) + - [`sdk.getEvents`](./src/build/build-get-events.ts) + - [`sdk.getEventsAtBlockHeightRange`](./src/build/build-get-events-at-block-height-range.ts) + - [`sdk.getEventsAtBlockIds`](./src/build/build-get-events-at-block-ids.ts) + - [`sdk.getLatestBlock`](./src/build/build-get-latest-block.ts) + - [`sdk.getTransactionStatus`](./src/build/build-get-transaction-status.ts) + - [`sdk.getTransaction`](./src/build/build-get-transaction.ts) + - [`sdk.getNetworkParameters`](./src/build/build-get-network-parameters.ts) + - [`sdk.invariant`](./src/build/build-invariant.ts) + - [`sdk.limit`](./src/build/build-limit.ts) + - [`sdk.payer`](./src/build/build-payer.ts) + - [`sdk.ping`](./src/build/build-ping.ts) + - [`sdk.voucherIntercept`](./src/build/build-voucher-intercept.ts) + - [`sdk.proposer`](./src/build/build-proposer.ts) + - [`sdk.ref`](./src/build/build-ref.ts) + - [`sdk.script`](./src/build/build-script.ts) + - [`sdk.transaction`](./src/build/build-transaction.ts) + - [`sdk.validator`](./src/build/build-validator.ts) - [Resolvers](./src/resolve) - [`sdk.resolveAccounts`](./src/resolve/resolve-accounts.ts) - - [`sdk.resolveArguments`](./src/resolve/resolve-arguments.js) - - [`sdk.resolveCadence`](./src/resolve/resolve-cadence.js) - - [`sdk.resolveFinalNormalization`](./src/resolve/resolve-final-normalization.js) - - [`sdk.resolveVoucherIntercept`](./src/resolve/resolve-voucher-intercept.js) - - [`sdk.resolveProposerSequenceNumber`](./src/resolve/resolve-proposer-sequence-number.js) - - [`sdk.resolveRefBlockId`](./src/resolve/resolve-ref-block-id.js) + - [`sdk.resolveArguments`](./src/resolve/resolve-arguments.ts) + - [`sdk.resolveCadence`](./src/resolve/resolve-cadence.ts) + - [`sdk.resolveFinalNormalization`](./src/resolve/resolve-final-normalization.ts) + - [`sdk.resolveVoucherIntercept`](./src/resolve/resolve-voucher-intercept.ts) + - [`sdk.resolveProposerSequenceNumber`](./src/resolve/resolve-proposer-sequence-number.ts) + - [`sdk.resolveRefBlockId`](./src/resolve/resolve-ref-block-id.ts) - [`sdk.resolveSignatures`](./src/resolve/resolve-signatures.ts) - - [`sdk.resolveValidators`](./src/resolve/resolve-validators.js) + - [`sdk.resolveValidators`](./src/resolve/resolve-validators.ts) - [Other Utils](./src/) - [`sdk.voucherToTxId`](./src/resolve/voucher.ts) diff --git a/packages/sdk/src/VERSION.js b/packages/sdk/src/VERSION.js deleted file mode 100644 index 5883643f2..000000000 --- a/packages/sdk/src/VERSION.js +++ /dev/null @@ -1 +0,0 @@ -export const VERSION = PACKAGE_CURRENT_VERSION || "TESTVERSION" diff --git a/packages/sdk/src/VERSION.ts b/packages/sdk/src/VERSION.ts new file mode 100644 index 000000000..d9ff78b73 --- /dev/null +++ b/packages/sdk/src/VERSION.ts @@ -0,0 +1,3 @@ +declare const PACKAGE_CURRENT_VERSION: string | undefined + +export const VERSION: string = PACKAGE_CURRENT_VERSION || "TESTVERSION" diff --git a/packages/sdk/src/account/account.test.js b/packages/sdk/src/account/account.test.ts similarity index 100% rename from packages/sdk/src/account/account.test.js rename to packages/sdk/src/account/account.test.ts diff --git a/packages/sdk/src/account/account.ts b/packages/sdk/src/account/account.ts index 8dec7266c..e9bbf2d0f 100644 --- a/packages/sdk/src/account/account.ts +++ b/packages/sdk/src/account/account.ts @@ -1,29 +1,31 @@ -import {atBlockHeight} from "../build/build-at-block-height.js" -import {atBlockId} from "../build/build-at-block-id.js" -import {atLatestBlock} from "../build/build-at-latest-block.js" -import {getAccount} from "../build/build-get-account.js" -import {invariant} from "@onflow/util-invariant" -import {decodeResponse as decode} from "../decode/decode.js" -import {send} from "../send/send.js" import type {Account} from "@onflow/typedefs" +import {invariant} from "@onflow/util-invariant" +import {atBlockHeight} from "../build/build-at-block-height" +import {atBlockId} from "../build/build-at-block-id" +import {atLatestBlock} from "../build/build-at-latest-block" +import {getAccount} from "../build/build-get-account" +import {decodeResponse as decode} from "../decode/decode" +import {send} from "../send/send" + +interface AccountQueryOptions { + height?: number + id?: string + isSealed?: boolean +} /** * @description Returns the details of an account from their public address - * @param address - Address of the account - * @param queryOptions - Query parameters - * @param queryOptions.height - Block height to query - * @param queryOptions.id - Block ID to query - * @param queryOptions.isSealed - Block finality - * @param opts - Optional parameters + * @param address Address of the account + * @param queryOptions Query parameters + * @param queryOptions.height Block height to query + * @param queryOptions.id Block ID to query + * @param queryOptions.isSealed Block finality + * @param opts Optional parameters * @returns A promise that resolves to an account response */ export async function account( address: string, - { - height, - id, - isSealed, - }: {height?: number; id?: string; isSealed?: boolean} = {}, + {height, id, isSealed}: AccountQueryOptions = {}, opts?: object ): Promise { invariant( @@ -32,18 +34,21 @@ export async function account( ) // Get account by ID - if (id) - return await send([getAccount(address), atBlockId(id)], opts).then(decode) + if (id) { + const ix = await send([getAccount(address), atBlockId(id)], opts) + return decode(ix) + } // Get account by height - if (height) - return await send([getAccount(address), atBlockHeight(height)], opts).then( - decode - ) + if (height) { + const ix = await send([getAccount(address), atBlockHeight(height)], opts) + return decode(ix) + } // Get account by latest block - return await send( + const ix = await send( [getAccount(address), atLatestBlock(isSealed ?? false)], opts - ).then(decode) + ) + return decode(ix) } diff --git a/packages/sdk/src/block/block.js b/packages/sdk/src/block/block.js deleted file mode 100644 index 6cc92df8e..000000000 --- a/packages/sdk/src/block/block.js +++ /dev/null @@ -1,41 +0,0 @@ -import {send} from "../send/send.js" -import {getBlock} from "../build/build-get-block" -import {atBlockHeight} from "../build/build-at-block-height.js" -import {atBlockId} from "../build/build-at-block-id.js" -import {decodeResponse as decode} from "../decode/decode.js" -import {invariant} from "@onflow/util-invariant" - -/** - * @typedef {import("@onflow/typedefs").Block} Block - */ - -/** - * @description Returns the latest block (optionally sealed or not), by id, or by height - * @param {object} [queryOptions] - Query parameters - * @param {boolean} [queryOptions.sealed] - Whether to query for a sealed block - * @param {number} [queryOptions.height] - Block height to query - * @param {string} [queryOptions.id] - Block ID to query - * @param {object} [opts] - Optional parameters - * @returns {Promise} - A promise that resolves to a block response - */ -export function block({sealed = false, id, height} = {}, opts = {}) { - invariant( - !((sealed && id) || (sealed && height)), - `Method: block -- Cannot pass "sealed" with "id" or "height"` - ) - - invariant( - !(id && height), - `Method: block -- Cannot pass "id" and "height" simultaneously` - ) - - // Get block by ID - if (id) return send([getBlock(), atBlockId(id)], opts).then(decode) - - // Get block by height - if (height) - return send([getBlock(), atBlockHeight(height)], opts).then(decode) - - // Get latest block - return send([getBlock(sealed)], opts).then(decode) -} diff --git a/packages/sdk/src/build/build-arguments.test.js b/packages/sdk/src/block/block.test.ts similarity index 100% rename from packages/sdk/src/build/build-arguments.test.js rename to packages/sdk/src/block/block.test.ts diff --git a/packages/sdk/src/block/block.ts b/packages/sdk/src/block/block.ts new file mode 100644 index 000000000..d68676c0e --- /dev/null +++ b/packages/sdk/src/block/block.ts @@ -0,0 +1,53 @@ +import type {Block} from "@onflow/typedefs" +import {invariant} from "@onflow/util-invariant" +import {atBlockHeight} from "../build/build-at-block-height" +import {atBlockId} from "../build/build-at-block-id" +import {getBlock} from "../build/build-get-block" +import {decodeResponse as decode} from "../decode/decode" +import {send} from "../send/send" + +interface BlockQueryOptions { + sealed?: boolean + height?: number + id?: string +} + +/** + * @description Returns the latest block (optionally sealed or not), by id, or by height + * @param queryOptions Query parameters + * @param queryOptions.sealed Whether to query for a sealed block + * @param queryOptions.height Block height to query + * @param queryOptions.id Block ID to query + * @param opts Optional parameters + * @returns A promise that resolves to a block response + */ +export async function block( + {sealed = false, id, height}: BlockQueryOptions = {}, + opts: object = {} +): Promise { + invariant( + !((sealed && id) || (sealed && height)), + `Method: block -- Cannot pass "sealed" with "id" or "height"` + ) + + invariant( + !(id && height), + `Method: block -- Cannot pass "id" and "height" simultaneously` + ) + + // Get block by ID + if (id) { + const ix = await send([getBlock(), atBlockId(id)], opts) + return decode(ix) + } + + // Get block by height + if (height) { + const ix = await send([getBlock(), atBlockHeight(height)], opts) + return decode(ix) + } + + // Get latest block + const ix = await send([getBlock(sealed)], opts) + return decode(ix) +} diff --git a/packages/sdk/src/build/build-get-events.test.js b/packages/sdk/src/build/build-arguments.test.ts similarity index 100% rename from packages/sdk/src/build/build-get-events.test.js rename to packages/sdk/src/build/build-arguments.test.ts diff --git a/packages/sdk/src/build/build-at-block-height.js b/packages/sdk/src/build/build-at-block-height.js deleted file mode 100644 index 1a295287e..000000000 --- a/packages/sdk/src/build/build-at-block-height.js +++ /dev/null @@ -1,23 +0,0 @@ -import {pipe} from "../interaction/interaction" -import {validator} from "./build-validator.js" - -/** - * @description - A builder function that returns a partial interaction to a block at a specific height - * @param {number} height - The height of the block to get - * @returns {Function} - A partial interaction object - */ -export function atBlockHeight(height) { - return pipe([ - ix => { - ix.block.height = height - return ix - }, - validator(ix => { - if (typeof ix.block.isSealed === "boolean") - throw new Error("Unable to specify both block height and isSealed.") - if (ix.block.id) - throw new Error("Unable to specify both block height and block id.") - return ix - }), - ]) -} diff --git a/packages/sdk/src/build/build-at-block-height.test.js b/packages/sdk/src/build/build-at-block-height.test.ts similarity index 60% rename from packages/sdk/src/build/build-at-block-height.test.js rename to packages/sdk/src/build/build-at-block-height.test.ts index d30830bc1..2945c454a 100644 --- a/packages/sdk/src/build/build-at-block-height.test.js +++ b/packages/sdk/src/build/build-at-block-height.test.ts @@ -1,8 +1,8 @@ import {initInteraction} from "../interaction/interaction" -import {atBlockHeight} from "./build-at-block-height.js" +import {atBlockHeight} from "./build-at-block-height" -describe("Build At Block ID", () => { - test("At Block ID", async () => { +describe("Build At Block Height", () => { + test("At Block Height", async () => { const blockHeight = 123 const ix = await atBlockHeight(blockHeight)(initInteraction()) diff --git a/packages/sdk/src/build/build-at-block-height.ts b/packages/sdk/src/build/build-at-block-height.ts new file mode 100644 index 000000000..d0485668c --- /dev/null +++ b/packages/sdk/src/build/build-at-block-height.ts @@ -0,0 +1,24 @@ +import {pipe, InteractionBuilderFn} from "../interaction/interaction" +import {Interaction} from "@onflow/typedefs" +import {validator} from "./build-validator" + +/** + * @description A builder function that returns a partial interaction to a block at a specific height + * @param height The height of the block to get + * @returns A function that processes a partial interaction object + */ +export function atBlockHeight(height: number): InteractionBuilderFn { + return pipe([ + (ix: Interaction) => { + ix.block.height = height + return ix + }, + validator((ix: Interaction) => { + if (typeof ix.block.isSealed === "boolean") + throw new Error("Unable to specify both block height and isSealed.") + if (ix.block.id) + throw new Error("Unable to specify both block height and block id.") + return ix + }), + ]) +} diff --git a/packages/sdk/src/build/build-at-block-id.js b/packages/sdk/src/build/build-at-block-id.js deleted file mode 100644 index 581568d0b..000000000 --- a/packages/sdk/src/build/build-at-block-id.js +++ /dev/null @@ -1,23 +0,0 @@ -import {isGetAccount, pipe, Ok} from "../interaction/interaction" -import {validator} from "./build-validator.js" - -export function atBlockId(id) { - return pipe([ - ix => { - ix.block.id = id - return Ok(ix) - }, - validator((ix, {Ok, Bad}) => { - if (isGetAccount(ix)) - return Bad( - ix, - "Unable to specify a block id with a Get Account interaction." - ) - if (typeof ix.block.isSealed === "boolean") - return Bad(ix, "Unable to specify both block id and isSealed.") - if (ix.block.height) - return Bad(ix, "Unable to specify both block id and block height.") - return Ok(ix) - }), - ]) -} diff --git a/packages/sdk/src/build/build-at-block-id.test.js b/packages/sdk/src/build/build-at-block-id.test.ts similarity index 84% rename from packages/sdk/src/build/build-at-block-id.test.js rename to packages/sdk/src/build/build-at-block-id.test.ts index 71738f04b..82d0bf619 100644 --- a/packages/sdk/src/build/build-at-block-id.test.js +++ b/packages/sdk/src/build/build-at-block-id.test.ts @@ -1,5 +1,5 @@ import {initInteraction} from "../interaction/interaction" -import {atBlockId} from "./build-at-block-id.js" +import {atBlockId} from "./build-at-block-id" describe("Build At Block ID", () => { test("At Block ID", async () => { diff --git a/packages/sdk/src/build/build-at-block-id.ts b/packages/sdk/src/build/build-at-block-id.ts new file mode 100644 index 000000000..7d7ea30fc --- /dev/null +++ b/packages/sdk/src/build/build-at-block-id.ts @@ -0,0 +1,32 @@ +import { + isGetAccount, + pipe, + Ok as OkFn, + Bad as BadFn, + InteractionBuilderFn, +} from "../interaction/interaction" +import {validator} from "./build-validator" +import {Interaction} from "@onflow/typedefs" + +export function atBlockId(id: string): InteractionBuilderFn { + return pipe([ + (ix: Interaction) => { + ix.block.id = id + return OkFn(ix) + }, + validator( + (ix: Interaction, {Ok, Bad}: {Ok: typeof OkFn; Bad: typeof BadFn}) => { + if (isGetAccount(ix)) + return Bad( + ix, + "Unable to specify a block id with a Get Account interaction." + ) + if (typeof ix.block.isSealed === "boolean") + return Bad(ix, "Unable to specify both block id and isSealed.") + if (ix.block.height) + return Bad(ix, "Unable to specify both block id and block height.") + return Ok(ix) + } + ), + ]) +} diff --git a/packages/sdk/src/build/build-at-latest-block.js b/packages/sdk/src/build/build-at-latest-block.js deleted file mode 100644 index 038bf9959..000000000 --- a/packages/sdk/src/build/build-at-latest-block.js +++ /dev/null @@ -1,25 +0,0 @@ -import {pipe} from "../interaction/interaction" -import {validator} from "./build-validator" - -/** - * @description - A builder function that returns a partial interaction to query the latest block with the given finality state - * @param {boolean} [isSealed=false] - Block finality state, defaults to latest executed block ("soft-finality"), set to true for sealed blocks ("hard-finality") - * @returns {Function} - A partial interaction object - */ -export function atLatestBlock(isSealed = false) { - return pipe([ - ix => { - ix.block.isSealed = isSealed - return ix - }, - validator(ix => { - if (ix.block.id) - throw new Error("Unable to specify both block finality and block id.") - if (ix.block.height) - throw new Error( - "Unable to specify both block finality and block height." - ) - return ix - }), - ]) -} diff --git a/packages/sdk/src/build/build-at-latest-block.test.js b/packages/sdk/src/build/build-at-latest-block.test.ts similarity index 100% rename from packages/sdk/src/build/build-at-latest-block.test.js rename to packages/sdk/src/build/build-at-latest-block.test.ts diff --git a/packages/sdk/src/build/build-at-latest-block.ts b/packages/sdk/src/build/build-at-latest-block.ts new file mode 100644 index 000000000..115e5fe18 --- /dev/null +++ b/packages/sdk/src/build/build-at-latest-block.ts @@ -0,0 +1,26 @@ +import {pipe, InteractionBuilderFn} from "../interaction/interaction" +import {Interaction} from "@onflow/typedefs" +import {validator} from "./build-validator" + +/** + * @description A builder function that returns a partial interaction to query the latest block with the given finality state + * @param isSealed Block finality state, defaults to latest executed block ("soft-finality"), set to true for sealed blocks ("hard-finality") + * @returns A function that processes a partial interaction object + */ +export function atLatestBlock(isSealed = false): InteractionBuilderFn { + return pipe([ + (ix: Interaction) => { + ix.block.isSealed = isSealed + return ix + }, + validator((ix: Interaction) => { + if (ix.block.id) + throw new Error("Unable to specify both block finality and block id.") + if (ix.block.height) + throw new Error( + "Unable to specify both block finality and block height." + ) + return ix + }), + ]) +} diff --git a/packages/sdk/src/build/build-authorizations.js b/packages/sdk/src/build/build-authorizations.js deleted file mode 100644 index 64a5b4b64..000000000 --- a/packages/sdk/src/build/build-authorizations.js +++ /dev/null @@ -1,14 +0,0 @@ -import {TransactionRole} from "@onflow/typedefs" -import {pipe, prepAccount} from "../interaction/interaction" - -export function authorizations(ax = []) { - return pipe( - ax.map(authz => { - return prepAccount(authz, {role: TransactionRole.AUTHORIZER}) - }) - ) -} - -export function authorization(addr, signingFunction, keyId, sequenceNum) { - return {addr, signingFunction, keyId, sequenceNum} -} diff --git a/packages/sdk/src/build/build-authorizations.test.js b/packages/sdk/src/build/build-authorizations.test.ts similarity index 85% rename from packages/sdk/src/build/build-authorizations.test.js rename to packages/sdk/src/build/build-authorizations.test.ts index 6357f0b9b..c51d63134 100644 --- a/packages/sdk/src/build/build-authorizations.test.js +++ b/packages/sdk/src/build/build-authorizations.test.ts @@ -1,5 +1,5 @@ import {initInteraction} from "../interaction/interaction" -import {authorizations, authorization} from "./build-authorizations.js" +import {authorizations, authorization} from "./build-authorizations" describe("Build Authorizations", () => { test("build authorizer", async () => { @@ -9,7 +9,8 @@ describe("Build Authorizations", () => { ]) )(initInteraction()) - const authorizerAccount = ix.accounts[ix.authorizations] + const authorizerAccount = + ix.accounts[ix.authorizations as unknown as string] expect(authorizerAccount.addr).toEqual("0xabc123") expect(authorizerAccount.role).toEqual({ diff --git a/packages/sdk/src/build/build-authorizations.ts b/packages/sdk/src/build/build-authorizations.ts new file mode 100644 index 000000000..28c249e8a --- /dev/null +++ b/packages/sdk/src/build/build-authorizations.ts @@ -0,0 +1,48 @@ +import {InteractionAccount, TransactionRole} from "@onflow/typedefs" +import { + AccountAuthorization, + pipe, + prepAccount, +} from "../interaction/interaction" +import {Voucher} from "../encode/encode" + +interface SignableMessage { + message: string + addr: string + keyId: number | string + roles: { + proposer: boolean + authorizer: boolean + payer: boolean + } + voucher: Voucher +} + +interface SigningResult { + addr?: string + keyId?: number | string + signature: string +} + +type SigningFn = ( + signable?: SignableMessage +) => SigningResult | Promise + +export function authorizations(ax: Array = []) { + return pipe( + ax.map(authz => { + return prepAccount(authz, { + role: TransactionRole.AUTHORIZER, + }) + }) + ) +} + +export function authorization( + addr: string, + signingFunction: SigningFn, + keyId?: number | string, + sequenceNum?: number +): Partial { + return {addr, signingFunction, keyId, sequenceNum} +} diff --git a/packages/sdk/src/build/build-get-account.js b/packages/sdk/src/build/build-get-account.js deleted file mode 100644 index b25adf310..000000000 --- a/packages/sdk/src/build/build-get-account.js +++ /dev/null @@ -1,17 +0,0 @@ -import {pipe, makeGetAccount, Ok} from "../interaction/interaction" -import {sansPrefix} from "@onflow/util-address" - -/** - * @description - A builder function that returns the interaction to get an account by address - * @param {string} addr - The address of the account to getq - * @returns {Function} - An interaction object - */ -export function getAccount(addr) { - return pipe([ - makeGetAccount, - ix => { - ix.account.addr = sansPrefix(addr) - return Ok(ix) - }, - ]) -} diff --git a/packages/sdk/src/build/build-get-account.test.js b/packages/sdk/src/build/build-get-account.test.ts similarity index 92% rename from packages/sdk/src/build/build-get-account.test.js rename to packages/sdk/src/build/build-get-account.test.ts index 125d328df..c0575b8e7 100644 --- a/packages/sdk/src/build/build-get-account.test.js +++ b/packages/sdk/src/build/build-get-account.test.ts @@ -1,6 +1,6 @@ import {initInteraction} from "../interaction/interaction" import {sansPrefix, withPrefix} from "@onflow/util-address" -import {getAccount} from "./build-get-account.js" +import {getAccount} from "./build-get-account" const ADDRESS = "0xf117a8efa34ffd58" diff --git a/packages/sdk/src/build/build-get-account.ts b/packages/sdk/src/build/build-get-account.ts new file mode 100644 index 000000000..c45086dbd --- /dev/null +++ b/packages/sdk/src/build/build-get-account.ts @@ -0,0 +1,22 @@ +import {sansPrefix} from "@onflow/util-address" +import { + InteractionBuilderFn, + makeGetAccount, + Ok, + pipe, +} from "../interaction/interaction" + +/** + * @description A builder function that returns the interaction to get an account by address + * @param addr The address of the account to get + * @returns A function that processes an interaction object + */ +export function getAccount(addr: string): InteractionBuilderFn { + return pipe([ + makeGetAccount, + ix => { + ix.account.addr = sansPrefix(addr) + return Ok(ix) + }, + ]) +} diff --git a/packages/sdk/src/build/build-get-block-header.js b/packages/sdk/src/build/build-get-block-header.js deleted file mode 100644 index b803793ab..000000000 --- a/packages/sdk/src/build/build-get-block-header.js +++ /dev/null @@ -1,16 +0,0 @@ -import {pipe, Ok, makeGetBlockHeader} from "../interaction/interaction" - -/** - * @description - A builder function that returns the interaction to get a block header - * @param {boolean} [isSealed] - Whether or not the block should be sealed - * @returns {Function} - An interaction object - */ -export function getBlockHeader(isSealed = null) { - return pipe([ - makeGetBlockHeader, - ix => { - ix.block.isSealed = isSealed - return Ok(ix) - }, - ]) -} diff --git a/packages/sdk/src/build/build-get-block-header.test.js b/packages/sdk/src/build/build-get-block-header.test.ts similarity index 91% rename from packages/sdk/src/build/build-get-block-header.test.js rename to packages/sdk/src/build/build-get-block-header.test.ts index b82e09dfa..8d76c307c 100644 --- a/packages/sdk/src/build/build-get-block-header.test.js +++ b/packages/sdk/src/build/build-get-block-header.test.ts @@ -1,5 +1,5 @@ import {initInteraction, isGetBlockHeader} from "../interaction/interaction" -import {getBlockHeader} from "./build-get-block-header.js" +import {getBlockHeader} from "./build-get-block-header" describe("Build Get Block Header", () => { test("Get Block Header, isSealed = false", async () => { diff --git a/packages/sdk/src/build/build-get-block-header.ts b/packages/sdk/src/build/build-get-block-header.ts new file mode 100644 index 000000000..7144a181c --- /dev/null +++ b/packages/sdk/src/build/build-get-block-header.ts @@ -0,0 +1,23 @@ +import { + pipe, + Ok, + makeGetBlockHeader, + InteractionBuilderFn, +} from "../interaction/interaction" + +/** + * @description A builder function that returns the interaction to get a block header + * @param isSealed Whether or not the block should be sealed + * @returns A function that processes an interaction object + */ +export function getBlockHeader( + isSealed: boolean | null = null +): InteractionBuilderFn { + return pipe([ + makeGetBlockHeader, + ix => { + ix.block.isSealed = isSealed + return Ok(ix) + }, + ]) +} diff --git a/packages/sdk/src/build/build-get-block.js b/packages/sdk/src/build/build-get-block.js deleted file mode 100644 index 0f8604c74..000000000 --- a/packages/sdk/src/build/build-get-block.js +++ /dev/null @@ -1,16 +0,0 @@ -import {pipe, Ok, makeGetBlock} from "../interaction/interaction" - -/** - * @description - A builder function that returns the interaction to get the latest block - * @param {boolean} [isSealed] - Whether or not the block should be sealed - * @returns {Function} - An interaction object - */ -export function getBlock(isSealed = null) { - return pipe([ - makeGetBlock, - ix => { - ix.block.isSealed = isSealed - return Ok(ix) - }, - ]) -} diff --git a/packages/sdk/src/build/build-get-block.test.js b/packages/sdk/src/build/build-get-block.test.ts similarity index 92% rename from packages/sdk/src/build/build-get-block.test.js rename to packages/sdk/src/build/build-get-block.test.ts index 7d43a19f2..565efaca3 100644 --- a/packages/sdk/src/build/build-get-block.test.js +++ b/packages/sdk/src/build/build-get-block.test.ts @@ -1,5 +1,5 @@ import {initInteraction, isGetBlock} from "../interaction/interaction" -import {getBlock} from "./build-get-block.js" +import {getBlock} from "./build-get-block" describe("Build Get Block", () => { test("Get Block - isSealed = false", async () => { diff --git a/packages/sdk/src/build/build-get-block.ts b/packages/sdk/src/build/build-get-block.ts new file mode 100644 index 000000000..bcf9fda68 --- /dev/null +++ b/packages/sdk/src/build/build-get-block.ts @@ -0,0 +1,23 @@ +import { + pipe, + Ok, + makeGetBlock, + InteractionBuilderFn, +} from "../interaction/interaction" + +/** + * @description A builder function that returns the interaction to get the latest block + * @param isSealed Whether or not the block should be sealed + * @returns A function that processes an interaction object + */ +export function getBlock( + isSealed: boolean | null = null +): InteractionBuilderFn { + return pipe([ + makeGetBlock, + ix => { + ix.block.isSealed = isSealed + return Ok(ix) + }, + ]) +} diff --git a/packages/sdk/src/build/build-get-collection.js b/packages/sdk/src/build/build-get-collection.js deleted file mode 100644 index 96f0ca585..000000000 --- a/packages/sdk/src/build/build-get-collection.js +++ /dev/null @@ -1,18 +0,0 @@ -import {pipe, makeGetCollection} from "../interaction/interaction" - -/** - * @description - A builder function that returns all a collection containing a list of transaction ids by its collection id - * NOTE: - * - The block range provided must be from the current spork. All events emitted during past sporks is current unavailable. - * @param {string} [id] - The id of the collection to get - * @returns {Function} - An interaction object - */ -export function getCollection(id = null) { - return pipe([ - makeGetCollection, - ix => { - ix.collection.id = id - return ix - }, - ]) -} diff --git a/packages/sdk/src/build/build-get-collection.test.js b/packages/sdk/src/build/build-get-collection.test.ts similarity index 86% rename from packages/sdk/src/build/build-get-collection.test.js rename to packages/sdk/src/build/build-get-collection.test.ts index 8f227c893..1efe0f550 100644 --- a/packages/sdk/src/build/build-get-collection.test.js +++ b/packages/sdk/src/build/build-get-collection.test.ts @@ -1,5 +1,5 @@ import {initInteraction, isGetCollection} from "../interaction/interaction" -import {getCollection} from "./build-get-collection.js" +import {getCollection} from "./build-get-collection" describe("Build Get Collection", () => { test("Get Collection", async () => { diff --git a/packages/sdk/src/build/build-get-collection.ts b/packages/sdk/src/build/build-get-collection.ts new file mode 100644 index 000000000..b5397f0e7 --- /dev/null +++ b/packages/sdk/src/build/build-get-collection.ts @@ -0,0 +1,21 @@ +import { + pipe, + Ok, + makeGetCollection, + InteractionBuilderFn, +} from "../interaction/interaction" + +/** + * @description A builder function that returns the interaction to get a collection by ID + * @param id The ID of the collection to get + * @returns A function that processes an interaction object + */ +export function getCollection(id: string | null = null): InteractionBuilderFn { + return pipe([ + makeGetCollection, + ix => { + ix.collection.id = id + return Ok(ix) + }, + ]) +} diff --git a/packages/sdk/src/build/build-get-events-at-block-height-range.js b/packages/sdk/src/build/build-get-events-at-block-height-range.js deleted file mode 100644 index 569aa12e1..000000000 --- a/packages/sdk/src/build/build-get-events-at-block-height-range.js +++ /dev/null @@ -1,27 +0,0 @@ -import {pipe, Ok, makeGetEvents} from "../interaction/interaction" - -/** - * @description - A builder function that returns all instances of a particular event (by name) within a height range - * NOTE: - * - The block range provided must be from the current spork. - * - The block range provided must be 250 blocks or lower per request. - * @param {string} eventName - The name of the event to get - * @param {number} fromBlockHeight - The height of the block to start looking for events (inclusive) - * @param {number} toBlockHeight - The height of the block to stop looking for events (inclusive) - * @returns {Function} - An interaction object - */ -export function getEventsAtBlockHeightRange( - eventName, - fromBlockHeight, - toBlockHeight -) { - return pipe([ - makeGetEvents, - ix => { - ix.events.eventType = eventName - ix.events.start = fromBlockHeight - ix.events.end = toBlockHeight - return Ok(ix) - }, - ]) -} diff --git a/packages/sdk/src/build/build-get-events-at-block-height-range.test.js b/packages/sdk/src/build/build-get-events-at-block-height-range.test.ts similarity index 96% rename from packages/sdk/src/build/build-get-events-at-block-height-range.test.js rename to packages/sdk/src/build/build-get-events-at-block-height-range.test.ts index 06a9e0d08..9ce5b0084 100644 --- a/packages/sdk/src/build/build-get-events-at-block-height-range.test.js +++ b/packages/sdk/src/build/build-get-events-at-block-height-range.test.ts @@ -1,5 +1,5 @@ import {initInteraction, isGetEvents} from "../interaction/interaction" -import {getEventsAtBlockHeightRange} from "./build-get-events-at-block-height-range.js" +import {getEventsAtBlockHeightRange} from "./build-get-events-at-block-height-range" describe("Build Get Events At Block Height Range", () => { test("Get Events At Block Height Range", async () => { diff --git a/packages/sdk/src/build/build-get-events-at-block-height-range.ts b/packages/sdk/src/build/build-get-events-at-block-height-range.ts new file mode 100644 index 000000000..85a019597 --- /dev/null +++ b/packages/sdk/src/build/build-get-events-at-block-height-range.ts @@ -0,0 +1,29 @@ +import { + pipe, + Ok, + makeGetEvents, + InteractionBuilderFn, +} from "../interaction/interaction" + +/** + * @description A builder function that returns the interaction to get events at a block height range + * @param eventType The type of event to get + * @param startHeight The start height of the block range + * @param endHeight The end height of the block range + * @returns A function that processes an interaction object + */ +export function getEventsAtBlockHeightRange( + eventType: string, + startHeight: number, + endHeight: number +): InteractionBuilderFn { + return pipe([ + makeGetEvents, + ix => { + ix.events.eventType = eventType + ix.events.start = startHeight + ix.events.end = endHeight + return Ok(ix) + }, + ]) +} diff --git a/packages/sdk/src/build/build-get-events-at-block-ids.js b/packages/sdk/src/build/build-get-events-at-block-ids.js deleted file mode 100644 index 6fe534032..000000000 --- a/packages/sdk/src/build/build-get-events-at-block-ids.js +++ /dev/null @@ -1,20 +0,0 @@ -import {pipe, Ok, makeGetEvents} from "../interaction/interaction" - -/** - * @description - A builder function that returns all instances of a particular event (by name) within a set of blocks, specified by block ids - * NOTE: - * - The block range provided must be from the current spork. - * @param {string} eventName - The name of the event to get - * @param {number[]} blockIds - The ids of the blocks to look for events - * @returns {Function} - An interaction object - */ -export function getEventsAtBlockIds(eventName, blockIds = []) { - return pipe([ - makeGetEvents, - ix => { - ix.events.eventType = eventName - ix.events.blockIds = blockIds - return Ok(ix) - }, - ]) -} diff --git a/packages/sdk/src/build/build-get-events-at-block-ids.test.js b/packages/sdk/src/build/build-get-events-at-block-ids.test.ts similarity index 98% rename from packages/sdk/src/build/build-get-events-at-block-ids.test.js rename to packages/sdk/src/build/build-get-events-at-block-ids.test.ts index 84f07a281..06faeab02 100644 --- a/packages/sdk/src/build/build-get-events-at-block-ids.test.js +++ b/packages/sdk/src/build/build-get-events-at-block-ids.test.ts @@ -1,5 +1,5 @@ import {initInteraction, isGetEvents} from "../interaction/interaction" -import {getEventsAtBlockIds} from "./build-get-events-at-block-ids.js" +import {getEventsAtBlockIds} from "./build-get-events-at-block-ids" describe("Build Get Events At Block Ids", () => { test("Get Events At Block Ids", async () => { diff --git a/packages/sdk/src/build/build-get-events-at-block-ids.ts b/packages/sdk/src/build/build-get-events-at-block-ids.ts new file mode 100644 index 000000000..1b2bc02d1 --- /dev/null +++ b/packages/sdk/src/build/build-get-events-at-block-ids.ts @@ -0,0 +1,26 @@ +import { + pipe, + Ok, + makeGetEvents, + InteractionBuilderFn, +} from "../interaction/interaction" + +/** + * @description A builder function that returns the interaction to get events at specific block IDs + * @param eventType The type of event to get + * @param blockIds The block IDs to get events from + * @returns A function that processes an interaction object + */ +export function getEventsAtBlockIds( + eventType: string, + blockIds: string[] +): InteractionBuilderFn { + return pipe([ + makeGetEvents, + ix => { + ix.events.eventType = eventType + ix.events.blockIds = blockIds + return Ok(ix) + }, + ]) +} diff --git a/packages/sdk/src/build/build-get-events.js b/packages/sdk/src/build/build-get-events.js deleted file mode 100644 index f338524e3..000000000 --- a/packages/sdk/src/build/build-get-events.js +++ /dev/null @@ -1,23 +0,0 @@ -import {pipe, Ok, makeGetEvents} from "../interaction/interaction" -import * as logger from "@onflow/util-logger" - -export function getEvents(eventType, start, end) { - if (typeof start !== "undefined" || typeof end !== "undefined") { - logger.log.deprecate({ - pkg: "FCL/SDK", - subject: "Passing a start and end into getEvents", - transition: - "https://github.com/onflow/flow-js-sdk/blob/master/packages/sdk/TRANSITIONS.md#0005-deprecate-start-end-get-events-builder", - }) - } - - return pipe([ - makeGetEvents, - ix => { - ix.events.eventType = eventType - ix.events.start = start - ix.events.end = end - return Ok(ix) - }, - ]) -} diff --git a/packages/sdk/src/build/build-get-latest-block.test.js b/packages/sdk/src/build/build-get-events.test.ts similarity index 100% rename from packages/sdk/src/build/build-get-latest-block.test.js rename to packages/sdk/src/build/build-get-events.test.ts diff --git a/packages/sdk/src/build/build-get-events.ts b/packages/sdk/src/build/build-get-events.ts new file mode 100644 index 000000000..c70f16d44 --- /dev/null +++ b/packages/sdk/src/build/build-get-events.ts @@ -0,0 +1,29 @@ +import { + pipe, + Ok, + makeGetEvents, + InteractionBuilderFn, +} from "../interaction/interaction" + +/** + * @description A builder function that returns the interaction to get events + * @param eventType The type of event to get + * @param start The start block ID or height + * @param end The end block ID or height + * @returns A function that processes an interaction object + */ +export function getEvents( + eventType: string, + start: number, + end: number +): InteractionBuilderFn { + return pipe([ + makeGetEvents, + ix => { + ix.events.eventType = eventType + ix.events.start = start + ix.events.end = end + return Ok(ix) + }, + ]) +} diff --git a/packages/sdk/src/build/build-get-latest-block.js b/packages/sdk/src/build/build-get-latest-block.js deleted file mode 100644 index 005a73557..000000000 --- a/packages/sdk/src/build/build-get-latest-block.js +++ /dev/null @@ -1,19 +0,0 @@ -import {log} from "@onflow/util-logger" -import {pipe, Ok, makeGetLatestBlock} from "../interaction/interaction" - -export function getLatestBlock(isSealed = false) { - log.deprecate({ - pkg: "FCL/SDK", - subject: "The getLatestBlock builder", - transition: - "https://github.com/onflow/flow-js-sdk/blob/master/packages/sdk/TRANSITIONS.md#0006-deprecate-get-latest-block-builder", - }) - - return pipe([ - makeGetLatestBlock, - ix => { - ix.block.isSealed = isSealed - return Ok(ix) - }, - ]) -} diff --git a/packages/sdk/src/build/build-validator.test.js b/packages/sdk/src/build/build-get-latest-block.test.ts similarity index 100% rename from packages/sdk/src/build/build-validator.test.js rename to packages/sdk/src/build/build-get-latest-block.test.ts diff --git a/packages/sdk/src/build/build-get-latest-block.ts b/packages/sdk/src/build/build-get-latest-block.ts new file mode 100644 index 000000000..7414cc1e0 --- /dev/null +++ b/packages/sdk/src/build/build-get-latest-block.ts @@ -0,0 +1,31 @@ +import {log} from "@onflow/util-logger" +import { + pipe, + Ok, + makeGetBlock, + InteractionBuilderFn, +} from "../interaction/interaction" + +/** + * @description A builder function that returns the interaction to get the latest block + * @param isSealed Whether or not the block should be sealed + * @returns A function that processes an interaction object + */ +export function getLatestBlock( + isSealed: boolean = false +): InteractionBuilderFn { + log.deprecate({ + pkg: "FCL/SDK", + subject: "The getLatestBlock builder", + transition: + "https://github.com/onflow/flow-js-sdk/blob/master/packages/sdk/TRANSITIONS.md#0006-deprecate-get-latest-block-builder", + }) + + return pipe([ + makeGetBlock, + ix => { + ix.block.isSealed = isSealed + return Ok(ix) + }, + ]) +} diff --git a/packages/sdk/src/build/build-get-network-parameters.js b/packages/sdk/src/build/build-get-network-parameters.js deleted file mode 100644 index 760ba7a91..000000000 --- a/packages/sdk/src/build/build-get-network-parameters.js +++ /dev/null @@ -1,10 +0,0 @@ -import {pipe, Ok, makeGetNetworkParameters} from "../interaction/interaction" - -export function getNetworkParameters() { - return pipe([ - makeGetNetworkParameters, - ix => { - return Ok(ix) - }, - ]) -} diff --git a/packages/sdk/src/build/build-get-network-parameters.test.js b/packages/sdk/src/build/build-get-network-parameters.test.ts similarity index 98% rename from packages/sdk/src/build/build-get-network-parameters.test.js rename to packages/sdk/src/build/build-get-network-parameters.test.ts index ef46a6ce8..86b442107 100644 --- a/packages/sdk/src/build/build-get-network-parameters.test.js +++ b/packages/sdk/src/build/build-get-network-parameters.test.ts @@ -2,7 +2,7 @@ import { initInteraction, isGetNetworkParameters, } from "../interaction/interaction" -import {getNetworkParameters} from "./build-get-network-parameters.js" +import {getNetworkParameters} from "./build-get-network-parameters" describe("Build Get Network Parameters", () => { test("Get Network Parameters", async () => { diff --git a/packages/sdk/src/build/build-get-network-parameters.ts b/packages/sdk/src/build/build-get-network-parameters.ts new file mode 100644 index 000000000..38dc74994 --- /dev/null +++ b/packages/sdk/src/build/build-get-network-parameters.ts @@ -0,0 +1,19 @@ +import { + pipe, + makeGetNetworkParameters, + Ok, + InteractionBuilderFn, +} from "../interaction/interaction" + +/** + * @description A builder function that returns the interaction to get network parameters + * @returns A function that processes an interaction object + */ +export function getNetworkParameters(): InteractionBuilderFn { + return pipe([ + makeGetNetworkParameters, + ix => { + return Ok(ix) + }, + ]) +} diff --git a/packages/sdk/src/build/build-get-node-version-info.ts b/packages/sdk/src/build/build-get-node-version-info.ts index 059fe4072..e9c8aed4c 100644 --- a/packages/sdk/src/build/build-get-node-version-info.ts +++ b/packages/sdk/src/build/build-get-node-version-info.ts @@ -1,9 +1,15 @@ -import {Ok, makeGetNodeVerionInfo, pipe} from "../interaction/interaction" +import { + Ok, + makeGetNodeVerionInfo, + pipe, + InteractionBuilderFn, +} from "../interaction/interaction" /** - * A builder function for the Get Node Version Info interaction + * @description A builder function for the Get Node Version Info interaction + * @returns An interaction object */ -export function getNodeVersionInfo(): Function { +export function getNodeVersionInfo(): InteractionBuilderFn { return pipe([ makeGetNodeVerionInfo, ix => { diff --git a/packages/sdk/src/build/build-get-transaction-status.js b/packages/sdk/src/build/build-get-transaction-status.js deleted file mode 100644 index adb4b6806..000000000 --- a/packages/sdk/src/build/build-get-transaction-status.js +++ /dev/null @@ -1,17 +0,0 @@ -import {pipe, Ok, makeGetTransactionStatus} from "../interaction/interaction" - -/** - * @description - A builder function that returns the status of transaction - * NOTE: The transactionID provided must be from the current spork. - * @param {string} transactionId - The id of the transaction to get status - * @returns {Function} - An interaction object - */ -export function getTransactionStatus(transactionId) { - return pipe([ - makeGetTransactionStatus, - ix => { - ix.transaction.id = transactionId - return Ok(ix) - }, - ]) -} diff --git a/packages/sdk/src/build/build-get-transaction-status.test.js b/packages/sdk/src/build/build-get-transaction-status.test.ts similarity index 98% rename from packages/sdk/src/build/build-get-transaction-status.test.js rename to packages/sdk/src/build/build-get-transaction-status.test.ts index 75496b8fe..b01ccdae1 100644 --- a/packages/sdk/src/build/build-get-transaction-status.test.js +++ b/packages/sdk/src/build/build-get-transaction-status.test.ts @@ -2,7 +2,7 @@ import { initInteraction, isGetTransactionStatus, } from "../interaction/interaction" -import {getTransactionStatus} from "./build-get-transaction-status.js" +import {getTransactionStatus} from "./build-get-transaction-status" describe("Build Get Transaction Status", () => { test("Get Transaction Status", async () => { diff --git a/packages/sdk/src/build/build-get-transaction-status.ts b/packages/sdk/src/build/build-get-transaction-status.ts new file mode 100644 index 000000000..555854140 --- /dev/null +++ b/packages/sdk/src/build/build-get-transaction-status.ts @@ -0,0 +1,24 @@ +import { + pipe, + Ok, + makeGetTransactionStatus, + InteractionBuilderFn, +} from "../interaction/interaction" + +/** + * @description A builder function that returns the status of transaction + * NOTE: The transactionID provided must be from the current spork. + * @param transactionId The id of the transaction to get status + * @returns An interaction object + */ +export function getTransactionStatus( + transactionId: string +): InteractionBuilderFn { + return pipe([ + makeGetTransactionStatus, + ix => { + ix.transaction.id = transactionId + return Ok(ix) + }, + ]) +} diff --git a/packages/sdk/src/build/build-get-transaction.js b/packages/sdk/src/build/build-get-transaction.js deleted file mode 100644 index 4f559843d..000000000 --- a/packages/sdk/src/build/build-get-transaction.js +++ /dev/null @@ -1,17 +0,0 @@ -import {pipe, Ok, makeGetTransaction} from "../interaction/interaction" - -/** - * @description - A builder function that returns a transaction - * NOTE: The transactionID provided must be from the current spork. - * @param {string} transactionId - The id of the transaction to get - * @returns {Function} - An interaction object - */ -export function getTransaction(transactionId) { - return pipe([ - makeGetTransaction, - ix => { - ix.transaction.id = transactionId - return Ok(ix) - }, - ]) -} diff --git a/packages/sdk/src/build/build-get-transaction.test.js b/packages/sdk/src/build/build-get-transaction.test.ts similarity index 86% rename from packages/sdk/src/build/build-get-transaction.test.js rename to packages/sdk/src/build/build-get-transaction.test.ts index da9a22e4d..a3a5154f4 100644 --- a/packages/sdk/src/build/build-get-transaction.test.js +++ b/packages/sdk/src/build/build-get-transaction.test.ts @@ -1,5 +1,5 @@ import {initInteraction, isGetTransaction} from "../interaction/interaction" -import {getTransaction} from "./build-get-transaction.js" +import {getTransaction} from "./build-get-transaction" describe("Build Get Transaction", () => { test("Get Transaction", async () => { diff --git a/packages/sdk/src/build/build-get-transaction.ts b/packages/sdk/src/build/build-get-transaction.ts new file mode 100644 index 000000000..f467ee236 --- /dev/null +++ b/packages/sdk/src/build/build-get-transaction.ts @@ -0,0 +1,21 @@ +import { + InteractionBuilderFn, + Ok, + makeGetTransaction, + pipe, +} from "../interaction/interaction" + +/** + * @description A builder function that returns the interaction to get a transaction by ID + * @param id The ID of the transaction to get + * @returns A function that processes an interaction object + */ +export function getTransaction(id: string): InteractionBuilderFn { + return pipe([ + makeGetTransaction, + ix => { + ix.transaction.id = id + return Ok(ix) + }, + ]) +} diff --git a/packages/sdk/src/build/build-limit.js b/packages/sdk/src/build/build-limit.js deleted file mode 100644 index e13f0ccee..000000000 --- a/packages/sdk/src/build/build-limit.js +++ /dev/null @@ -1,6 +0,0 @@ -export function limit(computeLimit) { - return ix => { - ix.message.computeLimit = computeLimit - return ix - } -} diff --git a/packages/sdk/src/build/build-limit.test.js b/packages/sdk/src/build/build-limit.test.ts similarity index 87% rename from packages/sdk/src/build/build-limit.test.js rename to packages/sdk/src/build/build-limit.test.ts index 31d603760..de45db035 100644 --- a/packages/sdk/src/build/build-limit.test.js +++ b/packages/sdk/src/build/build-limit.test.ts @@ -1,5 +1,5 @@ import {initInteraction} from "../interaction/interaction" -import {limit} from "./build-limit.js" +import {limit} from "./build-limit" describe("Build Limit", () => { test("Build Limit", async () => { diff --git a/packages/sdk/src/build/build-limit.ts b/packages/sdk/src/build/build-limit.ts new file mode 100644 index 000000000..7c9fa5576 --- /dev/null +++ b/packages/sdk/src/build/build-limit.ts @@ -0,0 +1,13 @@ +import {InteractionBuilderFn} from "../interaction/interaction" + +/** + * @description A builder function that sets the compute limit for a transaction + * @param limit The compute limit to set + * @returns A function that processes an interaction object + */ +export function limit(limit: number): InteractionBuilderFn { + return ix => { + ix.message.computeLimit = limit + return ix + } +} diff --git a/packages/sdk/src/build/build-payer.js b/packages/sdk/src/build/build-payer.js deleted file mode 100644 index 0828b7ad9..000000000 --- a/packages/sdk/src/build/build-payer.js +++ /dev/null @@ -1,16 +0,0 @@ -import {TransactionRole} from "@onflow/typedefs" -import {pipe, prepAccount} from "../interaction/interaction" - -/** - * @description - A builder function that adds payer account(s) to a transaction - * @param {Function | Function[] | Object | Object[]} ax - An account address or array of account addresses - * @returns {Function} - An interaction object - */ -export function payer(ax = []) { - if (!Array.isArray(ax)) ax = [ax] - return pipe( - ax.map(authz => { - return prepAccount(authz, {role: TransactionRole.PAYER}) - }) - ) -} diff --git a/packages/sdk/src/build/build-payer.test.js b/packages/sdk/src/build/build-payer.test.ts similarity index 82% rename from packages/sdk/src/build/build-payer.test.js rename to packages/sdk/src/build/build-payer.test.ts index a60295323..c7f1df397 100644 --- a/packages/sdk/src/build/build-payer.test.js +++ b/packages/sdk/src/build/build-payer.test.ts @@ -1,5 +1,5 @@ import {initInteraction} from "../interaction/interaction" -import {payer} from "./build-payer.js" +import {payer} from "./build-payer" describe("Build Payer", () => { test("Build Payer", async () => { @@ -7,7 +7,7 @@ describe("Build Payer", () => { let ix = await (await payer(authz))(initInteraction()) - const payerAccount = ix.accounts[ix.payer] + const payerAccount = ix.accounts[ix.payer[0]] expect(payerAccount.addr).toEqual(authz.addr) expect(payerAccount.role).toEqual({ diff --git a/packages/sdk/src/build/build-payer.ts b/packages/sdk/src/build/build-payer.ts new file mode 100644 index 000000000..7380bd2c7 --- /dev/null +++ b/packages/sdk/src/build/build-payer.ts @@ -0,0 +1,22 @@ +import {TransactionRole} from "@onflow/typedefs" +import { + AccountAuthorization, + pipe, + prepAccount, +} from "../interaction/interaction" + +/** + * @description A builder function that adds payer account(s) to a transaction + * @param ax An account address or array of account addresses + * @returns A function that takes an interaction and returns a new interaction with the payer(s) added + */ +export function payer(ax: AccountAuthorization[] = []) { + if (!Array.isArray(ax)) ax = [ax] + return pipe( + ax.map(authz => { + return prepAccount(authz, { + role: TransactionRole.PAYER, + }) + }) + ) +} diff --git a/packages/sdk/src/build/build-ping.js b/packages/sdk/src/build/build-ping.js deleted file mode 100644 index 0379ff2cc..000000000 --- a/packages/sdk/src/build/build-ping.js +++ /dev/null @@ -1,5 +0,0 @@ -import {makePing} from "../interaction/interaction" - -export function ping() { - return makePing -} diff --git a/packages/sdk/src/build/build-ping.test.js b/packages/sdk/src/build/build-ping.test.ts similarity index 85% rename from packages/sdk/src/build/build-ping.test.js rename to packages/sdk/src/build/build-ping.test.ts index 97179a32a..0d2edfb63 100644 --- a/packages/sdk/src/build/build-ping.test.js +++ b/packages/sdk/src/build/build-ping.test.ts @@ -1,5 +1,5 @@ import {initInteraction, isPing} from "../interaction/interaction" -import {ping} from "./build-ping.js" +import {ping} from "./build-ping" describe("Build Ping", () => { test("Build Ping", async () => { diff --git a/packages/sdk/src/build/build-ping.ts b/packages/sdk/src/build/build-ping.ts new file mode 100644 index 000000000..635227a75 --- /dev/null +++ b/packages/sdk/src/build/build-ping.ts @@ -0,0 +1,9 @@ +import {makePing, InteractionBuilderFn} from "../interaction/interaction" + +/** + * @description A builder function that creates a ping interaction + * @returns A function that processes an interaction object + */ +export function ping(): InteractionBuilderFn { + return makePing +} diff --git a/packages/sdk/src/build/build-proposer.js b/packages/sdk/src/build/build-proposer.js deleted file mode 100644 index cef048725..000000000 --- a/packages/sdk/src/build/build-proposer.js +++ /dev/null @@ -1,6 +0,0 @@ -import {TransactionRole} from "@onflow/typedefs" -import {prepAccount} from "../interaction/interaction" - -export function proposer(authz) { - return prepAccount(authz, {role: TransactionRole.PROPOSER}) -} diff --git a/packages/sdk/src/build/build-proposer.test.js b/packages/sdk/src/build/build-proposer.test.ts similarity index 81% rename from packages/sdk/src/build/build-proposer.test.js rename to packages/sdk/src/build/build-proposer.test.ts index 7d1972f3b..c67d0ae10 100644 --- a/packages/sdk/src/build/build-proposer.test.js +++ b/packages/sdk/src/build/build-proposer.test.ts @@ -1,5 +1,5 @@ import {initInteraction} from "../interaction/interaction" -import {proposer} from "./build-proposer.js" +import {proposer} from "./build-proposer" describe("Build Proposer", () => { test("Build Proposer", async () => { @@ -7,7 +7,7 @@ describe("Build Proposer", () => { let ix = await (await proposer(authz))(initInteraction()) - const proposerAccount = ix.accounts[ix.proposer] + const proposerAccount = ix.accounts[ix.proposer!] expect(proposerAccount.addr).toEqual(authz.addr) expect(proposerAccount.role).toEqual({ diff --git a/packages/sdk/src/build/build-proposer.ts b/packages/sdk/src/build/build-proposer.ts new file mode 100644 index 000000000..09230279d --- /dev/null +++ b/packages/sdk/src/build/build-proposer.ts @@ -0,0 +1,8 @@ +import {TransactionRole} from "@onflow/typedefs" +import {AccountAuthorization, prepAccount} from "../interaction/interaction" + +export function proposer(authz: AccountAuthorization) { + return prepAccount(authz, { + role: TransactionRole.PROPOSER, + }) +} diff --git a/packages/sdk/src/build/build-ref.js b/packages/sdk/src/build/build-ref.js deleted file mode 100644 index bc1648715..000000000 --- a/packages/sdk/src/build/build-ref.js +++ /dev/null @@ -1,10 +0,0 @@ -import {pipe, Ok} from "../interaction/interaction" - -export function ref(refBlock) { - return pipe([ - ix => { - ix.message.refBlock = refBlock - return Ok(ix) - }, - ]) -} diff --git a/packages/sdk/src/build/build-ref.test.js b/packages/sdk/src/build/build-ref.test.ts similarity index 88% rename from packages/sdk/src/build/build-ref.test.js rename to packages/sdk/src/build/build-ref.test.ts index 2a6919636..73c2717ce 100644 --- a/packages/sdk/src/build/build-ref.test.js +++ b/packages/sdk/src/build/build-ref.test.ts @@ -1,5 +1,5 @@ import {initInteraction} from "../interaction/interaction" -import {ref} from "./build-ref.js" +import {ref} from "./build-ref" describe("Build Ref", () => { test("Build Ref", async () => { diff --git a/packages/sdk/src/build/build-ref.ts b/packages/sdk/src/build/build-ref.ts new file mode 100644 index 000000000..bca557dac --- /dev/null +++ b/packages/sdk/src/build/build-ref.ts @@ -0,0 +1,15 @@ +import {pipe, Ok, InteractionBuilderFn} from "../interaction/interaction" + +/** + * @description A builder function that sets the reference block for a transaction + * @param refBlock The reference block ID + * @returns A function that processes an interaction object + */ +export function ref(refBlock: string): InteractionBuilderFn { + return pipe([ + ix => { + ix.message.refBlock = refBlock + return Ok(ix) + }, + ]) +} diff --git a/packages/sdk/src/build/build-script.js b/packages/sdk/src/build/build-script.js deleted file mode 100644 index 9dbd8072f..000000000 --- a/packages/sdk/src/build/build-script.js +++ /dev/null @@ -1,6 +0,0 @@ -import {pipe, Ok, put, makeScript} from "../interaction/interaction" -import {template} from "@onflow/util-template" - -export function script(...args) { - return pipe([makeScript, put("ix.cadence", template(...args))]) -} diff --git a/packages/sdk/src/build/build-script.test.js b/packages/sdk/src/build/build-script.test.ts similarity index 89% rename from packages/sdk/src/build/build-script.test.js rename to packages/sdk/src/build/build-script.test.ts index fe3c92f61..9217c8a9c 100644 --- a/packages/sdk/src/build/build-script.test.js +++ b/packages/sdk/src/build/build-script.test.ts @@ -1,5 +1,5 @@ import {initInteraction, isScript} from "../interaction/interaction" -import {script} from "./build-script.js" +import {script} from "./build-script" describe("Build Script", () => { test("Build Script", async () => { diff --git a/packages/sdk/src/build/build-script.ts b/packages/sdk/src/build/build-script.ts new file mode 100644 index 000000000..d51c73c6b --- /dev/null +++ b/packages/sdk/src/build/build-script.ts @@ -0,0 +1,20 @@ +import { + pipe, + put, + makeScript, + InteractionBuilderFn, +} from "../interaction/interaction" +import {template} from "@onflow/util-template" + +/** + * @description A builder function that creates a script interaction + * @returns A function that processes an interaction object + */ +export function script( + ...args: [ + string | TemplateStringsArray | ((x?: unknown) => string), + ...unknown[], + ] +): InteractionBuilderFn { + return pipe([makeScript, put("ix.cadence", template(...args))]) +} diff --git a/packages/sdk/src/build/build-subscribe-events.ts b/packages/sdk/src/build/build-subscribe-events.ts index b18fe9c42..a4648aef2 100644 --- a/packages/sdk/src/build/build-subscribe-events.ts +++ b/packages/sdk/src/build/build-subscribe-events.ts @@ -1,9 +1,16 @@ import {invariant} from "@onflow/util-invariant" -import {pipe, Ok, makeSubscribeEvents} from "../interaction/interaction" +import { + pipe, + Ok, + makeSubscribeEvents, + InteractionBuilderFn, +} from "../interaction/interaction" import {EventFilter, Interaction} from "@onflow/typedefs" /** - * Subscribe to events with the given filter & parameters + * @description Subscribe to events with the given filter & parameters + * @param filter The filter to subscribe to events with + * @returns A function that processes an interaction object */ export function subscribeEvents({ startBlockId, @@ -12,7 +19,7 @@ export function subscribeEvents({ addresses, contracts, heartbeatInterval, -}: EventFilter): Function { +}: EventFilter): InteractionBuilderFn { invariant( !(startBlockId && startHeight), `SDK Subscribe Events Error: Cannot set both startBlockId and startHeight.` @@ -29,5 +36,5 @@ export function subscribeEvents({ ix.subscribeEvents.heartbeatInterval = heartbeatInterval ?? null return Ok(ix) }, - ]) as any + ]) } diff --git a/packages/sdk/src/build/build-transaction.js b/packages/sdk/src/build/build-transaction.js deleted file mode 100644 index 27b003d02..000000000 --- a/packages/sdk/src/build/build-transaction.js +++ /dev/null @@ -1,22 +0,0 @@ -import {pipe, put, Ok, makeTransaction} from "../interaction/interaction" -import {template} from "@onflow/util-template" - -const DEFAULT_SCRIPT_ACCOUNTS = [] -const DEFUALT_REF = null - -/** - * @description - A template builder to use a Cadence transaction for an interaction - * @param {...*} args - The arguments to pass - * @returns {Function} - An interaction object - */ -export function transaction(...args) { - return pipe([ - makeTransaction, - put("ix.cadence", template(...args)), - ix => { - ix.message.refBlock = ix.message.refBlock || DEFUALT_REF - ix.authorizations = ix.authorizations || DEFAULT_SCRIPT_ACCOUNTS - return Ok(ix) - }, - ]) -} diff --git a/packages/sdk/src/build/build-transaction.test.js b/packages/sdk/src/build/build-transaction.test.ts similarity index 88% rename from packages/sdk/src/build/build-transaction.test.js rename to packages/sdk/src/build/build-transaction.test.ts index e64ae28c5..26d65e0d6 100644 --- a/packages/sdk/src/build/build-transaction.test.js +++ b/packages/sdk/src/build/build-transaction.test.ts @@ -1,5 +1,5 @@ import {initInteraction, isTransaction} from "../interaction/interaction" -import {transaction} from "./build-transaction.js" +import {transaction} from "./build-transaction" describe("Build Transaction", () => { test("Build Transaction", async () => { diff --git a/packages/sdk/src/build/build-transaction.ts b/packages/sdk/src/build/build-transaction.ts new file mode 100644 index 000000000..b58aa462f --- /dev/null +++ b/packages/sdk/src/build/build-transaction.ts @@ -0,0 +1,30 @@ +import { + pipe, + put, + Ok, + makeTransaction, + InteractionBuilderFn, +} from "../interaction/interaction" +import {template} from "@onflow/util-template" + +const DEFAULT_SCRIPT_ACCOUNTS: string[] = [] +const DEFAULT_REF = "" + +/** + * @description A template builder to use a Cadence transaction for an interaction + * @param args The arguments to pass + * @returns A function that processes an interaction object + */ +export function transaction( + ...args: [string | TemplateStringsArray, ...any[]] +): InteractionBuilderFn { + return pipe([ + makeTransaction, + put("ix.cadence", template(...args)), + ix => { + ix.message.refBlock = ix.message.refBlock || DEFAULT_REF + ix.authorizations = ix.authorizations || DEFAULT_SCRIPT_ACCOUNTS + return Ok(ix) + }, + ]) +} diff --git a/packages/sdk/src/build/build-validator.js b/packages/sdk/src/build/build-validator.js deleted file mode 100644 index c55a4e7f2..000000000 --- a/packages/sdk/src/build/build-validator.js +++ /dev/null @@ -1,7 +0,0 @@ -import {update} from "../interaction/interaction" - -export function validator(cb) { - return update("ix.validators", validators => - Array.isArray(validators) ? validators.push(cb) : [cb] - ) -} diff --git a/packages/sdk/src/resolve/resolve-final-normalization.test.js b/packages/sdk/src/build/build-validator.test.ts similarity index 100% rename from packages/sdk/src/resolve/resolve-final-normalization.test.js rename to packages/sdk/src/build/build-validator.test.ts diff --git a/packages/sdk/src/build/build-validator.ts b/packages/sdk/src/build/build-validator.ts new file mode 100644 index 000000000..34f4c6124 --- /dev/null +++ b/packages/sdk/src/build/build-validator.ts @@ -0,0 +1,12 @@ +import {update, InteractionBuilderFn} from "../interaction/interaction" + +/** + * @description A builder function that adds a validator to a transaction + * @param cb The validator function + * @returns A function that processes an interaction object + */ +export function validator(cb: Function): InteractionBuilderFn { + return update("ix.validators", (validators: Function | Function[]) => + Array.isArray(validators) ? [...validators, cb] : [cb] + ) +} diff --git a/packages/sdk/src/build/build-voucher-intercept.js b/packages/sdk/src/build/build-voucher-intercept.js deleted file mode 100644 index ae9392945..000000000 --- a/packages/sdk/src/build/build-voucher-intercept.js +++ /dev/null @@ -1,5 +0,0 @@ -import {put} from "../interaction/interaction" - -export function voucherIntercept(fn) { - return put("ix.voucher-intercept", fn) -} diff --git a/packages/sdk/src/build/build-voucher-intercept.test.js b/packages/sdk/src/build/build-voucher-intercept.test.ts similarity index 100% rename from packages/sdk/src/build/build-voucher-intercept.test.js rename to packages/sdk/src/build/build-voucher-intercept.test.ts diff --git a/packages/sdk/src/build/build-voucher-intercept.ts b/packages/sdk/src/build/build-voucher-intercept.ts new file mode 100644 index 000000000..b8af89832 --- /dev/null +++ b/packages/sdk/src/build/build-voucher-intercept.ts @@ -0,0 +1,13 @@ +import {put, InteractionBuilderFn} from "../interaction/interaction" +import {Voucher} from "../encode/encode" + +type VoucherInterceptFn = (voucher: Voucher) => any | Promise + +/** + * @description A builder function that intercepts and modifies a voucher + * @param fn The function to intercept and modify the voucher + * @returns A function that processes an interaction object + */ +export function voucherIntercept(fn: VoucherInterceptFn): InteractionBuilderFn { + return put("ix.voucher-intercept", fn) +} diff --git a/packages/sdk/src/build/build.js b/packages/sdk/src/build/build.js deleted file mode 100644 index c7c3b2725..000000000 --- a/packages/sdk/src/build/build.js +++ /dev/null @@ -1,5 +0,0 @@ -import {pipe, initInteraction} from "../interaction/interaction" - -export function build(fns = []) { - return pipe(initInteraction(), fns) -} diff --git a/packages/sdk/src/resolve/resolve-proposer-sequence-number.test.js b/packages/sdk/src/build/build.test.ts similarity index 100% rename from packages/sdk/src/resolve/resolve-proposer-sequence-number.test.js rename to packages/sdk/src/build/build.test.ts diff --git a/packages/sdk/src/build/build.ts b/packages/sdk/src/build/build.ts new file mode 100644 index 000000000..1efe94916 --- /dev/null +++ b/packages/sdk/src/build/build.ts @@ -0,0 +1,17 @@ +import { + pipe, + initInteraction, + InteractionBuilderFn, +} from "../interaction/interaction" +import {Interaction} from "@onflow/typedefs" + +/** + * @description A builder function that creates an interaction + * @param fns The functions to apply to the interaction + * @returns A promise of an interaction + */ +export function build( + fns: (InteractionBuilderFn | false)[] = [] +): Promise { + return pipe(initInteraction(), fns) +} diff --git a/packages/sdk/src/contract.test.js b/packages/sdk/src/contract.test.ts similarity index 89% rename from packages/sdk/src/contract.test.js rename to packages/sdk/src/contract.test.ts index 40f95cea8..9d131e135 100644 --- a/packages/sdk/src/contract.test.js +++ b/packages/sdk/src/contract.test.ts @@ -1,13 +1,13 @@ import * as root from "./sdk" -import * as decode from "./decode/decode.js" +import * as decode from "./decode/decode" import * as encode from "./encode/encode" import * as interaction from "./interaction/interaction" -import * as send from "./send/send.js" +import * as send from "./send/send" import * as template from "@onflow/util-template" const interfaceContract = - (label, wat) => - ([template]) => { + (label: string, wat: any) => + ([template]: TemplateStringsArray): void => { const keys = template.replace(/\s+/g, "|").split("|").filter(Boolean) describe(label, () => { diff --git a/packages/sdk/src/decode/decode.js b/packages/sdk/src/decode/decode.ts similarity index 59% rename from packages/sdk/src/decode/decode.js rename to packages/sdk/src/decode/decode.ts index 1d211e23c..11fcb8b4e 100644 --- a/packages/sdk/src/decode/decode.js +++ b/packages/sdk/src/decode/decode.ts @@ -1,7 +1,85 @@ import {log} from "@onflow/util-logger" import {decodeStream} from "./decode-stream" -const latestBlockDeprecationNotice = () => { +type DecoderFunction = ( + value: any, + decoders: DecoderMap, + stack: any[] +) => Promise + +interface DecoderMap { + [key: string]: DecoderFunction +} + +interface DecodeInstructions { + type: string + value?: any +} + +interface CompositeField { + name: string + value: DecodeInstructions +} + +interface CompositeInstruction { + id?: string + fields: CompositeField[] +} + +interface KeyValuePair { + key: DecodeInstructions + value: DecodeInstructions +} + +interface InclusiveRangeValue { + start?: DecodeInstructions + end?: DecodeInstructions + step?: DecodeInstructions + [key: string]: any +} + +interface FlowEvent { + type: string + transactionId: string + transactionIndex: number + eventIndex: number + payload: DecodeInstructions +} + +interface FlowBlockEvent extends FlowEvent { + blockId: string + blockHeight: number + blockTimestamp: string +} + +interface FlowTransactionStatus { + blockId: string + status: number + statusCode: number + errorMessage: string + events: FlowEvent[] +} + +interface FlowResponse { + encodedData?: DecodeInstructions + transactionStatus?: FlowTransactionStatus + transaction?: any + events?: FlowBlockEvent[] + account?: any + block?: any + blockHeader?: any + latestBlock?: any + transactionId?: string + collection?: any + networkParameters?: { + chainId: string + } + streamConnection?: any + heartbeat?: any + nodeVersionInfo?: any +} + +const latestBlockDeprecationNotice = (): void => { log.deprecate({ pkg: "@onflow/decode", subject: @@ -11,7 +89,11 @@ const latestBlockDeprecationNotice = () => { }) } -const decodeNumber = async (num, _, stack) => { +const decodeNumber = async ( + num: any, + _: DecoderMap, + stack: any[] +): Promise => { try { return Number(num) } catch (e) { @@ -19,18 +101,26 @@ const decodeNumber = async (num, _, stack) => { } } -const decodeImplicit = async i => i +const decodeImplicit = async (i: T): Promise => i -const decodeVoid = async () => null +const decodeVoid = async (): Promise => null -const decodeType = async type => { +const decodeType = async (type: any): Promise => { return type.staticType } -const decodeOptional = async (optional, decoders, stack) => +const decodeOptional = async ( + optional: any, + decoders: DecoderMap, + stack: any[] +): Promise => optional ? await recurseDecode(optional, decoders, stack) : null -const decodeArray = async (array, decoders, stack) => +const decodeArray = async ( + array: DecodeInstructions[], + decoders: DecoderMap, + stack: any[] +): Promise => await Promise.all( array.map( v => @@ -40,40 +130,61 @@ const decodeArray = async (array, decoders, stack) => ) ) -const decodeDictionary = async (dictionary, decoders, stack) => - await dictionary.reduce(async (acc, v) => { - acc = await acc - acc[await recurseDecode(v.key, decoders, [...stack, v.key])] = - await recurseDecode(v.value, decoders, [...stack, v.key]) - return acc - }, Promise.resolve({})) - -const decodeComposite = async (composite, decoders, stack) => { - const decoded = await composite.fields.reduce(async (acc, v) => { - acc = await acc - acc[v.name] = await recurseDecode(v.value, decoders, [...stack, v.name]) - return acc - }, Promise.resolve({})) +const decodeDictionary = async ( + dictionary: KeyValuePair[], + decoders: DecoderMap, + stack: any[] +): Promise> => + await dictionary.reduce( + async (acc, v) => { + acc = await acc + acc[await recurseDecode(v.key, decoders, [...stack, v.key])] = + await recurseDecode(v.value, decoders, [...stack, v.key]) + return acc + }, + Promise.resolve({}) as any + ) + +const decodeComposite = async ( + composite: CompositeInstruction, + decoders: DecoderMap, + stack: any[] +): Promise => { + const decoded = await composite.fields.reduce( + async (acc, v) => { + acc = await acc + acc[v.name] = await recurseDecode(v.value, decoders, [...stack, v.name]) + return acc + }, + Promise.resolve({}) as any + ) const decoder = composite.id && decoderLookup(decoders, composite.id) return decoder ? await decoder(decoded) : decoded } -const decodeInclusiveRange = async (range, decoders, stack) => { +const decodeInclusiveRange = async ( + range: InclusiveRangeValue, + decoders: DecoderMap, + stack: any[] +): Promise> => { // Recursive decode for start, end, and step // We don't do all fields just in case there are future API changes // where fields added and are not Cadence values const keys = ["start", "end", "step"] - const decoded = await Object.keys(range).reduce(async (acc, key) => { - acc = await acc - if (keys.includes(key)) { - acc[key] = await recurseDecode(range[key], decoders, [...stack, key]) - } - return acc - }, Promise.resolve({})) + const decoded = await Object.keys(range).reduce( + async (acc, key) => { + acc = await acc + if (keys.includes(key)) { + acc[key] = await recurseDecode(range[key], decoders, [...stack, key]) + } + return acc + }, + Promise.resolve({}) as any + ) return decoded } -const defaultDecoders = { +const defaultDecoders: DecoderMap = { UInt: decodeImplicit, Int: decodeImplicit, UInt8: decodeImplicit, @@ -115,7 +226,7 @@ const defaultDecoders = { InclusiveRange: decodeInclusiveRange, } -const decoderLookup = (decoders, lookup) => { +const decoderLookup = (decoders: DecoderMap, lookup: any): any => { const found = Object.keys(decoders).find(decoder => { if (/^\/.*\/$/.test(decoder)) { const reg = new RegExp(decoder.substring(1, decoder.length - 1)) @@ -126,7 +237,11 @@ const decoderLookup = (decoders, lookup) => { return lookup && found && decoders[found] } -const recurseDecode = async (decodeInstructions, decoders, stack) => { +const recurseDecode = async ( + decodeInstructions: DecodeInstructions, + decoders: DecoderMap, + stack: any[] +): Promise => { let decoder = decoderLookup(decoders, decodeInstructions.type) if (!decoder) throw new Error( @@ -137,16 +252,16 @@ const recurseDecode = async (decodeInstructions, decoders, stack) => { /** * @description - Decodes a response from Flow into JSON - * @param {*} decodeInstructions - The response object from Flow - * @param {object} customDecoders - An object of custom decoders - * @param {Array<*>} stack - The stack of the current decoding - * @returns {Promise<*>} - The decoded response + * @param decodeInstructions - The response object from Flow + * @param customDecoders - An object of custom decoders + * @param stack - The stack of the current decoding + * @returns - The decoded response */ export const decode = async ( - decodeInstructions, - customDecoders = {}, - stack = [] -) => { + decodeInstructions: DecodeInstructions, + customDecoders: DecoderMap = {}, + stack: any[] = [] +): Promise => { // Filter out all default decoders which are overridden by a custom decoder regex const filteredDecoders = Object.keys(defaultDecoders) .filter( @@ -167,7 +282,10 @@ export const decode = async ( return recurseDecode(decodeInstructions, decoders, stack) } -export const decodeResponse = async (response, customDecoders = {}) => { +export const decodeResponse = async ( + response: FlowResponse, + customDecoders: DecoderMap = {} +): Promise => { if (response.encodedData) { return decode(response.encodedData, customDecoders) } else if (response.transactionStatus) { @@ -218,7 +336,7 @@ export const decodeResponse = async (response, customDecoders = {}) => { } else if (response.networkParameters) { const prefixRegex = /^flow-/ const rawChainId = response.networkParameters.chainId - let formattedChainId + let formattedChainId: string if (rawChainId === "flow-emulator") { formattedChainId = "local" diff --git a/packages/sdk/src/decode/sdk-decode.js b/packages/sdk/src/decode/sdk-decode.ts similarity index 86% rename from packages/sdk/src/decode/sdk-decode.js rename to packages/sdk/src/decode/sdk-decode.ts index 6a1db6b72..58c103052 100644 --- a/packages/sdk/src/decode/sdk-decode.js +++ b/packages/sdk/src/decode/sdk-decode.ts @@ -1,7 +1,7 @@ import {config} from "@onflow/config" import {decodeResponse} from "./decode" -export async function decode(response) { +export async function decode(response: any): Promise { const decodersFromConfig = await config().where(/^decoder\./) const decoders = Object.entries(decodersFromConfig).map( ([pattern, xform]) => { diff --git a/packages/sdk/src/encode/encode.test.js b/packages/sdk/src/encode/encode.test.ts similarity index 100% rename from packages/sdk/src/encode/encode.test.js rename to packages/sdk/src/encode/encode.test.ts diff --git a/packages/sdk/src/interaction/interaction.test.ts b/packages/sdk/src/interaction/interaction.test.ts index cb2a5b9a0..f170e76bf 100644 --- a/packages/sdk/src/interaction/interaction.test.ts +++ b/packages/sdk/src/interaction/interaction.test.ts @@ -1,4 +1,4 @@ -import {InteractionAccount} from "@onflow/typedefs" +import {InteractionAccount, TransactionRole} from "@onflow/typedefs" import {resolveAccounts} from "../sdk" import {prepAccount, initAccount, initInteraction} from "./interaction" @@ -15,7 +15,7 @@ describe("prepAccount", () => { }), } - const ix = prepAccount(acct, {role: "proposer"})({ + const ix = prepAccount(acct, {role: TransactionRole.PROPOSER})({ ...initInteraction(), accounts: {}, }) @@ -37,13 +37,14 @@ describe("prepAccount", () => { } const ix = await resolveAccounts( - prepAccount(authz, {role: "proposer"})({ + prepAccount(authz, {role: TransactionRole.PROPOSER})({ ...initInteraction(), accounts: {}, }) ) - ix.accounts[ix.proposer] = await ix.accounts[ix.proposer].resolve() - expect(ix.accounts[ix.proposer].keyId).toBe(parseInt(keyId)) + ix.accounts[ix.proposer || ""] = + await ix.accounts[ix.proposer || ""].resolve() + expect(ix.accounts[ix.proposer || ""].keyId).toBe(parseInt(keyId)) }) test("prepAccount does not affect keyId if undefined/does not exist", async () => { @@ -59,12 +60,13 @@ describe("prepAccount", () => { } const ix = await resolveAccounts( - prepAccount(authz, {role: "proposer"})({ + prepAccount(authz, {role: TransactionRole.PROPOSER})({ ...initInteraction(), accounts: {}, }) ) - ix.accounts[ix.proposer] = await ix.accounts[ix.proposer].resolve() - expect(ix.accounts[ix.proposer].keyId).toBeUndefined() + ix.accounts[ix.proposer || ""] = + await ix.accounts[ix.proposer || ""].resolve() + expect(ix.accounts[ix.proposer || ""].keyId).toBeUndefined() }) }) diff --git a/packages/sdk/src/interaction/interaction.ts b/packages/sdk/src/interaction/interaction.ts index 74ecfd485..a4a022f88 100644 --- a/packages/sdk/src/interaction/interaction.ts +++ b/packages/sdk/src/interaction/interaction.ts @@ -10,10 +10,12 @@ import { InteractionStatus, InteractionTag, } from "@onflow/typedefs" -import {TypeDescriptor, TypeDescriptorInput} from "@onflow/types" +import {TypeDescriptorInput, TypeDescriptor} from "@onflow/types" -type AcctFn = (acct: InteractionAccount) => InteractionAccount -type AccountFn = AcctFn & Partial +export type AuthorizationFn = (acct: InteractionAccount) => InteractionAccount +export type AccountAuthorization = + | (AuthorizationFn & Partial) + | Partial type CadenceArgument> = { value: TypeDescriptorInput @@ -22,6 +24,10 @@ type CadenceArgument> = { export {CadenceArgument} +export type InteractionBuilderFn = ( + ix: Interaction +) => Interaction | Promise + const ACCT = `{ "kind":"${InteractionResolverKind.ACCOUNT}", "tempId":null, @@ -146,9 +152,7 @@ const makeIx = (wat: InteractionTag) => (ix: Interaction) => { return Ok(ix) } -const prepAccountKeyId = ( - acct: Partial | AccountFn -): Partial | AccountFn => { +const prepAccountKeyId = (acct: AccountAuthorization): AccountAuthorization => { if (acct.keyId == null) return acct invariant( @@ -159,7 +163,7 @@ const prepAccountKeyId = ( return { ...acct, keyId: parseInt(acct.keyId.toString()), - } as InteractionAccount | AccountFn + } as AccountAuthorization } interface IPrepAccountOpts { @@ -169,7 +173,7 @@ interface IPrepAccountOpts { export const initAccount = (): InteractionAccount => JSON.parse(ACCT) export const prepAccount = - (acct: InteractionAccount | AccountFn, opts: IPrepAccountOpts = {}) => + (acct: AccountAuthorization, opts: IPrepAccountOpts = {}) => (ix: Interaction) => { invariant( typeof acct === "function" || typeof acct === "object", @@ -324,10 +328,7 @@ type MaybePromise = T | Promise const recPipe = async ( ix: MaybePromise, - fns: ( - | ((x: Interaction) => MaybePromise) - | MaybePromise - )[] = [] + fns: (InteractionBuilderFn | false | MaybePromise)[] = [] ): Promise => { try { ix = hardMode(await ix) @@ -348,22 +349,16 @@ const recPipe = async ( * @description Async pipe function to compose interactions * @returns An interaction object */ -function pipe( - fns: ((x: Interaction) => Interaction)[] -): (x: Interaction) => Promise -/** - * @description Async pipe function to compose interactions - * @returns An interaction object - */ +function pipe(fns: (InteractionBuilderFn | false)[]): InteractionBuilderFn function pipe( ix: MaybePromise, - fns: ((x: Interaction) => Interaction)[] + fns: (InteractionBuilderFn | false)[] ): Promise function pipe( ...args: - | [((x: Interaction) => Interaction)[]] - | [MaybePromise, ((x: Interaction) => Interaction)[]] -): Promise | ((x: Interaction) => Promise) { + | [(InteractionBuilderFn | false)[]] + | [MaybePromise, (InteractionBuilderFn | false)[]] +): Promise | InteractionBuilderFn { const [arg1, arg2] = args if (isArray(arg1)) return (d: Interaction) => pipe(d, arg1) @@ -385,7 +380,7 @@ export const put = (key: string, value: any) => (ix: Interaction) => { } export const update = - (key: string, fn = identity) => + (key: string, fn: (v: T | T[], ...args: any[]) => T | T[] = identity) => (ix: Interaction) => { ix.assigns[key] = fn(ix.assigns[key], ix) return Ok(ix) diff --git a/packages/sdk/src/node-version-info/node-version-info.ts b/packages/sdk/src/node-version-info/node-version-info.ts index c905a76cd..ef79948c6 100644 --- a/packages/sdk/src/node-version-info/node-version-info.ts +++ b/packages/sdk/src/node-version-info/node-version-info.ts @@ -1,7 +1,7 @@ -import {send} from "../send/send.js" -import {decodeResponse as decode} from "../decode/decode.js" -import {getNodeVersionInfo} from "../build/build-get-node-version-info" import {NodeVersionInfo} from "@onflow/typedefs" +import {getNodeVersionInfo} from "../build/build-get-node-version-info" +import {decodeResponse as decode} from "../decode/decode" +import {send} from "../send/send" /** * @description Returns the version information from to connected node @@ -10,5 +10,6 @@ import {NodeVersionInfo} from "@onflow/typedefs" export async function nodeVersionInfo( opts: any = {} ): Promise { - return send([getNodeVersionInfo()], opts).then(decode) + const ix = await send([getNodeVersionInfo()], opts) + return decode(ix) } diff --git a/packages/sdk/src/resolve/__snapshots__/resolve-signatures.test.js.snap b/packages/sdk/src/resolve/__snapshots__/resolve-signatures.test.ts.snap similarity index 95% rename from packages/sdk/src/resolve/__snapshots__/resolve-signatures.test.js.snap rename to packages/sdk/src/resolve/__snapshots__/resolve-signatures.test.ts.snap index c448c6c5e..cae19e89a 100644 --- a/packages/sdk/src/resolve/__snapshots__/resolve-signatures.test.js.snap +++ b/packages/sdk/src/resolve/__snapshots__/resolve-signatures.test.ts.snap @@ -5,6 +5,7 @@ exports[`Golden Path 1`] = ` "accounts": { "foo": { "addr": "foo", + "authorization": [Function], "keyId": 1, "kind": "ACCOUNT", "resolve": null, @@ -84,11 +85,13 @@ exports[`Golden Path 1`] = ` "cadence": "", "computeLimit": 156, "params": [], - "payer": null, - "proposer": null, + "payer": "", + "proposer": "", "refBlock": "123", }, - "payer": "foo", + "payer": [ + "foo", + ], "proposer": "foo", "tag": "TRANSACTION", } diff --git a/packages/sdk/src/resolve/resolve-arguments.test.js b/packages/sdk/src/resolve/resolve-arguments.test.ts similarity index 93% rename from packages/sdk/src/resolve/resolve-arguments.test.js rename to packages/sdk/src/resolve/resolve-arguments.test.ts index ebf30cea7..22b02abd9 100644 --- a/packages/sdk/src/resolve/resolve-arguments.test.js +++ b/packages/sdk/src/resolve/resolve-arguments.test.ts @@ -29,7 +29,7 @@ describe("resolveArguments", () => { }, } - const res = await resolveArguments(ix) + const res = await resolveArguments(ix as any) expect(res.arguments[argID].asArgument).toEqual(argObj) }) @@ -56,7 +56,7 @@ describe("resolveArguments", () => { }, } - const res = await resolveArguments(ix) + const res = await resolveArguments(ix as any) expect(res.arguments[argID].resolve).not.toHaveBeenCalled() expect(res.arguments[argID].resolveArgument).toHaveBeenCalled() expect(res.arguments[argID].asArgument).toEqual(argObj) @@ -92,7 +92,7 @@ describe("resolveArguments", () => { }, } - const res = await resolveArguments(ix) + const res = await resolveArguments(ix as any) expect(res.arguments[argID].resolveArgument).toHaveBeenCalled() expect(resolveTwo).toHaveBeenCalled() expect(res.arguments[argID].asArgument).toEqual(argObj) @@ -134,6 +134,6 @@ describe("resolveArguments", () => { }, } - await expect(resolveArguments(ix)).rejects.toThrow() + await expect(resolveArguments(ix as any)).rejects.toThrow() }) }) diff --git a/packages/sdk/src/resolve/resolve-arguments.js b/packages/sdk/src/resolve/resolve-arguments.ts similarity index 63% rename from packages/sdk/src/resolve/resolve-arguments.js rename to packages/sdk/src/resolve/resolve-arguments.ts index eb1ad392c..7b3b1aaff 100644 --- a/packages/sdk/src/resolve/resolve-arguments.js +++ b/packages/sdk/src/resolve/resolve-arguments.ts @@ -1,9 +1,18 @@ import {invariant} from "@onflow/util-invariant" import {isTransaction, isScript} from "../interaction/interaction" +import {Interaction} from "@onflow/typedefs" + +interface Argument { + tempId: string + value: any + xform: any + resolveArgument?: () => Promise + asArgument?: any +} -const isFn = v => typeof v === "function" +const isFn = (v: any): v is Function => typeof v === "function" -function cast(arg) { +function cast(arg: Argument): any { // prettier-ignore invariant(typeof arg.xform != null, `No type specified for argument: ${arg.value}`) @@ -14,7 +23,10 @@ function cast(arg) { invariant(false, `Invalid Argument`, arg) } -async function handleArgResolution(arg, depth = 3) { +async function handleArgResolution( + arg: Argument, + depth = 3 +): Promise { invariant( depth > 0, `Argument Resolve Recursion Limit Exceeded for Arg: ${arg.tempId}` @@ -28,10 +40,10 @@ async function handleArgResolution(arg, depth = 3) { } } -export async function resolveArguments(ix) { +export async function resolveArguments(ix: Interaction): Promise { if (isTransaction(ix) || isScript(ix)) { for (let [id, arg] of Object.entries(ix.arguments)) { - const res = await handleArgResolution(arg) + const res = await handleArgResolution(arg as Argument) ix.arguments[id].asArgument = cast(res) } } diff --git a/packages/sdk/src/resolve/resolve-cadence.test.js b/packages/sdk/src/resolve/resolve-cadence.test.ts similarity index 97% rename from packages/sdk/src/resolve/resolve-cadence.test.js rename to packages/sdk/src/resolve/resolve-cadence.test.ts index 22e9c2ecc..c92f3ec92 100644 --- a/packages/sdk/src/resolve/resolve-cadence.test.js +++ b/packages/sdk/src/resolve/resolve-cadence.test.ts @@ -4,10 +4,10 @@ import { put, makeScript, } from "../interaction/interaction" -import {resolveCadence} from "./resolve-cadence.js" +import {resolveCadence} from "./resolve-cadence" import {config} from "@onflow/config" -const idle = () => new Promise(resolve => setTimeout(resolve), 0) +const idle = () => new Promise(resolve => setTimeout(resolve, 0)) describe("resolveCadence", () => { describe("0xHelloWorld-style account identifier syntax", () => { diff --git a/packages/sdk/src/resolve/resolve-cadence.js b/packages/sdk/src/resolve/resolve-cadence.ts similarity index 69% rename from packages/sdk/src/resolve/resolve-cadence.js rename to packages/sdk/src/resolve/resolve-cadence.ts index 3da21cbb4..78f6cf0e8 100644 --- a/packages/sdk/src/resolve/resolve-cadence.js +++ b/packages/sdk/src/resolve/resolve-cadence.ts @@ -3,34 +3,37 @@ import {invariant} from "@onflow/util-invariant" import {config} from "@onflow/config" import * as logger from "@onflow/util-logger" import {withPrefix} from "@onflow/util-address" +import {Interaction} from "@onflow/typedefs" -const isFn = v => typeof v === "function" -const isString = v => typeof v === "string" +const isFn = (v: any): v is Function => typeof v === "function" +const isString = (v: any): v is string => typeof v === "string" -const oldIdentifierPatternFn = () => /\b(0x\w+)\b/g -function isOldIdentifierSyntax(cadence) { +const oldIdentifierPatternFn = (): RegExp => /\b(0x\w+)\b/g +function isOldIdentifierSyntax(cadence: string): boolean { return oldIdentifierPatternFn().test(cadence) } -const newIdentifierPatternFn = () => /import\s+"(\w+)"/g -function isNewIdentifierSyntax(cadence) { +const newIdentifierPatternFn = (): RegExp => /import\s+"(\w+)"/g +function isNewIdentifierSyntax(cadence: string): boolean { return newIdentifierPatternFn().test(cadence) } -function getContractIdentifierSyntaxMatches(cadence) { +function getContractIdentifierSyntaxMatches( + cadence: string +): IterableIterator { return cadence.matchAll(newIdentifierPatternFn()) } -export async function resolveCadence(ix) { +export async function resolveCadence(ix: Interaction): Promise { if (!isTransaction(ix) && !isScript(ix)) return ix - var cadence = get(ix, "ix.cadence") + var cadence = get(ix, "ix.cadence", null) invariant( isFn(cadence) || isString(cadence), "Cadence needs to be a function or a string." ) - if (isFn(cadence)) cadence = await cadence({}) + if (isFn(cadence)) cadence = await cadence({} as Record) invariant(isString(cadence), "Cadence needs to be a string at this point.") invariant( !isOldIdentifierSyntax(cadence) || !isNewIdentifierSyntax(cadence), @@ -51,7 +54,9 @@ export async function resolveCadence(ix) { for (const [fullMatch, contractName] of getContractIdentifierSyntaxMatches( cadence )) { - const address = await config().get(`system.contracts.${contractName}`) + const address: string | null = await config().get( + `system.contracts.${contractName}` + ) if (address) { cadence = cadence.replace( fullMatch, diff --git a/packages/sdk/src/resolve/resolve-compute-limit.test.js b/packages/sdk/src/resolve/resolve-compute-limit.test.ts similarity index 95% rename from packages/sdk/src/resolve/resolve-compute-limit.test.js rename to packages/sdk/src/resolve/resolve-compute-limit.test.ts index 74cde6d82..3dd5febc8 100644 --- a/packages/sdk/src/resolve/resolve-compute-limit.test.js +++ b/packages/sdk/src/resolve/resolve-compute-limit.test.ts @@ -4,7 +4,7 @@ import { makeTransaction, } from "../interaction/interaction" import {config} from "@onflow/config" -import {resolveComputeLimit} from "./resolve-compute-limit.js" +import {resolveComputeLimit} from "./resolve-compute-limit" describe("resolveComputeLimit", () => { test("transaction compute limit has priority", async () => { diff --git a/packages/sdk/src/resolve/resolve-compute-limit.js b/packages/sdk/src/resolve/resolve-compute-limit.ts similarity index 84% rename from packages/sdk/src/resolve/resolve-compute-limit.js rename to packages/sdk/src/resolve/resolve-compute-limit.ts index a93cd58cf..7e693c7e4 100644 --- a/packages/sdk/src/resolve/resolve-compute-limit.js +++ b/packages/sdk/src/resolve/resolve-compute-limit.ts @@ -1,10 +1,13 @@ import {isTransaction} from "../interaction/interaction" import {config} from "@onflow/config" import * as logger from "@onflow/util-logger" +import {Interaction} from "@onflow/typedefs" const DEFAULT_COMPUTE_LIMIT = 100 -export async function resolveComputeLimit(ix) { +export async function resolveComputeLimit( + ix: Interaction +): Promise { if (isTransaction(ix)) { ix.message.computeLimit = ix.message.computeLimit || (await config.get("fcl.limit")) diff --git a/packages/sdk/src/resolve/resolve-validators.test.js b/packages/sdk/src/resolve/resolve-final-normalization.test.ts similarity index 100% rename from packages/sdk/src/resolve/resolve-validators.test.js rename to packages/sdk/src/resolve/resolve-final-normalization.test.ts diff --git a/packages/sdk/src/resolve/resolve-final-normalization.js b/packages/sdk/src/resolve/resolve-final-normalization.ts similarity index 55% rename from packages/sdk/src/resolve/resolve-final-normalization.js rename to packages/sdk/src/resolve/resolve-final-normalization.ts index 93a8cb2bc..f7593d139 100644 --- a/packages/sdk/src/resolve/resolve-final-normalization.js +++ b/packages/sdk/src/resolve/resolve-final-normalization.ts @@ -1,6 +1,9 @@ import {sansPrefix} from "@onflow/util-address" +import {Interaction} from "@onflow/typedefs" -export async function resolveFinalNormalization(ix) { +export async function resolveFinalNormalization( + ix: Interaction +): Promise { for (let key of Object.keys(ix.accounts)) { ix.accounts[key].addr = sansPrefix(ix.accounts[key].addr) } diff --git a/packages/sdk/src/resolve/resolve-proposer-sequence-number.test.ts b/packages/sdk/src/resolve/resolve-proposer-sequence-number.test.ts new file mode 100644 index 000000000..8c2e82ea0 --- /dev/null +++ b/packages/sdk/src/resolve/resolve-proposer-sequence-number.test.ts @@ -0,0 +1,3 @@ +test("placeholder", () => { + expect(0).toBe(0) +}) diff --git a/packages/sdk/src/resolve/resolve-proposer-sequence-number.js b/packages/sdk/src/resolve/resolve-proposer-sequence-number.ts similarity index 60% rename from packages/sdk/src/resolve/resolve-proposer-sequence-number.js rename to packages/sdk/src/resolve/resolve-proposer-sequence-number.ts index 4ec55db77..73abe0e8e 100644 --- a/packages/sdk/src/resolve/resolve-proposer-sequence-number.js +++ b/packages/sdk/src/resolve/resolve-proposer-sequence-number.ts @@ -2,38 +2,43 @@ import {isTransaction, Ok} from "../interaction/interaction" import * as ixModule from "../interaction/interaction" import {response as responseModule} from "../response/response" import {config} from "@onflow/config" -import {decodeResponse} from "../decode/decode.js" -import {getAccount} from "../build/build-get-account.js" -import {build} from "../build/build.js" +import {decodeResponse} from "../decode/decode" +import {getAccount} from "../build/build-get-account" +import {build} from "../build/build" import {invariant} from "@onflow/util-invariant" import {Buffer} from "@onflow/rlp" import {send as defaultSend} from "@onflow/transport-http" +import {Interaction} from "@onflow/typedefs" + +interface NodeConfig { + node: string +} export const resolveProposerSequenceNumber = - ({node}) => - async ix => { + ({node}: NodeConfig) => + async (ix: Interaction) => { if (!isTransaction(ix)) return Ok(ix) - if (ix.accounts[ix.proposer].sequenceNum) return Ok(ix) + if (ix.accounts[ix.proposer!].sequenceNum) return Ok(ix) - const sendFn = await config.first( + const sendFn: any = await config.first( ["sdk.transport", "sdk.send"], defaultSend ) invariant( - sendFn, + sendFn != null, `Required value for sdk.transport is not defined in config. See: ${"https://github.com/onflow/fcl-js/blob/master/packages/sdk/CHANGELOG.md#0057-alpha1----2022-01-21"}` ) const response = await sendFn( - await build([getAccount(ix.accounts[ix.proposer].addr)]), + await build([getAccount(ix.accounts[ix.proposer!].addr!)]), {config, response: responseModule, Buffer, ix: ixModule}, {node} ) const decoded = await decodeResponse(response) - ix.accounts[ix.proposer].sequenceNum = - decoded.keys[ix.accounts[ix.proposer].keyId].sequenceNumber + ix.accounts[ix.proposer!].sequenceNum = + decoded.keys[ix.accounts[ix.proposer!].keyId!].sequenceNumber return Ok(ix) } diff --git a/packages/sdk/src/resolve/resolve-ref-block-id.test.js b/packages/sdk/src/resolve/resolve-ref-block-id.test.ts similarity index 100% rename from packages/sdk/src/resolve/resolve-ref-block-id.test.js rename to packages/sdk/src/resolve/resolve-ref-block-id.test.ts diff --git a/packages/sdk/src/resolve/resolve-ref-block-id.js b/packages/sdk/src/resolve/resolve-ref-block-id.ts similarity index 72% rename from packages/sdk/src/resolve/resolve-ref-block-id.js rename to packages/sdk/src/resolve/resolve-ref-block-id.ts index 0a11e1c86..c94139619 100644 --- a/packages/sdk/src/resolve/resolve-ref-block-id.js +++ b/packages/sdk/src/resolve/resolve-ref-block-id.ts @@ -7,15 +7,18 @@ import { import * as ixModule from "../interaction/interaction" import {response} from "../response/response" import {config} from "@onflow/config" -import {decodeResponse} from "../decode/decode.js" -import {getBlock} from "../build/build-get-block.js" +import {decodeResponse} from "../decode/decode" +import {getBlock} from "../build/build-get-block" import {invariant} from "@onflow/util-invariant" import {Buffer} from "@onflow/rlp" import {send as defaultSend} from "@onflow/transport-http" -async function getRefId(opts) { +async function getRefId(opts?: {[key: string]: any}): Promise { const node = await config().get("accessNode.api") - const sendFn = await config.first(["sdk.transport", "sdk.send"], defaultSend) + const sendFn: any = await config.first( + ["sdk.transport", "sdk.send"], + defaultSend + ) invariant( sendFn, @@ -29,8 +32,8 @@ async function getRefId(opts) { return ix.id } -export function resolveRefBlockId(opts) { - return async ix => { +export function resolveRefBlockId(opts?: {[key: string]: any}) { + return async (ix: any) => { if (!isTransaction(ix)) return Ok(ix) if (ix.message.refBlock) return Ok(ix) diff --git a/packages/sdk/src/resolve/resolve-signatures.test.js b/packages/sdk/src/resolve/resolve-signatures.test.ts similarity index 85% rename from packages/sdk/src/resolve/resolve-signatures.test.js rename to packages/sdk/src/resolve/resolve-signatures.test.ts index 074c03d7d..654c50d81 100644 --- a/packages/sdk/src/resolve/resolve-signatures.test.js +++ b/packages/sdk/src/resolve/resolve-signatures.test.ts @@ -9,6 +9,7 @@ import { limit, authorizations, } from "../sdk" +import {InteractionResolverKind, InteractionTag} from "@onflow/typedefs" const signingFunction = jest.fn(() => ({ addr: "foo", @@ -17,20 +18,20 @@ const signingFunction = jest.fn(() => ({ })) const TRANSACTION = { - tag: "TRANSACTION", + tag: InteractionTag.TRANSACTION, message: { cadence: "", refBlock: "123", computeLimit: 156, - proposer: null, - payer: null, + proposer: "", + payer: "", authorizations: [], params: [], arguments: [], }, accounts: { foo: { - kind: "ACCOUNT", + kind: InteractionResolverKind.ACCOUNT, tempId: "foo", addr: "foo", keyId: 1, @@ -39,12 +40,13 @@ const TRANSACTION = { signingFunction: signingFunction, resolve: null, role: {proposer: false, authorizer: false, payer: true, param: false}, + authorization: () => {}, }, }, proposer: "foo", authorizations: ["foo"], - payer: "foo", -} + payer: ["foo"], +} as any test("exports function", () => { expect(typeof resolveSignatures).toBe("function") @@ -73,7 +75,7 @@ test("voucher in signable", async () => { ]) ) - const signable = buildSignable(ix.accounts[ix.proposer], {}, ix) + const signable = buildSignable(ix.accounts[ix.proposer!], {} as any, ix) expect(signable.voucher).toEqual({ cadence: "", diff --git a/packages/sdk/src/resolve/resolve-validators.js b/packages/sdk/src/resolve/resolve-validators.js deleted file mode 100644 index f86ebd02b..000000000 --- a/packages/sdk/src/resolve/resolve-validators.js +++ /dev/null @@ -1,9 +0,0 @@ -import {get, pipe, Ok, Bad} from "../interaction/interaction" - -export async function resolveValidators(ix) { - const validators = get(ix, "ix.validators", []) - return pipe( - ix, - validators.map(cb => ix => cb(ix, {Ok, Bad})) - ) -} diff --git a/packages/sdk/src/resolve/resolve-validators.test.ts b/packages/sdk/src/resolve/resolve-validators.test.ts new file mode 100644 index 000000000..8c2e82ea0 --- /dev/null +++ b/packages/sdk/src/resolve/resolve-validators.test.ts @@ -0,0 +1,3 @@ +test("placeholder", () => { + expect(0).toBe(0) +}) diff --git a/packages/sdk/src/resolve/resolve-validators.ts b/packages/sdk/src/resolve/resolve-validators.ts new file mode 100644 index 000000000..6ed6ba4c0 --- /dev/null +++ b/packages/sdk/src/resolve/resolve-validators.ts @@ -0,0 +1,10 @@ +import {get, pipe, Ok, Bad} from "../interaction/interaction" +import {Interaction} from "@onflow/typedefs" + +export async function resolveValidators(ix: Interaction): Promise { + const validators = get(ix, "ix.validators", []) + return pipe( + ix, + validators.map((cb: Function) => (ix: Interaction) => cb(ix, {Ok, Bad})) + ) +} diff --git a/packages/sdk/src/resolve/resolve-voucher-intercept.js b/packages/sdk/src/resolve/resolve-voucher-intercept.js deleted file mode 100644 index f1f6ac211..000000000 --- a/packages/sdk/src/resolve/resolve-voucher-intercept.js +++ /dev/null @@ -1,10 +0,0 @@ -import {get, isFn} from "../interaction/interaction" -import {createSignableVoucher} from "./voucher" - -export async function resolveVoucherIntercept(ix) { - const fn = get(ix, "ix.voucher-intercept") - if (isFn(fn)) { - await fn(createSignableVoucher(ix)) - } - return ix -} diff --git a/packages/sdk/src/resolve/resolve-voucher-intercept.test.js b/packages/sdk/src/resolve/resolve-voucher-intercept.test.ts similarity index 76% rename from packages/sdk/src/resolve/resolve-voucher-intercept.test.js rename to packages/sdk/src/resolve/resolve-voucher-intercept.test.ts index c1852f1f4..1292db8fc 100644 --- a/packages/sdk/src/resolve/resolve-voucher-intercept.test.js +++ b/packages/sdk/src/resolve/resolve-voucher-intercept.test.ts @@ -1,4 +1,5 @@ -import {resolveVoucherIntercept} from "./resolve-voucher-intercept.js" +import {InteractionResolverKind, InteractionTag} from "@onflow/typedefs" +import {resolveVoucherIntercept} from "./resolve-voucher-intercept" test("exports function", () => { expect(typeof resolveVoucherIntercept).toBe("function") @@ -7,13 +8,13 @@ test("exports function", () => { test("voucherIntercept is executed", async () => { let executed = false - const checkFunc = async voucher => { + const checkFunc = async (voucher: any) => { executed = true expect(typeof voucher).toBe("object") } const ix = { - tag: "TRANSACTION", + tag: InteractionTag.TRANSACTION, assigns: { "ix.voucher-intercept": checkFunc, }, @@ -21,15 +22,15 @@ test("voucherIntercept is executed", async () => { cadence: "", refBlock: "123", computeLimit: 156, - proposer: null, - payer: null, + proposer: "", + payer: "", authorizations: [], params: [], arguments: [], }, accounts: { foo: { - kind: "ACCOUNT", + kind: InteractionResolverKind.ACCOUNT, tempId: "foo", addr: "foo", keyId: 1, @@ -38,12 +39,13 @@ test("voucherIntercept is executed", async () => { signingFunction: () => ({signature: "123"}), resolve: null, role: {proposer: false, authorizer: false, payer: true, param: false}, + authorization: () => {}, }, }, proposer: "foo", authorizations: ["foo"], - payer: "foo", - } + payer: ["foo"], + } as any await resolveVoucherIntercept(ix) @@ -53,13 +55,13 @@ test("voucherIntercept is executed", async () => { test("voucherIntercept throws error", async () => { let executed = false - const checkFuncThrowError = async voucher => { + const checkFuncThrowError = async (voucher: any) => { executed = true throw new Error("test error") } const ix = { - tag: "TRANSACTION", + tag: InteractionTag.TRANSACTION, assigns: { "ix.voucher-intercept": checkFuncThrowError, }, @@ -67,15 +69,15 @@ test("voucherIntercept throws error", async () => { cadence: "", refBlock: "123", computeLimit: 156, - proposer: null, - payer: null, + proposer: "", + payer: "", authorizations: [], params: [], arguments: [], }, accounts: { foo: { - kind: "ACCOUNT", + kind: InteractionResolverKind.ACCOUNT, tempId: "foo", addr: "foo", keyId: 1, @@ -84,12 +86,13 @@ test("voucherIntercept throws error", async () => { signingFunction: () => ({signature: "123"}), resolve: null, role: {proposer: false, authorizer: false, payer: true, param: false}, + authorization: () => {}, }, }, proposer: "foo", authorizations: ["foo"], - payer: "foo", - } + payer: ["foo"], + } as any await expect(resolveVoucherIntercept(ix)).rejects.toThrow() diff --git a/packages/sdk/src/resolve/resolve-voucher-intercept.ts b/packages/sdk/src/resolve/resolve-voucher-intercept.ts new file mode 100644 index 000000000..60c8d7d53 --- /dev/null +++ b/packages/sdk/src/resolve/resolve-voucher-intercept.ts @@ -0,0 +1,13 @@ +import {get, isFn} from "../interaction/interaction" +import {Interaction} from "@onflow/typedefs" +import {createSignableVoucher} from "./voucher" + +export async function resolveVoucherIntercept( + ix: Interaction +): Promise { + const fn = get(ix, "ix.voucher-intercept", null) + if (isFn(fn)) { + await fn(createSignableVoucher(ix)) + } + return ix +} diff --git a/packages/sdk/src/resolve/resolve.js b/packages/sdk/src/resolve/resolve.ts similarity index 52% rename from packages/sdk/src/resolve/resolve.js rename to packages/sdk/src/resolve/resolve.ts index d8c57c3b8..acc326a1e 100644 --- a/packages/sdk/src/resolve/resolve.js +++ b/packages/sdk/src/resolve/resolve.ts @@ -5,30 +5,33 @@ import {Buffer} from "@onflow/rlp" import {send as defaultSend} from "@onflow/transport-http" import * as ixModule from "../interaction/interaction" import {response} from "../response/response" -import {build} from "../build/build.js" -import {getBlock} from "../build/build-get-block.js" -import {getAccount} from "../build/build-get-account.js" -import {decodeResponse as decode} from "../decode/decode.js" +import {build} from "../build/build" +import {getBlock} from "../build/build-get-block" +import {getAccount} from "../build/build-get-account" +import {decodeResponse as decode} from "../decode/decode" +import {Interaction} from "@onflow/typedefs" -import {resolveCadence} from "./resolve-cadence.js" -import {resolveArguments} from "./resolve-arguments.js" +import {resolveCadence} from "./resolve-cadence" +import {resolveArguments} from "./resolve-arguments" import {resolveAccounts} from "./resolve-accounts" import {resolveSignatures} from "./resolve-signatures" -import {resolveValidators} from "./resolve-validators.js" -import {resolveFinalNormalization} from "./resolve-final-normalization.js" -import {resolveVoucherIntercept} from "./resolve-voucher-intercept.js" -import {resolveComputeLimit} from "./resolve-compute-limit.js" +import {resolveValidators} from "./resolve-validators" +import {resolveFinalNormalization} from "./resolve-final-normalization" +import {resolveVoucherIntercept} from "./resolve-voucher-intercept" +import {resolveComputeLimit} from "./resolve-compute-limit" -const noop = v => v +type DebugCallback = (ix: Interaction, log: any, accts?: any) => any + +const noop = (v: any) => v const debug = - (key, fn = noop) => - async ix => { - const take = (obj, keys = []) => { + (key: string, fn: DebugCallback = noop) => + async (ix: Interaction): Promise => { + const take = (obj: any, keys: string | string[] = []) => { if (typeof keys === "string") keys = keys.split(" ") keys.reduce((acc, key) => ({...acc, [key]: obj[key]}), {}) } - const accts = ix => + const accts = (ix: Interaction) => [ "\nAccounts:", { @@ -40,7 +43,7 @@ const debug = ix.accounts, ].filter(Boolean) - const log = (...msg) => { + const log = (...msg: any[]) => { console.log(`debug[${key}] ---\n`, ...msg, "\n\n\n---") } @@ -50,33 +53,41 @@ const debug = export const resolve = pipe([ resolveCadence, - debug("cadence", (ix, log) => log(ix.message.cadence)), + debug("cadence", (ix: Interaction, log: any) => log(ix.message.cadence)), resolveComputeLimit, - debug("compute limit", (ix, log) => log(ix.message.computeLimit)), + debug("compute limit", (ix: Interaction, log: any) => + log(ix.message.computeLimit) + ), resolveArguments, - debug("arguments", (ix, log) => log(ix.message.arguments, ix.message)), + debug("arguments", (ix: Interaction, log: any) => + log(ix.message.arguments, ix.message) + ), resolveAccounts, - debug("accounts", (ix, log, accts) => log(...accts(ix))), + debug("accounts", (ix: Interaction, log: any, accts: any) => + log(...accts(ix)) + ), /* special */ execFetchRef, /* special */ execFetchSequenceNumber, resolveSignatures, - debug("signatures", (ix, log, accts) => log(...accts(ix))), + debug("signatures", (ix: Interaction, log: any, accts: any) => + log(...accts(ix)) + ), resolveFinalNormalization, resolveValidators, resolveVoucherIntercept, - debug("resolved", (ix, log) => log(ix)), + debug("resolved", (ix: Interaction, log: any) => log(ix)), ]) -async function execFetchRef(ix) { +async function execFetchRef(ix: Interaction): Promise { if (isTransaction(ix) && ix.message.refBlock == null) { const node = await config().get("accessNode.api") - const sendFn = await config.first( + const sendFn: any = await config.first( ["sdk.transport", "sdk.send"], defaultSend ) invariant( - sendFn, + sendFn !== undefined, `Required value for sdk.transport is not defined in config. See: ${"https://github.com/onflow/fcl-js/blob/master/packages/sdk/CHANGELOG.md#0057-alpha1----2022-01-21"}` ) @@ -91,31 +102,35 @@ async function execFetchRef(ix) { return ix } -async function execFetchSequenceNumber(ix) { +async function execFetchSequenceNumber(ix: Interaction): Promise { if (isTransaction(ix)) { - var acct = Object.values(ix.accounts).find(a => a.role.proposer) - invariant(acct, `Transactions require a proposer`) - if (acct.sequenceNum == null) { + var acct = Object.values(ix.accounts).find((a: any) => a.role.proposer) + invariant(acct !== undefined, `Transactions require a proposer`) + if (acct && acct.sequenceNum == null) { const node = await config().get("accessNode.api") - const sendFn = await config.first( + const sendFn: any = await config.first( ["sdk.transport", "sdk.send"], defaultSend ) invariant( - sendFn, + sendFn !== undefined, `Required value for sdk.transport is not defined in config. See: ${"https://github.com/onflow/fcl-js/blob/master/packages/sdk/CHANGELOG.md#0057-alpha1----2022-01-21"}` ) - ix.accounts[acct.tempId].sequenceNum = await sendFn( - await build([getAccount(acct.addr)]), + const keyId = acct.keyId + const tempId = acct.tempId + const addr = acct.addr || "" + + ix.accounts[tempId].sequenceNum = await sendFn( + await build([getAccount(addr)]), {config, response, Buffer, ix: ixModule}, {node} ) .then(decode) - .then(acct => acct.keys) - .then(keys => keys.find(key => key.index === acct.keyId)) - .then(key => key.sequenceNumber) + .then((acctResponse: any) => acctResponse.keys) + .then((keys: any[]) => keys.find((key: any) => key.index === keyId)) + .then((key: any) => key.sequenceNumber) } } return ix diff --git a/packages/sdk/src/sdk.ts b/packages/sdk/src/sdk.ts index 6676fa5f9..82e0a98d7 100644 --- a/packages/sdk/src/sdk.ts +++ b/packages/sdk/src/sdk.ts @@ -1,9 +1,9 @@ import * as logger from "@onflow/util-logger" // Base -export {build} from "./build/build.js" -export {resolve} from "./resolve/resolve.js" -export {send} from "./send/send.js" -export {decode} from "./decode/sdk-decode.js" +export {build} from "./build/build" +export {resolve} from "./resolve/resolve" +export {send} from "./send/send" +export {decode} from "./decode/sdk-decode" export { encodeTransactionPayload, encodeTransactionEnvelope, @@ -38,57 +38,62 @@ export { } from "./interaction/interaction" import type {CadenceArgument} from "./interaction/interaction" export {CadenceArgument} // Workaround for babel https://github.com/babel/babel/issues/8361 +import type {InteractionBuilderFn} from "./interaction/interaction" +export {InteractionBuilderFn} export {createSignableVoucher, voucherToTxId} from "./resolve/voucher" -export {encodeMessageFromSignable} from "./wallet-utils/encode-signable.js" +export {encodeMessageFromSignable} from "./wallet-utils/encode-signable" export {template as cadence} from "@onflow/util-template" export {template as cdc} from "@onflow/util-template" +import type {Voucher} from "./wallet-utils/encode-signable" +export {Voucher} + // Helpers export {account} from "./account/account" -export {block} from "./block/block.js" +export {block} from "./block/block" export {nodeVersionInfo} from "./node-version-info/node-version-info" // Builders -export {authorizations, authorization} from "./build/build-authorizations.js" -export {atBlockHeight} from "./build/build-at-block-height.js" -export {atBlockId} from "./build/build-at-block-id.js" -export {atLatestBlock} from "./build/build-at-latest-block.js" -export {getAccount} from "./build/build-get-account.js" -export {getEvents} from "./build/build-get-events.js" -export {getEventsAtBlockHeightRange} from "./build/build-get-events-at-block-height-range.js" +export {authorizations, authorization} from "./build/build-authorizations" +export {atBlockHeight} from "./build/build-at-block-height" +export {atBlockId} from "./build/build-at-block-id" +export {atLatestBlock} from "./build/build-at-latest-block" +export {getAccount} from "./build/build-get-account" +export {getEvents} from "./build/build-get-events" +export {getEventsAtBlockHeightRange} from "./build/build-get-events-at-block-height-range" export {getEventsAtBlockIds} from "./build/build-get-events-at-block-ids" -export {getBlock} from "./build/build-get-block.js" -export {getBlockHeader} from "./build/build-get-block-header.js" +export {getBlock} from "./build/build-get-block" +export {getBlockHeader} from "./build/build-get-block-header" export {getCollection} from "./build/build-get-collection" -export {getTransactionStatus} from "./build/build-get-transaction-status.js" -export {getTransaction} from "./build/build-get-transaction.js" -export {getNetworkParameters} from "./build/build-get-network-parameters.js" +export {getTransactionStatus} from "./build/build-get-transaction-status" +export {getTransaction} from "./build/build-get-transaction" +export {getNetworkParameters} from "./build/build-get-network-parameters" export {getNodeVersionInfo} from "./build/build-get-node-version-info" -export {limit} from "./build/build-limit.js" +export {limit} from "./build/build-limit" export {args, arg} from "./build/build-arguments" -export {proposer} from "./build/build-proposer.js" -export {payer} from "./build/build-payer.js" -export {ping} from "./build/build-ping.js" -export {ref} from "./build/build-ref.js" -export {script} from "./build/build-script.js" -export {transaction} from "./build/build-transaction.js" -export {validator} from "./build/build-validator.js" -export {invariant} from "./build/build-invariant.js" -export {voucherIntercept} from "./build/build-voucher-intercept.js" +export {proposer} from "./build/build-proposer" +export {payer} from "./build/build-payer" +export {ping} from "./build/build-ping" +export {ref} from "./build/build-ref" +export {script} from "./build/build-script" +export {transaction} from "./build/build-transaction" +export {validator} from "./build/build-validator" +export {invariant} from "./build/build-invariant" +export {voucherIntercept} from "./build/build-voucher-intercept" export {subscribeEvents} from "./build/build-subscribe-events" // Resolvers -export {resolveCadence} from "./resolve/resolve-cadence.js" +export {resolveCadence} from "./resolve/resolve-cadence" export {resolveFinalNormalization} from "./resolve/resolve-final-normalization" export {resolveProposerSequenceNumber} from "./resolve/resolve-proposer-sequence-number" -export {resolveArguments} from "./resolve/resolve-arguments.js" +export {resolveArguments} from "./resolve/resolve-arguments" export {resolveAccounts} from "./resolve/resolve-accounts" export {response} from "./response/response" export {resolveSignatures} from "./resolve/resolve-signatures" -export {resolveValidators} from "./resolve/resolve-validators.js" -export {resolveRefBlockId} from "./resolve/resolve-ref-block-id.js" -export {resolveVoucherIntercept} from "./resolve/resolve-voucher-intercept.js" +export {resolveValidators} from "./resolve/resolve-validators" +export {resolveRefBlockId} from "./resolve/resolve-ref-block-id" +export {resolveVoucherIntercept} from "./resolve/resolve-voucher-intercept" export {config} from "@onflow/config" @@ -116,3 +121,8 @@ export {TestUtils} export {VERSION} from "./VERSION" export {flowMainnet, flowTestnet, flowEmulator} from "./constants" + +export * from "@onflow/typedefs" + +import * as types from "@onflow/types" +export {types as t} diff --git a/packages/sdk/src/send/send.js b/packages/sdk/src/send/send.js deleted file mode 100644 index 1ed79a758..000000000 --- a/packages/sdk/src/send/send.js +++ /dev/null @@ -1,40 +0,0 @@ -import {Buffer} from "@onflow/rlp" -import {send as defaultSend} from "@onflow/transport-http" -import {initInteraction, pipe} from "../interaction/interaction" -import * as ixModule from "../interaction/interaction" -import {invariant} from "../build/build-invariant.js" -import {response} from "../response/response" -import {config} from "@onflow/config" -import {resolve as defaultResolve} from "../resolve/resolve.js" - -/** - * @description - Sends arbitrary scripts, transactions, and requests to Flow - * @param {Array. | Function | false} args - An array of functions that take interaction and return interaction - * @param {object} opts - Optional parameters - * @returns {Promise<*>} - A promise that resolves to a response - */ -export const send = async (args = [], opts = {}) => { - const sendFn = await config.first( - ["sdk.transport", "sdk.send"], - opts.send || defaultSend - ) - - invariant( - sendFn, - `Required value for sdk.transport is not defined in config. See: ${"https://github.com/onflow/fcl-js/blob/master/packages/sdk/CHANGELOG.md#0057-alpha1----2022-01-21"}` - ) - - const resolveFn = await config.first( - ["sdk.resolve"], - opts.resolve || defaultResolve - ) - - opts.node = opts.node || (await config().get("accessNode.api")) - - if (Array.isArray(args)) args = pipe(initInteraction(), args) - return sendFn( - await resolveFn(args), - {config, response, ix: ixModule, Buffer}, - opts - ) -} diff --git a/packages/sdk/src/send/send.test.js b/packages/sdk/src/send/send.test.ts similarity index 100% rename from packages/sdk/src/send/send.test.js rename to packages/sdk/src/send/send.test.ts diff --git a/packages/sdk/src/send/send.ts b/packages/sdk/src/send/send.ts new file mode 100644 index 000000000..0b65c551e --- /dev/null +++ b/packages/sdk/src/send/send.ts @@ -0,0 +1,53 @@ +import {config} from "@onflow/config" +import {Buffer} from "@onflow/rlp" +import {send as defaultSend} from "@onflow/transport-http" +import {invariant} from "../build/build-invariant" +import * as ixModule from "../interaction/interaction" +import { + initInteraction, + InteractionBuilderFn, + pipe, +} from "../interaction/interaction" +import {resolve as defaultResolve} from "../resolve/resolve" +import {response} from "../response/response" + +interface SendOptions { + send?: typeof defaultSend + resolve?: typeof defaultResolve + node?: string +} + +/** + * @description Sends arbitrary scripts, transactions, and requests to Flow + * @param args An array of functions that take interaction and return interaction + * @param opts Optional parameters + * @returns A promise that resolves to a response + */ +export const send = async ( + args: (InteractionBuilderFn | false)[] | InteractionBuilderFn | false, + opts: SendOptions = {} +): Promise => { + const sendFn = await config.first( + ["sdk.transport", "sdk.send"], + opts.send || defaultSend + ) + + invariant( + sendFn, + `Required value for sdk.transport is not defined in config. See: ${"https://github.com/onflow/fcl-js/blob/master/packages/sdk/CHANGELOG.md#0057-alpha1----2022-01-21"}` + ) + + const resolveFn: any = await config.first( + ["sdk.resolve"], + opts.resolve || defaultResolve + ) + + opts.node = opts.node || (await config().get("accessNode.api")) + + if (Array.isArray(args)) args = pipe(initInteraction(), args as any) as any + return sendFn( + await resolveFn(args), + {config, response, ix: ixModule, Buffer} as any, + opts + ) +} diff --git a/packages/sdk/src/test-utils/index.js b/packages/sdk/src/test-utils/index.ts similarity index 100% rename from packages/sdk/src/test-utils/index.js rename to packages/sdk/src/test-utils/index.ts diff --git a/packages/sdk/src/test-utils/run.js b/packages/sdk/src/test-utils/run.js deleted file mode 100644 index 3ca7df443..000000000 --- a/packages/sdk/src/test-utils/run.js +++ /dev/null @@ -1,5 +0,0 @@ -import {build} from "../build/build" -import {resolve} from "../resolve/resolve" -import {ref} from "../build/build-ref" - -export const run = (fns = []) => build([ref("123"), ...fns]).then(resolve) diff --git a/packages/sdk/src/test-utils/run.ts b/packages/sdk/src/test-utils/run.ts new file mode 100644 index 000000000..fbc70bf48 --- /dev/null +++ b/packages/sdk/src/test-utils/run.ts @@ -0,0 +1,8 @@ +import {build} from "../build/build" +import {resolve} from "../resolve/resolve" +import {ref} from "../build/build-ref" +import {Interaction} from "@onflow/typedefs" + +export const run = ( + fns: Array<(ix: Interaction) => Interaction | Promise> = [] +) => build([ref("123"), ...fns]).then(resolve) diff --git a/packages/sdk/src/wallet-utils/encode-signable.test.js b/packages/sdk/src/wallet-utils/encode-signable.test.ts similarity index 98% rename from packages/sdk/src/wallet-utils/encode-signable.test.js rename to packages/sdk/src/wallet-utils/encode-signable.test.ts index f6d88aa44..c8c1c8078 100644 --- a/packages/sdk/src/wallet-utils/encode-signable.test.js +++ b/packages/sdk/src/wallet-utils/encode-signable.test.ts @@ -1,7 +1,7 @@ import { encodeMessageFromSignable, UnableToDetermineMessageEncodingTypeForSignerAddress, -} from "./encode-signable.js" +} from "./encode-signable" import { encodeTransactionPayload as encodeInsideMessage, encodeTransactionEnvelope as encodeOutsideMessage, diff --git a/packages/sdk/src/wallet-utils/encode-signable.js b/packages/sdk/src/wallet-utils/encode-signable.ts similarity index 64% rename from packages/sdk/src/wallet-utils/encode-signable.js rename to packages/sdk/src/wallet-utils/encode-signable.ts index 724c78d0a..77253baa9 100644 --- a/packages/sdk/src/wallet-utils/encode-signable.js +++ b/packages/sdk/src/wallet-utils/encode-signable.ts @@ -4,22 +4,55 @@ import { encodeTransactionEnvelope, } from "../encode/encode" -const findPayloadSigners = voucher => { +interface Sig { + address: string + keyId: number | string + sig: string +} + +interface PayloadSig { + address: string + keyId: number | string + sig: string + [key: string]: any +} + +export interface Voucher { + authorizers: string[] + proposalKey: { + address: string + keyId?: number | string + sequenceNum?: number + [key: string]: any + } + payer: string + cadence: string + refBlock: string + computeLimit: number + arguments: any[] + payloadSigs: PayloadSig[] +} + +interface Signable { + voucher: Voucher +} + +const findPayloadSigners = (voucher: Voucher): string[] => { // Payload Signers Are: (authorizers + proposer) - payer - let payload = new Set(voucher.authorizers) + const payload: Set = new Set(voucher.authorizers) payload.add(voucher.proposalKey.address) payload.delete(voucher.payer) - return Array.from(payload).map(withPrefix) + return Array.from(payload).map(addr => withPrefix(addr)) } -const findEnvelopeSigners = voucher => { +const findEnvelopeSigners = (voucher: Voucher): string[] => { // Envelope Signers Are: (payer) - let envelope = new Set([voucher.payer]) - return Array.from(envelope).map(withPrefix) + const envelope: Set = new Set([voucher.payer]) + return Array.from(envelope).map(addr => withPrefix(addr)) } export class UnableToDetermineMessageEncodingTypeForSignerAddress extends Error { - constructor(signerAddress) { + constructor(signerAddress: string) { const msg = ` Encode Message From Signable Error: Unable to determine message encoding for signer addresss: ${signerAddress}. Please ensure the address: ${signerAddress} is intended to sign the given transaction as specified by the transaction signable. @@ -29,7 +62,10 @@ export class UnableToDetermineMessageEncodingTypeForSignerAddress extends Error } } -export const encodeMessageFromSignable = (signable, signerAddress) => { +export const encodeMessageFromSignable = ( + signable: Signable, + signerAddress: string +): string => { let payloadSigners = findPayloadSigners(signable.voucher) let envelopeSigners = findEnvelopeSigners(signable.voucher) @@ -42,7 +78,7 @@ export const encodeMessageFromSignable = (signable, signerAddress) => { ) } - const message = { + const message: any = { cadence: signable.voucher.cadence, refBlock: signable.voucher.refBlock, computeLimit: signable.voucher.computeLimit, diff --git a/packages/sdk/src/wallet-utils/index.js b/packages/sdk/src/wallet-utils/index.js deleted file mode 100644 index e3c4a24bf..000000000 --- a/packages/sdk/src/wallet-utils/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export {validateSignableTransaction} from "./validate-tx.js" -export {encodeMessageFromSignable} from "./encode-signable.js" diff --git a/packages/sdk/src/wallet-utils/index.ts b/packages/sdk/src/wallet-utils/index.ts new file mode 100644 index 000000000..0071d56cf --- /dev/null +++ b/packages/sdk/src/wallet-utils/index.ts @@ -0,0 +1,2 @@ +export {validateSignableTransaction} from "./validate-tx" +export {encodeMessageFromSignable} from "./encode-signable" diff --git a/packages/sdk/src/wallet-utils/validate-tx.test.js b/packages/sdk/src/wallet-utils/validate-tx.test.ts similarity index 97% rename from packages/sdk/src/wallet-utils/validate-tx.test.js rename to packages/sdk/src/wallet-utils/validate-tx.test.ts index b0ae56c26..3cae2d508 100644 --- a/packages/sdk/src/wallet-utils/validate-tx.test.js +++ b/packages/sdk/src/wallet-utils/validate-tx.test.ts @@ -1,4 +1,4 @@ -import {validateSignableTransaction} from "./" +import {validateSignableTransaction} from "." import { encodeTransactionPayload as encodeInsideMessage, encodeTransactionEnvelope as encodeOutsideMessage, diff --git a/packages/sdk/src/wallet-utils/validate-tx.js b/packages/sdk/src/wallet-utils/validate-tx.ts similarity index 58% rename from packages/sdk/src/wallet-utils/validate-tx.js rename to packages/sdk/src/wallet-utils/validate-tx.ts index 03b639d0c..e8cff04de 100644 --- a/packages/sdk/src/wallet-utils/validate-tx.js +++ b/packages/sdk/src/wallet-utils/validate-tx.ts @@ -4,23 +4,33 @@ import { } from "../encode/encode" import {invariant} from "@onflow/util-invariant" -const isPayer = signable => { +interface Signable { + roles: { + payer: boolean + } + voucher: any + message: string +} + +const isPayer = (signable: Signable): boolean => { return signable.roles.payer } -const getVoucher = signable => { + +const getVoucher = (signable: Signable): any => { return signable.voucher } -const getMessage = signable => { + +const getMessage = (signable: Signable): string => { return signable.message } -const isExpectedMessage = signable => { +const isExpectedMessage = (signable: Signable): boolean => { return isPayer(signable) ? encodeOutsideMessage(getVoucher(signable)) === getMessage(signable) : encodeInsideMessage(getVoucher(signable)) === getMessage(signable) } -export const validateSignableTransaction = signable => { +export const validateSignableTransaction = (signable: Signable): boolean => { invariant(isExpectedMessage(signable), "Signable payload must be transaction") return true diff --git a/packages/typedefs/src/interaction.ts b/packages/typedefs/src/interaction.ts index 0d45c8d72..3896cbde9 100644 --- a/packages/typedefs/src/interaction.ts +++ b/packages/typedefs/src/interaction.ts @@ -72,8 +72,8 @@ export interface Interaction { payer: string[] events: { eventType: string | null - start: string | null - end: string | null + start: string | number | null + end: string | number | null blockIds: string[] } transaction: { @@ -81,7 +81,7 @@ export interface Interaction { } block: { id: string | null - height: string | null + height: string | number | null isSealed: boolean | null } account: { From 5cc9c55c0f29b2d8aa820c696e22b9901f2f82b6 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Tue, 13 May 2025 09:37:00 -0700 Subject: [PATCH 39/72] Fix payload type --- packages/sdk/src/decode/decode.ts | 3 +++ packages/typedefs/src/subscriptions.ts | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/sdk/src/decode/decode.ts b/packages/sdk/src/decode/decode.ts index 4aa5b542e..040d5bc67 100644 --- a/packages/sdk/src/decode/decode.ts +++ b/packages/sdk/src/decode/decode.ts @@ -68,6 +68,9 @@ interface FlowResponse { account?: any block?: any blockHeader?: any + blockDigest?: any + event?: any + accountStatusEvent?: any latestBlock?: any transactionId?: string collection?: any diff --git a/packages/typedefs/src/subscriptions.ts b/packages/typedefs/src/subscriptions.ts index 291aa395e..3c73f8c64 100644 --- a/packages/typedefs/src/subscriptions.ts +++ b/packages/typedefs/src/subscriptions.ts @@ -52,7 +52,10 @@ type SubscriptionDataMap = { type RawSubscriptionDataMap = { [SubscriptionTopic.EVENTS]: { event: Omit & { - payload: string + payload: { + type: string + value: any + } } } [SubscriptionTopic.BLOCKS]: { @@ -66,7 +69,10 @@ type RawSubscriptionDataMap = { } [SubscriptionTopic.ACCOUNT_STATUSES]: { accountStatusEvent: Omit & { - payload: string + payload: { + type: string + value: any + } accountAddress: string } } @@ -82,7 +88,10 @@ type RawSubscriptionDataMap = { transactionId: string transactionIndex: number eventIndex: number - payload: string + payload: { + type: string + value: any + } }[] } } From bfac9840b67e9be2f95975f266470212339e0809 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Tue, 13 May 2025 09:41:10 -0700 Subject: [PATCH 40/72] Fix payload decoding --- .../src/subscribe/handlers/account-statuses.ts | 5 +++-- packages/transport-http/src/subscribe/handlers/events.ts | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/transport-http/src/subscribe/handlers/account-statuses.ts b/packages/transport-http/src/subscribe/handlers/account-statuses.ts index 41fe5e601..dabe3ab0b 100644 --- a/packages/transport-http/src/subscribe/handlers/account-statuses.ts +++ b/packages/transport-http/src/subscribe/handlers/account-statuses.ts @@ -1,7 +1,6 @@ import { RawSubscriptionData, SubscriptionArgs, - SubscriptionData, SubscriptionTopic, } from "@onflow/typedefs" import {createSubscriptionHandler} from "./types" @@ -64,7 +63,9 @@ export const accountStatusesHandler = createSubscriptionHandler<{ transactionId: event.transaction_id, transactionIndex: Number(event.transaction_index), eventIndex: Number(event.event_index), - payload: event.payload, + payload: JSON.parse( + Buffer.from(event.payload, "base64").toString() + ), }, } diff --git a/packages/transport-http/src/subscribe/handlers/events.ts b/packages/transport-http/src/subscribe/handlers/events.ts index 031d0deea..bb1998bd8 100644 --- a/packages/transport-http/src/subscribe/handlers/events.ts +++ b/packages/transport-http/src/subscribe/handlers/events.ts @@ -62,7 +62,9 @@ export const eventsHandler = createSubscriptionHandler<{ transactionId: event.transaction_id, transactionIndex: Number(event.transaction_index), eventIndex: Number(event.event_index), - payload: event.payload, + payload: JSON.parse( + Buffer.from(event.payload, "base64").toString() + ), }, } From 05979ba547db2ec53e908605cfc1436ac2b393db Mon Sep 17 00:00:00 2001 From: leopardracer <136604165+leopardracer@users.noreply.github.com> Date: Thu, 15 May 2025 02:58:13 +0300 Subject: [PATCH 41/72] Fix Typos in Documentation Files (#2420) --- .../fcl-core/src/wallet-provider-spec/authorization-function.md | 2 +- packages/types/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/fcl-core/src/wallet-provider-spec/authorization-function.md b/packages/fcl-core/src/wallet-provider-spec/authorization-function.md index 4d4a87a4f..b92879a0b 100644 --- a/packages/fcl-core/src/wallet-provider-spec/authorization-function.md +++ b/packages/fcl-core/src/wallet-provider-spec/authorization-function.md @@ -2,7 +2,7 @@ ## Overview -An Authorization Function is a function which enables the JS-SDK and FCL to know which Flow account fulfills which signatory role in a transaction and how to recieve a signature on behalf of the supplied account. +An Authorization Function is a function which enables the JS-SDK and FCL to know which Flow account fulfills which signatory role in a transaction and how to receive a signature on behalf of the supplied account. ## How to Use an Authorization Function diff --git a/packages/types/README.md b/packages/types/README.md index dfe8d3bf4..7ef970c87 100644 --- a/packages/types/README.md +++ b/packages/types/README.md @@ -403,7 +403,7 @@ sdk.build([ # Exist but not supported -The following, while technically possible, are impracticle. We strongly recommend not using them as arguments for transactions or scripts. +The following, while technically possible, are impractical. We strongly recommend not using them as arguments for transactions or scripts. ### Void From 681c3594ae0d69910f14ef5db0ab896cdc4bd84f Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Thu, 15 May 2025 19:23:31 +0000 Subject: [PATCH 42/72] Enter alpha mode (#2421) --- .changeset/pre.json | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .changeset/pre.json diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 000000000..6948d590c --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,33 @@ +{ + "mode": "pre", + "tag": "alpha", + "initialVersions": { + "@onflow/config": "1.5.2", + "@onflow/fcl": "1.17.0", + "@onflow/fcl-bundle": "1.7.0", + "@onflow/fcl-core": "1.18.0", + "@onflow/fcl-ethereum-provider": "0.0.4", + "@onflow/fcl-rainbowkit-adapter": "0.2.0", + "@onflow/fcl-react-native": "1.11.0", + "@onflow/fcl-wagmi-adapter": "0.0.4", + "@onflow/fcl-wc": "6.0.2", + "@onflow/kit": "0.1.0", + "@onflow/protobuf": "1.3.1", + "@onflow/rlp": "1.2.3", + "@onflow/sdk": "1.8.1", + "@onflow/transport-grpc": "1.4.2-alpha.0", + "@onflow/transport-http": "1.12.0", + "@onflow/typedefs": "1.5.0", + "@onflow/types": "1.4.1", + "@onflow/util-actor": "1.3.4", + "@onflow/util-address": "1.2.3", + "@onflow/util-encode-key": "1.2.4", + "@onflow/util-invariant": "1.2.4", + "@onflow/util-logger": "1.3.3", + "@onflow/util-rpc": "0.0.2", + "@onflow/util-semver": "1.0.3", + "@onflow/util-template": "1.2.3", + "@onflow/util-uid": "1.2.3" + }, + "changesets": [] +} From 099a1a99531172b8249938acf948761e1c8deed6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 15 May 2025 14:02:18 -0700 Subject: [PATCH 43/72] Version Packages (alpha) (#2396) --- .changeset/pre.json | 15 +++- package-lock.json | 78 ++++++++++---------- packages/fcl-core/CHANGELOG.md | 27 +++++++ packages/fcl-core/package.json | 8 +- packages/fcl-ethereum-provider/CHANGELOG.md | 8 ++ packages/fcl-ethereum-provider/package.json | 8 +- packages/fcl-rainbowkit-adapter/CHANGELOG.md | 9 +++ packages/fcl-rainbowkit-adapter/package.json | 10 +-- packages/fcl-react-native/CHANGELOG.md | 27 +++++++ packages/fcl-react-native/package.json | 8 +- packages/fcl-wagmi-adapter/CHANGELOG.md | 8 ++ packages/fcl-wagmi-adapter/package.json | 8 +- packages/fcl-wc/CHANGELOG.md | 7 ++ packages/fcl-wc/package.json | 6 +- packages/fcl/CHANGELOG.md | 28 +++++++ packages/fcl/package.json | 10 +-- packages/kit/CHANGELOG.md | 19 +++++ packages/kit/package.json | 6 +- packages/sdk/CHANGELOG.md | 27 +++++++ packages/sdk/package.json | 6 +- packages/transport-grpc/package.json | 2 +- packages/transport-http/CHANGELOG.md | 19 +++++ packages/transport-http/package.json | 4 +- packages/typedefs/CHANGELOG.md | 8 ++ packages/typedefs/package.json | 2 +- 25 files changed, 279 insertions(+), 79 deletions(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index 6948d590c..e3eeef8f4 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -29,5 +29,18 @@ "@onflow/util-template": "1.2.3", "@onflow/util-uid": "1.2.3" }, - "changesets": [] + "changesets": [ + "breezy-gifts-sit", + "fast-lobsters-train", + "forty-trees-report", + "good-books-call", + "mean-walls-hear", + "moody-ligers-rule", + "odd-seals-glow", + "sharp-suns-refuse", + "shy-cars-beam", + "sixty-pandas-retire", + "spicy-fishes-drum", + "tame-pianos-doubt" + ] } diff --git a/package-lock.json b/package-lock.json index 8a9029893..33320af10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30881,16 +30881,16 @@ }, "packages/fcl": { "name": "@onflow/fcl", - "version": "1.17.0", + "version": "1.18.0-alpha.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.18.0", - "@onflow/fcl-wc": "6.0.2", + "@onflow/fcl-core": "1.19.0-alpha.0", + "@onflow/fcl-wc": "6.0.3-alpha.0", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.1", + "@onflow/sdk": "1.9.0-alpha.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", @@ -30908,7 +30908,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.5.0", + "@onflow/typedefs": "1.6.0-alpha.0", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -30956,7 +30956,7 @@ }, "packages/fcl-core": { "name": "@onflow/fcl-core", - "version": "1.18.0", + "version": "1.19.0-alpha.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -30964,8 +30964,8 @@ "@onflow/config": "1.5.2", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.1", - "@onflow/transport-http": "1.12.0", + "@onflow/sdk": "1.9.0-alpha.0", + "@onflow/transport-http": "1.13.0-alpha.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", @@ -30979,7 +30979,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.5.0", + "@onflow/typedefs": "1.6.0-alpha.0", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -31011,14 +31011,14 @@ }, "packages/fcl-ethereum-provider": { "name": "@onflow/fcl-ethereum-provider", - "version": "0.0.4", + "version": "0.0.5-alpha.0", "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.2", + "@onflow/fcl-wc": "6.0.3-alpha.0", "@onflow/rlp": "^1.2.3", "@walletconnect/ethereum-provider": "^2.20.2", "@walletconnect/jsonrpc-http-connection": "^1.0.8", @@ -31030,7 +31030,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.5.0", + "@onflow/typedefs": "^1.6.0-alpha.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -31039,7 +31039,7 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.17.0" + "@onflow/fcl": "1.18.0-alpha.0" } }, "packages/fcl-ethereum-provider/node_modules/@react-native-async-storage/async-storage": { @@ -31184,14 +31184,14 @@ }, "packages/fcl-rainbowkit-adapter": { "name": "@onflow/fcl-rainbowkit-adapter", - "version": "0.2.0", + "version": "0.2.1-alpha.0", "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.4", - "@onflow/fcl-wagmi-adapter": "0.0.4", + "@onflow/fcl-ethereum-provider": "0.0.5-alpha.0", + "@onflow/fcl-wagmi-adapter": "0.0.5-alpha.0", "@onflow/rlp": "^1.2.3", "@wagmi/core": "^2.16.3", "mipd": "^0.0.7", @@ -31202,7 +31202,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.5.0", + "@onflow/typedefs": "^1.6.0-alpha.0", "@types/jest": "^29.5.13", "@types/react": "^16.0.0", "@typescript-eslint/eslint-plugin": "^6.21.0", @@ -31212,7 +31212,7 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.17.0", + "@onflow/fcl": "1.18.0-alpha.0", "@rainbow-me/rainbowkit": "^2.2.3", "react": "17.x || 18.x || 19.x" } @@ -31229,15 +31229,15 @@ }, "packages/fcl-react-native": { "name": "@onflow/fcl-react-native", - "version": "1.11.0", + "version": "1.12.0-alpha.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.18.0", + "@onflow/fcl-core": "1.19.0-alpha.0", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.1", + "@onflow/sdk": "1.9.0-alpha.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", @@ -31250,7 +31250,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.5.0", + "@onflow/typedefs": "1.6.0-alpha.0", "@types/estree": "^1.0.6", "@types/node": "^18.19.57", "eslint": "^8.57.1", @@ -31288,20 +31288,20 @@ }, "packages/fcl-wagmi-adapter": { "name": "@onflow/fcl-wagmi-adapter", - "version": "0.0.4", + "version": "0.0.5-alpha.0", "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.4", + "@onflow/fcl-ethereum-provider": "0.0.5-alpha.0", "@onflow/rlp": "^1.2.3", "viem": "^2.22.21" }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.5.0", + "@onflow/typedefs": "^1.6.0-alpha.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -31310,13 +31310,13 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.17.0", + "@onflow/fcl": "1.18.0-alpha.0", "@wagmi/core": "^2.16.3" } }, "packages/fcl-wc": { "name": "@onflow/fcl-wc", - "version": "6.0.2", + "version": "6.0.3-alpha.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -31335,7 +31335,7 @@ "@babel/plugin-transform-react-jsx": "^7.25.9", "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.5.0", + "@onflow/typedefs": "1.6.0-alpha.0", "autoprefixer": "^10.4.20", "eslint": "^8.57.1", "eslint-plugin-jsdoc": "^46.10.1", @@ -31343,7 +31343,7 @@ "jest-preset-preact": "^4.1.1" }, "peerDependencies": { - "@onflow/fcl-core": "1.18.0" + "@onflow/fcl-core": "1.19.0-alpha.0" } }, "packages/fcl-wc/node_modules/@react-native-async-storage/async-storage": { @@ -31490,7 +31490,7 @@ }, "packages/kit": { "name": "@onflow/kit", - "version": "0.1.0", + "version": "0.2.0-alpha.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -31503,7 +31503,7 @@ "@babel/preset-react": "^7.26.3", "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.5.0", + "@onflow/typedefs": "^1.6.0-alpha.0", "@testing-library/dom": "^10.4.0", "@types/jest": "^29.5.13", "@types/react": "^19.0.10", @@ -31516,7 +31516,7 @@ "jest-environment-jsdom": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": ">=1.17.0", + "@onflow/fcl": ">=1.18.0-alpha.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } @@ -31702,14 +31702,14 @@ }, "packages/sdk": { "name": "@onflow/sdk", - "version": "1.8.1", + "version": "1.9.0-alpha.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", "@onflow/rlp": "1.2.3", - "@onflow/transport-http": "1.12.0", - "@onflow/typedefs": "1.5.0", + "@onflow/transport-http": "1.13.0-alpha.0", + "@onflow/typedefs": "1.6.0-alpha.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", @@ -31758,13 +31758,13 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/sdk": "1.8.1", + "@onflow/sdk": "1.9.0-alpha.0", "jest": "^29.7.0" } }, "packages/transport-http": { "name": "@onflow/transport-http", - "version": "1.12.0", + "version": "1.13.0-alpha.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -31782,7 +31782,7 @@ "devDependencies": { "@onflow/fcl-bundle": "1.7.0", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.1", + "@onflow/sdk": "1.9.0-alpha.0", "@onflow/types": "1.4.1", "jest": "^29.7.0", "jest-websocket-mock": "^2.5.0", @@ -31798,7 +31798,7 @@ }, "packages/typedefs": { "name": "@onflow/typedefs", - "version": "1.5.0", + "version": "1.6.0-alpha.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7" diff --git a/packages/fcl-core/CHANGELOG.md b/packages/fcl-core/CHANGELOG.md index 2a05b6164..9f6458925 100644 --- a/packages/fcl-core/CHANGELOG.md +++ b/packages/fcl-core/CHANGELOG.md @@ -1,5 +1,32 @@ # @onflow/fcl +## 1.19.0-alpha.0 + +### Minor Changes + +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `rawSubscribe`. + + These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. + + The following topics are now available: + + - `blocks` + - `block_headers` + - `block_digests` + - `transaction_statues` + - `events` + - `account_statuses` + + Developers using `fcl.tx` and `fcl.events` will not need to make any changes to their existing app to realize the latency improvements of this change and will automatically benefit by upgrading to this version. + + Please see the [Flow Developer Documentation](https://developers.flow.com/clients/fcl-js/) for more details on how to use these new methods. + +### Patch Changes + +- Updated dependencies [[`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`694cd76807b7ca4441d1f8425ac4f8426cbc18fa`](https://github.com/onflow/fcl-js/commit/694cd76807b7ca4441d1f8425ac4f8426cbc18fa), [`4d3bb084c1442552d6a1de1f53435d1aa3f600b0`](https://github.com/onflow/fcl-js/commit/4d3bb084c1442552d6a1de1f53435d1aa3f600b0)]: + - @onflow/transport-http@1.13.0-alpha.0 + - @onflow/sdk@1.9.0-alpha.0 + ## 1.18.0 ### Minor Changes diff --git a/packages/fcl-core/package.json b/packages/fcl-core/package.json index b26b2d2bb..5a4e59f99 100644 --- a/packages/fcl-core/package.json +++ b/packages/fcl-core/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-core", - "version": "1.18.0", + "version": "1.19.0-alpha.0", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", @@ -20,7 +20,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.5.0", + "@onflow/typedefs": "1.6.0-alpha.0", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -52,8 +52,8 @@ "@onflow/config": "1.5.2", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.1", - "@onflow/transport-http": "1.12.0", + "@onflow/sdk": "1.9.0-alpha.0", + "@onflow/transport-http": "1.13.0-alpha.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", diff --git a/packages/fcl-ethereum-provider/CHANGELOG.md b/packages/fcl-ethereum-provider/CHANGELOG.md index ca9312bdd..29714ffa3 100644 --- a/packages/fcl-ethereum-provider/CHANGELOG.md +++ b/packages/fcl-ethereum-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @onflow/fcl-ethereum-provider +## 0.0.5-alpha.0 + +### Patch Changes + +- Updated dependencies [[`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab)]: + - @onflow/fcl@1.18.0-alpha.0 + - @onflow/fcl-wc@6.0.3-alpha.0 + ## 0.0.4 ### Patch Changes diff --git a/packages/fcl-ethereum-provider/package.json b/packages/fcl-ethereum-provider/package.json index f23fd8f19..013976343 100644 --- a/packages/fcl-ethereum-provider/package.json +++ b/packages/fcl-ethereum-provider/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-ethereum-provider", - "version": "0.0.4", + "version": "0.0.5-alpha.0", "description": "Ethereum provider for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -15,7 +15,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.5.0", + "@onflow/typedefs": "^1.6.0-alpha.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -40,7 +40,7 @@ "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", "@noble/hashes": "^1.7.1", - "@onflow/fcl-wc": "6.0.2", + "@onflow/fcl-wc": "6.0.3-alpha.0", "@onflow/rlp": "^1.2.3", "@walletconnect/ethereum-provider": "^2.20.2", "@walletconnect/jsonrpc-http-connection": "^1.0.8", @@ -50,6 +50,6 @@ "@walletconnect/utils": "^2.20.2" }, "peerDependencies": { - "@onflow/fcl": "1.17.0" + "@onflow/fcl": "1.18.0-alpha.0" } } diff --git a/packages/fcl-rainbowkit-adapter/CHANGELOG.md b/packages/fcl-rainbowkit-adapter/CHANGELOG.md index 1eb8aedb0..bc80b6535 100644 --- a/packages/fcl-rainbowkit-adapter/CHANGELOG.md +++ b/packages/fcl-rainbowkit-adapter/CHANGELOG.md @@ -1,5 +1,14 @@ # @onflow/fcl-rainbowkit-adapter +## 0.2.1-alpha.0 + +### Patch Changes + +- Updated dependencies [[`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab)]: + - @onflow/fcl@1.18.0-alpha.0 + - @onflow/fcl-ethereum-provider@1.0.0-alpha.0 + - @onflow/fcl-wagmi-adapter@1.0.0-alpha.0 + ## 0.2.0 ### Minor Changes diff --git a/packages/fcl-rainbowkit-adapter/package.json b/packages/fcl-rainbowkit-adapter/package.json index 9be86d943..bc35caac5 100644 --- a/packages/fcl-rainbowkit-adapter/package.json +++ b/packages/fcl-rainbowkit-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-rainbowkit-adapter", - "version": "0.2.0", + "version": "0.2.1-alpha.0", "description": "Rainbowkit adapter for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -15,7 +15,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.5.0", + "@onflow/typedefs": "^1.6.0-alpha.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -40,8 +40,8 @@ "@babel/runtime": "^7.25.7", "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", - "@onflow/fcl-ethereum-provider": "0.0.4", - "@onflow/fcl-wagmi-adapter": "0.0.4", + "@onflow/fcl-ethereum-provider": "0.0.5-alpha.0", + "@onflow/fcl-wagmi-adapter": "0.0.5-alpha.0", "@onflow/rlp": "^1.2.3", "@wagmi/core": "^2.16.3", "mipd": "^0.0.7", @@ -50,7 +50,7 @@ "wagmi": "^2.14.11" }, "peerDependencies": { - "@onflow/fcl": "1.17.0", + "@onflow/fcl": "1.18.0-alpha.0", "@rainbow-me/rainbowkit": "^2.2.3", "react": "17.x || 18.x || 19.x" } diff --git a/packages/fcl-react-native/CHANGELOG.md b/packages/fcl-react-native/CHANGELOG.md index 561a0f354..5f8234ac2 100644 --- a/packages/fcl-react-native/CHANGELOG.md +++ b/packages/fcl-react-native/CHANGELOG.md @@ -1,5 +1,32 @@ # @onflow/fcl-react-native +## 1.12.0-alpha.0 + +### Minor Changes + +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `rawSubscribe`. + + These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. + + The following topics are now available: + + - `blocks` + - `block_headers` + - `block_digests` + - `transaction_statues` + - `events` + - `account_statuses` + + Developers using `fcl.tx` and `fcl.events` will not need to make any changes to their existing app to realize the latency improvements of this change and will automatically benefit by upgrading to this version. + + Please see the [Flow Developer Documentation](https://developers.flow.com/clients/fcl-js/) for more details on how to use these new methods. + +### Patch Changes + +- Updated dependencies [[`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`4d3bb084c1442552d6a1de1f53435d1aa3f600b0`](https://github.com/onflow/fcl-js/commit/4d3bb084c1442552d6a1de1f53435d1aa3f600b0)]: + - @onflow/fcl-core@1.19.0-alpha.0 + - @onflow/sdk@1.9.0-alpha.0 + ## 1.11.0 ### Minor Changes diff --git a/packages/fcl-react-native/package.json b/packages/fcl-react-native/package.json index 42aefd1ac..08e64e050 100644 --- a/packages/fcl-react-native/package.json +++ b/packages/fcl-react-native/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-react-native", - "version": "1.11.0", + "version": "1.12.0-alpha.0", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", @@ -20,7 +20,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.5.0", + "@onflow/typedefs": "1.6.0-alpha.0", "@types/estree": "^1.0.6", "@types/node": "^18.19.57", "eslint": "^8.57.1", @@ -48,10 +48,10 @@ "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.18.0", + "@onflow/fcl-core": "1.19.0-alpha.0", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.1", + "@onflow/sdk": "1.9.0-alpha.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", diff --git a/packages/fcl-wagmi-adapter/CHANGELOG.md b/packages/fcl-wagmi-adapter/CHANGELOG.md index b125e9ff0..8e33ff5bc 100644 --- a/packages/fcl-wagmi-adapter/CHANGELOG.md +++ b/packages/fcl-wagmi-adapter/CHANGELOG.md @@ -1,5 +1,13 @@ # @onflow/fcl-wagmi-adapter +## 0.0.5-alpha.0 + +### Patch Changes + +- Updated dependencies [[`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab)]: + - @onflow/fcl@1.18.0-alpha.0 + - @onflow/fcl-ethereum-provider@0.0.5-alpha.0 + ## 0.0.4 ### Patch Changes diff --git a/packages/fcl-wagmi-adapter/package.json b/packages/fcl-wagmi-adapter/package.json index 552f8e736..f81c60e09 100644 --- a/packages/fcl-wagmi-adapter/package.json +++ b/packages/fcl-wagmi-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-wagmi-adapter", - "version": "0.0.4", + "version": "0.0.5-alpha.0", "description": "Wagmi adapter for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -15,7 +15,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.5.0", + "@onflow/typedefs": "^1.6.0-alpha.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -39,12 +39,12 @@ "@babel/runtime": "^7.25.7", "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", - "@onflow/fcl-ethereum-provider": "0.0.4", + "@onflow/fcl-ethereum-provider": "0.0.5-alpha.0", "@onflow/rlp": "^1.2.3", "viem": "^2.22.21" }, "peerDependencies": { - "@onflow/fcl": "1.17.0", + "@onflow/fcl": "1.18.0-alpha.0", "@wagmi/core": "^2.16.3" } } diff --git a/packages/fcl-wc/CHANGELOG.md b/packages/fcl-wc/CHANGELOG.md index ba2011daf..65527af6b 100644 --- a/packages/fcl-wc/CHANGELOG.md +++ b/packages/fcl-wc/CHANGELOG.md @@ -1,5 +1,12 @@ # @onflow/fcl-wc +## 6.0.3-alpha.0 + +### Patch Changes + +- Updated dependencies [[`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab)]: + - @onflow/fcl-core@1.19.0-alpha.0 + ## 6.0.2 ### Patch Changes diff --git a/packages/fcl-wc/package.json b/packages/fcl-wc/package.json index ed6fb9832..25eaf5f14 100644 --- a/packages/fcl-wc/package.json +++ b/packages/fcl-wc/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-wc", - "version": "6.0.2", + "version": "6.0.3-alpha.0", "description": "WalletConnect adapter for FCL", "license": "Apache-2.0", "author": "Flow Foundation", @@ -31,7 +31,7 @@ "@babel/plugin-transform-react-jsx": "^7.25.9", "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.5.0", + "@onflow/typedefs": "1.6.0-alpha.0", "autoprefixer": "^10.4.20", "eslint": "^8.57.1", "eslint-plugin-jsdoc": "^46.10.1", @@ -52,6 +52,6 @@ "tailwindcss": "^3.4.14" }, "peerDependencies": { - "@onflow/fcl-core": "1.18.0" + "@onflow/fcl-core": "1.19.0-alpha.0" } } diff --git a/packages/fcl/CHANGELOG.md b/packages/fcl/CHANGELOG.md index c32b860f6..420e22d7c 100644 --- a/packages/fcl/CHANGELOG.md +++ b/packages/fcl/CHANGELOG.md @@ -1,5 +1,33 @@ # @onflow/fcl +## 1.18.0-alpha.0 + +### Minor Changes + +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `rawSubscribe`. + + These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. + + The following topics are now available: + + - `blocks` + - `block_headers` + - `block_digests` + - `transaction_statues` + - `events` + - `account_statuses` + + Developers using `fcl.tx` and `fcl.events` will not need to make any changes to their existing app to realize the latency improvements of this change and will automatically benefit by upgrading to this version. + + Please see the [Flow Developer Documentation](https://developers.flow.com/clients/fcl-js/) for more details on how to use these new methods. + +### Patch Changes + +- Updated dependencies [[`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`4d3bb084c1442552d6a1de1f53435d1aa3f600b0`](https://github.com/onflow/fcl-js/commit/4d3bb084c1442552d6a1de1f53435d1aa3f600b0)]: + - @onflow/fcl-core@1.19.0-alpha.0 + - @onflow/sdk@1.9.0-alpha.0 + - @onflow/fcl-wc@7.0.0-alpha.0 + ## 1.17.0 ### Minor Changes diff --git a/packages/fcl/package.json b/packages/fcl/package.json index d0ec3d507..52b46f3a8 100644 --- a/packages/fcl/package.json +++ b/packages/fcl/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl", - "version": "1.17.0", + "version": "1.18.0-alpha.0", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", @@ -20,7 +20,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.5.0", + "@onflow/typedefs": "1.6.0-alpha.0", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -49,11 +49,11 @@ "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.18.0", - "@onflow/fcl-wc": "6.0.2", + "@onflow/fcl-core": "1.19.0-alpha.0", + "@onflow/fcl-wc": "6.0.3-alpha.0", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.1", + "@onflow/sdk": "1.9.0-alpha.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", diff --git a/packages/kit/CHANGELOG.md b/packages/kit/CHANGELOG.md index 8663147de..eb4ad7e92 100644 --- a/packages/kit/CHANGELOG.md +++ b/packages/kit/CHANGELOG.md @@ -1,5 +1,24 @@ # @onflow/kit +## 0.2.0-alpha.0 + +### Minor Changes + +- [#2368](https://github.com/onflow/fcl-js/pull/2368) [`eca4617c2d4d10d85bad0324f6c6064489c3d1c3`](https://github.com/onflow/fcl-js/commit/eca4617c2d4d10d85bad0324f6c6064489c3d1c3) Thanks [@jribbink](https://github.com/jribbink)! - Add `useCrossVmBatchTransaction` function + +- [#2414](https://github.com/onflow/fcl-js/pull/2414) [`605f66c7a78f9ff1474a18b70298956b92f90bc1`](https://github.com/onflow/fcl-js/commit/605f66c7a78f9ff1474a18b70298956b92f90bc1) Thanks [@chasefleming](https://github.com/chasefleming)! - **BREAKING**: Rename `useFlowTransaction` as `useFlowTransactionStatus` + +- [#2367](https://github.com/onflow/fcl-js/pull/2367) [`9595af75eeffb0c91f9bb94b70fb0adf4db40eec`](https://github.com/onflow/fcl-js/commit/9595af75eeffb0c91f9bb94b70fb0adf4db40eec) Thanks [@jribbink](https://github.com/jribbink)! - Add `useFlowChainId` hook to the `@onflow/kit` package. + +### Patch Changes + +- [#2419](https://github.com/onflow/fcl-js/pull/2419) [`f498aa9fdb0739aef8905593bdbd05af9db3267a`](https://github.com/onflow/fcl-js/commit/f498aa9fdb0739aef8905593bdbd05af9db3267a) Thanks [@chasefleming](https://github.com/chasefleming)! - Update readme with `useFlowRevertibleRandom` hook + +- [#2417](https://github.com/onflow/fcl-js/pull/2417) [`8608416f4d26e40d3bfa464da7e988c8beb35336`](https://github.com/onflow/fcl-js/commit/8608416f4d26e40d3bfa464da7e988c8beb35336) Thanks [@jribbink](https://github.com/jribbink)! - Fix `useFlowRevertibleRandom` range + +- Updated dependencies [[`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab)]: + - @onflow/fcl@1.18.0-alpha.0 + ## 0.1.0 ### Minor Changes diff --git a/packages/kit/package.json b/packages/kit/package.json index 3d0f7c6ae..e1c0c8ce7 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/kit", - "version": "0.1.0", + "version": "0.2.0-alpha.0", "description": "React library for interacting with the Flow blockchain", "license": "Apache-2.0", "author": "Flow Foundation", @@ -30,7 +30,7 @@ "@babel/preset-react": "^7.26.3", "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.5.0", + "@onflow/typedefs": "^1.6.0-alpha.0", "@testing-library/dom": "^10.4.0", "@types/jest": "^29.5.13", "@types/react": "^19.0.10", @@ -49,7 +49,7 @@ "viem": "^2.28.1" }, "peerDependencies": { - "@onflow/fcl": ">=1.17.0", + "@onflow/fcl": ">=1.18.0-alpha.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index cbe9d0a4d..48b522c41 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -1,5 +1,32 @@ # @onflow/sdk +## 1.9.0-alpha.0 + +### Minor Changes + +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `rawSubscribe`. + + These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. + + The following topics are now available: + + - `blocks` + - `block_headers` + - `block_digests` + - `transaction_statues` + - `events` + - `account_statuses` + + Please see the [Flow Developer Documentation](https://developers.flow.com/clients/fcl-js/) for more details on how to use these new methods. + +- [#2352](https://github.com/onflow/fcl-js/pull/2352) [`4d3bb084c1442552d6a1de1f53435d1aa3f600b0`](https://github.com/onflow/fcl-js/commit/4d3bb084c1442552d6a1de1f53435d1aa3f600b0) Thanks [@mfbz](https://github.com/mfbz)! - Refactored onflow/sdk package to improve TypeScript support + +### Patch Changes + +- Updated dependencies [[`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`694cd76807b7ca4441d1f8425ac4f8426cbc18fa`](https://github.com/onflow/fcl-js/commit/694cd76807b7ca4441d1f8425ac4f8426cbc18fa), [`4d3bb084c1442552d6a1de1f53435d1aa3f600b0`](https://github.com/onflow/fcl-js/commit/4d3bb084c1442552d6a1de1f53435d1aa3f600b0)]: + - @onflow/typedefs@1.6.0-alpha.0 + - @onflow/transport-http@1.13.0-alpha.0 + ## 1.8.1 ### Patch Changes diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 7778f340d..ef544552b 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/sdk", - "version": "1.8.1", + "version": "1.9.0-alpha.0", "description": "Flow SDK", "license": "Apache-2.0", "author": "Flow Foundation", @@ -43,8 +43,8 @@ "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", "@onflow/rlp": "1.2.3", - "@onflow/transport-http": "1.12.0", - "@onflow/typedefs": "1.5.0", + "@onflow/transport-http": "1.13.0-alpha.0", + "@onflow/typedefs": "1.6.0-alpha.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", diff --git a/packages/transport-grpc/package.json b/packages/transport-grpc/package.json index ade4e838b..b88a87081 100644 --- a/packages/transport-grpc/package.json +++ b/packages/transport-grpc/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/sdk": "1.8.1", + "@onflow/sdk": "1.9.0-alpha.0", "jest": "^29.7.0" }, "source": "src/sdk-send-grpc.js", diff --git a/packages/transport-http/CHANGELOG.md b/packages/transport-http/CHANGELOG.md index 44abf1e55..bd7748e0e 100644 --- a/packages/transport-http/CHANGELOG.md +++ b/packages/transport-http/CHANGELOG.md @@ -1,5 +1,24 @@ # @onflow/transport-http +## 1.13.0-alpha.0 + +### Minor Changes + +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add support for new WebSocket streaming methods. The following topics are now available: + + - `blocks` + - `block_headers` + - `block_digests` + - `transaction_statues` + - `events` + - `account_statuses` + +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Expose the `httpTransport` as a named export from `@onflow/transport-http` package. This follows the new object-style export for SDK transports and adds streaming support. + +### Patch Changes + +- [#2035](https://github.com/onflow/fcl-js/pull/2035) [`694cd76807b7ca4441d1f8425ac4f8426cbc18fa`](https://github.com/onflow/fcl-js/commit/694cd76807b7ca4441d1f8425ac4f8426cbc18fa) Thanks [@jribbink](https://github.com/jribbink)! - Add `parentVoterSignature` field to GetBlock request + ## 1.12.0 ### Minor Changes diff --git a/packages/transport-http/package.json b/packages/transport-http/package.json index 24d7afd1d..32b0f0437 100644 --- a/packages/transport-http/package.json +++ b/packages/transport-http/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/transport-http", - "version": "1.12.0", + "version": "1.13.0-alpha.0", "description": "Flow SDK HTTP Transport Module", "license": "Apache-2.0", "author": "Flow Foundation", @@ -15,7 +15,7 @@ "devDependencies": { "@onflow/fcl-bundle": "1.7.0", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.1", + "@onflow/sdk": "1.9.0-alpha.0", "@onflow/types": "1.4.1", "jest": "^29.7.0", "jest-websocket-mock": "^2.5.0", diff --git a/packages/typedefs/CHANGELOG.md b/packages/typedefs/CHANGELOG.md index 1550bcadf..14575b329 100644 --- a/packages/typedefs/CHANGELOG.md +++ b/packages/typedefs/CHANGELOG.md @@ -1,5 +1,13 @@ # @onflow/typedefs +## 1.6.0-alpha.0 + +### Minor Changes + +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add typedefs for streaming API + +- [#2352](https://github.com/onflow/fcl-js/pull/2352) [`4d3bb084c1442552d6a1de1f53435d1aa3f600b0`](https://github.com/onflow/fcl-js/commit/4d3bb084c1442552d6a1de1f53435d1aa3f600b0) Thanks [@mfbz](https://github.com/mfbz)! - Refactored onflow/sdk package to improve TypeScript support + ## 1.5.0 ### Minor Changes diff --git a/packages/typedefs/package.json b/packages/typedefs/package.json index c9b8037f9..efe6f57f3 100644 --- a/packages/typedefs/package.json +++ b/packages/typedefs/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/typedefs", - "version": "1.5.0", + "version": "1.6.0-alpha.0", "description": "Flow JS Type Defs", "license": "Apache-2.0", "author": "Flow Foundation", From 90ad3db248f01e9c0ee34bacc3c529efcd9c60a3 Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Tue, 20 May 2025 14:57:15 -0700 Subject: [PATCH 44/72] Fix current user returning false before checking authenticated (#2428) Co-authored-by: Chase Fleming <1666730+chasefleming@users.noreply.github.com> --- packages/kit/src/hooks/useCurrentFlowUser.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/kit/src/hooks/useCurrentFlowUser.ts b/packages/kit/src/hooks/useCurrentFlowUser.ts index 82a128c88..765679c60 100644 --- a/packages/kit/src/hooks/useCurrentFlowUser.ts +++ b/packages/kit/src/hooks/useCurrentFlowUser.ts @@ -3,18 +3,13 @@ import * as fcl from "@onflow/fcl" import {CurrentUser} from "@onflow/typedefs" interface UseCurrentFlowUserResult { - user: CurrentUser + user: CurrentUser | null authenticate: () => Promise unauthenticate: () => void } export function useCurrentFlowUser(): UseCurrentFlowUserResult { - const [user, setUser] = useState({ - f_type: "USER", - f_vsn: "1.0.0", - loggedIn: false, - services: [], - }) + const [user, setUser] = useState(null) useEffect(() => { const unsubscribe = fcl.currentUser.subscribe(setUser) From a36d78ee5283ceb9a2f411e6da9ddf0373777c24 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Wed, 21 May 2025 00:52:36 +0000 Subject: [PATCH 45/72] Allow undefined value for `useFlowTransactionStatus` (#2439) --- .changeset/chatty-ghosts-bake.md | 5 +++++ packages/kit/src/hooks/useFlowTransactionStatus.test.ts | 9 +++++++++ packages/kit/src/hooks/useFlowTransactionStatus.ts | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 .changeset/chatty-ghosts-bake.md diff --git a/.changeset/chatty-ghosts-bake.md b/.changeset/chatty-ghosts-bake.md new file mode 100644 index 000000000..7d7d3a93e --- /dev/null +++ b/.changeset/chatty-ghosts-bake.md @@ -0,0 +1,5 @@ +--- +"@onflow/kit": minor +--- + +Make `txId` optional for `useFlowTransactionStatus` diff --git a/packages/kit/src/hooks/useFlowTransactionStatus.test.ts b/packages/kit/src/hooks/useFlowTransactionStatus.test.ts index df84454b8..232a0c3e7 100644 --- a/packages/kit/src/hooks/useFlowTransactionStatus.test.ts +++ b/packages/kit/src/hooks/useFlowTransactionStatus.test.ts @@ -70,4 +70,13 @@ describe("useFlowTransactionStatus", () => { expect(result.current.error).not.toBeNull() expect(result.current.error?.message).toBe("Test error occurred") }) + + test("returns null when no transaction ID is provided", () => { + const {result} = renderHook(() => useFlowTransactionStatus({}), { + wrapper: FlowProvider, + }) + + expect(result.current.transactionStatus).toBe(null) + expect(result.current.error).toBe(null) + }) }) diff --git a/packages/kit/src/hooks/useFlowTransactionStatus.ts b/packages/kit/src/hooks/useFlowTransactionStatus.ts index 376803843..9af8642f7 100644 --- a/packages/kit/src/hooks/useFlowTransactionStatus.ts +++ b/packages/kit/src/hooks/useFlowTransactionStatus.ts @@ -4,7 +4,7 @@ import {TransactionStatus} from "@onflow/typedefs" export interface UseFlowTransactionStatusArgs { /** The Flow transaction ID to monitor */ - id: string + id?: string } export interface UseFlowTransactionStatusResult { From 3ac616d64c9abcda32f0c450119f22fa479d5e89 Mon Sep 17 00:00:00 2001 From: Michael Fabozzi <39808567+mfbz@users.noreply.github.com> Date: Wed, 21 May 2025 17:58:40 +0200 Subject: [PATCH 46/72] Fixed fcl.mutate hanging (#2434) * Fixed fcl-mutate not working * Update packages/sdk/src/block/block.ts Co-authored-by: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> * Update packages/sdk/src/block/block.ts Co-authored-by: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> * Update packages/sdk/src/block/block.ts Co-authored-by: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> * Update packages/sdk/src/node-version-info/node-version-info.ts Co-authored-by: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> * Update packages/sdk/src/resolve/resolve.ts Co-authored-by: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> * Added validator improvement * Create four-frogs-jump.md --------- Co-authored-by: mfbz Co-authored-by: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> --- .changeset/four-frogs-jump.md | 5 +++++ packages/sdk/src/account/account.ts | 19 ++++++++----------- packages/sdk/src/block/block.ts | 14 ++++---------- .../sdk/src/build/build-get-collection.ts | 3 +-- packages/sdk/src/build/build-transaction.ts | 2 +- packages/sdk/src/interaction/interaction.ts | 6 +++++- .../node-version-info/node-version-info.ts | 3 +-- packages/sdk/src/resolve/resolve-cadence.ts | 2 +- .../resolve-proposer-sequence-number.ts | 2 +- .../src/resolve/resolve-voucher-intercept.ts | 2 +- packages/sdk/src/resolve/resolve.ts | 14 +++++--------- .../sdk/src/wallet-utils/encode-signable.ts | 6 ------ 12 files changed, 33 insertions(+), 45 deletions(-) create mode 100644 .changeset/four-frogs-jump.md diff --git a/.changeset/four-frogs-jump.md b/.changeset/four-frogs-jump.md new file mode 100644 index 000000000..014670392 --- /dev/null +++ b/.changeset/four-frogs-jump.md @@ -0,0 +1,5 @@ +--- +"@onflow/sdk": patch +--- + +Fixed fcl.mutate hanging diff --git a/packages/sdk/src/account/account.ts b/packages/sdk/src/account/account.ts index 5aa468747..c617c193a 100644 --- a/packages/sdk/src/account/account.ts +++ b/packages/sdk/src/account/account.ts @@ -34,21 +34,18 @@ export async function account( ) // Get account by ID - if (id) { - const ix = await send([getAccount(address), atBlockId(id)], opts) - return decode(ix) - } + if (id) + return await send([getAccount(address), atBlockId(id)], opts).then(decode) // Get account by height - if (height) { - const ix = await send([getAccount(address), atBlockHeight(height)], opts) - return decode(ix) - } + if (height) + return await send([getAccount(address), atBlockHeight(height)], opts).then( + decode + ) // Get account by latest block - const ix = await send( + return await send( [getAccount(address), atLatestBlock(isSealed ?? false)], opts - ) - return decode(ix) + ).then(decode) } diff --git a/packages/sdk/src/block/block.ts b/packages/sdk/src/block/block.ts index d0012d8f4..30ba2d248 100644 --- a/packages/sdk/src/block/block.ts +++ b/packages/sdk/src/block/block.ts @@ -36,18 +36,12 @@ export async function block( ) // Get block by ID - if (id) { - const ix = await send([getBlock(), atBlockId(id)], opts) - return decode(ix) - } + if (id) return await send([getBlock(), atBlockId(id)], opts).then(decode) // Get block by height - if (height) { - const ix = await send([getBlock(), atBlockHeight(height)], opts) - return decode(ix) - } + if (height) + return await send([getBlock(), atBlockHeight(height)], opts).then(decode) // Get latest block - const ix = await send([getBlock(sealed)], opts) - return decode(ix) + return await send([getBlock(sealed)], opts).then(decode) } diff --git a/packages/sdk/src/build/build-get-collection.ts b/packages/sdk/src/build/build-get-collection.ts index b5397f0e7..1f8d0703f 100644 --- a/packages/sdk/src/build/build-get-collection.ts +++ b/packages/sdk/src/build/build-get-collection.ts @@ -1,6 +1,5 @@ import { pipe, - Ok, makeGetCollection, InteractionBuilderFn, } from "../interaction/interaction" @@ -15,7 +14,7 @@ export function getCollection(id: string | null = null): InteractionBuilderFn { makeGetCollection, ix => { ix.collection.id = id - return Ok(ix) + return ix }, ]) } diff --git a/packages/sdk/src/build/build-transaction.ts b/packages/sdk/src/build/build-transaction.ts index b58aa462f..3af1793ed 100644 --- a/packages/sdk/src/build/build-transaction.ts +++ b/packages/sdk/src/build/build-transaction.ts @@ -8,7 +8,7 @@ import { import {template} from "@onflow/util-template" const DEFAULT_SCRIPT_ACCOUNTS: string[] = [] -const DEFAULT_REF = "" +const DEFAULT_REF: any = null /** * @description A template builder to use a Cadence transaction for an interaction diff --git a/packages/sdk/src/interaction/interaction.ts b/packages/sdk/src/interaction/interaction.ts index a4a022f88..45d49cd1d 100644 --- a/packages/sdk/src/interaction/interaction.ts +++ b/packages/sdk/src/interaction/interaction.ts @@ -370,7 +370,11 @@ export {pipe} const identity = (v: T, ..._: any[]) => v -export const get = (ix: Interaction, key: string, fallback: any) => { +export const get = ( + ix: Interaction, + key: string, + fallback: any = undefined +) => { return ix.assigns[key] == null ? fallback : ix.assigns[key] } diff --git a/packages/sdk/src/node-version-info/node-version-info.ts b/packages/sdk/src/node-version-info/node-version-info.ts index ddd9b4389..a2e2786a0 100644 --- a/packages/sdk/src/node-version-info/node-version-info.ts +++ b/packages/sdk/src/node-version-info/node-version-info.ts @@ -10,6 +10,5 @@ import {send} from "../transport" export async function nodeVersionInfo( opts: any = {} ): Promise { - const ix = await send([getNodeVersionInfo()], opts) - return decode(ix) + return await send([getNodeVersionInfo()], opts).then(decode) } diff --git a/packages/sdk/src/resolve/resolve-cadence.ts b/packages/sdk/src/resolve/resolve-cadence.ts index 78f6cf0e8..af9809385 100644 --- a/packages/sdk/src/resolve/resolve-cadence.ts +++ b/packages/sdk/src/resolve/resolve-cadence.ts @@ -27,7 +27,7 @@ function getContractIdentifierSyntaxMatches( export async function resolveCadence(ix: Interaction): Promise { if (!isTransaction(ix) && !isScript(ix)) return ix - var cadence = get(ix, "ix.cadence", null) + var cadence = get(ix, "ix.cadence") invariant( isFn(cadence) || isString(cadence), diff --git a/packages/sdk/src/resolve/resolve-proposer-sequence-number.ts b/packages/sdk/src/resolve/resolve-proposer-sequence-number.ts index 73abe0e8e..5dcea631c 100644 --- a/packages/sdk/src/resolve/resolve-proposer-sequence-number.ts +++ b/packages/sdk/src/resolve/resolve-proposer-sequence-number.ts @@ -26,7 +26,7 @@ export const resolveProposerSequenceNumber = ) invariant( - sendFn != null, + sendFn, `Required value for sdk.transport is not defined in config. See: ${"https://github.com/onflow/fcl-js/blob/master/packages/sdk/CHANGELOG.md#0057-alpha1----2022-01-21"}` ) diff --git a/packages/sdk/src/resolve/resolve-voucher-intercept.ts b/packages/sdk/src/resolve/resolve-voucher-intercept.ts index 60c8d7d53..ea779de00 100644 --- a/packages/sdk/src/resolve/resolve-voucher-intercept.ts +++ b/packages/sdk/src/resolve/resolve-voucher-intercept.ts @@ -5,7 +5,7 @@ import {createSignableVoucher} from "./voucher" export async function resolveVoucherIntercept( ix: Interaction ): Promise { - const fn = get(ix, "ix.voucher-intercept", null) + const fn = get(ix, "ix.voucher-intercept") if (isFn(fn)) { await fn(createSignableVoucher(ix)) } diff --git a/packages/sdk/src/resolve/resolve.ts b/packages/sdk/src/resolve/resolve.ts index acc326a1e..8466b7b32 100644 --- a/packages/sdk/src/resolve/resolve.ts +++ b/packages/sdk/src/resolve/resolve.ts @@ -87,7 +87,7 @@ async function execFetchRef(ix: Interaction): Promise { ) invariant( - sendFn !== undefined, + sendFn, `Required value for sdk.transport is not defined in config. See: ${"https://github.com/onflow/fcl-js/blob/master/packages/sdk/CHANGELOG.md#0057-alpha1----2022-01-21"}` ) @@ -114,22 +114,18 @@ async function execFetchSequenceNumber(ix: Interaction): Promise { ) invariant( - sendFn !== undefined, + sendFn, `Required value for sdk.transport is not defined in config. See: ${"https://github.com/onflow/fcl-js/blob/master/packages/sdk/CHANGELOG.md#0057-alpha1----2022-01-21"}` ) - const keyId = acct.keyId - const tempId = acct.tempId - const addr = acct.addr || "" - - ix.accounts[tempId].sequenceNum = await sendFn( - await build([getAccount(addr)]), + ix.accounts[acct.tempId].sequenceNum = await sendFn( + await build([getAccount(acct.addr!)]), {config, response, Buffer, ix: ixModule}, {node} ) .then(decode) .then((acctResponse: any) => acctResponse.keys) - .then((keys: any[]) => keys.find((key: any) => key.index === keyId)) + .then((keys: any) => keys.find((key: any) => key.index === acct!.keyId)) .then((key: any) => key.sequenceNumber) } } diff --git a/packages/sdk/src/wallet-utils/encode-signable.ts b/packages/sdk/src/wallet-utils/encode-signable.ts index 77253baa9..4814573a2 100644 --- a/packages/sdk/src/wallet-utils/encode-signable.ts +++ b/packages/sdk/src/wallet-utils/encode-signable.ts @@ -4,12 +4,6 @@ import { encodeTransactionEnvelope, } from "../encode/encode" -interface Sig { - address: string - keyId: number | string - sig: string -} - interface PayloadSig { address: string keyId: number | string From b70f746a40a7a726b22ef2fad04ded7e274a0098 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 10:41:32 -0700 Subject: [PATCH 47/72] Version Packages (alpha) (#2440) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/pre.json | 2 ++ packages/fcl-core/CHANGELOG.md | 7 +++++++ packages/fcl-core/package.json | 4 ++-- packages/fcl-ethereum-provider/CHANGELOG.md | 8 ++++++++ packages/fcl-ethereum-provider/package.json | 6 +++--- packages/fcl-rainbowkit-adapter/CHANGELOG.md | 9 +++++++++ packages/fcl-rainbowkit-adapter/package.json | 8 ++++---- packages/fcl-react-native/CHANGELOG.md | 8 ++++++++ packages/fcl-react-native/package.json | 6 +++--- packages/fcl-wagmi-adapter/CHANGELOG.md | 8 ++++++++ packages/fcl-wagmi-adapter/package.json | 6 +++--- packages/fcl-wc/CHANGELOG.md | 7 +++++++ packages/fcl-wc/package.json | 4 ++-- packages/fcl/CHANGELOG.md | 9 +++++++++ packages/fcl/package.json | 8 ++++---- packages/kit/CHANGELOG.md | 11 +++++++++++ packages/kit/package.json | 4 ++-- packages/sdk/CHANGELOG.md | 6 ++++++ packages/sdk/package.json | 2 +- packages/transport-grpc/package.json | 2 +- packages/transport-http/package.json | 2 +- 21 files changed, 101 insertions(+), 26 deletions(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index e3eeef8f4..330872813 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -31,8 +31,10 @@ }, "changesets": [ "breezy-gifts-sit", + "chatty-ghosts-bake", "fast-lobsters-train", "forty-trees-report", + "four-frogs-jump", "good-books-call", "mean-walls-hear", "moody-ligers-rule", diff --git a/packages/fcl-core/CHANGELOG.md b/packages/fcl-core/CHANGELOG.md index 9f6458925..5b8851031 100644 --- a/packages/fcl-core/CHANGELOG.md +++ b/packages/fcl-core/CHANGELOG.md @@ -1,5 +1,12 @@ # @onflow/fcl +## 1.19.0-alpha.1 + +### Patch Changes + +- Updated dependencies [[`3ac616d64c9abcda32f0c450119f22fa479d5e89`](https://github.com/onflow/fcl-js/commit/3ac616d64c9abcda32f0c450119f22fa479d5e89)]: + - @onflow/sdk@1.9.0-alpha.1 + ## 1.19.0-alpha.0 ### Minor Changes diff --git a/packages/fcl-core/package.json b/packages/fcl-core/package.json index 5a4e59f99..463a4352c 100644 --- a/packages/fcl-core/package.json +++ b/packages/fcl-core/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-core", - "version": "1.19.0-alpha.0", + "version": "1.19.0-alpha.1", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", @@ -52,7 +52,7 @@ "@onflow/config": "1.5.2", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.0", + "@onflow/sdk": "1.9.0-alpha.1", "@onflow/transport-http": "1.13.0-alpha.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", diff --git a/packages/fcl-ethereum-provider/CHANGELOG.md b/packages/fcl-ethereum-provider/CHANGELOG.md index 29714ffa3..88f5507f6 100644 --- a/packages/fcl-ethereum-provider/CHANGELOG.md +++ b/packages/fcl-ethereum-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @onflow/fcl-ethereum-provider +## 0.0.5-alpha.1 + +### Patch Changes + +- Updated dependencies []: + - @onflow/fcl@1.18.0-alpha.1 + - @onflow/fcl-wc@6.0.3-alpha.1 + ## 0.0.5-alpha.0 ### Patch Changes diff --git a/packages/fcl-ethereum-provider/package.json b/packages/fcl-ethereum-provider/package.json index 013976343..3ba912c0b 100644 --- a/packages/fcl-ethereum-provider/package.json +++ b/packages/fcl-ethereum-provider/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-ethereum-provider", - "version": "0.0.5-alpha.0", + "version": "0.0.5-alpha.1", "description": "Ethereum provider for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -40,7 +40,7 @@ "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", "@noble/hashes": "^1.7.1", - "@onflow/fcl-wc": "6.0.3-alpha.0", + "@onflow/fcl-wc": "6.0.3-alpha.1", "@onflow/rlp": "^1.2.3", "@walletconnect/ethereum-provider": "^2.20.2", "@walletconnect/jsonrpc-http-connection": "^1.0.8", @@ -50,6 +50,6 @@ "@walletconnect/utils": "^2.20.2" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.0" + "@onflow/fcl": "1.18.0-alpha.1" } } diff --git a/packages/fcl-rainbowkit-adapter/CHANGELOG.md b/packages/fcl-rainbowkit-adapter/CHANGELOG.md index bc80b6535..acb4d9edd 100644 --- a/packages/fcl-rainbowkit-adapter/CHANGELOG.md +++ b/packages/fcl-rainbowkit-adapter/CHANGELOG.md @@ -1,5 +1,14 @@ # @onflow/fcl-rainbowkit-adapter +## 0.2.1-alpha.1 + +### Patch Changes + +- Updated dependencies []: + - @onflow/fcl@1.18.0-alpha.1 + - @onflow/fcl-ethereum-provider@0.0.5-alpha.1 + - @onflow/fcl-wagmi-adapter@0.0.5-alpha.1 + ## 0.2.1-alpha.0 ### Patch Changes diff --git a/packages/fcl-rainbowkit-adapter/package.json b/packages/fcl-rainbowkit-adapter/package.json index bc35caac5..3a972f35f 100644 --- a/packages/fcl-rainbowkit-adapter/package.json +++ b/packages/fcl-rainbowkit-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-rainbowkit-adapter", - "version": "0.2.1-alpha.0", + "version": "0.2.1-alpha.1", "description": "Rainbowkit adapter for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -40,8 +40,8 @@ "@babel/runtime": "^7.25.7", "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", - "@onflow/fcl-ethereum-provider": "0.0.5-alpha.0", - "@onflow/fcl-wagmi-adapter": "0.0.5-alpha.0", + "@onflow/fcl-ethereum-provider": "0.0.5-alpha.1", + "@onflow/fcl-wagmi-adapter": "0.0.5-alpha.1", "@onflow/rlp": "^1.2.3", "@wagmi/core": "^2.16.3", "mipd": "^0.0.7", @@ -50,7 +50,7 @@ "wagmi": "^2.14.11" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.0", + "@onflow/fcl": "1.18.0-alpha.1", "@rainbow-me/rainbowkit": "^2.2.3", "react": "17.x || 18.x || 19.x" } diff --git a/packages/fcl-react-native/CHANGELOG.md b/packages/fcl-react-native/CHANGELOG.md index 5f8234ac2..86da9fcaa 100644 --- a/packages/fcl-react-native/CHANGELOG.md +++ b/packages/fcl-react-native/CHANGELOG.md @@ -1,5 +1,13 @@ # @onflow/fcl-react-native +## 1.12.0-alpha.1 + +### Patch Changes + +- Updated dependencies [[`3ac616d64c9abcda32f0c450119f22fa479d5e89`](https://github.com/onflow/fcl-js/commit/3ac616d64c9abcda32f0c450119f22fa479d5e89)]: + - @onflow/sdk@1.9.0-alpha.1 + - @onflow/fcl-core@1.19.0-alpha.1 + ## 1.12.0-alpha.0 ### Minor Changes diff --git a/packages/fcl-react-native/package.json b/packages/fcl-react-native/package.json index 08e64e050..6d7bb74bd 100644 --- a/packages/fcl-react-native/package.json +++ b/packages/fcl-react-native/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-react-native", - "version": "1.12.0-alpha.0", + "version": "1.12.0-alpha.1", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", @@ -48,10 +48,10 @@ "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.19.0-alpha.0", + "@onflow/fcl-core": "1.19.0-alpha.1", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.0", + "@onflow/sdk": "1.9.0-alpha.1", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", diff --git a/packages/fcl-wagmi-adapter/CHANGELOG.md b/packages/fcl-wagmi-adapter/CHANGELOG.md index 8e33ff5bc..a78f1ad7d 100644 --- a/packages/fcl-wagmi-adapter/CHANGELOG.md +++ b/packages/fcl-wagmi-adapter/CHANGELOG.md @@ -1,5 +1,13 @@ # @onflow/fcl-wagmi-adapter +## 0.0.5-alpha.1 + +### Patch Changes + +- Updated dependencies []: + - @onflow/fcl@1.18.0-alpha.1 + - @onflow/fcl-ethereum-provider@0.0.5-alpha.1 + ## 0.0.5-alpha.0 ### Patch Changes diff --git a/packages/fcl-wagmi-adapter/package.json b/packages/fcl-wagmi-adapter/package.json index f81c60e09..0315c5b79 100644 --- a/packages/fcl-wagmi-adapter/package.json +++ b/packages/fcl-wagmi-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-wagmi-adapter", - "version": "0.0.5-alpha.0", + "version": "0.0.5-alpha.1", "description": "Wagmi adapter for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -39,12 +39,12 @@ "@babel/runtime": "^7.25.7", "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", - "@onflow/fcl-ethereum-provider": "0.0.5-alpha.0", + "@onflow/fcl-ethereum-provider": "0.0.5-alpha.1", "@onflow/rlp": "^1.2.3", "viem": "^2.22.21" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.0", + "@onflow/fcl": "1.18.0-alpha.1", "@wagmi/core": "^2.16.3" } } diff --git a/packages/fcl-wc/CHANGELOG.md b/packages/fcl-wc/CHANGELOG.md index 65527af6b..25cb3b010 100644 --- a/packages/fcl-wc/CHANGELOG.md +++ b/packages/fcl-wc/CHANGELOG.md @@ -1,5 +1,12 @@ # @onflow/fcl-wc +## 6.0.3-alpha.1 + +### Patch Changes + +- Updated dependencies []: + - @onflow/fcl-core@1.19.0-alpha.1 + ## 6.0.3-alpha.0 ### Patch Changes diff --git a/packages/fcl-wc/package.json b/packages/fcl-wc/package.json index 25eaf5f14..a20fbe55f 100644 --- a/packages/fcl-wc/package.json +++ b/packages/fcl-wc/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-wc", - "version": "6.0.3-alpha.0", + "version": "6.0.3-alpha.1", "description": "WalletConnect adapter for FCL", "license": "Apache-2.0", "author": "Flow Foundation", @@ -52,6 +52,6 @@ "tailwindcss": "^3.4.14" }, "peerDependencies": { - "@onflow/fcl-core": "1.19.0-alpha.0" + "@onflow/fcl-core": "1.19.0-alpha.1" } } diff --git a/packages/fcl/CHANGELOG.md b/packages/fcl/CHANGELOG.md index 420e22d7c..436ae1cfc 100644 --- a/packages/fcl/CHANGELOG.md +++ b/packages/fcl/CHANGELOG.md @@ -1,5 +1,14 @@ # @onflow/fcl +## 1.18.0-alpha.1 + +### Patch Changes + +- Updated dependencies [[`3ac616d64c9abcda32f0c450119f22fa479d5e89`](https://github.com/onflow/fcl-js/commit/3ac616d64c9abcda32f0c450119f22fa479d5e89)]: + - @onflow/sdk@1.9.0-alpha.1 + - @onflow/fcl-core@1.19.0-alpha.1 + - @onflow/fcl-wc@6.0.3-alpha.1 + ## 1.18.0-alpha.0 ### Minor Changes diff --git a/packages/fcl/package.json b/packages/fcl/package.json index 52b46f3a8..3cdb03dde 100644 --- a/packages/fcl/package.json +++ b/packages/fcl/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl", - "version": "1.18.0-alpha.0", + "version": "1.18.0-alpha.1", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", @@ -49,11 +49,11 @@ "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.19.0-alpha.0", - "@onflow/fcl-wc": "6.0.3-alpha.0", + "@onflow/fcl-core": "1.19.0-alpha.1", + "@onflow/fcl-wc": "6.0.3-alpha.1", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.0", + "@onflow/sdk": "1.9.0-alpha.1", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", diff --git a/packages/kit/CHANGELOG.md b/packages/kit/CHANGELOG.md index eb4ad7e92..880a3e8f8 100644 --- a/packages/kit/CHANGELOG.md +++ b/packages/kit/CHANGELOG.md @@ -1,5 +1,16 @@ # @onflow/kit +## 0.2.0-alpha.1 + +### Minor Changes + +- [#2439](https://github.com/onflow/fcl-js/pull/2439) [`a36d78ee5283ceb9a2f411e6da9ddf0373777c24`](https://github.com/onflow/fcl-js/commit/a36d78ee5283ceb9a2f411e6da9ddf0373777c24) Thanks [@jribbink](https://github.com/jribbink)! - Make `txId` optional for `useFlowTransactionStatus` + +### Patch Changes + +- Updated dependencies []: + - @onflow/fcl@1.18.0-alpha.1 + ## 0.2.0-alpha.0 ### Minor Changes diff --git a/packages/kit/package.json b/packages/kit/package.json index e1c0c8ce7..79b129e56 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/kit", - "version": "0.2.0-alpha.0", + "version": "0.2.0-alpha.1", "description": "React library for interacting with the Flow blockchain", "license": "Apache-2.0", "author": "Flow Foundation", @@ -49,7 +49,7 @@ "viem": "^2.28.1" }, "peerDependencies": { - "@onflow/fcl": ">=1.18.0-alpha.0", + "@onflow/fcl": ">=1.18.0-alpha.1", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index 48b522c41..d35035fc5 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -1,5 +1,11 @@ # @onflow/sdk +## 1.9.0-alpha.1 + +### Patch Changes + +- [#2434](https://github.com/onflow/fcl-js/pull/2434) [`3ac616d64c9abcda32f0c450119f22fa479d5e89`](https://github.com/onflow/fcl-js/commit/3ac616d64c9abcda32f0c450119f22fa479d5e89) Thanks [@mfbz](https://github.com/mfbz)! - Fixed fcl.mutate hanging + ## 1.9.0-alpha.0 ### Minor Changes diff --git a/packages/sdk/package.json b/packages/sdk/package.json index ef544552b..6e2df7266 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/sdk", - "version": "1.9.0-alpha.0", + "version": "1.9.0-alpha.1", "description": "Flow SDK", "license": "Apache-2.0", "author": "Flow Foundation", diff --git a/packages/transport-grpc/package.json b/packages/transport-grpc/package.json index b88a87081..ab482fd95 100644 --- a/packages/transport-grpc/package.json +++ b/packages/transport-grpc/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/sdk": "1.9.0-alpha.0", + "@onflow/sdk": "1.9.0-alpha.1", "jest": "^29.7.0" }, "source": "src/sdk-send-grpc.js", diff --git a/packages/transport-http/package.json b/packages/transport-http/package.json index 32b0f0437..55a6b1c9b 100644 --- a/packages/transport-http/package.json +++ b/packages/transport-http/package.json @@ -15,7 +15,7 @@ "devDependencies": { "@onflow/fcl-bundle": "1.7.0", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.0", + "@onflow/sdk": "1.9.0-alpha.1", "@onflow/types": "1.4.1", "jest": "^29.7.0", "jest-websocket-mock": "^2.5.0", From 2637889fdb47a2294ad2db9d06a16fac1d805a12 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Thu, 22 May 2025 15:07:51 +0000 Subject: [PATCH 48/72] Unsubscribe from transaction statuses once sealed (#2461) --- .changeset/slimy-drinks-bake.md | 5 ++ .../src/transaction/transaction.test.ts | 40 ++++++++++++++ .../fcl-core/src/transaction/transaction.ts | 53 ++++++++++++------- 3 files changed, 79 insertions(+), 19 deletions(-) create mode 100644 .changeset/slimy-drinks-bake.md diff --git a/.changeset/slimy-drinks-bake.md b/.changeset/slimy-drinks-bake.md new file mode 100644 index 000000000..5d77d08f1 --- /dev/null +++ b/.changeset/slimy-drinks-bake.md @@ -0,0 +1,5 @@ +--- +"@onflow/fcl-core": patch +--- + +Unsubscribe from transaction statuses when sealed diff --git a/packages/fcl-core/src/transaction/transaction.test.ts b/packages/fcl-core/src/transaction/transaction.test.ts index 83bf251b1..9f0723950 100644 --- a/packages/fcl-core/src/transaction/transaction.test.ts +++ b/packages/fcl-core/src/transaction/transaction.test.ts @@ -120,6 +120,46 @@ describe("transaction", () => { expect(() => transaction(txId)).toThrow("Invalid transactionId") }) + test("should unsubscribe once the transaction has sealed", async () => { + jest.resetModules() + const txId = + "4234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" + const callback = jest.fn() + transaction(txId).subscribe(callback) + + // Flush the event loop + await new Promise(resolve => setTimeout(resolve, 0)) + + // Mock the observable to emit a SEALED status + const subscribeParams = jest.mocked(subscribe).mock + .calls[0][0] as Parameters< + typeof subscribe + >[0] + + subscribeParams.onData({ + status: TransactionExecutionStatus.PENDING, + blockId: "", + statusCode: 0, + errorMessage: "", + events: [], + statusString: "PENDING", + }) + + subscribeParams.onData({ + status: TransactionExecutionStatus.SEALED, + blockId: "", + statusCode: 0, + errorMessage: "", + events: [], + statusString: "SEALED", + }) + + await new Promise(resolve => setTimeout(resolve, 100)) + + const unsubMock = jest.mocked(subscribe).mock.results[0].value + expect(unsubMock.unsubscribe).toHaveBeenCalledTimes(1) + }) + test("subscribe should fallback to polling if real-time streaming is not supported", async () => { const txId = "2234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" diff --git a/packages/fcl-core/src/transaction/transaction.ts b/packages/fcl-core/src/transaction/transaction.ts index 791013040..8ff6acce8 100644 --- a/packages/fcl-core/src/transaction/transaction.ts +++ b/packages/fcl-core/src/transaction/transaction.ts @@ -84,29 +84,26 @@ export function transaction( return function innerOnce(opts = {suppress: false}) { const suppress = opts.suppress || false return new Promise((resolve, reject) => { - const unsub = subscribe((( - txStatus?: TransactionStatus, - error?: Error - ) => { - if ((error || txStatus?.statusCode) && !suppress) { - if (error != null) { - reject(error) - unsub() - } else if (txStatus?.statusCode === 1) { + const unsub = subscribe( + (txStatus: TransactionStatus) => { + if (txStatus.statusCode === 1) { const transactionError = TransactionError.fromErrorMessage( txStatus.errorMessage ) reject(transactionError) unsub() + } else if (predicate(txStatus)) { + resolve(txStatus) + unsub() + } + }, + err => { + if (!suppress) { + reject(err) + unsub() } - return - } - - if (predicate(txStatus!)) { - resolve(txStatus!) - unsub() } - }) as any) + ) }) as Promise } } @@ -168,7 +165,7 @@ function createObservable( // Subscribe to transaction status updates function subscribeTransactionStatuses() { // Subscribe to transaction status updates - sdkSubscribe({ + const subscription = sdkSubscribe({ topic: SubscriptionTopic.TRANSACTION_STATUSES, args: {transactionId: txId}, onData: txStatus => { @@ -176,6 +173,16 @@ function createObservable( value = txStatus next(txStatus) } + + // Clean up the subscription if the transaction is sealed + // Wait for next tick to ensure unsubscribe is defined + if (isSealed(txStatus)) { + new Promise(resolve => setTimeout(resolve, 0)).then(() => { + if (isSealed(txStatus)) { + subscription.unsubscribe() + } + }) + } }, onError: (err: Error) => { if (err instanceof SubscriptionsNotSupportedError) { @@ -192,13 +199,21 @@ function createObservable( function fallbackLegacyPolling() { // Poll for transaction status updates - legacyTransaction(txId, opts).subscribe( + const unsubscribe = legacyTransaction(txId, opts).subscribe( (txStatus?: TransactionStatus, err?: Error) => { if (err) { error(err) - } else if (txStatus) { + } else if (txStatus && isDiff(value, txStatus)) { value = txStatus next(txStatus) + + // Clean up the subscription if the transaction is sealed + // Wait for next tick to ensure unsubscribe is defined + if (isSealed(txStatus)) { + new Promise(resolve => setTimeout(resolve, 0)).then(() => { + unsubscribe() + }) + } } } ) From 77bd6416570d67d0e99afac81fa6372f5272025a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 08:13:47 -0700 Subject: [PATCH 49/72] Version Packages (alpha) (#2465) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/pre.json | 1 + packages/fcl-core/CHANGELOG.md | 6 ++++++ packages/fcl-core/package.json | 2 +- packages/fcl-ethereum-provider/CHANGELOG.md | 8 ++++++++ packages/fcl-ethereum-provider/package.json | 6 +++--- packages/fcl-rainbowkit-adapter/CHANGELOG.md | 9 +++++++++ packages/fcl-rainbowkit-adapter/package.json | 8 ++++---- packages/fcl-react-native/CHANGELOG.md | 7 +++++++ packages/fcl-react-native/package.json | 4 ++-- packages/fcl-wagmi-adapter/CHANGELOG.md | 8 ++++++++ packages/fcl-wagmi-adapter/package.json | 6 +++--- packages/fcl-wc/CHANGELOG.md | 7 +++++++ packages/fcl-wc/package.json | 4 ++-- packages/fcl/CHANGELOG.md | 8 ++++++++ packages/fcl/package.json | 6 +++--- 15 files changed, 72 insertions(+), 18 deletions(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index 330872813..2dfde6c0b 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -42,6 +42,7 @@ "sharp-suns-refuse", "shy-cars-beam", "sixty-pandas-retire", + "slimy-drinks-bake", "spicy-fishes-drum", "tame-pianos-doubt" ] diff --git a/packages/fcl-core/CHANGELOG.md b/packages/fcl-core/CHANGELOG.md index 5b8851031..a3c8261bf 100644 --- a/packages/fcl-core/CHANGELOG.md +++ b/packages/fcl-core/CHANGELOG.md @@ -1,5 +1,11 @@ # @onflow/fcl +## 1.19.0-alpha.2 + +### Patch Changes + +- [#2461](https://github.com/onflow/fcl-js/pull/2461) [`2637889fdb47a2294ad2db9d06a16fac1d805a12`](https://github.com/onflow/fcl-js/commit/2637889fdb47a2294ad2db9d06a16fac1d805a12) Thanks [@jribbink](https://github.com/jribbink)! - Unsubscribe from transaction statuses when sealed + ## 1.19.0-alpha.1 ### Patch Changes diff --git a/packages/fcl-core/package.json b/packages/fcl-core/package.json index 463a4352c..9414f1311 100644 --- a/packages/fcl-core/package.json +++ b/packages/fcl-core/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-core", - "version": "1.19.0-alpha.1", + "version": "1.19.0-alpha.2", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", diff --git a/packages/fcl-ethereum-provider/CHANGELOG.md b/packages/fcl-ethereum-provider/CHANGELOG.md index 88f5507f6..b4c7e6142 100644 --- a/packages/fcl-ethereum-provider/CHANGELOG.md +++ b/packages/fcl-ethereum-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @onflow/fcl-ethereum-provider +## 0.0.5-alpha.2 + +### Patch Changes + +- Updated dependencies []: + - @onflow/fcl@1.18.0-alpha.2 + - @onflow/fcl-wc@6.0.3-alpha.2 + ## 0.0.5-alpha.1 ### Patch Changes diff --git a/packages/fcl-ethereum-provider/package.json b/packages/fcl-ethereum-provider/package.json index 3ba912c0b..9f5e933c1 100644 --- a/packages/fcl-ethereum-provider/package.json +++ b/packages/fcl-ethereum-provider/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-ethereum-provider", - "version": "0.0.5-alpha.1", + "version": "0.0.5-alpha.2", "description": "Ethereum provider for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -40,7 +40,7 @@ "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", "@noble/hashes": "^1.7.1", - "@onflow/fcl-wc": "6.0.3-alpha.1", + "@onflow/fcl-wc": "6.0.3-alpha.2", "@onflow/rlp": "^1.2.3", "@walletconnect/ethereum-provider": "^2.20.2", "@walletconnect/jsonrpc-http-connection": "^1.0.8", @@ -50,6 +50,6 @@ "@walletconnect/utils": "^2.20.2" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.1" + "@onflow/fcl": "1.18.0-alpha.2" } } diff --git a/packages/fcl-rainbowkit-adapter/CHANGELOG.md b/packages/fcl-rainbowkit-adapter/CHANGELOG.md index acb4d9edd..05c641bc6 100644 --- a/packages/fcl-rainbowkit-adapter/CHANGELOG.md +++ b/packages/fcl-rainbowkit-adapter/CHANGELOG.md @@ -1,5 +1,14 @@ # @onflow/fcl-rainbowkit-adapter +## 0.2.1-alpha.2 + +### Patch Changes + +- Updated dependencies []: + - @onflow/fcl@1.18.0-alpha.2 + - @onflow/fcl-ethereum-provider@0.0.5-alpha.2 + - @onflow/fcl-wagmi-adapter@0.0.5-alpha.2 + ## 0.2.1-alpha.1 ### Patch Changes diff --git a/packages/fcl-rainbowkit-adapter/package.json b/packages/fcl-rainbowkit-adapter/package.json index 3a972f35f..aa234a50a 100644 --- a/packages/fcl-rainbowkit-adapter/package.json +++ b/packages/fcl-rainbowkit-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-rainbowkit-adapter", - "version": "0.2.1-alpha.1", + "version": "0.2.1-alpha.2", "description": "Rainbowkit adapter for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -40,8 +40,8 @@ "@babel/runtime": "^7.25.7", "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", - "@onflow/fcl-ethereum-provider": "0.0.5-alpha.1", - "@onflow/fcl-wagmi-adapter": "0.0.5-alpha.1", + "@onflow/fcl-ethereum-provider": "0.0.5-alpha.2", + "@onflow/fcl-wagmi-adapter": "0.0.5-alpha.2", "@onflow/rlp": "^1.2.3", "@wagmi/core": "^2.16.3", "mipd": "^0.0.7", @@ -50,7 +50,7 @@ "wagmi": "^2.14.11" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.1", + "@onflow/fcl": "1.18.0-alpha.2", "@rainbow-me/rainbowkit": "^2.2.3", "react": "17.x || 18.x || 19.x" } diff --git a/packages/fcl-react-native/CHANGELOG.md b/packages/fcl-react-native/CHANGELOG.md index 86da9fcaa..97ebade61 100644 --- a/packages/fcl-react-native/CHANGELOG.md +++ b/packages/fcl-react-native/CHANGELOG.md @@ -1,5 +1,12 @@ # @onflow/fcl-react-native +## 1.12.0-alpha.2 + +### Patch Changes + +- Updated dependencies [[`2637889fdb47a2294ad2db9d06a16fac1d805a12`](https://github.com/onflow/fcl-js/commit/2637889fdb47a2294ad2db9d06a16fac1d805a12)]: + - @onflow/fcl-core@1.19.0-alpha.2 + ## 1.12.0-alpha.1 ### Patch Changes diff --git a/packages/fcl-react-native/package.json b/packages/fcl-react-native/package.json index 6d7bb74bd..329a50e51 100644 --- a/packages/fcl-react-native/package.json +++ b/packages/fcl-react-native/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-react-native", - "version": "1.12.0-alpha.1", + "version": "1.12.0-alpha.2", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", @@ -48,7 +48,7 @@ "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.19.0-alpha.1", + "@onflow/fcl-core": "1.19.0-alpha.2", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", "@onflow/sdk": "1.9.0-alpha.1", diff --git a/packages/fcl-wagmi-adapter/CHANGELOG.md b/packages/fcl-wagmi-adapter/CHANGELOG.md index a78f1ad7d..30534bf4e 100644 --- a/packages/fcl-wagmi-adapter/CHANGELOG.md +++ b/packages/fcl-wagmi-adapter/CHANGELOG.md @@ -1,5 +1,13 @@ # @onflow/fcl-wagmi-adapter +## 0.0.5-alpha.2 + +### Patch Changes + +- Updated dependencies []: + - @onflow/fcl@1.18.0-alpha.2 + - @onflow/fcl-ethereum-provider@0.0.5-alpha.2 + ## 0.0.5-alpha.1 ### Patch Changes diff --git a/packages/fcl-wagmi-adapter/package.json b/packages/fcl-wagmi-adapter/package.json index 0315c5b79..9bc630dbe 100644 --- a/packages/fcl-wagmi-adapter/package.json +++ b/packages/fcl-wagmi-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-wagmi-adapter", - "version": "0.0.5-alpha.1", + "version": "0.0.5-alpha.2", "description": "Wagmi adapter for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -39,12 +39,12 @@ "@babel/runtime": "^7.25.7", "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", - "@onflow/fcl-ethereum-provider": "0.0.5-alpha.1", + "@onflow/fcl-ethereum-provider": "0.0.5-alpha.2", "@onflow/rlp": "^1.2.3", "viem": "^2.22.21" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.1", + "@onflow/fcl": "1.18.0-alpha.2", "@wagmi/core": "^2.16.3" } } diff --git a/packages/fcl-wc/CHANGELOG.md b/packages/fcl-wc/CHANGELOG.md index 25cb3b010..95c2a77d3 100644 --- a/packages/fcl-wc/CHANGELOG.md +++ b/packages/fcl-wc/CHANGELOG.md @@ -1,5 +1,12 @@ # @onflow/fcl-wc +## 6.0.3-alpha.2 + +### Patch Changes + +- Updated dependencies [[`2637889fdb47a2294ad2db9d06a16fac1d805a12`](https://github.com/onflow/fcl-js/commit/2637889fdb47a2294ad2db9d06a16fac1d805a12)]: + - @onflow/fcl-core@1.19.0-alpha.2 + ## 6.0.3-alpha.1 ### Patch Changes diff --git a/packages/fcl-wc/package.json b/packages/fcl-wc/package.json index a20fbe55f..13a81e0ae 100644 --- a/packages/fcl-wc/package.json +++ b/packages/fcl-wc/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-wc", - "version": "6.0.3-alpha.1", + "version": "6.0.3-alpha.2", "description": "WalletConnect adapter for FCL", "license": "Apache-2.0", "author": "Flow Foundation", @@ -52,6 +52,6 @@ "tailwindcss": "^3.4.14" }, "peerDependencies": { - "@onflow/fcl-core": "1.19.0-alpha.1" + "@onflow/fcl-core": "1.19.0-alpha.2" } } diff --git a/packages/fcl/CHANGELOG.md b/packages/fcl/CHANGELOG.md index 436ae1cfc..59e622800 100644 --- a/packages/fcl/CHANGELOG.md +++ b/packages/fcl/CHANGELOG.md @@ -1,5 +1,13 @@ # @onflow/fcl +## 1.18.0-alpha.2 + +### Patch Changes + +- Updated dependencies [[`2637889fdb47a2294ad2db9d06a16fac1d805a12`](https://github.com/onflow/fcl-js/commit/2637889fdb47a2294ad2db9d06a16fac1d805a12)]: + - @onflow/fcl-core@1.19.0-alpha.2 + - @onflow/fcl-wc@6.0.3-alpha.2 + ## 1.18.0-alpha.1 ### Patch Changes diff --git a/packages/fcl/package.json b/packages/fcl/package.json index 3cdb03dde..64a8b7e1f 100644 --- a/packages/fcl/package.json +++ b/packages/fcl/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl", - "version": "1.18.0-alpha.1", + "version": "1.18.0-alpha.2", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", @@ -49,8 +49,8 @@ "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.19.0-alpha.1", - "@onflow/fcl-wc": "6.0.3-alpha.1", + "@onflow/fcl-core": "1.19.0-alpha.2", + "@onflow/fcl-wc": "6.0.3-alpha.2", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", "@onflow/sdk": "1.9.0-alpha.1", From e308f01a22f53a229c0ba85ed0895fd605936fae Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Thu, 22 May 2025 15:19:20 +0000 Subject: [PATCH 50/72] Exit alpha (#2466) --- .changeset/pre.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index 2dfde6c0b..4dc33f16d 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -1,5 +1,5 @@ { - "mode": "pre", + "mode": "exit", "tag": "alpha", "initialVersions": { "@onflow/config": "1.5.2", From 0b83658f62a428a70074d33875f264fbd48aff1e Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Thu, 22 May 2025 17:50:28 +0000 Subject: [PATCH 51/72] Rename `rawSubscribe` to `subscribeRaw` (#2463) --- .changeset/hip-beans-speak.md | 9 ++++ package-lock.json | 52 +++++++++---------- packages/fcl-core/src/fcl-core.ts | 2 +- .../fcl-react-native/src/fcl-react-native.ts | 2 +- packages/fcl/src/fcl.ts | 2 +- packages/sdk/src/sdk.ts | 2 +- packages/sdk/src/transport/index.ts | 2 +- ...ubscribe.test.ts => subscribe-raw.test.ts} | 8 +-- .../{raw-subscribe.ts => subscribe-raw.ts} | 6 +-- .../src/transport/subscribe/subscribe.test.ts | 20 +++---- .../sdk/src/transport/subscribe/subscribe.ts | 4 +- packages/sdk/src/transport/subscribe/types.ts | 2 +- 12 files changed, 60 insertions(+), 51 deletions(-) create mode 100644 .changeset/hip-beans-speak.md rename packages/sdk/src/transport/subscribe/{raw-subscribe.test.ts => subscribe-raw.test.ts} (91%) rename packages/sdk/src/transport/subscribe/{raw-subscribe.ts => subscribe-raw.ts} (89%) diff --git a/.changeset/hip-beans-speak.md b/.changeset/hip-beans-speak.md new file mode 100644 index 000000000..53b9c93ac --- /dev/null +++ b/.changeset/hip-beans-speak.md @@ -0,0 +1,9 @@ +--- +"@onflow/fcl-react-native": minor +"@onflow/transport-http": minor +"@onflow/fcl-core": minor +"@onflow/fcl": minor +"@onflow/sdk": minor +--- + +Rename `rawSubscribe` to `subscribeRaw` diff --git a/package-lock.json b/package-lock.json index 33320af10..533425ac8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30881,16 +30881,16 @@ }, "packages/fcl": { "name": "@onflow/fcl", - "version": "1.18.0-alpha.0", + "version": "1.18.0-alpha.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.19.0-alpha.0", - "@onflow/fcl-wc": "6.0.3-alpha.0", + "@onflow/fcl-core": "1.19.0-alpha.1", + "@onflow/fcl-wc": "6.0.3-alpha.1", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.0", + "@onflow/sdk": "1.9.0-alpha.1", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", @@ -30956,7 +30956,7 @@ }, "packages/fcl-core": { "name": "@onflow/fcl-core", - "version": "1.19.0-alpha.0", + "version": "1.19.0-alpha.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -30964,7 +30964,7 @@ "@onflow/config": "1.5.2", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.0", + "@onflow/sdk": "1.9.0-alpha.1", "@onflow/transport-http": "1.13.0-alpha.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", @@ -31011,14 +31011,14 @@ }, "packages/fcl-ethereum-provider": { "name": "@onflow/fcl-ethereum-provider", - "version": "0.0.5-alpha.0", + "version": "0.0.5-alpha.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.3-alpha.0", + "@onflow/fcl-wc": "6.0.3-alpha.1", "@onflow/rlp": "^1.2.3", "@walletconnect/ethereum-provider": "^2.20.2", "@walletconnect/jsonrpc-http-connection": "^1.0.8", @@ -31039,7 +31039,7 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.0" + "@onflow/fcl": "1.18.0-alpha.1" } }, "packages/fcl-ethereum-provider/node_modules/@react-native-async-storage/async-storage": { @@ -31184,14 +31184,14 @@ }, "packages/fcl-rainbowkit-adapter": { "name": "@onflow/fcl-rainbowkit-adapter", - "version": "0.2.1-alpha.0", + "version": "0.2.1-alpha.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.5-alpha.0", - "@onflow/fcl-wagmi-adapter": "0.0.5-alpha.0", + "@onflow/fcl-ethereum-provider": "0.0.5-alpha.1", + "@onflow/fcl-wagmi-adapter": "0.0.5-alpha.1", "@onflow/rlp": "^1.2.3", "@wagmi/core": "^2.16.3", "mipd": "^0.0.7", @@ -31212,7 +31212,7 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.0", + "@onflow/fcl": "1.18.0-alpha.1", "@rainbow-me/rainbowkit": "^2.2.3", "react": "17.x || 18.x || 19.x" } @@ -31229,15 +31229,15 @@ }, "packages/fcl-react-native": { "name": "@onflow/fcl-react-native", - "version": "1.12.0-alpha.0", + "version": "1.12.0-alpha.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.19.0-alpha.0", + "@onflow/fcl-core": "1.19.0-alpha.1", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.0", + "@onflow/sdk": "1.9.0-alpha.1", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", @@ -31288,13 +31288,13 @@ }, "packages/fcl-wagmi-adapter": { "name": "@onflow/fcl-wagmi-adapter", - "version": "0.0.5-alpha.0", + "version": "0.0.5-alpha.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.5-alpha.0", + "@onflow/fcl-ethereum-provider": "0.0.5-alpha.1", "@onflow/rlp": "^1.2.3", "viem": "^2.22.21" }, @@ -31310,13 +31310,13 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.0", + "@onflow/fcl": "1.18.0-alpha.1", "@wagmi/core": "^2.16.3" } }, "packages/fcl-wc": { "name": "@onflow/fcl-wc", - "version": "6.0.3-alpha.0", + "version": "6.0.3-alpha.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -31343,7 +31343,7 @@ "jest-preset-preact": "^4.1.1" }, "peerDependencies": { - "@onflow/fcl-core": "1.19.0-alpha.0" + "@onflow/fcl-core": "1.19.0-alpha.1" } }, "packages/fcl-wc/node_modules/@react-native-async-storage/async-storage": { @@ -31490,7 +31490,7 @@ }, "packages/kit": { "name": "@onflow/kit", - "version": "0.2.0-alpha.0", + "version": "0.2.0-alpha.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -31516,7 +31516,7 @@ "jest-environment-jsdom": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": ">=1.18.0-alpha.0", + "@onflow/fcl": ">=1.18.0-alpha.1", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } @@ -31702,7 +31702,7 @@ }, "packages/sdk": { "name": "@onflow/sdk", - "version": "1.9.0-alpha.0", + "version": "1.9.0-alpha.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -31758,7 +31758,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/sdk": "1.9.0-alpha.0", + "@onflow/sdk": "1.9.0-alpha.1", "jest": "^29.7.0" } }, @@ -31782,7 +31782,7 @@ "devDependencies": { "@onflow/fcl-bundle": "1.7.0", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.0", + "@onflow/sdk": "1.9.0-alpha.1", "@onflow/types": "1.4.1", "jest": "^29.7.0", "jest-websocket-mock": "^2.5.0", diff --git a/packages/fcl-core/src/fcl-core.ts b/packages/fcl-core/src/fcl-core.ts index abe43be38..1a764cb6f 100644 --- a/packages/fcl-core/src/fcl-core.ts +++ b/packages/fcl-core/src/fcl-core.ts @@ -72,7 +72,7 @@ export {invariant} from "@onflow/sdk" // Subscriptions export {subscribe} from "@onflow/sdk" -export {rawSubscribe} from "@onflow/sdk" +export {subscribeRaw} from "@onflow/sdk" import {watchForChainIdChanges} from "./utils" diff --git a/packages/fcl-react-native/src/fcl-react-native.ts b/packages/fcl-react-native/src/fcl-react-native.ts index 9cf87a27a..bc11379fa 100644 --- a/packages/fcl-react-native/src/fcl-react-native.ts +++ b/packages/fcl-react-native/src/fcl-react-native.ts @@ -111,4 +111,4 @@ export {useServiceDiscovery, ServiceDiscovery} // Subscriptions export {subscribe} from "@onflow/fcl-core" -export {rawSubscribe} from "@onflow/fcl-core" +export {subscribeRaw} from "@onflow/fcl-core" diff --git a/packages/fcl/src/fcl.ts b/packages/fcl/src/fcl.ts index f2d71799a..78508a077 100644 --- a/packages/fcl/src/fcl.ts +++ b/packages/fcl/src/fcl.ts @@ -116,4 +116,4 @@ initFclWcLoader() export {LOCAL_STORAGE, SESSION_STORAGE} from "./utils/web" // Subscriptions -export {subscribe, rawSubscribe} from "@onflow/fcl-core" +export {subscribe, subscribeRaw} from "@onflow/fcl-core" diff --git a/packages/sdk/src/sdk.ts b/packages/sdk/src/sdk.ts index a24a83a54..f86ee7e8c 100644 --- a/packages/sdk/src/sdk.ts +++ b/packages/sdk/src/sdk.ts @@ -5,7 +5,7 @@ export {resolve} from "./resolve/resolve" export { send, subscribe, - rawSubscribe, + subscribeRaw, SubscriptionsNotSupportedError, } from "./transport" export {decode} from "./decode/sdk-decode" diff --git a/packages/sdk/src/transport/index.ts b/packages/sdk/src/transport/index.ts index 3c22c862e..c3bd97ba7 100644 --- a/packages/sdk/src/transport/index.ts +++ b/packages/sdk/src/transport/index.ts @@ -1,5 +1,5 @@ export {send} from "./send/send" export {subscribe} from "./subscribe/subscribe" -export {rawSubscribe} from "./subscribe/raw-subscribe" +export {subscribeRaw} from "./subscribe/subscribe-raw" export {SubscriptionsNotSupportedError} from "./subscribe/errors" export * from "./subscribe/types" diff --git a/packages/sdk/src/transport/subscribe/raw-subscribe.test.ts b/packages/sdk/src/transport/subscribe/subscribe-raw.test.ts similarity index 91% rename from packages/sdk/src/transport/subscribe/raw-subscribe.test.ts rename to packages/sdk/src/transport/subscribe/subscribe-raw.test.ts index 75e26b02f..e5d370278 100644 --- a/packages/sdk/src/transport/subscribe/raw-subscribe.test.ts +++ b/packages/sdk/src/transport/subscribe/subscribe-raw.test.ts @@ -1,5 +1,5 @@ import {config} from "@onflow/config" -import {rawSubscribe} from "./raw-subscribe" +import {subscribeRaw} from "./subscribe-raw" import { Subscription, SubscriptionArgs, @@ -34,7 +34,7 @@ describe("subscribe", () => { "accessNode.api": "http://localhost:8080", }, () => { - return rawSubscribe({topic, args, onData, onError}) + return subscribeRaw({topic, args, onData, onError}) } ) @@ -63,7 +63,7 @@ describe("subscribe", () => { "accessNode.api": "http://localhost:8080", }, () => { - return rawSubscribe({topic, args, onData, onError}) + return subscribeRaw({topic, args, onData, onError}) } ) @@ -78,7 +78,7 @@ describe("subscribe", () => { const onError = jest.fn() await config().overload({}, () => { - return rawSubscribe({topic, args, onData, onError}) + return subscribeRaw({topic, args, onData, onError}) }) expect(onError).toHaveBeenCalledTimes(1) diff --git a/packages/sdk/src/transport/subscribe/raw-subscribe.ts b/packages/sdk/src/transport/subscribe/subscribe-raw.ts similarity index 89% rename from packages/sdk/src/transport/subscribe/raw-subscribe.ts rename to packages/sdk/src/transport/subscribe/subscribe-raw.ts index f02a4f8d9..f28069e5f 100644 --- a/packages/sdk/src/transport/subscribe/raw-subscribe.ts +++ b/packages/sdk/src/transport/subscribe/subscribe-raw.ts @@ -2,7 +2,7 @@ import {config} from "@onflow/config" import {SdkTransport, SubscriptionTopic} from "@onflow/typedefs" import {getTransport} from "../get-transport" import {invariant} from "@onflow/util-invariant" -import {RawSubscribeParams} from "./types" +import {SubscribeRawParams} from "./types" /** * Subscribe to a topic without decoding the data. @@ -10,8 +10,8 @@ import {RawSubscribeParams} from "./types" * @param opts - Additional options for the subscription. * @returns A promise that resolves once the subscription is active. */ -export function rawSubscribe( - {topic, args, onData, onError}: RawSubscribeParams, +export function subscribeRaw( + {topic, args, onData, onError}: SubscribeRawParams, opts: { node?: string transport?: SdkTransport diff --git a/packages/sdk/src/transport/subscribe/subscribe.test.ts b/packages/sdk/src/transport/subscribe/subscribe.test.ts index 8ec15cc1a..1ed191aa4 100644 --- a/packages/sdk/src/transport/subscribe/subscribe.test.ts +++ b/packages/sdk/src/transport/subscribe/subscribe.test.ts @@ -5,10 +5,10 @@ import { SdkTransport, } from "@onflow/typedefs" import {subscribe} from "./subscribe" -import {rawSubscribe} from "./raw-subscribe" +import {subscribeRaw} from "./subscribe-raw" -jest.mock("./raw-subscribe") -const mockRawSubscribe = jest.mocked(rawSubscribe) +jest.mock("./subscribe-raw") +const mocksubscribeRaw = jest.mocked(subscribeRaw) describe("subscribe", () => { let mockSub: jest.Mocked = { @@ -17,7 +17,7 @@ describe("subscribe", () => { beforeEach(() => { jest.resetAllMocks() - mockRawSubscribe.mockReturnValue(mockSub) + mocksubscribeRaw.mockReturnValue(mockSub) }) test("subscribes to a topic and returns a subscription", async () => { @@ -34,8 +34,8 @@ describe("subscribe", () => { }) expect(sub).toBe(mockSub) - expect(mockRawSubscribe).toHaveBeenCalledTimes(1) - expect(mockRawSubscribe).toHaveBeenCalledWith( + expect(mocksubscribeRaw).toHaveBeenCalledTimes(1) + expect(mocksubscribeRaw).toHaveBeenCalledWith( {topic, args, onData: expect.any(Function), onError}, {} ) @@ -78,8 +78,8 @@ describe("subscribe", () => { ) expect(sub).toBe(mockSub) - expect(mockRawSubscribe).toHaveBeenCalledTimes(1) - expect(mockRawSubscribe).toHaveBeenCalledWith( + expect(mocksubscribeRaw).toHaveBeenCalledTimes(1) + expect(mocksubscribeRaw).toHaveBeenCalledWith( {topic, args, onData: expect.any(Function), onError}, {node} ) @@ -108,8 +108,8 @@ describe("subscribe", () => { ) expect(sub).toBe(mockSub) - expect(mockRawSubscribe).toHaveBeenCalledTimes(1) - expect(mockRawSubscribe).toHaveBeenCalledWith( + expect(mocksubscribeRaw).toHaveBeenCalledTimes(1) + expect(mocksubscribeRaw).toHaveBeenCalledWith( {topic, args, onData: expect.any(Function), onError}, {node, transport} ) diff --git a/packages/sdk/src/transport/subscribe/subscribe.ts b/packages/sdk/src/transport/subscribe/subscribe.ts index 0325b572d..51dfa53c3 100644 --- a/packages/sdk/src/transport/subscribe/subscribe.ts +++ b/packages/sdk/src/transport/subscribe/subscribe.ts @@ -1,5 +1,5 @@ import {SdkTransport, Subscription, SubscriptionTopic} from "@onflow/typedefs" -import {rawSubscribe} from "./raw-subscribe" +import {subscribeRaw} from "./subscribe-raw" import {decodeResponse} from "../../decode/decode" import {SubscribeParams} from "./types" @@ -16,7 +16,7 @@ export function subscribe( transport?: SdkTransport } = {} ): Subscription { - const sub = rawSubscribe( + const sub = subscribeRaw( { topic, args, diff --git a/packages/sdk/src/transport/subscribe/types.ts b/packages/sdk/src/transport/subscribe/types.ts index d228c8e2b..95cc16963 100644 --- a/packages/sdk/src/transport/subscribe/types.ts +++ b/packages/sdk/src/transport/subscribe/types.ts @@ -24,7 +24,7 @@ export type SubscribeParams = { onError: (error: Error) => void } -export type RawSubscribeParams = { +export type SubscribeRawParams = { /** * The topic to subscribe to. */ From 6e52a2519220641cf8a70eac25172272ce73d0e9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 11:00:16 -0700 Subject: [PATCH 52/72] Version Packages (#2467) --- .changeset/breezy-gifts-sit.md | 5 -- .changeset/chatty-ghosts-bake.md | 5 -- .changeset/fast-lobsters-train.md | 5 -- .changeset/forty-trees-report.md | 5 -- .changeset/four-frogs-jump.md | 5 -- .changeset/good-books-call.md | 5 -- .changeset/hip-beans-speak.md | 9 --- .changeset/mean-walls-hear.md | 12 --- .changeset/moody-ligers-rule.md | 5 -- .changeset/odd-seals-glow.md | 5 -- .changeset/pre.json | 49 ------------ .changeset/sharp-suns-refuse.md | 22 ------ .changeset/shy-cars-beam.md | 5 -- .changeset/sixty-pandas-retire.md | 18 ----- .changeset/slimy-drinks-bake.md | 5 -- .changeset/spicy-fishes-drum.md | 5 -- .changeset/tame-pianos-doubt.md | 6 -- package-lock.json | 78 ++++++++++---------- packages/fcl-core/CHANGELOG.md | 31 +++++++- packages/fcl-core/package.json | 8 +- packages/fcl-ethereum-provider/CHANGELOG.md | 8 ++ packages/fcl-ethereum-provider/package.json | 8 +- packages/fcl-rainbowkit-adapter/CHANGELOG.md | 9 +++ packages/fcl-rainbowkit-adapter/package.json | 10 +-- packages/fcl-react-native/CHANGELOG.md | 29 +++++++- packages/fcl-react-native/package.json | 8 +- packages/fcl-wagmi-adapter/CHANGELOG.md | 8 ++ packages/fcl-wagmi-adapter/package.json | 8 +- packages/fcl-wc/CHANGELOG.md | 7 ++ packages/fcl-wc/package.json | 6 +- packages/fcl/CHANGELOG.md | 32 +++++++- packages/fcl/package.json | 10 +-- packages/kit/CHANGELOG.md | 21 ++++++ packages/kit/package.json | 6 +- packages/sdk/CHANGELOG.md | 31 +++++++- packages/sdk/package.json | 6 +- packages/transport-grpc/package.json | 2 +- packages/transport-http/CHANGELOG.md | 19 +++++ packages/transport-http/package.json | 4 +- packages/typedefs/CHANGELOG.md | 8 ++ packages/typedefs/package.json | 2 +- 41 files changed, 276 insertions(+), 254 deletions(-) delete mode 100644 .changeset/breezy-gifts-sit.md delete mode 100644 .changeset/chatty-ghosts-bake.md delete mode 100644 .changeset/fast-lobsters-train.md delete mode 100644 .changeset/forty-trees-report.md delete mode 100644 .changeset/four-frogs-jump.md delete mode 100644 .changeset/good-books-call.md delete mode 100644 .changeset/hip-beans-speak.md delete mode 100644 .changeset/mean-walls-hear.md delete mode 100644 .changeset/moody-ligers-rule.md delete mode 100644 .changeset/odd-seals-glow.md delete mode 100644 .changeset/pre.json delete mode 100644 .changeset/sharp-suns-refuse.md delete mode 100644 .changeset/shy-cars-beam.md delete mode 100644 .changeset/sixty-pandas-retire.md delete mode 100644 .changeset/slimy-drinks-bake.md delete mode 100644 .changeset/spicy-fishes-drum.md delete mode 100644 .changeset/tame-pianos-doubt.md diff --git a/.changeset/breezy-gifts-sit.md b/.changeset/breezy-gifts-sit.md deleted file mode 100644 index a1cd27be4..000000000 --- a/.changeset/breezy-gifts-sit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/typedefs": minor ---- - -Add typedefs for streaming API \ No newline at end of file diff --git a/.changeset/chatty-ghosts-bake.md b/.changeset/chatty-ghosts-bake.md deleted file mode 100644 index 7d7d3a93e..000000000 --- a/.changeset/chatty-ghosts-bake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/kit": minor ---- - -Make `txId` optional for `useFlowTransactionStatus` diff --git a/.changeset/fast-lobsters-train.md b/.changeset/fast-lobsters-train.md deleted file mode 100644 index f7a3c5baf..000000000 --- a/.changeset/fast-lobsters-train.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/kit": patch ---- - -Update readme with `useFlowRevertibleRandom` hook diff --git a/.changeset/forty-trees-report.md b/.changeset/forty-trees-report.md deleted file mode 100644 index 4598252b2..000000000 --- a/.changeset/forty-trees-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/kit": patch ---- - -Fix `useFlowRevertibleRandom` range diff --git a/.changeset/four-frogs-jump.md b/.changeset/four-frogs-jump.md deleted file mode 100644 index 014670392..000000000 --- a/.changeset/four-frogs-jump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/sdk": patch ---- - -Fixed fcl.mutate hanging diff --git a/.changeset/good-books-call.md b/.changeset/good-books-call.md deleted file mode 100644 index deea1ec01..000000000 --- a/.changeset/good-books-call.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/kit": minor ---- - -Add `useCrossVmBatchTransaction` function diff --git a/.changeset/hip-beans-speak.md b/.changeset/hip-beans-speak.md deleted file mode 100644 index 53b9c93ac..000000000 --- a/.changeset/hip-beans-speak.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@onflow/fcl-react-native": minor -"@onflow/transport-http": minor -"@onflow/fcl-core": minor -"@onflow/fcl": minor -"@onflow/sdk": minor ---- - -Rename `rawSubscribe` to `subscribeRaw` diff --git a/.changeset/mean-walls-hear.md b/.changeset/mean-walls-hear.md deleted file mode 100644 index ede2b65c7..000000000 --- a/.changeset/mean-walls-hear.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@onflow/transport-http": minor ---- - -Add support for new WebSocket streaming methods. The following topics are now available: - -- `blocks` -- `block_headers` -- `block_digests` -- `transaction_statues` -- `events` -- `account_statuses` diff --git a/.changeset/moody-ligers-rule.md b/.changeset/moody-ligers-rule.md deleted file mode 100644 index 2b30cfef4..000000000 --- a/.changeset/moody-ligers-rule.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/kit": minor ---- - -**BREAKING**: Rename `useFlowTransaction` as `useFlowTransactionStatus` diff --git a/.changeset/odd-seals-glow.md b/.changeset/odd-seals-glow.md deleted file mode 100644 index 9031d447c..000000000 --- a/.changeset/odd-seals-glow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/kit": minor ---- - -Add `useFlowChainId` hook to the `@onflow/kit` package. diff --git a/.changeset/pre.json b/.changeset/pre.json deleted file mode 100644 index 4dc33f16d..000000000 --- a/.changeset/pre.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "mode": "exit", - "tag": "alpha", - "initialVersions": { - "@onflow/config": "1.5.2", - "@onflow/fcl": "1.17.0", - "@onflow/fcl-bundle": "1.7.0", - "@onflow/fcl-core": "1.18.0", - "@onflow/fcl-ethereum-provider": "0.0.4", - "@onflow/fcl-rainbowkit-adapter": "0.2.0", - "@onflow/fcl-react-native": "1.11.0", - "@onflow/fcl-wagmi-adapter": "0.0.4", - "@onflow/fcl-wc": "6.0.2", - "@onflow/kit": "0.1.0", - "@onflow/protobuf": "1.3.1", - "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.8.1", - "@onflow/transport-grpc": "1.4.2-alpha.0", - "@onflow/transport-http": "1.12.0", - "@onflow/typedefs": "1.5.0", - "@onflow/types": "1.4.1", - "@onflow/util-actor": "1.3.4", - "@onflow/util-address": "1.2.3", - "@onflow/util-encode-key": "1.2.4", - "@onflow/util-invariant": "1.2.4", - "@onflow/util-logger": "1.3.3", - "@onflow/util-rpc": "0.0.2", - "@onflow/util-semver": "1.0.3", - "@onflow/util-template": "1.2.3", - "@onflow/util-uid": "1.2.3" - }, - "changesets": [ - "breezy-gifts-sit", - "chatty-ghosts-bake", - "fast-lobsters-train", - "forty-trees-report", - "four-frogs-jump", - "good-books-call", - "mean-walls-hear", - "moody-ligers-rule", - "odd-seals-glow", - "sharp-suns-refuse", - "shy-cars-beam", - "sixty-pandas-retire", - "slimy-drinks-bake", - "spicy-fishes-drum", - "tame-pianos-doubt" - ] -} diff --git a/.changeset/sharp-suns-refuse.md b/.changeset/sharp-suns-refuse.md deleted file mode 100644 index 55fa8ea3b..000000000 --- a/.changeset/sharp-suns-refuse.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -"@onflow/fcl-react-native": minor -"@onflow/fcl-core": minor -"@onflow/fcl": minor ---- - -Add real-time streaming methods `subscribe` and `rawSubscribe`. - -These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. - -The following topics are now available: - -- `blocks` -- `block_headers` -- `block_digests` -- `transaction_statues` -- `events` -- `account_statuses` - -Developers using `fcl.tx` and `fcl.events` will not need to make any changes to their existing app to realize the latency improvements of this change and will automatically benefit by upgrading to this version. - -Please see the [Flow Developer Documentation](https://developers.flow.com/clients/fcl-js/) for more details on how to use these new methods. \ No newline at end of file diff --git a/.changeset/shy-cars-beam.md b/.changeset/shy-cars-beam.md deleted file mode 100644 index 25a1954cc..000000000 --- a/.changeset/shy-cars-beam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/transport-http": minor ---- - -Expose the `httpTransport` as a named export from `@onflow/transport-http` package. This follows the new object-style export for SDK transports and adds streaming support. \ No newline at end of file diff --git a/.changeset/sixty-pandas-retire.md b/.changeset/sixty-pandas-retire.md deleted file mode 100644 index 842caef5e..000000000 --- a/.changeset/sixty-pandas-retire.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -"@onflow/sdk": minor ---- - -Add real-time streaming methods `subscribe` and `rawSubscribe`. - -These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. - -The following topics are now available: - -- `blocks` -- `block_headers` -- `block_digests` -- `transaction_statues` -- `events` -- `account_statuses` - -Please see the [Flow Developer Documentation](https://developers.flow.com/clients/fcl-js/) for more details on how to use these new methods. \ No newline at end of file diff --git a/.changeset/slimy-drinks-bake.md b/.changeset/slimy-drinks-bake.md deleted file mode 100644 index 5d77d08f1..000000000 --- a/.changeset/slimy-drinks-bake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/fcl-core": patch ---- - -Unsubscribe from transaction statuses when sealed diff --git a/.changeset/spicy-fishes-drum.md b/.changeset/spicy-fishes-drum.md deleted file mode 100644 index 94376ec18..000000000 --- a/.changeset/spicy-fishes-drum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/transport-http": patch ---- - -Add `parentVoterSignature` field to GetBlock request diff --git a/.changeset/tame-pianos-doubt.md b/.changeset/tame-pianos-doubt.md deleted file mode 100644 index f4d0f2b54..000000000 --- a/.changeset/tame-pianos-doubt.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@onflow/typedefs": minor -"@onflow/sdk": minor ---- - -Refactored onflow/sdk package to improve TypeScript support diff --git a/package-lock.json b/package-lock.json index 533425ac8..0dfa9ceb7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30881,16 +30881,16 @@ }, "packages/fcl": { "name": "@onflow/fcl", - "version": "1.18.0-alpha.1", + "version": "1.18.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.19.0-alpha.1", - "@onflow/fcl-wc": "6.0.3-alpha.1", + "@onflow/fcl-core": "1.19.0", + "@onflow/fcl-wc": "6.0.3", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.1", + "@onflow/sdk": "1.9.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", @@ -30908,7 +30908,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.6.0-alpha.0", + "@onflow/typedefs": "1.6.0", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -30956,7 +30956,7 @@ }, "packages/fcl-core": { "name": "@onflow/fcl-core", - "version": "1.19.0-alpha.1", + "version": "1.19.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -30964,8 +30964,8 @@ "@onflow/config": "1.5.2", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.1", - "@onflow/transport-http": "1.13.0-alpha.0", + "@onflow/sdk": "1.9.0", + "@onflow/transport-http": "1.13.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", @@ -30979,7 +30979,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.6.0-alpha.0", + "@onflow/typedefs": "1.6.0", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -31011,14 +31011,14 @@ }, "packages/fcl-ethereum-provider": { "name": "@onflow/fcl-ethereum-provider", - "version": "0.0.5-alpha.1", + "version": "0.0.5", "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.3-alpha.1", + "@onflow/fcl-wc": "6.0.3", "@onflow/rlp": "^1.2.3", "@walletconnect/ethereum-provider": "^2.20.2", "@walletconnect/jsonrpc-http-connection": "^1.0.8", @@ -31030,7 +31030,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.6.0-alpha.0", + "@onflow/typedefs": "^1.6.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -31039,7 +31039,7 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.1" + "@onflow/fcl": "1.18.0" } }, "packages/fcl-ethereum-provider/node_modules/@react-native-async-storage/async-storage": { @@ -31184,14 +31184,14 @@ }, "packages/fcl-rainbowkit-adapter": { "name": "@onflow/fcl-rainbowkit-adapter", - "version": "0.2.1-alpha.1", + "version": "0.2.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.5-alpha.1", - "@onflow/fcl-wagmi-adapter": "0.0.5-alpha.1", + "@onflow/fcl-ethereum-provider": "0.0.5", + "@onflow/fcl-wagmi-adapter": "0.0.5", "@onflow/rlp": "^1.2.3", "@wagmi/core": "^2.16.3", "mipd": "^0.0.7", @@ -31202,7 +31202,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.6.0-alpha.0", + "@onflow/typedefs": "^1.6.0", "@types/jest": "^29.5.13", "@types/react": "^16.0.0", "@typescript-eslint/eslint-plugin": "^6.21.0", @@ -31212,7 +31212,7 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.1", + "@onflow/fcl": "1.18.0", "@rainbow-me/rainbowkit": "^2.2.3", "react": "17.x || 18.x || 19.x" } @@ -31229,15 +31229,15 @@ }, "packages/fcl-react-native": { "name": "@onflow/fcl-react-native", - "version": "1.12.0-alpha.1", + "version": "1.12.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.19.0-alpha.1", + "@onflow/fcl-core": "1.19.0", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.1", + "@onflow/sdk": "1.9.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", @@ -31250,7 +31250,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.6.0-alpha.0", + "@onflow/typedefs": "1.6.0", "@types/estree": "^1.0.6", "@types/node": "^18.19.57", "eslint": "^8.57.1", @@ -31288,20 +31288,20 @@ }, "packages/fcl-wagmi-adapter": { "name": "@onflow/fcl-wagmi-adapter", - "version": "0.0.5-alpha.1", + "version": "0.0.5", "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.5-alpha.1", + "@onflow/fcl-ethereum-provider": "0.0.5", "@onflow/rlp": "^1.2.3", "viem": "^2.22.21" }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.6.0-alpha.0", + "@onflow/typedefs": "^1.6.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -31310,13 +31310,13 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.1", + "@onflow/fcl": "1.18.0", "@wagmi/core": "^2.16.3" } }, "packages/fcl-wc": { "name": "@onflow/fcl-wc", - "version": "6.0.3-alpha.1", + "version": "6.0.3", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -31335,7 +31335,7 @@ "@babel/plugin-transform-react-jsx": "^7.25.9", "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.6.0-alpha.0", + "@onflow/typedefs": "1.6.0", "autoprefixer": "^10.4.20", "eslint": "^8.57.1", "eslint-plugin-jsdoc": "^46.10.1", @@ -31343,7 +31343,7 @@ "jest-preset-preact": "^4.1.1" }, "peerDependencies": { - "@onflow/fcl-core": "1.19.0-alpha.1" + "@onflow/fcl-core": "1.19.0" } }, "packages/fcl-wc/node_modules/@react-native-async-storage/async-storage": { @@ -31490,7 +31490,7 @@ }, "packages/kit": { "name": "@onflow/kit", - "version": "0.2.0-alpha.1", + "version": "0.2.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -31503,7 +31503,7 @@ "@babel/preset-react": "^7.26.3", "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.6.0-alpha.0", + "@onflow/typedefs": "^1.6.0", "@testing-library/dom": "^10.4.0", "@types/jest": "^29.5.13", "@types/react": "^19.0.10", @@ -31516,7 +31516,7 @@ "jest-environment-jsdom": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": ">=1.18.0-alpha.1", + "@onflow/fcl": ">=1.18.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } @@ -31702,14 +31702,14 @@ }, "packages/sdk": { "name": "@onflow/sdk", - "version": "1.9.0-alpha.1", + "version": "1.9.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", "@onflow/rlp": "1.2.3", - "@onflow/transport-http": "1.13.0-alpha.0", - "@onflow/typedefs": "1.6.0-alpha.0", + "@onflow/transport-http": "1.13.0", + "@onflow/typedefs": "1.6.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", @@ -31758,13 +31758,13 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/sdk": "1.9.0-alpha.1", + "@onflow/sdk": "1.9.0", "jest": "^29.7.0" } }, "packages/transport-http": { "name": "@onflow/transport-http", - "version": "1.13.0-alpha.0", + "version": "1.13.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -31782,7 +31782,7 @@ "devDependencies": { "@onflow/fcl-bundle": "1.7.0", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.1", + "@onflow/sdk": "1.9.0", "@onflow/types": "1.4.1", "jest": "^29.7.0", "jest-websocket-mock": "^2.5.0", @@ -31798,7 +31798,7 @@ }, "packages/typedefs": { "name": "@onflow/typedefs", - "version": "1.6.0-alpha.0", + "version": "1.6.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7" diff --git a/packages/fcl-core/CHANGELOG.md b/packages/fcl-core/CHANGELOG.md index a3c8261bf..7aa1becfb 100644 --- a/packages/fcl-core/CHANGELOG.md +++ b/packages/fcl-core/CHANGELOG.md @@ -1,5 +1,34 @@ # @onflow/fcl +## 1.19.0 + +### Minor Changes + +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `subscribeRaw`. + + These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. + + The following topics are now available: + + - `blocks` + - `block_headers` + - `block_digests` + - `transaction_statues` + - `events` + - `account_statuses` + + Developers using `fcl.tx` and `fcl.events` will not need to make any changes to their existing app to realize the latency improvements of this change and will automatically benefit by upgrading to this version. + + Please see the [Flow Developer Documentation](https://developers.flow.com/clients/fcl-js/) for more details on how to use these new methods. + +### Patch Changes + +- [#2461](https://github.com/onflow/fcl-js/pull/2461) [`2637889fdb47a2294ad2db9d06a16fac1d805a12`](https://github.com/onflow/fcl-js/commit/2637889fdb47a2294ad2db9d06a16fac1d805a12) Thanks [@jribbink](https://github.com/jribbink)! - Unsubscribe from transaction statuses when sealed + +- Updated dependencies [[`3ac616d64c9abcda32f0c450119f22fa479d5e89`](https://github.com/onflow/fcl-js/commit/3ac616d64c9abcda32f0c450119f22fa479d5e89), [`0b83658f62a428a70074d33875f264fbd48aff1e`](https://github.com/onflow/fcl-js/commit/0b83658f62a428a70074d33875f264fbd48aff1e), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`694cd76807b7ca4441d1f8425ac4f8426cbc18fa`](https://github.com/onflow/fcl-js/commit/694cd76807b7ca4441d1f8425ac4f8426cbc18fa), [`4d3bb084c1442552d6a1de1f53435d1aa3f600b0`](https://github.com/onflow/fcl-js/commit/4d3bb084c1442552d6a1de1f53435d1aa3f600b0)]: + - @onflow/sdk@1.9.0 + - @onflow/transport-http@1.13.0 + ## 1.19.0-alpha.2 ### Patch Changes @@ -17,7 +46,7 @@ ### Minor Changes -- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `rawSubscribe`. +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `subscribeRaw`. These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. diff --git a/packages/fcl-core/package.json b/packages/fcl-core/package.json index 9414f1311..ded6a2947 100644 --- a/packages/fcl-core/package.json +++ b/packages/fcl-core/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-core", - "version": "1.19.0-alpha.2", + "version": "1.19.0", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", @@ -20,7 +20,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.6.0-alpha.0", + "@onflow/typedefs": "1.6.0", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -52,8 +52,8 @@ "@onflow/config": "1.5.2", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.1", - "@onflow/transport-http": "1.13.0-alpha.0", + "@onflow/sdk": "1.9.0", + "@onflow/transport-http": "1.13.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", diff --git a/packages/fcl-ethereum-provider/CHANGELOG.md b/packages/fcl-ethereum-provider/CHANGELOG.md index b4c7e6142..f1050ddfa 100644 --- a/packages/fcl-ethereum-provider/CHANGELOG.md +++ b/packages/fcl-ethereum-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @onflow/fcl-ethereum-provider +## 0.0.5 + +### Patch Changes + +- Updated dependencies [[`0b83658f62a428a70074d33875f264fbd48aff1e`](https://github.com/onflow/fcl-js/commit/0b83658f62a428a70074d33875f264fbd48aff1e), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab)]: + - @onflow/fcl@1.18.0 + - @onflow/fcl-wc@6.0.3 + ## 0.0.5-alpha.2 ### Patch Changes diff --git a/packages/fcl-ethereum-provider/package.json b/packages/fcl-ethereum-provider/package.json index 9f5e933c1..5eafc3c9a 100644 --- a/packages/fcl-ethereum-provider/package.json +++ b/packages/fcl-ethereum-provider/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-ethereum-provider", - "version": "0.0.5-alpha.2", + "version": "0.0.5", "description": "Ethereum provider for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -15,7 +15,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.6.0-alpha.0", + "@onflow/typedefs": "^1.6.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -40,7 +40,7 @@ "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", "@noble/hashes": "^1.7.1", - "@onflow/fcl-wc": "6.0.3-alpha.2", + "@onflow/fcl-wc": "6.0.3", "@onflow/rlp": "^1.2.3", "@walletconnect/ethereum-provider": "^2.20.2", "@walletconnect/jsonrpc-http-connection": "^1.0.8", @@ -50,6 +50,6 @@ "@walletconnect/utils": "^2.20.2" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.2" + "@onflow/fcl": "1.18.0" } } diff --git a/packages/fcl-rainbowkit-adapter/CHANGELOG.md b/packages/fcl-rainbowkit-adapter/CHANGELOG.md index 05c641bc6..0dbf2550e 100644 --- a/packages/fcl-rainbowkit-adapter/CHANGELOG.md +++ b/packages/fcl-rainbowkit-adapter/CHANGELOG.md @@ -1,5 +1,14 @@ # @onflow/fcl-rainbowkit-adapter +## 0.2.1 + +### Patch Changes + +- Updated dependencies [[`0b83658f62a428a70074d33875f264fbd48aff1e`](https://github.com/onflow/fcl-js/commit/0b83658f62a428a70074d33875f264fbd48aff1e), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab)]: + - @onflow/fcl@1.18.0 + - @onflow/fcl-ethereum-provider@0.0.5 + - @onflow/fcl-wagmi-adapter@0.0.5 + ## 0.2.1-alpha.2 ### Patch Changes diff --git a/packages/fcl-rainbowkit-adapter/package.json b/packages/fcl-rainbowkit-adapter/package.json index aa234a50a..d37a201bf 100644 --- a/packages/fcl-rainbowkit-adapter/package.json +++ b/packages/fcl-rainbowkit-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-rainbowkit-adapter", - "version": "0.2.1-alpha.2", + "version": "0.2.1", "description": "Rainbowkit adapter for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -15,7 +15,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.6.0-alpha.0", + "@onflow/typedefs": "^1.6.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -40,8 +40,8 @@ "@babel/runtime": "^7.25.7", "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", - "@onflow/fcl-ethereum-provider": "0.0.5-alpha.2", - "@onflow/fcl-wagmi-adapter": "0.0.5-alpha.2", + "@onflow/fcl-ethereum-provider": "0.0.5", + "@onflow/fcl-wagmi-adapter": "0.0.5", "@onflow/rlp": "^1.2.3", "@wagmi/core": "^2.16.3", "mipd": "^0.0.7", @@ -50,7 +50,7 @@ "wagmi": "^2.14.11" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.2", + "@onflow/fcl": "1.18.0", "@rainbow-me/rainbowkit": "^2.2.3", "react": "17.x || 18.x || 19.x" } diff --git a/packages/fcl-react-native/CHANGELOG.md b/packages/fcl-react-native/CHANGELOG.md index 97ebade61..20e459360 100644 --- a/packages/fcl-react-native/CHANGELOG.md +++ b/packages/fcl-react-native/CHANGELOG.md @@ -1,5 +1,32 @@ # @onflow/fcl-react-native +## 1.12.0 + +### Minor Changes + +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `subscribeRaw`. + + These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. + + The following topics are now available: + + - `blocks` + - `block_headers` + - `block_digests` + - `transaction_statues` + - `events` + - `account_statuses` + + Developers using `fcl.tx` and `fcl.events` will not need to make any changes to their existing app to realize the latency improvements of this change and will automatically benefit by upgrading to this version. + + Please see the [Flow Developer Documentation](https://developers.flow.com/clients/fcl-js/) for more details on how to use these new methods. + +### Patch Changes + +- Updated dependencies [[`3ac616d64c9abcda32f0c450119f22fa479d5e89`](https://github.com/onflow/fcl-js/commit/3ac616d64c9abcda32f0c450119f22fa479d5e89), [`0b83658f62a428a70074d33875f264fbd48aff1e`](https://github.com/onflow/fcl-js/commit/0b83658f62a428a70074d33875f264fbd48aff1e), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`2637889fdb47a2294ad2db9d06a16fac1d805a12`](https://github.com/onflow/fcl-js/commit/2637889fdb47a2294ad2db9d06a16fac1d805a12), [`4d3bb084c1442552d6a1de1f53435d1aa3f600b0`](https://github.com/onflow/fcl-js/commit/4d3bb084c1442552d6a1de1f53435d1aa3f600b0)]: + - @onflow/sdk@1.9.0 + - @onflow/fcl-core@1.19.0 + ## 1.12.0-alpha.2 ### Patch Changes @@ -19,7 +46,7 @@ ### Minor Changes -- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `rawSubscribe`. +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `subscribeRaw`. These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. diff --git a/packages/fcl-react-native/package.json b/packages/fcl-react-native/package.json index 329a50e51..f2cfd70a5 100644 --- a/packages/fcl-react-native/package.json +++ b/packages/fcl-react-native/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-react-native", - "version": "1.12.0-alpha.2", + "version": "1.12.0", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", @@ -20,7 +20,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.6.0-alpha.0", + "@onflow/typedefs": "1.6.0", "@types/estree": "^1.0.6", "@types/node": "^18.19.57", "eslint": "^8.57.1", @@ -48,10 +48,10 @@ "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.19.0-alpha.2", + "@onflow/fcl-core": "1.19.0", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.1", + "@onflow/sdk": "1.9.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", diff --git a/packages/fcl-wagmi-adapter/CHANGELOG.md b/packages/fcl-wagmi-adapter/CHANGELOG.md index 30534bf4e..49a99850c 100644 --- a/packages/fcl-wagmi-adapter/CHANGELOG.md +++ b/packages/fcl-wagmi-adapter/CHANGELOG.md @@ -1,5 +1,13 @@ # @onflow/fcl-wagmi-adapter +## 0.0.5 + +### Patch Changes + +- Updated dependencies [[`0b83658f62a428a70074d33875f264fbd48aff1e`](https://github.com/onflow/fcl-js/commit/0b83658f62a428a70074d33875f264fbd48aff1e), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab)]: + - @onflow/fcl@1.18.0 + - @onflow/fcl-ethereum-provider@0.0.5 + ## 0.0.5-alpha.2 ### Patch Changes diff --git a/packages/fcl-wagmi-adapter/package.json b/packages/fcl-wagmi-adapter/package.json index 9bc630dbe..a35b3cf3f 100644 --- a/packages/fcl-wagmi-adapter/package.json +++ b/packages/fcl-wagmi-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-wagmi-adapter", - "version": "0.0.5-alpha.2", + "version": "0.0.5", "description": "Wagmi adapter for FCL-compatible wallets", "license": "Apache-2.0", "author": "Dapper Labs ", @@ -15,7 +15,7 @@ "devDependencies": { "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.6.0-alpha.0", + "@onflow/typedefs": "^1.6.0", "@types/jest": "^29.5.13", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -39,12 +39,12 @@ "@babel/runtime": "^7.25.7", "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", - "@onflow/fcl-ethereum-provider": "0.0.5-alpha.2", + "@onflow/fcl-ethereum-provider": "0.0.5", "@onflow/rlp": "^1.2.3", "viem": "^2.22.21" }, "peerDependencies": { - "@onflow/fcl": "1.18.0-alpha.2", + "@onflow/fcl": "1.18.0", "@wagmi/core": "^2.16.3" } } diff --git a/packages/fcl-wc/CHANGELOG.md b/packages/fcl-wc/CHANGELOG.md index 95c2a77d3..4526dc619 100644 --- a/packages/fcl-wc/CHANGELOG.md +++ b/packages/fcl-wc/CHANGELOG.md @@ -1,5 +1,12 @@ # @onflow/fcl-wc +## 6.0.3 + +### Patch Changes + +- Updated dependencies [[`0b83658f62a428a70074d33875f264fbd48aff1e`](https://github.com/onflow/fcl-js/commit/0b83658f62a428a70074d33875f264fbd48aff1e), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`2637889fdb47a2294ad2db9d06a16fac1d805a12`](https://github.com/onflow/fcl-js/commit/2637889fdb47a2294ad2db9d06a16fac1d805a12)]: + - @onflow/fcl-core@1.19.0 + ## 6.0.3-alpha.2 ### Patch Changes diff --git a/packages/fcl-wc/package.json b/packages/fcl-wc/package.json index 13a81e0ae..b39cd7698 100644 --- a/packages/fcl-wc/package.json +++ b/packages/fcl-wc/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl-wc", - "version": "6.0.3-alpha.2", + "version": "6.0.3", "description": "WalletConnect adapter for FCL", "license": "Apache-2.0", "author": "Flow Foundation", @@ -31,7 +31,7 @@ "@babel/plugin-transform-react-jsx": "^7.25.9", "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.6.0-alpha.0", + "@onflow/typedefs": "1.6.0", "autoprefixer": "^10.4.20", "eslint": "^8.57.1", "eslint-plugin-jsdoc": "^46.10.1", @@ -52,6 +52,6 @@ "tailwindcss": "^3.4.14" }, "peerDependencies": { - "@onflow/fcl-core": "1.19.0-alpha.2" + "@onflow/fcl-core": "1.19.0" } } diff --git a/packages/fcl/CHANGELOG.md b/packages/fcl/CHANGELOG.md index 59e622800..c5eeddf8f 100644 --- a/packages/fcl/CHANGELOG.md +++ b/packages/fcl/CHANGELOG.md @@ -1,5 +1,33 @@ # @onflow/fcl +## 1.18.0 + +### Minor Changes + +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `subscribeRaw`. + + These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. + + The following topics are now available: + + - `blocks` + - `block_headers` + - `block_digests` + - `transaction_statues` + - `events` + - `account_statuses` + + Developers using `fcl.tx` and `fcl.events` will not need to make any changes to their existing app to realize the latency improvements of this change and will automatically benefit by upgrading to this version. + + Please see the [Flow Developer Documentation](https://developers.flow.com/clients/fcl-js/) for more details on how to use these new methods. + +### Patch Changes + +- Updated dependencies [[`3ac616d64c9abcda32f0c450119f22fa479d5e89`](https://github.com/onflow/fcl-js/commit/3ac616d64c9abcda32f0c450119f22fa479d5e89), [`0b83658f62a428a70074d33875f264fbd48aff1e`](https://github.com/onflow/fcl-js/commit/0b83658f62a428a70074d33875f264fbd48aff1e), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`2637889fdb47a2294ad2db9d06a16fac1d805a12`](https://github.com/onflow/fcl-js/commit/2637889fdb47a2294ad2db9d06a16fac1d805a12), [`4d3bb084c1442552d6a1de1f53435d1aa3f600b0`](https://github.com/onflow/fcl-js/commit/4d3bb084c1442552d6a1de1f53435d1aa3f600b0)]: + - @onflow/sdk@1.9.0 + - @onflow/fcl-core@1.19.0 + - @onflow/fcl-wc@6.0.3 + ## 1.18.0-alpha.2 ### Patch Changes @@ -21,7 +49,7 @@ ### Minor Changes -- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `rawSubscribe`. +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `subscribeRaw`. These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. @@ -43,7 +71,7 @@ - Updated dependencies [[`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`4d3bb084c1442552d6a1de1f53435d1aa3f600b0`](https://github.com/onflow/fcl-js/commit/4d3bb084c1442552d6a1de1f53435d1aa3f600b0)]: - @onflow/fcl-core@1.19.0-alpha.0 - @onflow/sdk@1.9.0-alpha.0 - - @onflow/fcl-wc@7.0.0-alpha.0 + - @onflow/fcl-wc@6.0.3-alpha.0 ## 1.17.0 diff --git a/packages/fcl/package.json b/packages/fcl/package.json index 64a8b7e1f..fbf699d26 100644 --- a/packages/fcl/package.json +++ b/packages/fcl/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/fcl", - "version": "1.18.0-alpha.2", + "version": "1.18.0", "description": "Flow Client Library", "license": "Apache-2.0", "author": "Flow Foundation", @@ -20,7 +20,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "1.6.0-alpha.0", + "@onflow/typedefs": "1.6.0", "@types/estree": "^1.0.6", "@types/jest": "^29.5.13", "@types/node": "^18.19.57", @@ -49,11 +49,11 @@ "dependencies": { "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", - "@onflow/fcl-core": "1.19.0-alpha.2", - "@onflow/fcl-wc": "6.0.3-alpha.2", + "@onflow/fcl-core": "1.19.0", + "@onflow/fcl-wc": "6.0.3", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.1", + "@onflow/sdk": "1.9.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", diff --git a/packages/kit/CHANGELOG.md b/packages/kit/CHANGELOG.md index 880a3e8f8..aeb874cfa 100644 --- a/packages/kit/CHANGELOG.md +++ b/packages/kit/CHANGELOG.md @@ -1,5 +1,26 @@ # @onflow/kit +## 0.2.0 + +### Minor Changes + +- [#2439](https://github.com/onflow/fcl-js/pull/2439) [`a36d78ee5283ceb9a2f411e6da9ddf0373777c24`](https://github.com/onflow/fcl-js/commit/a36d78ee5283ceb9a2f411e6da9ddf0373777c24) Thanks [@jribbink](https://github.com/jribbink)! - Make `txId` optional for `useFlowTransactionStatus` + +- [#2368](https://github.com/onflow/fcl-js/pull/2368) [`eca4617c2d4d10d85bad0324f6c6064489c3d1c3`](https://github.com/onflow/fcl-js/commit/eca4617c2d4d10d85bad0324f6c6064489c3d1c3) Thanks [@jribbink](https://github.com/jribbink)! - Add `useCrossVmBatchTransaction` function + +- [#2414](https://github.com/onflow/fcl-js/pull/2414) [`605f66c7a78f9ff1474a18b70298956b92f90bc1`](https://github.com/onflow/fcl-js/commit/605f66c7a78f9ff1474a18b70298956b92f90bc1) Thanks [@chasefleming](https://github.com/chasefleming)! - **BREAKING**: Rename `useFlowTransaction` as `useFlowTransactionStatus` + +- [#2367](https://github.com/onflow/fcl-js/pull/2367) [`9595af75eeffb0c91f9bb94b70fb0adf4db40eec`](https://github.com/onflow/fcl-js/commit/9595af75eeffb0c91f9bb94b70fb0adf4db40eec) Thanks [@jribbink](https://github.com/jribbink)! - Add `useFlowChainId` hook to the `@onflow/kit` package. + +### Patch Changes + +- [#2419](https://github.com/onflow/fcl-js/pull/2419) [`f498aa9fdb0739aef8905593bdbd05af9db3267a`](https://github.com/onflow/fcl-js/commit/f498aa9fdb0739aef8905593bdbd05af9db3267a) Thanks [@chasefleming](https://github.com/chasefleming)! - Update readme with `useFlowRevertibleRandom` hook + +- [#2417](https://github.com/onflow/fcl-js/pull/2417) [`8608416f4d26e40d3bfa464da7e988c8beb35336`](https://github.com/onflow/fcl-js/commit/8608416f4d26e40d3bfa464da7e988c8beb35336) Thanks [@jribbink](https://github.com/jribbink)! - Fix `useFlowRevertibleRandom` range + +- Updated dependencies [[`0b83658f62a428a70074d33875f264fbd48aff1e`](https://github.com/onflow/fcl-js/commit/0b83658f62a428a70074d33875f264fbd48aff1e), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab)]: + - @onflow/fcl@1.18.0 + ## 0.2.0-alpha.1 ### Minor Changes diff --git a/packages/kit/package.json b/packages/kit/package.json index 79b129e56..8c4611810 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/kit", - "version": "0.2.0-alpha.1", + "version": "0.2.0", "description": "React library for interacting with the Flow blockchain", "license": "Apache-2.0", "author": "Flow Foundation", @@ -30,7 +30,7 @@ "@babel/preset-react": "^7.26.3", "@babel/preset-typescript": "^7.25.7", "@onflow/fcl-bundle": "1.7.0", - "@onflow/typedefs": "^1.6.0-alpha.0", + "@onflow/typedefs": "^1.6.0", "@testing-library/dom": "^10.4.0", "@types/jest": "^29.5.13", "@types/react": "^19.0.10", @@ -49,7 +49,7 @@ "viem": "^2.28.1" }, "peerDependencies": { - "@onflow/fcl": ">=1.18.0-alpha.1", + "@onflow/fcl": ">=1.18.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index d35035fc5..50fc62b13 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -1,5 +1,34 @@ # @onflow/sdk +## 1.9.0 + +### Minor Changes + +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `subscribeRaw`. + + These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. + + The following topics are now available: + + - `blocks` + - `block_headers` + - `block_digests` + - `transaction_statues` + - `events` + - `account_statuses` + + Please see the [Flow Developer Documentation](https://developers.flow.com/clients/fcl-js/) for more details on how to use these new methods. + +- [#2352](https://github.com/onflow/fcl-js/pull/2352) [`4d3bb084c1442552d6a1de1f53435d1aa3f600b0`](https://github.com/onflow/fcl-js/commit/4d3bb084c1442552d6a1de1f53435d1aa3f600b0) Thanks [@mfbz](https://github.com/mfbz)! - Refactored onflow/sdk package to improve TypeScript support + +### Patch Changes + +- [#2434](https://github.com/onflow/fcl-js/pull/2434) [`3ac616d64c9abcda32f0c450119f22fa479d5e89`](https://github.com/onflow/fcl-js/commit/3ac616d64c9abcda32f0c450119f22fa479d5e89) Thanks [@mfbz](https://github.com/mfbz)! - Fixed fcl.mutate hanging + +- Updated dependencies [[`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`0b83658f62a428a70074d33875f264fbd48aff1e`](https://github.com/onflow/fcl-js/commit/0b83658f62a428a70074d33875f264fbd48aff1e), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab), [`694cd76807b7ca4441d1f8425ac4f8426cbc18fa`](https://github.com/onflow/fcl-js/commit/694cd76807b7ca4441d1f8425ac4f8426cbc18fa), [`4d3bb084c1442552d6a1de1f53435d1aa3f600b0`](https://github.com/onflow/fcl-js/commit/4d3bb084c1442552d6a1de1f53435d1aa3f600b0)]: + - @onflow/typedefs@1.6.0 + - @onflow/transport-http@1.13.0 + ## 1.9.0-alpha.1 ### Patch Changes @@ -10,7 +39,7 @@ ### Minor Changes -- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `rawSubscribe`. +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `subscribeRaw`. These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 6e2df7266..af5bb5af6 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/sdk", - "version": "1.9.0-alpha.1", + "version": "1.9.0", "description": "Flow SDK", "license": "Apache-2.0", "author": "Flow Foundation", @@ -43,8 +43,8 @@ "@babel/runtime": "^7.25.7", "@onflow/config": "1.5.2", "@onflow/rlp": "1.2.3", - "@onflow/transport-http": "1.13.0-alpha.0", - "@onflow/typedefs": "1.6.0-alpha.0", + "@onflow/transport-http": "1.13.0", + "@onflow/typedefs": "1.6.0", "@onflow/types": "1.4.1", "@onflow/util-actor": "1.3.4", "@onflow/util-address": "1.2.3", diff --git a/packages/transport-grpc/package.json b/packages/transport-grpc/package.json index ab482fd95..1bb6f07ac 100644 --- a/packages/transport-grpc/package.json +++ b/packages/transport-grpc/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.0", - "@onflow/sdk": "1.9.0-alpha.1", + "@onflow/sdk": "1.9.0", "jest": "^29.7.0" }, "source": "src/sdk-send-grpc.js", diff --git a/packages/transport-http/CHANGELOG.md b/packages/transport-http/CHANGELOG.md index bd7748e0e..047cdddf0 100644 --- a/packages/transport-http/CHANGELOG.md +++ b/packages/transport-http/CHANGELOG.md @@ -1,5 +1,24 @@ # @onflow/transport-http +## 1.13.0 + +### Minor Changes + +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add support for new WebSocket streaming methods. The following topics are now available: + + - `blocks` + - `block_headers` + - `block_digests` + - `transaction_statues` + - `events` + - `account_statuses` + +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Expose the `httpTransport` as a named export from `@onflow/transport-http` package. This follows the new object-style export for SDK transports and adds streaming support. + +### Patch Changes + +- [#2035](https://github.com/onflow/fcl-js/pull/2035) [`694cd76807b7ca4441d1f8425ac4f8426cbc18fa`](https://github.com/onflow/fcl-js/commit/694cd76807b7ca4441d1f8425ac4f8426cbc18fa) Thanks [@jribbink](https://github.com/jribbink)! - Add `parentVoterSignature` field to GetBlock request + ## 1.13.0-alpha.0 ### Minor Changes diff --git a/packages/transport-http/package.json b/packages/transport-http/package.json index 55a6b1c9b..d61fd54b3 100644 --- a/packages/transport-http/package.json +++ b/packages/transport-http/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/transport-http", - "version": "1.13.0-alpha.0", + "version": "1.13.0", "description": "Flow SDK HTTP Transport Module", "license": "Apache-2.0", "author": "Flow Foundation", @@ -15,7 +15,7 @@ "devDependencies": { "@onflow/fcl-bundle": "1.7.0", "@onflow/rlp": "1.2.3", - "@onflow/sdk": "1.9.0-alpha.1", + "@onflow/sdk": "1.9.0", "@onflow/types": "1.4.1", "jest": "^29.7.0", "jest-websocket-mock": "^2.5.0", diff --git a/packages/typedefs/CHANGELOG.md b/packages/typedefs/CHANGELOG.md index 14575b329..49b2cbf62 100644 --- a/packages/typedefs/CHANGELOG.md +++ b/packages/typedefs/CHANGELOG.md @@ -1,5 +1,13 @@ # @onflow/typedefs +## 1.6.0 + +### Minor Changes + +- [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add typedefs for streaming API + +- [#2352](https://github.com/onflow/fcl-js/pull/2352) [`4d3bb084c1442552d6a1de1f53435d1aa3f600b0`](https://github.com/onflow/fcl-js/commit/4d3bb084c1442552d6a1de1f53435d1aa3f600b0) Thanks [@mfbz](https://github.com/mfbz)! - Refactored onflow/sdk package to improve TypeScript support + ## 1.6.0-alpha.0 ### Minor Changes diff --git a/packages/typedefs/package.json b/packages/typedefs/package.json index efe6f57f3..79d2fe9ad 100644 --- a/packages/typedefs/package.json +++ b/packages/typedefs/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/typedefs", - "version": "1.6.0-alpha.0", + "version": "1.6.0", "description": "Flow JS Type Defs", "license": "Apache-2.0", "author": "Flow Foundation", From 9f9e18b5381d455ef4546b6521ea37c5eef3063c Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Thu, 22 May 2025 22:04:15 +0000 Subject: [PATCH 53/72] Fix `useFlowQuery` query key for script args (#2433) --- .changeset/afraid-avocados-beam.md | 5 +++ packages/kit/src/hooks/useFlowQuery.test.ts | 37 +++++++++++++++++++++ packages/kit/src/hooks/useFlowQuery.ts | 8 ++++- 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 .changeset/afraid-avocados-beam.md diff --git a/.changeset/afraid-avocados-beam.md b/.changeset/afraid-avocados-beam.md new file mode 100644 index 000000000..f64e7f7fc --- /dev/null +++ b/.changeset/afraid-avocados-beam.md @@ -0,0 +1,5 @@ +--- +"@onflow/kit": patch +--- + +Fix script args query key diff --git a/packages/kit/src/hooks/useFlowQuery.test.ts b/packages/kit/src/hooks/useFlowQuery.test.ts index 6c4dc8030..c4cbe9b03 100644 --- a/packages/kit/src/hooks/useFlowQuery.test.ts +++ b/packages/kit/src/hooks/useFlowQuery.test.ts @@ -146,4 +146,41 @@ describe("useFlowQuery", () => { args: argsFunction, }) }) + + test("detects args changes", async () => { + const cadenceScript = "access(all) fun main(a: Int): Int { return a }" + const initialResult = 7 + const updatedResult = 42 + const queryMock = jest.mocked(fcl.query) + queryMock.mockResolvedValueOnce(initialResult) + + const argsFunction = (arg: typeof fcl.arg, t: typeof fcl.t) => [ + arg(7, t.Int), + ] + + let hookResult: any + let hookRerender: any + + await act(async () => { + const {result, rerender} = renderHook(useFlowQuery, { + wrapper: FlowProvider, + initialProps: {cadence: cadenceScript, args: argsFunction}, + }) + hookResult = result + hookRerender = rerender + }) + + await waitFor(() => expect(hookResult.current.isLoading).toBe(false)) + expect(hookResult.current.data).toEqual(initialResult) + + queryMock.mockResolvedValueOnce(updatedResult) + await act(() => { + hookRerender({ + cadence: cadenceScript, + args: (arg: typeof fcl.arg, t: typeof fcl.t) => [arg(42, t.Int)], + }) + }) + + await waitFor(() => expect(hookResult.current.data).toEqual(updatedResult)) + }) }) diff --git a/packages/kit/src/hooks/useFlowQuery.ts b/packages/kit/src/hooks/useFlowQuery.ts index 0b715cfdc..42f7b22ca 100644 --- a/packages/kit/src/hooks/useFlowQuery.ts +++ b/packages/kit/src/hooks/useFlowQuery.ts @@ -32,9 +32,15 @@ export function useFlowQuery({ return fcl.query({cadence, args}) }, [cadence, args]) + // Encode the arguments to a JSON-CDC object so they can be deterministically + // serialized and used as the query key. + const encodedArgs = args?.(fcl.arg, fcl.t)?.map((x: any) => + x.xform.asArgument(x.value) + ) + return useQuery( { - queryKey: ["flowQuery", cadence, args], + queryKey: ["flowQuery", cadence, encodedArgs], queryFn: fetchQuery, enabled: queryOptions.enabled ?? true, ...queryOptions, From c4f1a896f31688c03153d6c7c37d9196748519bb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 16:06:51 -0700 Subject: [PATCH 54/72] Version Packages (#2469) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/afraid-avocados-beam.md | 5 ----- packages/kit/CHANGELOG.md | 6 ++++++ packages/kit/package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/afraid-avocados-beam.md diff --git a/.changeset/afraid-avocados-beam.md b/.changeset/afraid-avocados-beam.md deleted file mode 100644 index f64e7f7fc..000000000 --- a/.changeset/afraid-avocados-beam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/kit": patch ---- - -Fix script args query key diff --git a/packages/kit/CHANGELOG.md b/packages/kit/CHANGELOG.md index aeb874cfa..ca3460549 100644 --- a/packages/kit/CHANGELOG.md +++ b/packages/kit/CHANGELOG.md @@ -1,5 +1,11 @@ # @onflow/kit +## 0.2.1 + +### Patch Changes + +- [#2433](https://github.com/onflow/fcl-js/pull/2433) [`9f9e18b5381d455ef4546b6521ea37c5eef3063c`](https://github.com/onflow/fcl-js/commit/9f9e18b5381d455ef4546b6521ea37c5eef3063c) Thanks [@jribbink](https://github.com/jribbink)! - Fix script args query key + ## 0.2.0 ### Minor Changes diff --git a/packages/kit/package.json b/packages/kit/package.json index 8c4611810..ecfd5c2f0 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/kit", - "version": "0.2.0", + "version": "0.2.1", "description": "React library for interacting with the Flow blockchain", "license": "Apache-2.0", "author": "Flow Foundation", From 99510059485ffb2d741407a573f3be076c77e044 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Fri, 23 May 2025 19:11:59 +0000 Subject: [PATCH 55/72] Add `useCrossVmTokenBalance` hook (#2398) --- .changeset/cuddly-impalas-drop.md | 5 + package-lock.json | 45 ++-- packages/kit/README.md | 1 + packages/kit/jest.config.js | 5 + packages/kit/package.json | 2 +- packages/kit/src/constants.ts | 18 ++ .../src/hooks/useCrossVmTokenBalance.test.ts | 123 ++++++++++ .../kit/src/hooks/useCrossVmTokenBalance.ts | 231 ++++++++++++++++++ packages/kit/src/jest-setup.ts | 3 + 9 files changed, 410 insertions(+), 23 deletions(-) create mode 100644 .changeset/cuddly-impalas-drop.md create mode 100644 packages/kit/src/constants.ts create mode 100644 packages/kit/src/hooks/useCrossVmTokenBalance.test.ts create mode 100644 packages/kit/src/hooks/useCrossVmTokenBalance.ts create mode 100644 packages/kit/src/jest-setup.ts diff --git a/.changeset/cuddly-impalas-drop.md b/.changeset/cuddly-impalas-drop.md new file mode 100644 index 000000000..6621ec2af --- /dev/null +++ b/.changeset/cuddly-impalas-drop.md @@ -0,0 +1,5 @@ +--- +"@onflow/kit": minor +--- + +Add `useCrossVmTokenBalance` hook to get full token balance across both Cadence and EVM accounts \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 0dfa9ceb7..a30ebcf76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10057,9 +10057,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.40.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.2.tgz", - "integrity": "sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.0.tgz", + "integrity": "sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==", "cpu": [ "x64" ], @@ -20539,8 +20539,6 @@ }, "node_modules/jest-websocket-mock": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/jest-websocket-mock/-/jest-websocket-mock-2.5.0.tgz", - "integrity": "sha512-a+UJGfowNIWvtIKIQBHoEWIUqRxxQHFx4CXT+R5KxxKBtEQ5rS3pPOV/5299sHzqbmeCzxxY5qE4+yfXePePig==", "dev": true, "license": "MIT", "dependencies": { @@ -23318,8 +23316,6 @@ }, "node_modules/mock-socket": { "version": "9.3.1", - "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz", - "integrity": "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==", "dev": true, "license": "MIT", "engines": { @@ -31496,7 +31492,7 @@ "@babel/runtime": "^7.25.7", "@tanstack/react-query": "^5.67.3", "@testing-library/react": "^16.2.0", - "viem": "^2.28.1" + "viem": "^2.29.2" }, "devDependencies": { "@babel/preset-env": "^7.26.9", @@ -31523,8 +31519,6 @@ }, "packages/kit/node_modules/@noble/curves": { "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", - "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", "license": "MIT", "dependencies": { "@noble/hashes": "1.7.2" @@ -31538,8 +31532,6 @@ }, "packages/kit/node_modules/@noble/hashes": { "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", - "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", "license": "MIT", "engines": { "node": "^14.21.3 || >=16" @@ -31550,14 +31542,25 @@ }, "packages/kit/node_modules/eventemitter3": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "license": "MIT" }, + "packages/kit/node_modules/isows": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", + "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, "packages/kit/node_modules/ox": { "version": "0.6.9", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", - "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", "funding": [ { "type": "github", @@ -31584,9 +31587,9 @@ } }, "packages/kit/node_modules/viem": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.29.1.tgz", - "integrity": "sha512-mhLn0vDdsxZ4taB7XYgnIVNvXASm60KyPAkvw4k8uNCQ+HLH+5jUgKvLg4AP3y6VJxsgiVPwqUt0dJANDF5DZA==", + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.30.0.tgz", + "integrity": "sha512-hvO4l5JIOnYPL8imULoFQiVTSkebIqzGHmIfsdMfIHpAgBaCx8rJJH9cXAxQeWCqsFuTmjEj1cX912N7HSCgpQ==", "funding": [ { "type": "github", @@ -31600,7 +31603,7 @@ "@scure/bip32": "1.6.2", "@scure/bip39": "1.5.4", "abitype": "1.0.8", - "isows": "1.0.6", + "isows": "1.0.7", "ox": "0.6.9", "ws": "8.18.1" }, @@ -31615,8 +31618,6 @@ }, "packages/kit/node_modules/ws": { "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", "license": "MIT", "engines": { "node": ">=10.0.0" diff --git a/packages/kit/README.md b/packages/kit/README.md index 1440cdbce..60311b90a 100644 --- a/packages/kit/README.md +++ b/packages/kit/README.md @@ -42,6 +42,7 @@ import flowJson from "../flow.json" - `useFlowRevertibleRandom` - `useFlowMutate` - `useFlowTransaction` +- `useCrossVmTokenBalance` ## 📚 Full Documentation diff --git a/packages/kit/jest.config.js b/packages/kit/jest.config.js index cc52f8b4d..342d2c615 100644 --- a/packages/kit/jest.config.js +++ b/packages/kit/jest.config.js @@ -4,4 +4,9 @@ module.exports = { "^@walletconnect": "/src/__mocks__/noop.ts", "^preact": "/src/__mocks__/noop.ts", }, + // This is a workaround with Jest v29 issues related to BigInt serialization + // It can be removed once Jest v30 is released and upgraded + // https://github.com/jestjs/jest/issues/11617 + workerThreads: true, + setupFiles: ["/src/jest-setup.ts"], } diff --git a/packages/kit/package.json b/packages/kit/package.json index ecfd5c2f0..616d4dde2 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -46,7 +46,7 @@ "@babel/runtime": "^7.25.7", "@tanstack/react-query": "^5.67.3", "@testing-library/react": "^16.2.0", - "viem": "^2.28.1" + "viem": "^2.29.2" }, "peerDependencies": { "@onflow/fcl": ">=1.18.0", diff --git a/packages/kit/src/constants.ts b/packages/kit/src/constants.ts new file mode 100644 index 000000000..35e4c6f2b --- /dev/null +++ b/packages/kit/src/constants.ts @@ -0,0 +1,18 @@ +export const CONTRACT_ADDRESSES = { + testnet: { + EVM: "0x8c5303eaa26202d6", + FungibleToken: "0x9a0766d93b6608b7", + FlowEVMBridgeUtils: "0xdfc20aee650fcbdf", + FlowEVMBridgeConfig: "0xdfc20aee650fcbdf", + FungibleTokenMetadataViews: "0x9a0766d93b6608b7", + }, + mainnet: { + EVM: "0xe467b9dd11fa00df", + FungibleToken: "0xf233dcee88fe0abe", + FlowEVMBridgeUtils: "0x1e4aa0b87d10b141", + FlowEVMBridgeConfig: "0x1e4aa0b87d10b141", + FungibleTokenMetadataViews: "0xf233dcee88fe0abe", + }, +} + +export const CADENCE_UFIX64_PRECISION = 8 diff --git a/packages/kit/src/hooks/useCrossVmTokenBalance.test.ts b/packages/kit/src/hooks/useCrossVmTokenBalance.test.ts new file mode 100644 index 000000000..caf1a6a9d --- /dev/null +++ b/packages/kit/src/hooks/useCrossVmTokenBalance.test.ts @@ -0,0 +1,123 @@ +import {FlowProvider} from "../provider/FlowProvider" +import {useFlowChainId} from "./useFlowChainId" +import {useFlowQuery} from "./useFlowQuery" +import {useCrossVmTokenBalance} from "./useCrossVmTokenBalance" +import {act, renderHook, waitFor} from "@testing-library/react" + +jest.mock("@onflow/fcl", () => require("../__mocks__/fcl").default) +jest.mock("./useFlowQuery") +jest.mock("./useFlowChainId") + +describe("useCrossVmTokenBalance", () => { + beforeEach(() => { + jest.clearAllMocks() + }) + + test("should return null when data is undefined", async () => { + const mockQueryResult = { + data: undefined, + isLoading: false, + isError: false, + error: null, + } as unknown as ReturnType + + jest.mocked(useFlowQuery).mockReturnValue(mockQueryResult) + jest.mocked(useFlowChainId).mockReturnValue({ + data: "testnet", + isLoading: false, + isError: false, + error: null, + isSuccess: true, + } as unknown as ReturnType) + + let result: ReturnType> + act(() => { + result = renderHook(useCrossVmTokenBalance, { + wrapper: FlowProvider, + initialProps: { + contractIdentifier: "A.1234.Token", + owner: "0x5678", + }, + }) + }) + + await waitFor(() => expect(result.result.current).toBeDefined()) + + expect(jest.mocked(useFlowQuery)).toHaveBeenCalledWith( + expect.objectContaining({ + cadence: expect.any(String), + args: expect.any(Function), + query: { + enabled: true, + }, + }) + ) + + expect(result!.result.current).toEqual({ + ...mockQueryResult, + data: null, + }) + }) + + test("should return formatted balance when data is defined", async () => { + const mockQueryResult = { + data: ["4", "10.001", "200001"], + isLoading: false, + isError: false, + error: null, + } as unknown as ReturnType + + jest.mocked(useFlowQuery).mockReturnValue(mockQueryResult) + jest.mocked(useFlowChainId).mockReturnValue({ + data: "testnet", + isLoading: false, + isError: false, + error: null, + isSuccess: true, + } as unknown as ReturnType) + + let result: ReturnType> + act(() => { + result = renderHook(useCrossVmTokenBalance, { + wrapper: FlowProvider, + initialProps: { + contractIdentifier: "A.1234.Token", + owner: "0x5678", + }, + }) + }) + + await waitFor(() => expect(result.result.current).toBeDefined()) + + expect(jest.mocked(useFlowQuery)).toHaveBeenCalledWith( + expect.objectContaining({ + cadence: expect.any(String), + args: expect.any(Function), + query: { + enabled: true, + }, + }) + ) + + expect(result!.result.current).toEqual({ + ...mockQueryResult, + data: { + cadence: { + formatted: "10.001", + value: BigInt("1000100000"), + precision: 8, + }, + evm: { + formatted: "20.0001", + value: BigInt("200001"), + precision: 4, + }, + total: { + formatted: "30.0011", + value: BigInt("3000110000"), + precision: 8, + }, + }, + }) + }) +}) diff --git a/packages/kit/src/hooks/useCrossVmTokenBalance.ts b/packages/kit/src/hooks/useCrossVmTokenBalance.ts new file mode 100644 index 000000000..df60461b2 --- /dev/null +++ b/packages/kit/src/hooks/useCrossVmTokenBalance.ts @@ -0,0 +1,231 @@ +import {UseQueryOptions, UseQueryResult} from "@tanstack/react-query" +import {useFlowQuery} from "./useFlowQuery" +import {CADENCE_UFIX64_PRECISION, CONTRACT_ADDRESSES} from "../constants" +import {useFlowChainId} from "./useFlowChainId" +import {parseUnits, formatUnits} from "viem/utils" + +interface UseCrossVmTokenBalanceArgs { + owner?: string + erc20AddressHexArg?: string + contractIdentifier?: `A.${string}.${string}` + query?: Omit, "queryKey" | "queryFn"> +} + +interface TokenBalance { + value: string + formatted: string + precision: number +} + +interface UseCrossVmTokenBalanceData { + cadence: TokenBalance + evm: TokenBalance + combined: TokenBalance +} + +const getCrossVmTokenBalance = (network: "testnet" | "mainnet") => ` +import EVM from ${CONTRACT_ADDRESSES[network].EVM} +import FungibleToken from ${CONTRACT_ADDRESSES[network].FungibleToken} +import FlowEVMBridgeUtils from ${CONTRACT_ADDRESSES[network].FlowEVMBridgeUtils} +import FlowEVMBridgeConfig from ${CONTRACT_ADDRESSES[network].FlowEVMBridgeConfig} +import FungibleTokenMetadataViews from ${CONTRACT_ADDRESSES[network].FungibleTokenMetadataViews} + +/// Returns the balance of the owner of a given Fungible Token +/// from their Cadence account and their COA +/// Accepts multiple optional arguments, so the caller can query +/// the token by its EVM ERC20 address or by its Cadence contract address and name +/// +/// @param owner: The Flow address of the owner +/// @param contractAddressArg: The optional address of the FT contract in Cadence +/// @param contractNameArg: The optional name of the FT contract in Cadence +/// @param erc20AddressHex: The optional ERC20 address of the FT to query +/// +/// @return An array that contains the balance information for the user's accounts +/// in this order: +/// decimals (UInt256), cadence Balance (UFix64), EVM Balance (UInt256), Total Balance (UInt256) +/// + +access(all) fun main( + owner: Address, + vaultIdentifier: String?, + erc20AddressHexArg: String? +): [AnyStruct] { + pre { + vaultIdentifier == nil ? erc20AddressHexArg != nil : true: + "If the Cadence contract information is not provided, the ERC20 contract address must be provided." + } + + var typeIdentifier: String = "" + var compType: Type? = nil + var contractAddress: Address? = nil + var contractName: String? = nil + var tokenEVMAddress: String? = nil + var cadenceBalance: UFix64 = 0.0 + var coaBalance: UInt256 = 0 + var decimals: UInt8 = 0 + + // If the caller provided the Cadence information, + // Construct the composite type + if vaultIdentifier != nil { + typeIdentifier = vaultIdentifier! + compType = CompositeType(typeIdentifier) + ?? panic("Could not construct Cadence type with \(typeIdentifier)") + + // Get the EVM address of the bridged version of the Cadence FT contract + if let evmAddress = FlowEVMBridgeConfig.getEVMAddressAssociated(with: compType!) { + tokenEVMAddress = evmAddress.toString() + } + } else { + // If the caller provided the EVM information, + // get the Cadence type from the bridge + // If getting the Cadence type doesn't work, then we'll just return the EVM balance + tokenEVMAddress = erc20AddressHexArg! + let address = EVM.addressFromString(tokenEVMAddress!) + compType = FlowEVMBridgeConfig.getTypeAssociated(with: address) + } + + // Parse the FT identifier into its components if necessary + if compType != nil { + contractAddress = FlowEVMBridgeUtils.getContractAddress(fromType: compType!) + contractName = FlowEVMBridgeUtils.getContractName(fromType: compType!) + } + + if let address = contractAddress { + // Borrow a reference to the FT contract + let resolverRef = getAccount(address) + .contracts.borrow<&{FungibleToken}>(name: contractName!) + ?? panic("Could not borrow FungibleToken reference to the contract. Make sure the provided contract name (" + .concat(contractName!).concat(") and address (").concat(address.toString()).concat(") are correct!")) + + // Use that reference to retrieve the FTView + let vaultData = resolverRef.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTVaultData? + ?? panic("Could not resolve FTVaultData view. The ".concat(contractName!) + .concat(" contract needs to implement the FTVaultData Metadata view in order to execute this transaction.")) + + // Get the Cadence balance of the token + cadenceBalance = getAccount(owner).capabilities.borrow<&{FungibleToken.Balance}>( + vaultData.metadataPath + )?.balance + ?? 0.0 + } + + // Get the COA from the owner's account + if let coa = getAuthAccount(owner) + .storage.borrow( + from: /storage/evm + ) + { + if let erc20Address = tokenEVMAddress { + // Get the COA address + let coaAddress = coa.address().toString() + + // Get the ERC20 balance of the COA + coaBalance = FlowEVMBridgeUtils.balanceOf( + owner: EVM.addressFromString(coaAddress), + evmContractAddress: EVM.addressFromString(erc20Address) + ) + + // Get the token decimals of the ERC20 contract + decimals = FlowEVMBridgeUtils.getTokenDecimals( + evmContractAddress: EVM.addressFromString(erc20Address) + ) + } + } + + let balances = [decimals, cadenceBalance, coaBalance] + + return balances +} +` + +/** + * Returns the balance of the owner of a given Fungible Token across both Cadence and EVM accounts. + * @param param0 + * @returns + */ +export function useCrossVmTokenBalance(params: UseCrossVmTokenBalanceArgs) { + const chainIdResult = useFlowChainId() + const queryResult = useFlowQuery({ + cadence: chainIdResult.data + ? getCrossVmTokenBalance(chainIdResult.data as "testnet" | "mainnet") + : "", + args: (arg, t) => [ + params.owner ? arg(params.owner, t.Address) : null, + arg( + "contractIdentifier" in params && `${params.contractIdentifier}.Vault` + ? params.contractIdentifier + : null, + t.Optional(t.String) + ), + arg( + "erc20AddressHexArg" in params && params.erc20AddressHexArg + ? params.erc20AddressHexArg + : null, + t.Optional(t.String) + ), + ], + query: { + ...params.query, + enabled: + (params.query?.enabled ?? true) && + !!chainIdResult.data && + !!params.owner && + (!!params.contractIdentifier || !!params.erc20AddressHexArg), + }, + }) + + if (chainIdResult.isError) { + return chainIdResult + } + + const data = queryResult.data as [string, string, string, string] | undefined + if (!data) { + return { + ...queryResult, + data: null, + } as UseQueryResult + } + + const [evmDecimals, cadenceBalance, evmBalance] = data + + // Convert the values to the max precision between Cadence and EVM + // to avoid precision loss when summing the two balances + const totalPrecision = Math.max(CADENCE_UFIX64_PRECISION, Number(evmDecimals)) + const totalPrecisionCadenceBalance = parseUnits( + cadenceBalance, + totalPrecision + ) + const totalPrecisionEvmBalance = parseUnits( + formatUnits(BigInt(evmBalance), Number(evmDecimals)), + totalPrecision + ) + + return { + ...queryResult, + data: data + ? { + cadence: { + formatted: formatUnits( + parseUnits(cadenceBalance, CADENCE_UFIX64_PRECISION), + CADENCE_UFIX64_PRECISION + ), + value: parseUnits(cadenceBalance, CADENCE_UFIX64_PRECISION), + precision: CADENCE_UFIX64_PRECISION, + }, + evm: { + formatted: formatUnits(BigInt(evmBalance), Number(evmDecimals)), + precision: Number(evmDecimals), + value: BigInt(evmBalance), + }, + total: { + formatted: formatUnits( + totalPrecisionCadenceBalance + totalPrecisionEvmBalance, + totalPrecision + ), + value: totalPrecisionCadenceBalance + totalPrecisionEvmBalance, + precision: totalPrecision, + }, + } + : null, + } as UseQueryResult +} diff --git a/packages/kit/src/jest-setup.ts b/packages/kit/src/jest-setup.ts new file mode 100644 index 000000000..e58025af3 --- /dev/null +++ b/packages/kit/src/jest-setup.ts @@ -0,0 +1,3 @@ +import {TextEncoder, TextDecoder} from "util" + +Object.assign(global, {TextDecoder, TextEncoder}) From 3f5d5037882d2da03713ece0ff4f6b7e9d3693b2 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Wed, 4 Jun 2025 18:36:19 +0200 Subject: [PATCH 56/72] Switch cross VM balance to vault identifier (#2486) --- .changeset/twenty-teachers-smell.md | 5 +++++ packages/kit/src/hooks/useCrossVmTokenBalance.test.ts | 4 ++-- packages/kit/src/hooks/useCrossVmTokenBalance.ts | 10 +++++----- 3 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 .changeset/twenty-teachers-smell.md diff --git a/.changeset/twenty-teachers-smell.md b/.changeset/twenty-teachers-smell.md new file mode 100644 index 000000000..9b96cc3bf --- /dev/null +++ b/.changeset/twenty-teachers-smell.md @@ -0,0 +1,5 @@ +--- +"@onflow/kit": patch +--- + +Switch `contractIdentifier` to `vaultIdentifier` in `useCrossVmTokenBalance` hook diff --git a/packages/kit/src/hooks/useCrossVmTokenBalance.test.ts b/packages/kit/src/hooks/useCrossVmTokenBalance.test.ts index caf1a6a9d..9a05a7327 100644 --- a/packages/kit/src/hooks/useCrossVmTokenBalance.test.ts +++ b/packages/kit/src/hooks/useCrossVmTokenBalance.test.ts @@ -35,7 +35,7 @@ describe("useCrossVmTokenBalance", () => { result = renderHook(useCrossVmTokenBalance, { wrapper: FlowProvider, initialProps: { - contractIdentifier: "A.1234.Token", + vaultIdentifier: "A.1234.Token.Vault", owner: "0x5678", }, }) @@ -81,7 +81,7 @@ describe("useCrossVmTokenBalance", () => { result = renderHook(useCrossVmTokenBalance, { wrapper: FlowProvider, initialProps: { - contractIdentifier: "A.1234.Token", + vaultIdentifier: "A.1234.Token.Vault", owner: "0x5678", }, }) diff --git a/packages/kit/src/hooks/useCrossVmTokenBalance.ts b/packages/kit/src/hooks/useCrossVmTokenBalance.ts index df60461b2..6eb652854 100644 --- a/packages/kit/src/hooks/useCrossVmTokenBalance.ts +++ b/packages/kit/src/hooks/useCrossVmTokenBalance.ts @@ -7,12 +7,12 @@ import {parseUnits, formatUnits} from "viem/utils" interface UseCrossVmTokenBalanceArgs { owner?: string erc20AddressHexArg?: string - contractIdentifier?: `A.${string}.${string}` + vaultIdentifier?: string query?: Omit, "queryKey" | "queryFn"> } interface TokenBalance { - value: string + value: bigint formatted: string precision: number } @@ -152,8 +152,8 @@ export function useCrossVmTokenBalance(params: UseCrossVmTokenBalanceArgs) { args: (arg, t) => [ params.owner ? arg(params.owner, t.Address) : null, arg( - "contractIdentifier" in params && `${params.contractIdentifier}.Vault` - ? params.contractIdentifier + "vaultIdentifier" in params && params.vaultIdentifier + ? params.vaultIdentifier : null, t.Optional(t.String) ), @@ -170,7 +170,7 @@ export function useCrossVmTokenBalance(params: UseCrossVmTokenBalanceArgs) { (params.query?.enabled ?? true) && !!chainIdResult.data && !!params.owner && - (!!params.contractIdentifier || !!params.erc20AddressHexArg), + (!!params.vaultIdentifier || !!params.erc20AddressHexArg), }, }) From e9427727c50a018458d83b4f284e2de7a63a2713 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 4 Jun 2025 09:42:57 -0700 Subject: [PATCH 57/72] Version Packages (#2471) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/cuddly-impalas-drop.md | 5 ----- .changeset/twenty-teachers-smell.md | 5 ----- packages/kit/CHANGELOG.md | 10 ++++++++++ packages/kit/package.json | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) delete mode 100644 .changeset/cuddly-impalas-drop.md delete mode 100644 .changeset/twenty-teachers-smell.md diff --git a/.changeset/cuddly-impalas-drop.md b/.changeset/cuddly-impalas-drop.md deleted file mode 100644 index 6621ec2af..000000000 --- a/.changeset/cuddly-impalas-drop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/kit": minor ---- - -Add `useCrossVmTokenBalance` hook to get full token balance across both Cadence and EVM accounts \ No newline at end of file diff --git a/.changeset/twenty-teachers-smell.md b/.changeset/twenty-teachers-smell.md deleted file mode 100644 index 9b96cc3bf..000000000 --- a/.changeset/twenty-teachers-smell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/kit": patch ---- - -Switch `contractIdentifier` to `vaultIdentifier` in `useCrossVmTokenBalance` hook diff --git a/packages/kit/CHANGELOG.md b/packages/kit/CHANGELOG.md index ca3460549..3af70a29e 100644 --- a/packages/kit/CHANGELOG.md +++ b/packages/kit/CHANGELOG.md @@ -1,5 +1,15 @@ # @onflow/kit +## 0.3.0 + +### Minor Changes + +- [#2398](https://github.com/onflow/fcl-js/pull/2398) [`99510059485ffb2d741407a573f3be076c77e044`](https://github.com/onflow/fcl-js/commit/99510059485ffb2d741407a573f3be076c77e044) Thanks [@jribbink](https://github.com/jribbink)! - Add `useCrossVmTokenBalance` hook to get full token balance across both Cadence and EVM accounts + +### Patch Changes + +- [#2486](https://github.com/onflow/fcl-js/pull/2486) [`3f5d5037882d2da03713ece0ff4f6b7e9d3693b2`](https://github.com/onflow/fcl-js/commit/3f5d5037882d2da03713ece0ff4f6b7e9d3693b2) Thanks [@jribbink](https://github.com/jribbink)! - Switch `contractIdentifier` to `vaultIdentifier` in `useCrossVmTokenBalance` hook + ## 0.2.1 ### Patch Changes diff --git a/packages/kit/package.json b/packages/kit/package.json index 616d4dde2..9cfce16a6 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/kit", - "version": "0.2.1", + "version": "0.3.0", "description": "React library for interacting with the Flow blockchain", "license": "Apache-2.0", "author": "Flow Foundation", From ff07e0ea38845f188f0bbbcb9a365cad96cfb8b7 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Fri, 6 Jun 2025 08:41:14 -0700 Subject: [PATCH 58/72] Export `useCrossVmTokenBalance` hook (#2491) --- .changeset/new-turtles-pretend.md | 5 +++++ package-lock.json | 2 +- packages/kit/src/constants.ts | 2 ++ packages/kit/src/hooks/index.ts | 1 + .../kit/src/hooks/useCrossVmTokenBalance.ts | 17 ++++++++++++----- 5 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 .changeset/new-turtles-pretend.md diff --git a/.changeset/new-turtles-pretend.md b/.changeset/new-turtles-pretend.md new file mode 100644 index 000000000..971ebcab8 --- /dev/null +++ b/.changeset/new-turtles-pretend.md @@ -0,0 +1,5 @@ +--- +"@onflow/kit": patch +--- + +Export `useCrossVmTokenBalance` hook diff --git a/package-lock.json b/package-lock.json index a30ebcf76..0a5e65180 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31486,7 +31486,7 @@ }, "packages/kit": { "name": "@onflow/kit", - "version": "0.2.0", + "version": "0.3.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", diff --git a/packages/kit/src/constants.ts b/packages/kit/src/constants.ts index 35e4c6f2b..54243f06f 100644 --- a/packages/kit/src/constants.ts +++ b/packages/kit/src/constants.ts @@ -2,6 +2,7 @@ export const CONTRACT_ADDRESSES = { testnet: { EVM: "0x8c5303eaa26202d6", FungibleToken: "0x9a0766d93b6608b7", + FlowToken: "0x7e60df042a9c0868", FlowEVMBridgeUtils: "0xdfc20aee650fcbdf", FlowEVMBridgeConfig: "0xdfc20aee650fcbdf", FungibleTokenMetadataViews: "0x9a0766d93b6608b7", @@ -9,6 +10,7 @@ export const CONTRACT_ADDRESSES = { mainnet: { EVM: "0xe467b9dd11fa00df", FungibleToken: "0xf233dcee88fe0abe", + FlowToken: "0x1654653399040a61", FlowEVMBridgeUtils: "0x1e4aa0b87d10b141", FlowEVMBridgeConfig: "0x1e4aa0b87d10b141", FungibleTokenMetadataViews: "0xf233dcee88fe0abe", diff --git a/packages/kit/src/hooks/index.ts b/packages/kit/src/hooks/index.ts index 597e5ddca..d7c52adf9 100644 --- a/packages/kit/src/hooks/index.ts +++ b/packages/kit/src/hooks/index.ts @@ -7,4 +7,5 @@ export {useFlowMutate} from "./useFlowMutate" export {useFlowQuery} from "./useFlowQuery" export {useFlowRevertibleRandom} from "./useFlowRevertibleRandom" export {useCrossVmBatchTransaction} from "./useCrossVmBatchTransaction" +export {useCrossVmTokenBalance} from "./useCrossVmTokenBalance" export {useFlowTransactionStatus} from "./useFlowTransactionStatus" diff --git a/packages/kit/src/hooks/useCrossVmTokenBalance.ts b/packages/kit/src/hooks/useCrossVmTokenBalance.ts index 6eb652854..457f54f4e 100644 --- a/packages/kit/src/hooks/useCrossVmTokenBalance.ts +++ b/packages/kit/src/hooks/useCrossVmTokenBalance.ts @@ -6,7 +6,7 @@ import {parseUnits, formatUnits} from "viem/utils" interface UseCrossVmTokenBalanceArgs { owner?: string - erc20AddressHexArg?: string + erc20Address?: string vaultIdentifier?: string query?: Omit, "queryKey" | "queryFn"> } @@ -25,6 +25,7 @@ interface UseCrossVmTokenBalanceData { const getCrossVmTokenBalance = (network: "testnet" | "mainnet") => ` import EVM from ${CONTRACT_ADDRESSES[network].EVM} +import FlowToken from ${CONTRACT_ADDRESSES[network].FlowToken} import FungibleToken from ${CONTRACT_ADDRESSES[network].FungibleToken} import FlowEVMBridgeUtils from ${CONTRACT_ADDRESSES[network].FlowEVMBridgeUtils} import FlowEVMBridgeConfig from ${CONTRACT_ADDRESSES[network].FlowEVMBridgeConfig} @@ -130,6 +131,10 @@ access(all) fun main( evmContractAddress: EVM.addressFromString(erc20Address) ) } + + if compType == Type<@FlowToken.Vault>() { + coaBalance = coaBalance! + UInt256(coa.address().balance().inAttoFLOW()) + } } let balances = [decimals, cadenceBalance, coaBalance] @@ -150,7 +155,9 @@ export function useCrossVmTokenBalance(params: UseCrossVmTokenBalanceArgs) { ? getCrossVmTokenBalance(chainIdResult.data as "testnet" | "mainnet") : "", args: (arg, t) => [ - params.owner ? arg(params.owner, t.Address) : null, + params.owner + ? arg(params.owner, t.Address) + : arg(null, t.Optional(t.Address)), arg( "vaultIdentifier" in params && params.vaultIdentifier ? params.vaultIdentifier @@ -158,8 +165,8 @@ export function useCrossVmTokenBalance(params: UseCrossVmTokenBalanceArgs) { t.Optional(t.String) ), arg( - "erc20AddressHexArg" in params && params.erc20AddressHexArg - ? params.erc20AddressHexArg + "erc20Address" in params && params.erc20Address + ? params.erc20Address : null, t.Optional(t.String) ), @@ -170,7 +177,7 @@ export function useCrossVmTokenBalance(params: UseCrossVmTokenBalanceArgs) { (params.query?.enabled ?? true) && !!chainIdResult.data && !!params.owner && - (!!params.vaultIdentifier || !!params.erc20AddressHexArg), + (!!params.vaultIdentifier || !!params.erc20Address), }, }) From ad50c627b31e38fdb39ec3a5c4bb4cbf392347f4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 6 Jun 2025 08:48:48 -0700 Subject: [PATCH 59/72] Version Packages (#2494) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/new-turtles-pretend.md | 5 ----- packages/kit/CHANGELOG.md | 6 ++++++ packages/kit/package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/new-turtles-pretend.md diff --git a/.changeset/new-turtles-pretend.md b/.changeset/new-turtles-pretend.md deleted file mode 100644 index 971ebcab8..000000000 --- a/.changeset/new-turtles-pretend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/kit": patch ---- - -Export `useCrossVmTokenBalance` hook diff --git a/packages/kit/CHANGELOG.md b/packages/kit/CHANGELOG.md index 3af70a29e..b9dfa0516 100644 --- a/packages/kit/CHANGELOG.md +++ b/packages/kit/CHANGELOG.md @@ -1,5 +1,11 @@ # @onflow/kit +## 0.3.1 + +### Patch Changes + +- [#2491](https://github.com/onflow/fcl-js/pull/2491) [`ff07e0ea38845f188f0bbbcb9a365cad96cfb8b7`](https://github.com/onflow/fcl-js/commit/ff07e0ea38845f188f0bbbcb9a365cad96cfb8b7) Thanks [@jribbink](https://github.com/jribbink)! - Export `useCrossVmTokenBalance` hook + ## 0.3.0 ### Minor Changes diff --git a/packages/kit/package.json b/packages/kit/package.json index 9cfce16a6..1bd778ecd 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/kit", - "version": "0.3.0", + "version": "0.3.1", "description": "React library for interacting with the Flow blockchain", "license": "Apache-2.0", "author": "Flow Foundation", From d7b673e2ea97f6ab5ec2b81d2186b3e9799460cf Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Fri, 6 Jun 2025 14:58:14 -0700 Subject: [PATCH 60/72] Add `useCrossVmSpendNft` hook (#2460) --- .changeset/tiny-rabbits-try.md | 5 + packages/kit/src/constants.ts | 12 + packages/kit/src/hooks/index.ts | 1 + .../hooks/useCrossVmBatchTransaction.test.ts | 12 +- .../src/hooks/useCrossVmBatchTransaction.ts | 42 +-- .../kit/src/hooks/useCrossVmSpendNft.test.ts | 171 +++++++++++ packages/kit/src/hooks/useCrossVmSpendNft.ts | 281 ++++++++++++++++++ 7 files changed, 501 insertions(+), 23 deletions(-) create mode 100644 .changeset/tiny-rabbits-try.md create mode 100644 packages/kit/src/hooks/useCrossVmSpendNft.test.ts create mode 100644 packages/kit/src/hooks/useCrossVmSpendNft.ts diff --git a/.changeset/tiny-rabbits-try.md b/.changeset/tiny-rabbits-try.md new file mode 100644 index 000000000..81e4e86d8 --- /dev/null +++ b/.changeset/tiny-rabbits-try.md @@ -0,0 +1,5 @@ +--- +"@onflow/kit": minor +--- + +Add `useCrossVmSpendNft` hook diff --git a/packages/kit/src/constants.ts b/packages/kit/src/constants.ts index 54243f06f..4dfcb4eee 100644 --- a/packages/kit/src/constants.ts +++ b/packages/kit/src/constants.ts @@ -2,7 +2,12 @@ export const CONTRACT_ADDRESSES = { testnet: { EVM: "0x8c5303eaa26202d6", FungibleToken: "0x9a0766d93b6608b7", + NonFungibleToken: "0x631e88ae7f1d7c20", + ViewResolver: "0x631e88ae7f1d7c20", + MetadataViews: "0x631e88ae7f1d7c20", FlowToken: "0x7e60df042a9c0868", + ScopedFTProviders: "0xdfc20aee650fcbdf", + FlowEVMBridge: "0xdfc20aee650fcbdf", FlowEVMBridgeUtils: "0xdfc20aee650fcbdf", FlowEVMBridgeConfig: "0xdfc20aee650fcbdf", FungibleTokenMetadataViews: "0x9a0766d93b6608b7", @@ -10,7 +15,12 @@ export const CONTRACT_ADDRESSES = { mainnet: { EVM: "0xe467b9dd11fa00df", FungibleToken: "0xf233dcee88fe0abe", + NonFungibleToken: "0x1d7e57aa55817448", + ViewResolver: "0x1d7e57aa55817448", + MetadataViews: "0x1d7e57aa55817448", FlowToken: "0x1654653399040a61", + ScopedFTProviders: "0x1e4aa0b87d10b141", + FlowEVMBridge: "0x1e4aa0b87d10b141", FlowEVMBridgeUtils: "0x1e4aa0b87d10b141", FlowEVMBridgeConfig: "0x1e4aa0b87d10b141", FungibleTokenMetadataViews: "0xf233dcee88fe0abe", @@ -18,3 +28,5 @@ export const CONTRACT_ADDRESSES = { } export const CADENCE_UFIX64_PRECISION = 8 + +export const DEFAULT_EVM_GAS_LIMIT = "15000000" diff --git a/packages/kit/src/hooks/index.ts b/packages/kit/src/hooks/index.ts index d7c52adf9..c01fd1401 100644 --- a/packages/kit/src/hooks/index.ts +++ b/packages/kit/src/hooks/index.ts @@ -9,3 +9,4 @@ export {useFlowRevertibleRandom} from "./useFlowRevertibleRandom" export {useCrossVmBatchTransaction} from "./useCrossVmBatchTransaction" export {useCrossVmTokenBalance} from "./useCrossVmTokenBalance" export {useFlowTransactionStatus} from "./useFlowTransactionStatus" +export {useCrossVmSpendNft} from "./useCrossVmSpendNft" diff --git a/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts b/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts index c9ec48eee..4b4e1fac3 100644 --- a/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts +++ b/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts @@ -56,12 +56,12 @@ describe("useBatchEvmTransaction", () => { const result = encodeCalls(mockCalls as any) expect(result).toEqual([ - [ - {key: "to", value: "0x123"}, - {key: "data", value: ""}, - {key: "gasLimit", value: "100000"}, - {key: "value", value: "0"}, - ], + { + to: "0x123", + data: "", + gasLimit: "100000", + value: "0", + }, ]) }) }) diff --git a/packages/kit/src/hooks/useCrossVmBatchTransaction.ts b/packages/kit/src/hooks/useCrossVmBatchTransaction.ts index 89219309d..6fdfed55e 100644 --- a/packages/kit/src/hooks/useCrossVmBatchTransaction.ts +++ b/packages/kit/src/hooks/useCrossVmBatchTransaction.ts @@ -8,8 +8,9 @@ import { } from "@tanstack/react-query" import {useFlowChainId} from "./useFlowChainId" import {useFlowQueryClient} from "../provider/FlowQueryClient" +import {DEFAULT_EVM_GAS_LIMIT} from "../constants" -interface useCrossVmBatchTransactionArgs { +export interface UseCrossVmBatchTransactionArgs { mutation?: Omit< UseMutationOptions< { @@ -26,7 +27,7 @@ interface useCrossVmBatchTransactionArgs { > } -interface useCrossVmBatchTransactionResult +export interface UseCrossVmBatchTransactionResult extends Omit< UseMutationResult< { @@ -57,7 +58,7 @@ interface useCrossVmBatchTransactionResult }> } -interface EvmBatchCall { +export interface EvmBatchCall { // The target EVM contract address (as a string) address: string // The contract ABI fragment @@ -71,13 +72,14 @@ interface EvmBatchCall { // The value to send with the call value?: bigint } -interface CallOutcome { + +export interface CallOutcome { status: "passed" | "failed" | "skipped" hash?: string errorMessage?: string } -type EvmTransactionExecutedData = { +export interface EvmTransactionExecutedData { hash: string[] index: string type: string @@ -93,11 +95,9 @@ type EvmTransactionExecutedData = { stateUpdateChecksum: string } -// Helper to encode our ca lls using viem. -// Returns an array of objects with keys "address" and "data" (hex-encoded string without the "0x" prefix). export function encodeCalls( calls: EvmBatchCall[] -): Array> { +): Array<{to: string; data: string; gasLimit: string; value: string}> { return calls.map(call => { const encodedData = encodeFunctionData({ abi: call.abi, @@ -105,13 +105,13 @@ export function encodeCalls( args: call.args, }) - return [ - {key: "to", value: call.address}, - {key: "data", value: fcl.sansPrefix(encodedData) ?? ""}, - {key: "gasLimit", value: call.gasLimit?.toString() ?? "15000000"}, - {key: "value", value: call.value?.toString() ?? "0"}, - ] - }) as any + return { + to: call.address, + data: fcl.sansPrefix(encodedData) ?? "", + gasLimit: call.gasLimit?.toString() ?? DEFAULT_EVM_GAS_LIMIT, + value: call.value?.toString() ?? "0", + } + }) } const EVM_CONTRACT_ADDRESSES = { @@ -178,7 +178,7 @@ transaction(calls: [{String: AnyStruct}], mustPass: Bool) { */ export function useCrossVmBatchTransaction({ mutation: mutationOptions = {}, -}: useCrossVmBatchTransactionArgs = {}): useCrossVmBatchTransactionResult { +}: UseCrossVmBatchTransactionArgs = {}): UseCrossVmBatchTransactionResult { const chainId = useFlowChainId() const cadenceTx = chainId.data ? getCadenceBatchTransaction(chainId.data) @@ -203,7 +203,15 @@ export function useCrossVmBatchTransaction({ cadence: cadenceTx, args: (arg, t) => [ arg( - encodedCalls, + encodedCalls.map(call => [ + {key: "to", value: call.to}, + {key: "data", value: call.data}, + { + key: "gasLimit", + value: call.gasLimit, + }, + {key: "value", value: call.value}, + ]), t.Array( t.Dictionary([ {key: t.String, value: t.String}, diff --git a/packages/kit/src/hooks/useCrossVmSpendNft.test.ts b/packages/kit/src/hooks/useCrossVmSpendNft.test.ts new file mode 100644 index 000000000..ea14a92b2 --- /dev/null +++ b/packages/kit/src/hooks/useCrossVmSpendNft.test.ts @@ -0,0 +1,171 @@ +import {renderHook, act, waitFor} from "@testing-library/react" +import * as fcl from "@onflow/fcl" +import {FlowProvider} from "../provider" +import { + getCrossVmSpendNftransaction, + useCrossVmSpendNft, +} from "./useCrossVmSpendNft" +import {useFlowChainId} from "./useFlowChainId" + +jest.mock("@onflow/fcl", () => require("../__mocks__/fcl").default) +jest.mock("viem", () => ({ + encodeFunctionData: jest.fn(), + bytesToHex: jest.fn(x => `0x${x}`), +})) +jest.mock("./useFlowChainId", () => ({ + useFlowChainId: jest.fn(), +})) + +describe("useBatchEvmTransaction", () => { + const mockCalls = [ + { + address: "0x123", + abi: [{type: "function", name: "test"}], + functionName: "test", + args: [1, 2], + gasLimit: BigInt(100000), + value: BigInt(0), + }, + ] + + const mockTxId = "0x123" + const mockTxResult = { + events: [ + { + type: "TransactionExecuted", + data: { + hash: ["1", "2", "3"], + errorCode: "0", + errorMessage: "", + }, + }, + ], + } + + beforeEach(() => { + jest.clearAllMocks() + jest.mocked(useFlowChainId).mockReturnValue({ + data: "mainnet", + isLoading: false, + } as any) + }) + + describe("getCrossVmSpendNftTransaction", () => { + it("should return correct cadence for mainnet", () => { + const result = getCrossVmSpendNftransaction("mainnet") + expect(result).toContain("import EVM from 0xe467b9dd11fa00df") + }) + + it("should return correct cadence for testnet", () => { + const result = getCrossVmSpendNftransaction("testnet") + expect(result).toContain("import EVM from 0x8c5303eaa26202d6") + }) + + it("should throw error for unsupported chain", () => { + expect(() => getCrossVmSpendNftransaction("unsupported")).toThrow( + "Unsupported chain: unsupported" + ) + }) + }) + + describe("useCrossVmBatchTransaction", () => { + test("should handle successful transaction", async () => { + jest.mocked(fcl.mutate).mockResolvedValue(mockTxId) + jest.mocked(fcl.tx).mockReturnValue({ + onceExecuted: jest.fn().mockResolvedValue(mockTxResult), + } as any) + + let result: any + let rerender: any + await act(async () => { + ;({result, rerender} = renderHook(useCrossVmSpendNft, { + wrapper: FlowProvider, + })) + }) + + await act(async () => { + await result.current.spendNft({ + calls: mockCalls, + nftIdentifier: "nft123", + nftIds: ["1", "2"], + }) + rerender() + }) + + await waitFor(() => result.current.isPending === false) + + expect(result.current.isError).toBe(false) + expect(result.current.data).toBe(mockTxId) + }) + + it("should handle missing chain ID", async () => { + ;(useFlowChainId as jest.Mock).mockReturnValue({ + data: null, + isLoading: false, + }) + + let hookResult: any + + await act(async () => { + const {result} = renderHook(() => useCrossVmSpendNft(), { + wrapper: FlowProvider, + }) + hookResult = result + }) + + await act(async () => { + await hookResult.current.spendNft({calls: mockCalls}) + }) + + await waitFor(() => expect(hookResult.current.isError).toBe(true)) + expect(hookResult.current.error?.message).toBe("No current chain found") + }) + + it("should handle loading chain ID", async () => { + ;(useFlowChainId as jest.Mock).mockReturnValue({ + data: null, + isLoading: true, + }) + + let hookResult: any + + await act(async () => { + const {result} = renderHook(() => useCrossVmSpendNft(), { + wrapper: FlowProvider, + }) + hookResult = result + }) + + await act(async () => { + await hookResult.current.spendNft(mockCalls) + }) + + await waitFor(() => expect(hookResult.current.isError).toBe(true)) + expect(hookResult.current.error?.message).toBe("No current chain found") + }) + + it("should handle mutation error", async () => { + ;(fcl.mutate as jest.Mock).mockRejectedValue(new Error("Mutation failed")) + + let hookResult: any + + await act(async () => { + const {result} = renderHook(() => useCrossVmSpendNft(), { + wrapper: FlowProvider, + }) + hookResult = result + }) + + await act(async () => { + await hookResult.current.spendNft({ + calls: mockCalls, + nftIdentifier: "nft123", + nftIds: ["1", "2"], + }) + }) + + await waitFor(() => expect(hookResult.current.isError).toBe(true)) + expect(hookResult.current.error?.message).toBe("Mutation failed") + }) + }) +}) diff --git a/packages/kit/src/hooks/useCrossVmSpendNft.ts b/packages/kit/src/hooks/useCrossVmSpendNft.ts new file mode 100644 index 000000000..1e3b46f3f --- /dev/null +++ b/packages/kit/src/hooks/useCrossVmSpendNft.ts @@ -0,0 +1,281 @@ +import * as fcl from "@onflow/fcl" +import { + UseMutateAsyncFunction, + UseMutateFunction, + useMutation, + UseMutationOptions, + UseMutationResult, +} from "@tanstack/react-query" +import {useFlowChainId} from "./useFlowChainId" +import {useFlowQueryClient} from "../provider/FlowQueryClient" +import {encodeCalls, EvmBatchCall} from "./useCrossVmBatchTransaction" +import {CONTRACT_ADDRESSES} from "../constants" + +export interface UseCrossVmSpendNftTxArgs { + mutation?: Omit< + UseMutationOptions, + "mutationFn" + > +} + +export interface UseCrossVmSpendNftTxMutateArgs { + nftIdentifier: string + nftIds: string[] + calls: EvmBatchCall[] +} + +export interface UseCrossVmSpendNftTxResult + extends Omit, "mutate" | "mutateAsync"> { + spendNft: UseMutateFunction + spendNftAsync: UseMutateAsyncFunction< + string, + Error, + UseCrossVmSpendNftTxMutateArgs + > +} + +// Takes a chain id and returns the cadence tx with addresses set +export const getCrossVmSpendNftransaction = (chainId: string) => { + const contractAddresses = + CONTRACT_ADDRESSES[chainId as keyof typeof CONTRACT_ADDRESSES] + if (!contractAddresses) { + throw new Error(`Unsupported chain: ${chainId}`) + } + + return ` +import FungibleToken from ${contractAddresses.FungibleToken} +import NonFungibleToken from ${contractAddresses.NonFungibleToken} +import ViewResolver from ${contractAddresses.ViewResolver} +import MetadataViews from ${contractAddresses.MetadataViews} +import FlowToken from ${contractAddresses.FlowToken} + +import ScopedFTProviders from ${contractAddresses.ScopedFTProviders} + +import EVM from ${contractAddresses.EVM} + +import FlowEVMBridge from ${contractAddresses.FlowEVMBridge} +import FlowEVMBridgeConfig from ${contractAddresses.FlowEVMBridgeConfig} +import FlowEVMBridgeUtils from ${contractAddresses.FlowEVMBridgeUtils} + +/// Bridges NFTs (from the same collection) from the signer's collection in Cadence to the signer's COA in FlowEVM +/// and then performs an arbitrary number of calls afterwards to potentially do things +/// with the bridged NFTs +/// +/// NOTE: This transaction also onboards the NFT to the bridge if necessary which may incur additional fees +/// than bridging an asset that has already been onboarded. +/// +/// @param nftIdentifier: The Cadence type identifier of the NFT to bridge - e.g. nft.getType().identifier +/// @param ids: The Cadence NFT.id of the NFTs to bridge to EVM +/// @params evmContractAddressHexes, calldatas, gasLimits, values: Arrays of calldata +/// to be included in transaction calls to Flow EVM from the signer's COA. +/// The arrays are all expected to be of the same length +/// +transaction( + nftIdentifier: String, + ids: [UInt64], + evmContractAddressHexes: [String], + calldatas: [String], + gasLimits: [UInt64], + values: [UInt] +) { + let nftType: Type + let collection: auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection} + let coa: auth(EVM.Bridge, EVM.Call) &EVM.CadenceOwnedAccount + let requiresOnboarding: Bool + let scopedProvider: @ScopedFTProviders.ScopedFTProvider + + prepare(signer: auth(CopyValue, BorrowValue, IssueStorageCapabilityController, PublishCapability, SaveValue) &Account) { + pre { + (evmContractAddressHexes.length == calldatas.length) + && (calldatas.length == gasLimits.length) + && (gasLimits.length == values.length): + "Calldata array lengths must all be the same!" + } + + /* --- Reference the signer's CadenceOwnedAccount --- */ + // + // Borrow a reference to the signer's COA + self.coa = signer.storage.borrow(from: /storage/evm) + ?? panic("Could not borrow COA signer's account at path /storage/evm") + + /* --- Construct the NFT type --- */ + // + // Construct the NFT type from the provided identifier + self.nftType = CompositeType(nftIdentifier) + ?? panic("Could not construct NFT type from identifier: ".concat(nftIdentifier)) + // Parse the NFT identifier into its components + let nftContractAddress = FlowEVMBridgeUtils.getContractAddress(fromType: self.nftType) + ?? panic("Could not get contract address from identifier: ".concat(nftIdentifier)) + let nftContractName = FlowEVMBridgeUtils.getContractName(fromType: self.nftType) + ?? panic("Could not get contract name from identifier: ".concat(nftIdentifier)) + + /* --- Retrieve the NFT --- */ + // + // Borrow a reference to the NFT collection, configuring if necessary + let viewResolver = getAccount(nftContractAddress).contracts.borrow<&{ViewResolver}>(name: nftContractName) + ?? panic("Could not borrow ViewResolver from NFT contract with name " + .concat(nftContractName).concat(" and address ") + .concat(nftContractAddress.toString())) + let collectionData = viewResolver.resolveContractView( + resourceType: self.nftType, + viewType: Type() + ) as! MetadataViews.NFTCollectionData? + ?? panic("Could not resolve NFTCollectionData view for NFT type ".concat(self.nftType.identifier)) + self.collection = signer.storage.borrow( + from: collectionData.storagePath + ) ?? panic("Could not borrow a NonFungibleToken Collection from the signer's storage path " + .concat(collectionData.storagePath.toString())) + + // Withdraw the requested NFT & set a cap on the withdrawable bridge fee + var approxFee = FlowEVMBridgeUtils.calculateBridgeFee( + bytes: 400_000 // 400 kB as upper bound on movable storage used in a single transaction + ) + (FlowEVMBridgeConfig.baseFee * UFix64(ids.length)) + // Determine if the NFT requires onboarding - this impacts the fee required + self.requiresOnboarding = FlowEVMBridge.typeRequiresOnboarding(self.nftType) + ?? panic("Bridge does not support the requested asset type ".concat(nftIdentifier)) + // Add the onboarding fee if onboarding is necessary + if self.requiresOnboarding { + approxFee = approxFee + FlowEVMBridgeConfig.onboardFee + } + + /* --- Configure a ScopedFTProvider --- */ + // + // Issue and store bridge-dedicated Provider Capability in storage if necessary + if signer.storage.type(at: FlowEVMBridgeConfig.providerCapabilityStoragePath) == nil { + let providerCap = signer.capabilities.storage.issue( + /storage/flowTokenVault + ) + signer.storage.save(providerCap, to: FlowEVMBridgeConfig.providerCapabilityStoragePath) + } + // Copy the stored Provider capability and create a ScopedFTProvider + let providerCapCopy = signer.storage.copy>( + from: FlowEVMBridgeConfig.providerCapabilityStoragePath + ) ?? panic("Invalid FungibleToken Provider Capability found in storage at path " + .concat(FlowEVMBridgeConfig.providerCapabilityStoragePath.toString())) + let providerFilter = ScopedFTProviders.AllowanceFilter(approxFee) + self.scopedProvider <- ScopedFTProviders.createScopedFTProvider( + provider: providerCapCopy, + filters: [ providerFilter ], + expiration: getCurrentBlock().timestamp + 1.0 + ) + } + + execute { + if self.requiresOnboarding { + // Onboard the NFT to the bridge + FlowEVMBridge.onboardByType( + self.nftType, + feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ) + } + + // Iterate over requested IDs and bridge each NFT to the signer's COA in EVM + for id in ids { + // Withdraw the NFT & ensure it's the correct type + let nft <-self.collection.withdraw(withdrawID: id) + assert( + nft.getType() == self.nftType, + message: "Bridged nft type mismatch - requested: ".concat(self.nftType.identifier) + .concat(", received: ").concat(nft.getType().identifier) + ) + // Execute the bridge to EVM for the current ID + self.coa.depositNFT( + nft: <-nft, + feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ) + } + + // Destroy the ScopedFTProvider + destroy self.scopedProvider + + // Perform all the calls + for index, evmAddressHex in evmContractAddressHexes { + let evmAddress = EVM.addressFromString(evmAddressHex) + + let valueBalance = EVM.Balance(attoflow: values[index]) + let callResult = self.coa.call( + to: evmAddress, + data: calldatas[index].decodeHex(), + gasLimit: gasLimits[index], + value: valueBalance + ) + assert( + callResult.status == EVM.Status.successful, + message: "Call failed with address \(evmAddressHex) and calldata \(calldatas[index]) with error \(callResult.errorMessage)" + ) + } + } +} +` +} + +/** + * Hook to send a cross-VM NFT spend transaction. This function will + * bundle multiple EVM calls into one atomic Cadence transaction and return the transaction ID. + * + * Use `useCrossVmSpendNftStatus` to watch the status of the transaction and get the transaction id + result of each EVM call. + * + * @returns The mutation object used to send the transaction. + */ +export function useCrossVmSpendNft({ + mutation: mutationOptions = {}, +}: UseCrossVmSpendNftTxArgs = {}): UseCrossVmSpendNftTxResult { + const chainId = useFlowChainId() + const cadenceTx = chainId.data + ? getCrossVmSpendNftransaction(chainId.data) + : null + + const queryClient = useFlowQueryClient() + const mutation = useMutation( + { + mutationFn: async ({ + nftIdentifier, + nftIds, + calls, + }: UseCrossVmSpendNftTxMutateArgs) => { + if (!cadenceTx) { + throw new Error("No current chain found") + } + const encodedCalls = encodeCalls(calls) + + const txId = await fcl.mutate({ + cadence: cadenceTx, + args: (arg, t) => [ + arg(nftIdentifier, t.String), + arg(nftIds, t.Array(t.UInt64)), + arg( + encodedCalls.map(call => call.to), + t.Array(t.String) + ), + arg( + encodedCalls.map(call => call.data), + t.Array(t.String) + ), + arg( + encodedCalls.map(call => call.gasLimit), + t.Array(t.UInt64) + ), + arg( + encodedCalls.map(call => call.value), + t.Array(t.UInt) + ), + ], + limit: 9999, + }) + + return txId + }, + retry: false, + ...mutationOptions, + }, + queryClient + ) + + const {mutate: spendNft, mutateAsync: spendNftAsync, ...rest} = mutation + + return { + spendNft, + spendNftAsync, + ...rest, + } +} From f1a7eeab04a46e78b34a7a19aa4d8d93f3add452 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Mon, 9 Jun 2025 15:44:23 -0700 Subject: [PATCH 61/72] Add `useCrossVmSpendFt` hook (#2499) --- .changeset/young-gorillas-jog.md | 5 + package-lock.json | 2 +- packages/kit/src/hooks/index.ts | 1 + .../kit/src/hooks/useCrossVmSpendNft.test.ts | 4 - .../src/hooks/useCrossVmSpendToken.test.ts | 175 +++++++++++ .../kit/src/hooks/useCrossVmSpendToken.ts | 272 ++++++++++++++++++ 6 files changed, 454 insertions(+), 5 deletions(-) create mode 100644 .changeset/young-gorillas-jog.md create mode 100644 packages/kit/src/hooks/useCrossVmSpendToken.test.ts create mode 100644 packages/kit/src/hooks/useCrossVmSpendToken.ts diff --git a/.changeset/young-gorillas-jog.md b/.changeset/young-gorillas-jog.md new file mode 100644 index 000000000..276e4e5dc --- /dev/null +++ b/.changeset/young-gorillas-jog.md @@ -0,0 +1,5 @@ +--- +"@onflow/kit": minor +--- + +Add `useCrossVmSpendToken` hook diff --git a/package-lock.json b/package-lock.json index 0a5e65180..4a4263cb3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31486,7 +31486,7 @@ }, "packages/kit": { "name": "@onflow/kit", - "version": "0.3.0", + "version": "0.3.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", diff --git a/packages/kit/src/hooks/index.ts b/packages/kit/src/hooks/index.ts index c01fd1401..30033aa51 100644 --- a/packages/kit/src/hooks/index.ts +++ b/packages/kit/src/hooks/index.ts @@ -10,3 +10,4 @@ export {useCrossVmBatchTransaction} from "./useCrossVmBatchTransaction" export {useCrossVmTokenBalance} from "./useCrossVmTokenBalance" export {useFlowTransactionStatus} from "./useFlowTransactionStatus" export {useCrossVmSpendNft} from "./useCrossVmSpendNft" +export {useCrossVmSpendToken} from "./useCrossVmSpendToken" diff --git a/packages/kit/src/hooks/useCrossVmSpendNft.test.ts b/packages/kit/src/hooks/useCrossVmSpendNft.test.ts index ea14a92b2..298fd514a 100644 --- a/packages/kit/src/hooks/useCrossVmSpendNft.test.ts +++ b/packages/kit/src/hooks/useCrossVmSpendNft.test.ts @@ -8,10 +8,6 @@ import { import {useFlowChainId} from "./useFlowChainId" jest.mock("@onflow/fcl", () => require("../__mocks__/fcl").default) -jest.mock("viem", () => ({ - encodeFunctionData: jest.fn(), - bytesToHex: jest.fn(x => `0x${x}`), -})) jest.mock("./useFlowChainId", () => ({ useFlowChainId: jest.fn(), })) diff --git a/packages/kit/src/hooks/useCrossVmSpendToken.test.ts b/packages/kit/src/hooks/useCrossVmSpendToken.test.ts new file mode 100644 index 000000000..b0ab06c45 --- /dev/null +++ b/packages/kit/src/hooks/useCrossVmSpendToken.test.ts @@ -0,0 +1,175 @@ +import {renderHook, act, waitFor} from "@testing-library/react" +import * as fcl from "@onflow/fcl" +import {FlowProvider} from "../provider" +import { + getCrossVmSpendTokenTransaction, + useCrossVmSpendToken, +} from "./useCrossVmSpendToken" +import {useFlowChainId} from "./useFlowChainId" + +jest.mock("@onflow/fcl", () => require("../__mocks__/fcl").default) +jest.mock("./useFlowChainId", () => ({ + useFlowChainId: jest.fn(), +})) + +describe("useCrossVmSpendToken", () => { + const mockCalls = [ + { + address: "0x123", + abi: [{type: "function", name: "test"}], + functionName: "test", + args: [1, 2], + gasLimit: BigInt(100000), + value: BigInt(0), + }, + ] + + const mockTxId = "0x123" + const mockTxResult = { + events: [ + { + type: "TransactionExecuted", + data: { + hash: ["1", "2", "3"], + errorCode: "0", + errorMessage: "", + }, + }, + ], + } + + beforeEach(() => { + jest.clearAllMocks() + jest.mocked(useFlowChainId).mockReturnValue({ + data: "mainnet", + isLoading: false, + } as any) + }) + + describe("getCrossVmSpendTokenTransaction", () => { + it("should return correct cadence for mainnet", () => { + const result = getCrossVmSpendTokenTransaction("mainnet") + expect(result).toContain("import EVM from 0xe467b9dd11fa00df") + }) + + it("should return correct cadence for testnet", () => { + const result = getCrossVmSpendTokenTransaction("testnet") + expect(result).toContain("import EVM from 0x8c5303eaa26202d6") + }) + + it("should throw error for unsupported chain", () => { + expect(() => getCrossVmSpendTokenTransaction("unsupported")).toThrow( + "Unsupported chain: unsupported" + ) + }) + }) + + describe("useCrossVmBatchTransaction", () => { + test("should handle successful transaction", async () => { + jest.mocked(fcl.mutate).mockResolvedValue(mockTxId) + jest.mocked(fcl.tx).mockReturnValue({ + onceExecuted: jest.fn().mockResolvedValue(mockTxResult), + } as any) + + let result: any + let rerender: any + await act(async () => { + ;({result, rerender} = renderHook(useCrossVmSpendToken, { + wrapper: FlowProvider, + })) + }) + + await act(async () => { + await result.current.spendToken({ + calls: mockCalls, + vaultIdentifier: "A.1234.Token.Vault", + amount: "100.0", + }) + rerender() + }) + + await waitFor(() => result.current.isPending === false) + + expect(result.current.isError).toBe(false) + expect(result.current.data).toBe(mockTxId) + }) + + it("should handle missing chain ID", async () => { + ;(useFlowChainId as jest.Mock).mockReturnValue({ + data: null, + isLoading: false, + }) + + let hookResult: any + + await act(async () => { + const {result} = renderHook(() => useCrossVmSpendToken(), { + wrapper: FlowProvider, + }) + hookResult = result + }) + + await act(async () => { + await hookResult.current.spendToken({ + calls: mockCalls, + vaultIdentifier: "A.1234.Token.Vault", + amount: "100.0", + }) + }) + + await waitFor(() => expect(hookResult.current.isError).toBe(true)) + expect(hookResult.current.error?.message).toBe("No current chain found") + }) + + it("should handle loading chain ID", async () => { + ;(useFlowChainId as jest.Mock).mockReturnValue({ + data: null, + isLoading: true, + }) + + let hookResult: any + + await act(async () => { + const {result} = renderHook(() => useCrossVmSpendToken(), { + wrapper: FlowProvider, + }) + hookResult = result + }) + + await act(async () => { + await hookResult.current.spendToken({ + calls: mockCalls, + vaultIdentifier: "A.1234.Token.Vault", + amount: "100.0", + }) + }) + + await waitFor(() => expect(hookResult.current.isError).toBe(true)) + expect(hookResult.current.error?.message).toBe("No current chain found") + }) + + it("should handle mutation error", async () => { + ;(fcl.mutate as jest.Mock).mockRejectedValue(new Error("Mutation failed")) + + let hookResult: any + + await act(async () => { + const {result} = renderHook(() => useCrossVmSpendToken(), { + wrapper: FlowProvider, + }) + hookResult = result + }) + + await act(async () => { + await hookResult.current.spendToken({ + calls: mockCalls, + vaultIdentifier: "A.1234.Token.Vault", + amount: "100.0", + }) + }) + + await waitFor(() => expect(hookResult.current.isError).toBe(true)) + expect(hookResult.current.error?.message).toBe("Mutation failed") + }) + }) +}) diff --git a/packages/kit/src/hooks/useCrossVmSpendToken.ts b/packages/kit/src/hooks/useCrossVmSpendToken.ts new file mode 100644 index 000000000..64c36e191 --- /dev/null +++ b/packages/kit/src/hooks/useCrossVmSpendToken.ts @@ -0,0 +1,272 @@ +import * as fcl from "@onflow/fcl" +import { + UseMutateAsyncFunction, + UseMutateFunction, + useMutation, + UseMutationOptions, + UseMutationResult, +} from "@tanstack/react-query" +import {useFlowChainId} from "./useFlowChainId" +import {useFlowQueryClient} from "../provider/FlowQueryClient" +import {encodeCalls, EvmBatchCall} from "./useCrossVmBatchTransaction" +import {CONTRACT_ADDRESSES} from "../constants" + +export interface UseCrossVmSpendTokenArgs { + mutation?: Omit< + UseMutationOptions, + "mutationFn" + > +} + +export interface UseCrossVmSpendTokenMutateArgs { + vaultIdentifier: string + amount: string + calls: EvmBatchCall[] +} + +export interface UseCrossVmSpendTokenResult + extends Omit, "mutate" | "mutateAsync"> { + spendToken: UseMutateFunction + spendTokenAsync: UseMutateAsyncFunction< + string, + Error, + UseCrossVmSpendTokenMutateArgs + > +} + +// Takes a chain id and returns the cadence tx with addresses set +export const getCrossVmSpendTokenTransaction = (chainId: string) => { + const contractAddresses = + CONTRACT_ADDRESSES[chainId as keyof typeof CONTRACT_ADDRESSES] + if (!contractAddresses) { + throw new Error(`Unsupported chain: ${chainId}`) + } + + return ` +import FungibleToken from ${contractAddresses.FungibleToken} +import ViewResolver from ${contractAddresses.ViewResolver} +import FungibleTokenMetadataViews from ${contractAddresses.FungibleTokenMetadataViews} +import FlowToken from ${contractAddresses.FlowToken} + +import ScopedFTProviders from ${contractAddresses.ScopedFTProviders} + +import EVM from ${contractAddresses.EVM} + +import FlowEVMBridge from ${contractAddresses.FlowEVMBridge} +import FlowEVMBridgeConfig from ${contractAddresses.FlowEVMBridgeConfig} +import FlowEVMBridgeUtils from ${contractAddresses.FlowEVMBridgeUtils} + +/// Bridges a Vault from the signer's storage to the signer's COA in EVM.Account +/// and then executes an arbitrary number of EVM transactions. +/// +/// NOTE: This transaction also onboards the Vault to the bridge if necessary which may incur additional fees +/// than bridging an asset that has already been onboarded. +/// +/// @param vaultIdentifier: The Cadence type identifier of the FungibleToken Vault to bridge +/// - e.g. vault.getType().identifier +/// @param amount: The amount of tokens to bridge from EVM +/// @params evmContractAddressHexes, calldatas, gasLimits, values: Arrays of calldata +/// to be included in transaction calls to Flow EVM from the signer's COA. +/// The arrays are all expected to be of the same length +/// +/// +transaction( + vaultIdentifier: String, + amount: UFix64, + evmContractAddressHexes: [String], + calldatas: [String], + gasLimits: [UInt64], + values: [UInt] +) { + + let sentVault: @{FungibleToken.Vault} + let coa: auth(EVM.Bridge, EVM.Call) &EVM.CadenceOwnedAccount + let requiresOnboarding: Bool + let scopedProvider: @ScopedFTProviders.ScopedFTProvider + + prepare(signer: auth(CopyValue, BorrowValue, IssueStorageCapabilityController, PublishCapability, SaveValue) &Account) { + pre { + (evmContractAddressHexes.length == calldatas.length) + && (calldatas.length == gasLimits.length) + && (gasLimits.length == values.length): + "Calldata array lengths must all be the same!" + } + + /* --- Reference the signer's CadenceOwnedAccount --- */ + // + // Borrow a reference to the signer's COA + self.coa = signer.storage.borrow(from: /storage/evm) + ?? panic("Could not borrow COA signer's account at path /storage/evm") + + /* --- Construct the Vault type --- */ + // + // Construct the Vault type from the provided identifier + let vaultType = CompositeType(vaultIdentifier) + ?? panic("Could not construct Vault type from identifier: ".concat(vaultIdentifier)) + // Parse the Vault identifier into its components + let tokenContractAddress = FlowEVMBridgeUtils.getContractAddress(fromType: vaultType) + ?? panic("Could not get contract address from identifier: ".concat(vaultIdentifier)) + let tokenContractName = FlowEVMBridgeUtils.getContractName(fromType: vaultType) + ?? panic("Could not get contract name from identifier: ".concat(vaultIdentifier)) + + /* --- Retrieve the funds --- */ + // + // Borrow a reference to the FungibleToken Vault + let viewResolver = getAccount(tokenContractAddress).contracts.borrow<&{ViewResolver}>(name: tokenContractName) + ?? panic("Could not borrow ViewResolver from FungibleToken contract with name" + .concat(tokenContractName).concat(" and address ") + .concat(tokenContractAddress.toString())) + let vaultData = viewResolver.resolveContractView( + resourceType: vaultType, + viewType: Type() + ) as! FungibleTokenMetadataViews.FTVaultData? + ?? panic("Could not resolve FTVaultData view for Vault type ".concat(vaultType.identifier)) + let vault = signer.storage.borrow( + from: vaultData.storagePath + ) ?? panic("Could not borrow FungibleToken Vault from storage path ".concat(vaultData.storagePath.toString())) + + // Withdraw the requested balance & set a cap on the withdrawable bridge fee + self.sentVault <- vault.withdraw(amount: amount) + var approxFee = FlowEVMBridgeUtils.calculateBridgeFee( + bytes: 400_000 // 400 kB as upper bound on movable storage used in a single transaction + ) + // Determine if the Vault requires onboarding - this impacts the fee required + self.requiresOnboarding = FlowEVMBridge.typeRequiresOnboarding(self.sentVault.getType()) + ?? panic("Bridge does not support the requested asset type ".concat(vaultIdentifier)) + if self.requiresOnboarding { + approxFee = approxFee + FlowEVMBridgeConfig.onboardFee + } + + /* --- Configure a ScopedFTProvider --- */ + // + // Issue and store bridge-dedicated Provider Capability in storage if necessary + if signer.storage.type(at: FlowEVMBridgeConfig.providerCapabilityStoragePath) == nil { + let providerCap = signer.capabilities.storage.issue( + /storage/flowTokenVault + ) + signer.storage.save(providerCap, to: FlowEVMBridgeConfig.providerCapabilityStoragePath) + } + // Copy the stored Provider capability and create a ScopedFTProvider + let providerCapCopy = signer.storage.copy>( + from: FlowEVMBridgeConfig.providerCapabilityStoragePath + ) ?? panic("Invalid FungibleToken Provider Capability found in storage at path " + .concat(FlowEVMBridgeConfig.providerCapabilityStoragePath.toString())) + let providerFilter = ScopedFTProviders.AllowanceFilter(approxFee) + self.scopedProvider <- ScopedFTProviders.createScopedFTProvider( + provider: providerCapCopy, + filters: [ providerFilter ], + expiration: getCurrentBlock().timestamp + 1.0 + ) + } + + pre { + self.sentVault.getType().identifier == vaultIdentifier: + "Attempting to send invalid vault type - requested: ".concat(vaultIdentifier) + .concat(", sending: ").concat(self.sentVault.getType().identifier) + } + + execute { + if self.requiresOnboarding { + // Onboard the Vault to the bridge + FlowEVMBridge.onboardByType( + self.sentVault.getType(), + feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ) + } + // Execute the bridge + self.coa.depositTokens( + vault: <-self.sentVault, + feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider} + ) + // Destroy the ScopedFTProvider + destroy self.scopedProvider + + // Perform all the calls + for index, evmAddressHex in evmContractAddressHexes { + let evmAddress = EVM.addressFromString(evmAddressHex) + + let valueBalance = EVM.Balance(attoflow: values[index]) + let callResult = self.coa.call( + to: evmAddress, + data: calldatas[index].decodeHex(), + gasLimit: gasLimits[index], + value: valueBalance + ) + assert( + callResult.status == EVM.Status.successful, + message: "Call failed with address \(evmAddressHex) and calldata \(calldatas[index]) with error \(callResult.errorMessage)" + ) + } + } +} +` +} + +/** + * Hook to send a cross-VM FT spend transaction. This function will + * bundle multiple EVM calls into one atomic Cadence transaction and return the transaction ID. + * + * @returns The mutation object used to send the transaction. + */ +export function useCrossVmSpendToken({ + mutation: mutationOptions = {}, +}: UseCrossVmSpendTokenArgs = {}): UseCrossVmSpendTokenResult { + const chainId = useFlowChainId() + const cadenceTx = chainId.data + ? getCrossVmSpendTokenTransaction(chainId.data) + : null + + const queryClient = useFlowQueryClient() + const mutation = useMutation( + { + mutationFn: async ({ + vaultIdentifier, + amount, + calls, + }: UseCrossVmSpendTokenMutateArgs) => { + if (!cadenceTx) { + throw new Error("No current chain found") + } + const encodedCalls = encodeCalls(calls) + + const txId = await fcl.mutate({ + cadence: cadenceTx, + args: (arg, t) => [ + arg(vaultIdentifier, t.String), + arg(amount, t.UFix64), + arg( + encodedCalls.map(call => call.to), + t.Array(t.String) + ), + arg( + encodedCalls.map(call => call.data), + t.Array(t.String) + ), + arg( + encodedCalls.map(call => call.gasLimit), + t.Array(t.UInt64) + ), + arg( + encodedCalls.map(call => call.value), + t.Array(t.UInt) + ), + ], + limit: 9999, + }) + + return txId + }, + retry: false, + ...mutationOptions, + }, + queryClient + ) + + const {mutate: spendToken, mutateAsync: spendTokenAsync, ...rest} = mutation + + return { + spendToken, + spendTokenAsync, + ...rest, + } +} From 29a2c99b08d6f5a427bef5362e5d4e7ada9d51e7 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Tue, 10 Jun 2025 08:27:15 -0700 Subject: [PATCH 62/72] Change `useCrossVmBatchTransaction` to only return Cadence TX hash (#2502) --- .changeset/slow-eels-juggle.md | 9 ++ .../hooks/useCrossVmBatchTransaction.test.ts | 63 ++-------- .../src/hooks/useCrossVmBatchTransaction.ts | 117 +++--------------- 3 files changed, 33 insertions(+), 156 deletions(-) create mode 100644 .changeset/slow-eels-juggle.md diff --git a/.changeset/slow-eels-juggle.md b/.changeset/slow-eels-juggle.md new file mode 100644 index 000000000..36f60970c --- /dev/null +++ b/.changeset/slow-eels-juggle.md @@ -0,0 +1,9 @@ +--- +"@onflow/kit": minor +--- + +**BREAKING** Update `useCrossVmBatchTransaction` result data to the Cadence transaction ID instead of waiting for the EVM transaction hash. + +This change ensures consistency with the existing `useFlowMutate` response format and latencies, as waiting for the transaction execution for EVM results adds unnecessary delays and harms user experience. + +Developers should instead manually subscribe to the Cadence transaction status to track execution status and determine the EVM transaction results. \ No newline at end of file diff --git a/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts b/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts index 4b4e1fac3..1097aac67 100644 --- a/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts +++ b/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts @@ -21,7 +21,7 @@ describe("useBatchEvmTransaction", () => { const mockCalls = [ { address: "0x123", - abi: [{type: "function", name: "test"}], + abi: [{type: "function", name: "test"} as any], functionName: "test", args: [1, 2], gasLimit: BigInt(100000), @@ -30,18 +30,6 @@ describe("useBatchEvmTransaction", () => { ] const mockTxId = "0x123" - const mockTxResult = { - events: [ - { - type: "TransactionExecuted", - data: { - hash: ["1", "2", "3"], - errorCode: "0", - errorMessage: "", - }, - }, - ], - } beforeEach(() => { jest.clearAllMocks() @@ -53,7 +41,7 @@ describe("useBatchEvmTransaction", () => { describe("encodeCalls", () => { it("should encode calls correctly", () => { - const result = encodeCalls(mockCalls as any) + const result = encodeCalls(mockCalls) expect(result).toEqual([ { @@ -92,9 +80,6 @@ describe("useBatchEvmTransaction", () => { describe("useCrossVmBatchTransaction", () => { test("should handle successful transaction", async () => { jest.mocked(fcl.mutate).mockResolvedValue(mockTxId) - jest.mocked(fcl.tx).mockReturnValue({ - onceExecuted: jest.fn().mockResolvedValue(mockTxResult), - } as any) let result: any let rerender: any @@ -112,18 +97,11 @@ describe("useBatchEvmTransaction", () => { await waitFor(() => result.current.isPending === false) expect(result.current.isError).toBe(false) - expect(result.current.data?.txId).toBe(mockTxId) - expect(result.current.data?.results).toHaveLength(1) - expect(result.current.data?.results[0].status).toBe("passed") + expect(result.current.data).toBe(mockTxId) }) - test("should handle failed transaction", async () => { - jest.mocked(fcl.mutate).mockResolvedValue(mockTxId) - jest.mocked(fcl.tx).mockReturnValue({ - onceExecuted: jest - .fn() - .mockRejectedValue(new Error("Transaction failed")), - } as any) + test("should handle error transaction", async () => { + jest.mocked(fcl.mutate).mockRejectedValue(new Error("Transaction failed")) let hookResult: any @@ -140,35 +118,8 @@ describe("useBatchEvmTransaction", () => { await waitFor(() => expect(hookResult.current.isPending).toBe(false)) - expect(hookResult.current.isError).toBe(false) - expect(hookResult.current.data?.results[0].status).toBe("failed") - expect(hookResult.current.data?.results[0].errorMessage).toBe( - "Transaction reverted" - ) - }) - - test("should handle skipped calls", async () => { - jest.mocked(fcl.mutate).mockResolvedValue(mockTxId) - jest.mocked(fcl.tx).mockReturnValue({ - onceExecuted: jest.fn().mockResolvedValue({events: []}), - } as any) - - let hookResult: any - - await act(async () => { - const {result} = renderHook(() => useCrossVmBatchTransaction(), { - wrapper: FlowProvider, - }) - hookResult = result - }) - - await act(async () => { - await hookResult.current.sendBatchTransaction({calls: mockCalls}) - }) - - await waitFor(() => expect(hookResult.current.isPending).toBe(false)) - - expect(hookResult.current.data?.results[0].status).toBe("skipped") + expect(hookResult.current.isError).toBe(true) + expect(hookResult.current.error?.message).toBe("Transaction failed") }) it("should handle missing chain ID", async () => { diff --git a/packages/kit/src/hooks/useCrossVmBatchTransaction.ts b/packages/kit/src/hooks/useCrossVmBatchTransaction.ts index 6fdfed55e..b090c8f90 100644 --- a/packages/kit/src/hooks/useCrossVmBatchTransaction.ts +++ b/packages/kit/src/hooks/useCrossVmBatchTransaction.ts @@ -1,6 +1,7 @@ import * as fcl from "@onflow/fcl" -import {Abi, bytesToHex, encodeFunctionData} from "viem" +import {Abi, encodeFunctionData} from "viem" import { + UseMutateAsyncFunction, UseMutateFunction, useMutation, UseMutationOptions, @@ -10,52 +11,33 @@ import {useFlowChainId} from "./useFlowChainId" import {useFlowQueryClient} from "../provider/FlowQueryClient" import {DEFAULT_EVM_GAS_LIMIT} from "../constants" +interface UseCrossVmBatchTransactionMutateArgs { + calls: EvmBatchCall[] + mustPass?: boolean +} + export interface UseCrossVmBatchTransactionArgs { mutation?: Omit< - UseMutationOptions< - { - txId: string - results: CallOutcome[] - }, - Error, - { - calls: EvmBatchCall[] - mustPass?: boolean - } - >, + UseMutationOptions, "mutationFn" > } export interface UseCrossVmBatchTransactionResult extends Omit< - UseMutationResult< - { - txId: string - results: CallOutcome[] - }, - Error - >, + UseMutationResult, "mutate" | "mutateAsync" > { sendBatchTransaction: UseMutateFunction< - { - txId: string - results: CallOutcome[] - }, + string, Error, - { - calls: EvmBatchCall[] - mustPass?: boolean - } + UseCrossVmBatchTransactionMutateArgs + > + sendBatchTransactionAsync: UseMutateAsyncFunction< + string, + Error, + UseCrossVmBatchTransactionMutateArgs > - sendBatchTransactionAsync: (args: { - calls: EvmBatchCall[] - mustPass?: boolean - }) => Promise<{ - txId: string - results: CallOutcome[] - }> } export interface EvmBatchCall { @@ -73,28 +55,6 @@ export interface EvmBatchCall { value?: bigint } -export interface CallOutcome { - status: "passed" | "failed" | "skipped" - hash?: string - errorMessage?: string -} - -export interface EvmTransactionExecutedData { - hash: string[] - index: string - type: string - payload: string[] - errorCode: string - errorMessage: string - gasConsumed: string - contractAddress: string - logs: string[] - blockHeight: string - returnedData: string[] - precompiledCalls: string[] - stateUpdateChecksum: string -} - export function encodeCalls( calls: EvmBatchCall[] ): Array<{to: string; data: string; gasLimit: string; value: string}> { @@ -226,50 +186,7 @@ export function useCrossVmBatchTransaction({ limit: 9999, }) - let txResult - try { - txResult = await fcl.tx(txId).onceExecuted() - } catch (txError) { - // If we land here, the transaction likely reverted. - // We can return partial or "failed" outcomes for all calls. - return { - txId, - results: calls.map(() => ({ - status: "failed" as const, - hash: undefined, - errorMessage: "Transaction reverted", - })), - } - } - - // Filter for TransactionExecuted events - const executedEvents = txResult.events.filter((e: any) => - e.type.includes("TransactionExecuted") - ) - - // Build a full outcomes array for every call. - // For any call index where no event exists, mark it as "skipped". - const results: CallOutcome[] = calls.map((_, index) => { - const eventData = executedEvents[index] - ?.data as EvmTransactionExecutedData - if (eventData) { - return { - hash: bytesToHex( - Uint8Array.from( - eventData.hash.map((x: string) => parseInt(x, 10)) - ) - ), - status: eventData.errorCode === "0" ? "passed" : "failed", - errorMessage: eventData.errorMessage, - } - } else { - return { - status: "skipped", - } - } - }) - - return {txId, results} + return txId }, retry: false, ...mutationOptions, From 8f17152d2c41297039d857c532d5d3412f5b22a6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 10 Jun 2025 09:57:36 -0700 Subject: [PATCH 63/72] Version Packages (#2504) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/slow-eels-juggle.md | 9 --------- .changeset/tiny-rabbits-try.md | 5 ----- .changeset/young-gorillas-jog.md | 5 ----- packages/kit/CHANGELOG.md | 14 ++++++++++++++ packages/kit/package.json | 2 +- 5 files changed, 15 insertions(+), 20 deletions(-) delete mode 100644 .changeset/slow-eels-juggle.md delete mode 100644 .changeset/tiny-rabbits-try.md delete mode 100644 .changeset/young-gorillas-jog.md diff --git a/.changeset/slow-eels-juggle.md b/.changeset/slow-eels-juggle.md deleted file mode 100644 index 36f60970c..000000000 --- a/.changeset/slow-eels-juggle.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@onflow/kit": minor ---- - -**BREAKING** Update `useCrossVmBatchTransaction` result data to the Cadence transaction ID instead of waiting for the EVM transaction hash. - -This change ensures consistency with the existing `useFlowMutate` response format and latencies, as waiting for the transaction execution for EVM results adds unnecessary delays and harms user experience. - -Developers should instead manually subscribe to the Cadence transaction status to track execution status and determine the EVM transaction results. \ No newline at end of file diff --git a/.changeset/tiny-rabbits-try.md b/.changeset/tiny-rabbits-try.md deleted file mode 100644 index 81e4e86d8..000000000 --- a/.changeset/tiny-rabbits-try.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/kit": minor ---- - -Add `useCrossVmSpendNft` hook diff --git a/.changeset/young-gorillas-jog.md b/.changeset/young-gorillas-jog.md deleted file mode 100644 index 276e4e5dc..000000000 --- a/.changeset/young-gorillas-jog.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@onflow/kit": minor ---- - -Add `useCrossVmSpendToken` hook diff --git a/packages/kit/CHANGELOG.md b/packages/kit/CHANGELOG.md index b9dfa0516..972d393e3 100644 --- a/packages/kit/CHANGELOG.md +++ b/packages/kit/CHANGELOG.md @@ -1,5 +1,19 @@ # @onflow/kit +## 0.4.0 + +### Minor Changes + +- [#2503](https://github.com/onflow/fcl-js/pull/2503) [`29a2c99b08d6f5a427bef5362e5d4e7ada9d51e7`](https://github.com/onflow/fcl-js/commit/29a2c99b08d6f5a427bef5362e5d4e7ada9d51e7) Thanks [@jribbink](https://github.com/jribbink)! - **BREAKING** Update `useCrossVmBatchTransaction` result data to the Cadence transaction ID instead of waiting for the EVM transaction hash. + + This change ensures consistency with the existing `useFlowMutate` response format and latencies, as waiting for the transaction execution for EVM results adds unnecessary delays and harms user experience. + + Developers should instead manually subscribe to the Cadence transaction status to track execution status and determine the EVM transaction results. + +- [#2460](https://github.com/onflow/fcl-js/pull/2460) [`d7b673e2ea97f6ab5ec2b81d2186b3e9799460cf`](https://github.com/onflow/fcl-js/commit/d7b673e2ea97f6ab5ec2b81d2186b3e9799460cf) Thanks [@jribbink](https://github.com/jribbink)! - Add `useCrossVmSpendNft` hook + +- [#2503](https://github.com/onflow/fcl-js/pull/2503) [`f1a7eeab04a46e78b34a7a19aa4d8d93f3add452`](https://github.com/onflow/fcl-js/commit/f1a7eeab04a46e78b34a7a19aa4d8d93f3add452) Thanks [@jribbink](https://github.com/jribbink)! - Add `useCrossVmSpendToken` hook + ## 0.3.1 ### Patch Changes diff --git a/packages/kit/package.json b/packages/kit/package.json index 1bd778ecd..c87473b1d 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/kit", - "version": "0.3.1", + "version": "0.4.0", "description": "React library for interacting with the Flow blockchain", "license": "Apache-2.0", "author": "Flow Foundation", From 3263a098d32d8d4f73224f3d1facebd1a824c53b Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Tue, 10 Jun 2025 16:19:42 -0700 Subject: [PATCH 64/72] Make `useFlowChainId` args consistent with other hooks (#2506) --- .changeset/blue-suns-accept.md | 5 +++++ packages/kit/src/hooks/useFlowChainId.test.ts | 9 ++++++--- packages/kit/src/hooks/useFlowChainId.ts | 13 +++++++------ 3 files changed, 18 insertions(+), 9 deletions(-) create mode 100644 .changeset/blue-suns-accept.md diff --git a/.changeset/blue-suns-accept.md b/.changeset/blue-suns-accept.md new file mode 100644 index 000000000..7771344ad --- /dev/null +++ b/.changeset/blue-suns-accept.md @@ -0,0 +1,5 @@ +--- +"@onflow/kit": patch +--- + +Make `useFlowChainId` args consistent with other hooks diff --git a/packages/kit/src/hooks/useFlowChainId.test.ts b/packages/kit/src/hooks/useFlowChainId.test.ts index 244629c70..b3e5424a0 100644 --- a/packages/kit/src/hooks/useFlowChainId.test.ts +++ b/packages/kit/src/hooks/useFlowChainId.test.ts @@ -96,9 +96,12 @@ describe("useFlowChainId", () => { let hookResult: any await act(async () => { - const {result} = renderHook(() => useFlowChainId(customOptions), { - wrapper: FlowProvider, - }) + const {result} = renderHook( + () => useFlowChainId({query: customOptions}), + { + wrapper: FlowProvider, + } + ) hookResult = result }) diff --git a/packages/kit/src/hooks/useFlowChainId.ts b/packages/kit/src/hooks/useFlowChainId.ts index b554f9d4f..7a20bafef 100644 --- a/packages/kit/src/hooks/useFlowChainId.ts +++ b/packages/kit/src/hooks/useFlowChainId.ts @@ -4,15 +4,16 @@ import {useFlowQueryClient} from "../provider/FlowQueryClient" import {useCallback} from "react" import {useFlowConfig} from "./useFlowConfig" +interface UseFlowChainIdArgs { + query?: Omit, "queryKey" | "queryFn"> +} + /** * Gets the Flow chain ID. */ -export function useFlowChainId( - queryOptions: Omit< - UseQueryOptions, - "queryKey" | "queryFn" - > = {} -): UseQueryResult { +export function useFlowChainId({ + query: queryOptions = {}, +}: UseFlowChainIdArgs = {}): UseQueryResult { const queryClient = useFlowQueryClient() const config = useFlowConfig() From 5725d68f39c45d3567332de156fd56f3d52f2770 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 13 Jun 2025 14:51:41 -0700 Subject: [PATCH 65/72] Run prettier --- package-lock.json | 2 +- packages/fcl-core/package.json | 2 +- packages/fcl-core/src/fcl-core.ts | 140 +++++++++--------- .../src/transaction/transaction.test.ts | 30 ++-- .../fcl-core/src/transaction/transaction.ts | 20 +-- packages/fcl-ethereum-provider/package.json | 2 +- packages/fcl-rainbowkit-adapter/package.json | 2 +- packages/fcl-react-native/package.json | 2 +- .../fcl-react-native/src/fcl-react-native.ts | 12 +- packages/fcl-wagmi-adapter/package.json | 2 +- packages/fcl-wc/package.json | 2 +- packages/fcl/package.json | 2 +- packages/fcl/src/fcl.ts | 14 +- packages/kit/package.json | 2 +- packages/kit/src/hooks/index.ts | 26 ++-- .../hooks/useCrossVmBatchTransaction.test.ts | 32 ++-- .../src/hooks/useCrossVmBatchTransaction.ts | 24 +-- packages/kit/src/hooks/useFlowChainId.test.ts | 16 +- packages/kit/src/hooks/useFlowChainId.ts | 8 +- packages/sdk/package.json | 2 +- packages/sdk/src/sdk.ts | 116 +++++++-------- packages/sdk/src/transport/index.ts | 8 +- .../src/transport/subscribe/subscribe.test.ts | 26 ++-- .../sdk/src/transport/subscribe/subscribe.ts | 10 +- packages/transport-grpc/package.json | 2 +- packages/transport-http/package.json | 2 +- packages/typedefs/package.json | 2 +- 27 files changed, 254 insertions(+), 254 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6c65da8e4..76e6033dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32263,4 +32263,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/fcl-core/package.json b/packages/fcl-core/package.json index 39713ffd8..ded6a2947 100644 --- a/packages/fcl-core/package.json +++ b/packages/fcl-core/package.json @@ -65,4 +65,4 @@ "abort-controller": "^3.0.0", "cross-fetch": "^4.0.0" } -} \ No newline at end of file +} diff --git a/packages/fcl-core/src/fcl-core.ts b/packages/fcl-core/src/fcl-core.ts index 5043c0802..1a764cb6f 100644 --- a/packages/fcl-core/src/fcl-core.ts +++ b/packages/fcl-core/src/fcl-core.ts @@ -1,104 +1,104 @@ -export { VERSION } from "./VERSION" -export { query } from "./exec/query" -export { verifyUserSignatures } from "./exec/verify" -export { serialize } from "./serialize" -export { transaction as tx, TransactionError } from "./transaction" -export { events } from "./events" -export { pluginRegistry } from "./current-user/exec-service/plugins" +export {VERSION} from "./VERSION" +export {query} from "./exec/query" +export {verifyUserSignatures} from "./exec/verify" +export {serialize} from "./serialize" +export {transaction as tx, TransactionError} from "./transaction" +export {events} from "./events" +export {pluginRegistry} from "./current-user/exec-service/plugins" -import { discovery } from "./discovery" -export { discovery } +import {discovery} from "./discovery" +export {discovery} import * as types from "@onflow/types" -export { types as t } +export {types as t} import * as WalletUtils from "./wallet-utils" -export { WalletUtils } +export {WalletUtils} import * as AppUtils from "./app-utils" -export { AppUtils } +export {AppUtils} import * as InteractionTemplateUtils from "./interaction-template-utils" -export { InteractionTemplateUtils } +export {InteractionTemplateUtils} -export { getChainId } from "./utils" +export {getChainId} from "./utils" -export { TestUtils } from "@onflow/sdk" +export {TestUtils} from "@onflow/sdk" -import { config } from "@onflow/config" -export { config } +import {config} from "@onflow/config" +export {config} -export { send } from "@onflow/sdk" -export { decode } from "@onflow/sdk" -export { account } from "@onflow/sdk" -export { block } from "@onflow/sdk" -export { nodeVersionInfo } from "@onflow/sdk" -export { isOk, isBad, why, pipe, build } from "@onflow/sdk" -export { withPrefix, sansPrefix, display } from "@onflow/util-address" -export { template as cadence } from "@onflow/util-template" -export { template as cdc } from "@onflow/util-template" -export { createSignableVoucher } from "@onflow/sdk" -export { voucherIntercept } from "@onflow/sdk" -export { voucherToTxId } from "@onflow/sdk" -export { flowMainnet, flowTestnet, flowEmulator } from "@onflow/sdk" +export {send} from "@onflow/sdk" +export {decode} from "@onflow/sdk" +export {account} from "@onflow/sdk" +export {block} from "@onflow/sdk" +export {nodeVersionInfo} from "@onflow/sdk" +export {isOk, isBad, why, pipe, build} from "@onflow/sdk" +export {withPrefix, sansPrefix, display} from "@onflow/util-address" +export {template as cadence} from "@onflow/util-template" +export {template as cdc} from "@onflow/util-template" +export {createSignableVoucher} from "@onflow/sdk" +export {voucherIntercept} from "@onflow/sdk" +export {voucherToTxId} from "@onflow/sdk" +export {flowMainnet, flowTestnet, flowEmulator} from "@onflow/sdk" // builders -export { transaction } from "@onflow/sdk" -export { script } from "@onflow/sdk" -export { ping } from "@onflow/sdk" -export { atBlockHeight } from "@onflow/sdk" -export { atBlockId } from "@onflow/sdk" -export { getAccount } from "@onflow/sdk" -export { getEvents } from "@onflow/sdk" -export { getEventsAtBlockHeightRange } from "@onflow/sdk" -export { getEventsAtBlockIds } from "@onflow/sdk" -export { getBlock } from "@onflow/sdk" -export { getBlockHeader } from "@onflow/sdk" -export { getCollection } from "@onflow/sdk" -export { getTransactionStatus } from "@onflow/sdk" -export { getTransaction } from "@onflow/sdk" -export { getNetworkParameters } from "@onflow/sdk" -export { getNodeVersionInfo } from "@onflow/sdk" -export { authorizations, authorization } from "@onflow/sdk" -export { subscribeEvents } from "@onflow/sdk" -export { args, arg } from "@onflow/sdk" -export { proposer } from "@onflow/sdk" -export { payer } from "@onflow/sdk" -export { limit } from "@onflow/sdk" -export { ref } from "@onflow/sdk" -export { params, param } from "@onflow/sdk" -export { validator } from "@onflow/sdk" -export { invariant } from "@onflow/sdk" +export {transaction} from "@onflow/sdk" +export {script} from "@onflow/sdk" +export {ping} from "@onflow/sdk" +export {atBlockHeight} from "@onflow/sdk" +export {atBlockId} from "@onflow/sdk" +export {getAccount} from "@onflow/sdk" +export {getEvents} from "@onflow/sdk" +export {getEventsAtBlockHeightRange} from "@onflow/sdk" +export {getEventsAtBlockIds} from "@onflow/sdk" +export {getBlock} from "@onflow/sdk" +export {getBlockHeader} from "@onflow/sdk" +export {getCollection} from "@onflow/sdk" +export {getTransactionStatus} from "@onflow/sdk" +export {getTransaction} from "@onflow/sdk" +export {getNetworkParameters} from "@onflow/sdk" +export {getNodeVersionInfo} from "@onflow/sdk" +export {authorizations, authorization} from "@onflow/sdk" +export {subscribeEvents} from "@onflow/sdk" +export {args, arg} from "@onflow/sdk" +export {proposer} from "@onflow/sdk" +export {payer} from "@onflow/sdk" +export {limit} from "@onflow/sdk" +export {ref} from "@onflow/sdk" +export {params, param} from "@onflow/sdk" +export {validator} from "@onflow/sdk" +export {invariant} from "@onflow/sdk" // Subscriptions -export { subscribe } from "@onflow/sdk" -export { subscribeRaw } from "@onflow/sdk" +export {subscribe} from "@onflow/sdk" +export {subscribeRaw} from "@onflow/sdk" -import { watchForChainIdChanges } from "./utils" +import {watchForChainIdChanges} from "./utils" // Set chain id default on access node change watchForChainIdChanges() -export { getMutate } from "./exec/mutate" +export {getMutate} from "./exec/mutate" -export { getCurrentUser } from "./current-user" +export {getCurrentUser} from "./current-user" -export { initServiceRegistry } from "./current-user/exec-service/plugins" +export {initServiceRegistry} from "./current-user/exec-service/plugins" -export { isReactNative, setIsReactNative } from "./utils/is-react-native" +export {isReactNative, setIsReactNative} from "./utils/is-react-native" -export { getExecHttpPost } from "./current-user/exec-service/strategies/http-post" +export {getExecHttpPost} from "./current-user/exec-service/strategies/http-post" -export { normalizePollingResponse } from "./normalizers/service/polling-response" -export { buildMessageHandler } from "./current-user/exec-service/strategies/utils/buildMessageHandler" -export { serviceEndpoint } from "./current-user/exec-service/strategies/utils/service-endpoint" -export { URL } from "./utils/url" +export {normalizePollingResponse} from "./normalizers/service/polling-response" +export {buildMessageHandler} from "./current-user/exec-service/strategies/utils/buildMessageHandler" +export {serviceEndpoint} from "./current-user/exec-service/strategies/utils/service-endpoint" +export {URL} from "./utils/url" export { CORE_STRATEGIES, FCL_REDIRECT_URL_PARAM_NAME, FCL_RESPONSE_PARAM_NAME, } from "./utils/constants" -export { execStrategy } from "./current-user/exec-service" +export {execStrategy} from "./current-user/exec-service" -export type { StorageProvider } from "./utils/storage" +export type {StorageProvider} from "./utils/storage" diff --git a/packages/fcl-core/src/transaction/transaction.test.ts b/packages/fcl-core/src/transaction/transaction.test.ts index d839b9c32..9f0723950 100644 --- a/packages/fcl-core/src/transaction/transaction.test.ts +++ b/packages/fcl-core/src/transaction/transaction.test.ts @@ -1,9 +1,9 @@ -import { subscribe } from "@onflow/sdk" -import { SubscriptionsNotSupportedError } from "@onflow/sdk" -import { SubscriptionTopic, TransactionExecutionStatus } from "@onflow/typedefs" -import { transaction } from "./transaction" -import { transaction as legacyTransaction } from "./legacy-polling" -import { getChainId } from "../utils" +import {subscribe} from "@onflow/sdk" +import {SubscriptionsNotSupportedError} from "@onflow/sdk" +import {SubscriptionTopic, TransactionExecutionStatus} from "@onflow/typedefs" +import {transaction} from "./transaction" +import {transaction as legacyTransaction} from "./legacy-polling" +import {getChainId} from "../utils" jest.mock("@onflow/sdk") jest.mock("./legacy-polling") @@ -29,7 +29,7 @@ describe("transaction", () => { }) test("should throw an error if transactionId is not a 64 byte hash string", () => { - const { transaction } = require("./transaction") + const {transaction} = require("./transaction") const actual = () => transaction("invalid-transaction-id") expect(actual).toThrow("Invalid transactionId") @@ -47,12 +47,12 @@ describe("transaction", () => { // Expect the subscribe method to be called with the correct parameters const subscribeParams = jest.mocked(subscribe).mock .calls[0][0] as Parameters< - typeof subscribe - >[0] + typeof subscribe + >[0] expect(subscribeParams).toStrictEqual({ topic: SubscriptionTopic.TRANSACTION_STATUSES, - args: { transactionId: txId }, + args: {transactionId: txId}, onData: expect.any(Function), onError: expect.any(Function), }) @@ -133,8 +133,8 @@ describe("transaction", () => { // Mock the observable to emit a SEALED status const subscribeParams = jest.mocked(subscribe).mock .calls[0][0] as Parameters< - typeof subscribe - >[0] + typeof subscribe + >[0] subscribeParams.onData({ status: TransactionExecutionStatus.PENDING, @@ -173,12 +173,12 @@ describe("transaction", () => { // Expect the subscribe method to be called with the correct parameters const subscribeParams = jest.mocked(subscribe).mock .calls[0][0] as Parameters< - typeof subscribe - >[0] + typeof subscribe + >[0] expect(subscribeParams).toStrictEqual({ topic: SubscriptionTopic.TRANSACTION_STATUSES, - args: { transactionId: txId }, + args: {transactionId: txId}, onData: expect.any(Function), onError: expect.any(Function), }) diff --git a/packages/fcl-core/src/transaction/transaction.ts b/packages/fcl-core/src/transaction/transaction.ts index d2c0a2619..8ff6acce8 100644 --- a/packages/fcl-core/src/transaction/transaction.ts +++ b/packages/fcl-core/src/transaction/transaction.ts @@ -13,15 +13,15 @@ import { isSealed, scoped, } from "./utils" -import { TXID_REGEXP } from "./constants" +import {TXID_REGEXP} from "./constants" import { isUnknown, subscribe as sdkSubscribe, SubscriptionsNotSupportedError, } from "@onflow/sdk" -import { TransactionError } from "./transaction-error" -import { transaction as legacyTransaction } from "./legacy-polling" -import { getChainId } from "../utils" +import {TransactionError} from "./transaction-error" +import {transaction as legacyTransaction} from "./legacy-polling" +import {getChainId} from "../utils" const FLOW_EMULATOR = "local" @@ -43,7 +43,7 @@ export function transaction( opts: { pollRate?: number txNotFoundTimeout?: number - } = { txNotFoundTimeout: 12500, pollRate: 1000 } + } = {txNotFoundTimeout: 12500, pollRate: 1000} ): { snapshot: () => Promise subscribe: ( @@ -76,12 +76,12 @@ export function transaction( onError?: (err: Error) => void ) { const observable = getObservable() - const { unsubscribe } = observable.subscribe(onData, onError) + const {unsubscribe} = observable.subscribe(onData, onError) return () => unsubscribe() } function once(predicate: (txStatus: TransactionStatus) => boolean) { - return function innerOnce(opts = { suppress: false }) { + return function innerOnce(opts = {suppress: false}) { const suppress = opts.suppress || false return new Promise((resolve, reject) => { const unsub = subscribe( @@ -129,7 +129,7 @@ transaction.isExpired = isExpired */ function createObservable( txId: string, - opts: { pollRate?: number; txNotFoundTimeout?: number } + opts: {pollRate?: number; txNotFoundTimeout?: number} ) { const observers = new Set<{ onData: (txStatus: TransactionStatus) => void @@ -167,7 +167,7 @@ function createObservable( // Subscribe to transaction status updates const subscription = sdkSubscribe({ topic: SubscriptionTopic.TRANSACTION_STATUSES, - args: { transactionId: txId }, + args: {transactionId: txId}, onData: txStatus => { if (isDiff(value, txStatus)) { value = txStatus @@ -246,7 +246,7 @@ function createObservable( ) { const observer = { onData, - onError: onError || (() => { }), + onError: onError || (() => {}), } observers.add(observer) onData(value) diff --git a/packages/fcl-ethereum-provider/package.json b/packages/fcl-ethereum-provider/package.json index c26bc99e4..5eafc3c9a 100644 --- a/packages/fcl-ethereum-provider/package.json +++ b/packages/fcl-ethereum-provider/package.json @@ -52,4 +52,4 @@ "peerDependencies": { "@onflow/fcl": "1.18.0" } -} \ No newline at end of file +} diff --git a/packages/fcl-rainbowkit-adapter/package.json b/packages/fcl-rainbowkit-adapter/package.json index 1f4703a96..d37a201bf 100644 --- a/packages/fcl-rainbowkit-adapter/package.json +++ b/packages/fcl-rainbowkit-adapter/package.json @@ -54,4 +54,4 @@ "@rainbow-me/rainbowkit": "^2.2.3", "react": "17.x || 18.x || 19.x" } -} \ No newline at end of file +} diff --git a/packages/fcl-react-native/package.json b/packages/fcl-react-native/package.json index 1583a8f52..f2cfd70a5 100644 --- a/packages/fcl-react-native/package.json +++ b/packages/fcl-react-native/package.json @@ -69,4 +69,4 @@ "react": "^18.0.0 || ^19.0.0", "react-native": "^0.0.0-0 || 0.60 - 0.78 || 1000.0.0" } -} \ No newline at end of file +} diff --git a/packages/fcl-react-native/src/fcl-react-native.ts b/packages/fcl-react-native/src/fcl-react-native.ts index cd0a06dff..bc11379fa 100644 --- a/packages/fcl-react-native/src/fcl-react-native.ts +++ b/packages/fcl-react-native/src/fcl-react-native.ts @@ -90,25 +90,25 @@ export const logIn = (opts = {}) => currentUser().authenticate(opts) export const authz = currentUser().authorization -import { config } from "@onflow/config" +import {config} from "@onflow/config" import { coreStrategies, getDefaultConfig, useServiceDiscovery, ServiceDiscovery, } from "./utils/react-native" -import { getAsyncStorage } from "./utils/react-native/storage" +import {getAsyncStorage} from "./utils/react-native/storage" config(getDefaultConfig()) // Set chain id default on access node change -initServiceRegistry({ coreStrategies }) +initServiceRegistry({coreStrategies}) // Set isReactNative flag setIsReactNative(true) -export { useServiceDiscovery, ServiceDiscovery } +export {useServiceDiscovery, ServiceDiscovery} // Subscriptions -export { subscribe } from "@onflow/fcl-core" -export { subscribeRaw } from "@onflow/fcl-core" +export {subscribe} from "@onflow/fcl-core" +export {subscribeRaw} from "@onflow/fcl-core" diff --git a/packages/fcl-wagmi-adapter/package.json b/packages/fcl-wagmi-adapter/package.json index ebf0b28d2..a35b3cf3f 100644 --- a/packages/fcl-wagmi-adapter/package.json +++ b/packages/fcl-wagmi-adapter/package.json @@ -47,4 +47,4 @@ "@onflow/fcl": "1.18.0", "@wagmi/core": "^2.16.3" } -} \ No newline at end of file +} diff --git a/packages/fcl-wc/package.json b/packages/fcl-wc/package.json index a062d52bf..b39cd7698 100644 --- a/packages/fcl-wc/package.json +++ b/packages/fcl-wc/package.json @@ -54,4 +54,4 @@ "peerDependencies": { "@onflow/fcl-core": "1.19.0" } -} \ No newline at end of file +} diff --git a/packages/fcl/package.json b/packages/fcl/package.json index d2ebdfb99..fbf699d26 100644 --- a/packages/fcl/package.json +++ b/packages/fcl/package.json @@ -69,4 +69,4 @@ "events": "^3.3.0", "sha3": "^2.1.4" } -} \ No newline at end of file +} diff --git a/packages/fcl/src/fcl.ts b/packages/fcl/src/fcl.ts index 69bacbdcc..78508a077 100644 --- a/packages/fcl/src/fcl.ts +++ b/packages/fcl/src/fcl.ts @@ -74,7 +74,7 @@ import { StorageProvider, } from "@onflow/fcl-core" -import { execStrategyHook } from "./discovery/exec-hook" +import {execStrategyHook} from "./discovery/exec-hook" const discoveryOpts = { execStrategy: execStrategyHook, } @@ -101,19 +101,19 @@ export const logIn = (opts = {}) => currentUser().authenticate(opts) export const authz = currentUser().authorization -import { config } from "@onflow/config" -import { getDefaultConfig, coreStrategies, LOCAL_STORAGE } from "./utils/web" -import { initFclWcLoader } from "./utils/walletconnect/loader" +import {config} from "@onflow/config" +import {getDefaultConfig, coreStrategies, LOCAL_STORAGE} from "./utils/web" +import {initFclWcLoader} from "./utils/walletconnect/loader" config(getDefaultConfig()) -initServiceRegistry({ coreStrategies }) +initServiceRegistry({coreStrategies}) // Automatically load fcl-wc plugin // Based on the user's config initFclWcLoader() -export { LOCAL_STORAGE, SESSION_STORAGE } from "./utils/web" +export {LOCAL_STORAGE, SESSION_STORAGE} from "./utils/web" // Subscriptions -export { subscribe, subscribeRaw } from "@onflow/fcl-core" +export {subscribe, subscribeRaw} from "@onflow/fcl-core" diff --git a/packages/kit/package.json b/packages/kit/package.json index 616c16815..c90983261 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -56,4 +56,4 @@ "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } -} \ No newline at end of file +} diff --git a/packages/kit/src/hooks/index.ts b/packages/kit/src/hooks/index.ts index 4ff35112a..30033aa51 100644 --- a/packages/kit/src/hooks/index.ts +++ b/packages/kit/src/hooks/index.ts @@ -1,13 +1,13 @@ -export { useCurrentFlowUser } from "./useCurrentFlowUser" -export { useFlowAccount } from "./useFlowAccount" -export { useFlowBlock } from "./useFlowBlock" -export { useFlowConfig } from "./useFlowConfig" -export { useFlowEvents } from "./useFlowEvents" -export { useFlowMutate } from "./useFlowMutate" -export { useFlowQuery } from "./useFlowQuery" -export { useFlowRevertibleRandom } from "./useFlowRevertibleRandom" -export { useCrossVmBatchTransaction } from "./useCrossVmBatchTransaction" -export { useCrossVmTokenBalance } from "./useCrossVmTokenBalance" -export { useFlowTransactionStatus } from "./useFlowTransactionStatus" -export { useCrossVmSpendNft } from "./useCrossVmSpendNft" -export { useCrossVmSpendToken } from "./useCrossVmSpendToken" +export {useCurrentFlowUser} from "./useCurrentFlowUser" +export {useFlowAccount} from "./useFlowAccount" +export {useFlowBlock} from "./useFlowBlock" +export {useFlowConfig} from "./useFlowConfig" +export {useFlowEvents} from "./useFlowEvents" +export {useFlowMutate} from "./useFlowMutate" +export {useFlowQuery} from "./useFlowQuery" +export {useFlowRevertibleRandom} from "./useFlowRevertibleRandom" +export {useCrossVmBatchTransaction} from "./useCrossVmBatchTransaction" +export {useCrossVmTokenBalance} from "./useCrossVmTokenBalance" +export {useFlowTransactionStatus} from "./useFlowTransactionStatus" +export {useCrossVmSpendNft} from "./useCrossVmSpendNft" +export {useCrossVmSpendToken} from "./useCrossVmSpendToken" diff --git a/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts b/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts index 68c5f4d43..1097aac67 100644 --- a/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts +++ b/packages/kit/src/hooks/useCrossVmBatchTransaction.test.ts @@ -1,12 +1,12 @@ -import { renderHook, act, waitFor } from "@testing-library/react" +import {renderHook, act, waitFor} from "@testing-library/react" import * as fcl from "@onflow/fcl" -import { FlowProvider } from "../provider" +import {FlowProvider} from "../provider" import { encodeCalls, getCadenceBatchTransaction, useCrossVmBatchTransaction, } from "./useCrossVmBatchTransaction" -import { useFlowChainId } from "./useFlowChainId" +import {useFlowChainId} from "./useFlowChainId" jest.mock("@onflow/fcl", () => require("../__mocks__/fcl").default) jest.mock("viem", () => ({ @@ -21,7 +21,7 @@ describe("useBatchEvmTransaction", () => { const mockCalls = [ { address: "0x123", - abi: [{ type: "function", name: "test" } as any], + abi: [{type: "function", name: "test"} as any], functionName: "test", args: [1, 2], gasLimit: BigInt(100000), @@ -84,13 +84,13 @@ describe("useBatchEvmTransaction", () => { let result: any let rerender: any await act(async () => { - ; ({ result, rerender } = renderHook(useCrossVmBatchTransaction, { + ;({result, rerender} = renderHook(useCrossVmBatchTransaction, { wrapper: FlowProvider, })) }) await act(async () => { - await result.current.sendBatchTransaction({ calls: mockCalls }) + await result.current.sendBatchTransaction({calls: mockCalls}) rerender() }) @@ -106,14 +106,14 @@ describe("useBatchEvmTransaction", () => { let hookResult: any await act(async () => { - const { result } = renderHook(useCrossVmBatchTransaction, { + const {result} = renderHook(useCrossVmBatchTransaction, { wrapper: FlowProvider, }) hookResult = result }) await act(async () => { - await hookResult.current.sendBatchTransaction({ calls: mockCalls }) + await hookResult.current.sendBatchTransaction({calls: mockCalls}) }) await waitFor(() => expect(hookResult.current.isPending).toBe(false)) @@ -123,7 +123,7 @@ describe("useBatchEvmTransaction", () => { }) it("should handle missing chain ID", async () => { - ; (useFlowChainId as jest.Mock).mockReturnValue({ + ;(useFlowChainId as jest.Mock).mockReturnValue({ data: null, isLoading: false, }) @@ -131,14 +131,14 @@ describe("useBatchEvmTransaction", () => { let hookResult: any await act(async () => { - const { result } = renderHook(() => useCrossVmBatchTransaction(), { + const {result} = renderHook(() => useCrossVmBatchTransaction(), { wrapper: FlowProvider, }) hookResult = result }) await act(async () => { - await hookResult.current.sendBatchTransaction({ calls: mockCalls }) + await hookResult.current.sendBatchTransaction({calls: mockCalls}) }) await waitFor(() => expect(hookResult.current.isError).toBe(true)) @@ -146,7 +146,7 @@ describe("useBatchEvmTransaction", () => { }) it("should handle loading chain ID", async () => { - ; (useFlowChainId as jest.Mock).mockReturnValue({ + ;(useFlowChainId as jest.Mock).mockReturnValue({ data: null, isLoading: true, }) @@ -154,7 +154,7 @@ describe("useBatchEvmTransaction", () => { let hookResult: any await act(async () => { - const { result } = renderHook(() => useCrossVmBatchTransaction(), { + const {result} = renderHook(() => useCrossVmBatchTransaction(), { wrapper: FlowProvider, }) hookResult = result @@ -169,19 +169,19 @@ describe("useBatchEvmTransaction", () => { }) it("should handle mutation error", async () => { - ; (fcl.mutate as jest.Mock).mockRejectedValue(new Error("Mutation failed")) + ;(fcl.mutate as jest.Mock).mockRejectedValue(new Error("Mutation failed")) let hookResult: any await act(async () => { - const { result } = renderHook(() => useCrossVmBatchTransaction(), { + const {result} = renderHook(() => useCrossVmBatchTransaction(), { wrapper: FlowProvider, }) hookResult = result }) await act(async () => { - await hookResult.current.sendBatchTransaction({ calls: mockCalls }) + await hookResult.current.sendBatchTransaction({calls: mockCalls}) }) await waitFor(() => expect(hookResult.current.isError).toBe(true)) diff --git a/packages/kit/src/hooks/useCrossVmBatchTransaction.ts b/packages/kit/src/hooks/useCrossVmBatchTransaction.ts index 9cc855b0e..b090c8f90 100644 --- a/packages/kit/src/hooks/useCrossVmBatchTransaction.ts +++ b/packages/kit/src/hooks/useCrossVmBatchTransaction.ts @@ -1,5 +1,5 @@ import * as fcl from "@onflow/fcl" -import { Abi, encodeFunctionData } from "viem" +import {Abi, encodeFunctionData} from "viem" import { UseMutateAsyncFunction, UseMutateFunction, @@ -7,9 +7,9 @@ import { UseMutationOptions, UseMutationResult, } from "@tanstack/react-query" -import { useFlowChainId } from "./useFlowChainId" -import { useFlowQueryClient } from "../provider/FlowQueryClient" -import { DEFAULT_EVM_GAS_LIMIT } from "../constants" +import {useFlowChainId} from "./useFlowChainId" +import {useFlowQueryClient} from "../provider/FlowQueryClient" +import {DEFAULT_EVM_GAS_LIMIT} from "../constants" interface UseCrossVmBatchTransactionMutateArgs { calls: EvmBatchCall[] @@ -57,7 +57,7 @@ export interface EvmBatchCall { export function encodeCalls( calls: EvmBatchCall[] -): Array<{ to: string; data: string; gasLimit: string; value: string }> { +): Array<{to: string; data: string; gasLimit: string; value: string}> { return calls.map(call => { const encodedData = encodeFunctionData({ abi: call.abi, @@ -164,20 +164,20 @@ export function useCrossVmBatchTransaction({ args: (arg, t) => [ arg( encodedCalls.map(call => [ - { key: "to", value: call.to }, - { key: "data", value: call.data }, + {key: "to", value: call.to}, + {key: "data", value: call.data}, { key: "gasLimit", value: call.gasLimit, }, - { key: "value", value: call.value }, + {key: "value", value: call.value}, ]), t.Array( t.Dictionary([ - { key: t.String, value: t.String }, - { key: t.String, value: t.String }, - { key: t.String, value: t.UInt64 }, - { key: t.String, value: t.UInt }, + {key: t.String, value: t.String}, + {key: t.String, value: t.String}, + {key: t.String, value: t.UInt64}, + {key: t.String, value: t.UInt}, ] as any) ) ), diff --git a/packages/kit/src/hooks/useFlowChainId.test.ts b/packages/kit/src/hooks/useFlowChainId.test.ts index 998ee32ee..b3e5424a0 100644 --- a/packages/kit/src/hooks/useFlowChainId.test.ts +++ b/packages/kit/src/hooks/useFlowChainId.test.ts @@ -1,7 +1,7 @@ -import { renderHook, act, waitFor } from "@testing-library/react" +import {renderHook, act, waitFor} from "@testing-library/react" import * as fcl from "@onflow/fcl" -import { FlowProvider } from "../provider" -import { useFlowChainId } from "./useFlowChainId" +import {FlowProvider} from "../provider" +import {useFlowChainId} from "./useFlowChainId" jest.mock("@onflow/fcl", () => require("../__mocks__/fcl").default) @@ -19,7 +19,7 @@ describe("useFlowChainId", () => { let hookResult: any await act(async () => { - const { result } = renderHook(() => useFlowChainId(), { + const {result} = renderHook(() => useFlowChainId(), { wrapper: FlowProvider, }) hookResult = result @@ -44,7 +44,7 @@ describe("useFlowChainId", () => { let hookResult: any await act(async () => { - const { result } = renderHook(() => useFlowChainId(), { + const {result} = renderHook(() => useFlowChainId(), { wrapper: FlowProvider, }) hookResult = result @@ -64,7 +64,7 @@ describe("useFlowChainId", () => { let hookResult: any await act(async () => { - const { result } = renderHook(() => useFlowChainId(), { + const {result} = renderHook(() => useFlowChainId(), { wrapper: FlowProvider, }) hookResult = result @@ -96,8 +96,8 @@ describe("useFlowChainId", () => { let hookResult: any await act(async () => { - const { result } = renderHook( - () => useFlowChainId({ query: customOptions }), + const {result} = renderHook( + () => useFlowChainId({query: customOptions}), { wrapper: FlowProvider, } diff --git a/packages/kit/src/hooks/useFlowChainId.ts b/packages/kit/src/hooks/useFlowChainId.ts index 88f7f96e0..7a20bafef 100644 --- a/packages/kit/src/hooks/useFlowChainId.ts +++ b/packages/kit/src/hooks/useFlowChainId.ts @@ -1,8 +1,8 @@ import * as fcl from "@onflow/fcl" -import { useQuery, UseQueryOptions, UseQueryResult } from "@tanstack/react-query" -import { useFlowQueryClient } from "../provider/FlowQueryClient" -import { useCallback } from "react" -import { useFlowConfig } from "./useFlowConfig" +import {useQuery, UseQueryOptions, UseQueryResult} from "@tanstack/react-query" +import {useFlowQueryClient} from "../provider/FlowQueryClient" +import {useCallback} from "react" +import {useFlowConfig} from "./useFlowConfig" interface UseFlowChainIdArgs { query?: Omit, "queryKey" | "queryFn"> diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 1fe939b8b..af5bb5af6 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -56,4 +56,4 @@ "sha3": "^2.1.4", "uuid": "^9.0.1" } -} \ No newline at end of file +} diff --git a/packages/sdk/src/sdk.ts b/packages/sdk/src/sdk.ts index 9667fb047..f86ee7e8c 100644 --- a/packages/sdk/src/sdk.ts +++ b/packages/sdk/src/sdk.ts @@ -1,14 +1,14 @@ import * as logger from "@onflow/util-logger" // Base -export { build } from "./build/build" -export { resolve } from "./resolve/resolve" +export {build} from "./build/build" +export {resolve} from "./resolve/resolve" export { send, subscribe, subscribeRaw, SubscriptionsNotSupportedError, } from "./transport" -export { decode } from "./decode/sdk-decode" +export {decode} from "./decode/sdk-decode" export { encodeTransactionPayload, encodeTransactionEnvelope, @@ -41,66 +41,66 @@ export { isGetNetworkParameters, isGetNodeVersionInfo, } from "./interaction/interaction" -import type { CadenceArgument } from "./interaction/interaction" -export { CadenceArgument } // Workaround for babel https://github.com/babel/babel/issues/8361 -import type { InteractionBuilderFn } from "./interaction/interaction" -export { InteractionBuilderFn } +import type {CadenceArgument} from "./interaction/interaction" +export {CadenceArgument} // Workaround for babel https://github.com/babel/babel/issues/8361 +import type {InteractionBuilderFn} from "./interaction/interaction" +export {InteractionBuilderFn} -export { createSignableVoucher, voucherToTxId } from "./resolve/voucher" -export { encodeMessageFromSignable } from "./wallet-utils/encode-signable" -export { template as cadence } from "@onflow/util-template" -export { template as cdc } from "@onflow/util-template" +export {createSignableVoucher, voucherToTxId} from "./resolve/voucher" +export {encodeMessageFromSignable} from "./wallet-utils/encode-signable" +export {template as cadence} from "@onflow/util-template" +export {template as cdc} from "@onflow/util-template" -import type { Voucher } from "./wallet-utils/encode-signable" -export { Voucher } +import type {Voucher} from "./wallet-utils/encode-signable" +export {Voucher} // Helpers -export { account } from "./account/account" -export { block } from "./block/block" -export { nodeVersionInfo } from "./node-version-info/node-version-info" +export {account} from "./account/account" +export {block} from "./block/block" +export {nodeVersionInfo} from "./node-version-info/node-version-info" // Builders -export { authorizations, authorization } from "./build/build-authorizations" -export { atBlockHeight } from "./build/build-at-block-height" -export { atBlockId } from "./build/build-at-block-id" -export { atLatestBlock } from "./build/build-at-latest-block" -export { getAccount } from "./build/build-get-account" -export { getEvents } from "./build/build-get-events" -export { getEventsAtBlockHeightRange } from "./build/build-get-events-at-block-height-range" -export { getEventsAtBlockIds } from "./build/build-get-events-at-block-ids" -export { getBlock } from "./build/build-get-block" -export { getBlockHeader } from "./build/build-get-block-header" -export { getCollection } from "./build/build-get-collection" -export { getTransactionStatus } from "./build/build-get-transaction-status" -export { getTransaction } from "./build/build-get-transaction" -export { getNetworkParameters } from "./build/build-get-network-parameters" -export { getNodeVersionInfo } from "./build/build-get-node-version-info" -export { limit } from "./build/build-limit" -export { args, arg } from "./build/build-arguments" -export { proposer } from "./build/build-proposer" -export { payer } from "./build/build-payer" -export { ping } from "./build/build-ping" -export { ref } from "./build/build-ref" -export { script } from "./build/build-script" -export { transaction } from "./build/build-transaction" -export { validator } from "./build/build-validator" -export { invariant } from "./build/build-invariant" -export { voucherIntercept } from "./build/build-voucher-intercept" -export { subscribeEvents } from "./build/build-subscribe-events" +export {authorizations, authorization} from "./build/build-authorizations" +export {atBlockHeight} from "./build/build-at-block-height" +export {atBlockId} from "./build/build-at-block-id" +export {atLatestBlock} from "./build/build-at-latest-block" +export {getAccount} from "./build/build-get-account" +export {getEvents} from "./build/build-get-events" +export {getEventsAtBlockHeightRange} from "./build/build-get-events-at-block-height-range" +export {getEventsAtBlockIds} from "./build/build-get-events-at-block-ids" +export {getBlock} from "./build/build-get-block" +export {getBlockHeader} from "./build/build-get-block-header" +export {getCollection} from "./build/build-get-collection" +export {getTransactionStatus} from "./build/build-get-transaction-status" +export {getTransaction} from "./build/build-get-transaction" +export {getNetworkParameters} from "./build/build-get-network-parameters" +export {getNodeVersionInfo} from "./build/build-get-node-version-info" +export {limit} from "./build/build-limit" +export {args, arg} from "./build/build-arguments" +export {proposer} from "./build/build-proposer" +export {payer} from "./build/build-payer" +export {ping} from "./build/build-ping" +export {ref} from "./build/build-ref" +export {script} from "./build/build-script" +export {transaction} from "./build/build-transaction" +export {validator} from "./build/build-validator" +export {invariant} from "./build/build-invariant" +export {voucherIntercept} from "./build/build-voucher-intercept" +export {subscribeEvents} from "./build/build-subscribe-events" // Resolvers -export { resolveCadence } from "./resolve/resolve-cadence" -export { resolveFinalNormalization } from "./resolve/resolve-final-normalization" -export { resolveProposerSequenceNumber } from "./resolve/resolve-proposer-sequence-number" -export { resolveArguments } from "./resolve/resolve-arguments" -export { resolveAccounts } from "./resolve/resolve-accounts" -export { response } from "./response/response" -export { resolveSignatures } from "./resolve/resolve-signatures" -export { resolveValidators } from "./resolve/resolve-validators" -export { resolveRefBlockId } from "./resolve/resolve-ref-block-id" -export { resolveVoucherIntercept } from "./resolve/resolve-voucher-intercept" +export {resolveCadence} from "./resolve/resolve-cadence" +export {resolveFinalNormalization} from "./resolve/resolve-final-normalization" +export {resolveProposerSequenceNumber} from "./resolve/resolve-proposer-sequence-number" +export {resolveArguments} from "./resolve/resolve-arguments" +export {resolveAccounts} from "./resolve/resolve-accounts" +export {response} from "./response/response" +export {resolveSignatures} from "./resolve/resolve-signatures" +export {resolveValidators} from "./resolve/resolve-validators" +export {resolveRefBlockId} from "./resolve/resolve-ref-block-id" +export {resolveVoucherIntercept} from "./resolve/resolve-voucher-intercept" -export { config } from "@onflow/config" +export {config} from "@onflow/config" // Deprecated export const params = (params: never) => @@ -121,13 +121,13 @@ export const param = (params: never) => }) import * as TestUtils from "./test-utils" -export { TestUtils } +export {TestUtils} -export { VERSION } from "./VERSION" +export {VERSION} from "./VERSION" -export { flowMainnet, flowTestnet, flowEmulator } from "./constants" +export {flowMainnet, flowTestnet, flowEmulator} from "./constants" export * from "@onflow/typedefs" import * as types from "@onflow/types" -export { types as t } +export {types as t} diff --git a/packages/sdk/src/transport/index.ts b/packages/sdk/src/transport/index.ts index 66a76fe49..c3bd97ba7 100644 --- a/packages/sdk/src/transport/index.ts +++ b/packages/sdk/src/transport/index.ts @@ -1,5 +1,5 @@ -export { send } from "./send/send" -export { subscribe } from "./subscribe/subscribe" -export { subscribeRaw } from "./subscribe/subscribe-raw" -export { SubscriptionsNotSupportedError } from "./subscribe/errors" +export {send} from "./send/send" +export {subscribe} from "./subscribe/subscribe" +export {subscribeRaw} from "./subscribe/subscribe-raw" +export {SubscriptionsNotSupportedError} from "./subscribe/errors" export * from "./subscribe/types" diff --git a/packages/sdk/src/transport/subscribe/subscribe.test.ts b/packages/sdk/src/transport/subscribe/subscribe.test.ts index 5cf26e127..1ed191aa4 100644 --- a/packages/sdk/src/transport/subscribe/subscribe.test.ts +++ b/packages/sdk/src/transport/subscribe/subscribe.test.ts @@ -4,8 +4,8 @@ import { SubscriptionTopic, SdkTransport, } from "@onflow/typedefs" -import { subscribe } from "./subscribe" -import { subscribeRaw } from "./subscribe-raw" +import {subscribe} from "./subscribe" +import {subscribeRaw} from "./subscribe-raw" jest.mock("./subscribe-raw") const mocksubscribeRaw = jest.mocked(subscribeRaw) @@ -22,7 +22,7 @@ describe("subscribe", () => { test("subscribes to a topic and returns a subscription", async () => { const topic = "topic" as SubscriptionTopic - const args = { foo: "bar" } as SubscriptionArgs + const args = {foo: "bar"} as SubscriptionArgs const onData = jest.fn() const onError = jest.fn() @@ -36,14 +36,14 @@ describe("subscribe", () => { expect(sub).toBe(mockSub) expect(mocksubscribeRaw).toHaveBeenCalledTimes(1) expect(mocksubscribeRaw).toHaveBeenCalledWith( - { topic, args, onData: expect.any(Function), onError }, + {topic, args, onData: expect.any(Function), onError}, {} ) }) test("unsubscribes from a subscription", async () => { const topic = "topic" as SubscriptionTopic - const args = { foo: "bar" } as SubscriptionArgs + const args = {foo: "bar"} as SubscriptionArgs const onData = jest.fn() const onError = jest.fn() @@ -61,7 +61,7 @@ describe("subscribe", () => { test("subscribes to a topic with a node", async () => { const topic = "topic" as SubscriptionTopic - const args = { foo: "bar" } as SubscriptionArgs + const args = {foo: "bar"} as SubscriptionArgs const onData = jest.fn() const onError = jest.fn() @@ -74,20 +74,20 @@ describe("subscribe", () => { onData, onError, }, - { node } + {node} ) expect(sub).toBe(mockSub) expect(mocksubscribeRaw).toHaveBeenCalledTimes(1) expect(mocksubscribeRaw).toHaveBeenCalledWith( - { topic, args, onData: expect.any(Function), onError }, - { node } + {topic, args, onData: expect.any(Function), onError}, + {node} ) }) test("subscribes to a topic with custom node and transport", async () => { const topic = "topic" as SubscriptionTopic - const args = { foo: "bar" } as SubscriptionArgs + const args = {foo: "bar"} as SubscriptionArgs const onData = jest.fn() const onError = jest.fn() @@ -104,14 +104,14 @@ describe("subscribe", () => { onData, onError, }, - { node, transport } + {node, transport} ) expect(sub).toBe(mockSub) expect(mocksubscribeRaw).toHaveBeenCalledTimes(1) expect(mocksubscribeRaw).toHaveBeenCalledWith( - { topic, args, onData: expect.any(Function), onError }, - { node, transport } + {topic, args, onData: expect.any(Function), onError}, + {node, transport} ) }) }) diff --git a/packages/sdk/src/transport/subscribe/subscribe.ts b/packages/sdk/src/transport/subscribe/subscribe.ts index 3227f934e..51dfa53c3 100644 --- a/packages/sdk/src/transport/subscribe/subscribe.ts +++ b/packages/sdk/src/transport/subscribe/subscribe.ts @@ -1,7 +1,7 @@ -import { SdkTransport, Subscription, SubscriptionTopic } from "@onflow/typedefs" -import { subscribeRaw } from "./subscribe-raw" -import { decodeResponse } from "../../decode/decode" -import { SubscribeParams } from "./types" +import {SdkTransport, Subscription, SubscriptionTopic} from "@onflow/typedefs" +import {subscribeRaw} from "./subscribe-raw" +import {decodeResponse} from "../../decode/decode" +import {SubscribeParams} from "./types" /** * Subscribe to a topic and decode the data. @@ -10,7 +10,7 @@ import { SubscribeParams } from "./types" * @returns A promise that resolves when the subscription is active. */ export function subscribe( - { topic, args, onData, onError }: SubscribeParams, + {topic, args, onData, onError}: SubscribeParams, opts: { node?: string transport?: SdkTransport diff --git a/packages/transport-grpc/package.json b/packages/transport-grpc/package.json index 657bdfb5c..1bb6f07ac 100644 --- a/packages/transport-grpc/package.json +++ b/packages/transport-grpc/package.json @@ -39,4 +39,4 @@ "@onflow/util-invariant": "1.2.4", "@onflow/util-template": "1.2.3" } -} \ No newline at end of file +} diff --git a/packages/transport-http/package.json b/packages/transport-http/package.json index 3d1d42c3f..d61fd54b3 100644 --- a/packages/transport-http/package.json +++ b/packages/transport-http/package.json @@ -47,4 +47,4 @@ "isomorphic-ws": "^5.0.0", "ws": "^8.18.0" } -} \ No newline at end of file +} diff --git a/packages/typedefs/package.json b/packages/typedefs/package.json index c73df4f7d..79d2fe9ad 100644 --- a/packages/typedefs/package.json +++ b/packages/typedefs/package.json @@ -37,4 +37,4 @@ "dependencies": { "@babel/runtime": "^7.25.7" } -} \ No newline at end of file +} From 110766f17f3292c39d08cad5c6204f50015be22e Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 13 Jun 2025 14:56:14 -0700 Subject: [PATCH 66/72] Run install --- package-lock.json | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 76e6033dd..a802095e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28695,7 +28695,6 @@ "node_modules/sucrase": { "version": "3.34.0", "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -28716,7 +28715,6 @@ "node_modules/sucrase/node_modules/brace-expansion": { "version": "1.1.11", "license": "MIT", - "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -28725,7 +28723,6 @@ "node_modules/sucrase/node_modules/commander": { "version": "4.1.1", "license": "MIT", - "peer": true, "engines": { "node": ">= 6" } @@ -28733,7 +28730,6 @@ "node_modules/sucrase/node_modules/glob": { "version": "7.1.6", "license": "ISC", - "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -28751,13 +28747,11 @@ }, "node_modules/sucrase/node_modules/lines-and-columns": { "version": "1.2.4", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/sucrase/node_modules/minimatch": { "version": "3.1.2", "license": "ISC", - "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -31701,7 +31695,7 @@ }, "packages/kit": { "name": "@onflow/kit", - "version": "0.3.1", + "version": "0.4.0", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", From f6fbbf8ce629a525980e4f02582e5adaed165dad Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Fri, 13 Jun 2025 14:57:13 -0700 Subject: [PATCH 67/72] Update packages/fcl-core/CHANGELOG.md Co-authored-by: Michael Fabozzi <39808567+mfbz@users.noreply.github.com> --- packages/fcl-core/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/fcl-core/CHANGELOG.md b/packages/fcl-core/CHANGELOG.md index 7aa1becfb..c18bb4d68 100644 --- a/packages/fcl-core/CHANGELOG.md +++ b/packages/fcl-core/CHANGELOG.md @@ -6,7 +6,7 @@ - [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `subscribeRaw`. - These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. + These are only available when using a REST API endpoint and not supported by the deprecated GRPC transport. The following topics are now available: From 7735281bfc1026b56a2704c0be0c4e479ed7c0d0 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 13 Jun 2025 14:59:37 -0700 Subject: [PATCH 68/72] Fix import --- packages/sdk/src/transport/subscribe/raw-subscribe.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sdk/src/transport/subscribe/raw-subscribe.ts b/packages/sdk/src/transport/subscribe/raw-subscribe.ts index f02a4f8d9..b51530dfd 100644 --- a/packages/sdk/src/transport/subscribe/raw-subscribe.ts +++ b/packages/sdk/src/transport/subscribe/raw-subscribe.ts @@ -2,7 +2,7 @@ import {config} from "@onflow/config" import {SdkTransport, SubscriptionTopic} from "@onflow/typedefs" import {getTransport} from "../get-transport" import {invariant} from "@onflow/util-invariant" -import {RawSubscribeParams} from "./types" +import {SubscribeRawParams} from "./types" /** * Subscribe to a topic without decoding the data. @@ -11,7 +11,7 @@ import {RawSubscribeParams} from "./types" * @returns A promise that resolves once the subscription is active. */ export function rawSubscribe( - {topic, args, onData, onError}: RawSubscribeParams, + {topic, args, onData, onError}: SubscribeRawParams, opts: { node?: string transport?: SdkTransport From 7527700bce83c7a0e1eaf575da074b0fa1089ff3 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 13 Jun 2025 15:01:52 -0700 Subject: [PATCH 69/72] Add tailwind merge --- package-lock.json | 11 +++++++++++ packages/kit/package.json | 1 + 2 files changed, 12 insertions(+) diff --git a/package-lock.json b/package-lock.json index a802095e5..fe68196cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28851,6 +28851,16 @@ "version": "6.2.0", "license": "MIT" }, + "node_modules/tailwind-merge": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", + "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { "version": "3.4.17", "license": "MIT", @@ -31702,6 +31712,7 @@ "@headlessui/react": "^2.2.2", "@tanstack/react-query": "^5.67.3", "@testing-library/react": "^16.2.0", + "tailwind-merge": "^3.3.1", "viem": "^2.29.2" }, "devDependencies": { diff --git a/packages/kit/package.json b/packages/kit/package.json index c90983261..608624cac 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -49,6 +49,7 @@ "@headlessui/react": "^2.2.2", "@tanstack/react-query": "^5.67.3", "@testing-library/react": "^16.2.0", + "tailwind-merge": "^3.3.1", "viem": "^2.29.2" }, "peerDependencies": { From 99f3592d1aa901dda4d47d17d20ebe460fbda226 Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Fri, 13 Jun 2025 15:09:35 -0700 Subject: [PATCH 70/72] Update packages/fcl-react-native/CHANGELOG.md Co-authored-by: Michael Fabozzi <39808567+mfbz@users.noreply.github.com> --- packages/fcl-react-native/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/fcl-react-native/CHANGELOG.md b/packages/fcl-react-native/CHANGELOG.md index 20e459360..ce41c0fcb 100644 --- a/packages/fcl-react-native/CHANGELOG.md +++ b/packages/fcl-react-native/CHANGELOG.md @@ -6,7 +6,7 @@ - [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `subscribeRaw`. - These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. + These are only available when using a REST API endpoint and not supported by the deprecated GRPC transport. The following topics are now available: From 924726f6b590a065ca3e509471ab685b0c6c3bb9 Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Fri, 13 Jun 2025 15:09:55 -0700 Subject: [PATCH 71/72] Update packages/fcl/CHANGELOG.md Co-authored-by: Michael Fabozzi <39808567+mfbz@users.noreply.github.com> --- packages/fcl/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/fcl/CHANGELOG.md b/packages/fcl/CHANGELOG.md index c5eeddf8f..41a723f7d 100644 --- a/packages/fcl/CHANGELOG.md +++ b/packages/fcl/CHANGELOG.md @@ -6,7 +6,7 @@ - [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `subscribeRaw`. - These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. + These are only available when using a REST API endpoint and not supported by the deprecated GRPC transport. The following topics are now available: From 34f6a43c93f16da4ae2a54ae8a1f880d390246dd Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Fri, 13 Jun 2025 15:23:50 -0700 Subject: [PATCH 72/72] Update packages/sdk/CHANGELOG.md Co-authored-by: Michael Fabozzi <39808567+mfbz@users.noreply.github.com> --- packages/sdk/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index 50fc62b13..206f8a756 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -6,7 +6,7 @@ - [#2201](https://github.com/onflow/fcl-js/pull/2201) [`b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab`](https://github.com/onflow/fcl-js/commit/b9c4ed3b95c2dc73698e45f353a6ef9a48f23cab) Thanks [@jribbink](https://github.com/jribbink)! - Add real-time streaming methods `subscribe` and `subscribeRaw`. - These are only available when using a REST API endpoint and not supported by the deprecated GRPC trasnport. + These are only available when using a REST API endpoint and not supported by the deprecated GRPC transport. The following topics are now available: