diff --git a/apps/desktop/src/utils/beacon/SignPayloadRequestModal.test.tsx b/apps/desktop/src/utils/beacon/SignPayloadRequestModal.test.tsx index 8bb15b646a..3600c8f2cf 100644 --- a/apps/desktop/src/utils/beacon/SignPayloadRequestModal.test.tsx +++ b/apps/desktop/src/utils/beacon/SignPayloadRequestModal.test.tsx @@ -51,7 +51,7 @@ describe("", () => { it("renders the payload to sign", async () => { render(, { store }); - await waitFor(() => expect(screen.getByText(decodedPayload)).toBeVisible()); + await waitFor(() => expect(screen.getByText(new RegExp(decodedPayload))).toBeVisible()); }); it("sends the signed payload back to the DApp", async () => { diff --git a/apps/desktop/src/utils/beacon/SignPayloadRequestModal.tsx b/apps/desktop/src/utils/beacon/SignPayloadRequestModal.tsx index 4406adcec1..eecc43f44d 100644 --- a/apps/desktop/src/utils/beacon/SignPayloadRequestModal.tsx +++ b/apps/desktop/src/utils/beacon/SignPayloadRequestModal.tsx @@ -5,12 +5,14 @@ import { } from "@airgap/beacon-wallet"; import { Box, + Flex, Heading, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, + Switch, Text, useToast, } from "@chakra-ui/react"; @@ -18,8 +20,10 @@ import { type TezosToolkit } from "@taquito/taquito"; import { useDynamicModalContext } from "@umami/components"; import { decodeBeaconPayload } from "@umami/core"; import { WalletClient, useGetImplicitAccount } from "@umami/state"; +import { useState } from "react"; import { FormProvider, useForm } from "react-hook-form"; +import { WarningIcon } from "../../assets/icons"; import { SignButton } from "../../components/SendFlow/SignButton"; import colors from "../../style/colors"; @@ -29,6 +33,12 @@ export const SignPayloadRequestModal = ({ request }: { request: SignPayloadReque const signerAccount = getAccount(request.sourceAddress); const toast = useToast(); const form = useForm(); + const [showRaw, setShowRaw] = useState(false); + + const { result: parsedPayload, error: parsingError } = decodeBeaconPayload( + request.payload, + request.signingType + ); const sign = async (tezosToolkit: TezosToolkit) => { const result = await tezosToolkit.signer.sign(request.payload); @@ -53,14 +63,21 @@ export const SignPayloadRequestModal = ({ request }: { request: SignPayloadReque - Connect with pairing request + {`${request.appMetadata.name}/dApp Pairing Request`} - - {`${request.appMetadata.name}/dApp Pairing Request`} - + + Payload + + {!parsingError && ( + + Raw + setShowRaw(val => !val)} /> + + )} + - {decodeBeaconPayload(request.payload)} + {showRaw ? request.payload : parsedPayload.trim()} + {parsingError && ( + + + + Raw Payload. Parsing failed + + + )} diff --git a/apps/desktop/src/utils/beacon/useHandleBeaconMessage.test.tsx b/apps/desktop/src/utils/beacon/useHandleBeaconMessage.test.tsx index e6efe33add..0347013a1c 100644 --- a/apps/desktop/src/utils/beacon/useHandleBeaconMessage.test.tsx +++ b/apps/desktop/src/utils/beacon/useHandleBeaconMessage.test.tsx @@ -106,7 +106,7 @@ describe("", () => { act(() => handleMessage(message)); - await screen.findByText("Connect with pairing request"); + await screen.findByText("mockDappName/dApp Pairing Request"); }); it("sends an error response to the dapp on close", async () => { @@ -127,7 +127,7 @@ describe("", () => { act(() => handleMessage(message)); - await screen.findByText("Connect with pairing request"); + await screen.findByText("mockDappName/dApp Pairing Request"); act(() => screen.getByRole("button", { name: "Close" }).click()); diff --git a/apps/web/src/components/beacon/SignPayloadRequestModal.test.tsx b/apps/web/src/components/beacon/SignPayloadRequestModal.test.tsx index 399f4a4f4e..9923d4dbe4 100644 --- a/apps/web/src/components/beacon/SignPayloadRequestModal.test.tsx +++ b/apps/web/src/components/beacon/SignPayloadRequestModal.test.tsx @@ -51,7 +51,7 @@ describe("", () => { it("renders the payload to sign", async () => { await renderInModal(, store); - await waitFor(() => expect(screen.getByText(decodedPayload)).toBeVisible()); + await waitFor(() => expect(screen.getByText(new RegExp(decodedPayload))).toBeVisible()); }); it("sends the signed payload back to the DApp", async () => { diff --git a/apps/web/src/components/beacon/SignPayloadRequestModal.tsx b/apps/web/src/components/beacon/SignPayloadRequestModal.tsx index 55e1577852..603f5aa78f 100644 --- a/apps/web/src/components/beacon/SignPayloadRequestModal.tsx +++ b/apps/web/src/components/beacon/SignPayloadRequestModal.tsx @@ -3,14 +3,17 @@ import { type SignPayloadRequestOutput, type SignPayloadResponseInput, } from "@airgap/beacon-wallet"; +import { WarningIcon } from "@chakra-ui/icons"; import { Box, + Flex, Heading, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, + Switch, Text, useToast, } from "@chakra-ui/react"; @@ -18,6 +21,7 @@ import { type TezosToolkit } from "@taquito/taquito"; import { useDynamicModalContext } from "@umami/components"; import { decodeBeaconPayload } from "@umami/core"; import { WalletClient, useGetImplicitAccount } from "@umami/state"; +import { useState } from "react"; import { FormProvider, useForm } from "react-hook-form"; import { SignButton } from "../../components/SendFlow/SignButton"; @@ -30,6 +34,12 @@ export const SignPayloadRequestModal = ({ request }: { request: SignPayloadReque const toast = useToast(); const form = useForm(); const color = useColor(); + const [showRaw, setShowRaw] = useState(false); + + const { result: parsedPayload, error: parsingError } = decodeBeaconPayload( + request.payload, + request.signingType + ); const sign = async (tezosToolkit: TezosToolkit) => { const result = await tezosToolkit.signer.sign(request.payload); @@ -54,14 +64,22 @@ export const SignPayloadRequestModal = ({ request }: { request: SignPayloadReque - Connect with pairing request + {`${request.appMetadata.name}/dApp Pairing Request`} - - {`${request.appMetadata.name}/dApp Pairing Request`} - + + Payload + + {!parsingError && ( + + Raw + setShowRaw(val => !val)} /> + + )} + + - {decodeBeaconPayload(request.payload)} + {showRaw ? request.payload : parsedPayload.trim()} + + {parsingError && ( + + + + Raw Payload. Parsing failed + + + )} diff --git a/apps/web/src/components/beacon/useHandleBeaconMessage.test.tsx b/apps/web/src/components/beacon/useHandleBeaconMessage.test.tsx index 5f56ac807c..b1a16cd6f9 100644 --- a/apps/web/src/components/beacon/useHandleBeaconMessage.test.tsx +++ b/apps/web/src/components/beacon/useHandleBeaconMessage.test.tsx @@ -106,7 +106,7 @@ describe("", () => { act(() => handleMessage(message)); - await screen.findByText("Connect with pairing request"); + await screen.findByText("mockDappName/dApp Pairing Request"); }); it("sends an error response to the dapp on close", async () => { @@ -127,7 +127,7 @@ describe("", () => { act(() => handleMessage(message)); - await screen.findByText("Connect with pairing request"); + await screen.findByText("mockDappName/dApp Pairing Request"); act(() => screen.getByRole("button", { name: "Close" }).click()); diff --git a/packages/core/package.json b/packages/core/package.json index 3dcad3789a..e86ae3ac42 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -61,6 +61,8 @@ }, "dependencies": { "@airgap/beacon-wallet": "^4.3.0", + "@taquito/local-forging": "^20.0.1", + "@taquito/michel-codec": "^20.0.1", "@taquito/rpc": "^20.0.1", "@taquito/signer": "^20.0.1", "@taquito/taquito": "^20.0.1", diff --git a/packages/core/src/decodeBeaconPayload.test.ts b/packages/core/src/decodeBeaconPayload.test.ts index 3e14cc8934..5ad39dcef2 100644 --- a/packages/core/src/decodeBeaconPayload.test.ts +++ b/packages/core/src/decodeBeaconPayload.test.ts @@ -1,37 +1,98 @@ +import { SigningType } from "@airgap/beacon-wallet"; + import { decodeBeaconPayload } from "./decodeBeaconPayload"; describe("decodeBeaconPayload", () => { + it("returns an error message if the payload is not a valid utf8", () => { + const payload = + "05010000004354657a6f73205369676e6564204d6573736167653a20496e76616c696420555446383a20c380c2afc3bfc3bec3bd3b204e6f6e7072696e7461626c653a20000115073b"; + + expect(decodeBeaconPayload(payload, SigningType.MICHELINE)).toEqual({ + result: payload, + error: "Cannot parse Beacon payload", + }); + }); + it("decodes a valid payload with '0501' prefix and padding", () => { const payload = "05010000004254657a6f73205369676e6564204d6573736167653a206d79646170702e636f6d20323032312d30312d31345431353a31363a30345a2048656c6c6f20776f726c6421"; const expected = "Tezos Signed Message: mydapp.com 2021-01-14T15:16:04Z Hello world!"; - expect(decodeBeaconPayload(payload)).toEqual(expected); + + expect(decodeBeaconPayload(payload, SigningType.MICHELINE)).toEqual({ result: expected }); }); - it("decodes a payload without '0501' prefix", () => { + it.each([SigningType.MICHELINE, SigningType.OPERATION])( + "throws without a valid prefix for %s", + signingType => { + const payload = + "010000004254657a6f73205369676e6564204d6573736167653a206d79646170702e636f6d20323032312d30312d31345431353a31363a30345a2048656c6c6f20776f726c6421"; + + expect(decodeBeaconPayload(payload, signingType)).toEqual({ + error: "Cannot parse Beacon payload", + result: + "010000004254657a6f73205369676e6564204d6573736167653a206d79646170702e636f6d20323032312d30312d31345431353a31363a30345a2048656c6c6f20776f726c6421", + }); + } + ); + + it("decodes a raw payload", () => { const payload = "54657a6f73205369676e6564204d6573736167653a206d79646170702e636f6d20323032312d30312d31345431353a31363a30345a2048656c6c6f20776f726c6421"; - const expected = "Tezos Signed Message: mydapp.com 2021-01-14T15:16:04Z Hello world!"; - expect(decodeBeaconPayload(payload)).toEqual(expected); + const expected = { + result: "Tezos Signed Message: mydapp.com 2021-01-14T15:16:04Z Hello world!", + }; + expect(decodeBeaconPayload(payload, SigningType.RAW)).toEqual(expected); + }); + + it("parses a Michelson expression", () => { + const raw = + "95564d877fe9b5d1f90ad501799e63d25ed0f676381b7b4678f404c9e1d8bd9a6c00e7cf51bc4b6068aae1f385c22c85ec281eba46ecac02ddfd940580bd3fe0d403c096b1020000e7cf51bc4b6068aae1f385c22c85ec281eba46ec00"; + const result = JSON.stringify({ + branch: "BLr3xAWdfd7BEnhUXU7vzcTBMy52upMWLiLDvwd8VdHyzKnmho4", + contents: [ + { + kind: "transaction", + source: "tz1gmj9EBXqQqQBmEVaCHBfunPJ67N82YJcz", + fee: "300", + counter: "10829533", + gas_limit: "1040000", + storage_limit: "60000", + amount: "5000000", + destination: "tz1gmj9EBXqQqQBmEVaCHBfunPJ67N82YJcz", + }, + ], + }); + + expect(decodeBeaconPayload(raw, SigningType.RAW)).toEqual({ result }); }); it("returns original payload if length is invalid", () => { - const payload = "05010000005254657a6f73205369676e6564204d6573736167653a20696e76616c69642e"; - expect(decodeBeaconPayload(payload)).toEqual(payload); + const payload = "050100000053254657a6f73205369676e6564204d6573736167653a20696e76616c69642e"; + expect(decodeBeaconPayload(payload, SigningType.RAW)).toEqual({ + result: payload, + error: "Cannot parse Beacon payload", + }); }); - it("returns original payload if an error occurs during decoding", () => { + it("can parse a message without a body", () => { const invalidPayload = "0501000000"; - expect(decodeBeaconPayload(invalidPayload)).toEqual(invalidPayload); + expect(decodeBeaconPayload(invalidPayload, SigningType.RAW)).toEqual({ + result: '{"branch":"JJhMAmr4o7mqnC","contents":[]}', + }); }); it("handles an empty payload", () => { const emptyPayload = ""; - expect(decodeBeaconPayload(emptyPayload)).toEqual(emptyPayload); + expect(decodeBeaconPayload(emptyPayload, SigningType.RAW)).toEqual({ + result: "", + }); }); it("handles a payload with non-hex characters", () => { const nonHexPayload = "0501ZZZZ"; - expect(decodeBeaconPayload(nonHexPayload)).toEqual(nonHexPayload); + expect(decodeBeaconPayload(nonHexPayload, SigningType.RAW)).toEqual({ + error: "Cannot parse Beacon payload", + result: "0501ZZZZ", + }); }); }); diff --git a/packages/core/src/decodeBeaconPayload.ts b/packages/core/src/decodeBeaconPayload.ts index cc1f641688..9dc620cb2f 100644 --- a/packages/core/src/decodeBeaconPayload.ts +++ b/packages/core/src/decodeBeaconPayload.ts @@ -1,45 +1,8 @@ -import { type SignPayloadRequestOutput } from "@airgap/beacon-wallet"; +import { SigningType } from "@airgap/beacon-wallet"; +import { CODEC, type ProtocolsHash, Uint8ArrayConsumer, getCodec } from "@taquito/local-forging"; +import { DefaultProtocol, unpackData } from "@taquito/michel-codec"; import { hex2buf } from "@taquito/utils"; -// Padding for a sign request payload in Micheline expression. -const PAYLOAD_PADDING = "0501"; - -const getPayloadHexBytes = (payload: SignPayloadRequestOutput["payload"]) => { - let index = 0; - - if (payload.startsWith(PAYLOAD_PADDING)) { - index = 4; - - while (index < payload.length && payload[index] === "0") { - index += 1; - } - - let payloadByteLengthRaw = ""; - let payloadByteLength = 0; - const paddingLength = index; - - while (index < payload.length && payload[index] !== "0") { - payloadByteLengthRaw += payload[index]; - payloadByteLength = parseInt(payloadByteLengthRaw, 16); - - const remainingPayloadLength = payload.length - payloadByteLengthRaw.length - paddingLength; - - if (payloadByteLength * 2 === remainingPayloadLength) { - index += 1; - break; - } - - if (payloadByteLength * 2 > remainingPayloadLength) { - throw new Error("Invalid payload length"); - } - - index += 1; - } - } - - return payload.slice(index); -}; - /** * Decodes a sign request payload string. * @@ -47,12 +10,54 @@ const getPayloadHexBytes = (payload: SignPayloadRequestOutput["payload"]) => { * @returns The decoded string, or the original payload if decoding fails. * @see {@link https://taquito.io/docs/signing/} for more info. */ -export const decodeBeaconPayload = (payload: SignPayloadRequestOutput["payload"]): string => { +export const decodeBeaconPayload = ( + payload: string, + signingType: SigningType +): { result: string; error?: string } => { try { - const string = new TextDecoder("utf-8").decode(hex2buf(getPayloadHexBytes(payload))); + if (!payload.length) { + return { result: "" }; + } + let result = payload; + + switch (signingType) { + case SigningType.MICHELINE: + case SigningType.OPERATION: { + const consumer = Uint8ArrayConsumer.fromHexString(payload); + const uint8array = consumer.consume(consumer.length()); + const parsed = unpackData(uint8array); + + if ("string" in parsed && Object.keys(parsed).length === 1) { + result = parsed.string; + } else { + result = JSON.stringify(parsed); + } + break; + } + case SigningType.RAW: { + try { + result = JSON.stringify(parseOperationMicheline(payload)); + } catch { + result = new TextDecoder("utf-8", { fatal: true }).decode(hex2buf(payload)); + } + break; + } + default: { + throw new Error(`Unsupported signing type: ${signingType}`); + } + } - return string || payload; - } catch (_) { - return payload; + if (!isValidASCII(result)) { + throw new Error("Invalid payload. Only ASCII characters are supported."); + } + + return { result }; + } catch { + return { result: payload, error: "Cannot parse Beacon payload" }; } }; + +const isValidASCII = (str: string) => str.split("").every(char => char.charCodeAt(0) < 128); + +const parseOperationMicheline = (payload: string) => + getCodec(CODEC.MANAGER, DefaultProtocol as string as ProtocolsHash).decoder(payload); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index de6ac35359..dc69e04943 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -880,7 +880,7 @@ importers: version: 2.5.2 jest-transformer-svg: specifier: ^2.0.2 - version: 2.0.2(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0))(react@18.3.1) + version: 2.0.2(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)))(react@18.3.1) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1010,7 +1010,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) lodash: specifier: ^4.17.21 version: 4.17.21 @@ -1038,6 +1038,12 @@ importers: '@airgap/beacon-wallet': specifier: ^4.3.0 version: 4.3.0 + '@taquito/local-forging': + specifier: ^20.0.1 + version: 20.0.1 + '@taquito/michel-codec': + specifier: ^20.0.1 + version: 20.0.1 '@taquito/rpc': specifier: ^20.0.1 version: 20.0.1(encoding@0.1.13) @@ -1107,7 +1113,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1165,7 +1171,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1280,7 +1286,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1331,13 +1337,13 @@ importers: version: 2.30.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) eslint-plugin-jest: specifier: ^28.8.3 - version: 28.8.3(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4) + version: 28.8.3(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4) eslint-plugin-jest-dom: specifier: ^5.4.0 version: 5.4.0(@testing-library/dom@10.4.0)(eslint@8.57.0) eslint-plugin-playwright: specifier: ^1.6.2 - version: 1.6.2(eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4))(eslint@8.57.0) + version: 1.6.2(eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4))(eslint@8.57.0) eslint-plugin-react: specifier: ^7.36.1 version: 7.36.1(eslint@8.57.0) @@ -1364,7 +1370,7 @@ importers: devDependencies: jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -1440,7 +1446,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1498,7 +1504,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1649,7 +1655,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1710,7 +1716,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1792,7 +1798,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1873,7 +1879,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -12783,6 +12789,41 @@ snapshots: - supports-color - ts-node + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.14.11 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.7 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + '@jest/environment@29.7.0': dependencies: '@jest/fake-timers': 29.7.0 @@ -15832,6 +15873,21 @@ snapshots: - supports-color - ts-node + create-jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + create-require@1.1.1: {} cross-env@7.0.3: @@ -16630,23 +16686,23 @@ snapshots: optionalDependencies: '@testing-library/dom': 10.4.0 - eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4): + eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4): dependencies: '@typescript-eslint/utils': 7.18.0(eslint@8.57.0)(typescript@5.5.4) eslint: 8.57.0 optionalDependencies: '@typescript-eslint/eslint-plugin': 8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) - jest: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + jest: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) transitivePeerDependencies: - supports-color - typescript - eslint-plugin-playwright@1.6.2(eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4))(eslint@8.57.0): + eslint-plugin-playwright@1.6.2(eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4))(eslint@8.57.0): dependencies: eslint: 8.57.0 globals: 13.24.0 optionalDependencies: - eslint-plugin-jest: 28.8.3(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4) + eslint-plugin-jest: 28.8.3(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4) eslint-plugin-react-hooks@4.6.2(eslint@8.57.0): dependencies: @@ -17844,6 +17900,25 @@ snapshots: - supports-color - ts-node + jest-cli@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest-config@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)): dependencies: '@babel/core': 7.25.2 @@ -17875,6 +17950,68 @@ snapshots: - babel-plugin-macros - supports-color + jest-config@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@babel/core': 7.25.2 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.25.2) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.7 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.14.11 + ts-node: 10.9.2(@types/node@22.1.0)(typescript@5.5.4) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-config@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@babel/core': 7.25.2 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.25.2) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.7 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.1.0 + ts-node: 10.9.2(@types/node@22.1.0)(typescript@5.5.4) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -18071,7 +18208,7 @@ snapshots: transitivePeerDependencies: - supports-color - jest-transformer-svg@2.0.2(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0))(react@18.3.1): + jest-transformer-svg@2.0.2(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)))(react@18.3.1): dependencies: jest: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) react: 18.3.1 @@ -18135,6 +18272,18 @@ snapshots: - supports-color - ts-node + jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jiti@1.21.6: {} jju@1.4.0: {} @@ -20443,6 +20592,25 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.1.0 + acorn: 8.12.1 + acorn-walk: 8.3.3 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.5.4 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29