From c161d3d47391e33b9ea78329acd817f92b2ac33f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Quiroz?= Date: Tue, 29 Nov 2022 12:24:47 -0300 Subject: [PATCH 1/6] chore: add metadata image --- public/images/metadata-gopher.png | Bin 0 -> 49817 bytes public/vercel.svg | 4 ---- 2 files changed, 4 deletions(-) create mode 100644 public/images/metadata-gopher.png delete mode 100644 public/vercel.svg diff --git a/public/images/metadata-gopher.png b/public/images/metadata-gopher.png new file mode 100644 index 0000000000000000000000000000000000000000..83cfdc617ce7c8ce3a1b612d35ef0d42f746c8f0 GIT binary patch literal 49817 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

qH>zLIRI(F2|sw3sIX%Nb%U%iScM_TIK*`Cgq) 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 - - \ No newline at end of file From 3efb3a6a186237ea367a7f4e465db42fbad163a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Quiroz?= Date: Tue, 29 Nov 2022 12:25:11 -0300 Subject: [PATCH 2/6] chore: update PageMetadata default image --- src/components/UI/PageMetadata.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/UI/PageMetadata.tsx b/src/components/UI/PageMetadata.tsx index 5cb76a4ae6..f92ed32864 100644 --- a/src/components/UI/PageMetadata.tsx +++ b/src/components/UI/PageMetadata.tsx @@ -13,7 +13,7 @@ export const PageMetadata: React.FC = ({ title, description, image }) => const router = useRouter(); const url = `${SITE_URL}${router.asPath}`; const fullTitle = `${title} | ${SITE_NAME}`; - const defaultOgImage = `${SITE_URL}/images/pages/gopher-downloads-front-light.svg`; // TODO: update with right image + const defaultOgImage = `${SITE_URL}/images/metadata-gopher.png`; const ogImage = !image ? defaultOgImage : `${SITE_URL}${image}`; return ( From c7b99ab9ea168f09c7bd7302413130dab083cd71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Quiroz?= Date: Tue, 29 Nov 2022 13:59:19 -0300 Subject: [PATCH 3/6] chore: update h2 font-size --- src/theme/foundations/textStyles.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/theme/foundations/textStyles.ts b/src/theme/foundations/textStyles.ts index fb95731677..6f7dfbe1c2 100644 --- a/src/theme/foundations/textStyles.ts +++ b/src/theme/foundations/textStyles.ts @@ -10,7 +10,7 @@ export const textStyles = { h2: { fontFamily: 'heading', fontWeight: 400, - fontSize: '1.5rem', + fontSize: '1.75rem', lineHeight: 'normal', letterSpacing: '0.04em', color: 'body' From 91dd04faa20a2c0f1b472cf0073468798ecf697c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Quiroz?= Date: Tue, 29 Nov 2022 15:29:52 -0300 Subject: [PATCH 4/6] feat: All releases downloads (#46) * chore: update constants * feat: add releases data utils * chore: add fast-xml-parser * chore: update types * feat: fetch & parse all releases data * chore: update utils * wip: use real data on DataTable * chore: update yarn.lock * fix: getReleaseCommitHash * feat: filter data per downloads tab * chore: update DownloadsTable * chore: update DownloadsTable Props * fix: getReleaseArch.ts * feat: add fetchXMLData util * feat: add fetchLatestReleaseCommit util * feat: add getSortedReleases util * chore: comment wip primary release feature * fix: fetchXMLData * chore: add netlify.toml * fix: total number of releases count * fix: center showing latest releases text and use smaller font * chore: prettier * chore: update textStyles * fix: merge conflicts --- .../dapp-developer/native-bindings.md | 2 +- docs/developers/evm-tracing/basic-traces.md | 45 +- .../evm-tracing/built-in-tracers.md | 60 +- docs/developers/evm-tracing/custom-tracer.md | 18 +- docs/developers/evm-tracing/index.md | 23 +- .../evm-tracing/javascript-tutorial.md | 20 +- docs/fundamentals/peer-to-peer.md | 2 +- docs/fundamentals/sync-modes.md | 4 +- docs/getting-started/index.md | 4 +- docs/interacting-with-geth/rpc/ns-admin.md | 2 +- docs/interacting-with-geth/rpc/ns-debug.md | 84 +- .../rpc/ns_personal_deprecation.md | 14 +- docs/monitoring/dashboards.md | 7 +- netlify.toml | 4 + package.json | 1 + src/components/MDXComponents.tsx | 18 +- src/components/UI/ButtonLinkSecondary.tsx | 6 +- src/components/UI/DataTable.tsx | 41 +- src/components/UI/Header.tsx | 7 +- src/components/UI/docs/index.tsx | 2 +- .../UI/downloads/DownloadsTable.tsx | 63 +- src/components/UI/homepage/QuickLinks.tsx | 12 +- src/components/UI/homepage/WhyRunANode.tsx | 2 +- src/components/UI/icons/DiscordIcon.tsx | 7 +- src/components/UI/icons/GitHubIcon.tsx | 7 +- src/components/UI/icons/SunIcon.tsx | 35 +- src/components/UI/search/Search.tsx | 10 +- src/components/UI/search/index.ts | 2 +- src/components/UI/svgs/GlyphHome.tsx | 48 +- src/components/UI/svgs/GopherDownloads.tsx | 3422 ++++++++++++++--- src/components/UI/svgs/GopherHomeFront.tsx | 3163 ++++++++++++--- src/components/UI/svgs/GopherHomeLinks.tsx | 2911 ++++++++++++-- src/components/UI/svgs/GopherHomeNodes.tsx | 2078 ++++++++-- src/components/docs/index.ts | 2 +- src/constants.ts | 42 +- src/data/test/download-testdata.ts | 122 - src/pages/downloads.tsx | 456 ++- src/types.ts | 36 + src/utils/compareReleasesFn.ts | 13 + src/utils/fetchLatestReleaseCommit.ts | 7 + src/utils/fetchLatestReleaseVersionAndName.ts | 12 + src/utils/fetchXMLData.ts | 25 + src/utils/getChecksum.ts | 10 + src/utils/getLatestBinaryURL.ts | 13 + src/utils/getParsedDate.ts | 12 + src/utils/getReleaseArch.ts | 28 + src/utils/getReleaseCommitHash.ts | 3 + src/utils/getReleaseCommitURL.ts | 3 + src/utils/getReleaseKind.ts | 17 + src/utils/getReleaseName.ts | 5 + src/utils/getReleaseSize.ts | 8 + src/utils/getReleaseURL.ts | 3 + src/utils/getSignatureURL.ts | 4 + src/utils/getSortedReleases.ts | 6 + src/utils/index.ts | 19 +- src/utils/mapReleasesData.ts | 45 + yarn.lock | 226 +- 57 files changed, 11015 insertions(+), 2226 deletions(-) create mode 100644 netlify.toml delete mode 100644 src/data/test/download-testdata.ts create mode 100644 src/types.ts create mode 100644 src/utils/compareReleasesFn.ts create mode 100644 src/utils/fetchLatestReleaseCommit.ts create mode 100644 src/utils/fetchLatestReleaseVersionAndName.ts create mode 100644 src/utils/fetchXMLData.ts create mode 100644 src/utils/getChecksum.ts create mode 100644 src/utils/getLatestBinaryURL.ts create mode 100644 src/utils/getParsedDate.ts create mode 100644 src/utils/getReleaseArch.ts create mode 100644 src/utils/getReleaseCommitHash.ts create mode 100644 src/utils/getReleaseCommitURL.ts create mode 100644 src/utils/getReleaseKind.ts create mode 100644 src/utils/getReleaseName.ts create mode 100644 src/utils/getReleaseSize.ts create mode 100644 src/utils/getReleaseURL.ts create mode 100644 src/utils/getSignatureURL.ts create mode 100644 src/utils/getSortedReleases.ts create mode 100644 src/utils/mapReleasesData.ts diff --git a/docs/developers/dapp-developer/native-bindings.md b/docs/developers/dapp-developer/native-bindings.md index 413c2db2f5..7a5a6168a5 100644 --- a/docs/developers/dapp-developer/native-bindings.md +++ b/docs/developers/dapp-developer/native-bindings.md @@ -153,7 +153,7 @@ type Storage struct { an Ethereum testnet and interact with it using the Go bindings. ### Deploying contracts to Ethereum {#deploying-contracts} - + In the previous section, the contract ABI was sufficient for generating the contract bindings from its ABI. However, deploying the contract requires some additional information in the form of the compiled bytecode. The bytecode is obtained by running the compiler again but this passing the `--bin` flag, e.g. diff --git a/docs/developers/evm-tracing/basic-traces.md b/docs/developers/evm-tracing/basic-traces.md index f66604605b..12271bb43c 100644 --- a/docs/developers/evm-tracing/basic-traces.md +++ b/docs/developers/evm-tracing/basic-traces.md @@ -3,16 +3,16 @@ title: Basic traces description: Introduction to basic EVM traces --- -The simplest type of transaction trace that Geth can generate are raw EVM opcode traces. For every VM instruction the transaction executes, a structured log entry is emitted, containing all contextual metadata deemed useful. This includes the *program counter*, *opcode name*, *opcode cost*, *remaining gas*, *execution depth* and any *occurred error*. The structured logs can optionally also contain the content of the *execution stack*, *execution memory* and *contract storage*. +The simplest type of transaction trace that Geth can generate are raw EVM opcode traces. For every VM instruction the transaction executes, a structured log entry is emitted, containing all contextual metadata deemed useful. This includes the _program counter_, _opcode name_, _opcode cost_, _remaining gas_, _execution depth_ and any _occurred error_. The structured logs can optionally also contain the content of the _execution stack_, _execution memory_ and _contract storage_. -The entire output of a raw EVM opcode trace is a JSON object having a few metadata fields: *consumed gas*, *failure status*, *return value*; and a list of *opcode entries*: +The entire output of a raw EVM opcode trace is a JSON object having a few metadata fields: _consumed gas_, _failure status_, _return value_; and a list of _opcode entries_: ```json { - "gas": 25523, - "failed": false, + "gas": 25523, + "failed": false, "returnValue": "", - "structLogs": [] + "structLogs": [] } ``` @@ -20,12 +20,12 @@ An example log for a single opcode entry has the following format: ```json { - "pc": 48, - "op": "DIV", + "pc": 48, + "op": "DIV", "gasCost": 5, - "gas": 64532, - "depth": 1, - "error": null, + "gas": 64532, + "depth": 1, + "error": null, "stack": [ "00000000000000000000000000000000000000000000000000000000ffffffff", "0000000100000000000000000000000000000000000000000000000000000000", @@ -36,8 +36,7 @@ An example log for a single opcode entry has the following format: "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000060" ], - "storage": { - } + "storage": {} } ``` @@ -45,11 +44,11 @@ An example log for a single opcode entry has the following format: To generate a raw EVM opcode trace, Geth provides a few [RPC API endpoints](/docs/rpc/ns-debug). The most commonly used is [`debug_traceTransaction`](/docs/rpc/ns-debug#debug_tracetransaction). -In its simplest form, `traceTransaction` accepts a transaction hash as its only argument. It then traces the transaction, aggregates all the generated +In its simplest form, `traceTransaction` accepts a transaction hash as its only argument. It then traces the transaction, aggregates all the generated data and returns it as a **large** JSON object. A sample invocation from the Geth console would be: ```js -debug.traceTransaction("0xfc9359e49278b7ba99f59edac0e3de49956e46e530a53c15aa71226b7aa92c6f") +debug.traceTransaction('0xfc9359e49278b7ba99f59edac0e3de49956e46e530a53c15aa71226b7aa92c6f'); ``` The same call can also be invoked from outside the node too via HTTP RPC (e.g. using Curl). In this case, the HTTP endpoint must be enabled in Geth using the `--http` command and the `debug` API namespace must be exposed using `--http.api=debug`. @@ -60,7 +59,7 @@ $ curl -H "Content-Type: application/json" -d '{"id": 1, "method": "debug_traceT To follow along with this tutorial, transaction hashes can be found from a local Geth node (e.g. by attaching a [Javascript console](/docs/interface/javascript-console) and running `eth.getBlock('latest')` then passing a transaction hash from the returned block to `debug.traceTransaction()`) or from a block explorer (for [Mainnet](https://etherscan.io/) or a [testnet](https://goerli.etherscan.io/)). -It is also possible to configure the trace by passing Boolean (true/false) values for four parameters that tweak the verbosity of the trace. By default, the *EVM memory* and *Return data* are not reported but the *EVM stack* and *EVM storage* are. To report the maximum amount of data: +It is also possible to configure the trace by passing Boolean (true/false) values for four parameters that tweak the verbosity of the trace. By default, the _EVM memory_ and _Return data_ are not reported but the _EVM stack_ and _EVM storage_ are. To report the maximum amount of data: ```shell enableMemory: true @@ -72,12 +71,17 @@ enableReturnData: true An example call, made in the Geth Javascript console, configured to report the maximum amount of data looks as follows: ```js -debug.traceTransaction("0xfc9359e49278b7ba99f59edac0e3de49956e46e530a53c15aa71226b7aa92c6f",{enableMemory: true, disableStack: false, disableStorage: false, enableReturnData: true}) +debug.traceTransaction('0xfc9359e49278b7ba99f59edac0e3de49956e46e530a53c15aa71226b7aa92c6f', { + enableMemory: true, + disableStack: false, + disableStorage: false, + enableReturnData: true +}); ``` The above operation was run on the (now-deprecated) Rinkeby network (with a node retaining enough history), resulting in this [trace dump](https://gist.github.com/karalabe/c91f95ac57f5e57f8b950ec65ecc697f). -Alternatively, disabling *EVM Stack*, *EVM Memory*, *Storage* and *Return data* (as demonstrated in the Curl request below) results in the following, much shorter, [trace dump](https://gist.github.com/karalabe/d74a7cb33a70f2af75e7824fc772c5b4). +Alternatively, disabling _EVM Stack_, _EVM Memory_, _Storage_ and _Return data_ (as demonstrated in the Curl request below) results in the following, much shorter, [trace dump](https://gist.github.com/karalabe/d74a7cb33a70f2af75e7824fc772c5b4). ``` $ curl -H "Content-Type: application/json" -d '{"id": 1, "method": "debug_traceTransaction", "params": ["0xfc9359e49278b7ba99f59edac0e3de49956e46e530a53c15aa71226b7aa92c6f", {"disableStack": true, "disableStorage": true}]}' localhost:8545 @@ -85,14 +89,13 @@ $ curl -H "Content-Type: application/json" -d '{"id": 1, "method": "debug_traceT ### Limits of basic traces {#list-of-basic-traces} -Although the raw opcode traces generated above are useful, having an individual log entry for every single opcode is too low level for most use cases, +Although the raw opcode traces generated above are useful, having an individual log entry for every single opcode is too low level for most use cases, and will require developers to create additional tools to post-process the traces. Additionally, a full opcode trace can easily go into the hundreds of megabytes, making them very resource intensive to get out of the node and process externally. -To avoid those issues, Geth supports running custom JavaScript tracers *within* the Ethereum node, which have full access to the EVM stack, memory and contract storage. This means developers only have to gather the data they actually need, and do any processing at the source. - +To avoid those issues, Geth supports running custom JavaScript tracers _within_ the Ethereum node, which have full access to the EVM stack, memory and contract storage. This means developers only have to gather the data they actually need, and do any processing at the source. ## Summary {#summary} This page described how to do basic traces in Geth. Basic traces are very low level and can generate lots of data that might not all be useful. Therefore, it is also possible to use a set of built-in tracers or write custom ones in Javascript or Go. -Read more about [built-in](/docs/evm-tracing/builtin-tracers) and [custom](/docs/evm-tracing/custom-tracer) traces. \ No newline at end of file +Read more about [built-in](/docs/evm-tracing/builtin-tracers) and [custom](/docs/evm-tracing/custom-tracer) traces. diff --git a/docs/developers/evm-tracing/built-in-tracers.md b/docs/developers/evm-tracing/built-in-tracers.md index 9fdea51f41..ca12a13738 100644 --- a/docs/developers/evm-tracing/built-in-tracers.md +++ b/docs/developers/evm-tracing/built-in-tracers.md @@ -3,8 +3,7 @@ title: Built-in tracers description: Explanation of the tracers that come bundled in Geth as part of the tracing API. --- -Geth comes bundled with a choice of tracers that can be invoked via the [tracing API](/docs/rpc/ns-debug). Some of these built-in tracers are implemented natively in Go, and others in Javascript. The default tracer is the opcode logger (otherwise known as struct logger) which is the default tracer for all the methods. Other tracers have to be specified by passing their name to the `tracer` parameter in the API call. - +Geth comes bundled with a choice of tracers that can be invoked via the [tracing API](/docs/rpc/ns-debug). Some of these built-in tracers are implemented natively in Go, and others in Javascript. The default tracer is the opcode logger (otherwise known as struct logger) which is the default tracer for all the methods. Other tracers have to be specified by passing their name to the `tracer` parameter in the API call. ## Struct/opcode logger {#struct-opcode-logger} @@ -86,7 +85,7 @@ Return: } }, - ... + ... ``` @@ -94,10 +93,9 @@ Return: The following tracers are implement in Go. This means they are much more performant than other tracers that are written in Javascript. The tracers are selected by passing their name to the `tracer` parameter when invoking a tracing API method, e.g. `debug.traceTransaction(, { tracer: 'callTracer' })`. - ### 4byteTracer {#4byte-tracer} -Solidity contract functions are +Solidity contract functions are [addressed](https://docs.soliditylang.org/en/develop/abi-spec.html#function-selector) using the first four four byte of the Keccak-256 hash of their signature. Therefore when calling the function of a contract, the caller must send this function selector as well as the ABI-encoded arguments as call data. The `4byteTracer` collects the function selectors of every function executed in the lifetime of a transaction, along with the size of the supplied call data. The result is a `map[string]int` where the keys are `SELECTOR-CALLDATASIZE` and the values are number of occurances of this key. For example: @@ -138,7 +136,6 @@ The `callTracer` tracks all the call frames executed during a transaction, inclu | revertReason | string | Solidity revert reason, if any | | calls | []callframe | list of sub-calls | - Example Call: ```sh @@ -211,7 +208,15 @@ To run this tracer in `diff` mode, pass `tracerConfig: {diffMode: true}` in the Example: ```js -debug.traceCall({from: "0x35a9f94af726f07b5162df7e828cc9dc8439e7d0", to: "0xc8ba32cab1757528daf49033e3673fae77dcf05d", data: "0xd1a2eab2000000000000000000000000000000000000000000000000000000000024aea100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000204895cd480cc8412691a880028a25aec86786f1ed2aa5562bc400000000000000c6403c14f35be1da6f433eadbb6e9178a47fbc7c6c1d568d2f2b876e929089c8d8db646304fd001a187dc8a600000000000000000000000000000000"}, 'latest', {tracer: 'prestateTracer'}) +debug.traceCall( + { + from: '0x35a9f94af726f07b5162df7e828cc9dc8439e7d0', + to: '0xc8ba32cab1757528daf49033e3673fae77dcf05d', + data: '0xd1a2eab2000000000000000000000000000000000000000000000000000000000024aea100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000204895cd480cc8412691a880028a25aec86786f1ed2aa5562bc400000000000000c6403c14f35be1da6f433eadbb6e9178a47fbc7c6c1d568d2f2b876e929089c8d8db646304fd001a187dc8a600000000000000000000000000000000' + }, + 'latest', + { tracer: 'prestateTracer' } +); ``` Return: @@ -264,7 +269,6 @@ Return (same call with `{diffMode: True}`): This tracer is noop. It returns an empty object and is only meant for testing the setup. - ## Javascript tracers {#js-tracers} There are also a set of tracers written in Javascript. These are less performant than the Go native tracers because of overheads associated with interpreting the Javascript in Geth's Go environment. @@ -276,7 +280,15 @@ There are also a set of tracers written in Javascript. These are less performant Example: ```js -debug.traceCall({from: "0x35a9f94af726f07b5162df7e828cc9dc8439e7d0", to: "0xc8ba32cab1757528daf49033e3673fae77dcf05d", data: "0xd1a2eab2000000000000000000000000000000000000000000000000000000000024aea100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000204895cd480cc8412691a880028a25aec86786f1ed2aa5562bc400000000000000c6403c14f35be1da6f433eadbb6e9178a47fbc7c6c1d568d2f2b876e929089c8d8db646304fd001a187dc8a600000000000000000000000000000000"}, 'latest', {tracer: 'bigramTracer'}) +debug.traceCall( + { + from: '0x35a9f94af726f07b5162df7e828cc9dc8439e7d0', + to: '0xc8ba32cab1757528daf49033e3673fae77dcf05d', + data: '0xd1a2eab2000000000000000000000000000000000000000000000000000000000024aea100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000204895cd480cc8412691a880028a25aec86786f1ed2aa5562bc400000000000000c6403c14f35be1da6f433eadbb6e9178a47fbc7c6c1d568d2f2b876e929089c8d8db646304fd001a187dc8a600000000000000000000000000000000' + }, + 'latest', + { tracer: 'bigramTracer' } +); ``` Returns: @@ -370,7 +382,15 @@ Returns: Example: ```js -debug.traceCall({from: "0x35a9f94af726f07b5162df7e828cc9dc8439e7d0", to: "0xc8ba32cab1757528daf49033e3673fae77dcf05d", data: "0xd1a2eab2000000000000000000000000000000000000000000000000000000000024aea100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000204895cd480cc8412691a880028a25aec86786f1ed2aa5562bc400000000000000c6403c14f35be1da6f433eadbb6e9178a47fbc7c6c1d568d2f2b876e929089c8d8db646304fd001a187dc8a600000000000000000000000000000000"}, 'latest', {tracer: 'opcountTracer'}) +debug.traceCall( + { + from: '0x35a9f94af726f07b5162df7e828cc9dc8439e7d0', + to: '0xc8ba32cab1757528daf49033e3673fae77dcf05d', + data: '0xd1a2eab2000000000000000000000000000000000000000000000000000000000024aea100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000204895cd480cc8412691a880028a25aec86786f1ed2aa5562bc400000000000000c6403c14f35be1da6f433eadbb6e9178a47fbc7c6c1d568d2f2b876e929089c8d8db646304fd001a187dc8a600000000000000000000000000000000' + }, + 'latest', + { tracer: 'opcountTracer' } +); ``` Returns: @@ -386,10 +406,19 @@ Returns: Example: ```js -debug.traceCall({from: "0x35a9f94af726f07b5162df7e828cc9dc8439e7d0", to: "0xc8ba32cab1757528daf49033e3673fae77dcf05d", data: "0xd1a2eab2000000000000000000000000000000000000000000000000000000000024aea100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000204895cd480cc8412691a880028a25aec86786f1ed2aa5562bc400000000000000c6403c14f35be1da6f433eadbb6e9178a47fbc7c6c1d568d2f2b876e929089c8d8db646304fd001a187dc8a600000000000000000000000000000000"}, 'latest', {tracer: 'trigramTracer'}) +debug.traceCall( + { + from: '0x35a9f94af726f07b5162df7e828cc9dc8439e7d0', + to: '0xc8ba32cab1757528daf49033e3673fae77dcf05d', + data: '0xd1a2eab2000000000000000000000000000000000000000000000000000000000024aea100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000204895cd480cc8412691a880028a25aec86786f1ed2aa5562bc400000000000000c6403c14f35be1da6f433eadbb6e9178a47fbc7c6c1d568d2f2b876e929089c8d8db646304fd001a187dc8a600000000000000000000000000000000' + }, + 'latest', + { tracer: 'trigramTracer' } +); ``` Returns: + ```terminal { --PUSH1: 1, @@ -414,17 +443,18 @@ Returns: } ``` - ### unigram {#unigram} `unigramTracer` counts the frequency of occurrance of each opcode. Example: + ```js > debug.traceCall({from: "0x35a9f94af726f07b5162df7e828cc9dc8439e7d0", to: "0xc8ba32cab1757528daf49033e3673fae77dcf05d", data: "0xd1a2eab2000000000000000000000000000000000000000000000000000000000024aea100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000204895cd480cc8412691a880028a25aec86786f1ed2aa5562bc400000000000000c6403c14f35be1da6f433eadbb6e9178a47fbc7c6c1d568d2f2b876e929089c8d8db646304fd001a187dc8a600000000000000000000000000000000"}, 'latest', {tracer: 'unigramTracer'}) ``` Returns: + ```terminal { ADD: 36, @@ -447,9 +477,9 @@ Returns: ## State overrides {#state-overrides} -It is possible to give temporary state modifications to Geth in order to simulate the effects of `eth_call`. For example, some new byetcode could be deployed to some address *temporarily just for the duration of the execution* and then a transaction interacting with that address canm be traced. This can be used for scenario testing or determining the outcome of some hypothetical transaction before executing for real. +It is possible to give temporary state modifications to Geth in order to simulate the effects of `eth_call`. For example, some new byetcode could be deployed to some address _temporarily just for the duration of the execution_ and then a transaction interacting with that address canm be traced. This can be used for scenario testing or determining the outcome of some hypothetical transaction before executing for real. -To do this, the tracer is written as normal, but the parameter `stateOverrides` is passed an address and some bytecode. +To do this, the tracer is written as normal, but the parameter `stateOverrides` is passed an address and some bytecode. ```js var code = //contract bytecode @@ -459,4 +489,4 @@ debug.traceCall({from: , to: , input: }, 'latest', {stateOverrides: {'0x...': {c ## Summary {#summary} -This page showed how to use the tracers that come bundled with Geth. There are a set written in Go and a set written in Javascript. They are invoked by passing their names when calling an API method. State overrides can be used in combination with tracers to examine precisely what the EVM will do in some hypothetical scenarios. \ No newline at end of file +This page showed how to use the tracers that come bundled with Geth. There are a set written in Go and a set written in Javascript. They are invoked by passing their names when calling an API method. State overrides can be used in combination with tracers to examine precisely what the EVM will do in some hypothetical scenarios. diff --git a/docs/developers/evm-tracing/custom-tracer.md b/docs/developers/evm-tracing/custom-tracer.md index df47276b9e..b7768940cd 100644 --- a/docs/developers/evm-tracing/custom-tracer.md +++ b/docs/developers/evm-tracing/custom-tracer.md @@ -249,7 +249,7 @@ And these fields are only available for tracing mined transactions (i.e. not ava - `getGasUsed()` - returns amount of gas used throughout the frame as a Number - `getOutput()` - returns the output as a buffer -` -getError()` - returns an error if one occured during execution and `undefined` otherwise + ` -getError()` - returns an error if one occured during execution and `undefined` otherwise ### Usage @@ -258,18 +258,20 @@ Note that several values are Golang big.Int objects, not JavaScript numbers or J Usage example, returns the top element of the stack at each CALL opcode only: ```js -debug.traceTransaction(txhash, {tracer: '{data: [], fault: function(log) {}, step: function(log) { if(log.op.toString() == "CALL") this.data.push(log.stack.peek(0)); }, result: function() { return this.data; }}'}); +debug.traceTransaction(txhash, { + tracer: + '{data: [], fault: function(log) {}, step: function(log) { if(log.op.toString() == "CALL") this.data.push(log.stack.peek(0)); }, result: function() { return this.data; }}' +}); ``` ## Other traces -This tutorial has focused on `debug_traceTransaction()` which reports information -about individual transactions. There are also RPC endpoints that provide different -information, including tracing the EVM execution within a block, between two blocks, -for specific `eth_call`s or rejected blocks. The full list of trace functions can +This tutorial has focused on `debug_traceTransaction()` which reports information +about individual transactions. There are also RPC endpoints that provide different +information, including tracing the EVM execution within a block, between two blocks, +for specific `eth_call`s or rejected blocks. The full list of trace functions can be explored in the [reference documentation](/content/docs/interacting_with_geth/RPC/ns-debug.md). - ## Summary -This page described how to write custom tracers for Geth. Custom tracers can be written in Javascript or Go. \ No newline at end of file +This page described how to write custom tracers for Geth. Custom tracers can be written in Javascript or Go. diff --git a/docs/developers/evm-tracing/index.md b/docs/developers/evm-tracing/index.md index b41493624f..434e98e25f 100644 --- a/docs/developers/evm-tracing/index.md +++ b/docs/developers/evm-tracing/index.md @@ -11,13 +11,11 @@ Also see this [Devcon 2022 talk](https://www.youtube.com/watch?v=b8RdmGsilfU) on In its simplest form, tracing a transaction entails requesting the Ethereum node to reexecute the desired transaction with varying degrees of data collection and have it return an aggregated summary. In order for a Geth node to reexecute a transaction, all historical state accessed by the transaction must be available. This includes: -- Balance, nonce, bytecode and storage of both the recipient as well as all +- Balance, nonce, bytecode and storage of both the recipient as well as all internally invoked contracts. - -- Block metadata referenced during execution of both the outer as well as all +- Block metadata referenced during execution of both the outer as well as all internally created transactions. - -- Intermediate state generated by all preceding transactions contained in the +- Intermediate state generated by all preceding transactions contained in the same block as the one being traced. This means there are limits on the transactions that can be traced imposed by the synchronization and pruning configuration of a node: @@ -31,12 +29,12 @@ This means there are limits on the transactions that can be traced imposed by th - A **light synced** node retrieving data **on demand** can in theory trace transactions for which all required historical state is readily available in the network. This is because the data required to generate the trace is requested from an les-serving full node. In practice, data availability **cannot** be reasonably assumed. ![state pruning options](/public/images/docs/state-pruning.png) - -*This image shows the state stored by each sync-mode - red indicates stored state. The full width of each line represents origin to present head* + +_This image shows the state stored by each sync-mode - red indicates stored state. The full width of each line represents origin to present head_ More detailed information about syncing is available on the [sync modes page](/docs/interface/sync-modes). -When a trace of a specific transaction is executed, the state is prepared by fetching the state of the parent block from the database. If it is not available, Geth will crawl backwards in time to find the next available state but only up to a limit defined in the `reexec` parameter which defaults to 128 blocks. If no state is available within the `reexec` window then the trace fails with `Error: required historical state unavailable` and the `reexec` parameter must be increased. If a valid state *is* found in the `reexec` window, then Geth sequentially re-executes the transcations in each block between the last available state and the target block. The greater the value of `reexec` the longer the tracing will take because more blocks have to be re-executed to regenerate the target state. +When a trace of a specific transaction is executed, the state is prepared by fetching the state of the parent block from the database. If it is not available, Geth will crawl backwards in time to find the next available state but only up to a limit defined in the `reexec` parameter which defaults to 128 blocks. If no state is available within the `reexec` window then the trace fails with `Error: required historical state unavailable` and the `reexec` parameter must be increased. If a valid state _is_ found in the `reexec` window, then Geth sequentially re-executes the transcations in each block between the last available state and the target block. The greater the value of `reexec` the longer the tracing will take because more blocks have to be re-executed to regenerate the target state. The `debug_getAccessibleStates` endpoint is a useful tool for estimating a suitable value for `reexec`. Passing the number of the block that contains the target transaction and a search distance to this endpoint will return the number of blocks behind the current head where the most recent available state exists. This value can be passed to the tracer as `re-exec`. @@ -48,26 +46,23 @@ _There are exceptions to the above rules when running batch traces of entire blo ### Basic traces {#basic-traces} -The simplest type of transaction trace that Geth can generate are raw EVM opcode traces. For every EVM instruction the transaction executes, a structured log entry is emitted, containing all contextual metadata deemed useful. This includes the *program counter*, *opcode name*, *opcode cost*, *remaining gas*, *execution depth* and any *occurred error*. The structured logs can optionally also contain the content of the *execution stack*, *execution memory* and *contract storage*. +The simplest type of transaction trace that Geth can generate are raw EVM opcode traces. For every EVM instruction the transaction executes, a structured log entry is emitted, containing all contextual metadata deemed useful. This includes the _program counter_, _opcode name_, _opcode cost_, _remaining gas_, _execution depth_ and any _occurred error_. The structured logs can optionally also contain the content of the _execution stack_, _execution memory_ and _contract storage_. Read more about Geth's basic traces on the [basic traces page](/docs/evm-tracing/basic-traces). - ### Built-in tracers {#built-in-tracers} -The tracing API accepts an optional `tracer` parameter that defines how the data returned to the API call should be processed. If this parameter is ommitted the default tracer is used. The default is the struct (or 'opcode') logger. These raw opcode traces are sometimes useful, but the returned data is very low level and can be too extensive and awkward to read for many use-cases. A full opcode trace can easily go into the hundreds of megabytes, making them very resource intensive to get out of the node and process externally. For these reasons, there are a set of non-default built-in tracers that can be named in the API call to return different data from the method. Under the hood, these tracers are Go or Javascript +The tracing API accepts an optional `tracer` parameter that defines how the data returned to the API call should be processed. If this parameter is ommitted the default tracer is used. The default is the struct (or 'opcode') logger. These raw opcode traces are sometimes useful, but the returned data is very low level and can be too extensive and awkward to read for many use-cases. A full opcode trace can easily go into the hundreds of megabytes, making them very resource intensive to get out of the node and process externally. For these reasons, there are a set of non-default built-in tracers that can be named in the API call to return different data from the method. Under the hood, these tracers are Go or Javascript functions that do some specific preprocessing on the trace data before it is returned. More information about Geth's built-in tracers is available on the [built-in tracers](/docs/evm-tracing/builtin-tracers) page. - ### Custom tracers {#custom-tracers} In addition to built-in tracers, it is possible to provide custom code that hooks to events in the EVM to process and return data in a consumable format. Custom tracers can be written either in Javascript or Go. JS tracers are good for quick prototyping and experimentation as well as for less intensive applications. Go tracers are performant but require the tracer to be compiled together with the Geth source code. This means developers only have to gather the data they actually need, and do any processing at the source. More information about custom tracers is available on the [custom tracers](/docs/evm-tracing/custom-tracer) page. - ## Summary {#summary} -This page gave an introduction to the concept of tracing and explained issues around state availability. More detailed information on Geth's built-in and custom tracers can be found on their dedicated pages. \ No newline at end of file +This page gave an introduction to the concept of tracing and explained issues around state availability. More detailed information on Geth's built-in and custom tracers can be found on their dedicated pages. diff --git a/docs/developers/evm-tracing/javascript-tutorial.md b/docs/developers/evm-tracing/javascript-tutorial.md index b777b91bc9..7bfba83c53 100644 --- a/docs/developers/evm-tracing/javascript-tutorial.md +++ b/docs/developers/evm-tracing/javascript-tutorial.md @@ -13,15 +13,15 @@ Filters are Javascript functions that select information from the trace to persi ```js tracer = function (tx) { - return debug.traceTransaction(tx, { + return debug.traceTransaction(tx, { tracer: - '{' + - 'retVal: [],' + - 'step: function(log,db) {this.retVal.push(log.getPC() + ":" + log.op.toString())},' + - 'fault: function(log,db) {this.retVal.push("FAULT: " + JSON.stringify(log))},' + - 'result: function(ctx,db) {return this.retVal}' + - '}' - }); // return debug.traceTransaction ... + '{' + + 'retVal: [],' + + 'step: function(log,db) {this.retVal.push(log.getPC() + ":" + log.op.toString())},' + + 'fault: function(log,db) {this.retVal.push("FAULT: " + JSON.stringify(log))},' + + 'result: function(ctx,db) {return this.retVal}' + + '}' + }); // return debug.traceTransaction ... }; // tracer = function ... ``` @@ -71,7 +71,7 @@ This object has three member functions: - `step`, called for each opcode. - `fault`, called if there is a problem in the execution. -- `result`, called to produce the results that are returned by `debug.traceTransaction` +- `result`, called to produce the results that are returned by `debug.traceTransaction` - after the execution is done. In this case, `retVal` is used to store the list of strings to return in `result`. @@ -297,4 +297,4 @@ The output is similar to: " Result: b38558064d8dd9c883d2a8c80c604667ddb90a324bc70b1bac4e70d90b148ed4", "11041: SSTORE 22ff293e14f1ec3a09b137e9e06084afd63addf9:6 <- 0" ] -``` \ No newline at end of file +``` diff --git a/docs/fundamentals/peer-to-peer.md b/docs/fundamentals/peer-to-peer.md index 51287036c2..99ff141f2b 100644 --- a/docs/fundamentals/peer-to-peer.md +++ b/docs/fundamentals/peer-to-peer.md @@ -151,7 +151,7 @@ admin.addTrustedPeer( 'enode://f4642fa65af50cfdea8fa7414a5def7bb7991478b768e296f5e4a54e8b995de102e0ceae2e826f293c481b5325f89be6d207b003382e18a8ecba66fbaf6416c0@33.4.2.1:30303' ); ``` - + ## Summary {#summary} Geth connects to Ethereum Mainnet by default. However, this behaviour can be changed using combinations of command line flags and files. This page has described the various options available for connecting a Geth node to Ethereum, public testnets and private networks. Remember that to connect to a proof-of-stake network (e.g. Ethereum Mainnet, Goerli, Sepolia) a consensus client is also required. diff --git a/docs/fundamentals/sync-modes.md b/docs/fundamentals/sync-modes.md index c4321e8e00..898e243356 100644 --- a/docs/fundamentals/sync-modes.md +++ b/docs/fundamentals/sync-modes.md @@ -11,12 +11,12 @@ There are two types of full node that use different mechanisms to sync up to the ### Snap (default) {#snap-sync} -Snap sync starts froma relatively recent block and syncs from there to the head of the chain, keeping only the most recent 128 block states in memory. The block header to sync up to is provided by the consensus client. Between the initial sync block and the 128 most recent blocks, the node stores occasional snapshots that can be used to rebuild any intermediate state "on-the-fly". The difference between the snap-synced node and a full block-by-block synced node is that a snap synced node started from an initial checkpoint that was more recent than the genesis block. Snap sync is much faster than a full block-by-block sync from genesis. To start a node with snap sync pass `--syncmode snap` at startup. +Snap sync starts froma relatively recent block and syncs from there to the head of the chain, keeping only the most recent 128 block states in memory. The block header to sync up to is provided by the consensus client. Between the initial sync block and the 128 most recent blocks, the node stores occasional snapshots that can be used to rebuild any intermediate state "on-the-fly". The difference between the snap-synced node and a full block-by-block synced node is that a snap synced node started from an initial checkpoint that was more recent than the genesis block. Snap sync is much faster than a full block-by-block sync from genesis. To start a node with snap sync pass `--syncmode snap` at startup. ![state pruning options](/public/images/docs/state-pruning.png) _This image shows the state stored by each sync-mode - red indicates stored state. The full width of each line represents origin to present head_ -Snap sync works by first downloading the headers for a chunk of blocks. Once the headers have been verified, the block bodies and receipts for those blocks are downloaded. In parallel, Geth also sync begins state-sync. In state-sync, Geth first downloads the leaves of the state trie for each block without the intermediate nodes along with a range proof. The state trie is then regenerated locally. +Snap sync works by first downloading the headers for a chunk of blocks. Once the headers have been verified, the block bodies and receipts for those blocks are downloaded. In parallel, Geth also sync begins state-sync. In state-sync, Geth first downloads the leaves of the state trie for each block without the intermediate nodes along with a range proof. The state trie is then regenerated locally. The state download is the part of the snap-sync that takes the most time to complete and the progress can be monitored using the ETA values in the log messages. However, the blockchain is also progressing at the same time and invalidating some of the regenerated state data. This means it is also necessary to have a 'healing' phase where errors in the state are fixed. It is not possible to monitor the progress of the state heal because the extent of the errors cannot be known until the current state has already been regenerated. Geth regularly reports `Syncing, state heal in progress` during state healing - this informs the user that state heal has not finished. It is also possible to confirm this using `eth.syncing` - if this command returns `false` then the node is in sync. If it returns anything other than `false` then syncing is still in progress. diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index 7fd157227d..cd20231d5c 100644 --- a/docs/getting-started/index.md +++ b/docs/getting-started/index.md @@ -3,7 +3,7 @@ title: Getting started with Geth description: Guide to getting up and running with Geth using Clef. --- -This page explains how to set up Geth and execute some basic tasks using the command line tools. In order to use Geth, the software must first be installed. There are several ways Geth can be installed depending on the operating system and the user's choice of installation method, for example using a package manager, container or building from source. Instructions for installing Geth can be found on the ["Install and Build"](/docs/getting_started/Installing-Geth) pages. +This page explains how to set up Geth and execute some basic tasks using the command line tools. In order to use Geth, the software must first be installed. There are several ways Geth can be installed depending on the operating system and the user's choice of installation method, for example using a package manager, container or building from source. Instructions for installing Geth can be found on the ["Install and Build"](/docs/getting_started/Installing-Geth) pages. Geth also needs to be connected to a [consensus client](docs/getting-started/consensus-clients.md) in order to function as an Ethereum node. The tutorial on this page assumes Geth and a consensus client have been installed successfully and that a firewall has been configured to block external traffic to the JSON-RPC port `8545` see [Security](/docs/fundamentals/security). @@ -156,6 +156,7 @@ This message will be displayed periodically until state healing has finished: ``` INFO [10-20|20:20:09.510] State heal in progress accounts=313,309@17.95MiB slots=363,525@28.77MiB codes=7222@50.73MiB nodes=49,616,912@12.67GiB pending=29805 ``` + When state healing is finished, the node is in sync and ready to use. Sending an empty Curl request to the http server provides a quick way to confirm that this too has been started without any issues. In a third terminal, the following command can be run: @@ -166,7 +167,6 @@ curl http://localhost:8545 If there is no error message reported to the terminal, everything is OK. Geth must be running and synced in order for a user to interact with the Ethereum network. If the terminal running Geth is closed down then Geth must be restarted again in a new terminal. Geth can be started and stopped easily, but it must be running for any interaction with Ethereum to take place. To shut down Geth, simply press `CTRL+C` in the Geth terminal. To start it again, run the previous command `geth --datadir `. - ## Step 4: Get Testnet Ether {#get-test-eth} In order to make some transactions, the user must fund their account with ether. On Ethereum mainnet, ether can only be obtained in three ways: 1) by receiving it as a reward for mining/validating; 2) receiving it in a transfer from another Ethereum user or contract; 3) receiving it from an exchange, 3) having paid for it with fiat money. On Ethereum testnets, the ether has no real world value so it 4) can be made freely available via faucets. Faucets allow users to request a transfer of testnet ether to their account. diff --git a/docs/interacting-with-geth/rpc/ns-admin.md b/docs/interacting-with-geth/rpc/ns-admin.md index 7f6c46873e..a68612f023 100644 --- a/docs/interacting-with-geth/rpc/ns-admin.md +++ b/docs/interacting-with-geth/rpc/ns-admin.md @@ -178,7 +178,7 @@ Removes a remote node from the trusted peer set, but it does not disconnect it a | RPC | `{"method": "admin_removeTrustedPeer", "params": [string]}` | ## admin_startHTTP {#admin-starthttp} - + The `startHTTP` administrative method starts an HTTP based JSON-RPC [API](/docs/rpc/server) webserver to handle client requests. All the parameters are optional: - `host`: network interface to open the listener socket on (defaults to `"localhost"`) diff --git a/docs/interacting-with-geth/rpc/ns-debug.md b/docs/interacting-with-geth/rpc/ns-debug.md index 774e105c7d..3d574603f1 100644 --- a/docs/interacting-with-geth/rpc/ns-debug.md +++ b/docs/interacting-with-geth/rpc/ns-debug.md @@ -29,7 +29,7 @@ The location is specified as `:`. Example: -``` javascript +```javascript > debug.backtraceAt("server.go:443") ``` @@ -42,7 +42,6 @@ Turns on block profiling for the given duration and writes profile data to disk. | Console | `debug.blockProfile(file, seconds)` | | RPC | `{"method": "debug_blockProfile", "params": [string, number]}` | - ### debug_chaindbCompact Flattens the entire key-value database into a single level, removing all unused slots and merging all keys. @@ -52,7 +51,6 @@ Flattens the entire key-value database into a single level, removing all unused | Console | `debug.chaindbCompact()` | | RPC | `{"method": "debug_chaindbCompact", "params": []}` | - ### debug_chaindbProperty Returns leveldb properties of the key-value database. @@ -62,7 +60,6 @@ Returns leveldb properties of the key-value database. | Console | `debug.chaindbProperty(property string)` | | RPC | `{"method": "debug_chaindbProperty", "params": [property]}` | - ### debug_cpuProfile Turns on CPU profiling for the given duration and writes profile data to disk. @@ -72,7 +69,6 @@ Turns on CPU profiling for the given duration and writes profile data to disk. | Console | `debug.cpuProfile(file, seconds)` | | RPC | `{"method": "debug_cpuProfile", "params": [string, number]}` | - ### debug_dbAncient Retrieves an ancient binary blob from the freezer. The freezer is a collection of append-only immutable files. The first argument `kind` specifies which table to look up data from. The list of all table kinds are as follows: @@ -106,8 +102,6 @@ Returns the raw value of a key stored in the database. | Console | `debug.dbGet(key string)` | | RPC | `{"method": "debug_dbGet", "params": [key]}` | - - ### debug_dumpBlock Retrieves the state that corresponds to the block number and returns a list of accounts (including storage and code). @@ -154,8 +148,6 @@ Forces garbage collection | Console | `debug.freeOSMemory()` | | RPC | `{"method": "debug_freeOSMemory", "params": []}` | - - ### debug_freezeClient Forces a temporary client freeze, normally when the server is overloaded. Available as part of LES light server. @@ -165,8 +157,6 @@ Forces a temporary client freeze, normally when the server is overloaded. Availa | Console | `debug.freezeClient(node string)` | | RPC | `{"method": "debug_freezeClient", "params": [node]}` | - - ### debug_gcStats Returns garbage collection statistics. @@ -178,10 +168,9 @@ See https://golang.org/pkg/runtime/debug/#GCStats for information about the fiel | Console | `debug.gcStats()` | | RPC | `{"method": "debug_gcStats", "params": []}` | - ### debug_getAccessibleState -Returns the first number where the node has accessible state on disk. This is the post-state of that block and the pre-state of the next +Returns the first number where the node has accessible state on disk. This is the post-state of that block and the pre-state of the next block. The (from, to) parameters are the sequence of blocks to search, which can go either forwards or backwards. Note: to get the last state pass in the range of blocks in reverse, i.e. (last, first). @@ -191,7 +180,6 @@ Note: to get the last state pass in the range of blocks in reverse, i.e. (last, | Console | `debug.getAccessibleState(from, to rpc.BlockNumber)` | | RPC | `{"method": "debug_getAccessibleState", "params": [from, to]}` | - ### debug_getBadBlocks Returns a list of the last 'bad blocks' that the client has seen on the network and returns them as a JSON list of block-hashes. @@ -201,7 +189,6 @@ Returns a list of the last 'bad blocks' that the client has seen on the network | Console | `debug.getBadBlocks()` | | RPC | `{"method": "debug_getBadBlocks", "params": []}` | - ### debug_getBlockRlp Retrieves and returns the RLP encoded block by number. @@ -234,7 +221,7 @@ Returns all accounts that have changed between the two blocks specified. A chang ### debug_getModifiedAccountsByNumber -Returns all accounts that have changed between the two blocks specified. A change is defined as a difference in nonce, balance, code hash or +Returns all accounts that have changed between the two blocks specified. A change is defined as a difference in nonce, balance, code hash or storage hash. | Client | Method invocation | @@ -298,7 +285,6 @@ Returns the preimage for a sha3 hash, if known. | Console | `debug.preimage(hash)` | | RPC | `{"method": "debug_preimage", "params": [hash]}` | - ### debug_printBlock Retrieves a block and returns its pretty printed form. @@ -308,7 +294,6 @@ Retrieves a block and returns its pretty printed form. | Console | `debug.printBlock(number uint64)` | | RPC | `{"method": "debug_printBlock", "params": [number]}` | - ### debug_seedHash Fetches and retrieves the seed hash of the block by number @@ -338,10 +323,9 @@ Sets the garbage collection target percentage. A negative value disables garbage | Console | `debug.setGCPercent(v)` | | RPC | `{"method": "debug_setGCPercent", "params": [v]}` | - ### debug_setHead -Sets the current head of the local chain by block number. **Note**, this is a destructive action and may severely damage your chain. Use with *extreme* caution. +Sets the current head of the local chain by block number. **Note**, this is a destructive action and may severely damage your chain. Use with _extreme_ caution. | Client | Method invocation | | :------ | ------------------------------------------------- | @@ -370,7 +354,6 @@ Returns a printed representation of the stacks of all goroutines. Note that the | Console | `debug.stacks()` | | RPC | `{"method": "debug_stacks", "params": []}` | - ### debug_standardTraceBlockToFile When JS-based tracing (see below) was first implemented, the intended usecase was to enable long-running tracers that could stream results back via a subscription channel. This method works a bit differently. (For full details, see [PR](https://github.com/ethereum/go-ethereum/pull/17914)) @@ -378,23 +361,27 @@ When JS-based tracing (see below) was first implemented, the intended usecase wa - It streams output to disk during the execution, to not blow up the memory usage on the node - It uses `jsonl` as output format (to allow streaming) - Uses a cross-client standardized output, so called 'standard json' - * Uses `op` for string-representation of opcode, instead of `op`/`opName` for numeric/string, and other simlar small differences. - * has `refund` - * Represents memory as a contiguous chunk of data, as opposed to a list of `32`-byte segments like `debug_traceTransaction` + - Uses `op` for string-representation of opcode, instead of `op`/`opName` for numeric/string, and other simlar small differences. + - has `refund` + - Represents memory as a contiguous chunk of data, as opposed to a list of `32`-byte segments like `debug_traceTransaction` This means that this method is only 'useful' for callers who control the node -- at least sufficiently to be able to read the artefacts from the filesystem after the fact. The method can be used to dump a certain transaction out of a given block: + ``` > debug.standardTraceBlockToFile("0x0bbe9f1484668a2bf159c63f0cf556ed8c8282f99e3ffdb03ad2175a863bca63", {txHash:"0x4049f61ffbb0747bb88dc1c85dd6686ebf225a3c10c282c45a8e0c644739f7e9", disableMemory:true}) ["/tmp/block_0x0bbe9f14-14-0x4049f61f-099048234"] ``` + Or all txs from a block: + ``` > debug.standardTraceBlockToFile("0x0bbe9f1484668a2bf159c63f0cf556ed8c8282f99e3ffdb03ad2175a863bca63", {disableMemory:true}) ["/tmp/block_0x0bbe9f14-0-0xb4502ea7-409046657", "/tmp/block_0x0bbe9f14-1-0xe839be8f-954614764", "/tmp/block_0x0bbe9f14-2-0xc6e2052f-542255195", "/tmp/block_0x0bbe9f14-3-0x01b7f3fe-209673214", "/tmp/block_0x0bbe9f14-4-0x0f290422-320999749", "/tmp/block_0x0bbe9f14-5-0x2dc0fb80-844117472", "/tmp/block_0x0bbe9f14-6-0x35542da1-256306111", "/tmp/block_0x0bbe9f14-7-0x3e199a08-086370834", "/tmp/block_0x0bbe9f14-8-0x87778b88-194603593", "/tmp/block_0x0bbe9f14-9-0xbcb081ba-629580052", "/tmp/block_0x0bbe9f14-10-0xc254381a-578605923", "/tmp/block_0x0bbe9f14-11-0xcc434d58-405931366", "/tmp/block_0x0bbe9f14-12-0xce61967d-874423181", "/tmp/block_0x0bbe9f14-13-0x05a20b35-267153288", "/tmp/block_0x0bbe9f14-14-0x4049f61f-606653767", "/tmp/block_0x0bbe9f14-15-0x46d473d2-614457338", "/tmp/block_0x0bbe9f14-16-0x35cf5500-411906321", "/tmp/block_0x0bbe9f14-17-0x79222961-278569788", "/tmp/block_0x0bbe9f14-18-0xad84e7b1-095032683", "/tmp/block_0x0bbe9f14-19-0x4bd48260-019097038", "/tmp/block_0x0bbe9f14-20-0x1517411d-292624085", "/tmp/block_0x0bbe9f14-21-0x6857e350-971385904", "/tmp/block_0x0bbe9f14-22-0xbe3ae2ca-236639695"] ``` + Files are created in a temp-location, with the naming standard `block_---`. Each opcode immediately streams to file, with no in-geth buffering aside from whatever buffering the os normally does. On the server side, it also adds some more info when regenerating historical state, namely, the reexec-number if `required historical state is not avaiable` is encountered, so a user can experiment with increasing that setting. It also prints out the remaining block until it reaches target: @@ -409,6 +396,7 @@ INFO [10-15|13:48:34.421] Wrote trace file=/tmp/block_0x14490c57-2-0x3f4263fe-05 ``` The `options` is as follows: + ``` type StdTraceConfig struct { *vm.LogConfig @@ -421,7 +409,6 @@ type StdTraceConfig struct { This method is similar to `debug_standardTraceBlockToFile`, but can be used to obtain info about a block which has been _rejected_ as invalid (for some reason). - ### debug_startCPUProfile Turns on CPU profiling indefinitely, writing to the given file. @@ -552,7 +539,6 @@ Similar to [debug_traceBlock](#debug_traceblock), `traceBlockByHash` accepts a b References: [RLP](https://github.com/ethereum/wiki/wiki/RLP) - ### debug_traceBlockFromFile Similar to [debug_traceBlock](#debug_traceblock), `traceBlockFromFile` accepts a file containing the RLP of the block. For the second parameter see [TraceConfig](#traceconfig) reference. @@ -589,6 +575,7 @@ No specific call options: structLogs: [] } ``` + Tracing a call with a destination and specific sender, disabling the storage and memory output (less data returned over RPC) ```sh @@ -601,16 +588,16 @@ debug.traceCall({ "latest", {"disableStorage": true, "disableMemory": true}) ``` -It is possible to supply 'overrides' for both state-data (accounts/storage) and block data (number, timestamp etc). In the example below, a call which executes `NUMBER` is performed, and the overridden number is placed on the stack: +It is possible to supply 'overrides' for both state-data (accounts/storage) and block data (number, timestamp etc). In the example below, a call which executes `NUMBER` is performed, and the overridden number is placed on the stack: ```sh > debug.traceCall({ - from: eth.accounts[0], + from: eth.accounts[0], value:"0x1", - gasPrice: "0xffffffff", - gas: "0xffff", + gasPrice: "0xffffffff", + gas: "0xffff", input: "0x43"}, - "latest", + "latest", {"blockoverrides": {"number": "0x50"} }) @@ -636,7 +623,7 @@ It is possible to supply 'overrides' for both state-data (accounts/storage) and } ``` -Curl example: +Curl example: ```sh > curl -H "Content-Type: application/json" -X POST localhost:8545 --data '{"jsonrpc":"2.0","method":"debug_traceCall","params":[null, "pending"],"id":1}' @@ -653,7 +640,6 @@ const res = provider.send('debug_subscribe', ['traceChain', '0x3f3a2a', '0x3f3a2 please refer to the [subscription page](https://geth.ethereum.org/docs/rpc/pubsub) for more details. - ### debug_traceTransaction **OBS** In most scenarios, `debug.standardTraceBlockToFile` is better suited for tracing! @@ -667,22 +653,21 @@ hash. | Console | `debug.traceTransaction(txHash, [options])` | | RPC | `{"method": "debug_traceTransaction", "params": [txHash, {}]}` | - #### TraceConfig -In addition to the hash of the transaction you may give it a secondary *optional* argument, which specifies the options for this specific call. The possible options are: +In addition to the hash of the transaction you may give it a secondary _optional_ argument, which specifies the options for this specific call. The possible options are: + +- `disableStorage`: `BOOL`. Setting this to true will disable storage capture (default = false). +- `disableStack`: `BOOL`. Setting this to true will disable stack capture (default = false). +- `enableMemory`: `BOOL`. Setting this to true will enable memory capture (default = false). +- `enableReturnData`: `BOOL`. Setting this to true will enable return data capture (default = false). +- `tracer`: `STRING`. Name for built-in tracer or Javascript expression. See below for more details. -* `disableStorage`: `BOOL`. Setting this to true will disable storage capture (default = false). -* `disableStack`: `BOOL`. Setting this to true will disable stack capture (default = false). -* `enableMemory`: `BOOL`. Setting this to true will enable memory capture (default = false). -* `enableReturnData`: `BOOL`. Setting this to true will enable return data capture (default = false). -* `tracer`: `STRING`. Name for built-in tracer or Javascript expression. See below for more details. - If set, the previous four arguments will be ignored. -* `timeout`: `STRING`. Overrides the default timeout of 5 seconds for JavaScript-based tracing calls. +- `timeout`: `STRING`. Overrides the default timeout of 5 seconds for JavaScript-based tracing calls. Valid values are described [here](https://golang.org/pkg/time/#ParseDuration). -* `tracerConfig`: Config for the specified `tracer`. For example see callTracer's [config](/docs/evm-tracing/builtin-tracers#config). +- `tracerConfig`: Config for the specified `tracer`. For example see callTracer's [config](/docs/evm-tracing/builtin-tracers#config). Geth comes with a bundle of [built-in tracers](/docs/evm-tracing/builtin-tracers), each providing various data about a transaction. This method defaults to the [struct logger](/docs/evm-tracing/builtin-tracers#structopcode-logger). The `tracer` field of the second parameter can be set to use any of the other tracers. Alternatively a [custom tracer](/docs/evm-tracing/custom-tracer) can be implemented in either Go or Javascript. @@ -742,31 +727,30 @@ Sets the logging verbosity pattern. | Console | `debug.vmodule(string)` | | RPC | `{"method": "debug_vmodule", "params": [string]}` | - #### Examples If you want to see messages from a particular Go package (directory) and all subdirectories, use: -``` javascript +```javascript > debug.vmodule("eth/*=6") ``` If you want to restrict messages to a particular package (e.g. p2p) but exclude subdirectories, use: -``` javascript +```javascript > debug.vmodule("p2p=6") ``` If you want to see log messages from a particular source file, use -``` javascript +```javascript > debug.vmodule("server.go=6") ``` You can compose these basic patterns. If you want to see all output from peer.go in a package below eth (eth/peer.go, eth/downloader/peer.go) as well as output from package p2p at level <= 5, use: -``` javascript -debug.vmodule("eth/*/peer.go=6,p2p=5") +```javascript +debug.vmodule('eth/*/peer.go=6,p2p=5'); ``` ### debug_writeBlockProfile @@ -794,4 +778,4 @@ Writes a goroutine blocking profile to the given file. | Client | Method invocation | | :------ | --------------------------------------------------------- | | Console | `debug.writeMutexProfile(file)` | -| RPC | `{"method": "debug_writeMutexProfile", "params": [file]}` | \ No newline at end of file +| RPC | `{"method": "debug_writeMutexProfile", "params": [file]}` | diff --git a/docs/interacting-with-geth/rpc/ns_personal_deprecation.md b/docs/interacting-with-geth/rpc/ns_personal_deprecation.md index 5691dbf133..a4e4ae880b 100644 --- a/docs/interacting-with-geth/rpc/ns_personal_deprecation.md +++ b/docs/interacting-with-geth/rpc/ns_personal_deprecation.md @@ -9,7 +9,7 @@ The JSON-RPC API's `personal` namespace has historically been used to manage acc ### personal_unlockAccount -There is no need for a direct replacement for `personal_unlockAccount`. Using Clef to manually approve actions or to attest custom rulesets is a much more secure way to interact with accounts without needing to indiscriminately unlock accounts. +There is no need for a direct replacement for `personal_unlockAccount`. Using Clef to manually approve actions or to attest custom rulesets is a much more secure way to interact with accounts without needing to indiscriminately unlock accounts. ### personal_lockAccount @@ -38,7 +38,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1 ```js // eth_accounts in Geth's JS console -eth.accounts +eth.accounts; ``` ```sh @@ -68,8 +68,8 @@ curl --data '{"id": 4, "jsonrpc": "2.0", "method": "account_ecRecover","params": clef importraw ``` - ### personal_listWallets + As opposed to `listAccounts`, this method lists full details, including usb path or keystore-file paths. The equivalent method is `clef_listWallets`. This method can be called from the terminal using: ```sh @@ -100,18 +100,19 @@ Both require manual approval in Clef unless a custom ruleset is in place. ### personal_sendTransaction -`personal_sendTransaction` ws used to sign and submit a transaction. This can be done using `eth_sendTransaction`, requiring manual approval in Clef. +`personal_sendTransaction` ws used to sign and submit a transaction. This can be done using `eth_sendTransaction`, requiring manual approval in Clef. Example call (Javascript console): ```js // this command requires 2x approval in Clef because it loads account data via eth.accounts[0] // and eth.accounts[1] -var tx = {from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(0.1, "ether")} +var tx = { from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(0.1, 'ether') }; // then send the transaction -eth.sendTransaction(tx) +eth.sendTransaction(tx); ``` + Example call (terminal) ```sh @@ -218,4 +219,3 @@ Example call (terminal): ```sh curl --data '{"id": 2, "jsonrpc": "2.0", "method": "account_signTransaction", "params": [{"from": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db", "gas": "0x55555","gasPrice": "0x1234", "input": "0xabcd", "nonce": "0x0", "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value": "0x1234"}]}' -X POST -H "Content-Type: application/json" localhost:8550 ``` - diff --git a/docs/monitoring/dashboards.md b/docs/monitoring/dashboards.md index 27f64dc6d6..4113776284 100644 --- a/docs/monitoring/dashboards.md +++ b/docs/monitoring/dashboards.md @@ -71,7 +71,7 @@ InfluxDB is running and configured to store metrics from Geth. ## Preparing Geth {#preparing-geth} -After setting up database, metrics need to be enabled in Geth. Various options are available, as documented in the `METRICS AND STATS OPTIONS` +After setting up database, metrics need to be enabled in Geth. Various options are available, as documented in the `METRICS AND STATS OPTIONS` in `geth --help` and in our [metrics page](/docs/monitoring/metrics). In this case Geth will be configured to push data into InfluxDB. Basic setup specifies the endpoint where InfluxDB is reachable and authenticates the database. ```sh @@ -132,10 +132,9 @@ For a Geth monitoring dashboard, copy the URL of [this dashboard](https://grafan ![Grafana 1](/public/images/docs/grafana.png) - ## Customization {#customization} -The dashboards can be customized further. Each panel can be edited, moved, removed or added. To learn more about how dashboards work, refer to +The dashboards can be customized further. Each panel can be edited, moved, removed or added. To learn more about how dashboards work, refer to [Grafana's documentation](https://grafana.com/docs/grafana/latest/dashboards/). Some users might also be interested in automatic [alerting](https://grafana.com/docs/grafana/latest/alerting/), which sets up alert notifications that are sent automatically when metrics reach certain values. Various communication channels are supported. @@ -144,4 +143,4 @@ Some users might also be interested in automatic [alerting](https://grafana.com/ This page has outlined how to set up a simple node monitoring dashboard using Grafana. -***NB: this page was adapted from a tutorial on ethereum.org written by Mario Havel*** \ No newline at end of file +**_NB: this page was adapted from a tutorial on ethereum.org written by Mario Havel_** diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000000..25601165c3 --- /dev/null +++ b/netlify.toml @@ -0,0 +1,4 @@ +# https://docs.netlify.com/integrations/frameworks/next-js/incremental-static-regeneration/ + +[functions] + included_files = ["src/**"] diff --git a/package.json b/package.json index 3a34a00742..80854be9b8 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@mdx-js/react": "^2.1.3", "@next/mdx": "^12.3.0", "chakra-ui-markdown-renderer": "^4.1.0", + "fast-xml-parser": "^4.0.12", "focus-visible": "^5.2.0", "framer-motion": "^7.3.2", "gray-matter": "^4.0.3", diff --git a/src/components/MDXComponents.tsx b/src/components/MDXComponents.tsx index c8296ccc62..64c3215a21 100644 --- a/src/components/MDXComponents.tsx +++ b/src/components/MDXComponents.tsx @@ -92,14 +92,22 @@ const MDXComponents = { // code code: ({ children, ...props }: any) => {children}, // list - ul: ({children}: any) => { - return {children} + ul: ({ children }: any) => { + return ( + + {children} + + ); }, - ol: ({children}: any) => { - return {children} + ol: ({ children }: any) => { + return ( + + {children} + + ); }, li: ({ children }: any) => { - return {children} + return {children}; } }; diff --git a/src/components/UI/ButtonLinkSecondary.tsx b/src/components/UI/ButtonLinkSecondary.tsx index 882a8a4a2d..94ff6ff629 100644 --- a/src/components/UI/ButtonLinkSecondary.tsx +++ b/src/components/UI/ButtonLinkSecondary.tsx @@ -1,15 +1,15 @@ import { Link, Stack, Text } from '@chakra-ui/react'; import NextLink, { LinkProps } from 'next/link'; -import { Link as LinkTheme } from "../../theme/components" +import { Link as LinkTheme } from '../../theme/components'; interface Props extends LinkProps { children: React.ReactNode; } -export const ButtonLinkSecondary: React.FC = ({ href, children, ...restProps}) => { +export const ButtonLinkSecondary: React.FC = ({ href, children, ...restProps }) => { const isExternal: boolean = href.toString().startsWith('http'); - const variant = LinkTheme.variants["button-link-secondary"] + const variant = LinkTheme.variants['button-link-secondary']; return ( diff --git a/src/components/UI/DataTable.tsx b/src/components/UI/DataTable.tsx index 12fe2f9af6..915f597bae 100644 --- a/src/components/UI/DataTable.tsx +++ b/src/components/UI/DataTable.tsx @@ -1,8 +1,11 @@ -import { Table, Thead, Tr, Th, TableContainer, Text, Tbody, Td } from '@chakra-ui/react'; +import { Link, Table, Thead, Tr, Th, TableContainer, Text, Tbody, Td } from '@chakra-ui/react'; import { FC } from 'react'; +import { ReleaseData } from '../../types'; +import { getParsedDate } from '../../utils'; interface Props { columnHeaders: string[]; + // TODO: update data type data: any; } @@ -41,20 +44,44 @@ export const DataTable: FC = ({ columnHeaders, data }) => { })} + - {data.map((item: any, idx: number) => { + {data.map((r: ReleaseData, idx: number) => { return ( - {columnHeaders.map((columnHeader, idx) => { - // TODO: Make the font size smaller (refer to design system) + {Object.entries(r).map((item, idx) => { + const objectItems = ['release', 'commit', 'signature']; + + if (objectItems.includes(item[0])) { + const label = item[1].label; + const url = item[1].url; + + return ( + + + + {item[0] === 'commit' ? `${label}...` : label} + + + + ); + } + + if (item[0] === 'published') { + return ( + + {getParsedDate(item[1])} + + ); + } + return ( - - {item[columnHeader.toLowerCase()]} + + {item[1]} ); })} diff --git a/src/components/UI/Header.tsx b/src/components/UI/Header.tsx index e87a2edcf1..7ad993fd0e 100644 --- a/src/components/UI/Header.tsx +++ b/src/components/UI/Header.tsx @@ -36,14 +36,12 @@ export const Header: FC = () => { {/* HEADER BUTTONS */} - + {/* SEARCH */} - + @@ -65,7 +63,6 @@ export const Header: FC = () => { {/* MOBILE MENU */} - ); }; diff --git a/src/components/UI/docs/index.tsx b/src/components/UI/docs/index.tsx index 823cfaea66..c3aa9443d1 100644 --- a/src/components/UI/docs/index.tsx +++ b/src/components/UI/docs/index.tsx @@ -1 +1 @@ -export * from './Code'; \ No newline at end of file +export * from './Code'; diff --git a/src/components/UI/downloads/DownloadsTable.tsx b/src/components/UI/downloads/DownloadsTable.tsx index a8b69925d2..d77789f73f 100644 --- a/src/components/UI/downloads/DownloadsTable.tsx +++ b/src/components/UI/downloads/DownloadsTable.tsx @@ -1,20 +1,43 @@ import { Stack, Tabs, TabList, Tab, Text, TabPanel, TabPanels } from '@chakra-ui/react'; import { FC } from 'react'; -import { DOWNLOAD_TABS, DOWNLOAD_TAB_COLUMN_HEADERS } from '../../../constants'; - import { DataTable } from '../../UI'; +import { DOWNLOADS_TABLE_TABS, DOWNLOADS_TABLE_TAB_COLUMN_HEADERS } from '../../../constants'; +import { ReleaseData } from '../../../types'; + interface Props { - data: any; + linuxData: ReleaseData[]; + macOSData: ReleaseData[]; + windowsData: ReleaseData[]; + iOSData: ReleaseData[]; + androidData: ReleaseData[]; + amountOfReleasesToShow: number; + setTotalReleases: (idx: number) => void; } -export const DownloadsTable: FC = ({ data }) => { +export const DownloadsTable: FC = ({ + linuxData, + macOSData, + windowsData, + iOSData, + androidData, + amountOfReleasesToShow, + setTotalReleases +}) => { + const totalReleases = [ + linuxData.length, + macOSData.length, + windowsData.length, + iOSData.length, + androidData.length + ]; + return ( - + setTotalReleases(totalReleases[idx])}> - {DOWNLOAD_TABS.map((tab, idx) => { + {DOWNLOADS_TABLE_TABS.map((tab, idx) => { return ( = ({ data }) => { color: 'bg' }} borderBottom='2px solid' - borderRight={idx === DOWNLOAD_TABS.length - 1 ? 'none' : '2px solid'} + borderRight={idx === DOWNLOADS_TABLE_TABS.length - 1 ? 'none' : '2px solid'} borderColor='primary' > {tab} @@ -33,21 +56,37 @@ export const DownloadsTable: FC = ({ data }) => { ); })} + - + - + - + - + - + diff --git a/src/components/UI/homepage/QuickLinks.tsx b/src/components/UI/homepage/QuickLinks.tsx index 28e6d5e895..34307c5ff2 100644 --- a/src/components/UI/homepage/QuickLinks.tsx +++ b/src/components/UI/homepage/QuickLinks.tsx @@ -18,11 +18,7 @@ export const QuickLinks: FC = () => { sx={{ mt: '0 !important' }} > {/* get started */} - + Don't know where to start? @@ -60,11 +56,7 @@ export const QuickLinks: FC = () => { {/* faq */} - + Have doubts? diff --git a/src/components/UI/homepage/WhyRunANode.tsx b/src/components/UI/homepage/WhyRunANode.tsx index bed89b8eec..cacbabe2ea 100644 --- a/src/components/UI/homepage/WhyRunANode.tsx +++ b/src/components/UI/homepage/WhyRunANode.tsx @@ -1,7 +1,7 @@ import { Box, Grid, GridItem, Stack } from '@chakra-ui/react'; import { FC } from 'react'; -import { ButtonLinkSecondary } from '..' +import { ButtonLinkSecondary } from '..'; import { GopherHomeNodes } from '../svgs/GopherHomeNodes'; import { ETHEREUM_ORG_RUN_A_NODE_URL } from '../../../constants'; diff --git a/src/components/UI/icons/DiscordIcon.tsx b/src/components/UI/icons/DiscordIcon.tsx index 5fc6c33c78..dd068036b5 100644 --- a/src/components/UI/icons/DiscordIcon.tsx +++ b/src/components/UI/icons/DiscordIcon.tsx @@ -4,8 +4,11 @@ export const DiscordIcon = createIcon({ displayName: 'DiscordIcon', viewBox: '0 0 32 24', path: ( - - + + ) }); diff --git a/src/components/UI/icons/GitHubIcon.tsx b/src/components/UI/icons/GitHubIcon.tsx index f1e04499c5..a7954f782a 100644 --- a/src/components/UI/icons/GitHubIcon.tsx +++ b/src/components/UI/icons/GitHubIcon.tsx @@ -4,8 +4,11 @@ export const GitHubIcon = createIcon({ displayName: 'GitHubIcon', viewBox: '0 0 26 24', path: ( - - + + ) }); diff --git a/src/components/UI/icons/SunIcon.tsx b/src/components/UI/icons/SunIcon.tsx index d866d86daf..4a69f77fa5 100644 --- a/src/components/UI/icons/SunIcon.tsx +++ b/src/components/UI/icons/SunIcon.tsx @@ -4,16 +4,31 @@ export const SunIcon = createIcon({ displayName: 'SunIcon', viewBox: '0 0 44 44', path: ( - - - - - - - - - - + + + + + + + + + + ) }); diff --git a/src/components/UI/search/Search.tsx b/src/components/UI/search/Search.tsx index e6e14c5d33..27913e5e51 100644 --- a/src/components/UI/search/Search.tsx +++ b/src/components/UI/search/Search.tsx @@ -1,7 +1,7 @@ import { FC } from 'react'; -import { Input, InputGroup, Stack } from '@chakra-ui/react' +import { Input, InputGroup, Stack } from '@chakra-ui/react'; -import { BORDER_WIDTH } from '../../../constants' +import { BORDER_WIDTH } from '../../../constants'; import { LensIcon } from '../icons'; export const Search: FC = () => { @@ -12,14 +12,14 @@ export const Search: FC = () => { borderColor={{ base: 'bg', md: 'primary' }} px={4} py={{ base: 8, md: 4 }} - _hover={{ base: {bg: 'primary'}, md: {bg: 'none'}}} + _hover={{ base: { bg: 'primary' }, md: { bg: 'none' } }} > @@ -27,4 +27,4 @@ export const Search: FC = () => { ); -}; \ No newline at end of file +}; diff --git a/src/components/UI/search/index.ts b/src/components/UI/search/index.ts index 14c382eab6..addd53308b 100644 --- a/src/components/UI/search/index.ts +++ b/src/components/UI/search/index.ts @@ -1 +1 @@ -export * from './Search'; \ No newline at end of file +export * from './Search'; diff --git a/src/components/UI/svgs/GlyphHome.tsx b/src/components/UI/svgs/GlyphHome.tsx index 6abf1fbe1f..4e25ad08b0 100644 --- a/src/components/UI/svgs/GlyphHome.tsx +++ b/src/components/UI/svgs/GlyphHome.tsx @@ -7,15 +7,47 @@ const Icon = createIcon({ displayName: 'GlyphHome', viewBox: `0 0 ${w} ${h}`, path: ( - - - - - - - + + + + + + + ) }); -export const GlyphHome: React.FC = (props) => ; +export const GlyphHome: React.FC = props => ( + +); diff --git a/src/components/UI/svgs/GopherDownloads.tsx b/src/components/UI/svgs/GopherDownloads.tsx index 56a86936db..df438c2dd9 100644 --- a/src/components/UI/svgs/GopherDownloads.tsx +++ b/src/components/UI/svgs/GopherDownloads.tsx @@ -7,497 +7,2939 @@ const Icon = createIcon({ displayName: 'GopherDownloads', viewBox: `0 0 ${w} ${h}`, path: ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) }); -export const GopherDownloads: React.FC = (props) => ; +export const GopherDownloads: React.FC = props => ( + +); diff --git a/src/components/UI/svgs/GopherHomeFront.tsx b/src/components/UI/svgs/GopherHomeFront.tsx index 6695320581..c27023c3ce 100644 --- a/src/components/UI/svgs/GopherHomeFront.tsx +++ b/src/components/UI/svgs/GopherHomeFront.tsx @@ -7,460 +7,2717 @@ const Icon = createIcon({ displayName: 'GopherHomeFront', viewBox: `0 0 ${w} ${h}`, path: ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) }); -export const GopherHomeFront: React.FC = (props) => ; +export const GopherHomeFront: React.FC = props => ( + +); diff --git a/src/components/UI/svgs/GopherHomeLinks.tsx b/src/components/UI/svgs/GopherHomeLinks.tsx index 0660ea53b2..abc8883c2d 100644 --- a/src/components/UI/svgs/GopherHomeLinks.tsx +++ b/src/components/UI/svgs/GopherHomeLinks.tsx @@ -7,424 +7,2501 @@ const Icon = createIcon({ displayName: 'GopherHomeLinks', viewBox: `0 0 ${w} ${h}`, path: ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) }); -export const GopherHomeLinks: React.FC = (props) => ; \ No newline at end of file +export const GopherHomeLinks: React.FC = props => ( + +); diff --git a/src/components/UI/svgs/GopherHomeNodes.tsx b/src/components/UI/svgs/GopherHomeNodes.tsx index 17f798a13b..f80517c2c7 100644 --- a/src/components/UI/svgs/GopherHomeNodes.tsx +++ b/src/components/UI/svgs/GopherHomeNodes.tsx @@ -7,305 +7,1787 @@ const Icon = createIcon({ displayName: 'GopherHomeNodes', viewBox: `0 0 ${w} ${h}`, path: ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) }); -export const GopherHomeNodes: React.FC = (props) => ; \ No newline at end of file +export const GopherHomeNodes: React.FC = props => ( + +); diff --git a/src/components/docs/index.ts b/src/components/docs/index.ts index 381317adf2..ce977548b1 100644 --- a/src/components/docs/index.ts +++ b/src/components/docs/index.ts @@ -1 +1 @@ -export * from './Breadcrumbs' \ No newline at end of file +export * from './Breadcrumbs'; diff --git a/src/constants.ts b/src/constants.ts index c083f48c6b..51e4822e0c 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -54,8 +54,8 @@ export const DOWNLOAD_HEADER_BUTTONS: { buildURL: '' } }; -export const DOWNLOAD_TABS = ['Linux', 'macOS', 'Windows', 'iOS', 'Android']; -export const DOWNLOAD_TAB_COLUMN_HEADERS = [ +export const DOWNLOADS_TABLE_TABS = ['Linux', 'macOS', 'Windows', 'iOS', 'Android']; +export const DOWNLOADS_TABLE_TAB_COLUMN_HEADERS = [ 'Release', 'Commit', 'Kind', @@ -65,13 +65,13 @@ export const DOWNLOAD_TAB_COLUMN_HEADERS = [ 'Signature', 'Checksum (MD5)' ]; -export const DOWNLOAD_OPENPGP_BUILD_HEADERS = [ +export const DOWNLOADS_OPENPGP_BUILD_HEADERS = [ 'Build Server', 'Unique ID', 'OpenPGP Key', 'Fingerprint' ]; -export const DOWNLOAD_OPENPGP_DEVELOPER_HEADERS = [ +export const DOWNLOADS_OPENPGP_DEVELOPER_HEADERS = [ 'Developer', 'Unique ID', 'OpenPGP Key', @@ -92,9 +92,11 @@ export const METADATA = { // GitHub urls export const LATEST_GETH_RELEASE_URL = 'https://api.github.com/repos/ethereum/go-ethereum/releases/latest'; -export const ALL_GETH_RELEASES_URL = 'https://api.github.com/repos/ethereum/go-ethereum/releases'; export const ALL_GETH_COMMITS_URL = 'https://api.github.com/repos/ethereum/go-ethereum/commits/'; +export const RELEASE_COMMIT_BASE_URL = 'https://github.com/ethereum/go-ethereum/tree/'; +// Binaries urls +export const BINARIES_BASE_URL = 'https://gethstore.blob.core.windows.net/builds/'; export const LINUX_BINARY_BASE_URL = 'https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-'; export const MACOS_BINARY_BASE_URL = @@ -102,7 +104,37 @@ export const MACOS_BINARY_BASE_URL = export const WINDOWS_BINARY_BASE_URL = 'https://gethstore.blob.core.windows.net/builds/geth-windows-amd64-'; +// Blobs urls +// linux +export const ALL_LINUX_GETH_RELEASES_URL = + 'https://gethstore.blob.core.windows.net/builds?restype=container&comp=list&prefix=geth-linux'; +export const ALL_LINUX_ALLTOOLS_GETH_RELEASES_URL = + 'https://gethstore.blob.core.windows.net/builds?restype=container&comp=list&prefix=geth-alltools-linux'; + +// macOS +export const ALL_MACOS_GETH_RELEASES_URL = + 'https://gethstore.blob.core.windows.net/builds?restype=container&comp=list&prefix=geth-darwin'; +export const ALL_MACOS_ALLTOOLS_GETH_RELEASES_URL = + 'https://gethstore.blob.core.windows.net/builds?restype=container&comp=list&prefix=geth-alltools-darwin'; + +// windows +export const ALL_WINDOWS_GETH_RELEASES_URL = + 'https://gethstore.blob.core.windows.net/builds?restype=container&comp=list&prefix=geth-windows'; +export const ALL_WINDOWS_ALLTOOLS_GETH_RELEASES_URL = + 'https://gethstore.blob.core.windows.net/builds?restype=container&comp=list&prefix=geth-alltools-windows'; + +// android +export const ALL_ANDROID_GETH_RELEASES_URL = + 'https://gethstore.blob.core.windows.net/builds?restype=container&comp=list&prefix=geth-android-all'; + +// iOS +export const ALL_IOS_GETH_RELEASES_URL = + 'https://gethstore.blob.core.windows.net/builds?restype=container&comp=list&prefix=geth-ios-all'; + +// Sources urls export const LATEST_SOURCES_BASE_URL = 'https://github.com/ethereum/go-ethereum/archive/'; + +// Release notes urls export const RELEASE_NOTES_BASE_URL = 'https://github.com/ethereum/go-ethereum/releases/tag/'; // Code snippet class constants diff --git a/src/data/test/download-testdata.ts b/src/data/test/download-testdata.ts deleted file mode 100644 index 7dff5e4753..0000000000 --- a/src/data/test/download-testdata.ts +++ /dev/null @@ -1,122 +0,0 @@ -export const testDownloadData = [ - { - release: 'Geth 1.10.23', - commit: 'd901d853…', - kind: 'archive', - arch: '64-bit', - size: '11.71 MB', - published: 'Last Wednesday at 11:11 AM', - signature: 'Signature', - 'checksum (md5)': 'c93b0339413a8f2b95aa4b23b32d64af' - }, - { - release: 'Geth 1.10.23', - commit: 'd901d853…', - kind: 'archive', - arch: '64-bit', - size: '11.71 MB', - published: 'Last Wednesday at 11:11 AM', - signature: 'Signature', - 'checksum (md5)': 'c93b0339413a8f2b95aa4b23b32d64af' - }, - { - release: 'Geth 1.10.23', - commit: 'd901d853…', - kind: 'archive', - arch: '64-bit', - size: '11.71 MB', - published: 'Last Wednesday at 11:11 AM', - signature: 'Signature', - 'checksum (md5)': 'c93b0339413a8f2b95aa4b23b32d64af' - }, - { - release: 'Geth 1.10.23', - commit: 'd901d853…', - kind: 'archive', - arch: '64-bit', - size: '11.71 MB', - published: 'Last Wednesday at 11:11 AM', - signature: 'Signature', - 'checksum (md5)': 'c93b0339413a8f2b95aa4b23b32d64af' - }, - { - release: 'Geth 1.10.23', - commit: 'd901d853…', - kind: 'archive', - arch: '64-bit', - size: '11.71 MB', - published: 'Last Wednesday at 11:11 AM', - signature: 'Signature', - 'checksum (md5)': 'c93b0339413a8f2b95aa4b23b32d64af' - }, - { - release: 'Geth 1.10.23', - commit: 'd901d853…', - kind: 'archive', - arch: '64-bit', - size: '11.71 MB', - published: 'Last Wednesday at 11:11 AM', - signature: 'Signature', - 'checksum (md5)': 'c93b0339413a8f2b95aa4b23b32d64af' - }, - { - release: 'Geth 1.10.23', - commit: 'd901d853…', - kind: 'archive', - arch: '64-bit', - size: '11.71 MB', - published: 'Last Wednesday at 11:11 AM', - signature: 'Signature', - 'checksum (md5)': 'c93b0339413a8f2b95aa4b23b32d64af' - }, - { - release: 'Geth 1.10.23', - commit: 'd901d853…', - kind: 'archive', - arch: '64-bit', - size: '11.71 MB', - published: 'Last Wednesday at 11:11 AM', - signature: 'Signature', - 'checksum (md5)': 'c93b0339413a8f2b95aa4b23b32d64af' - }, - { - release: 'Geth 1.10.23', - commit: 'd901d853…', - kind: 'archive', - arch: '64-bit', - size: '11.71 MB', - published: 'Last Wednesday at 11:11 AM', - signature: 'Signature', - 'checksum (md5)': 'c93b0339413a8f2b95aa4b23b32d64af' - }, - { - release: 'Geth 1.10.23', - commit: 'd901d853…', - kind: 'archive', - arch: '64-bit', - size: '11.71 MB', - published: 'Last Wednesday at 11:11 AM', - signature: 'Signature', - 'checksum (md5)': 'c93b0339413a8f2b95aa4b23b32d64af' - }, - { - release: 'Geth 1.10.23', - commit: 'd901d853…', - kind: 'archive', - arch: '64-bit', - size: '11.71 MB', - published: 'Last Wednesday at 11:11 AM', - signature: 'Signature', - 'checksum (md5)': 'c93b0339413a8f2b95aa4b23b32d64af' - }, - { - release: 'Geth 1.10.23', - commit: 'd901d853…', - kind: 'archive', - arch: '64-bit', - size: '11.71 MB', - published: 'Last Wednesday at 11:11 AM', - signature: 'Signature', - 'checksum (md5)': 'c93b0339413a8f2b95aa4b23b32d64af' - } -]; diff --git a/src/pages/downloads.tsx b/src/pages/downloads.tsx index 5222cd34e3..8f119d926c 100644 --- a/src/pages/downloads.tsx +++ b/src/pages/downloads.tsx @@ -1,6 +1,7 @@ import { Center, Code, Flex, Link, ListItem, Stack, Text, UnorderedList } from '@chakra-ui/react'; -import type { GetServerSideProps, NextPage } from 'next'; +import type { GetStaticProps, NextPage } from 'next'; import { useState } from 'react'; +import { XMLParser } from 'fast-xml-parser'; import { DownloadsHero, @@ -11,49 +12,43 @@ import { import { DataTable, PageMetadata } from '../components/UI'; import { - ALL_GETH_COMMITS_URL, DEFAULT_BUILD_AMOUNT_TO_SHOW, - DOWNLOAD_OPENPGP_BUILD_HEADERS, - DOWNLOAD_OPENPGP_DEVELOPER_HEADERS, + DOWNLOADS_OPENPGP_BUILD_HEADERS, + DOWNLOADS_OPENPGP_DEVELOPER_HEADERS, GETH_REPO_URL, METADATA, - LATEST_GETH_RELEASE_URL, LATEST_SOURCES_BASE_URL, - LINUX_BINARY_BASE_URL, - MACOS_BINARY_BASE_URL, - RELEASE_NOTES_BASE_URL, - WINDOWS_BINARY_BASE_URL + RELEASE_NOTES_BASE_URL } from '../constants'; -import { testDownloadData } from '../data/test/download-testdata'; import { pgpBuildTestData } from '../data/test/pgpbuild-testdata'; import { pgpDeveloperTestData } from '../data/test/pgpdeveloper-testdata'; -export const getServerSideProps: GetServerSideProps = async () => { - // Latest release name & version number - const { versionNumber, releaseName } = await fetch(LATEST_GETH_RELEASE_URL) - .then(response => response.json()) - .then(release => { - return { - versionNumber: release.tag_name, - releaseName: release.name - }; - }); +import { + fetchLatestReleaseCommit, + fetchLatestReleaseVersionAndName, + fetchXMLData, + getLatestBinaryURL, + getSortedReleases, + mapReleasesData +} from '../utils'; +import { LatestReleasesData, ReleaseData } from '../types'; + +// This function gets called at build time on server-side. +// It'll be called again if a new request comes in after 1hr, so data is refreshed periodically +// More info: https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration +export const getStaticProps: GetStaticProps = async () => { + // ==== LATEST RELEASES DATA ==== + + // Latest version number & release name + const { versionNumber, releaseName } = await fetchLatestReleaseVersionAndName(); // Latest release commit hash - const commit = await fetch(`${ALL_GETH_COMMITS_URL}/${versionNumber}`) - .then(response => response.json()) - .then(commit => commit.sha.slice(0, 8)); + const commit = await fetchLatestReleaseCommit(versionNumber); // Latest binaries urls - const LATEST_LINUX_BINARY_URL = `${LINUX_BINARY_BASE_URL}${versionNumber.slice( - 1 - )}-${commit}.tar.gz`; - const LATEST_MACOS_BINARY_URL = `${MACOS_BINARY_BASE_URL}${versionNumber.slice( - 1 - )}-${commit}.tar.gz`; - const LATEST_WINDOWS_BINARY_URL = `${WINDOWS_BINARY_BASE_URL}${versionNumber.slice( - 1 - )}-${commit}.exe`; + const LATEST_LINUX_BINARY_URL = getLatestBinaryURL('linux', versionNumber, commit); + const LATEST_MACOS_BINARY_URL = getLatestBinaryURL('darwin', versionNumber, commit); + const LATEST_WINDOWS_BINARY_URL = getLatestBinaryURL('windows', versionNumber, commit); // Sources urls const LATEST_SOURCES_URL = `${LATEST_SOURCES_BASE_URL}${versionNumber}.tar.gz`; @@ -71,63 +66,249 @@ export const getServerSideProps: GetServerSideProps = async () => { } }; - return { - props: { - data: { LATEST_RELEASES_DATA } - } - }; + // ==== ALL RELEASES DATA ==== + + // 1) fetch XML data + try { + const [ + ALL_LINUX_RELEASES_XML_DATA, + ALL_LINUX_ALL_TOOLS_RELEASES_XML_DATA, + ALL_MACOS_RELEASES_XML_DATA, + ALL_MACOS_ALL_TOOLS_RELEASES_XML_DATA, + ALL_WINDOWS_RELEASES_XML_DATA, + ALL_WINDOWS_ALL_TOOLS_RELEASES_XML_DATA, + ALL_ANDROID_RELEASES_XML_DATA, + ALL_IOS_RELEASES_XML_DATA + ] = await fetchXMLData(); + + // 2) XML data parsing + const parser = new XMLParser(); + + // linux + const linuxJson = parser.parse(ALL_LINUX_RELEASES_XML_DATA); + const ALL_LINUX_BLOBS_JSON_DATA = linuxJson.EnumerationResults.Blobs.Blob; + + const linuxAllToolsJson = parser.parse(ALL_LINUX_ALL_TOOLS_RELEASES_XML_DATA); + const ALL_LINUX_ALL_TOOLS_BLOBS_JSON_DATA = linuxAllToolsJson.EnumerationResults.Blobs.Blob; + + // macOS + const macOSJson = parser.parse(ALL_MACOS_RELEASES_XML_DATA); + const ALL_MACOS_BLOBS_JSON_DATA = macOSJson.EnumerationResults.Blobs.Blob; + + const macOSAllToolsJson = parser.parse(ALL_MACOS_ALL_TOOLS_RELEASES_XML_DATA); + const ALL_MACOS_ALL_TOOLS_BLOBS_JSON_DATA = macOSAllToolsJson.EnumerationResults.Blobs.Blob; + + // windows + const windowsJson = parser.parse(ALL_WINDOWS_RELEASES_XML_DATA); + const ALL_WINDOWS_BLOBS_JSON_DATA = windowsJson.EnumerationResults.Blobs.Blob; + + const windowsAllToolsJson = parser.parse(ALL_WINDOWS_ALL_TOOLS_RELEASES_XML_DATA); + const ALL_WINDOWS_ALL_TOOLS_BLOBS_JSON_DATA = windowsAllToolsJson.EnumerationResults.Blobs.Blob; + + // android + const androidJson = parser.parse(ALL_ANDROID_RELEASES_XML_DATA); + const ALL_ANDROID_BLOBS_JSON_DATA = androidJson.EnumerationResults.Blobs.Blob; + + // iOS + const iOSJson = parser.parse(ALL_IOS_RELEASES_XML_DATA); + const ALL_IOS_BLOBS_JSON_DATA = iOSJson.EnumerationResults.Blobs.Blob; + + // 3) get blobs + // linux + const LINUX_STABLE_RELEASES_DATA = mapReleasesData({ + blobsList: ALL_LINUX_BLOBS_JSON_DATA, + isStableRelease: true + }); + const LINUX_ALLTOOLS_STABLE_RELEASES_DATA = mapReleasesData({ + blobsList: ALL_LINUX_ALL_TOOLS_BLOBS_JSON_DATA, + isStableRelease: true + }); + const LINUX_DEV_BUILDS_DATA = mapReleasesData({ + blobsList: ALL_LINUX_BLOBS_JSON_DATA, + isStableRelease: false + }); + const LINUX_ALLTOOLS_DEV_BUILDS_DATA = mapReleasesData({ + blobsList: ALL_LINUX_ALL_TOOLS_BLOBS_JSON_DATA, + isStableRelease: false + }); + + // macOS + const MACOS_STABLE_RELEASES_DATA = mapReleasesData({ + blobsList: ALL_MACOS_BLOBS_JSON_DATA, + isStableRelease: true + }); + const MACOS_ALLTOOLS_STABLE_RELEASES_DATA = mapReleasesData({ + blobsList: ALL_MACOS_ALL_TOOLS_BLOBS_JSON_DATA, + isStableRelease: true + }); + const MACOS_DEV_BUILDS_DATA = mapReleasesData({ + blobsList: ALL_MACOS_BLOBS_JSON_DATA, + isStableRelease: false + }); + const MACOS_ALLTOOLS_DEV_BUILDS_DATA = mapReleasesData({ + blobsList: ALL_MACOS_ALL_TOOLS_BLOBS_JSON_DATA, + isStableRelease: false + }); + + // windows + const WINDOWS_STABLE_RELEASES_DATA = mapReleasesData({ + blobsList: ALL_WINDOWS_BLOBS_JSON_DATA, + isStableRelease: true + }); + const WINDOWS_ALLTOOLS_STABLE_RELEASES_DATA = mapReleasesData({ + blobsList: ALL_WINDOWS_ALL_TOOLS_BLOBS_JSON_DATA, + isStableRelease: true + }); + const WINDOWS_DEV_BUILDS_DATA = mapReleasesData({ + blobsList: ALL_WINDOWS_BLOBS_JSON_DATA, + isStableRelease: false + }); + const WINDOWS_ALLTOOLS_DEV_BUILDS_DATA = mapReleasesData({ + blobsList: ALL_WINDOWS_ALL_TOOLS_BLOBS_JSON_DATA, + isStableRelease: false + }); + + // android + const ANDROID_STABLE_RELEASES_DATA = mapReleasesData({ + blobsList: ALL_ANDROID_BLOBS_JSON_DATA, + isStableRelease: true + }); + const ANDROID_DEV_BUILDS_DATA = mapReleasesData({ + blobsList: ALL_ANDROID_BLOBS_JSON_DATA, + isStableRelease: false + }); + + // iOS + const IOS_STABLE_RELEASES_DATA = mapReleasesData({ + blobsList: ALL_IOS_BLOBS_JSON_DATA, + isStableRelease: true + }); + const IOS_DEV_BUILDS_DATA = mapReleasesData({ + blobsList: ALL_IOS_BLOBS_JSON_DATA, + isStableRelease: false + }); + + return { + props: { + data: { + // latest + LATEST_RELEASES_DATA, + // linux + ALL_LINUX_STABLE_RELEASES: getSortedReleases( + LINUX_STABLE_RELEASES_DATA, + LINUX_ALLTOOLS_STABLE_RELEASES_DATA + ), + ALL_LINUX_DEV_BUILDS: getSortedReleases( + LINUX_DEV_BUILDS_DATA, + LINUX_ALLTOOLS_DEV_BUILDS_DATA + ), + // macOS + ALL_MACOS_STABLE_RELEASES: getSortedReleases( + MACOS_STABLE_RELEASES_DATA, + MACOS_ALLTOOLS_STABLE_RELEASES_DATA + ), + ALL_MACOS_DEV_BUILDS: getSortedReleases( + MACOS_DEV_BUILDS_DATA, + MACOS_ALLTOOLS_DEV_BUILDS_DATA + ), + // windows + ALL_WINDOWS_STABLE_RELEASES: getSortedReleases( + WINDOWS_STABLE_RELEASES_DATA, + WINDOWS_ALLTOOLS_STABLE_RELEASES_DATA + ), + ALL_WINDOWS_DEV_BUILDS: getSortedReleases( + WINDOWS_DEV_BUILDS_DATA, + WINDOWS_ALLTOOLS_DEV_BUILDS_DATA + ), + // android + ALL_ANDROID_STABLE_RELEASES: getSortedReleases(ANDROID_STABLE_RELEASES_DATA), + ALL_ANDROID_DEV_BUILDS: getSortedReleases(ANDROID_DEV_BUILDS_DATA), + // iOS + ALL_IOS_STABLE_RELEASES: getSortedReleases(IOS_STABLE_RELEASES_DATA), + ALL_IOS_DEV_BUILDS: getSortedReleases(IOS_DEV_BUILDS_DATA) + } + }, + // using ISR here (https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration) + revalidate: 3600 // 1hr in seconds + }; + } catch (error) { + console.error(error); + + return { notFound: true }; + } }; interface Props { data: { - // TODO: define interfaces after adding the rest of the logic - LATEST_RELEASES_DATA: { - versionNumber: string; - releaseName: string; - urls: { - LATEST_LINUX_BINARY_URL: string; - LATEST_MACOS_BINARY_URL: string; - LATEST_WINDOWS_BINARY_URL: string; - LATEST_SOURCES_URL: string; - RELEASE_NOTES_URL: string; - }; - }; + // latest + LATEST_RELEASES_DATA: LatestReleasesData; + // linux + ALL_LINUX_STABLE_RELEASES: ReleaseData[]; + ALL_LINUX_DEV_BUILDS: ReleaseData[]; + // macOS + ALL_MACOS_STABLE_RELEASES: ReleaseData[]; + ALL_MACOS_DEV_BUILDS: ReleaseData[]; + // windows + ALL_WINDOWS_STABLE_RELEASES: ReleaseData[]; + ALL_WINDOWS_DEV_BUILDS: ReleaseData[]; + // android + ALL_ANDROID_STABLE_RELEASES: ReleaseData[]; + ALL_ANDROID_DEV_BUILDS: ReleaseData[]; + // iOS + ALL_IOS_STABLE_RELEASES: ReleaseData[]; + ALL_IOS_DEV_BUILDS: ReleaseData[]; }; } const DownloadsPage: NextPage = ({ data }) => { - const [amountStableReleases, updateAmountStables] = useState(DEFAULT_BUILD_AMOUNT_TO_SHOW); - const [amountDevelopBuilds, updateAmountDevelopBuilds] = useState(DEFAULT_BUILD_AMOUNT_TO_SHOW); + const { + // latest + LATEST_RELEASES_DATA, + // linux + ALL_LINUX_STABLE_RELEASES, + ALL_LINUX_DEV_BUILDS, + // macOS + ALL_MACOS_STABLE_RELEASES, + ALL_MACOS_DEV_BUILDS, + // windows + ALL_WINDOWS_STABLE_RELEASES, + ALL_WINDOWS_DEV_BUILDS, + // android + ALL_ANDROID_STABLE_RELEASES, + ALL_ANDROID_DEV_BUILDS, + // iOS + ALL_IOS_STABLE_RELEASES, + ALL_IOS_DEV_BUILDS + } = data; + + const [amountStableReleases, setAmountStableReleases] = useState(DEFAULT_BUILD_AMOUNT_TO_SHOW); + const [amountDevBuilds, setAmountDevBuilds] = useState(DEFAULT_BUILD_AMOUNT_TO_SHOW); + + const [totalStableReleases, setTotalStableReleases] = useState(ALL_LINUX_STABLE_RELEASES.length); + const [totalDevBuilds, setTotalDevBuilds] = useState(ALL_LINUX_DEV_BUILDS.length); const showMoreStableReleases = () => { - updateAmountStables(amountStableReleases + 10); + setAmountStableReleases(amountStableReleases + 10); }; - const showMoreDevelopBuilds = () => { - updateAmountDevelopBuilds(amountDevelopBuilds + 10); + const showMoreDevBuilds = () => { + setAmountDevBuilds(amountDevBuilds + 10); }; - const { - LATEST_RELEASES_DATA: { releaseName, versionNumber, urls } - } = data; - return ( <> - +
@@ -168,6 +349,7 @@ const DownloadsPage: NextPage = ({ data }) => { + {/* STABLE RELEASES */} = ({ data }) => { } sectionTitle='Stable releases' > - {/* TODO: swap test data for real data */} - - + - -

- {/* TODO: swap testDownloadData with actual data */} - - Showing {amountStableReleases} latest releases of a total{' '} - {testDownloadData.length} releases - -
+ + + {totalStableReleases > 0 + ? `Showing ${Math.min( + amountStableReleases, + totalStableReleases + )} latest releases of + a total ${totalStableReleases} releases` + : `No releases`} + - - - amountStableReleases && ( + + - Show older releases - - - + + Show older releases + + + + )} + {/* DEV BUILDS */} = ({ data }) => { } sectionTitle='Develop builds' > - {/* TODO: swap for real data */} - - + - -
- {/* TODO: swap testDownloadData with actual data */} - - Showing {amountDevelopBuilds} latest releases of a total{' '} - {testDownloadData.length} releases - -
-
- - - - Show older releases - - + + + {totalDevBuilds > 0 + ? `Showing ${Math.min(amountDevBuilds, totalDevBuilds)} latest releases of + a total ${totalDevBuilds} releases` + : `No releases`} + + + {totalDevBuilds > amountDevBuilds && ( + + + + Show older releases + + + + )}
@@ -277,13 +485,13 @@ const DownloadsPage: NextPage = ({ data }) => { > {/* TODO: swap for real data */} - + {/* TODO: swap for real data */} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000000..0a262c01dd --- /dev/null +++ b/src/types.ts @@ -0,0 +1,36 @@ +export interface LatestReleasesData { + versionNumber: string; + releaseName: string; + urls: { + LATEST_LINUX_BINARY_URL: string; + LATEST_MACOS_BINARY_URL: string; + LATEST_WINDOWS_BINARY_URL: string; + LATEST_SOURCES_URL: string; + RELEASE_NOTES_URL: string; + }; +} + +export interface ReleaseData { + release: { + label: string; + url: string; + }; + commit: { + label: string; + url: string; + }; + kind: string; + arch: string; + size: string; + published: string; + signature: { + label: string; + url: string; + }; + checksum: string; +} + +export interface ReleaseParams { + blobsList: string[]; + isStableRelease: boolean; +} diff --git a/src/utils/compareReleasesFn.ts b/src/utils/compareReleasesFn.ts new file mode 100644 index 0000000000..fa2f2b02ef --- /dev/null +++ b/src/utils/compareReleasesFn.ts @@ -0,0 +1,13 @@ +import { ReleaseData } from '../types'; + +export const compareReleasesFn = (a: ReleaseData, b: ReleaseData) => { + if (new Date(a.published) > new Date(b.published)) { + return -1; + } + + if (new Date(a.published) < new Date(b.published)) { + return 1; + } + + return 0; +}; diff --git a/src/utils/fetchLatestReleaseCommit.ts b/src/utils/fetchLatestReleaseCommit.ts new file mode 100644 index 0000000000..005abcbb33 --- /dev/null +++ b/src/utils/fetchLatestReleaseCommit.ts @@ -0,0 +1,7 @@ +import { ALL_GETH_COMMITS_URL } from '../constants'; + +export const fetchLatestReleaseCommit = (versionNumber: string) => { + return fetch(`${ALL_GETH_COMMITS_URL}/${versionNumber}`) + .then(response => response.json()) + .then(commit => commit.sha.slice(0, 8)); +}; diff --git a/src/utils/fetchLatestReleaseVersionAndName.ts b/src/utils/fetchLatestReleaseVersionAndName.ts new file mode 100644 index 0000000000..e022766067 --- /dev/null +++ b/src/utils/fetchLatestReleaseVersionAndName.ts @@ -0,0 +1,12 @@ +import { LATEST_GETH_RELEASE_URL } from '../constants'; + +export const fetchLatestReleaseVersionAndName = () => { + return fetch(LATEST_GETH_RELEASE_URL) + .then(response => response.json()) + .then(release => { + return { + versionNumber: release.tag_name as string, + releaseName: release.name as string + }; + }); +}; diff --git a/src/utils/fetchXMLData.ts b/src/utils/fetchXMLData.ts new file mode 100644 index 0000000000..a379608340 --- /dev/null +++ b/src/utils/fetchXMLData.ts @@ -0,0 +1,25 @@ +import { + ALL_ANDROID_GETH_RELEASES_URL, + ALL_IOS_GETH_RELEASES_URL, + ALL_LINUX_ALLTOOLS_GETH_RELEASES_URL, + ALL_LINUX_GETH_RELEASES_URL, + ALL_MACOS_ALLTOOLS_GETH_RELEASES_URL, + ALL_MACOS_GETH_RELEASES_URL, + ALL_WINDOWS_ALLTOOLS_GETH_RELEASES_URL, + ALL_WINDOWS_GETH_RELEASES_URL +} from '../constants'; + +export const fetchXMLData = () => { + const urls = [ + ALL_LINUX_GETH_RELEASES_URL, + ALL_LINUX_ALLTOOLS_GETH_RELEASES_URL, + ALL_MACOS_GETH_RELEASES_URL, + ALL_MACOS_ALLTOOLS_GETH_RELEASES_URL, + ALL_WINDOWS_GETH_RELEASES_URL, + ALL_WINDOWS_ALLTOOLS_GETH_RELEASES_URL, + ALL_ANDROID_GETH_RELEASES_URL, + ALL_IOS_GETH_RELEASES_URL + ]; + + return Promise.all(urls.map(url => fetch(url).then(response => response.text()))); +}; diff --git a/src/utils/getChecksum.ts b/src/utils/getChecksum.ts new file mode 100644 index 0000000000..8c7c3a34ef --- /dev/null +++ b/src/utils/getChecksum.ts @@ -0,0 +1,10 @@ +export const getChecksum = (contentMD5: string) => { + // based on https://github.com/ethereum/go-ethereum/blob/7519505d6fbd1fd29a8595aafbf880a04fb3e7e1/downloads.html#L318 + return Buffer.from(contentMD5, 'base64') + .toString('binary') + .split('') + .map(function (char) { + return ('0' + char.charCodeAt(0).toString(16)).slice(-2); + }) + .join(''); +}; diff --git a/src/utils/getLatestBinaryURL.ts b/src/utils/getLatestBinaryURL.ts new file mode 100644 index 0000000000..d9b3ec0952 --- /dev/null +++ b/src/utils/getLatestBinaryURL.ts @@ -0,0 +1,13 @@ +import { + LINUX_BINARY_BASE_URL, + MACOS_BINARY_BASE_URL, + WINDOWS_BINARY_BASE_URL +} from '../constants'; + +export const getLatestBinaryURL = (os: string, versionNumber: string, commit: string) => { + if (os === 'linux') return `${LINUX_BINARY_BASE_URL}${versionNumber.slice(1)}-${commit}.tar.gz`; + + if (os === 'darwin') return `${MACOS_BINARY_BASE_URL}${versionNumber.slice(1)}-${commit}.tar.gz`; + + return `${WINDOWS_BINARY_BASE_URL}${versionNumber.slice(1)}-${commit}.exe`; +}; diff --git a/src/utils/getParsedDate.ts b/src/utils/getParsedDate.ts new file mode 100644 index 0000000000..5c87738c12 --- /dev/null +++ b/src/utils/getParsedDate.ts @@ -0,0 +1,12 @@ +export const getParsedDate = (date: string) => { + const dateOptions = { + year: 'numeric', + month: 'long', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + timeZone: 'UTC' + } as const; + + return new Date(date).toLocaleDateString('en', dateOptions); +}; diff --git a/src/utils/getReleaseArch.ts b/src/utils/getReleaseArch.ts new file mode 100644 index 0000000000..a2633bed0a --- /dev/null +++ b/src/utils/getReleaseArch.ts @@ -0,0 +1,28 @@ +export const getReleaseArch = (filename: string) => { + const arch = filename.includes('alltools') ? filename.split('-')[3] : filename.split('-')[2]; + + switch (arch) { + case '386': + return '32-bit'; + case 'amd64': + return '64-bit'; + case 'arm5': + return 'ARMv5'; + case 'arm6': + return 'ARMv6'; + case 'arm7': + return 'ARMv7'; + case 'arm64': + return 'ARM64'; + case 'mips': + return 'MIPS32'; + case 'mipsle': + return 'MIPS32(le)'; + case 'mips64': + return 'MIPS64'; + case 'MIPS64(le)': + return 'MIPS64(le)'; + default: + return 'all'; + } +}; diff --git a/src/utils/getReleaseCommitHash.ts b/src/utils/getReleaseCommitHash.ts new file mode 100644 index 0000000000..4a769d01ce --- /dev/null +++ b/src/utils/getReleaseCommitHash.ts @@ -0,0 +1,3 @@ +export const getReleaseCommitHash = (filename: string) => { + return filename.split('-').reverse()[0].split('.')[0]; +}; diff --git a/src/utils/getReleaseCommitURL.ts b/src/utils/getReleaseCommitURL.ts new file mode 100644 index 0000000000..6560be48e5 --- /dev/null +++ b/src/utils/getReleaseCommitURL.ts @@ -0,0 +1,3 @@ +import { RELEASE_COMMIT_BASE_URL } from '../constants'; + +export const getReleaseCommitURL = (hash: string) => `${RELEASE_COMMIT_BASE_URL}${hash}`; diff --git a/src/utils/getReleaseKind.ts b/src/utils/getReleaseKind.ts new file mode 100644 index 0000000000..5b0f5d036a --- /dev/null +++ b/src/utils/getReleaseKind.ts @@ -0,0 +1,17 @@ +export const getReleaseKind = (filename: string) => { + const os = filename.includes('alltools') ? filename.split('-')[2] : filename.split('-')[1]; + + if (os == 'android' || os == 'ios') { + return 'Library'; + } + + if (os == 'windows') { + if (filename.endsWith('.exe')) { + return 'Installer'; + } else { + return 'Library'; + } + } + + return 'Archive'; +}; diff --git a/src/utils/getReleaseName.ts b/src/utils/getReleaseName.ts new file mode 100644 index 0000000000..6b40eef568 --- /dev/null +++ b/src/utils/getReleaseName.ts @@ -0,0 +1,5 @@ +export const getReleaseName = (filename: string) => { + return filename.includes('alltools') + ? `Geth & Tools ${filename.split('-')[4]}` + : `Geth ${filename.split('-')[3]}`; +}; diff --git a/src/utils/getReleaseSize.ts b/src/utils/getReleaseSize.ts new file mode 100644 index 0000000000..77153ebab8 --- /dev/null +++ b/src/utils/getReleaseSize.ts @@ -0,0 +1,8 @@ +export const getReleaseSize = (bytes: number) => { + const k = 1024; + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + + const i = Math.floor(Math.log(bytes) / Math.log(k)); + + return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`; +}; diff --git a/src/utils/getReleaseURL.ts b/src/utils/getReleaseURL.ts new file mode 100644 index 0000000000..bd083a3fa8 --- /dev/null +++ b/src/utils/getReleaseURL.ts @@ -0,0 +1,3 @@ +import { BINARIES_BASE_URL } from '../constants'; + +export const getReleaseURL = (filename: string) => `${BINARIES_BASE_URL}${filename}`; diff --git a/src/utils/getSignatureURL.ts b/src/utils/getSignatureURL.ts new file mode 100644 index 0000000000..d5107c6d89 --- /dev/null +++ b/src/utils/getSignatureURL.ts @@ -0,0 +1,4 @@ +import { BINARIES_BASE_URL } from '../constants'; + +// only .sc files are being considered for signatures (https://github.com/ethereum/go-ethereum/blob/7519505d6fbd1fd29a8595aafbf880a04fb3e7e1/downloads.html#L299) +export const getSignatureURL = (filename: string) => `${BINARIES_BASE_URL}${filename}.asc`; diff --git a/src/utils/getSortedReleases.ts b/src/utils/getSortedReleases.ts new file mode 100644 index 0000000000..830c406852 --- /dev/null +++ b/src/utils/getSortedReleases.ts @@ -0,0 +1,6 @@ +import { ReleaseData } from './../types'; +import { compareReleasesFn } from './compareReleasesFn'; + +export const getSortedReleases = (releases: ReleaseData[], moreReleases: ReleaseData[] = []) => { + return releases.concat(moreReleases).sort(compareReleasesFn); +}; diff --git a/src/utils/index.ts b/src/utils/index.ts index e3d2a70842..dcc6c5caa4 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1 +1,18 @@ -export * from './getProgrammingLanguageName'; +export { compareReleasesFn } from './compareReleasesFn'; +export { fetchLatestReleaseCommit } from './fetchLatestReleaseCommit'; +export { fetchLatestReleaseVersionAndName } from './fetchLatestReleaseVersionAndName'; +export { fetchXMLData } from './fetchXMLData'; +export { getLatestBinaryURL } from './getLatestBinaryURL'; +export { getChecksum } from './getChecksum'; +export { getParsedDate } from './getParsedDate'; +export { getProgrammingLanguageName } from './getProgrammingLanguageName'; +export { getReleaseArch } from './getReleaseArch'; +export { getReleaseCommitHash } from './getReleaseCommitHash'; +export { getReleaseCommitURL } from './getReleaseCommitURL'; +export { getReleaseKind } from './getReleaseKind'; +export { getReleaseName } from './getReleaseName'; +export { getReleaseSize } from './getReleaseSize'; +export { getReleaseURL } from './getReleaseURL'; +export { getSignatureURL } from './getSignatureURL'; +export { getSortedReleases } from './getSortedReleases'; +export { mapReleasesData } from './mapReleasesData'; diff --git a/src/utils/mapReleasesData.ts b/src/utils/mapReleasesData.ts new file mode 100644 index 0000000000..96db513945 --- /dev/null +++ b/src/utils/mapReleasesData.ts @@ -0,0 +1,45 @@ +import { + getChecksum, + getReleaseArch, + getReleaseCommitHash, + getReleaseCommitURL, + getReleaseKind, + getReleaseName, + getReleaseSize, + getReleaseURL, + getSignatureURL +} from '.'; + +import { ReleaseData, ReleaseParams } from '../types'; + +export const mapReleasesData = ({ blobsList, isStableRelease }: ReleaseParams): ReleaseData[] => { + return blobsList + .filter(({ Name }: any) => !Name.endsWith('.asc') && !Name.endsWith('.sig')) // skip blobs we don't need to list + .filter(({ Name }: any) => + isStableRelease ? !Name.includes('unstable') : Name.includes('unstable') + ) // filter by stable/dev builds + .map(({ Name, Properties }: any) => { + const commitHash = getReleaseCommitHash(Name); + + return { + release: { + label: getReleaseName(Name), + url: getReleaseURL(Name) + }, + commit: { + label: commitHash, + url: getReleaseCommitURL(commitHash) + }, + kind: getReleaseKind(Name), + arch: getReleaseArch(Name), + size: getReleaseSize(Properties['Content-Length']), + // date is formatted later on the table, we use the raw value here for comparison + published: Properties['Last-Modified'], + signature: { + label: 'Signature', + url: getSignatureURL(Name) + }, + checksum: getChecksum(Properties['Content-MD5']) + }; + }); +}; diff --git a/yarn.lock b/yarn.lock index b4a8d58fea..9cee803ca5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -73,7 +73,7 @@ "@chakra-ui/accordion@2.0.12": version "2.0.12" - resolved "https://registry.npmjs.org/@chakra-ui/accordion/-/accordion-2.0.12.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/accordion/-/accordion-2.0.12.tgz#dd260fbecb639748314f440c89052ed45006c585" integrity sha512-O3qq8mILo1QODjCGr2xwxC5LNFakBoMzTjEgpvpIMynxWc/1RKfGuFLis3IDfpHIicXmBTK6sNiZXewmna88CQ== dependencies: "@chakra-ui/descendant" "3.0.9" @@ -85,7 +85,7 @@ "@chakra-ui/alert@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/alert/-/alert-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/alert/-/alert-2.0.9.tgz#25e88c105e095def374c9fe1e3c8a3f6fab08f6c" integrity sha512-hFRIh6ZzQJ0sAESRym15mW/mcZE/yu4z6lFtdToBhpfSlhZLuE7gDdOTxqGkg417hY//48NiNXOCoQ2dUUuHKw== dependencies: "@chakra-ui/icon" "3.0.9" @@ -94,12 +94,12 @@ "@chakra-ui/anatomy@2.0.6": version "2.0.6" - resolved "https://registry.npmjs.org/@chakra-ui/anatomy/-/anatomy-2.0.6.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/anatomy/-/anatomy-2.0.6.tgz#83164841d27eaa271ffa747534519bcd323c312f" integrity sha512-Vgop2FFdhVtX7BydjZdJWZAWy+DdXBU1IMaBppz6COaH+/7OXxoI2ec2bs17ehJyBO0M+ud3OLj5UCFQ79YsoQ== "@chakra-ui/avatar@2.1.0": version "2.1.0" - resolved "https://registry.npmjs.org/@chakra-ui/avatar/-/avatar-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/avatar/-/avatar-2.1.0.tgz#009b4e126c58ef0183618cfbfb29f8e7e3357ee9" integrity sha512-SRQeH6NNvIBgUc4OsO14ypvcn8I66ndw7r4piIkm+R2zqbYnrzpp1d2zNPNHkChc4xQY71/GenenYO5Fhsi2DA== dependencies: "@chakra-ui/image" "2.0.10" @@ -108,7 +108,7 @@ "@chakra-ui/breadcrumb@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/breadcrumb/-/breadcrumb-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/breadcrumb/-/breadcrumb-2.0.9.tgz#357e4e2a50cdad87c0b3b59656aafa85671e6142" integrity sha512-cc3WbxrJNRUph4v45qCdcIKJI0xECeV9VikQNIactBB+iexN4d+5P66xZABAkD8wWGmyH5KuSZcd9sFYNmC13w== dependencies: "@chakra-ui/react-children-utils" "2.0.1" @@ -116,12 +116,12 @@ "@chakra-ui/breakpoint-utils@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/breakpoint-utils/-/breakpoint-utils-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/breakpoint-utils/-/breakpoint-utils-2.0.3.tgz#af7f7603f31a7d8d0166307a47e88cf5902401b4" integrity sha512-smi41ZtaiPw4mXaCgicyAh5M45Drt20wypThP+qQUT2CQ51UFZhYlItRA2lCXKQ9QB83POcHPC/oAwIsNOAfTg== "@chakra-ui/button@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/button/-/button-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/button/-/button-2.0.9.tgz#f005f98bb5f1d5673a244957e6b3e2396acdf395" integrity sha512-4BuDBiBlChHW1rQ9iod9MKs87AY3IyvZQwjV3DZTU4IG0KcDDfLQf++jj4dkg9Ttu+pIWhwF42pzA40JxW1oNg== dependencies: "@chakra-ui/react-context" "2.0.3" @@ -130,7 +130,7 @@ "@chakra-ui/checkbox@2.1.8": version "2.1.8" - resolved "https://registry.npmjs.org/@chakra-ui/checkbox/-/checkbox-2.1.8.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/checkbox/-/checkbox-2.1.8.tgz#d04a9a65494cf22e8bcfafa161bb7185d92dc13b" integrity sha512-HhRs3nwTFoIE/UpX4N2AZxxW39Xm/Vw01HjwP/59X60kdKs3RBXlm52cODkfUDfveyT9o5ezLhU/jRf0qA909Q== dependencies: "@chakra-ui/form-control" "2.0.9" @@ -146,33 +146,33 @@ "@chakra-ui/clickable@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/clickable/-/clickable-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/clickable/-/clickable-2.0.9.tgz#c06486d36f4a4cb517ea75176e05021dfde117cd" integrity sha512-tGXYM6M6I954fif98QkNu5M76oBZmksCTj2mILOan9/BSimpFpu06aPGX3ZIkNsz300nIObn0FdtMvKpIEQueA== dependencies: "@chakra-ui/react-use-merge-refs" "2.0.3" "@chakra-ui/close-button@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/close-button/-/close-button-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/close-button/-/close-button-2.0.9.tgz#dab2d66c7a240c4d3d150e370980709336a4a266" integrity sha512-0RI/zLR+/mycGbYCCwDAc9hAVG7IIVmdikmo1ET7+rYip4TN94aWR0hA4dYtWqqghG1oW/pYQ9Yja6fEY90V5w== dependencies: "@chakra-ui/icon" "3.0.9" "@chakra-ui/color-mode@2.1.7": version "2.1.7" - resolved "https://registry.npmjs.org/@chakra-ui/color-mode/-/color-mode-2.1.7.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/color-mode/-/color-mode-2.1.7.tgz#91c02e82e551c5448081e4934efeddb10bb732c5" integrity sha512-GAoKJzVRQeuEfCa2i0BZdMwxuOoaGknU3+5wgvLuaSpwlov4OyqpjKMRdSdpjr4IFiqqHK47dsr3H4LQsbO+9w== dependencies: "@chakra-ui/react-use-safe-layout-effect" "2.0.1" "@chakra-ui/control-box@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/control-box/-/control-box-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/control-box/-/control-box-2.0.9.tgz#b3cd98ceb1ce683c00445ab7469e65ba3d90c3cc" integrity sha512-/viS9OBah1wCLNZbgfwkoQOnVRUYgp8Gypjqk9QNQwnNdFUTEgWc1RWN+1RYO85esJzHLkA2hZFIrYu1TZeZ6g== "@chakra-ui/counter@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/counter/-/counter-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/counter/-/counter-2.0.9.tgz#b1b7c74c4e5d1ac506d699d93da57d535370a702" integrity sha512-LuqtpyxCOZM19gAmV0vtVeaFd9ccPmEjoGJQ0NoO8CFheltgLC/7m/8YpDbgWiG4+BAkTUfIG+5nLg5hwvvQxw== dependencies: "@chakra-ui/number-utils" "2.0.3" @@ -180,12 +180,12 @@ "@chakra-ui/css-reset@2.0.7": version "2.0.7" - resolved "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-2.0.7.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/css-reset/-/css-reset-2.0.7.tgz#28f4284c36230e30892dc3f2de2464aaacc4f623" integrity sha512-ztGdFQ6U1hX2k6a3HZ8D3A/dZWVxlGe2F5mvUrRU554mFWBYmsq0ydZ7UBEPlykv9NoCz4nN8VCkIxcKJ3p29Q== "@chakra-ui/descendant@3.0.9": version "3.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/descendant/-/descendant-3.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/descendant/-/descendant-3.0.9.tgz#6574a1ce00067c49a070c5b005f8f1ca399006ea" integrity sha512-30E5yMWvxgBx43PoI/67r9h9OhbpDfLb/MLOCjtEwebSbD0V5+fmnmCoUELScQbhozQVjA9t195X6UP0VQWj8w== dependencies: "@chakra-ui/react-context" "2.0.3" @@ -193,12 +193,12 @@ "@chakra-ui/dom-utils@2.0.1": version "2.0.1" - resolved "https://registry.npmjs.org/@chakra-ui/dom-utils/-/dom-utils-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/dom-utils/-/dom-utils-2.0.1.tgz#3061819ac365f5947423d63a5fcc26a281bbb5c2" integrity sha512-sbob9AHQq1+KIQ3XKslafislwtC8pYcpwM0S1SLzgyZumHRwhDimKwdi4MtRQfOCenub0E3diRjp4RpGRL0JuQ== "@chakra-ui/editable@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/editable/-/editable-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/editable/-/editable-2.0.9.tgz#a31d2e1c176c0817574e98a8567314c1a74444ab" integrity sha512-s5F3UMR09s6ga3eVhw0UBMGmegtxg6jCp29VLqaEwP5BuWIEOjcJz358gTlnFr3dhvb31e3rcr+B1XiYv4wxqg== dependencies: "@chakra-ui/react-context" "2.0.3" @@ -212,12 +212,12 @@ "@chakra-ui/event-utils@2.0.4": version "2.0.4" - resolved "https://registry.npmjs.org/@chakra-ui/event-utils/-/event-utils-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/event-utils/-/event-utils-2.0.4.tgz#eeb3eb4f37c3828955dbbc182ea43a8a3238a599" integrity sha512-J2YgAM5Dw9hMkwfMsWhsiAG848GfTMxNclUIUcgV9RQhLEs0eTFhelzNiKVOMA3vBxlT6lOARuRun/ESiFZgGg== "@chakra-ui/focus-lock@2.0.10": version "2.0.10" - resolved "https://registry.npmjs.org/@chakra-ui/focus-lock/-/focus-lock-2.0.10.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/focus-lock/-/focus-lock-2.0.10.tgz#8f17d212786bd2977afc07f72b520aeae30b9434" integrity sha512-LeRZYzwfJp0eq84oO8e1pC2qC8v8fJw/P4nYDrCDjuJU753DV6nVjp5MKMRqbkp+6IAElPc+ojy/sp2a9GCocw== dependencies: "@chakra-ui/dom-utils" "2.0.1" @@ -225,7 +225,7 @@ "@chakra-ui/form-control@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/form-control/-/form-control-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/form-control/-/form-control-2.0.9.tgz#10678857e6586e7d1be0a34c8d045c6484c1180b" integrity sha512-P8Tr45z/XSAa1m6uAma0eKf1h7Ltg2sLj2jK5YhaXJER9VUUY18iGe96D4JrAXlgEWDhTyWMb63nB+eYO1tKtw== dependencies: "@chakra-ui/icon" "3.0.9" @@ -235,7 +235,7 @@ "@chakra-ui/hooks@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/hooks/-/hooks-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/hooks/-/hooks-2.0.9.tgz#1f6d6157968a60dd9678112763d8f5fd3bdeffad" integrity sha512-0JRgEPtsBaXr9nQW1xEKlWGA7WwFbLNqac7fQXp9zQvoHOWTfNJkK/NJaVBvyFPgfTLxy37WKHooVSwNG/Lwmg== dependencies: "@chakra-ui/react-utils" "2.0.6" @@ -245,14 +245,14 @@ "@chakra-ui/icon@3.0.11": version "3.0.11" - resolved "https://registry.npmjs.org/@chakra-ui/icon/-/icon-3.0.11.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/icon/-/icon-3.0.11.tgz#a51dda24bed2f2ed77b4136ada8f22d3249c9870" integrity sha512-RG4jf/XmBdaxOYI5J5QstEtTCPoVlmrQ/XiWhvN0LTgAnmZIqVwFl3Uw+satArdStHAs0GmJZg/E/soFTWuFmw== dependencies: "@chakra-ui/shared-utils" "2.0.2" "@chakra-ui/icon@3.0.9": version "3.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/icon/-/icon-3.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/icon/-/icon-3.0.9.tgz#ba127d9eefd727f62e9bce07a23eca39ae506744" integrity sha512-P2Pwm/za6m1W1oqL2kGHH6XrrymsBjqYAFwOW2lB5Q6mI1e+RYe/iMxDoPSLHMYhqdfH7vyib/ffE3Vv3a5oTA== dependencies: "@chakra-ui/shared-utils" "2.0.1" @@ -266,14 +266,14 @@ "@chakra-ui/image@2.0.10": version "2.0.10" - resolved "https://registry.npmjs.org/@chakra-ui/image/-/image-2.0.10.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/image/-/image-2.0.10.tgz#712c0e1c579d959225bd8316d8d8f66cbeb95bb8" integrity sha512-Atc1bdog4V5xv7IbpF2F2UkKWfgG/TD74cIac09JuSpQcYyh7lrJ7iVvhTkeP+LDdCs+QCD7SnTUM4Y0ZlaHbA== dependencies: "@chakra-ui/react-use-safe-layout-effect" "2.0.1" "@chakra-ui/input@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/input/-/input-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/input/-/input-2.0.9.tgz#905b82ed647a20080a25a6a7e6740e3bb65586c1" integrity sha512-6MKydxTyF7JV7PtQHircQ5HBTd6Ik9Vn7p8fCLeAieT0TK8UQTxMWZVPminS7TRWMutrq8W99DcQOBlMz0cKrw== dependencies: "@chakra-ui/form-control" "2.0.9" @@ -284,7 +284,7 @@ "@chakra-ui/layout@2.1.6": version "2.1.6" - resolved "https://registry.npmjs.org/@chakra-ui/layout/-/layout-2.1.6.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/layout/-/layout-2.1.6.tgz#3dfdd8b3f08d9ff34fc923d44ebe4bc86291b889" integrity sha512-QDNaVu44UI46c+YlSF1KrzJkiwua0UtRXNTnR3jBE1uzcuqRow7xgr3E60dLphY2cPFqAljfQZUNlP3sgvCLww== dependencies: "@chakra-ui/breakpoint-utils" "2.0.3" @@ -296,17 +296,17 @@ "@chakra-ui/lazy-utils@2.0.1": version "2.0.1" - resolved "https://registry.npmjs.org/@chakra-ui/lazy-utils/-/lazy-utils-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/lazy-utils/-/lazy-utils-2.0.1.tgz#6814836552028fa0823563ce3d39d22bccb203e1" integrity sha512-986YjYq+hEzHDLZiqYlYbdqfiKdC3h2g896Eoe5K2UXtAVxqZI3UOnMH781X6N1R7rGJWquskzG681qFigW/BA== "@chakra-ui/live-region@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/live-region/-/live-region-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/live-region/-/live-region-2.0.9.tgz#f26cf1b96df51515cd3a0897f9516f8b5f6bbfec" integrity sha512-ilbo/C5wcUoSHDU5owFPQP3KsabPYGzDEbwV+Z76BlyNdFN2PD0j13RGEH+sBNNZ3HzLyyuuc1YmkVcJi7ycQg== "@chakra-ui/media-query@3.2.5": version "3.2.5" - resolved "https://registry.npmjs.org/@chakra-ui/media-query/-/media-query-3.2.5.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/media-query/-/media-query-3.2.5.tgz#c0b9dc4bc6245d9abddcbe17693e40bf5dfe34f8" integrity sha512-V+Dngi/r7u/uj7JhsZerM1RI597Oo4wED2ojNfclnnEVb/IoqktiuFy6RQgbo3HmE7M/E5B1i4yYzt7tQJhXlg== dependencies: "@chakra-ui/breakpoint-utils" "2.0.3" @@ -314,7 +314,7 @@ "@chakra-ui/menu@2.0.13": version "2.0.13" - resolved "https://registry.npmjs.org/@chakra-ui/menu/-/menu-2.0.13.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/menu/-/menu-2.0.13.tgz#3ac5f448efc894045769c606ebe1376051556be9" integrity sha512-XZYoq9k/txAELUgn5OokyxfXEpVZwBueVYXiT9ji0XvMuzXVxeHd40klJEkiJUctNsOahZf10t5yxlT4B00pwA== dependencies: "@chakra-ui/clickable" "2.0.9" @@ -334,7 +334,7 @@ "@chakra-ui/modal@2.1.7": version "2.1.7" - resolved "https://registry.npmjs.org/@chakra-ui/modal/-/modal-2.1.7.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/modal/-/modal-2.1.7.tgz#dba55bddd407689f4c2bba886b03a5355578a20d" integrity sha512-A+CbvhQYpmLH3SrqJ1wJysUCGm0mNoSDxRjP4wX98j56nMTDAsMYlzttpuLmKaSzvbJ7uEQDLtQV8lZjB0gUuw== dependencies: "@chakra-ui/close-button" "2.0.9" @@ -349,7 +349,7 @@ "@chakra-ui/number-input@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/number-input/-/number-input-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/number-input/-/number-input-2.0.9.tgz#c5ebfa0311f7586fb4c1e5f4284355b1d1f04383" integrity sha512-RsDzoNvSBZMgyXjN543AtQ2v99U1p/0xnGWZy4NCkgCDWMBn3kIXqSzQq5CB9Ot0MD8nnKF5VYdVdXWguXExEQ== dependencies: "@chakra-ui/counter" "2.0.9" @@ -366,17 +366,17 @@ "@chakra-ui/number-utils@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/number-utils/-/number-utils-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/number-utils/-/number-utils-2.0.3.tgz#2cf1190647ac5a17c90baaf8176226a98eb3bfff" integrity sha512-oN03kYAUCCp/FNtpLr5mh+cvd/sRTzZWTBoFydmxc955psXq/X950gzs6o5kzoeFCpgXaxMmHAXQm3ReEK2NsQ== "@chakra-ui/object-utils@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/object-utils/-/object-utils-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/object-utils/-/object-utils-2.0.3.tgz#0bc8d1c7c452fe1ce8fcda439336e0392e867d7e" integrity sha512-36prckrqTynVD/JTzyCr8OCWVOrMs/awZo3djVbIiNxRIcJ5iEwUVy26h3MWN4ENSopipBtxNfAwPNTLU5Si/g== "@chakra-ui/pin-input@2.0.12": version "2.0.12" - resolved "https://registry.npmjs.org/@chakra-ui/pin-input/-/pin-input-2.0.12.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/pin-input/-/pin-input-2.0.12.tgz#1ff927fdc61433a7b9b4421ceafad5674299e91a" integrity sha512-gaMRp5AFW+qAJCUj93V1WluuYBBZ/5A3Wy5q796g8Auvw7vufgkVtl6EBznwvtynZN8gJwbRFpMtJxQyXCkUiw== dependencies: "@chakra-ui/descendant" "3.0.9" @@ -387,7 +387,7 @@ "@chakra-ui/popover@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/popover/-/popover-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/popover/-/popover-2.0.9.tgz#7f2df4cbbc3eee7440c311750e18ba00150f973f" integrity sha512-+7tH4RVuheFQOyAZ5KT9x+qsLvz7rGuKaHtb0427+5bhUzLaSAghtr/afzOKHDwUVBwF2tTUNanR23ipW1fXDg== dependencies: "@chakra-ui/close-button" "2.0.9" @@ -401,7 +401,7 @@ "@chakra-ui/popper@3.0.7": version "3.0.7" - resolved "https://registry.npmjs.org/@chakra-ui/popper/-/popper-3.0.7.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/popper/-/popper-3.0.7.tgz#af3428bf5d64ad9372210a70181f69a9d79eefb2" integrity sha512-xLYhuNsk1gOjymtek1ZdZlG21hmg2a7Iu2KsD9Hi7+aUxc2K5/XxX+/vyjjz8u4s0gmj83pTqnauQRynb/TCXA== dependencies: "@chakra-ui/react-types" "2.0.3" @@ -410,7 +410,7 @@ "@chakra-ui/portal@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/portal/-/portal-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/portal/-/portal-2.0.9.tgz#b427c383a9d602c5b52b21312b4b1c0ffecaf583" integrity sha512-9e9S0MLbkpofPGlyYA12jNYSdndugy6ylPi5pC9nr3/VqG2Kn+8VcBChAeXW8K4ms7WFc74rNX1pBY/UVwr4qg== dependencies: "@chakra-ui/react-context" "2.0.3" @@ -418,14 +418,14 @@ "@chakra-ui/progress@2.0.10": version "2.0.10" - resolved "https://registry.npmjs.org/@chakra-ui/progress/-/progress-2.0.10.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/progress/-/progress-2.0.10.tgz#9191ae9061ef08066d37c5cb8341fedc10214a29" integrity sha512-my0Pi3NG1PYhlvCav4fybg3gL5HBNe+7lO4PVdri4QHEyfJlrDeBWID+1GgqlpUWdTj3sOf7ysku+FEgkeOeSA== dependencies: "@chakra-ui/react-context" "2.0.3" "@chakra-ui/provider@2.0.16": version "2.0.16" - resolved "https://registry.npmjs.org/@chakra-ui/provider/-/provider-2.0.16.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/provider/-/provider-2.0.16.tgz#a4afdb4c8f2050beb5d2b61db8971a145481c6f2" integrity sha512-4t/PmjJ7WXPPaPfoYgw8F1/rVtorZuvknugHfOZcOtAPGQmOPotSv28qjKpu/mCvc1GMGV0swMsvCeInYz7g0w== dependencies: "@chakra-ui/css-reset" "2.0.7" @@ -436,7 +436,7 @@ "@chakra-ui/radio@2.0.10": version "2.0.10" - resolved "https://registry.npmjs.org/@chakra-ui/radio/-/radio-2.0.10.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/radio/-/radio-2.0.10.tgz#82eb02313efafc460da3030d011bfd434b1ecabc" integrity sha512-LhAWsY22cmb+M/iyhFgkzf2+V9TJmAC77Cd+GbP3M3sxDSEUDtq08KOc3JjoYc3GzeZml3JL1yssbxh+liY3xA== dependencies: "@chakra-ui/form-control" "2.0.9" @@ -447,27 +447,27 @@ "@chakra-ui/react-children-utils@2.0.1": version "2.0.1" - resolved "https://registry.npmjs.org/@chakra-ui/react-children-utils/-/react-children-utils-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-children-utils/-/react-children-utils-2.0.1.tgz#321ac05362ade1495a34ea74052d3c7da3d9e923" integrity sha512-sEgpuh/vWSt2+W0F49EGYXXUyjmg0lbosjVg6qUKHv9sAyx5tbrOrZ6df/TaMUSAe9m3AUOMGqUIPLpxno0DjA== "@chakra-ui/react-context@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/react-context/-/react-context-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-context/-/react-context-2.0.3.tgz#e988be62f5f5fe29d6a8496c79cbf934f840fa5a" integrity sha512-KmPq6sb1y05WsOUqXZtBBC4LsNKZIFrp2thTsLBwcuH7lkXZwPMHmJGKa9K980P+SWEgfH2s2PY2z+QrIuqWGg== "@chakra-ui/react-env@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/react-env/-/react-env-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-env/-/react-env-2.0.9.tgz#d51efc31d77197a3526e2c4b2f2fde557396bb3c" integrity sha512-4AJHNUGBR19hzVyOILYpZZgq8jGrpEcbhvR++CppbvPH7vfPZpoz6L/cBtHxS07YwDtUeBL8yCNiLlTxctV//Q== "@chakra-ui/react-types@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/react-types/-/react-types-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-types/-/react-types-2.0.3.tgz#dc454c4703b4de585e6461fd607304ede06fe595" integrity sha512-1mJYOQldFTALE0Wr3j6tk/MYvgQIp6CKkJulNzZrI8QN+ox/bJOh8OVP4vhwqvfigdLTui0g0k8M9h+j2ub/Mw== "@chakra-ui/react-use-animation-state@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-animation-state/-/react-use-animation-state-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-animation-state/-/react-use-animation-state-2.0.3.tgz#c10e575de76e907a84358595884a819039b24200" integrity sha512-sjGgzMMmxurwKDSFhDLpLNn3SWUERI5iAZOOa0pYnyOLGVXMowgIjK6jpZxre1vc3A+unjJk5P4qeiyY+C4uwQ== dependencies: "@chakra-ui/dom-utils" "2.0.1" @@ -475,33 +475,33 @@ "@chakra-ui/react-use-callback-ref@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-callback-ref/-/react-use-callback-ref-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-callback-ref/-/react-use-callback-ref-2.0.3.tgz#532f993ae0dda27b2638d41e98f42c83751cd3b6" integrity sha512-kdYlhgnQKWWLNwl3WSv/Oq3+mlnu2p3y4Xc1AqKVHVcBOdQE9lpW3d7ZaOoK2aIXXWq1rocscOiXBUtM0Vqd2A== "@chakra-ui/react-use-controllable-state@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-controllable-state/-/react-use-controllable-state-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-controllable-state/-/react-use-controllable-state-2.0.3.tgz#7aa3f9c038513763332f6754e69ece90aed55a9c" integrity sha512-su8efwCWWnY2LQUU6PEnYwSGJX8kvPSO2KyUKuymx8q3fNWuyhzAZriG/TbeeCxESLp70+wuniUlSGRa4vxylQ== dependencies: "@chakra-ui/react-use-callback-ref" "2.0.3" "@chakra-ui/react-use-disclosure@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-disclosure/-/react-use-disclosure-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-disclosure/-/react-use-disclosure-2.0.3.tgz#c27bfc7e3af0728423b9e2def1e1665d0ba941bb" integrity sha512-3IdrzvQZcgjqSx5wTVffInOyhMU+d3ZlIE26JmqejMyN/B+qAs932iKfm0A1mTMPTz38ZnNtuaKazmzyfR1ePg== dependencies: "@chakra-ui/react-use-callback-ref" "2.0.3" "@chakra-ui/react-use-event-listener@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-event-listener/-/react-use-event-listener-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-event-listener/-/react-use-event-listener-2.0.3.tgz#11b5409c4442888e7981d5288c9e781acdacd685" integrity sha512-m3ZdJjo3QQ1HcQGnehlBTgHaCVewz5fwIRTXVzbZTraVJr4k589Zf87eagW57tT4dyv656lSmdhaFGZ8p5Snww== dependencies: "@chakra-ui/react-use-callback-ref" "2.0.3" "@chakra-ui/react-use-focus-effect@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-focus-effect/-/react-use-focus-effect-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-focus-effect/-/react-use-focus-effect-2.0.3.tgz#3e221a5e9b06a7b832a6fca1f883e6335fd69f19" integrity sha512-N0rho7P+rH5cn13dbS8GUOye+6RYXAmXhmlS+WW/3lWidGH3HAbMoOVf56UiuSnE1+2or8/U7qRshUryj2H1nA== dependencies: "@chakra-ui/dom-utils" "2.0.1" @@ -510,33 +510,33 @@ "@chakra-ui/react-use-focus-on-pointer-down@2.0.1": version "2.0.1" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-focus-on-pointer-down/-/react-use-focus-on-pointer-down-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-focus-on-pointer-down/-/react-use-focus-on-pointer-down-2.0.1.tgz#be0668ff844dec8bbfe978d6eaff50534f290c48" integrity sha512-f0qL2iWvajUo+0jwDZyJpUMJ6J6BH3WjDZE2Rp6cns4pgI6uYuv2gj+FqQ5jnoYdXkeER6lBI56a+aIW/1RYiA== dependencies: "@chakra-ui/react-use-event-listener" "2.0.3" "@chakra-ui/react-use-interval@2.0.1": version "2.0.1" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-interval/-/react-use-interval-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-interval/-/react-use-interval-2.0.1.tgz#a8f5dbf83607f5dc53022aa2a766fdcb09d8a081" integrity sha512-6ZLzKA7Ga894UZcXO3bbGYThlhviiau1oxZ1UcJG5pUXNM9Up7O/4Joq31sL+KcpteCN45vd1etomilsv/blxw== dependencies: "@chakra-ui/react-use-callback-ref" "2.0.3" "@chakra-ui/react-use-merge-refs@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-merge-refs/-/react-use-merge-refs-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-merge-refs/-/react-use-merge-refs-2.0.3.tgz#cd8dac79c62dd45daaf4acc4507721d23dc5dc51" integrity sha512-n35BmVbasy5Esa6qxznWmiV3NaRxGpqMpZH0n+X7aXt8VkGAJzRpAVjUmKCLNYyCLpqsQceCmAEK8a5SR6vxqw== "@chakra-ui/react-use-outside-click@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-outside-click/-/react-use-outside-click-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-outside-click/-/react-use-outside-click-2.0.3.tgz#d0136d1c2fb45d86361224e98e3a50648bf9b85f" integrity sha512-r5OohM8lOuZTz6e3vVHvfm/3sEkd06nUPBNU+r3rWh1I7bR9z5Gia/BOQD6GE4jUTanDkHcH76Pf9qJ45kpibQ== dependencies: "@chakra-ui/react-use-callback-ref" "2.0.3" "@chakra-ui/react-use-pan-event@2.0.4": version "2.0.4" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-pan-event/-/react-use-pan-event-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-pan-event/-/react-use-pan-event-2.0.4.tgz#bfc2c1a2a44b2996951a729182566f02c7dc05e4" integrity sha512-lcEjngfCgIjE5qZeJiaDx+aJzZPLjbjUmbWumi8pIgWOnDL8Ffjh7AMKW4CddP5OgcRnDDb+7aqJbb55wraboA== dependencies: "@chakra-ui/event-utils" "2.0.4" @@ -544,36 +544,36 @@ "@chakra-ui/react-use-previous@2.0.1": version "2.0.1" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-previous/-/react-use-previous-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-previous/-/react-use-previous-2.0.1.tgz#e19f6b363271f62c36c9f3bd91dc60caa4c4e340" integrity sha512-ROi+/puVd8D1QaxBSOcGlJNqV2x02ppSgmXzZZJhM8ryFLZjY9ojV3HhamB2IJ/7SIb1rMSSV1GPedFw7YMCwA== "@chakra-ui/react-use-safe-layout-effect@2.0.1": version "2.0.1" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-safe-layout-effect/-/react-use-safe-layout-effect-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-safe-layout-effect/-/react-use-safe-layout-effect-2.0.1.tgz#76f8882abaf17078c3b6eb93e1bb26f8c319f3f7" integrity sha512-H+ZOjkPqv3KBPEoP68JKpQBNdLOI0mwzEiTT397UdvBVCCJ+1/ijWVUT+Ub/pYic60O6xUghy5ORaWqJHhnKDA== "@chakra-ui/react-use-size@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-size/-/react-use-size-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-size/-/react-use-size-2.0.3.tgz#ae3bd683eb87a40208cf0dd467a5dafb68d87b3e" integrity sha512-hr4hKepPUmM2paXseSZiOTK2y+ZqnSzYNusDEB01f+cDerFjdN1jSfNJKXpiKF0+hNESXfOPQb3Zt0eDusRdoA== dependencies: "@zag-js/element-size" "0.1.0" "@chakra-ui/react-use-timeout@2.0.1": version "2.0.1" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-timeout/-/react-use-timeout-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-timeout/-/react-use-timeout-2.0.1.tgz#acacadfb7c1443aacf634ddce710b1cd7cf3b6ec" integrity sha512-zXh9RH+GciKr8hvaOADHOoHP72B7UZUEymA8CWCV4WEs/9s/PfQJH7X1bwvaj43CcOmfVQg4oODWqCYQM1lSsg== dependencies: "@chakra-ui/react-use-callback-ref" "2.0.3" "@chakra-ui/react-use-update-effect@2.0.3": version "2.0.3" - resolved "https://registry.npmjs.org/@chakra-ui/react-use-update-effect/-/react-use-update-effect-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-update-effect/-/react-use-update-effect-2.0.3.tgz#5b0128fe1325b5b1413690db6bc8dd0712d01e29" integrity sha512-8hkP1o/UUUA49w/R+XyAlPiCjxXTCWCNsHWUOEhAitjJfoCNUjgaNKOD52hT07kc5ACJEcJQHA5327LnwtiIlg== "@chakra-ui/react-utils@2.0.6": version "2.0.6" - resolved "https://registry.npmjs.org/@chakra-ui/react-utils/-/react-utils-2.0.6.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-utils/-/react-utils-2.0.6.tgz#bb471ce2bff724b99563685962145a2cc56bf61d" integrity sha512-ZL0FPaolovXOxMzYRSLHgBYtvxIkA/c5GTSYpXL8DcC+TBLZnAmQ8BPTS2b6xys6xvwdQjkZRUeQ0cBNFaryJg== dependencies: "@chakra-ui/utils" "2.0.9" @@ -633,24 +633,24 @@ "@chakra-ui/select@2.0.10": version "2.0.10" - resolved "https://registry.npmjs.org/@chakra-ui/select/-/select-2.0.10.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/select/-/select-2.0.10.tgz#827028484769a32205f99baed3098a115da292b3" integrity sha512-7AslBWwI/JyczjMMGtPuN34M/C38koVd+N/pb6swHoIP9TRkkdvDlonIakcmtO1oLEzlNIFKmt4FQ7bUp9ea5Q== dependencies: "@chakra-ui/form-control" "2.0.9" "@chakra-ui/shared-utils@2.0.1": version "2.0.1" - resolved "https://registry.npmjs.org/@chakra-ui/shared-utils/-/shared-utils-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/shared-utils/-/shared-utils-2.0.1.tgz#41e314e42c96039e8ffb265e73145cf755813ab4" integrity sha512-NXDBl/u4wrSNp0ON5R3r3evkRurrAz2yuO7neooaG+O5HEenVouGqm4CsXd6lUAPmjwiGzA0LQFNCt0Hj92dXg== "@chakra-ui/shared-utils@2.0.2": version "2.0.2" - resolved "https://registry.npmjs.org/@chakra-ui/shared-utils/-/shared-utils-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/shared-utils/-/shared-utils-2.0.2.tgz#1df08133194c12ac4df9302604ec37784c2bb026" integrity sha512-wC58Fh6wCnFFQyiebVZ0NI7PFW9+Vch0QE6qN7iR+bLseOzQY9miYuzPJ1kMYiFd6QTOmPJkI39M3wHqrPYiOg== "@chakra-ui/skeleton@2.0.15": version "2.0.15" - resolved "https://registry.npmjs.org/@chakra-ui/skeleton/-/skeleton-2.0.15.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/skeleton/-/skeleton-2.0.15.tgz#fd41383bf84319e47c6ea1f4f3138f5f5e0dabca" integrity sha512-QVMkXwrH9jLfim8uJTZcjHeGjzoquNcHGXD5wapd7eDqp9BygvmMXAHBxFm8eEJLHuvIqLX94P6DLeiieYwX7Q== dependencies: "@chakra-ui/media-query" "3.2.5" @@ -658,7 +658,7 @@ "@chakra-ui/slider@2.0.10": version "2.0.10" - resolved "https://registry.npmjs.org/@chakra-ui/slider/-/slider-2.0.10.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/slider/-/slider-2.0.10.tgz#ffd7376d4a7fd9aa02e72b148e3ad4739c880498" integrity sha512-F0RGl2ruADbXO/GnoBUiTEl+przxhZo2e0tfw9VTtS+RsJZ22uHrTNVvVJHNmjK7/E3++kBfaLCacoJFz/io+g== dependencies: "@chakra-ui/number-utils" "2.0.3" @@ -673,12 +673,12 @@ "@chakra-ui/spinner@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/spinner/-/spinner-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/spinner/-/spinner-2.0.9.tgz#1d8544cc136699a590c3f5c518ae2c14abb459cf" integrity sha512-9ALl51fiVWptDu2J2xcv0TSfGf4buumpHrEXHvV2Qy+HZ6rYnUmSThBSb/VgoQS+rASG8bAbLUPlQTQ+v9ibFg== "@chakra-ui/stat@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/stat/-/stat-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/stat/-/stat-2.0.9.tgz#cecf35a4392a88227c3b85e80a45f0f5ac5f298d" integrity sha512-C9cytqegWSGJ/hh3/qwsgGlerXLYHrU0iQcJQ+pKSRFJhshXsv3go5IR6kVL72Yf2s4Gs5c3GsMZrLM22ePpDg== dependencies: "@chakra-ui/icon" "3.0.9" @@ -686,7 +686,7 @@ "@chakra-ui/styled-system@2.3.1": version "2.3.1" - resolved "https://registry.npmjs.org/@chakra-ui/styled-system/-/styled-system-2.3.1.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/styled-system/-/styled-system-2.3.1.tgz#abf7c4e1638aaa9d92e7cf9acde17785703d166e" integrity sha512-jyR9s2yk5TEyq4HUfjrgUeaOzd9ZTZrbjK96UjtiTCZGO/q4j2RXtYvfheUjUyW1UnzI2A1ffHOJca8tBMDjpA== dependencies: csstype "^3.0.11" @@ -694,14 +694,14 @@ "@chakra-ui/switch@2.0.11": version "2.0.11" - resolved "https://registry.npmjs.org/@chakra-ui/switch/-/switch-2.0.11.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/switch/-/switch-2.0.11.tgz#57117417d1bb072f506c8c30e1a961ee7f78496b" integrity sha512-gY8OGBnoPosZpq7dDNVf432t67pTc/cz5VkGhbtER7bbjXSoXe0DAiAYL+HT2kD7mbTJQzzHK/y0St0WimR1Mw== dependencies: "@chakra-ui/checkbox" "2.1.8" "@chakra-ui/system@2.2.9": version "2.2.9" - resolved "https://registry.npmjs.org/@chakra-ui/system/-/system-2.2.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/system/-/system-2.2.9.tgz#d6e7dfb9a954b8ab03c28e14c69aad56a9fcffbd" integrity sha512-SyTeIGm+goyYK8vqX4dU6oeLhxUAeGI3Cl+mxA+aiKIX01YTALhTWhpbrsuMYBevV+l9EGK12egPUQE+Mo3WlQ== dependencies: "@chakra-ui/color-mode" "2.1.7" @@ -712,14 +712,14 @@ "@chakra-ui/table@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/table/-/table-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/table/-/table-2.0.9.tgz#2ddb0202e8146e517bf602e62195d13fee8f1b0a" integrity sha512-XRz6+x4dMeQX3xyViyG2H/P1STI/2vwvgU2cjzzwS+5fZ2JdGaTgYzBb+IZoH9agEq1Ma3rlKMUPDrRCFb7kLQ== dependencies: "@chakra-ui/react-context" "2.0.3" "@chakra-ui/tabs@2.1.1": version "2.1.1" - resolved "https://registry.npmjs.org/@chakra-ui/tabs/-/tabs-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/tabs/-/tabs-2.1.1.tgz#0fb540782c2e4122b63a203fc1f04eff850f2c0e" integrity sha512-xA+vwqpAHb0nBLrkiO5Lea2UDGROyAIBqsyp/8XXXEr6eKxtNe1I6WJPbDQy0aazB2ToAA0R6fT34HjLaXP8MQ== dependencies: "@chakra-ui/clickable" "2.0.9" @@ -733,7 +733,7 @@ "@chakra-ui/tag@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/tag/-/tag-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/tag/-/tag-2.0.9.tgz#bf8530aa766bd6b9196d374ff75b0b1ce62cd0d3" integrity sha512-NKARwhsZ04t2vkrdRhNcakEiVtg1q44yUUsDw2Jwdu4idAWQupZGGochQI2Ac4T2MI1b66zQUkaGnm3l1mhTtg== dependencies: "@chakra-ui/icon" "3.0.9" @@ -741,14 +741,14 @@ "@chakra-ui/textarea@2.0.10": version "2.0.10" - resolved "https://registry.npmjs.org/@chakra-ui/textarea/-/textarea-2.0.10.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/textarea/-/textarea-2.0.10.tgz#dbbc8df8adddb488d0ee97164917e7be33d6b247" integrity sha512-HSo0EPsY8XKGA+Af6jTob1oe1T6NKZwgjLmX0binK3MMM9pDTXsUTw8GD0g971lxw9oktVMLK/O9QVAgVAm5mw== dependencies: "@chakra-ui/form-control" "2.0.9" "@chakra-ui/theme-tools@2.0.11": version "2.0.11" - resolved "https://registry.npmjs.org/@chakra-ui/theme-tools/-/theme-tools-2.0.11.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/theme-tools/-/theme-tools-2.0.11.tgz#de97b422799627b5a514ae424ca08c1d348bc2a5" integrity sha512-0Juf98bAyOgnBeQ39nMKWqRsOxZDw75BbAB8o0oVyjhYVS1wJh7tFX1ZRV8N/+AN6fuRXEznZPpyUh3J+ZTiRg== dependencies: "@chakra-ui/anatomy" "2.0.6" @@ -756,7 +756,7 @@ "@chakra-ui/theme@2.1.11": version "2.1.11" - resolved "https://registry.npmjs.org/@chakra-ui/theme/-/theme-2.1.11.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/theme/-/theme-2.1.11.tgz#cdfca3e84fc6913c5bb1a06e24b7cbb1246e127e" integrity sha512-gI0NLU6wO/5cRq8gbDHuy24Y/ZhJxN4D/2uucNN9is3h+d58/En5jV3fwzZW8PLiLKW/T2CmbYWEZWV2YkcUVA== dependencies: "@chakra-ui/anatomy" "2.0.6" @@ -764,7 +764,7 @@ "@chakra-ui/toast@3.0.10": version "3.0.10" - resolved "https://registry.npmjs.org/@chakra-ui/toast/-/toast-3.0.10.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/toast/-/toast-3.0.10.tgz#5918beb208ca592f72a9e24923254341fa38df58" integrity sha512-i/oEtzmarO0hM6fxa55OmA8ZGkZv9b+vIC2xs5kQ/C0rJaC0ycibok8srq2Stjq9309fZNezyzThQp6e9acUYQ== dependencies: "@chakra-ui/alert" "2.0.9" @@ -776,7 +776,7 @@ "@chakra-ui/tooltip@2.0.10": version "2.0.10" - resolved "https://registry.npmjs.org/@chakra-ui/tooltip/-/tooltip-2.0.10.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/tooltip/-/tooltip-2.0.10.tgz#2166753f9f246dd217d3170fd85f95a86392d9b6" integrity sha512-pBILBdZoux2K3EW9V6JuyZYUWz2/Y7oYCVO6AwNOesiEBGAONyzoDwFV728EzPEHe9e+YBcKOSZ9tEpDdrzHMA== dependencies: "@chakra-ui/popper" "3.0.7" @@ -788,12 +788,12 @@ "@chakra-ui/transition@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/transition/-/transition-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/transition/-/transition-2.0.9.tgz#1967fd77f44b57681a9efe4e87561c82420cd2a2" integrity sha512-cVfKdZl128AEj0LDS8M9dzXao4wmTVj3gRJBnm91Qcg243Pm8OlgIBNbHEwsq/Fps+PsN431BtEGfL4w79wQEA== "@chakra-ui/utils@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/utils/-/utils-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/utils/-/utils-2.0.9.tgz#1af3882b31fb46e0a411998d8e3607656f8d5043" integrity sha512-7ct5562Jw6pZdtj63XfUkEUXXsCCVqdqIXyLtQ9VgOKtRQWwDxzc8uPI5Zjdw9AleEITZFUH8TNKWn75nm54kQ== dependencies: "@types/lodash.mergewith" "4.6.6" @@ -803,7 +803,7 @@ "@chakra-ui/visually-hidden@2.0.9": version "2.0.9" - resolved "https://registry.npmjs.org/@chakra-ui/visually-hidden/-/visually-hidden-2.0.9.tgz" + resolved "https://registry.yarnpkg.com/@chakra-ui/visually-hidden/-/visually-hidden-2.0.9.tgz#b43a3dd0bc1108954ad0eeb50d0261887ab5e31c" integrity sha512-PkNxrRGp9H3bdqEaoo8XGt/AL9UuGRTom0/9XJa+G/Dj8Cy1sDuamOWk3pN/ZQs46RokfK9Uh5LqPY5dwSDweg== "@ctrl/tinycolor@^3.4.0": @@ -812,33 +812,33 @@ integrity sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw== "@emotion/babel-plugin@^11.10.0": - version "11.10.2" - resolved "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.2.tgz" - integrity sha512-xNQ57njWTFVfPAc3cjfuaPdsgLp5QOSuRsj9MA6ndEhH/AzuZM86qIQzt6rq+aGBwj3n5/TkLmU5lhAfdRmogA== + version "11.10.5" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz#65fa6e1790ddc9e23cc22658a4c5dea423c55c3c" + integrity sha512-xE7/hyLHJac7D2Ve9dKroBBZqBT7WuPQmWcq7HSGb84sUuP4mlOWoB8dvVfD9yk5DHkU1m6RW7xSoDtnQHNQeA== dependencies: "@babel/helper-module-imports" "^7.16.7" "@babel/plugin-syntax-jsx" "^7.17.12" "@babel/runtime" "^7.18.3" "@emotion/hash" "^0.9.0" "@emotion/memoize" "^0.8.0" - "@emotion/serialize" "^1.1.0" + "@emotion/serialize" "^1.1.1" babel-plugin-macros "^3.1.0" convert-source-map "^1.5.0" escape-string-regexp "^4.0.0" find-root "^1.1.0" source-map "^0.5.7" - stylis "4.0.13" + stylis "4.1.3" "@emotion/cache@^11.10.0": - version "11.10.3" - resolved "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.3.tgz" - integrity sha512-Psmp/7ovAa8appWh3g51goxu/z3iVms7JXOreq136D8Bbn6dYraPnmL6mdM8GThEx9vwSn92Fz+mGSjBzN8UPQ== + version "11.10.5" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.5.tgz#c142da9351f94e47527ed458f7bbbbe40bb13c12" + integrity sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA== dependencies: "@emotion/memoize" "^0.8.0" - "@emotion/sheet" "^1.2.0" + "@emotion/sheet" "^1.2.1" "@emotion/utils" "^1.2.0" "@emotion/weak-memoize" "^0.3.0" - stylis "4.0.13" + stylis "4.1.3" "@emotion/hash@^0.9.0": version "0.9.0" @@ -883,10 +883,10 @@ "@emotion/weak-memoize" "^0.3.0" hoist-non-react-statics "^3.3.1" -"@emotion/serialize@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.0.tgz" - integrity sha512-F1ZZZW51T/fx+wKbVlwsfchr5q97iW8brAnXmsskz4d0hVB4O3M/SiA3SaeH06x02lSNzkkQv+n3AX3kCXKSFA== +"@emotion/serialize@^1.1.0", "@emotion/serialize@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.1.tgz#0595701b1902feded8a96d293b26be3f5c1a5cf0" + integrity sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA== dependencies: "@emotion/hash" "^0.9.0" "@emotion/memoize" "^0.8.0" @@ -894,10 +894,10 @@ "@emotion/utils" "^1.2.0" csstype "^3.0.2" -"@emotion/sheet@^1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.0.tgz" - integrity sha512-OiTkRgpxescko+M51tZsMq7Puu/KP55wMT8BgpcXVG2hqXc0Vo0mfymJ/Uj24Hp0i083ji/o0aLddh08UEjq8w== +"@emotion/sheet@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.1.tgz#0767e0305230e894897cadb6c8df2c51e61a6c2c" + integrity sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA== "@emotion/styled@^11.10.4": version "11.10.4" @@ -1064,7 +1064,7 @@ "@next/env@13.0.2": version "13.0.2" - resolved "https://registry.npmjs.org/@next/env/-/env-13.0.2.tgz" + resolved "https://registry.yarnpkg.com/@next/env/-/env-13.0.2.tgz#5fbd7b4146175ae406edfb4a38b62de8c880c09d" integrity sha512-Qb6WPuRriGIQ19qd6NBxpcrFOfj8ziN7l9eZUfwff5gl4zLXluqtuZPddYZM/oWjN53ZYcuRXzL+oowKyJeYtA== "@next/eslint-plugin-next@12.2.5": @@ -1091,7 +1091,7 @@ "@next/swc-darwin-arm64@13.0.2": version "13.0.2" - resolved "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.0.2.tgz" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.0.2.tgz#d7e01a33393e83456dbfdc41446bb8a923968ff7" integrity sha512-1zGIOkInkOLRv0QQGZ+3wffYsyKI4vIy62LYTvDWUn7TAYqnmXwougp9NSLqDeagLwgsv2URrykyAFixA/YqxA== "@next/swc-darwin-x64@13.0.2": @@ -2156,6 +2156,13 @@ fast-levenshtein@^2.0.6: resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-xml-parser@^4.0.12: + version "4.0.12" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.0.12.tgz#9e3117d76523d20dfbd30482c1621fb9b03a7817" + integrity sha512-/Nmo3823Rfx7UTJosQNz6hBVbszfv1Unb7A4iNJZhvCGCgtIHv/uODmrYIH8vc05+XKZ4hNIOv6SlBejvJgATw== + dependencies: + strnum "^1.0.5" + fastq@^1.6.0: version "1.13.0" resolved "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz" @@ -4096,6 +4103,11 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +strnum@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" + integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== + style-to-object@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz" @@ -4118,10 +4130,10 @@ styled-jsx@5.1.0: dependencies: client-only "0.0.1" -stylis@4.0.13: - version "4.0.13" - resolved "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz" - integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== +stylis@4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7" + integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA== supports-color@^5.3.0: version "5.5.0" From c946a1672ca9251680109aaabe0fbb80ebe1987f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Quiroz?= Date: Tue, 29 Nov 2022 15:31:41 -0300 Subject: [PATCH 5/6] Update src/theme/foundations/textStyles.ts Co-authored-by: Paul Wackerow <54227730+wackerow@users.noreply.github.com> --- src/theme/foundations/textStyles.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/theme/foundations/textStyles.ts b/src/theme/foundations/textStyles.ts index 6f7dfbe1c2..cb1c3bd2fc 100644 --- a/src/theme/foundations/textStyles.ts +++ b/src/theme/foundations/textStyles.ts @@ -10,7 +10,7 @@ export const textStyles = { h2: { fontFamily: 'heading', fontWeight: 400, - fontSize: '1.75rem', + fontSize: { base: '1.5rem', md: '1.75rem' }, lineHeight: 'normal', letterSpacing: '0.04em', color: 'body' From 520d48f11955d615dfa584bff18d0349d8850883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Quiroz?= Date: Tue, 29 Nov 2022 15:47:58 -0300 Subject: [PATCH 6/6] chore: update SpecificVersionsSection component layout to match homepage (#64) * chore: update SpecificVersionsSection component layout to match homepage * chore: remove non-required repeat function --- .../UI/downloads/SpecificVersionsSection.tsx | 56 ++++++++++--------- src/pages/index.tsx | 2 +- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/components/UI/downloads/SpecificVersionsSection.tsx b/src/components/UI/downloads/SpecificVersionsSection.tsx index 2909379d63..aa619529bb 100644 --- a/src/components/UI/downloads/SpecificVersionsSection.tsx +++ b/src/components/UI/downloads/SpecificVersionsSection.tsx @@ -1,4 +1,4 @@ -import { Box, Flex, Image, Stack } from '@chakra-ui/react'; +import { Box, Flex, Grid, GridItem, Image, Stack } from '@chakra-ui/react'; import { FC } from 'react'; import { GopherHomeLinks } from '../svgs'; @@ -8,31 +8,33 @@ interface Props { export const SpecificVersionsSection: FC = ({ children }) => { return ( - - - - - - - - Specific Versions - - - {children} - - + + + + {/* TODO: replace with animated/video version */} + + + + + + + + + + + Specific Versions + + + {children} + + + ); }; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 1ca4bb54fd..d49a3bb476 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -142,7 +142,7 @@ const HomePage: NextPage = ({}) => { - + {/* TODO: replace with animated/video version */}