diff --git a/.gitignore b/.gitignore
index e7c522b9..fe3a5738 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
PRIVATE.scratch.md
*~undo-tree~
-proxy/node_modules/*
-dev
\ No newline at end of file
+node_modules
+dev
+.DS_Store
+ui/dist
diff --git a/.urb/log/data.mdb b/.urb/log/data.mdb
new file mode 100644
index 00000000..68dc5152
Binary files /dev/null and b/.urb/log/data.mdb differ
diff --git a/.urb/log/lock.mdb b/.urb/log/lock.mdb
new file mode 100644
index 00000000..f71d029d
Binary files /dev/null and b/.urb/log/lock.mdb differ
diff --git a/btc-desk/lib/btc-provider.hoon b/btc-desk/lib/btc-provider.hoon
index ab857b5c..a9a51ae1 100644
--- a/btc-desk/lib/btc-provider.hoon
+++ b/btc-desk/lib/btc-provider.hoon
@@ -72,7 +72,8 @@
::
++ utxo
%- ot
- :~ ['tx_pos' ni]
+ :~ ['tx_index' ni]
+ ['tx_pos' ni]
['tx_hash' (cu from-cord:hxb:bcu so)]
[%height ni]
[%value ni]
diff --git a/btc-desk/lib/btc.hoon b/btc-desk/lib/btc.hoon
index dc79bef2..8c03f050 100644
--- a/btc-desk/lib/btc.hoon
+++ b/btc-desk/lib/btc.hoon
@@ -161,7 +161,7 @@
`(encode:pbt:bc %.y get-rawtx get-txid ins outs)
--
:: wad: door for processing walts (wallets)
-:: parameterized on a walt and it's chyg account
+:: parameterized on a walt and it's chyg account
::
++ wad
|_ [w=walt =chyg]
@@ -468,7 +468,8 @@
==
++ utxo
%- ot
- :~ ['tx_pos' ni]
+ :~ ['tx_index' ni]
+ ['tx_pos' ni]
['tx_hash' (cu from-cord:hxb:bcu so)]
[%height ni]
[%value ni]
@@ -510,7 +511,7 @@
==
++ block-headers
%- ot
- :~ [%count ni]
+ :~ [%count ni]
[%hex (cu from-cord:hxb:bcu so)]
[%max ni]
[%root (cu:dejs-soft:format from-cord:hxb:bcu so:dejs-soft:format)]
@@ -519,7 +520,7 @@
++ tx-from-pos
%- ot
:~ [%tx-hash (cu from-cord:hxb:bcu so)]
- [%merkle (ar (cu from-cord:hxb:bcu so))]
+ [%merkle (ar (cu from-cord:hxb:bcu so))]
==
++ block-txs
%- ot
@@ -569,27 +570,27 @@
(mk-url '/feehistogram' '')
::
%get-block-headers
- %+ post-request
- %+ mk-url '/blockheaders' ''
+ %+ post-request
+ %+ mk-url '/blockheaders' ''
%- pairs
- :~ [%start (numb start.ract)]
+ :~ [%start (numb start.ract)]
[%count (numb count.ract)]
- [%cp (numb (fall cp.ract 0))]
- ==
+ [%cp (numb (fall cp.ract 0))]
+ ==
::
%get-tx-from-pos
- %+ post-request
- %+ mk-url '/txfrompos' ''
+ %+ post-request
+ %+ mk-url '/txfrompos' ''
%- pairs
- :~ [%height (numb height.ract)]
+ :~ [%height (numb height.ract)]
[%pos (numb pos.ract)]
- [%merkle %b merkle.ract]
- ==
+ [%merkle %b merkle.ract]
+ ==
::
%get-fee
%- get-request
%+ mk-url '/estimatefee/'
- %- crip
+ %- crip
%+ scow %ud block.ract
::
%update-psbt
diff --git a/btc-desk/sur/bitcoin.hoon b/btc-desk/sur/bitcoin.hoon
index 4b83b5bf..477f242b 100644
--- a/btc-desk/sur/bitcoin.hoon
+++ b/btc-desk/sur/bitcoin.hoon
@@ -20,7 +20,7 @@
+$ sats @ud
+$ vbytes @ud
+$ txid hexb
-+$ utxo [pos=@ =txid height=@ value=sats recvd=(unit @da)]
++$ utxo [tx-index=@ pos=@ =txid height=@ value=sats recvd=(unit @da)]
++ address-info
$: =address
confirmed-value=sats
diff --git a/package.json b/package.json
index caf992cf..c1a0591b 100644
--- a/package.json
+++ b/package.json
@@ -2,6 +2,7 @@
"dependencies": {
"@grpc/proto-loader": "^0.7.4",
"express": "^4.18.2",
- "grpc": "^1.24.11"
+ "grpc": "^1.24.11",
+ "urbit-ob": "^5.0.1"
}
}
diff --git a/proxy/invoices.proto b/proxy/invoices.proto
index d5f327d8..dc88918f 100644
--- a/proxy/invoices.proto
+++ b/proxy/invoices.proto
@@ -1,7 +1,5 @@
syntax = "proto3";
-import "lightning.proto";
-
package invoicesrpc;
option go_package = "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc";
@@ -172,4 +170,4 @@ message LookupInvoiceMsg {
}
LookupModifier lookup_modifier = 4;
-}
\ No newline at end of file
+}
diff --git a/proxy/router.proto b/proxy/router.proto
index d072fb87..149e0204 100644
--- a/proxy/router.proto
+++ b/proxy/router.proto
@@ -1,7 +1,5 @@
syntax = "proto3";
-import "lightning.proto";
-
package routerrpc;
option go_package = "github.com/lightningnetwork/lnd/lnrpc/routerrpc";
@@ -949,4 +947,4 @@ enum ChanStatusAction {
}
message UpdateChanStatusResponse {
-}
\ No newline at end of file
+}
diff --git a/proxy/yarn.lock b/proxy/yarn.lock
new file mode 100644
index 00000000..f51448d9
--- /dev/null
+++ b/proxy/yarn.lock
@@ -0,0 +1,981 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@grpc/grpc-js@^1.9.1":
+ version "1.10.1"
+ resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.10.1.tgz#be450560c990c08274bc19d514e181ea205ccaa8"
+ integrity sha512-55ONqFytZExfOIjF1RjXPcVmT/jJqFzbbDqxK9jmRV4nxiYWtL9hENSW1Jfx0SdZfrvoqd44YJ/GJTqfRrawSQ==
+ dependencies:
+ "@grpc/proto-loader" "^0.7.8"
+ "@types/node" ">=12.12.47"
+
+"@grpc/proto-loader@^0.7.8", "@grpc/proto-loader@^0.7.9":
+ version "0.7.10"
+ resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.10.tgz#6bf26742b1b54d0a473067743da5d3189d06d720"
+ integrity sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==
+ dependencies:
+ lodash.camelcase "^4.3.0"
+ long "^5.0.0"
+ protobufjs "^7.2.4"
+ yargs "^17.7.2"
+
+"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
+ integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==
+
+"@protobufjs/base64@^1.1.2":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
+ integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
+
+"@protobufjs/codegen@^2.0.4":
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb"
+ integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
+
+"@protobufjs/eventemitter@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
+ integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==
+
+"@protobufjs/fetch@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
+ integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==
+ dependencies:
+ "@protobufjs/aspromise" "^1.1.1"
+ "@protobufjs/inquire" "^1.1.0"
+
+"@protobufjs/float@^1.0.2":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
+ integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==
+
+"@protobufjs/inquire@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
+ integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==
+
+"@protobufjs/path@^1.1.2":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
+ integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==
+
+"@protobufjs/pool@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
+ integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==
+
+"@protobufjs/utf8@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
+ integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
+
+"@types/node@>=12.12.47", "@types/node@>=13.7.0":
+ version "20.11.19"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.19.tgz#b466de054e9cb5b3831bee38938de64ac7f81195"
+ integrity sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==
+ dependencies:
+ undici-types "~5.26.4"
+
+accepts@~1.3.8:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
+ integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
+ dependencies:
+ mime-types "~2.1.34"
+ negotiator "0.6.3"
+
+ajv@^6.12.3:
+ version "6.12.6"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+ dependencies:
+ fast-deep-equal "^3.1.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
+ansi-regex@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+ integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+
+ansi-styles@^4.0.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+ dependencies:
+ color-convert "^2.0.1"
+
+array-flatten@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+ integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==
+
+asn1@~0.2.3:
+ version "0.2.6"
+ resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d"
+ integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==
+ dependencies:
+ safer-buffer "~2.1.0"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+ integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==
+
+asynckit@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+ integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
+aws-sign2@~0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
+ integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==
+
+aws4@^1.8.0:
+ version "1.12.0"
+ resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3"
+ integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==
+
+bcrypt-pbkdf@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
+ integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==
+ dependencies:
+ tweetnacl "^0.14.3"
+
+body-parser@1.20.1:
+ version "1.20.1"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668"
+ integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==
+ dependencies:
+ bytes "3.1.2"
+ content-type "~1.0.4"
+ debug "2.6.9"
+ depd "2.0.0"
+ destroy "1.2.0"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ on-finished "2.4.1"
+ qs "6.11.0"
+ raw-body "2.5.1"
+ type-is "~1.6.18"
+ unpipe "1.0.0"
+
+bytes@3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
+ integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
+
+call-bind@^1.0.6:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
+ integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
+ dependencies:
+ es-define-property "^1.0.0"
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.4"
+ set-function-length "^1.2.1"
+
+caseless@~0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+ integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==
+
+cliui@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
+ integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.1"
+ wrap-ansi "^7.0.0"
+
+color-convert@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+ dependencies:
+ color-name "~1.1.4"
+
+color-name@~1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+combined-stream@^1.0.6, combined-stream@~1.0.6:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+ integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+ dependencies:
+ delayed-stream "~1.0.0"
+
+content-disposition@0.5.4:
+ version "0.5.4"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
+ integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
+ dependencies:
+ safe-buffer "5.2.1"
+
+content-type@~1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
+ integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
+
+cookie-signature@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+ integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
+
+cookie@0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
+ integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
+
+core-util-is@1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+ integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==
+
+dashdash@^1.12.0:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+ integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==
+ dependencies:
+ assert-plus "^1.0.0"
+
+debug@2.6.9:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
+define-data-property@^1.1.2:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
+ integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
+ dependencies:
+ es-define-property "^1.0.0"
+ es-errors "^1.3.0"
+ gopd "^1.0.1"
+
+delayed-stream@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+ integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
+depd@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
+ integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
+
+destroy@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
+ integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
+
+dotenv@^16.3.1:
+ version "16.4.5"
+ resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
+ integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==
+
+ecc-jsbn@~0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
+ integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==
+ dependencies:
+ jsbn "~0.1.0"
+ safer-buffer "^2.1.0"
+
+ee-first@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+ integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
+
+emoji-regex@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+encodeurl@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+ integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
+
+es-define-property@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
+ integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
+ dependencies:
+ get-intrinsic "^1.2.4"
+
+es-errors@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
+ integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
+
+escalade@^3.1.1:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
+ integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
+
+escape-html@~1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+ integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
+
+etag@~1.8.1:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
+ integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
+
+express@^4.17.1:
+ version "4.18.2"
+ resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59"
+ integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==
+ dependencies:
+ accepts "~1.3.8"
+ array-flatten "1.1.1"
+ body-parser "1.20.1"
+ content-disposition "0.5.4"
+ content-type "~1.0.4"
+ cookie "0.5.0"
+ cookie-signature "1.0.6"
+ debug "2.6.9"
+ depd "2.0.0"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ finalhandler "1.2.0"
+ fresh "0.5.2"
+ http-errors "2.0.0"
+ merge-descriptors "1.0.1"
+ methods "~1.1.2"
+ on-finished "2.4.1"
+ parseurl "~1.3.3"
+ path-to-regexp "0.1.7"
+ proxy-addr "~2.0.7"
+ qs "6.11.0"
+ range-parser "~1.2.1"
+ safe-buffer "5.2.1"
+ send "0.18.0"
+ serve-static "1.15.0"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ type-is "~1.6.18"
+ utils-merge "1.0.1"
+ vary "~1.1.2"
+
+extend@~3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+ integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
+extsprintf@1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
+ integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==
+
+extsprintf@^1.2.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07"
+ integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==
+
+fast-deep-equal@^3.1.1:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+ integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+
+fast-json-stable-stringify@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+ integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+finalhandler@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32"
+ integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==
+ dependencies:
+ debug "2.6.9"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ on-finished "2.4.1"
+ parseurl "~1.3.3"
+ statuses "2.0.1"
+ unpipe "~1.0.0"
+
+forever-agent@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+ integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==
+
+form-data@~2.3.2:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
+ integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.6"
+ mime-types "^2.1.12"
+
+forwarded@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
+ integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
+
+fresh@0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+ integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
+
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
+get-caller-file@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+ integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
+get-intrinsic@^1.1.3, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
+ integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
+ dependencies:
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+ has-proto "^1.0.1"
+ has-symbols "^1.0.3"
+ hasown "^2.0.0"
+
+getpass@^0.1.1:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
+ integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==
+ dependencies:
+ assert-plus "^1.0.0"
+
+gopd@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
+ integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
+ dependencies:
+ get-intrinsic "^1.1.3"
+
+har-schema@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
+ integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==
+
+har-validator@~5.1.3:
+ version "5.1.5"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
+ integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
+ dependencies:
+ ajv "^6.12.3"
+ har-schema "^2.0.0"
+
+has-property-descriptors@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
+ integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
+ dependencies:
+ es-define-property "^1.0.0"
+
+has-proto@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
+ integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
+
+has-symbols@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
+ integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+
+hasown@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.1.tgz#26f48f039de2c0f8d3356c223fb8d50253519faa"
+ integrity sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==
+ dependencies:
+ function-bind "^1.1.2"
+
+http-errors@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
+ integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
+ dependencies:
+ depd "2.0.0"
+ inherits "2.0.4"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ toidentifier "1.0.1"
+
+http-signature@~1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
+ integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==
+ dependencies:
+ assert-plus "^1.0.0"
+ jsprim "^1.2.2"
+ sshpk "^1.7.0"
+
+iconv-lite@0.4.24:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+inherits@2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+ipaddr.js@1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
+ integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
+
+is-fullwidth-code-point@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
+is-typedarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+ integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==
+
+isstream@~0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+ integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==
+
+jsbn@~0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+ integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-schema@0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5"
+ integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==
+
+json-stringify-safe@~5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+ integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==
+
+jsprim@^1.2.2:
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb"
+ integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==
+ dependencies:
+ assert-plus "1.0.0"
+ extsprintf "1.3.0"
+ json-schema "0.4.0"
+ verror "1.10.0"
+
+lodash.camelcase@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
+ integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
+
+long@^5.0.0:
+ version "5.2.3"
+ resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1"
+ integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==
+
+media-typer@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+ integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
+
+merge-descriptors@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
+ integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==
+
+methods@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+ integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
+
+mime-db@1.52.0:
+ version "1.52.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34:
+ version "2.1.35"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+ dependencies:
+ mime-db "1.52.0"
+
+mime@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+ integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
+
+ms@2.1.3:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+negotiator@0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
+ integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
+
+oauth-sign@~0.9.0:
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
+ integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
+
+object-inspect@^1.13.1:
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
+ integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
+
+on-finished@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
+ integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
+ dependencies:
+ ee-first "1.1.1"
+
+parseurl@~1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+ integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
+path-to-regexp@0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
+ integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==
+
+performance-now@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
+ integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==
+
+protobufjs@^7.2.4:
+ version "7.2.6"
+ resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.6.tgz#4a0ccd79eb292717aacf07530a07e0ed20278215"
+ integrity sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw==
+ dependencies:
+ "@protobufjs/aspromise" "^1.1.2"
+ "@protobufjs/base64" "^1.1.2"
+ "@protobufjs/codegen" "^2.0.4"
+ "@protobufjs/eventemitter" "^1.1.0"
+ "@protobufjs/fetch" "^1.1.0"
+ "@protobufjs/float" "^1.0.2"
+ "@protobufjs/inquire" "^1.1.0"
+ "@protobufjs/path" "^1.1.2"
+ "@protobufjs/pool" "^1.1.0"
+ "@protobufjs/utf8" "^1.1.0"
+ "@types/node" ">=13.7.0"
+ long "^5.0.0"
+
+proxy-addr@~2.0.7:
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
+ integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
+ dependencies:
+ forwarded "0.2.0"
+ ipaddr.js "1.9.1"
+
+psl@^1.1.28:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
+ integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
+
+punycode@^2.1.0, punycode@^2.1.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
+ integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
+
+qs@6.11.0:
+ version "6.11.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
+ integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
+ dependencies:
+ side-channel "^1.0.4"
+
+qs@~6.5.2:
+ version "6.5.3"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad"
+ integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==
+
+range-parser@~1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@2.5.1:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857"
+ integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==
+ dependencies:
+ bytes "3.1.2"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ unpipe "1.0.0"
+
+request@^2.88.2:
+ version "2.88.2"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
+ integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
+ dependencies:
+ aws-sign2 "~0.7.0"
+ aws4 "^1.8.0"
+ caseless "~0.12.0"
+ combined-stream "~1.0.6"
+ extend "~3.0.2"
+ forever-agent "~0.6.1"
+ form-data "~2.3.2"
+ har-validator "~5.1.3"
+ http-signature "~1.2.0"
+ is-typedarray "~1.0.0"
+ isstream "~0.1.2"
+ json-stringify-safe "~5.0.1"
+ mime-types "~2.1.19"
+ oauth-sign "~0.9.0"
+ performance-now "^2.1.0"
+ qs "~6.5.2"
+ safe-buffer "^5.1.2"
+ tough-cookie "~2.5.0"
+ tunnel-agent "^0.6.0"
+ uuid "^3.3.2"
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+ integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
+
+safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.2:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+send@0.18.0:
+ version "0.18.0"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
+ integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==
+ dependencies:
+ debug "2.6.9"
+ depd "2.0.0"
+ destroy "1.2.0"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ fresh "0.5.2"
+ http-errors "2.0.0"
+ mime "1.6.0"
+ ms "2.1.3"
+ on-finished "2.4.1"
+ range-parser "~1.2.1"
+ statuses "2.0.1"
+
+serve-static@1.15.0:
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540"
+ integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==
+ dependencies:
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ parseurl "~1.3.3"
+ send "0.18.0"
+
+set-function-length@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.1.tgz#47cc5945f2c771e2cf261c6737cf9684a2a5e425"
+ integrity sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==
+ dependencies:
+ define-data-property "^1.1.2"
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.3"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.1"
+
+setprototypeof@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
+ integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
+
+side-channel@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.5.tgz#9a84546599b48909fb6af1211708d23b1946221b"
+ integrity sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==
+ dependencies:
+ call-bind "^1.0.6"
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.4"
+ object-inspect "^1.13.1"
+
+sshpk@^1.7.0:
+ version "1.18.0"
+ resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028"
+ integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==
+ dependencies:
+ asn1 "~0.2.3"
+ assert-plus "^1.0.0"
+ bcrypt-pbkdf "^1.0.0"
+ dashdash "^1.12.0"
+ ecc-jsbn "~0.1.1"
+ getpass "^0.1.1"
+ jsbn "~0.1.0"
+ safer-buffer "^2.0.2"
+ tweetnacl "~0.14.0"
+
+statuses@2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
+ integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
+
+string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
+toidentifier@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
+ integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
+
+tough-cookie@~2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
+ integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
+ dependencies:
+ psl "^1.1.28"
+ punycode "^2.1.1"
+
+tunnel-agent@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+ integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==
+ dependencies:
+ safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+ version "0.14.5"
+ resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+ integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==
+
+type-is@~1.6.18:
+ version "1.6.18"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+ integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+ dependencies:
+ media-typer "0.3.0"
+ mime-types "~2.1.24"
+
+undici-types@~5.26.4:
+ version "5.26.5"
+ resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
+ integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
+
+unpipe@1.0.0, unpipe@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+ integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
+
+uri-js@^4.2.2:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+ dependencies:
+ punycode "^2.1.0"
+
+utils-merge@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+ integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
+
+uuid@^3.3.2:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
+ integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
+
+vary@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+ integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
+
+verror@1.10.0:
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
+ integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==
+ dependencies:
+ assert-plus "^1.0.0"
+ core-util-is "1.0.2"
+ extsprintf "^1.2.0"
+
+wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+y18n@^5.0.5:
+ version "5.0.8"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+ integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
+yargs-parser@^21.1.1:
+ version "21.1.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
+ integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
+
+yargs@^17.7.2:
+ version "17.7.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
+ integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
+ dependencies:
+ cliui "^8.0.1"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.3"
+ y18n "^5.0.5"
+ yargs-parser "^21.1.1"
diff --git a/ui/.env.wet b/ui/.env.wet
new file mode 100644
index 00000000..c6018ea1
--- /dev/null
+++ b/ui/.env.wet
@@ -0,0 +1,2 @@
+VITE_SHIP_URL=http://localhost:8080
+VITE_SHIP_NAME=wet
diff --git a/ui/.env.zod b/ui/.env.zod
new file mode 100644
index 00000000..c5a25a23
--- /dev/null
+++ b/ui/.env.zod
@@ -0,0 +1,2 @@
+VITE_SHIP_URL=http://localhost:80
+VITE_SHIP_NAME=zod
diff --git a/ui/README.md b/ui/README.md
new file mode 100644
index 00000000..90dbf8f8
--- /dev/null
+++ b/ui/README.md
@@ -0,0 +1,17 @@
+# Volt UI
+
+## Developing
+- Run %volt as described in the ``../README.md``
+- Run `yarn install` inside `volt/ui`
+- Run `vite --mode zod` / `vite --mode wet` to run the UI against the `.env.zod` / `.env.wet` config files respectively
+
+Alternatively, you can make your own config file by setting `VITE_SHIP_URL` and `VITE_SHIP_NAME` (e.g. for `.env.bus `run `vite --mode bus`)
+
+If you run the app in development mode like this, it will not show up in Landscape.
+
+## Building / Installing
+
+ - Run `yarn build` inside your `ui` directory, which will bundle all the code and assets into the `dist` folder
+ - Navigate to ${ship_url}/docket/upload (e.g. http://localhost/docket/upload) and upload `dist`
+
+ You should then see a tile for Volt in Landscape. If you `|commit %volt`, the Landscape tile will show an error, and you will need to upload `dist` again.
diff --git a/ui/index.html b/ui/index.html
new file mode 100644
index 00000000..86c59932
--- /dev/null
+++ b/ui/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+ volt
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/package.json b/ui/package.json
new file mode 100644
index 00000000..d15feaac
--- /dev/null
+++ b/ui/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "volt",
+ "version": "0.0.0",
+ "private": true,
+ "scripts": {
+ "zod": "vite --mode zod",
+ "wet": "vite --mode wet",
+ "build": "tsc && vite build",
+ "serve": "vite preview",
+ "test": "tsc --noEmit",
+ "tsc": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@urbit/api": "^2.3.0",
+ "@urbit/aura": "^1.0.0",
+ "@urbit/http-api": "^2.3.0",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-qr-code": "2.0.12"
+ },
+ "devDependencies": {
+ "@types/react": "^18.2.0",
+ "@types/react-dom": "^18.2.0",
+ "@urbit/vite-plugin-urbit": "^0.8.0",
+ "@vitejs/plugin-react": "^4.0.0",
+ "autoprefixer": "^10.4.14",
+ "postcss": "^8.4.23",
+ "tailwindcss": "^3.3.2",
+ "vite": "^4.3.9"
+ }
+}
diff --git a/ui/postcss.config.js b/ui/postcss.config.js
new file mode 100644
index 00000000..f1c8dac8
--- /dev/null
+++ b/ui/postcss.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ }
+}
diff --git a/ui/src/app.tsx b/ui/src/app.tsx
new file mode 100644
index 00000000..c1d678b9
--- /dev/null
+++ b/ui/src/app.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import './index.css';
+import CommandFeedback from './components/feedback/FeedbackConsole';
+import { FeedbackContextProvider } from './contexts/FeedbackContext';
+import { ChannelContextProvider } from './contexts/ChannelContext';
+import { InvoiceContextProvider } from './contexts/InvoiceContext';
+import Commands from './components/commands/Commands';
+import LiquidityDisplay from './components/status/LiquidityDisplay';
+import ChannelDisplay from './components/status/ChannelDisplay';
+import { VoltProviderContextProvider } from './contexts/VoltProviderContext';
+
+export function App() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/ui/src/assets/Telegrama.otf b/ui/src/assets/Telegrama.otf
new file mode 100644
index 00000000..fb2a1488
Binary files /dev/null and b/ui/src/assets/Telegrama.otf differ
diff --git a/ui/src/assets/android-chrome-512x512.png b/ui/src/assets/android-chrome-512x512.png
new file mode 100644
index 00000000..cbccf9f9
Binary files /dev/null and b/ui/src/assets/android-chrome-512x512.png differ
diff --git a/ui/src/assets/apple-touch-icon.png b/ui/src/assets/apple-touch-icon.png
new file mode 100644
index 00000000..33e361ce
Binary files /dev/null and b/ui/src/assets/apple-touch-icon.png differ
diff --git a/ui/src/assets/favicon.ico b/ui/src/assets/favicon.ico
new file mode 100644
index 00000000..2cd747c8
Binary files /dev/null and b/ui/src/assets/favicon.ico differ
diff --git a/ui/src/assets/favicon.svg b/ui/src/assets/favicon.svg
new file mode 100644
index 00000000..1f34862b
--- /dev/null
+++ b/ui/src/assets/favicon.svg
@@ -0,0 +1,12 @@
+
diff --git a/ui/src/assets/manifest.json b/ui/src/assets/manifest.json
new file mode 100644
index 00000000..228ae3d3
--- /dev/null
+++ b/ui/src/assets/manifest.json
@@ -0,0 +1,14 @@
+{
+ "name": "Volt UI",
+ "short_name": "Volt UI",
+ "icons": [
+ {
+ "src": "/apps/grid/android-chrome-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ],
+ "theme_color": "#ffffff",
+ "background_color": "#ffffff",
+ "display": "standalone"
+}
diff --git a/ui/src/assets/safari-pinned-tab.svg b/ui/src/assets/safari-pinned-tab.svg
new file mode 100644
index 00000000..c3de016e
--- /dev/null
+++ b/ui/src/assets/safari-pinned-tab.svg
@@ -0,0 +1,54 @@
+
+
+
diff --git a/ui/src/components/commands/AddInvoice.tsx b/ui/src/components/commands/AddInvoice.tsx
new file mode 100644
index 00000000..15678b42
--- /dev/null
+++ b/ui/src/components/commands/AddInvoice.tsx
@@ -0,0 +1,151 @@
+import React, { useState, useEffect, useRef, useContext } from 'react';
+import Urbit from '@urbit/http-api';
+import Button from './shared/Button';
+import Text from './shared/Text';
+import { FeedbackContext } from '../../contexts/FeedbackContext';
+import Command from '../../types/Command';
+import Input from './shared/Input';
+import Dropdown from './shared/Dropdown';
+import Network from '../../types/Network';
+import QRCode from 'react-qr-code'
+import { InvoiceContext } from '../../contexts/InvoiceContext';
+import CommandForm from './shared/CommandForm';
+import Invoice from '../../types/Invoice';
+import BitcoinAmount from '../../types/BitcoinAmount';
+import CopyButton from './shared/CopyButton';
+
+const AddInvoice = ({ api }: { api: Urbit }) => {
+ const { displayCommandSuccess, displayCommandError, displayJsError } = useContext(FeedbackContext);
+ const { latestInvoice } = useContext(InvoiceContext);
+
+ const [amountMsatsInput, setAmountMsatsInput] = useState('');
+ const [amount, setAmount] = useState(null);
+ const [memo, setMemo] = useState('');
+ const [network, setNetwork] = useState(Network.Regtest);
+ // Recorded when user presses the submit button
+ // Used to check if `latestInvoice` comming from our ship is probably the one we just submitted
+ const [submittedInvoiceAmount, setSubmittedInvoiceAmount] = useState(null);
+ // New invoice received from ship
+ const [confirmedInvoice, setConfirmedInvoice] = useState(null);
+
+ useEffect(() => {
+ if (
+ // Check that we submitted an invoice through the UI and not the dojo
+ submittedInvoiceAmount &&
+ // Don't let `confirmedInvoice` get overwritten
+ !confirmedInvoice &&
+ // Check that `latestInvoice` comming from our ship looks like the one we just submitted
+ latestInvoice && latestInvoice.amount.eq(submittedInvoiceAmount)
+ ) {
+ setConfirmedInvoice(latestInvoice)
+ }
+ }, [latestInvoice])
+
+ const handleChangeAmountMsatsInput = (e: React.ChangeEvent) => {
+ const input = e.target.value;
+ // Allow only positive integers
+ const isEmptyString = input === '';
+ const isPositiveInteger = /^\d*$/.test(input) && parseInt(input) > 0;
+ if (isEmptyString) {
+ setAmountMsatsInput(input);
+ setAmount(null);
+ } else if (isPositiveInteger) {
+ setAmountMsatsInput(input);
+ setAmount(new BitcoinAmount(parseInt(input)));
+ }
+ };
+
+ const handleChangeMemo = (e: React.ChangeEvent) => {
+ setMemo(e.target.value);
+ }
+
+ const handleChangeNetwork = (e: React.ChangeEvent) => {
+ setNetwork(e.target.value as Network);
+ };
+
+ const addInvoice = (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!amount) {
+ displayJsError('Amount required');
+ return;
+ }
+ try {
+ api.poke({
+ app: "volt",
+ mark: "volt-command",
+ json: {
+ 'add-invoice': {
+ 'amount': (amount as BitcoinAmount).millisatoshis,
+ memo: memo,
+ network: network
+ }
+ },
+ onSuccess: () => {
+ displayCommandSuccess(Command.AddInvoice)
+ setSubmittedInvoiceAmount(amount)
+ },
+ onError: (e) => displayCommandError(Command.AddInvoice, e),
+ });
+ } catch (e) {
+ displayJsError('Error adding invoice');
+ console.error(e);
+ }
+ };
+
+ const onClickDone = (e: React.FormEvent) => {
+ e.preventDefault();
+ setSubmittedInvoiceAmount(null);
+ setConfirmedInvoice(null);
+ }
+
+ const options = [
+ { value: Network.Regtest, label: 'Regtest' },
+ { value: Network.Testnet, label: 'Testnet' },
+ { value: Network.Mainnet, label: 'Mainnet' }
+ ];
+
+
+ // Show QR display component even without a confirmed invoice to prevent user from submitting multiple invoices
+ if (submittedInvoiceAmount) {
+ return (
+
+ {latestInvoice?.payreq ? : null}
+
+
+ {memo ? : null}
+ {latestInvoice?.payreq ?
+ : null }
+
+ );
+ } else {
+ return (
+
+
+
+
+
+
+ );
+ }
+};
+
+export default AddInvoice;
diff --git a/ui/src/components/commands/CloseChannel.tsx b/ui/src/components/commands/CloseChannel.tsx
new file mode 100644
index 00000000..9c4f4dcd
--- /dev/null
+++ b/ui/src/components/commands/CloseChannel.tsx
@@ -0,0 +1,66 @@
+import React, { useState, useEffect, useContext } from 'react';
+import Urbit from '@urbit/http-api';
+import Channel from '../../types/Channel';
+import Button from './shared/Button';
+import { FeedbackContext } from '../../contexts/FeedbackContext';
+import Command from '../../types/Command';
+import Dropdown from './shared/Dropdown';
+import CommandForm from './shared/CommandForm';
+
+const CloseChannel = ({ api, openChannels }: { api: Urbit, openChannels: Array }) => {
+ const { displayCommandSuccess, displayCommandError, displayJsError } = useContext(FeedbackContext);
+ const [channelId, setChannelId] = useState(openChannels[0]?.id || null);
+
+ useEffect(() => {
+ if (channelId === null && openChannels.length > 0) {
+ setChannelId(openChannels[0].id)
+ }
+ }, [openChannels]);
+
+
+ const onChangeChannelId = (event: React.ChangeEvent) => {
+ setChannelId(event.target.value);
+ }
+
+ const closeChannel = (e: React.FormEvent) => {
+ e.preventDefault();
+ try {
+ api.poke({
+ app: "volt",
+ mark: "volt-command",
+ json: { "close-channel": channelId },
+ onSuccess: () => displayCommandSuccess(Command.CloseChannel),
+ onError: (e) => displayCommandError(Command.CloseChannel, e),
+ });
+ } catch (e) {
+ displayJsError('Error closing channel');
+ console.error(e);
+ }
+ }
+
+ const getChannelLabel = (channel: Channel) => {
+ return `${channel.who}, ${channel.our.displayAsSats()}, id=${channel.id.slice(0, 12)}...`
+ }
+
+ const options = openChannels.map((channel) => {
+ return { value: channel.id, label: getChannelLabel(channel) }
+ })
+
+ return (
+ <>
+ {openChannels.length > 0 ? (
+
+
+
+
+ ) : No open channels
}
+ >
+ );
+};
+
+export default CloseChannel;
diff --git a/ui/src/components/commands/Commands.tsx b/ui/src/components/commands/Commands.tsx
new file mode 100644
index 00000000..cbe0f85e
--- /dev/null
+++ b/ui/src/components/commands/Commands.tsx
@@ -0,0 +1,72 @@
+import React, { useState, useContext } from 'react';
+import AddInvoice from './AddInvoice';
+import CloseChannel from './CloseChannel';
+import CreateFunding from './CreateFunding';
+import OpenChannel from './OpenChannel';
+import SendPayment from './SendPayment';
+import SetProvider from './SetProvider';
+import TestInvoice from './TestInvoice';
+import { ChannelStatus } from '../../types/Channel';
+import SetUrl from './SetUrl';
+import { ChannelContext } from '../../contexts/ChannelContext';
+import { ApiContext } from '../../contexts/ApiContext';
+// import TestInvoice from './TestInvoice';
+
+
+const Commands: React.FC = () => {
+ const api = useContext(ApiContext)
+ const { channelsByStatus } = useContext(ChannelContext);
+
+ const [selectedCommand, setSelectedCommand] = useState('Set Provider');
+
+ const openChannels = channelsByStatus[ChannelStatus.Open];
+ const preopeningChannels = channelsByStatus[ChannelStatus.Preopening];
+
+ const commands = [
+ { name: 'Set Provider', component: },
+ { name: 'Set URL', component: },
+
+ { name: 'Open Channel', component: },
+ {
+ name: 'Create Funding',
+ component:
+ },
+ {
+ name: 'Send Payment',
+ component: },
+ {
+ name: 'Close Channel',
+ component:
+ },
+ { name: 'Add Invoice', component: },
+ { name: 'Test Invoice', component: },
+ ];
+
+ const handleCommandChange = (event: React.ChangeEvent) => {
+ setSelectedCommand(event.target.value);
+ };
+
+ return (
+
+
Command
+
+ {selectedCommand && (
+
+ {commands.find((command) => command.name === selectedCommand)?.component}
+
+ )}
+
+ );
+ };
+
+ export default Commands;
diff --git a/ui/src/components/commands/CreateFunding.tsx b/ui/src/components/commands/CreateFunding.tsx
new file mode 100644
index 00000000..fde79c0d
--- /dev/null
+++ b/ui/src/components/commands/CreateFunding.tsx
@@ -0,0 +1,91 @@
+import React, { useState, useContext, useMemo } from 'react';
+import Urbit from '@urbit/http-api';
+import Channel from '../../types/Channel';
+import Button from './shared/Button';
+import { FeedbackContext } from '../../contexts/FeedbackContext';
+import Command from '../../types/Command';
+import Input from './shared/Input';
+import Dropdown from './shared/Dropdown';
+import CommandForm from './shared/CommandForm';
+import CopyButton from './shared/CopyButton';
+
+const CreateFunding = (
+ { api, preopeningChannels }: { api: Urbit, preopeningChannels: Array }
+) => {
+
+ const { displayCommandSuccess, displayCommandError, displayJsError } = useContext(FeedbackContext);
+
+ const ourPreopeningChannels = useMemo(() => {
+ return preopeningChannels.filter(channel => channel.fundingAddress);
+ }, [preopeningChannels]);
+ const [channel, setChannel] = useState(ourPreopeningChannels[0] || null);
+ const [psbt, setPsbt] = useState('');
+
+ const psbtCommand: null | string = useMemo(() => {
+ if (!channel?.fundingAddress) return (null);
+ return `bitcoin-cli walletprocesspsbt $(bitcoin-cli walletcreatefundedpsbt "[]" `
+ + `"[{\\"${channel.fundingAddress as string}\\":${channel.our.asBtc()}}]" `
+ + `| grep -o '"psbt": "[^"]*' | cut -d'"' -f4) | grep -o '"psbt": "[^"]*' | cut -d'"' -f4`;
+ }, [channel]);
+
+ const onChangeSelectedChannel = (event: React.ChangeEvent) => {
+ setChannel(ourPreopeningChannels.find(channel => channel.id === event.target.value) as Channel);
+ };
+
+ const onChangePsbt = (event: React.ChangeEvent) => {
+ setPsbt(event.target.value);
+ };
+
+ const createFunding = (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!psbt) {
+ displayJsError("PSBT required")
+ return;
+ }
+ try {
+ api.poke({
+ app: "volt",
+ mark: "volt-command",
+ json: {
+ 'create-funding': {
+ 'temporary-channel-id': channel.id,
+ 'psbt': psbt,
+ }
+ },
+ onSuccess: () => displayCommandSuccess(Command.CreateFunding),
+ onError: (e) => displayCommandError(Command.CreateFunding, e),
+ });
+ } catch (e) {
+ displayJsError('Error creating funding');
+ console.error(e);
+ }
+ };
+
+ const getChannelLabel = (channel: Channel) => {
+ return `~${channel.who}, ${channel.our.displayAsSats()}, id=${channel.id.slice(0, 12)}...`
+ }
+
+ const options = ourPreopeningChannels.map((channel) => {
+ return { value: channel.id, label: getChannelLabel(channel) }
+ });
+
+ return (
+ <>
+ {ourPreopeningChannels.length > 0 ? (
+
+
+
+
+
+
+ ) : No preopening channels
}
+ >
+ );
+};
+
+export default CreateFunding;
diff --git a/ui/src/components/commands/OpenChannel.tsx b/ui/src/components/commands/OpenChannel.tsx
new file mode 100644
index 00000000..75db2ffe
--- /dev/null
+++ b/ui/src/components/commands/OpenChannel.tsx
@@ -0,0 +1,152 @@
+import React, { useState, useContext } from 'react';
+import Urbit from '@urbit/http-api';
+import { isValidPatp, preSig } from '@urbit/aura'
+import Button from './shared/Button';
+import { FeedbackContext } from '../../contexts/FeedbackContext';
+import Command from '../../types/Command';
+import Input from './shared/Input';
+import Dropdown from './shared/Dropdown';
+import Network from '../../types/Network';
+import CommandForm from './shared/CommandForm';
+import BitcoinAmount, { MIN_FUNDING_AMOUNT } from '../../types/BitcoinAmount';
+
+const OpenChannel = ({ api }: { api: Urbit }) => {
+ const { displayCommandSuccess, displayCommandError, displayJsError } = useContext(FeedbackContext);
+
+ const [channelPartnerInput, setChannelPartnerInput] = useState('~');
+ const [channelPartner, setChannelPartner] = useState(null);
+ const [fundingSatsInput, setFundingSatsInput] = useState('');
+ const [fundingSats, setFundingSats] = useState(null);
+ const [pushMsatsInput, setPushMsatsInput] = useState('0');
+ const [pushAmount, setPushAmount] = useState(new BitcoinAmount(0));
+ const [selectedOption, setSelectedOption] = useState(Network.Regtest);
+
+ const onChangeChannelPartnerInput = (e: React.ChangeEvent) => {
+ setChannelPartnerInput(e.target.value);
+ if (isValidPatp(preSig(e.target.value))) {
+ setChannelPartner(preSig(e.target.value));
+ } else {
+ setChannelPartner(null);
+ }
+ };
+
+ const onChangeFundingSatsInput = (e: React.ChangeEvent) => {
+ const input = e.target.value;
+ // Only allow only positive integers
+ const isEmptyString = input === '';
+ const isPositiveInteger = /^\d*$/.test(input) && parseInt(input) > 0;
+ if (isEmptyString) {
+ setFundingSatsInput(input);
+ setFundingSats(null);
+ } else if (isPositiveInteger) {
+ setFundingSatsInput(input);
+ setFundingSats(parseInt(input));
+ }
+ };
+
+ const onChangePushMsatsInput = (e: React.ChangeEvent) => {
+ const input = e.target.value;
+ // Only allow only positive integers
+ const isEmptyString = input === '';
+ const isPositiveInteger = /^\d*$/.test(input) && parseInt(input) >= 0;
+ if (isEmptyString) {
+ setPushMsatsInput('');
+ setPushAmount(new BitcoinAmount(0));
+ } else if (isPositiveInteger) {
+ setPushMsatsInput(input);
+ setPushAmount(new BitcoinAmount(parseInt(input)));
+ }
+ };
+
+ const onChangeNetwork = (e: React.ChangeEvent) => {
+ setSelectedOption(e.target.value as Network);
+ };
+
+ const validateOpenChannelParams = () => {
+ let valid = true;
+
+ if (channelPartner === null && ['', '~'].includes(channelPartnerInput)) {
+ displayJsError("Channel partner required")
+ valid = false;
+ } else if (channelPartner === null) {
+ displayJsError("Invalid channel partner")
+ valid = false;
+ } else if (channelPartner === api.ship || channelPartner === `~${api.ship}`) {
+ displayJsError("Cannot open channel with self")
+ valid = false;
+ }
+
+ if (fundingSats === null) {
+ displayJsError("Funding sats required")
+ valid = false;
+ } else if (MIN_FUNDING_AMOUNT.gt(BitcoinAmount.fromSatoshis(fundingSats))) {
+ displayJsError(`Funding sats must be at least ${MIN_FUNDING_AMOUNT.displayAsSats()}`)
+ valid = false;
+ }
+
+ if (fundingSats && pushAmount.gt(BitcoinAmount.fromSatoshis(fundingSats))) {
+ displayJsError(`Push msats must be less than or equal to funding`)
+ valid = false;
+ }
+ return valid;
+ }
+
+ const openChannel = (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!validateOpenChannelParams()) return;
+ try {
+ api.poke({
+ app: "volt",
+ mark: "volt-command",
+ json: {
+ "open-channel": {
+ who: channelPartner,
+ 'funding-sats': fundingSats,
+ 'push-msats': pushAmount.millisatoshis,
+ network: selectedOption
+ }
+ },
+ onSuccess: () => displayCommandSuccess(Command.OpenChannel),
+ onError: (e) => displayCommandError(Command.OpenChannel, e),
+ });
+ } catch (e) {
+ displayJsError('Error opening channel');
+ console.error(e);
+ }
+ };
+
+ const options = [
+ { value: Network.Regtest, label: 'Regtest' },
+ { value: Network.Testnet, label: 'Testnet' },
+ { value: Network.Mainnet, label: 'Mainnet' }
+ ];
+
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+export default OpenChannel;
diff --git a/ui/src/components/commands/SendPayment.tsx b/ui/src/components/commands/SendPayment.tsx
new file mode 100644
index 00000000..4f8c4d36
--- /dev/null
+++ b/ui/src/components/commands/SendPayment.tsx
@@ -0,0 +1,72 @@
+import React, { useState, useContext } from 'react';
+import Urbit from '@urbit/http-api';
+import { isValidPatp, preSig } from '@urbit/aura'
+import Button from './shared/Button';
+import { FeedbackContext } from '../../contexts/FeedbackContext';
+import Command from '../../types/Command';
+import Input from './shared/Input';
+import CommandForm from './shared/CommandForm';
+
+const SendPayment = ({ api }: { api: Urbit }) => {
+ const { displayCommandSuccess, displayCommandError, displayJsError } = useContext(FeedbackContext);
+
+ const [payreq, setPayreq] = useState('');
+ const [shipInput, setShipInput] = useState('~');
+ const [ship, setShip] = useState(null);
+
+ const onChangePayreq = (e: React.ChangeEvent) => {
+ setPayreq(e.target.value);
+ };
+
+ const onChangeShipInput = (e: React.ChangeEvent) => {
+ setShipInput(e.target.value);
+ if (isValidPatp(preSig(e.target.value))) {
+ setShip(preSig(e.target.value));
+ } else {
+ setShip(null);
+ }
+ };
+
+ const sendPayment = (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!payreq) {
+ displayJsError("Payreq required");
+ return;
+ }
+ try {
+ api.poke({
+ app: "volt",
+ mark: "volt-command",
+ json: {
+ "send-payment": {
+ payreq: payreq,
+ who: ship
+ }
+ },
+ onSuccess: () => displayCommandSuccess(Command.SendPayment),
+ onError: (e) => displayCommandError(Command.SendPayment, e),
+ });
+ } catch (e) {
+ displayJsError('Error sending payment');
+ console.error(e);
+ }
+ };
+
+ return (
+
+
+
+
+
+ );
+};
+
+export default SendPayment;
diff --git a/ui/src/components/commands/SetProvider.tsx b/ui/src/components/commands/SetProvider.tsx
new file mode 100644
index 00000000..b657fda9
--- /dev/null
+++ b/ui/src/components/commands/SetProvider.tsx
@@ -0,0 +1,58 @@
+import React, { useState, useContext } from 'react';
+import Urbit from '@urbit/http-api';
+import { isValidPatp, preSig } from '@urbit/aura'
+import Button from './shared/Button';
+import { FeedbackContext } from '../../contexts/FeedbackContext';
+import Command from '../../types/Command';
+import Input from './shared/Input';
+import CommandForm from './shared/CommandForm';
+
+const SetProvider = ({ api }: { api: Urbit }) => {
+ const { displayCommandSuccess, displayCommandError, displayJsError } = useContext(FeedbackContext);
+
+ const [providerShipInput, setProviderShipInput] = useState('~');
+ const [providerShip, setProviderShip] = useState(null);
+
+ const handleInputChange = (e: React.ChangeEvent) => {
+ setProviderShipInput(e.target.value);
+ if (isValidPatp(preSig(e.target.value))) {
+ setProviderShip(preSig(e.target.value));
+ } else {
+ setProviderShip(null);
+ }
+ };
+
+ const setProvider = (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!providerShip) {
+ displayJsError("Invalid provider ship")
+ return;
+ };
+ try {
+ api.poke({
+ app: "volt",
+ mark: "volt-command",
+ json: {"set-provider": providerShip},
+ onSuccess: () => displayCommandSuccess(Command.SetProvider),
+ onError: (e) => displayCommandError(Command.SetProvider, e),
+ });
+ } catch (e) {
+ displayJsError("Error setting provider");
+ console.error(e);
+ }
+ }
+
+ return (
+
+
+
+
+ );
+};
+
+export default SetProvider;
diff --git a/ui/src/components/commands/SetUrl.tsx b/ui/src/components/commands/SetUrl.tsx
new file mode 100644
index 00000000..f23a4cdc
--- /dev/null
+++ b/ui/src/components/commands/SetUrl.tsx
@@ -0,0 +1,70 @@
+import React, { useState, useContext } from 'react';
+import Urbit from '@urbit/http-api';
+import Button from './shared/Button';
+import { FeedbackContext } from '../../contexts/FeedbackContext';
+import Command from '../../types/Command';
+import Input from './shared/Input';
+import CommandForm from './shared/CommandForm';
+
+const SetUrl = ({ api }: { api: Urbit }) => {
+ const {
+ displayCommandSuccess,
+ displayCommandError,
+ displayJsError
+ } = useContext(FeedbackContext);
+
+ const [urlInput, setUrlInput] = useState('');
+ const [url, setUrl] = useState(null);
+
+ const isValidUrl = (maybeUrl: string) => {
+ try {
+ new URL(maybeUrl);
+ return true;
+ } catch (e) {
+ return false;
+ }
+ }
+
+ const handleInputChange = (e: React.ChangeEvent) => {
+ setUrlInput(e.target.value);
+ if (isValidUrl(e.target.value)) {
+ setUrl(e.target.value);
+ } else {
+ setUrl(null);
+ }
+ };
+
+ const setProviderUrl = (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!url) {
+ displayJsError("Invalid provider url");
+ return;
+ }
+ try {
+ api.poke({
+ app: "volt-provider",
+ mark: "volt-provider-command",
+ json: {"set-url": url},
+ onSuccess: () => displayCommandSuccess(Command.SetUrl),
+ onError: (e) => displayCommandError(Command.SetUrl, e),
+ });
+ } catch (e) {
+ displayJsError("Error setting provider url");
+ console.error(e);
+ }
+ }
+
+ return (
+
+
+
+
+ );
+};
+
+export default SetUrl;
diff --git a/ui/src/components/commands/TestInvoice.tsx b/ui/src/components/commands/TestInvoice.tsx
new file mode 100644
index 00000000..262bd79e
--- /dev/null
+++ b/ui/src/components/commands/TestInvoice.tsx
@@ -0,0 +1,119 @@
+import React, { useState, useContext } from 'react';
+import Urbit from '@urbit/http-api';
+import { isValidPatp, preSig } from '@urbit/aura'
+import Button from './shared/Button';
+import { FeedbackContext } from '../../contexts/FeedbackContext';
+import Command from '../../types/Command';
+import Input from './shared/Input';
+import Dropdown from './shared/Dropdown';
+import Network from '../../types/Network';
+import CommandForm from './shared/CommandForm';
+
+const TestInvoice = ({ api }: { api: Urbit }) => {
+ const { displayCommandSuccess, displayCommandError, displayJsError } = useContext(FeedbackContext);
+
+ const [amountMsatsInput, setAmountMsatsInput] = useState('');
+ const [amountMsats, setAmountMsats] = useState(null);
+ const [shipInput, setShipInput] = useState('~');
+ const [ship, setShip] = useState(null);
+ const [network, setNetwork] = useState(Network.Regtest);
+
+ const onChangeShipInput = (e: React.ChangeEvent) => {
+ setShipInput(e.target.value);
+ if (isValidPatp(preSig(e.target.value))) {
+ setShip(preSig(e.target.value));
+ } else {
+ setShip(null);
+ }
+ };
+
+ const onChangePushMsatsInput = (e: React.ChangeEvent) => {
+ const input = e.target.value;
+ // Only allow positive integers
+ const isEmptyString = input === '';
+ const isPositiveInteger = /^\d*$/.test(input) && parseInt(input) > 0;
+ if (isEmptyString) {
+ setAmountMsatsInput(input);
+ setAmountMsats(null);
+ } else if (isPositiveInteger) {
+ setAmountMsatsInput(input);
+ setAmountMsats(parseInt(input));
+ }
+ };
+
+ const handleChangeNetwork = (e: React.ChangeEvent) => {
+ const target = e.target as HTMLInputElement;
+ setNetwork(target.value as Network);
+ };
+
+ const validateTestInvoiceParams = () => {
+ let valid = true;
+ if (!ship && ['~', ''].includes(shipInput)) {
+ displayJsError('Ship required');
+ valid = false;
+ } else if (!ship) {
+ displayJsError('Invalid ship');
+ valid = false;
+ } else if (ship === api.ship) {
+ displayJsError('Cannot send invoice to self');
+ valid = false;
+ }
+ if (!amountMsats) {
+ displayJsError('Amount required');
+ valid = false;
+ }
+ return valid;
+ }
+
+ const sendTestInvoice = (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!validateTestInvoiceParams()) return;
+ try {
+ api.poke({
+ app: "volt",
+ mark: "volt-command",
+ json: {
+ 'test-invoice': {
+ ship: ship,
+ msats: amountMsats,
+ network: network
+ }
+ },
+ onSuccess: () => displayCommandSuccess(Command.TestInvoice),
+ onError: (e) => displayCommandError(Command.TestInvoice, e),
+ });
+ } catch (e) {
+ displayJsError('Error sending test invoice')
+ }
+ };
+
+ const networkOptions = [
+ { value: Network.Regtest, label: 'Regtest' },
+ { value: Network.Testnet, label: 'Testnet' },
+ { value: Network.Mainnet, label: 'Mainnet' }
+ ];
+
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default TestInvoice;
diff --git a/ui/src/components/commands/shared/Button.tsx b/ui/src/components/commands/shared/Button.tsx
new file mode 100644
index 00000000..c78f61e7
--- /dev/null
+++ b/ui/src/components/commands/shared/Button.tsx
@@ -0,0 +1,20 @@
+import React, { FormEvent } from 'react';
+
+interface ButtonProps {
+ label: string;
+ onClick: (e: FormEvent) => void;
+ className?: string;
+}
+
+const Button = ({ label, onClick, className = '' }: ButtonProps) => {
+ return (
+
+ );
+};
+
+export default Button;
diff --git a/ui/src/components/commands/shared/CommandForm.tsx b/ui/src/components/commands/shared/CommandForm.tsx
new file mode 100644
index 00000000..48b385ea
--- /dev/null
+++ b/ui/src/components/commands/shared/CommandForm.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+
+interface CommandFormProps {
+ children: React.ReactNode[];
+}
+
+const CommandForm: React.FC = ({ children }) => {
+ return (
+
+
+ );
+};
+
+export default CommandForm;
diff --git a/ui/src/components/commands/shared/CopyButton.tsx b/ui/src/components/commands/shared/CopyButton.tsx
new file mode 100644
index 00000000..e67f18b5
--- /dev/null
+++ b/ui/src/components/commands/shared/CopyButton.tsx
@@ -0,0 +1,40 @@
+import React, { useState } from 'react';
+
+interface CopyButtonProps {
+ buttonText: string;
+ label: string | null | undefined;
+ copyText: string | null | undefined;
+ onClick?: (event: React.ChangeEvent) => void;
+ className?: string;
+}
+
+const CopyButton: React.FC = (
+ { buttonText, label = null, copyText = null, className = ''}
+) => {
+ const [showConfirmation, setShowConfirmation] = useState(false);
+
+ const onClick = (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!copyText) return;
+ navigator.clipboard.writeText(copyText);
+ setShowConfirmation(true);
+ setTimeout(() => setShowConfirmation(false), 1000);
+ }
+
+ return (
+
+ { label ? : null }
+
+
+ )
+};
+
+export default CopyButton;
diff --git a/ui/src/components/commands/shared/Dropdown.tsx b/ui/src/components/commands/shared/Dropdown.tsx
new file mode 100644
index 00000000..ebe43d14
--- /dev/null
+++ b/ui/src/components/commands/shared/Dropdown.tsx
@@ -0,0 +1,40 @@
+import React from 'react';
+
+interface Option {
+ label: string;
+ value: any;
+}
+
+interface DropdownProps {
+ label: string;
+ value: any;
+ onChange: (event: React.ChangeEvent) => void;
+ options: Option[];
+ className?: string;
+}
+
+const Dropdown: React.FC = (
+ { label, options, value, onChange, className = '' }
+) => {
+ const classNames = `border border-gray-300 px-4 py-3 rounded-md w-full ${className}`
+
+ return (
+
+
+
+
+ );
+};
+
+
+export default Dropdown;
diff --git a/ui/src/components/commands/shared/Input.tsx b/ui/src/components/commands/shared/Input.tsx
new file mode 100644
index 00000000..8783e840
--- /dev/null
+++ b/ui/src/components/commands/shared/Input.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+
+interface InputProps {
+ label: string;
+ value: string;
+ onChange: (event: React.ChangeEvent) => void;
+ className?: string;
+}
+
+const Input: React.FC = ({ label, value, onChange, className = ''}) => {
+ return (
+
+
+
+
+ )
+};
+
+export default Input;
diff --git a/ui/src/components/commands/shared/Text.tsx b/ui/src/components/commands/shared/Text.tsx
new file mode 100644
index 00000000..85f0c1a9
--- /dev/null
+++ b/ui/src/components/commands/shared/Text.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import Button from './Button';
+
+interface TextProps {
+ text: string;
+ className?: string;
+}
+
+
+const Text = ({ text, className = '' }: TextProps) => {
+ return (
+
+ {text}
+
+ );
+};
+
+export default Text;
diff --git a/ui/src/components/feedback/FeedbackConsole.tsx b/ui/src/components/feedback/FeedbackConsole.tsx
new file mode 100644
index 00000000..02335ea1
--- /dev/null
+++ b/ui/src/components/feedback/FeedbackConsole.tsx
@@ -0,0 +1,26 @@
+import React, { useEffect, useRef, useContext } from 'react';
+import { FeedbackContext } from '../../contexts/FeedbackContext';
+
+const FeedbackConsole: React.FC = () => {
+ const { lines } = useContext(FeedbackContext);
+
+ const bottomScrollDiv = useRef(null);
+
+ useEffect(() => {
+ if (lines?.length) {
+ bottomScrollDiv.current?.scrollIntoView({
+ behavior: "smooth",
+ block: "end",
+ });
+ }
+ }, [lines]);
+
+ return (
+
+ );
+};
+
+export default FeedbackConsole;
diff --git a/ui/src/components/feedback/FeedbackConsoleLine.tsx b/ui/src/components/feedback/FeedbackConsoleLine.tsx
new file mode 100644
index 00000000..c8a62592
--- /dev/null
+++ b/ui/src/components/feedback/FeedbackConsoleLine.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+
+interface FeedbackConsoleLine {
+ text: string;
+ isError?: boolean;
+ isSuccess?: boolean;
+}
+
+const FeedbackConsoleLine = ({ text, isError = false, isSuccess = false }: { text: string, isError: boolean, isSuccess: boolean }) => {
+ const prompt = {'>'}
+ if (isError) {
+ return (
+ {prompt}{text}
+ )
+ } else if (isSuccess) {
+ return (
+ {prompt}{text}
+ )
+ } else {
+ return {prompt}{text}
+ }
+}
+
+export default FeedbackConsoleLine;
diff --git a/ui/src/components/status/ChannelDisplay.tsx b/ui/src/components/status/ChannelDisplay.tsx
new file mode 100644
index 00000000..37e73c50
--- /dev/null
+++ b/ui/src/components/status/ChannelDisplay.tsx
@@ -0,0 +1,110 @@
+import React, { useContext, useMemo } from 'react';
+import { ChannelContext } from '../../contexts/ChannelContext';
+import Channel, { ChannelStatus } from '../../types/Channel';
+
+const ChannelDisplay: React.FC = () => {
+ const { channelsByStatus, channels } = useContext(ChannelContext);
+
+ const getStatusSortPriority = (status: ChannelStatus) => {
+ switch (status) {
+ case ChannelStatus.Open:
+ return 1;
+ case ChannelStatus.ForceClosing:
+ return 2;
+ case ChannelStatus.Closing:
+ return 3;
+ case ChannelStatus.Shutdown:
+ return 4;
+ case ChannelStatus.Funded:
+ return 5;
+ case ChannelStatus.Opening:
+ return 6;
+ case ChannelStatus.Preopening:
+ return 7;
+ case ChannelStatus.Closed:
+ return 8;
+ case ChannelStatus.Redeemed:
+ return 9;
+ }
+ }
+
+ const compareChannels = (a: Channel, b: Channel) => {
+ // Group by status
+ if (a.status !== b.status) {
+ return getStatusSortPriority(a.status) - getStatusSortPriority(b.status);
+ }
+ // Order within status by liquidity
+ const aLiquidity = a.our.add(a.his);
+ const bLiquidity = b.our.add(b.his);
+ if (aLiquidity.gt(bLiquidity)) {
+ return -1;
+ } else if (bLiquidity.gt(aLiquidity)) {
+ return 1;
+ // Order by channel partner ship as fallback
+ } else if (a.who !== b.who) {
+ return a.who.localeCompare(b.who);
+ // Order by channel id as fallback
+ } else {{
+ return a.id.localeCompare(b.id);
+ }}
+ }
+
+ const notOpenChannels = useMemo(() => {
+ return channels
+ .filter((channel) => channel.status !== ChannelStatus.Open)
+ .sort(compareChannels)
+ }, [channels]);
+
+ const openChannels = useMemo(() => {
+ return channelsByStatus.open.sort(compareChannels)
+ }, [channelsByStatus]);
+
+ const headerClassnames = 'text-center font-normal w-1/4';
+ const rowClassnames = 'text-center text-gray-500 font-normal w-1/4';
+ const closedRowClassnames = 'text-center font-normal text-gray-400 w-1/4';
+
+ return (
+ <>
+ Channels
+
+ {channels.length === 0 ?
+
No channels found
+ : (
+
+
+
+
+ | Partner |
+ Ours |
+ Theirs |
+ Status |
+
+
+
+ {openChannels.map((channel) => (
+
+ | ~{channel.who} |
+ {channel.our.displayAsSats()} |
+ {channel.his.displayAsSats()} |
+ {channel.status.toUpperCase()} |
+
+
+ ))}
+ {notOpenChannels.map((channel) => (
+
+ | ~{channel.who} |
+ {channel.our.displayAsSats()} |
+ {channel.his.displayAsSats()} |
+ {channel.status.toUpperCase()} |
+
+ ))}
+
+
+
+ )}
+
+ >
+ );
+};
+
+ export default ChannelDisplay;
diff --git a/ui/src/components/status/LiquidityDisplay.tsx b/ui/src/components/status/LiquidityDisplay.tsx
new file mode 100644
index 00000000..3d331a77
--- /dev/null
+++ b/ui/src/components/status/LiquidityDisplay.tsx
@@ -0,0 +1,19 @@
+import React, { useContext } from 'react';
+import { ChannelContext } from '../../contexts/ChannelContext';
+
+
+const LiquidityDisplay: React.FC = () => {
+ const { inboundCapacity, outboundCapacity } = useContext(ChannelContext)
+
+ return (
+
+
Liquidity
+
+ {`Inbound: ${inboundCapacity.displayAsSats()}`}
+ {`Outbound: ${outboundCapacity.displayAsSats()}`}
+
+
+ );
+};
+
+export default LiquidityDisplay;
diff --git a/ui/src/contexts/ApiContext.tsx b/ui/src/contexts/ApiContext.tsx
new file mode 100644
index 00000000..ad1c75e9
--- /dev/null
+++ b/ui/src/contexts/ApiContext.tsx
@@ -0,0 +1,17 @@
+import React, { createContext } from 'react';
+import Urbit from '@urbit/http-api';
+
+type ApiContextValue = Urbit;
+
+const api = new Urbit('', '', window.desk);
+api.ship = process.env.VITE_SHIP_NAME || window.ship;
+
+export const ApiContext = createContext(api);
+
+export const ApiProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
+ return (
+
+ {children}
+
+ );
+};
diff --git a/ui/src/contexts/ChannelContext.tsx b/ui/src/contexts/ChannelContext.tsx
new file mode 100644
index 00000000..8eb34447
--- /dev/null
+++ b/ui/src/contexts/ChannelContext.tsx
@@ -0,0 +1,197 @@
+import React, { createContext, useState, useEffect, useContext, useMemo} from 'react';
+import Channel, { ChannelJson, ChannelStatus } from '../types/Channel';
+import { FeedbackContext } from './FeedbackContext';
+import { ApiContext } from './ApiContext';
+import BitcoinAmount from '../types/BitcoinAmount';
+import { ChannelDeletedUpdate, ChannelStateUpdate, InitialStateUpdate, NewChannelUpdate, Update, UpdateType } from '../types/Update';
+
+interface ChannelContextValue {
+ subscriptionConnected: boolean;
+ inboundCapacity: BitcoinAmount;
+ outboundCapacity: BitcoinAmount;
+ channels: Array;
+ channelsByStatus: {
+ preopening: Channel[];
+ opening: Channel[];
+ funded: Channel[];
+ open: Channel[];
+ shutdown: Channel[];
+ closing: Channel[];
+ "force-closing": Channel[];
+ closed: Channel[];
+ redeemed: Channel[];
+ };
+}
+
+export const ChannelContext = createContext({
+ subscriptionConnected: false,
+ inboundCapacity: new BitcoinAmount(0),
+ outboundCapacity: new BitcoinAmount(0),
+ channels: [],
+ channelsByStatus: {
+ preopening: [],
+ opening: [],
+ funded: [],
+ open: [],
+ shutdown: [],
+ closing: [],
+ "force-closing": [],
+ closed: [],
+ redeemed: [],
+ },
+});
+
+export const ChannelContextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
+ const api = useContext(ApiContext);
+ const { displayJsInfo, displayJsSuccess, displayJsError } = useContext(FeedbackContext);
+
+ const [subscriptionConnected, setSubscriptionConnected] = useState(false);
+ const [channels, setChannels] = useState>([]);
+
+ const channelsByStatus = useMemo(() => {
+ return channels.reduce(
+ (acc: { [key in ChannelStatus]: Channel[] }, channel) => {
+ const status = channel.status;
+ acc[status].push(channel);
+ return acc;
+ },
+ {
+ preopening: [],
+ opening: [],
+ funded: [],
+ open: [],
+ shutdown: [],
+ closing: [],
+ "force-closing": [],
+ closed: [],
+ redeemed: [],
+ } as { [key in ChannelStatus]: Channel[] }
+ );
+ }, [channels]);
+
+ useEffect(() => {
+ if (subscriptionConnected) {
+ displayJsSuccess("Subscription to /all succeeded");
+ }
+ }, [subscriptionConnected]);
+
+ useEffect(() => {
+ const handleAllUpdate = (update: Update) => {
+ console.log('Got update from /all', update);
+ if (!subscriptionConnected) {
+ setSubscriptionConnected(true);
+ } else {
+ displayJsInfo("Got update from /all");
+ }
+ if (update.type === UpdateType.InitialState) {
+ console.log('Got initial state update from /all', update);
+ handleInitialState(update as InitialStateUpdate);
+ } else if (update.type === UpdateType.ChannelState) {
+ console.log('Got channel state update from /all', update);
+ handleChannelUpdate(update as ChannelStateUpdate);
+ } else if (update.type === UpdateType.NewChannel) {
+ console.log('Got new channel update from /all', update);
+ handleNewChannel(update as NewChannelUpdate);
+ } else if (update.type === UpdateType.ChannelDeleted) {
+ console.log('Got channel deleted update from /all', update);
+ handleChannelDeleted(update as ChannelDeletedUpdate);
+ } else {
+ console.log('Unimplemented update type', update);
+ }
+ }
+
+ const handleChannelUpdate = (update: ChannelStateUpdate) => {
+ const { id, status }: { id: string, status: ChannelStatus } = update;
+ if (!id || !status) return;
+ return setChannels((channels) => {
+ const channel = channels.find((channel) => channel.id === id);
+ if (!channel) {
+ console.error('Channel not found in update from /all', update);
+ return channels;
+ }
+ channel.status = status;
+ return [...channels];
+ })
+ }
+
+ const handleNewChannel = (update: NewChannelUpdate) => {
+ const { 'chan-info': jsonChan }: { 'chan-info': ChannelJson } = update;
+ setChannels((channels) => {
+ if (channels.find((channel) => channel.id === jsonChan.id)) return channels;
+ const channel = {
+ ...jsonChan,
+ his: new BitcoinAmount(jsonChan.his),
+ our: new BitcoinAmount(jsonChan.our),
+ fundingAddress: jsonChan['funding-address'],
+ };
+ return [...channels, channel];
+ });
+ }
+
+ const handleChannelDeleted = (update: ChannelDeletedUpdate) => {
+ const { id }: { id: string } = update;
+ setChannels((channels) => {
+ const channel = channels.find((channel) => channel.id === id);
+ if (!channel) return channels;
+ return channels.filter((channel) => channel.id !== id);
+ })
+ }
+
+ const handleInitialState = (update: InitialStateUpdate) => {
+ const { chans: jsonChans }: { 'chans': Array } = update;
+ const channels: Array = jsonChans.map((chan) => {
+ return {
+ ...chan,
+ his: new BitcoinAmount(chan.his),
+ our: new BitcoinAmount(chan.our),
+ fundingAddress: chan['funding-address']
+ }
+ });
+ setChannels(channels);
+ };
+
+ const subscribe = () => {
+ try {
+ api.subscribe({
+ app: "volt",
+ path: "/all",
+ event: (e) => {
+ handleAllUpdate(e);
+ },
+ err: () => displayJsError("Subscription to /all rejected"),
+ quit: () => displayJsError("Kicked from subscription to /all"),
+ });
+ } catch (e) {
+ displayJsError("Error subscribing to /all"),
+ console.error(e)
+ }
+ };
+ subscribe()
+ }, [])
+
+ const inboundCapacity = useMemo(() => {
+ return channelsByStatus.open?.reduce(
+ (total, channel) => total.add(channel.his), new BitcoinAmount(0)
+ );
+ }, [channelsByStatus]);
+
+ const outboundCapacity = useMemo(() => {
+ return channelsByStatus.open?.reduce(
+ (total, channel) => total.add(channel.our), new BitcoinAmount(0)
+ );
+ }, [channelsByStatus]);
+
+ const value = {
+ subscriptionConnected,
+ channels,
+ channelsByStatus,
+ inboundCapacity,
+ outboundCapacity
+ };
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/ui/src/contexts/FeedbackContext.tsx b/ui/src/contexts/FeedbackContext.tsx
new file mode 100644
index 00000000..c78b20b2
--- /dev/null
+++ b/ui/src/contexts/FeedbackContext.tsx
@@ -0,0 +1,79 @@
+import React, { createContext, useMemo, useState } from 'react';
+import FeedbackConsoleLine from '../components/feedback/FeedbackConsoleLine';
+import Command from '../types/Command';
+
+interface FeedbackContextValue {
+ displayCommandSuccess: (command: Command) => void;
+ displayCommandError: (command: Command, text: string) => void;
+ displayJsSuccess: (text: string) => void;
+ displayJsInfo: (text: string) => void;
+ displayJsError: (text: string) => void;
+ lines: Array;
+}
+
+export const FeedbackContext = createContext({
+ displayCommandSuccess: () => {},
+ displayCommandError: () => {},
+ displayJsSuccess: () => {},
+ displayJsInfo: () => {},
+ displayJsError: () => {},
+ lines: [],
+});
+
+export const FeedbackContextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
+ const defaultLine =
+ const [lines, setLines] = useState>([defaultLine]);
+
+ const displayCommandSuccess = useMemo(() => {
+ return (command: Command): void => {
+ const text = `[JS]: %${command} succeeded ✅`;
+ const newLine =
+ setLines(oldLines => [...oldLines, newLine]);
+ }
+ }, [lines])
+
+ const displayCommandError = (command: Command, text: string): void => {
+ const newLines = text.split('\n').filter(line => line.length).map(line => {
+ return
+ })
+ newLines.unshift(
+
+ )
+ setLines(oldLines => [...oldLines, ...newLines]);
+ }
+
+ const displayJsSuccess = useMemo(() => {
+ return (text: string): void => {
+ text = `[JS]: ${text} ✅`;
+ const newLine =
+ setLines(oldLines => [...oldLines, newLine]);
+ }
+ }, [lines])
+
+ const displayJsInfo = (text: string): void => {
+ text = `[JS]: ${text}`;
+ const newLine =
+ setLines(oldLines => [...oldLines, newLine]);
+ }
+
+ const displayJsError = (text: string): void => {
+ text = `[JS]: ${text} ❌`;
+ const newLine =
+ setLines(oldLines => [...oldLines, newLine]);
+ }
+
+ const value = {
+ displayCommandSuccess,
+ displayCommandError,
+ displayJsSuccess,
+ displayJsInfo,
+ displayJsError,
+ lines,
+ };
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/ui/src/contexts/InvoiceContext.tsx b/ui/src/contexts/InvoiceContext.tsx
new file mode 100644
index 00000000..4738eb99
--- /dev/null
+++ b/ui/src/contexts/InvoiceContext.tsx
@@ -0,0 +1,60 @@
+import React, { useState, useEffect, useContext, createContext } from 'react';
+import { ApiContext } from './ApiContext';
+import { FeedbackContext } from './FeedbackContext';
+import Invoice from '../types/Invoice';
+import BitcoinAmount from '../types/BitcoinAmount';
+
+interface InvoiceContextValue {
+ latestInvoice: Invoice | null;
+}
+
+export const InvoiceContext = createContext({
+ latestInvoice: null,
+});
+
+export const InvoiceContextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
+ const api = useContext(ApiContext);
+ const { displayJsError, displayJsInfo } = useContext(FeedbackContext);
+
+ const [latestInvoice, setLatestInvoice] = useState(null);
+
+ useEffect(() => {
+ const handleLatestInvoice = (invoiceRaw: any) => {
+ displayJsInfo("Got update from /latest-invoice");
+ const payreq = invoiceRaw['payment-request'].payreq;
+ setLatestInvoice(
+ { payreq,
+ amount: new BitcoinAmount(invoiceRaw['payment-request']['amount-msats'])
+ }
+ )
+ }
+
+ const subscribe = () => {
+ try {
+ api.subscribe({
+ app: "volt",
+ path: "/latest-invoice",
+ event: (e) => {
+ handleLatestInvoice(e);
+ },
+ err: () => displayJsError("Subscription to /latest-invoice rejected"),
+ quit: () => displayJsError("Kicked from subscription to /latest-invoice"),
+ });
+ } catch (e) {
+ displayJsError("Error subscribing to /latest-invoice"),
+ console.error(e)
+ }
+ };
+ subscribe()
+ }, [])
+
+ const value = {
+ latestInvoice
+ };
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/ui/src/contexts/VoltProviderContext.tsx b/ui/src/contexts/VoltProviderContext.tsx
new file mode 100644
index 00000000..d91079f4
--- /dev/null
+++ b/ui/src/contexts/VoltProviderContext.tsx
@@ -0,0 +1,62 @@
+import React, { createContext, useState, useEffect, useContext } from 'react';
+import { FeedbackContext } from './FeedbackContext';
+import { ApiContext } from './ApiContext';
+
+
+interface VoltProviderContextValue {
+ providerIsConnected: boolean | null;
+}
+
+export const VoltProviderContext = createContext(undefined);
+
+export const VoltProviderContextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
+ const api = useContext(ApiContext);
+ const { displayJsSuccess, displayJsError } = useContext(FeedbackContext);
+
+ const [providerIsConnected, setProviderIsConnected] = useState(null);
+
+ useEffect(() => {
+ if (providerIsConnected === true) {
+ displayJsSuccess("Connected to provider");
+ } else if (providerIsConnected === false) {
+ displayJsError("Provider disconnected");
+ }
+ }, [providerIsConnected]);
+
+
+ useEffect(() => {
+ const handleProviderStatusUpdate = (e: any) => {
+ if (e?.connected === true && !providerIsConnected) {
+ setProviderIsConnected(true);
+ } else if (e?.connected === false) {
+ setProviderIsConnected(false);
+ }
+ }
+
+ const subscribeProvider = () => {
+ try {
+ api.subscribe({
+ app: "volt-provider",
+ path: "/status",
+ event: handleProviderStatusUpdate,
+ err: () => displayJsError("Subscription to /status rejected"),
+ quit: () => displayJsError("Kicked from subscription to /status"),
+ });
+ } catch (e) {
+ displayJsError("Error subscribing to /status"),
+ console.error(e)
+ }
+ }
+ subscribeProvider()
+ }, [])
+
+ const value = {
+ providerIsConnected
+ };
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/ui/src/env.d.ts b/ui/src/env.d.ts
new file mode 100644
index 00000000..703a0046
--- /dev/null
+++ b/ui/src/env.d.ts
@@ -0,0 +1,7 @@
+interface ImportMetaEnv extends Readonly> {
+ /* Add custom env properties here */
+}
+
+interface ImportMeta {
+ readonly env: ImportMetaEnv;
+}
diff --git a/ui/src/index.css b/ui/src/index.css
new file mode 100644
index 00000000..7c60e809
--- /dev/null
+++ b/ui/src/index.css
@@ -0,0 +1,26 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+html {
+ font-family: 'Telegrama', monospace;
+}
+
+@font-face {
+ font-family: 'Telegrama';
+ src: local('Telegrama'), url(./assets/Telegrama.otf) format('opentype');
+}
+
+body, html {
+ font-family: 'Telegrama', monospace !important;
+ color: rgb(128, 128, 128) !important
+}
+
+.not-selectable {
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
diff --git a/ui/src/main.tsx b/ui/src/main.tsx
new file mode 100644
index 00000000..a4c0f629
--- /dev/null
+++ b/ui/src/main.tsx
@@ -0,0 +1,11 @@
+import React from 'react';
+import { createRoot } from 'react-dom/client';
+import { App } from './app';
+import './index.css';
+
+const container = document.getElementById('app') as HTMLElement;
+createRoot(container).render(
+
+
+
+);
diff --git a/ui/src/types/BitcoinAmount.ts b/ui/src/types/BitcoinAmount.ts
new file mode 100644
index 00000000..5a731192
--- /dev/null
+++ b/ui/src/types/BitcoinAmount.ts
@@ -0,0 +1,66 @@
+const MSAT_PER_SAT = 1000;
+const SAT_PER_BTC = 100000000;
+const MSAT_PER_BTC = MSAT_PER_SAT * SAT_PER_BTC;
+
+export default class BitcoinAmount {
+ readonly millisatoshis: number;
+
+ constructor(millisatoshis: number) {
+ if (
+ !Number.isInteger(millisatoshis) ||
+ millisatoshis < 0 ||
+ millisatoshis > Number.MAX_SAFE_INTEGER
+ ) {
+ throw new Error('Invalid value for millisatoshis');
+ }
+ this.millisatoshis = millisatoshis;
+ }
+
+ static fromSatoshis(satoshis: number): BitcoinAmount {
+ const millisatoshis = satoshis * MSAT_PER_SAT;
+ return new BitcoinAmount(millisatoshis);
+ }
+
+ static fromBtc(btc: number): BitcoinAmount {
+ const millisatoshis = btc * MSAT_PER_BTC;
+ return new BitcoinAmount(millisatoshis);
+ }
+
+ add(other: BitcoinAmount): BitcoinAmount {
+ const sum = this.millisatoshis + other.millisatoshis;
+ return new BitcoinAmount(sum);
+ }
+
+ eq(other: BitcoinAmount): boolean {
+ return this.millisatoshis === other.millisatoshis;
+ }
+
+ gt(other: BitcoinAmount): boolean {
+ return this.millisatoshis > other.millisatoshis;
+ }
+
+ asBtc(): number {
+ return this.millisatoshis / MSAT_PER_BTC;
+ }
+
+ asSats(): number {
+ return this.millisatoshis / MSAT_PER_SAT;
+ }
+
+ displayAsMsats(): string {
+ return `${this.millisatoshis} msat.`;
+ }
+
+ displayAsSats(): string {
+ const satoshis = this.millisatoshis / MSAT_PER_SAT;
+ return `${satoshis} sat.`;
+ }
+
+ displayAsBtc(): string {
+ const btc = this.millisatoshis / MSAT_PER_BTC;
+ return `${btc} BTC`;
+ }
+}
+
+const MIN_FUNDING_SATS = 200000;
+export const MIN_FUNDING_AMOUNT = new BitcoinAmount(MIN_FUNDING_SATS * MSAT_PER_SAT);
diff --git a/ui/src/types/Channel.ts b/ui/src/types/Channel.ts
new file mode 100644
index 00000000..cacfc0dd
--- /dev/null
+++ b/ui/src/types/Channel.ts
@@ -0,0 +1,38 @@
+import BitcoinAmount from "./BitcoinAmount";
+
+export type ChannelId = string;
+export type Satoshis = number;
+export type Millisatoshis = number;
+export type Ship = string;
+
+export enum ChannelStatus {
+ Preopening = 'preopening',
+ Opening = 'opening',
+ Funded = 'funded',
+ Open = 'open',
+ Shutdown = 'shutdown',
+ Closing = 'closing',
+ ForceClosing = 'force-closing',
+ Closed = 'closed',
+ Redeemed = 'redeemed',
+}
+
+export interface ChannelJson {
+ id: ChannelId;
+ who: Ship;
+ our: number;
+ his: number;
+ 'funding-address': string | null;
+ status: ChannelStatus;
+}
+
+type Channel = {
+ id: ChannelId;
+ who: Ship;
+ our: BitcoinAmount;
+ his: BitcoinAmount;
+ fundingAddress: string | null;
+ status: ChannelStatus;
+};
+
+export default Channel;
diff --git a/ui/src/types/Command.ts b/ui/src/types/Command.ts
new file mode 100644
index 00000000..a6bb7db9
--- /dev/null
+++ b/ui/src/types/Command.ts
@@ -0,0 +1,12 @@
+enum Command {
+ AddInvoice = "add-invoice",
+ CloseChannel = "close-channel",
+ CreateFunding = "create-funding",
+ OpenChannel = "open-channel",
+ SendPayment = "send-payment",
+ SetProvider = "set-provider",
+ SetUrl = "set-url",
+ TestInvoice = "test-invoice",
+}
+
+export default Command;
diff --git a/ui/src/types/Invoice.ts b/ui/src/types/Invoice.ts
new file mode 100644
index 00000000..22b97ef2
--- /dev/null
+++ b/ui/src/types/Invoice.ts
@@ -0,0 +1,8 @@
+import BitcoinAmount from "./BitcoinAmount";
+
+type Invoice = {
+ amount: BitcoinAmount;
+ payreq: string;
+}
+
+export default Invoice;
diff --git a/ui/src/types/Network.ts b/ui/src/types/Network.ts
new file mode 100644
index 00000000..061ae24b
--- /dev/null
+++ b/ui/src/types/Network.ts
@@ -0,0 +1,7 @@
+enum Network {
+ Regtest = "regtest",
+ Testnet = "testnet",
+ Mainnet = "main",
+}
+
+export default Network;
diff --git a/ui/src/types/Update.ts b/ui/src/types/Update.ts
new file mode 100644
index 00000000..7f54e179
--- /dev/null
+++ b/ui/src/types/Update.ts
@@ -0,0 +1,57 @@
+import { ChannelStatus } from "./Channel";
+
+export enum UpdateType {
+ ChannelState = "channel-state",
+ ReceivedPayment = "received-payment",
+ NewInvoice = "new-invoice",
+ InvoicePaid = "invoice-paid",
+ PaymentResult = "payment-result",
+ ChannelDeleted = "channel-deleted",
+ NewChannel = "new-channel",
+ InitialState = "initial-state",
+}
+
+export type Update = {
+ type: UpdateType;
+ [key: string]: any;
+};
+
+export type ChannelStateUpdate = {
+ type: UpdateType.ChannelState;
+ id: string;
+ status: ChannelStatus;
+};
+
+export type NewInvoiceUpdate = {
+ type: UpdateType.NewInvoice;
+ 'payment-request': {
+ 'amount-msats': number;
+ payreq: string;
+ };
+};
+
+export type NewChannelUpdate = {
+ type: UpdateType.NewChannel;
+ 'chan-info': ChanInfo;
+};
+
+export type ChannelDeletedUpdate = {
+ type: UpdateType.ChannelDeleted;
+ id: string;
+};
+
+export type InitialStateUpdate = {
+ type: UpdateType.InitialState;
+ chans: Array;
+ txs: Array;
+ invoices: Array;
+};
+
+export type ChanInfo = {
+ id: string;
+ who: string;
+ our: number;
+ his: number;
+ 'funding-address': string | null;
+ status: ChannelStatus;
+};
diff --git a/ui/src/vite-env.d.ts b/ui/src/vite-env.d.ts
new file mode 100644
index 00000000..11f02fe2
--- /dev/null
+++ b/ui/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/ui/src/window.ts b/ui/src/window.ts
new file mode 100644
index 00000000..46b86eae
--- /dev/null
+++ b/ui/src/window.ts
@@ -0,0 +1,8 @@
+declare global {
+ interface Window {
+ ship: string;
+ desk: string;
+ }
+}
+
+export {};
diff --git a/ui/tailwind.config.js b/ui/tailwind.config.js
new file mode 100644
index 00000000..12850ffe
--- /dev/null
+++ b/ui/tailwind.config.js
@@ -0,0 +1,11 @@
+module.exports = {
+ content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
+ theme: {
+ extend: {}
+ },
+ screens: {},
+ variants: {
+ extend: {}
+ },
+ plugins: []
+};
diff --git a/ui/tsconfig.json b/ui/tsconfig.json
new file mode 100644
index 00000000..22a4fcbf
--- /dev/null
+++ b/ui/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
+ "allowJs": false,
+ "skipLibCheck": true,
+ "esModuleInterop": false,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "module": "ESNext",
+ "moduleResolution": "Node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react"
+ },
+ "include": ["./src"]
+}
diff --git a/ui/vite.config.ts b/ui/vite.config.ts
new file mode 100644
index 00000000..75c6a759
--- /dev/null
+++ b/ui/vite.config.ts
@@ -0,0 +1,12 @@
+import { loadEnv, defineConfig } from 'vite';
+import reactRefresh from '@vitejs/plugin-react';
+import { urbitPlugin } from '@urbit/vite-plugin-urbit';
+
+// https://vitejs.dev/config/
+export default ({ mode }) => {
+ const env = loadEnv(mode, process.cwd());
+ return defineConfig({
+ define: { 'process.env': env },
+ plugins: [urbitPlugin({ base: 'volt', target: env.VITE_SHIP_URL, secure: false }), reactRefresh()]
+ });
+};
diff --git a/ui/yarn.lock b/ui/yarn.lock
new file mode 100644
index 00000000..0774ecf2
--- /dev/null
+++ b/ui/yarn.lock
@@ -0,0 +1,1336 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@alloc/quick-lru@^5.2.0":
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30"
+ integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
+
+"@ampproject/remapping@^2.2.0":
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630"
+ integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.0"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
+"@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244"
+ integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==
+ dependencies:
+ "@babel/highlight" "^7.23.4"
+ chalk "^2.4.2"
+
+"@babel/compat-data@^7.22.9":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98"
+ integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==
+
+"@babel/core@^7.23.3":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.5.tgz#6e23f2acbcb77ad283c5ed141f824fd9f70101c7"
+ integrity sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==
+ dependencies:
+ "@ampproject/remapping" "^2.2.0"
+ "@babel/code-frame" "^7.23.5"
+ "@babel/generator" "^7.23.5"
+ "@babel/helper-compilation-targets" "^7.22.15"
+ "@babel/helper-module-transforms" "^7.23.3"
+ "@babel/helpers" "^7.23.5"
+ "@babel/parser" "^7.23.5"
+ "@babel/template" "^7.22.15"
+ "@babel/traverse" "^7.23.5"
+ "@babel/types" "^7.23.5"
+ convert-source-map "^2.0.0"
+ debug "^4.1.0"
+ gensync "^1.0.0-beta.2"
+ json5 "^2.2.3"
+ semver "^6.3.1"
+
+"@babel/generator@^7.23.5":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.5.tgz#17d0a1ea6b62f351d281350a5f80b87a810c4755"
+ integrity sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==
+ dependencies:
+ "@babel/types" "^7.23.5"
+ "@jridgewell/gen-mapping" "^0.3.2"
+ "@jridgewell/trace-mapping" "^0.3.17"
+ jsesc "^2.5.1"
+
+"@babel/helper-compilation-targets@^7.22.15":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52"
+ integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==
+ dependencies:
+ "@babel/compat-data" "^7.22.9"
+ "@babel/helper-validator-option" "^7.22.15"
+ browserslist "^4.21.9"
+ lru-cache "^5.1.1"
+ semver "^6.3.1"
+
+"@babel/helper-environment-visitor@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
+ integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
+
+"@babel/helper-function-name@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
+ integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
+ dependencies:
+ "@babel/template" "^7.22.15"
+ "@babel/types" "^7.23.0"
+
+"@babel/helper-hoist-variables@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
+ integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
+"@babel/helper-module-imports@^7.22.15":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0"
+ integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==
+ dependencies:
+ "@babel/types" "^7.22.15"
+
+"@babel/helper-module-transforms@^7.23.3":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1"
+ integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==
+ dependencies:
+ "@babel/helper-environment-visitor" "^7.22.20"
+ "@babel/helper-module-imports" "^7.22.15"
+ "@babel/helper-simple-access" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ "@babel/helper-validator-identifier" "^7.22.20"
+
+"@babel/helper-plugin-utils@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295"
+ integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==
+
+"@babel/helper-simple-access@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de"
+ integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
+"@babel/helper-split-export-declaration@^7.22.6":
+ version "7.22.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
+ integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
+"@babel/helper-string-parser@^7.23.4":
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83"
+ integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==
+
+"@babel/helper-validator-identifier@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
+ integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
+
+"@babel/helper-validator-option@^7.22.15":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307"
+ integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==
+
+"@babel/helpers@^7.23.5":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.5.tgz#52f522840df8f1a848d06ea6a79b79eefa72401e"
+ integrity sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==
+ dependencies:
+ "@babel/template" "^7.22.15"
+ "@babel/traverse" "^7.23.5"
+ "@babel/types" "^7.23.5"
+
+"@babel/highlight@^7.23.4":
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b"
+ integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.22.20"
+ chalk "^2.4.2"
+ js-tokens "^4.0.0"
+
+"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.5":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.5.tgz#37dee97c4752af148e1d38c34b856b2507660563"
+ integrity sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==
+
+"@babel/plugin-transform-react-jsx-self@^7.23.3":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz#ed3e7dadde046cce761a8e3cf003a13d1a7972d9"
+ integrity sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-react-jsx-source@^7.23.3":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz#03527006bdc8775247a78643c51d4e715fe39a3e"
+ integrity sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/runtime@^7.12.5", "@babel/runtime@^7.16.0":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.5.tgz#11edb98f8aeec529b82b211028177679144242db"
+ integrity sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==
+ dependencies:
+ regenerator-runtime "^0.14.0"
+
+"@babel/template@^7.22.15":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
+ integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
+ dependencies:
+ "@babel/code-frame" "^7.22.13"
+ "@babel/parser" "^7.22.15"
+ "@babel/types" "^7.22.15"
+
+"@babel/traverse@^7.23.5":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.5.tgz#f546bf9aba9ef2b042c0e00d245990c15508e7ec"
+ integrity sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==
+ dependencies:
+ "@babel/code-frame" "^7.23.5"
+ "@babel/generator" "^7.23.5"
+ "@babel/helper-environment-visitor" "^7.22.20"
+ "@babel/helper-function-name" "^7.23.0"
+ "@babel/helper-hoist-variables" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ "@babel/parser" "^7.23.5"
+ "@babel/types" "^7.23.5"
+ debug "^4.1.0"
+ globals "^11.1.0"
+
+"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.5":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.5.tgz#48d730a00c95109fa4393352705954d74fb5b602"
+ integrity sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==
+ dependencies:
+ "@babel/helper-string-parser" "^7.23.4"
+ "@babel/helper-validator-identifier" "^7.22.20"
+ to-fast-properties "^2.0.0"
+
+"@esbuild/android-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622"
+ integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==
+
+"@esbuild/android-arm@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682"
+ integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==
+
+"@esbuild/android-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2"
+ integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==
+
+"@esbuild/darwin-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1"
+ integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==
+
+"@esbuild/darwin-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d"
+ integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==
+
+"@esbuild/freebsd-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54"
+ integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==
+
+"@esbuild/freebsd-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e"
+ integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==
+
+"@esbuild/linux-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0"
+ integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==
+
+"@esbuild/linux-arm@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0"
+ integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==
+
+"@esbuild/linux-ia32@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7"
+ integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==
+
+"@esbuild/linux-loong64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d"
+ integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==
+
+"@esbuild/linux-mips64el@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231"
+ integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==
+
+"@esbuild/linux-ppc64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb"
+ integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==
+
+"@esbuild/linux-riscv64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6"
+ integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==
+
+"@esbuild/linux-s390x@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071"
+ integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==
+
+"@esbuild/linux-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338"
+ integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==
+
+"@esbuild/netbsd-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1"
+ integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==
+
+"@esbuild/openbsd-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae"
+ integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==
+
+"@esbuild/sunos-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d"
+ integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==
+
+"@esbuild/win32-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9"
+ integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==
+
+"@esbuild/win32-ia32@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102"
+ integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==
+
+"@esbuild/win32-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d"
+ integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==
+
+"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2":
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098"
+ integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==
+ dependencies:
+ "@jridgewell/set-array" "^1.0.1"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/resolve-uri@^3.1.0":
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
+ integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
+
+"@jridgewell/set-array@^1.0.1":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
+ integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
+
+"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
+ version "1.4.15"
+ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
+ integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
+
+"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9":
+ version "0.3.20"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f"
+ integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.1.0"
+ "@jridgewell/sourcemap-codec" "^1.4.14"
+
+"@microsoft/fetch-event-source@^2.0.0":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz#9ceecc94b49fbaa15666e38ae8587f64acce007d"
+ integrity sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA==
+
+"@nodelib/fs.scandir@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+ dependencies:
+ "@nodelib/fs.stat" "2.0.5"
+ run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3":
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+ integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.5"
+ fastq "^1.6.0"
+
+"@types/babel__core@^7.20.4":
+ version "7.20.5"
+ resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017"
+ integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==
+ dependencies:
+ "@babel/parser" "^7.20.7"
+ "@babel/types" "^7.20.7"
+ "@types/babel__generator" "*"
+ "@types/babel__template" "*"
+ "@types/babel__traverse" "*"
+
+"@types/babel__generator@*":
+ version "7.6.7"
+ resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.7.tgz#a7aebf15c7bc0eb9abd638bdb5c0b8700399c9d0"
+ integrity sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==
+ dependencies:
+ "@babel/types" "^7.0.0"
+
+"@types/babel__template@*":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f"
+ integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==
+ dependencies:
+ "@babel/parser" "^7.1.0"
+ "@babel/types" "^7.0.0"
+
+"@types/babel__traverse@*":
+ version "7.20.4"
+ resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.4.tgz#ec2c06fed6549df8bc0eb4615b683749a4a92e1b"
+ integrity sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==
+ dependencies:
+ "@babel/types" "^7.20.7"
+
+"@types/prop-types@*":
+ version "15.7.11"
+ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563"
+ integrity sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==
+
+"@types/react-dom@^18.2.0":
+ version "18.2.17"
+ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.17.tgz#375c55fab4ae671bd98448dcfa153268d01d6f64"
+ integrity sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==
+ dependencies:
+ "@types/react" "*"
+
+"@types/react@*", "@types/react@^18.2.0":
+ version "18.2.39"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.39.tgz#744bee99e053ad61fe74eb8b897f3ab5b19a7e25"
+ integrity sha512-Oiw+ppED6IremMInLV4HXGbfbG6GyziY3kqAwJYOR0PNbkYDmLWQA3a95EhdSmamsvbkJN96ZNN+YD+fGjzSBA==
+ dependencies:
+ "@types/prop-types" "*"
+ "@types/scheduler" "*"
+ csstype "^3.0.2"
+
+"@types/scheduler@*":
+ version "0.16.8"
+ resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff"
+ integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==
+
+"@urbit/api@^2.3.0":
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/@urbit/api/-/api-2.3.0.tgz#c876c9ca0569ae4cc7cb393edee33abe66b023df"
+ integrity sha512-uC0GyerFy6WaFHkgauvuJ55in2AUAJgCv/bHPOiwOKbdJQF4QgMaECn5gu/7n3d1/RGdNPaKw28nh0GCZ0AQKA==
+ dependencies:
+ "@babel/runtime" "^7.16.0"
+ big-integer "^1.6.48"
+ core-js "^3.19.1"
+ immer "^9.0.1"
+ urbit-ob "^5.0.1"
+
+"@urbit/aura@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@urbit/aura/-/aura-1.0.0.tgz#791cba1de04f128a4f30374ef4b9924f6b6d478b"
+ integrity sha512-IeP3uoDzZ0Rpn345auXK0y/BCcXTmpgAlOPbgf7n4eD35h56OnSoit1kuXKA21sWE19gFjK/wqZcz5ULjz2ADg==
+
+"@urbit/http-api@^2.3.0":
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/@urbit/http-api/-/http-api-2.3.0.tgz#3187c30e4d223da4245ad6282d5a6ca0da510bf6"
+ integrity sha512-3cKSdbBVcpoHqZLvoV23UK+nkqK0nFEBFKbaEwfBQE/NpkWf/7iP+mT7ldXTk7Uv/5bzDEBPqPB2fJNwdMQwcA==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ "@microsoft/fetch-event-source" "^2.0.0"
+ browser-or-node "^1.3.0"
+ core-js "^3.19.1"
+
+"@urbit/vite-plugin-urbit@^0.8.0":
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/@urbit/vite-plugin-urbit/-/vite-plugin-urbit-0.8.0.tgz#89a1efba6be7bdf50963d9c4ff83acdace943663"
+ integrity sha512-cx540xZBuHfzud/kOuYU4xPpsFcgE7mF0heac5uXVutDqjySvVXimEuZgBN23ULC7l60R/bAJ2jOWygBwWen4A==
+ dependencies:
+ vite-plugin-html-config "^1.0.6"
+ vite-plugin-rewrite-all "^0.1.2"
+
+"@vitejs/plugin-react@^4.0.0":
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.2.0.tgz#d71352b1a443c09c7aae8f278dd071ab3d9d8490"
+ integrity sha512-+MHTH/e6H12kRp5HUkzOGqPMksezRMmW+TNzlh/QXfI8rRf6l2Z2yH/v12no1UvTwhZgEDMuQ7g7rrfMseU6FQ==
+ dependencies:
+ "@babel/core" "^7.23.3"
+ "@babel/plugin-transform-react-jsx-self" "^7.23.3"
+ "@babel/plugin-transform-react-jsx-source" "^7.23.3"
+ "@types/babel__core" "^7.20.4"
+ react-refresh "^0.14.0"
+
+ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+ dependencies:
+ color-convert "^1.9.0"
+
+any-promise@^1.0.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
+ integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==
+
+anymatch@~3.1.2:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+ integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
+ dependencies:
+ normalize-path "^3.0.0"
+ picomatch "^2.0.4"
+
+arg@^5.0.2:
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
+ integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
+
+autoprefixer@^10.4.14:
+ version "10.4.16"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.16.tgz#fad1411024d8670880bdece3970aa72e3572feb8"
+ integrity sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==
+ dependencies:
+ browserslist "^4.21.10"
+ caniuse-lite "^1.0.30001538"
+ fraction.js "^4.3.6"
+ normalize-range "^0.1.2"
+ picocolors "^1.0.0"
+ postcss-value-parser "^4.2.0"
+
+balanced-match@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+big-integer@^1.6.48:
+ version "1.6.52"
+ resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85"
+ integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==
+
+binary-extensions@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
+ integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
+
+bn.js@^4.11.8:
+ version "4.12.0"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
+ integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+braces@^3.0.2, braces@~3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+ integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+ dependencies:
+ fill-range "^7.0.1"
+
+browser-or-node@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/browser-or-node/-/browser-or-node-1.3.0.tgz#f2a4e8568f60263050a6714b2cc236bb976647a7"
+ integrity sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg==
+
+browserslist@^4.21.10, browserslist@^4.21.9:
+ version "4.22.1"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619"
+ integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==
+ dependencies:
+ caniuse-lite "^1.0.30001541"
+ electron-to-chromium "^1.4.535"
+ node-releases "^2.0.13"
+ update-browserslist-db "^1.0.13"
+
+camelcase-css@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5"
+ integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
+
+caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541:
+ version "1.0.30001565"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz#a528b253c8a2d95d2b415e11d8b9942acc100c4f"
+ integrity sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==
+
+chalk@^2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+chokidar@^3.5.3:
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
+ integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
+ dependencies:
+ anymatch "~3.1.2"
+ braces "~3.0.2"
+ glob-parent "~5.1.2"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.6.0"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+color-convert@^1.9.0:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+ dependencies:
+ color-name "1.1.3"
+
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+
+commander@^4.0.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
+ integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+connect-history-api-fallback@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc"
+ integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==
+
+convert-source-map@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
+ integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
+
+core-js@^3.19.1:
+ version "3.33.3"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.33.3.tgz#3c644a323f0f533a0d360e9191e37f7fc059088d"
+ integrity sha512-lo0kOocUlLKmm6kv/FswQL8zbkH7mVsLJ/FULClOhv8WRVmKLVcs6XPNQAzstfeJTCHMyButEwG+z1kHxHoDZw==
+
+cssesc@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
+ integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+
+csstype@^3.0.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
+ integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
+
+debug@^4.1.0:
+ version "4.3.4"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+ integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+ dependencies:
+ ms "2.1.2"
+
+didyoumean@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
+ integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
+
+dlv@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
+ integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
+
+electron-to-chromium@^1.4.535:
+ version "1.4.596"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.596.tgz#6752d1aa795d942d49dfc5d3764d6ea283fab1d7"
+ integrity sha512-zW3zbZ40Icb2BCWjm47nxwcFGYlIgdXkAx85XDO7cyky9J4QQfq8t0W19/TLZqq3JPQXtlv8BPIGmfa9Jb4scg==
+
+esbuild@^0.18.10:
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6"
+ integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==
+ optionalDependencies:
+ "@esbuild/android-arm" "0.18.20"
+ "@esbuild/android-arm64" "0.18.20"
+ "@esbuild/android-x64" "0.18.20"
+ "@esbuild/darwin-arm64" "0.18.20"
+ "@esbuild/darwin-x64" "0.18.20"
+ "@esbuild/freebsd-arm64" "0.18.20"
+ "@esbuild/freebsd-x64" "0.18.20"
+ "@esbuild/linux-arm" "0.18.20"
+ "@esbuild/linux-arm64" "0.18.20"
+ "@esbuild/linux-ia32" "0.18.20"
+ "@esbuild/linux-loong64" "0.18.20"
+ "@esbuild/linux-mips64el" "0.18.20"
+ "@esbuild/linux-ppc64" "0.18.20"
+ "@esbuild/linux-riscv64" "0.18.20"
+ "@esbuild/linux-s390x" "0.18.20"
+ "@esbuild/linux-x64" "0.18.20"
+ "@esbuild/netbsd-x64" "0.18.20"
+ "@esbuild/openbsd-x64" "0.18.20"
+ "@esbuild/sunos-x64" "0.18.20"
+ "@esbuild/win32-arm64" "0.18.20"
+ "@esbuild/win32-ia32" "0.18.20"
+ "@esbuild/win32-x64" "0.18.20"
+
+escalade@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+ integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+
+escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
+
+fast-glob@^3.3.0:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
+ integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.2"
+ merge2 "^1.3.0"
+ micromatch "^4.0.4"
+
+fastq@^1.6.0:
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a"
+ integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==
+ dependencies:
+ reusify "^1.0.4"
+
+fill-range@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+ integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+ dependencies:
+ to-regex-range "^5.0.1"
+
+fraction.js@^4.3.6:
+ version "4.3.7"
+ resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7"
+ integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
+
+fsevents@~2.3.2:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+ integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
+gensync@^1.0.0-beta.2:
+ version "1.0.0-beta.2"
+ resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
+ integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
+
+glob-parent@^5.1.2, glob-parent@~5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+ dependencies:
+ is-glob "^4.0.1"
+
+glob-parent@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
+ integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
+ dependencies:
+ is-glob "^4.0.3"
+
+glob@7.1.6:
+ version "7.1.6"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
+ integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+globals@^11.1.0:
+ version "11.12.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+ integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
+
+hasown@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c"
+ integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==
+ dependencies:
+ function-bind "^1.1.2"
+
+immer@^9.0.1:
+ version "9.0.21"
+ resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176"
+ integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+is-binary-path@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+ integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+ dependencies:
+ binary-extensions "^2.0.0"
+
+is-core-module@^2.13.0:
+ version "2.13.1"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384"
+ integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
+ dependencies:
+ hasown "^2.0.0"
+
+is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+ integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-number@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+jiti@^1.19.1:
+ version "1.21.0"
+ resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d"
+ integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==
+
+"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+ integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+jsesc@^2.5.1:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
+ integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
+
+json5@^2.2.3:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
+ integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
+
+lilconfig@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52"
+ integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==
+
+lilconfig@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.0.0.tgz#f8067feb033b5b74dab4602a5f5029420be749bc"
+ integrity sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==
+
+lines-and-columns@^1.1.6:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
+ integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
+
+lodash.chunk@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/lodash.chunk/-/lodash.chunk-4.2.0.tgz#66e5ce1f76ed27b4303d8c6512e8d1216e8106bc"
+ integrity sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==
+
+lodash.isequal@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+ integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
+
+loose-envify@^1.1.0, loose-envify@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+ integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+ dependencies:
+ js-tokens "^3.0.0 || ^4.0.0"
+
+lru-cache@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
+ integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
+ dependencies:
+ yallist "^3.0.2"
+
+merge2@^1.3.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+micromatch@^4.0.4, micromatch@^4.0.5:
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
+ integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
+ dependencies:
+ braces "^3.0.2"
+ picomatch "^2.3.1"
+
+minimatch@^3.0.4:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+ms@2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+ integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+mz@^2.7.0:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
+ integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
+ dependencies:
+ any-promise "^1.0.0"
+ object-assign "^4.0.1"
+ thenify-all "^1.0.0"
+
+nanoid@^3.3.6:
+ version "3.3.7"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
+ integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
+
+node-releases@^2.0.13:
+ version "2.0.13"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d"
+ integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==
+
+normalize-path@^3.0.0, normalize-path@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+normalize-range@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
+ integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==
+
+object-assign@^4.0.1, object-assign@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
+
+object-hash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9"
+ integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
+
+once@^1.3.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+ dependencies:
+ wrappy "1"
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+
+path-parse@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+picocolors@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+ integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+pify@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+ integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
+
+pirates@^4.0.1:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9"
+ integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==
+
+postcss-import@^15.1.0:
+ version "15.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70"
+ integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==
+ dependencies:
+ postcss-value-parser "^4.0.0"
+ read-cache "^1.0.0"
+ resolve "^1.1.7"
+
+postcss-js@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2"
+ integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==
+ dependencies:
+ camelcase-css "^2.0.1"
+
+postcss-load-config@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3"
+ integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==
+ dependencies:
+ lilconfig "^3.0.0"
+ yaml "^2.3.4"
+
+postcss-nested@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.1.tgz#f83dc9846ca16d2f4fa864f16e9d9f7d0961662c"
+ integrity sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==
+ dependencies:
+ postcss-selector-parser "^6.0.11"
+
+postcss-selector-parser@^6.0.11:
+ version "6.0.13"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b"
+ integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==
+ dependencies:
+ cssesc "^3.0.0"
+ util-deprecate "^1.0.2"
+
+postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
+ integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
+
+postcss@^8.4.23, postcss@^8.4.27:
+ version "8.4.31"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
+ integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
+ dependencies:
+ nanoid "^3.3.6"
+ picocolors "^1.0.0"
+ source-map-js "^1.0.2"
+
+prop-types@^15.8.1:
+ version "15.8.1"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
+ integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
+ dependencies:
+ loose-envify "^1.4.0"
+ object-assign "^4.1.1"
+ react-is "^16.13.1"
+
+qr.js@0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f"
+ integrity sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==
+
+queue-microtask@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+ integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+react-dom@^18.2.0:
+ version "18.2.0"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
+ integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
+ dependencies:
+ loose-envify "^1.1.0"
+ scheduler "^0.23.0"
+
+react-is@^16.13.1:
+ version "16.13.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+ integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+
+react-qr-code@2.0.12:
+ version "2.0.12"
+ resolved "https://registry.yarnpkg.com/react-qr-code/-/react-qr-code-2.0.12.tgz#98f99e9ad5ede46d73ab819e2dd9925c5f5d7a2d"
+ integrity sha512-k+pzP5CKLEGBRwZsDPp98/CAJeXlsYRHM2iZn1Sd5Th/HnKhIZCSg27PXO58zk8z02RaEryg+60xa4vyywMJwg==
+ dependencies:
+ prop-types "^15.8.1"
+ qr.js "0.0.0"
+
+react-refresh@^0.14.0:
+ version "0.14.0"
+ resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
+ integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
+
+react@^18.2.0:
+ version "18.2.0"
+ resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
+ integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
+ dependencies:
+ loose-envify "^1.1.0"
+
+read-cache@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
+ integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==
+ dependencies:
+ pify "^2.3.0"
+
+readdirp@~3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+ integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
+ dependencies:
+ picomatch "^2.2.1"
+
+regenerator-runtime@^0.14.0:
+ version "0.14.0"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45"
+ integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==
+
+resolve@^1.1.7, resolve@^1.22.2:
+ version "1.22.8"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
+ integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
+ dependencies:
+ is-core-module "^2.13.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
+
+reusify@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+ integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
+rollup@^3.27.1:
+ version "3.29.4"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981"
+ integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+run-parallel@^1.1.9:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+ integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+ dependencies:
+ queue-microtask "^1.2.2"
+
+scheduler@^0.23.0:
+ version "0.23.0"
+ resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
+ integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
+ dependencies:
+ loose-envify "^1.1.0"
+
+semver@^6.3.1:
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
+
+source-map-js@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
+ integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
+
+sucrase@^3.32.0:
+ version "3.34.0"
+ resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.34.0.tgz#1e0e2d8fcf07f8b9c3569067d92fbd8690fb576f"
+ integrity sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.2"
+ commander "^4.0.0"
+ glob "7.1.6"
+ lines-and-columns "^1.1.6"
+ mz "^2.7.0"
+ pirates "^4.0.1"
+ ts-interface-checker "^0.1.9"
+
+supports-color@^5.3.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+ dependencies:
+ has-flag "^3.0.0"
+
+supports-preserve-symlinks-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+ integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+tailwindcss@^3.3.2:
+ version "3.3.5"
+ resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.5.tgz#22a59e2fbe0ecb6660809d9cc5f3976b077be3b8"
+ integrity sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==
+ dependencies:
+ "@alloc/quick-lru" "^5.2.0"
+ arg "^5.0.2"
+ chokidar "^3.5.3"
+ didyoumean "^1.2.2"
+ dlv "^1.1.3"
+ fast-glob "^3.3.0"
+ glob-parent "^6.0.2"
+ is-glob "^4.0.3"
+ jiti "^1.19.1"
+ lilconfig "^2.1.0"
+ micromatch "^4.0.5"
+ normalize-path "^3.0.0"
+ object-hash "^3.0.0"
+ picocolors "^1.0.0"
+ postcss "^8.4.23"
+ postcss-import "^15.1.0"
+ postcss-js "^4.0.1"
+ postcss-load-config "^4.0.1"
+ postcss-nested "^6.0.1"
+ postcss-selector-parser "^6.0.11"
+ resolve "^1.22.2"
+ sucrase "^3.32.0"
+
+thenify-all@^1.0.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
+ integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==
+ dependencies:
+ thenify ">= 3.1.0 < 4"
+
+"thenify@>= 3.1.0 < 4":
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f"
+ integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
+ dependencies:
+ any-promise "^1.0.0"
+
+to-fast-properties@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+ integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
+
+to-regex-range@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+ dependencies:
+ is-number "^7.0.0"
+
+ts-interface-checker@^0.1.9:
+ version "0.1.13"
+ resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699"
+ integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
+
+update-browserslist-db@^1.0.13:
+ version "1.0.13"
+ resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4"
+ integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==
+ dependencies:
+ escalade "^3.1.1"
+ picocolors "^1.0.0"
+
+urbit-ob@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/urbit-ob/-/urbit-ob-5.0.1.tgz#4338580e883bcf80af91777890572f8e5001ceda"
+ integrity sha512-qGNAwu87XNkW3g8ah4fUwmh2EKXtsdhEbyEiE5qX4Op17rhLH3HSkvu8g9z+MhqX51Uz9sf8ktvqJj/IRwETIQ==
+ dependencies:
+ bn.js "^4.11.8"
+ lodash.chunk "^4.2.0"
+ lodash.isequal "^4.5.0"
+
+util-deprecate@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+
+vite-plugin-html-config@^1.0.6:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/vite-plugin-html-config/-/vite-plugin-html-config-1.0.11.tgz#7018fb41d17ced527d79f76361e9a9cf587f80bc"
+ integrity sha512-hUybhgI+/LQQ5q6xoMMsTvI4PBuQD/Wv6Z1vtDPVWjanS8weCIexXuLLYNGD/93f0v8W2hpNfXpmxgpZMahJ0g==
+
+vite-plugin-rewrite-all@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/vite-plugin-rewrite-all/-/vite-plugin-rewrite-all-0.1.2.tgz#312bbcd76c700ceac5153bfc5ad7e3e3e4bc9606"
+ integrity sha512-hBFuG043kbixgZ/ke9SzKhkO6P8a5ryxD0CmZTe+/Cz17RIKi7uSeNUJy79V4FgavZ7pWVRg0tqVwJ7lP/A2/Q==
+ dependencies:
+ connect-history-api-fallback "^1.6.0"
+
+vite@^4.3.9:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.0.tgz#ec406295b4167ac3bc23e26f9c8ff559287cff26"
+ integrity sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==
+ dependencies:
+ esbuild "^0.18.10"
+ postcss "^8.4.27"
+ rollup "^3.27.1"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+yallist@^3.0.2:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
+ integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
+
+yaml@^2.3.4:
+ version "2.3.4"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2"
+ integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==
diff --git a/urbit/app/peerswap.hoon b/urbit/app/peerswap.hoon
new file mode 100644
index 00000000..eb4a32d4
--- /dev/null
+++ b/urbit/app/peerswap.hoon
@@ -0,0 +1,295 @@
+/- *peerswap, bolt
+/+ *peerswap-state, *peerswap-utils, *peerswap-threads
+/+ default-agent, dbug, utilities
+/= peerswap-message /mar/peerswap/message
+|%
++$ card card:agent:gall
++$ versioned-state
+ $% state-0
+ ==
++$ state-0
+ $: %0
+ swaps=(map swap-id swap)
+ keypairs=(map pubkey:bolt pair:key:bolt)
+ ==
+--
+%- agent:dbug
+=| state-0
+=* state -
+^- agent:gall
+=<
+|_ =bowl:gall
++* this .
+ def ~(. (default-agent this %.n) bowl)
+ hc ~(. +> bowl)
+++ on-init
+ ^- (quip card _this)
+ `this(state *state-0)
+::
+++ on-save
+ ^- vase
+ !>(state)
+::
+++ on-load on-load:def
+ :: |= old-state=vase
+ :: ^- (quip card _this)
+ :: :: `this(state !<(versioned-state old-state))
+ :: `this(state !<(versioned-state ~))
+++ on-poke
+ |= [=mark =vase]
+ ^- (quip card _this)
+ =^ cards state
+ ?+ mark (on-poke:def mark vase)
+ %peerswap-command
+ ?> (team:title our.bowl src.bowl)
+ (handle-command:hc !<(command vase))
+ %peerswap-message
+ ?< =((clan:title src.bowl) %pawn)
+ (handle-message:hc !<(message vase))
+ ::
+ ==
+ [cards this]
+::
+++ on-watch on-watch:def
+++ on-leave on-leave:def
+++ on-peek on-peek:def
+++ on-agent
+ |= [=wire =sign:agent:gall]
+ ^- (quip card _this)
+ =^ cards state
+ ?+ -.wire `state
+ %thread
+ (handle-thread wire sign)
+ ==
+ [cards this]
+++ on-arvo on-arvo:def
+++ on-fail on-fail:def
+--
+::
+|_ =bowl:gall
+++ handle-thread
+ |= [=wire =sign:agent:gall]
+ ?+ -.sign `state
+ %poke-ack
+ ?~ p.sign
+ %- (slog leaf+"Thread started successfully" ~)
+ `state
+ %- (slog leaf+"Thread failed to start" u.p.sign)
+ `state
+::
+ %fact
+ ?+ p.cage.sign `state
+ %thread-fail
+ =/ err !< (pair term tang) q.cage.sign
+ %- (slog leaf+"Thread failed: {(trip p.err)}" q.err)
+ `state
+ %thread-done
+ =/ =swap-id (get-swap-id-from-wire wire)
+ =/ =thread-type (get-thread-type-from-wire wire)
+ =/ =swap (get-swap swap-id)
+ =/ res !<(=update:volt q.cage.sign)
+ ~& 'thread done'
+ ~& thread-type
+ ~& -.res
+ ?+ -.res `state
+ %new-invoice (send-swap-out-agreement swap +.res)
+ %outgoing-payment ~& 'invoice payed' ~& +>.res (handle-payed-tx-fee-payreq swap)
+ ==
+ ==
+==
+::
+++ print-swap
+ |= =swap
+ ~& 'swap:'
+ ~& swap
+ `state
+++ debug-print
+ |= [swap-id=(unit swap-id) all=?]
+ :: print swap by
+ ?: ?=(^ swap-id)
+ =/ swap (~(get by swaps.state) +.swap-id)
+ ?: ?=(^ swap)
+ (print-swap +.swap)
+ ~& 'No swap found with id={}' `state
+ ?: all ~& 'Print all swap ids' ~& swaps.state `state
+ ~& 'Print last swap id'
+ `state
+++ handle-command
+ |= =command
+ ^- (quip card _state)
+ ?- -.command
+ %request-swap-in
+ (request-swap-in +.command)
+ %request-swap-out
+ (request-swap-out +.command)
+ %debug-print
+ (debug-print +.command)
+ ==
+::
+++ request-swap-in
+ |= [p=swap-params]
+ ^- (quip card _state)
+ (request-swap p %swap-in)
+::
+++ request-swap-out
+ |= [p=swap-params]
+ ^- (quip card _state)
+ (request-swap p %swap-out)
+::
+++ request-swap
+ |= [p=swap-params =swap-type]
+ ^- (quip card _state)
+ :: todo: should move more filtering into query-chans on volt side
+ =/ scid (select-swap-chan (query-chans ship.p) p swap-type)
+ =/ =pair:key:bolt (make-keypair bowl)
+ =/ =swap-request [protocol-version=1 (make-swap-id bowl) asset=~ network.p scid sats.p pub.pair]
+ =/ =swap (new-initiator-swap swap-request swap-type)
+ =/ message ?- swap-type
+ %swap-in [%swap-in-request swap-request]
+ %swap-out [%swap-out-request swap-request]
+ ==
+ :- ~[(send-message message ship.p)]
+ %= state
+ swaps (~(put by swaps) swap-id.swap swap)
+ keypairs (~(put by keypairs) pub.pair pair)
+ ==
+::
+++ handle-message
+ |= =message
+ ^- (quip card _state)
+ ~& -.message
+ ?- -.message
+ %swap-in-request
+ (handle-swap-in-request +.message)
+ %swap-in-agreement
+ (handle-swap-in-agreement +.message)
+ %swap-out-request
+ (handle-swap-out-request +.message)
+ %swap-out-agreement
+ (handle-swap-out-agreement +.message)
+ %opening-tx-broadcasted
+ (handle-opening-tx-broadcasted message)
+ %cancel
+ (handle-cancel message)
+ %coop-close
+ (handle-coop-close message)
+==
+::
+++ handle-swap-in-request
+ |= req=swap-request
+ ^- (quip card _state)
+ =/ =chan:bolt (get-chan scid.req)
+ ?> (can-facilitate-swap-in req chan)
+ =/ =pair:key:bolt (make-keypair bowl)
+ =/ message [%swap-in-agreement protocol-version=1 swap-id.req pub.pair premium=1]
+ =/ =swap (new-responder-swap-in req pub.pair 1)
+ :- ~[(send-message message src.bowl)]
+ %= state
+ swaps (~(put by swaps) swap-id.swap swap)
+ keypairs (~(put by keypairs) pub.pair pair)
+ ==
+::
+++ handle-swap-out-request
+ |= req=swap-request
+ ^- (quip card _state)
+ =/ =chan:bolt (get-chan scid.req)
+ ?> (can-facilitate-swap-out req chan)
+ =/ =pair:key:bolt (make-keypair bowl)
+ =/ =swap (new-responder-swap-out req pub.pair)
+ :- (get-opening-tx-fee-payreq bowl req)
+ %= state
+ swaps (~(put by swaps) swap-id.swap swap)
+ keypairs (~(put by keypairs) pub.pair pair)
+ ==
+::
+:: todo: how to distinguish this thread from other threads that get invoices
+++ send-swap-out-agreement
+ |= [s=swap p=payment-request:volt]
+ ^- (quip card _state)
+ =/ message [%swap-out-agreement protocol-version=1 swap-id.s our-pubkey.s payreq.p]
+ =/ new=swap (add-tx-fee-payreq s payreq.p)
+ :- ~[(send-message message src.bowl)]
+ %= state
+ swaps (~(put by swaps) swap-id.new new)
+ ==
+::
+++ handle-swap-in-agreement
+ |= a=swap-in-agreement
+ ^- (quip card _state)
+ :: create opening tx
+ :: send tx opened message
+ `state
+::
+++ handle-swap-out-agreement
+ |= a=swap-out-agreement
+ ^- (quip card _state)
+ =/ =swap (add-swap-out-agreement (get-swap swap-id.a) a)
+ :- (pay-opening-tx-fee-payreq bowl swap)
+ %= state
+ swaps (~(put by swaps) swap-id.swap swap)
+ ==
+::
+++ handle-payed-tx-fee-payreq
+ |= =swap
+ :- ~
+ %= state
+ swaps (~(put by swaps) swap-id.swap (update-swap-payed-tx-fee-payreq swap))
+ ==
+::
+++ handle-received-tx-fee-payment
+ |= =swap
+ !!
+::
+++ pay-tx-fee-invoice
+ |= =swap
+ ^- (list card)
+ ~
+::
+++ handle-opening-tx-broadcasted
+ |= =message
+ ^- (quip card _state)
+ !!
+::
+++ handle-cancel
+ |= =message
+ ^- (quip card _state)
+ !!
+::
+++ handle-coop-close
+ |= =message
+ ^- (quip card _state)
+ !!
+::
+++ send-message
+ |= [=message who=@p]
+ ^- card
+ :* %pass /message/[(scot %p who)]/[(scot %da now.bowl)]
+ %agent who^%peerswap
+ %poke %peerswap-message !>(message)
+ ==
+::
+++ get-swap
+ |= =swap-id
+ ^- swap
+ =/ maybe-swap=(unit swap) (~(get by swaps) swap-id)
+ ?. ?=(^ maybe-swap)
+ ~|("%peerswap: swap with id={} not found" !!)
+ +.maybe-swap
+::
+++ get-chan
+ |= =scid
+ ^- chan:bolt
+ =/ chans (skim (query-chans src.bowl) |=(=chan:bolt &(?=(^ scid.chan) =(+.scid.chan scid))))
+ ?. =(1 (lent chans))
+ ~|('%peerswap: Unrecognized channel id={} in swap request' !!)
+ -:chans
+::
+:: scries
+++ query-chans
+ :: todo: filter by network
+ |= ship=@p
+ ^- (list chan:bolt)
+ =/ bas=path /(scot %p our.bowl)/volt/(scot %da now.bowl)
+ .^((list chan:bolt) %gx (weld bas /channels/open/partner/(scot %p ship)/noun))
+::
+--
diff --git a/urbit/app/volt-provider.hoon b/urbit/app/volt-provider.hoon
index 6a0646f6..453feba1 100644
--- a/urbit/app/volt-provider.hoon
+++ b/urbit/app/volt-provider.hoon
@@ -138,6 +138,9 @@
?- -.action
%ping
[(do-rpc [%get-info ~]) state]
+ ::
+ %list-channels
+ [(do-rpc [%list-channels ~]) state]
::
%add-hold-invoice
[(do-rpc [%add-hold-invoice +.action]) state]
@@ -305,6 +308,9 @@
|= [=wire =result:rpc:volt]
^- (quip card _state)
?+ -.wire ~|("Unexpected RPC result" !!)
+ %list-channels
+ ~& 'list channels result!!'
+ `state
%get-info
?> ?=([%get-info *] result)
:_ state(connected.host-info %.y, node-info +.result)
diff --git a/urbit/app/volt.hoon b/urbit/app/volt.hoon
index 9353a113..a56fafa1 100644
--- a/urbit/app/volt.hoon
+++ b/urbit/app/volt.hoon
@@ -1,7 +1,7 @@
:: volt.hoon
:: Lightning channel management agent
::
-/- *volt, btc-provider
+/- *volt, btc-provider, bitcoin
/+ default-agent, dbug
/+ bc=bitcoin, bolt11, bip-b158
/+ revocation=revocation-store, tx=transactions
@@ -108,7 +108,7 @@
^- vase
!>(state)
::
-++ on-load
+++ on-load :: on-load:def
|= old-state=vase
^- (quip card _this)
~& > '%volt recompiled successfully'
@@ -165,7 +165,7 @@
`state(volt.prov ~)
::
%fact
- ?. =(%volt-provider-status p.cage.sign)
+ ?. =(%volt-provider-status p.cage.sign)
`state
(handle-provider-status:hc !<(status:provider q.cage.sign))
==
@@ -187,7 +187,7 @@
`state(volt.prov ~)
::
%fact
- ?. =(%volt-provider-update p.cage.sign)
+ ?. =(%volt-provider-update p.cage.sign)
`state
(handle-provider-update:hc !<(update:provider q.cage.sign))
==
@@ -252,14 +252,64 @@
|= =path
^- (quip card _this)
?+ path (on-watch:def path)
+ [%payment *]
+ `this
[%all ~]
?> (team:title our.bowl src.bowl)
- `this
+ =/ chans=(list chan-info)
+ %+ turn ~(tap by larv.chan)
+ |= [=id:bolt l=larva-chan:bolt]
+ :* id
+ ship.her.l
+ initial-msats.our.l
+ initial-msats.her.l
+ ?.(initiator.l ~ (get-funding-address id))
+ %preopening
+ ==
+ =. chans
+ %+ weld chans
+ %+ turn ~(tap by live.chan)
+ |= [=id:bolt c=chan:bolt]
+ :: confirm LI/FI
+ =+ our-com=(rear our.commitments.c)
+ =+ her-com=(rear her.commitments.c)
+ :* id
+ ship.her.config.c
+ balance.our.our-com
+ balance.her.her-com
+ `(unit address:bitcoin)`~
+ state.c
+ ==
+ =/ payment-requests=(list payment-request)
+ %+ turn ~(tap by incoming.payments)
+ |= [=hexb:bc =payment-request]
+ payment-request
+ :: pays
+ :_ this
+ ~[[%give %fact ~ %volt-update !>(`update`[%initial-state chans ~ payment-requests])]]
[%latest-invoice ~]
?> (team:title our.bowl src.bowl)
`this
==
::
+++ on-peek
+ |= =path
+ ^- (unit (unit cage))
+ ?+ path (on-peek:def path)
+ [%x %channels %open %partner @ ~]
+ =/ who=@p (slav %p i.t.t.t.t.path)
+ =/ peer-ids=(list id:bolt) ~(tap in (fall (~(get by peer.chan) who) [~]))
+ =/ peer-chans=(list chan:bolt)
+ %+ turn
+ %+ skim
+ %+ turn
+ peer-ids
+ |= =id:bolt (~(get by live.chan) id)
+ |= c=(unit chan:bolt) ?=(^ c)
+ need
+ ``noun+!>(peer-chans)
+ ==
+::
++ on-arvo
|= [=wire sign=sign-arvo]
^- (quip card _this)
@@ -271,12 +321,24 @@
[cards this]
==
::
-++ on-peek on-peek:def
++ on-leave on-leave:def
++ on-fail on-fail:def
--
::
|_ =bowl:gall
+++ get-funding-address
+ |= =id:bolt
+ =/ c=(unit larva-chan:bolt) (~(get by larv.chan) id)
+ ^- (unit address:bc)
+ ?> ?=(^ c)
+ ?> ?=(^ u.c)
+ ?> ?=(^ ac.u.c)
+ =+ ^= funding-address
+ %^ make-funding-address:channel
+ network.our.u.c
+ pub.multisig-key.our.u.c
+ funding-pubkey.u.ac.u.c
+ [~ funding-address]
++ handle-command
|= =command
|^ ^- (quip card _state)
@@ -332,6 +394,9 @@
:: ?. btcp.prov :: TODO: larval core pattern, avoid these checks everywhere
:: ~& >>> "%volt: no btc-provider set"
:: `state
+ ?: =(who src.bowl)
+ ~| "%volt: cannot open channel with self"
+ !!
?: (gth funding-sats max-funding-sats:const:bolt)
~| "%volt: must set funding-sats to less than 2^24 sats"
!!
@@ -399,14 +464,14 @@
=/ c=(unit larva-chan:bolt)
(~(get by larv.chan) temporary-channel-id)
?~ c
- ~& >>> "%volt: no channel with id: {}"
- `state
+ ~| "%volt: no channel with id: {}"
+ !!
?~ oc.u.c
- ~& >>> "%volt: invalid channel state: {}"
- `state
+ ~| "%volt: open channel message missing for channel with id: {}"
+ !!
?~ ac.u.c
- ~& >>> "%volt: invalid channel state: {}"
- `state
+ ~| "%volt: accept channel message missing for channel with id: {}"
+ !!
~| [%invalid-funding-tx funding]
:: =. -.funding (extract-unsigned:psbt funding)
:: =/ funding-tx=psbt:psbt (from-byts:create:^psbt psbt)
@@ -470,16 +535,29 @@
live.chan (~(put by live.chan) id.new-channel new-channel)
fund.chan (~(put by fund.chan) id.new-channel funding)
==
- ~[(send-message [%funding-created funding-created] ship.her.u.c)]
+ =/ =chan-info
+ :* id.new-channel
+ ship.her.config.new-channel
+ initial-msats.our.u.c
+ initial-msats.her.u.c
+ `(unit address:bitcoin)`~
+ state.new-channel
+ ==
+ :~ (send-message [%funding-created funding-created] ship.her.u.c)
+ (give-update [%channel-deleted temporary-channel-id])
+ (give-update [%new-channel chan-info])
+ ==
::
++ close-channel
|= =chan-id
^- (quip card _state)
?: (~(has by shut.chan) chan-id)
- ~& >>> "%volt: channel already closing"
- `state :: should probably crash,
+ ~| "%volt: channel already closing"
+ !!
=+ c=(~(get by live.chan) chan-id)
- ?~ c `state :: should probably crash, or at least report
+ ?~ c
+ ~| "%volt: no channel with id: {}"
+ !!
=| close=coop-close-state
=/ timer=@da (add now.bowl ~m1)
=. close
@@ -539,15 +617,15 @@
?. btcp.prov `state
=+ invoice=(de:bolt11 payreq)
?~ invoice
- ~& >>> "%volt: invalid payreq"
- `state
+ ~| "%volt: invalid payreq"
+ !!
?~ amount.u.invoice
- ~& >>> "%volt: payreq didn't specify amount"
- `state
+ ~| "%volt: payreq didn't specify amount"
+ !!
=+ amount-msats=(amount-to-msats:bolt11 u.amount.u.invoice)
?: =(0 amount-msats)
- ~& >>> "%volt: payreq amount is below 1 msat"
- `state
+ ~| "%volt: payreq amount is below 1 msat"
+ !!
=+ pubkey-point=(decompress-point:secp256k1:secp:crypto dat.pubkey.u.invoice)
=+ req=(~(get by incoming.payments) payment-hash.u.invoice)
?~ who
@@ -580,20 +658,27 @@
:: no bilateral capacity, try asking provider
::
(forward-to-provider payreq who)
- =^ result state (pay-channel u.channel amount-msats payment-hash.u.invoice %.n)
- [+.result state]
+ =^ result state
+ (pay-channel u.channel amount-msats payment-hash.u.invoice %.n)
+ [(snoc +.result (give-update-outgoing-payment payreq %.y)) state]
+ ::[(snoc ->.result (give-update-outgoing-payment payreq %.y)) state]
+ ::
+ ::
+ :: =/ res=(quip card _state) ->:(pay-channel u.channel amount-msats payment-hash.u.invoice %.n)
+ :: =. -.res (snoc -.res (give-update-outgoing-payment payreq %.y))
+ :: res
::
++ pay-ship
|= [who=@p =amount=msats =payment=hash =payreq]
^- (quip card _state)
=+ ids=(~(get by peer.chan) who)
?~ ids
- ~& >>> "%volt: no channels with {}"
- `state
+ ~| "%volt: no channels with {}"
+ !!
=+ c=(find-channel-with-capacity u.ids amount-msats)
?~ c
- ~& >>> "%volt: insufficient capacity with {}"
- `state
+ ~| "%volt: insufficient capacity with {}"
+ !!
=^ result state (pay-channel u.c amount-msats payment-hash %.n)
=| req=forward-request
=. req
@@ -609,20 +694,20 @@
|= [pay=payreq who=(unit ship)]
^- (quip card _state)
?~ volt.prov
- ~& >>> "%volt: no provider configured"
- `state
+ ~| "%volt: no provider configured"
+ !!
=+ provider-channels=(~(get by peer.chan) host.u.volt.prov)
?~ provider-channels
- ~& >>> "%volt: no channel with provider"
- `state
+ ~| "%volt: no channel with provider"
+ !!
=+ invoice=(de:bolt11 pay)
?~ invoice !!
?~ amount.u.invoice !!
=+ amount-msats=(amount-to-msats:bolt11 u.amount.u.invoice)
=+ c=(find-channel-with-capacity u.provider-channels amount-msats)
?~ c
- ~& >>> "%volt: insufficient capacity with provider"
- `state
+ ~| "%volt: insufficient capacity with provider"
+ !!
?> =(state.u.c %open)
=+ final-cltv=(add block.chain min-final-cltv-expiry:const:bolt)
=| update=update-add-htlc:msg:bolt
@@ -652,9 +737,10 @@
==
::
++ add-invoice
- |= [=amount=sats:bc memo=(unit @t) network=(unit network:bolt)]
- =+ amount-msats=(sats-to-msats:bolt amount-sats)
- ?~ volt.prov !!
+ |= [=amount=msats memo=(unit @t) network=(unit network:bolt)]
+ ?~ volt.prov
+ ~| "%volt: no provider configured"
+ !!
=/ rng ~(. og eny.bowl)
=^ preimage rng (rads:rng (bex 256))
=+ hash=(sha256:bcu:bc 32^preimage)
@@ -882,11 +968,20 @@
ac `accept-channel
==
::
+ =/ =chan-info
+ :* temporary-channel-id
+ ship.her.lar
+ initial-msats.our.lar
+ initial-msats.her.lar
+ ~
+ %preopening
+ ==
:_ %= state
larv.chan (~(put by larv.chan) temporary-channel-id lar)
chal.keys (~(put by chal.keys) src.bowl chal)
==
:~ (send-message [%accept-channel accept-channel] src.bowl)
+ (give-update [%new-channel chan-info])
(volt-action [%give-pubkey chal] src.bowl)
==
::
@@ -961,7 +1056,7 @@
=? heat.chan.state tau
(~(put by heat.chan) [%bech32 tau-addr] temporary-channel-id.msg)
=| cards=(list card)
- =? cards tau ~[(give-update [%need-funding [%bech32 tau-addr] initial-msats.our.u.c])]
+ :: =? cards tau ~[(give-update [%need-funding [%bech32 tau-addr] initial-msats.our.u.c])]
%- (slog leaf+"wallet-address={}" ~)
::
:_ %= state
@@ -971,8 +1066,15 @@
her remote-config
ac `msg
== ==
- %+ snoc cards
- (give-update [%need-funding-signature temporary-channel-id.msg funding-address])
+ =/ =chan-info
+ :* temporary-channel-id.msg
+ ship.her.u.c
+ initial-msats.our.u.c
+ initial-msats.her.u.c
+ [~ funding-address]
+ %preopening
+ ==
+ ~[(give-update [%new-channel chan-info])]
::
++ handle-funding-created
|= msg=funding-created:msg:bolt
@@ -1031,8 +1133,20 @@
wach.chan
(~(put by wach.chan) script-pubkey.funding-output id.new-channel)
==
+ =+ our-com=(rear our.commitments.new-channel)
+ =+ her-com=(rear her.commitments.new-channel)
+ ~& > "returning signed funding tx to initiator"
+ =/ =chan-info
+ :* id.new-channel
+ ship.her.config.new-channel
+ balance.our.our-com
+ balance.her.her-com
+ `(unit address:bitcoin)`~
+ %opening
+ ==
:~ (send-message [%funding-signed id.new-channel sig] src.bowl)
- (give-update [%channel-state id.new-channel %opening])
+ (give-update [%channel-deleted temporary-channel-id.msg])
+ (give-update [%new-channel chan-info])
==
::
++ handle-funding-signed
@@ -1055,8 +1169,9 @@
sats.funding-outpoint.c
=. c (~(receive-first-commitment channel c) signature.msg)
=. c (~(set-state channel c) %opening)
- :: =+ tx=(encode-tx:psbt (extract-unsigned:psbt funding-tx))
- =+ tx=(extract:psbt funding-tx)
+ =+ tx=(encode-tx:psbt (extract-unsigned:psbt funding-tx))
+ :: todo: commenting this seems to fix my problem
+ :: =+ tx=(extract:psbt funding-tx)
=+ id=(request-id dat.tx)
=/ =action:btc-provider [id %broadcast-tx tx]
:_
@@ -1076,8 +1191,10 @@
wach.chan
(~(put by wach.chan) script-pubkey.funding-output channel-id.msg)
==
- %+ snoc (poke-btc-provider action)
- (give-update [%channel-state id.c %opening])
+ %- snoc
+ :- (poke-btc-provider action)
+ (give-update [%channel-state id.c %opening])
+
::
++ handle-funding-locked
|= msg=funding-locked:msg:bolt
@@ -1104,6 +1221,7 @@
::
++ handle-update-add-htlc
|= msg=update-add-htlc:msg:bolt
+ ~& 'handle-update-add-htlc'
^- (quip card _state)
?> (~(has by live.chan) channel-id.msg)
=+ c=(~(got by live.chan) channel-id.msg)
@@ -1114,6 +1232,7 @@
::
++ handle-commitment-signed
|= msg=commitment-signed:msg:bolt
+ ~& 'handle-commitment-signed'
^- (quip card _state)
?> (~(has by live.chan) channel-id.msg)
=+ c=(~(got by live.chan) channel-id.msg)
@@ -1129,6 +1248,7 @@
::
++ handle-revoke-and-ack
|= msg=revoke-and-ack:msg:bolt
+ ~& 'handle-revoke-and-ack'
^- (quip card _state)
?> (~(has by live.chan) channel-id.msg)
=+ c=(~(got by live.chan) channel-id.msg)
@@ -1281,7 +1401,7 @@
~| "%volt: recvd fulfill for unknown htlc"
=+ fwd=(~(got by outgoing.payments) payment-hash)
=? cards-2 ours.fwd
- (snoc cards-2 (give-update-payment [%payment-result payreq.fwd %.y]))
+ (snoc cards-2 (give-update-outgoing-payment payreq.fwd %.y))
:- (weld cards-1 cards-2)
%= state
live.chan
@@ -1305,7 +1425,7 @@
?: &(=(channel-id channel-id.htlc.fwd) =(htlc-id htlc-id.htlc.fwd))
ours.fwd %.n
=? cards =(^ reqs)
- (snoc cards (give-update-payment [%payment-result payreq:(head reqs) %.n]))
+ (snoc cards (give-update-outgoing-payment payreq:(head reqs) %.n))
~& >>> "{} failed HTLC: {}"
[cards state(live.chan (~(put by live.chan) id.c c))]
::
@@ -1357,7 +1477,7 @@
?~ inv `state
=+ pr=(~(got by incoming.payments) payment-hash.u.inv)
=. payreq.pr payreq.action
- :- ~[(give-update-invoice [%new-invoice payreq.action])]
+ :- ~[(give-update-invoice pr)]
state(incoming.payments (~(put by incoming.payments) payment-hash.u.inv pr))
::
%give-pubkey
@@ -1568,6 +1688,7 @@
=/ =action:btc-provider [id %block-txs blockhash.status]
:_ state(pend.prov (~(put by pend.prov) id action))
(welp cards (poke-btc-provider action))
+
:: [addr-info state]
::
%connected
@@ -1603,7 +1724,7 @@
%^ ~(add-signature update:psbt tx)
0
pub:(need keys)
-
+
%^ ~(one sign:psbt tx)
0
(priv-to-hexb:key-gen prv:(need keys))
@@ -2003,7 +2124,7 @@
:: u.fees.chain.state
:: ==
:: =/ =force-close-state [ship.her.config.ch %.y u.revoked 0]
- :: :-
+ :: :-
:: :~ (poke-btc-provider [%broadcast-tx (extract:psbt sweep-tx)])
:: (give-update [%channel-state id %closing])
:: ==
@@ -2128,6 +2249,7 @@
height.u.utxo
0
block
+ =. scid.channel `(unit @t)`[~ (get-scid:bolt u.utxo)]
:: update the channel, if it's being found for the first time trigger funding-locked flow
=^ cards channel
(on-channel-update channel u.utxo block)
@@ -2208,8 +2330,6 @@
|= [=id:bolt acc=(unit chan:bolt)]
=+ c=(~(get by live.chan) id)
?~ c acc
- :: ~& > "STATE"
- :: ~& state.u.c
?: ?&(=(state.u.c %open) (~(can-pay channel u.c) amount-msats))
`u.c
acc
@@ -2338,7 +2458,7 @@
++ maybe-send-commitment
|= c=chan:bolt
^- (quip card chan:bolt)
- ?: (~(has-unacked-commitment channel c) %remote)
+ ?: (~(has-unacked-commitment channel c) %remote)
`c
?. (~(owes-commitment channel c) %local) `c
=^ sigs c ~(sign-next-commitment channel c)
@@ -2411,7 +2531,7 @@
=| cards=(list card)
=+ pr=(~(got by incoming.payments) payment-hash.h)
=? cards =(our.bowl payee.pr)
- (snoc cards (give-update-payment [%payment-result payreq.pr %.y]))
+ (snoc cards (give-update-outgoing-payment payreq.pr %.y))
:_ (~(settle-htlc channel c) preimage htlc-id.h)
=- (snoc cards (send-message - ship.her.config.c))
[%update-fulfill-htlc id.c htlc-id.h preimage]
@@ -2436,7 +2556,7 @@
=. c (~(settle-htlc channel c) preimage htlc-id.htlc.u.fwd)
=^ cards c (maybe-send-commitment c)
=? cards ours.u.fwd
- (snoc cards (give-update-payment [%payment-result payreq.u.fwd %.y]))
+ (snoc cards (give-update-outgoing-payment payreq.u.fwd %.y))
:_ %= state
live.chan
(~(put by live.chan) id.c c)
@@ -2689,17 +2809,22 @@
[%give %fact ~[/all] %volt-update !>(update)]
::
++ give-update-invoice
- |= =update
+ |= =payment-request
^- card
+ =/ update [%new-invoice payment-request]
[%give %fact ~[/latest-invoice] %volt-update !>(update)]
::
-++ give-update-payment
- |= =update
+++ give-update-outgoing-payment
+ |= [=payreq success=?]
^- card
- ?+ -.update !!
- %payment-result
- [%give %fact ~[/[payreq.update]] %volt-update !>(update)]
- ==
+ =/ update [%outgoing-payment payreq success]
+ [%give %fact ~[/payment/outgoing/[payreq]] %volt-update !>(update)]
+::
+++ give-update-incoming-payment
+ |= [=payreq]
+ ^- card
+ =/ update [%incoming-payment payreq]
+ [%give %fact ~[/payment/incoming/[payreq]] %volt-update !>(update)]
::
++ request-id
|= salt=@
@@ -2751,4 +2876,4 @@
==
::
:: TODO add command type for hard force close in case of problem with updates log etc - not for app, footgun, troubleshoot only
---
\ No newline at end of file
+--
diff --git a/urbit/desk.bill b/urbit/desk.bill
index da8c7a83..ec7e1c9a 100644
--- a/urbit/desk.bill
+++ b/urbit/desk.bill
@@ -1,4 +1,5 @@
:~ %bitcoin-rpc
%volt-provider
%volt
+ %peerswap
==
diff --git a/urbit/desk.docket-0 b/urbit/desk.docket-0
new file mode 100644
index 00000000..9cede4d3
--- /dev/null
+++ b/urbit/desk.docket-0
@@ -0,0 +1,10 @@
+:~
+ title+'Volt'
+ info+'Lightning on Urbit'
+ color+0xe4.e4e7
+ version+[0 1 0]
+ website+'https://urbit.org'
+ license+'MIT'
+ base+'volt'
+ glob-ames+[~zod 0v0]
+==
diff --git a/urbit/lib/btc.hoon b/urbit/lib/btc.hoon
index 98a17e58..82870a02 100644
--- a/urbit/lib/btc.hoon
+++ b/urbit/lib/btc.hoon
@@ -161,7 +161,7 @@
`(encode:pbt:bc %.y get-rawtx get-txid ins outs)
--
:: wad: door for processing walts (wallets)
-:: parameterized on a walt and it's chyg account
+:: parameterized on a walt and it's chyg account
::
++ wad
|_ [w=walt =chyg]
@@ -468,7 +468,8 @@
==
++ utxo
%- ot
- :~ ['tx_pos' ni]
+ :~ ['tx_index' ni]
+ ['tx_pos' ni]
['tx_hash' (cu from-cord:hxb:bcu so)]
[%height ni]
[%value ni]
@@ -510,7 +511,7 @@
==
++ block-headers
%- ot
- :~ [%count ni]
+ :~ [%count ni]
[%hex (cu from-cord:hxb:bcu so)]
[%max ni]
[%root (cu:dejs-soft:format from-cord:hxb:bcu so:dejs-soft:format)]
@@ -519,7 +520,7 @@
++ tx-from-pos
%- ot
:~ [%tx-hash (cu from-cord:hxb:bcu so)]
- [%merkle (ar (cu from-cord:hxb:bcu so))]
+ [%merkle (ar (cu from-cord:hxb:bcu so))]
==
++ block-txs
%- ot
@@ -569,27 +570,27 @@
(mk-url '/feehistogram' '')
::
%get-block-headers
- %+ post-request
- %+ mk-url '/blockheaders' ''
+ %+ post-request
+ %+ mk-url '/blockheaders' ''
%- pairs
- :~ [%start (numb start.ract)]
+ :~ [%start (numb start.ract)]
[%count (numb count.ract)]
- [%cp (numb (fall cp.ract 0))]
- ==
+ [%cp (numb (fall cp.ract 0))]
+ ==
::
%get-tx-from-pos
- %+ post-request
- %+ mk-url '/txfrompos' ''
+ %+ post-request
+ %+ mk-url '/txfrompos' ''
%- pairs
- :~ [%height (numb height.ract)]
+ :~ [%height (numb height.ract)]
[%pos (numb pos.ract)]
- [%merkle %b merkle.ract]
- ==
+ [%merkle %b merkle.ract]
+ ==
::
%get-fee
%- get-request
%+ mk-url '/estimatefee/'
- %- crip
+ %- crip
%+ scow %ud block.ract
::
%update-psbt
diff --git a/urbit/lib/channel.hoon b/urbit/lib/channel.hoon
index 38b2d7b5..a0994f3f 100644
--- a/urbit/lib/channel.hoon
+++ b/urbit/lib/channel.hoon
@@ -1100,8 +1100,8 @@
++ sign-next-commitment
^- (pair (pair signature (list signature)) chan)
%- ?. (owes-commitment %local)
- ~& >>> "%volt: unexpected commitment"
- same
+ ~| "%volt: unexpected commitment"
+ !!
same
?: ~(has-unacked-commitment commitment-chain her.commitments.c)
~|(%unexpected-commitment !!)
@@ -1153,8 +1153,8 @@
|= [sig=signature htlc-sigs=(list signature)]
^- chan
%- ?. (owes-commitment %remote)
- ~& >>> "%volt: unexpected commitment"
- same
+ ~| "%volt: unexpected commitment"
+ !!
same
=+ previous=(oldest-unrevoked-commitment %remote)
?~ previous !!
diff --git a/urbit/lib/lnd-rpc.hoon b/urbit/lib/lnd-rpc.hoon
index a21fd424..7d54f00a 100644
--- a/urbit/lib/lnd-rpc.hoon
+++ b/urbit/lib/lnd-rpc.hoon
@@ -13,6 +13,7 @@
|= act=action:rpc:volt
|^ ^- json
?+ -.act ~|("Unknown request type" !!)
+ %list-channels ~ :: (list-channels +.act)
%open-channel (open-channel +.act)
%send-payment (send-payment +.act)
%add-hold-invoice (add-hold-invoice +.act)
@@ -279,6 +280,7 @@
%settle-invoice [%settle-invoice ~]
%subscribe-confirms [%subscribe-confirms ~]
%subscribe-spends [%subscribe-spends ~]
+ %list-channels [%list-channels ~]
==
++ node-info
%- ot
@@ -333,6 +335,12 @@
|= act=action:rpc:volt
|^ ^- request:http
?- -.act
+ ::
+ %list-channels
+ %- get-request
+ %+ url '/listChannels' ''
+ :: act
+ ::
%get-info
%- get-request
%+ url '/getinfo' ''
@@ -383,6 +391,7 @@
%+ post-request
%+ url '/spends' ''
act
+
==
++ url
|= [route=@t params=@t]
diff --git a/urbit/lib/peerswap/state.hoon b/urbit/lib/peerswap/state.hoon
new file mode 100644
index 00000000..dbb2fd0b
--- /dev/null
+++ b/urbit/lib/peerswap/state.hoon
@@ -0,0 +1,87 @@
+/- *peerswap, bc=bitcoin
+|%
+:: todo: sub-cores for responder vs initiator
+++ new-responder-swap-in
+ |= [req=swap-request our-pubkey=pubkey:bolt premium=sats:bc]
+ ^- swap
+ =| =swap
+ %= swap
+ protocol-version protocol-version.req
+ swap-id swap-id.req
+ network network.req
+ scid scid.req
+ amount amount.req
+ our-pubkey our-pubkey
+ their-pubkey (some pubkey.req)
+ premium (some premium)
+ initiator |
+ swap-type %swap-in
+ status %awaiting-tx-open
+ ==
+::
+++ new-responder-swap-out
+ |= [req=swap-request our-pubkey=pubkey:bolt]
+ ^- swap
+ =| =swap
+ %= swap
+ protocol-version protocol-version.req
+ swap-id swap-id.req
+ network network.req
+ scid scid.req
+ amount amount.req
+ our-pubkey our-pubkey
+ their-pubkey (some pubkey.req)
+ initiator |
+ swap-type %swap-out
+ status %generating-tx-fee-payreq
+ ==
+::
+++ new-initiator-swap
+ |= [req=swap-request =swap-type]
+ ^- swap
+ =| =swap
+ %= swap
+ protocol-version protocol-version.req
+ swap-id swap-id.req
+ network network.req
+ scid scid.req
+ amount amount.req
+ our-pubkey pubkey.req
+ initiator &
+ swap-type swap-type
+ status %awaiting-agreement
+ ==
+::
+++ add-tx-fee-payreq
+ |= [old=swap =payreq]
+ ^- swap
+ %= old
+ payreq (some payreq)
+ status %awaiting-tx-fee-payment
+ ==
+::
+++ add-swap-out-agreement
+ |= [old=swap agreement=swap-out-agreement]
+ ^- swap
+ %= old
+ payreq (some payreq.agreement)
+ their-pubkey (some pubkey.agreement)
+ status %paying-tx-fee-payreq
+ ==
+::
+++ update-swap-payed-tx-fee-payreq
+ |= [old=swap]
+ ^- swap
+ old(status %awaiting-tx-open)
+::
+++ update-swap-opening-tx-broadcasted
+ |= [old=swap msg=opening-tx-broadcasted]
+ ^- swap
+ %= old
+ payreq (some payreq.msg)
+ txid (some txid.msg)
+ script-out (some script-out.msg)
+ status %awaiting-swap
+ ==
+::
+--
diff --git a/urbit/lib/peerswap/threads.hoon b/urbit/lib/peerswap/threads.hoon
new file mode 100644
index 00000000..1780e152
--- /dev/null
+++ b/urbit/lib/peerswap/threads.hoon
@@ -0,0 +1,76 @@
+/- *peerswap, bolt, volt
+/+ *peerswap-utils
+|%
++$ card card:agent:gall
+::
+++ get-opening-tx-fee-payreq
+ |= [=bowl:gall req=swap-request]
+ ^- (list card)
+ =/ =command:volt
+ :*
+ %add-invoice
+ (estimate-opening-tx-fee)
+ (some 'Peerswap opening tx fee')
+ (some (get-bc-network network.req))
+ ==
+ (poke-volt bowl command swap-id.req)
+::
+++ pay-opening-tx-fee-payreq
+ |= [=bowl:gall =swap]
+ :: ?> =(status.swap %paying-tx-fee-payreq)
+ ^- (list card)
+ =/ =command:volt [%send-payment +.payreq.swap (some src.bowl)]
+ (poke-volt bowl command swap-id.swap)
+::
+:: todo
+++ estimate-opening-tx-fee
+ |= ~
+ ^- sats:bc
+ 100
+::
+++ get-thread-type-from-command
+ |= =command:volt
+ ^- thread-type
+ ?+ -.command !!
+ %add-invoice %get-opening-tx-fee-payreq
+ %send-payment %pay-opening-tx-fee-payreq
+ ==
+++ get-thread-type-from-wire
+ |= =wire
+ ^- thread-type
+ =/ thread-type-raw `term`(scan (trip (snag 1 wire)) sym)
+ ?> ?=(thread-type thread-type-raw)
+ thread-type-raw
+::
+++ get-swap-id-from-wire
+ |= =wire
+ ^- swap-id
+ (scan (trip (snag 2 wire)) dem:ag)
+::
+++ get-thread-file
+ |= =command:volt
+ ^- term
+ ?+ -.command !!
+ %add-invoice %api-get-invoice
+ %send-payment %api-send-payment
+ ==
+::
+++ poke-volt
+ |= [=bowl:gall =command:volt =swap-id]
+ ^- (list card)
+ =/ hash (scot %uv (sham eny.bowl))
+ =/ tid `@ta`(cat 3 'thread_' (scot %uv (sham eny.bowl)))
+ =/ swapid `@ta`(crip "{}")
+ =/ ta-now `@ta`(scot %da now.bowl)
+ =/ =thread-type (get-thread-type-from-command command)
+ =/ =wire /thread/[thread-type]/[swapid]/[ta-now]
+ :: ~& 'wire' ~& wire
+ ~& "thread file in threads.hoon: {<(get-thread-file command)>}"
+ ~& "thread-type in threads.hoon: {}"
+ ~& "command in threads.hoon: {}"
+ =/ start-args [~ `tid byk.bowl(r da+now.bowl) (get-thread-file command) !>(command)]
+ :~
+ [%pass wire %agent [our.bowl %spider] %watch /thread-result/[tid]]
+ [%pass wire %agent [our.bowl %spider] %poke %spider-start !>(start-args)]
+ ==
+--
diff --git a/urbit/lib/peerswap/utils.hoon b/urbit/lib/peerswap/utils.hoon
new file mode 100644
index 00000000..e65c68ac
--- /dev/null
+++ b/urbit/lib/peerswap/utils.hoon
@@ -0,0 +1,98 @@
+/- *peerswap, bolt
+/+ key-gen=key-generation
+|%
+++ select-swap-chan
+ |= [chans=(list chan:bolt) p=swap-params =swap-type]
+ ^- scid
+ ?: =(0 (lent chans))
+ ~|("%peerswap: no open channel with {}" !!)
+ =/ chan-can-swap ?- swap-type
+ %swap-in can-be-maker
+ %swap-out can-be-taker
+ ==
+ =/ can-swap-chans=(list chan:bolt) (skim chans (curr chan-can-swap sats.p))
+ ?: =(0 (lent can-swap-chans))
+ ~|("%peerswap: no open channel with {} has sufficient outbound capacity" !!)
+ +.scid:(rear can-swap-chans)
+::
+++ can-facilitate-swap
+ |= [req=swap-request =chan:bolt =swap-type]
+ ^- ?
+ ?. =(protocol-version.req 1)
+ ~|('%peerswap: Unrecognized protocol version={} in swap request' !!)
+ =/ chan-can-swap ?- swap-type
+ %swap-in can-be-taker
+ %swap-out can-be-maker
+ ==
+ ?. (chan-can-swap chan amount.req)
+ ~|("%peerswap: Proposed swap channel from {} does not have sufficient inbound capacity={} sat." !!)
+ &
+::
+++ can-be-maker
+ |= [=chan:bolt =sats:bc]
+ ^- ?
+ ?& (chan-has-outbound-liq chan sats)
+ ?=(^ scid.chan)
+ ==
+::
+++ can-be-taker
+ |= [=chan:bolt =sats:bc]
+ ^- ?
+ ?& (chan-has-inbound-liq chan sats)
+ ?=(^ scid.chan)
+ ==
+::
+++ chan-has-inbound-liq
+ |= [=chan:bolt amount=sats:bc]
+ :: todo: need util for this conversion
+ =/ =msats:bolt (mul amount 1.000)
+ ^- ?
+ :: todo: should we check our commitment or theirs
+ =+ our-com=(rear our.commitments.chan)
+ (gte balance.her.our-com msats)
+::
+++ chan-has-outbound-liq
+ |= [=chan:bolt amount=sats:bc]
+ :: todo: need util for this conversion
+ =/ =msats:bolt (mul amount 1.000)
+ ^- ?
+ :: todo: should we check our commitment or theirs
+ =+ our-com=(rear our.commitments.chan)
+ (gte balance.our.our-com msats)
+::
+++ can-facilitate-swap-in
+ |= [req=swap-request =chan:bolt]
+ ^- ?
+ (can-facilitate-swap req chan %swap-in)
+::
+++ can-facilitate-swap-out
+ |= [req=swap-request =chan:bolt]
+ ^- ?
+ (can-facilitate-swap req chan %swap-out)
+::
+++ make-swap-id
+ |= =bowl:gall
+ ^- swap-id
+ =/ rng ~(. og eny.bowl)
+ =^ tmp-id rng (rads:rng (bex 256))
+ tmp-id
+:: todo: check that this actually works
+++ make-keypair
+ |= =bowl:gall
+ =/ rng ~(. og eny.bowl)
+ =/ seed=@ (~(rad og eny.bowl) (bex 256))
+ :: todo: configure network
+ :: todo: look into key family (%multisig here)
+ =/ =pair:key:bolt (generate-keypair:key-gen seed %regtest %multisig)
+ pair
+::
+++ get-bc-network
+ |= peerswap-network=network
+ ^- network:bc
+ ?- peerswap-network
+ %liquid ~|('%peerswap: Liquid network not supported' !!)
+ %mainnet %main
+ %testnet %testnet
+ %signet %regtest
+ ==
+--
diff --git a/urbit/lib/utilities.hoon b/urbit/lib/utilities.hoon
index 3806ba3c..db08edc0 100644
--- a/urbit/lib/utilities.hoon
+++ b/urbit/lib/utilities.hoon
@@ -1,5 +1,5 @@
-/- *bolt
-/+ bc=bitcoin, bolt11
+/- *bolt, volt
+/+ bc=bitcoin, bolt11, bcu=bitcoin-utils
/+ der, psbt, ring
|%
++ bcu bcu:bc
@@ -172,4 +172,15 @@
%bech32
(bech32-decode +.address)
==
+::
+::
+++ get-scid
+ |= =utxo:bc
+ ^- scid:volt
+ :: https://developers.urbit.org/reference/hoon/stdlib/4k
+ =/ block "{((em-co:co [16 1] |=([? b=@ c=tape] [~(x ne b) c])) height.utxo)}"
+ =/ tx-index "{((em-co:co [16 1] |=([? b=@ c=tape] [~(x ne b) c])) tx-index.utxo)}"
+ =/ vout "{((em-co:co [16 1] |=([? b=@ c=tape] [~(x ne b) c])) pos.utxo)}"
+ (crip "{block}:{tx-index}:{vout}")
--
+
diff --git a/urbit/lib/volt-json.hoon b/urbit/lib/volt-json.hoon
new file mode 100644
index 00000000..e557b585
--- /dev/null
+++ b/urbit/lib/volt-json.hoon
@@ -0,0 +1,161 @@
+/- volt, bitcoin :: psbt
+/+ psbt
+|%
+++ dejs
+ =, dejs:format
+ |%
+ ++ command
+ |= jon=json
+ ^- command:volt
+ ~& jon
+ %. jon
+ %- of
+ :~ set-provider+(mu ship)
+ open-channel+(ot ~[who+ship funding-sats+ni push-msats+ni network+network])
+ create-funding+(ot ~[temporary-channel-id+(se %ud) psbt+psbt])
+ close-channel+(se %ud)
+ send-payment+(ot ~[payreq+so who+(mu ship)])
+ add-invoice+(ot ~[amount+ni memo+so:dejs-soft:format network+(mu network)])
+ test-invoice+(ot ~[ship+ship msats+ni network+network])
+ ==
+ ::
+ ++ psbt
+ |= jon=json
+ ^- psbt:^psbt
+ ?. ?=([%s @t] jon)
+ ~| "%volt: invalid psbt"
+ !!
+ (need (from-base64:create:^psbt +.jon))
+ ::
+ ++ provider
+ |%
+ ++ command
+ |= jon=json
+ ^- command:provider:volt
+ %. jon
+ %- of
+ :~ set-url+so
+ ==
+ --
+ ++ ship (su ;~(pfix sig fed:ag))
+ ++ network (su (perk %main %testnet %regtest ~))
+ --
+::
+++ enjs
+ =, enjs:format
+ |%
+ ++ provider
+ |%
+ ++ status
+ |= s=status:provider:volt
+ ^- json
+ (frond 'connected' b+=(s %connected))
+ ::
+ ++ update
+ |= upd=update:provider:volt
+ ^- json
+ ?- -.upd
+ %res
+ ?+ +<.upd !!
+ %node-info
+ (frond 'node-info' ~)
+ ==
+ %err
+ ?- +<.upd
+ %rpc-error
+ (frond 'error' s+'rpc-error')
+ %not-connected
+ (frond 'error' s+'not-connected')
+ %bad-request
+ (frond 'error' s+'not-connected')
+ ==
+ ==
+ --
+ ++ update
+ |= upd=update:volt
+ ^- json
+ ?+ -.upd (frond 'type' s+'unimplemented')
+ %channel-state
+ %- pairs
+ :~ ['type' s+'channel-state']
+ ['id' s+`@t`(scot %ud chan-id.upd)]
+ ['status' s+chan-state.upd]
+ ==
+ ::
+ %new-invoice
+ %- pairs
+ :~ ['type' s+'new-invoice']
+ ['payment-request' (payment-request payment-request.upd)]
+ ==
+ ::
+ %new-channel
+ %- pairs
+ :~ ['type' s+'new-channel']
+ ['chan-info' (chan-info chan-info.upd)]
+ ==
+ ::
+ %channel-deleted
+ %- pairs
+ :~ ['type' s+'channel-deleted']
+ ['id' s+`@t`(scot %ud id.upd)]
+ ==
+ ::
+ %initial-state
+ %- pairs
+ :~ ['type' s+'initial-state']
+ ['chans' a+(turn chans.upd chan-info)]
+ ['txs' a+(turn txs.upd pay-info)]
+ ['invoices' a+(turn invoices.upd payment-request)]
+ ==
+ ==
+ ::
+ ++ chan-info
+ |= info=chan-info:volt
+ ^- json
+ %- pairs
+ :~ ['id' s+`@t`(scot %ud id.info)]
+ ['who' (ship who.info)]
+ ['our' (numb our.info)]
+ ['his' (numb his.info)]
+ ['funding-address' (funding-address funding-address.info)]
+ ['status' s+status.info]
+ ==
+ ::
+ ++ funding-address
+ |= f=(unit address:bitcoin)
+ ^- json
+ ?~ f ~
+ ?- +<.f
+ %base58
+ !!
+ %bech32
+ s++>.f
+ ==
+ ::
+ ++ payment-request
+ |= payment-request=payment-request:volt
+ ^- json
+ %- pairs
+ :~ ['amount-msats' (numb amount-msats.payment-request)]
+ ['payreq' (payreq payreq.payment-request)]
+ ==
+ ::
+ ++ payreq
+ |= payreq=payreq:volt
+ ^- json
+ s+payreq
+ ::
+ ++ pay-info
+ |= info=pay-info:volt
+ ^- json
+ ~
+ ::
+ ++ hexb
+ |= h=hexb:bitcoin
+ ^- json
+ %- pairs
+ :~ wid+(numb:enjs wid.h)
+ dat+s+(scot %ux dat.h)
+ ==
+ --
+--
diff --git a/urbit/mar/peerswap/message.hoon b/urbit/mar/peerswap/message.hoon
new file mode 100644
index 00000000..ef7bb36a
--- /dev/null
+++ b/urbit/mar/peerswap/message.hoon
@@ -0,0 +1,12 @@
+/- peerswap
+|_ msg=message:peerswap
+++ grab
+ |%
+ ++ noun message:peerswap
+ --
+++ grow
+ |%
+ ++ noun msg
+ --
+++ grad %noun
+--
diff --git a/urbit/mar/volt-provider/command.hoon b/urbit/mar/volt-provider/command.hoon
index 57821c68..ec5b38f9 100644
--- a/urbit/mar/volt-provider/command.hoon
+++ b/urbit/mar/volt-provider/command.hoon
@@ -1,8 +1,10 @@
/- volt
+/+ volt-json
|_ cmd=command:provider:volt
++ grab
|%
++ noun command:provider:volt
+ ++ json command:provider:dejs:volt-json
--
++ grow
|%
diff --git a/urbit/mar/volt-provider/status.hoon b/urbit/mar/volt-provider/status.hoon
index 530de3c2..b8ed3730 100644
--- a/urbit/mar/volt-provider/status.hoon
+++ b/urbit/mar/volt-provider/status.hoon
@@ -1,4 +1,5 @@
/- volt
+/+ volt-json
|_ =status:provider:volt
++ grab
|%
@@ -7,6 +8,7 @@
++ grow
|%
++ noun status
+ ++ json (status:provider:enjs:volt-json status)
--
++ grad %noun
--
diff --git a/urbit/mar/volt-provider/update.hoon b/urbit/mar/volt-provider/update.hoon
index fa88e4b4..f86605b9 100644
--- a/urbit/mar/volt-provider/update.hoon
+++ b/urbit/mar/volt-provider/update.hoon
@@ -1,4 +1,5 @@
/- volt
+/+ volt-json
|_ =update:provider:volt
++ grab
|%
@@ -7,6 +8,7 @@
++ grow
|%
++ noun update
+ ++ json (update:provider:enjs:volt-json update)
--
++ grad %noun
--
diff --git a/urbit/mar/volt/command.hoon b/urbit/mar/volt/command.hoon
index c4a60c50..f7accdb4 100644
--- a/urbit/mar/volt/command.hoon
+++ b/urbit/mar/volt/command.hoon
@@ -1,8 +1,10 @@
/- *volt
+/+ volt-json
|_ cmd=command
++ grab
|%
++ noun command
+ ++ json command:dejs:volt-json
--
++ grow
|%
diff --git a/urbit/mar/volt/update.hoon b/urbit/mar/volt/update.hoon
index bd56ea93..7154a958 100644
--- a/urbit/mar/volt/update.hoon
+++ b/urbit/mar/volt/update.hoon
@@ -1,4 +1,5 @@
/- *volt
+/+ volt-json
|_ upd=update
++ grab
|%
@@ -7,14 +8,7 @@
++ grow
|%
++ noun upd
- ++ json
- =, enjs:format
- ?+ -.upd !!
- %new-invoice
- %- pairs
- :~ ['payreq' s+payreq.upd]
- ==
- ==
+ ++ json (update:enjs:volt-json upd)
--
++ grad %noun
---
\ No newline at end of file
+--
diff --git a/urbit/sur/bitcoin.hoon b/urbit/sur/bitcoin.hoon
index 4b83b5bf..477f242b 100644
--- a/urbit/sur/bitcoin.hoon
+++ b/urbit/sur/bitcoin.hoon
@@ -20,7 +20,7 @@
+$ sats @ud
+$ vbytes @ud
+$ txid hexb
-+$ utxo [pos=@ =txid height=@ value=sats recvd=(unit @da)]
++$ utxo [tx-index=@ pos=@ =txid height=@ value=sats recvd=(unit @da)]
++ address-info
$: =address
confirmed-value=sats
diff --git a/urbit/sur/bolt.hoon b/urbit/sur/bolt.hoon
index 8fcb1e4a..37d66032 100644
--- a/urbit/sur/bolt.hoon
+++ b/urbit/sur/bolt.hoon
@@ -8,10 +8,11 @@
:: [our-view=? our=a her=a]
:: TODO: remove =foo=type turn into foo=type
:: EXCEPT where this pattern is used to distinguish sat- and msat-denominated values
-+$ id @ :: channel ID
++$ id @ :: channel ID
++$ scid @t :: short channel ID
+$ htlc-id @
-+$ blocks @ :: number of blocks
-+$ msats @ :: millisats
++$ blocks @ :: number of blocks
++$ msats @ :: millisats
+$ commitment-number @
::
:: TODO: unify key types
@@ -258,6 +259,7 @@
::
+$ chan
$: =id
+ scid=(unit scid)
state=chan-state
=funding=outpoint
$= constraints
diff --git a/urbit/sur/peerswap.hoon b/urbit/sur/peerswap.hoon
new file mode 100644
index 00000000..f86767e0
--- /dev/null
+++ b/urbit/sur/peerswap.hoon
@@ -0,0 +1,94 @@
+:: https://github.com/ElementsProject/peerswap/blob/master/docs/peer-protocol.md
+/- bc=bitcoin, bolt, volt
+|%
++$ protocol-version @u
++$ asset (unit @t) :: only used for Liquid Network
++$ swap-id @
++$ payreq payreq:volt
++$ txid hexb:bc
++$ scid scid:volt
++$ network ?(%liquid %mainnet %testnet %signet)
++$ status
+ $? %awaiting-agreement
+ :: I think if the state is ever updated for this one, it has succeded?
+ %generating-tx-fee-payreq
+ :: same as ^^
+ %paying-tx-fee-payreq
+ %awaiting-tx-fee-payment
+ %awaiting-tx-open
+ %awaiting-fee-invoice
+ %awaiting-fee-invoice-payment
+ %awaiting-swap
+==
++$ swap-type ?(%swap-in %swap-out)
++$ swap-params [ship=@p =network =sats:bc]
++$ swap $:
+ =protocol-version
+ =swap-id
+ =asset
+ =network
+ =scid
+ amount=sats:bc
+ our-pubkey=pubkey:bolt
+ their-pubkey=(unit pubkey:bolt)
+ premium=(unit sats:bc)
+ payreq=(unit payreq)
+ initiator=?
+ =swap-type
+ =status
+ txid=(unit txid)
+ script-out=(unit @)
+ cancel-message=(unit @t)
+ coop-close-message=(unit @t)
+ coop-close-privkey=(unit privkey:bolt)
+==
++$ swap-request
+ $: =protocol-version
+ =swap-id
+ =asset
+ =network
+ =scid
+ amount=sats:bc
+ pubkey=pubkey:bolt
+==
++$ swap-in-agreement
+ $: =protocol-version
+ =swap-id
+ pubkey=pubkey:bolt
+ premium=sats:bc
+==
++$ swap-out-agreement
+ $: =protocol-version
+ =swap-id
+ pubkey=pubkey:bolt
+ payreq=payreq:volt
+==
++$ opening-tx-broadcasted
+ $: =swap-id
+ =payreq
+ =txid
+ script-out=@
+ blinding-key=(unit @) :: only used for Liquid Network
+==
+++ thread-type
+ $?
+ %get-opening-tx-fee-payreq
+ %pay-opening-tx-fee-payreq
+ ==
+++ message
+ $%
+ $:(%swap-in-request =swap-request)
+ $:(%swap-in-agreement =swap-in-agreement)
+ $:(%swap-out-request =swap-request)
+ $:(%swap-out-agreement =swap-out-agreement)
+ $:(%opening-tx-broadcasted =opening-tx-broadcasted)
+ $:(%cancel =swap-id message=@t)
+ $:(%coop-close =swap-id message=@t privkey=privkey:bolt)
+ ==
+ ++ command
+ $%
+ $:(%request-swap-in =swap-params)
+ $:(%request-swap-out =swap-params)
+ $:(%debug-print swap-id=(unit swap-id) all=?)
+ ==
+--
diff --git a/urbit/sur/volt.hoon b/urbit/sur/volt.hoon
index cb3454ac..14630fab 100644
--- a/urbit/sur/volt.hoon
+++ b/urbit/sur/volt.hoon
@@ -7,6 +7,9 @@
+$ hash hexb:bc
+$ preimage hexb:bc
+$ rpc-tx [=txid rawtx=hexb:bc]
+:: todo:
+:: +$ scid [height=@ tx-index=@ output-idx=@]
++$ scid @t
::
+$ msats msats:bolt
+$ chan-id id:bolt
@@ -23,6 +26,7 @@
+$ action
$% [%get-info ~]
[%wallet-balance ~]
+ [%list-channels ~]
[%open-channel node=pubkey local-amount=sats:bc push-amount=sats:bc]
[%close-channel funding-txid=txid output-index=@]
[%send-payment invoice=cord timeout=(unit @dr) fee-limit=(unit sats:bc)]
@@ -41,6 +45,7 @@
+$ result
$% [%get-info node-info]
[%wallet-balance total=msats confirmed=msats unconfirmed=msats]
+ [%list-channels ~]
[%open-channel channel-point]
[%close-channel ~]
[%send-payment ~]
@@ -210,6 +215,7 @@
::
+$ action
$% [%ping ~]
+ [%list-channels ~]
[%add-hold-invoice =amt=msats memo=(unit @t) =payment=hash expiry=(unit @dr)]
[%settle-invoice =preimage]
[%cancel-invoice =payment=hash]
@@ -225,6 +231,7 @@
::
+$ result
$% [%node-info =node-info]
+ [%list-channels ~]
[%hold-invoice payment-request=cord]
[%invoice-added add-invoice-response:rpc]
[%invoice-update invoice:rpc]
@@ -299,13 +306,34 @@
[%forward-payment =payreq htlc=update-add-htlc:msg:bolt dest=(unit ship)]
==
::
++$ chan-info
+ $: =id:bolt
+ who=ship
+ our=msats
+ his=msats
+ funding-address=(unit address:bc)
+ status=chan-state:bolt
+ ==
++$ pay-info
+ $: =payreq
+ chan=id:bolt
+ amt=sats:bc
+ pat-p=(unit ship)
+ node-id=(unit @)
+ done=?
+ ==
+::
+$ update
- $% [%need-funding-signature temporary-channel-id=@ =address:bc]
- [%need-funding =address:bc =msats]
- [%channel-state =chan-id =chan-state:bolt]
- [%received-payment from=ship =amt=msats]
- [%new-invoice =payreq]
- [%invoice-paid =payreq]
- [%payment-result =payreq success=?]
+ $% [%channel-state =chan-id =chan-state:bolt]
+ [%new-invoice =payment-request]
+ [%outgoing-payment =payreq success=?] :: ship? amount?
+ [%incoming-payment =payreq] :: :: ship? amount?
+ [%new-channel =chan-info]
+ [%channel-deleted id=@]
+ $: %initial-state
+ chans=(list chan-info)
+ txs=(list pay-info)
+ invoices=(list payment-request)
+ ==
==
--
diff --git a/urbit/ted/api/get-invoice.hoon b/urbit/ted/api/get-invoice.hoon
index 2a962a11..06ab9594 100644
--- a/urbit/ted/api/get-invoice.hoon
+++ b/urbit/ted/api/get-invoice.hoon
@@ -14,9 +14,9 @@
(take-fact:io /volt)
--
^- thread:spider
-|= arg=vase
+|= v=vase
=/ m (strand ,vase)
-=+ !<(=command:volt arg)
+=+ !<(=command:volt v)
;< ~ bind:m watch-volt
;< ~ bind:m (poke-volt command)
;< =cage bind:m take-result
diff --git a/urbit/ted/api/send-payment.hoon b/urbit/ted/api/send-payment.hoon
index 98e6873d..6ae6613b 100644
--- a/urbit/ted/api/send-payment.hoon
+++ b/urbit/ted/api/send-payment.hoon
@@ -1,26 +1,28 @@
/- spider, volt
/+ strand, io=strandio
=, strand=strand:spider
-::|%
-::++ poke-volt
-:: |= =command:volt
-:: ?> =(%send-payment -.command)
-:: (poke-our:io %volt %volt-command !>(command))
-::++ watch-volt
-:: =/ m (strand ,~)
-:: ;< =bowl:spider bind:m get-bowl:io
-:: (watch-our:io /[payreq.command] %volt /[payreq.command])
-::++ take-result
-:: (take-fact:io /[payreq.command])
-::--
+|%
+++ poke-volt
+ |= =command:volt
+ ?> ?=([%send-payment =payreq:volt who=(unit @p)] command)
+ ~& payreq.command
+ (poke-our:io %volt %volt-command !>(command))
+++ watch-volt
+ |= =payreq:volt
+ =/ m (strand ,~)
+ ;< =bowl:spider bind:m get-bowl:io
+ (watch-our:io /payment/outgoing/[payreq] %volt /payment/outgoing/[payreq])
+++ take-result
+ |= =payreq:volt
+ (take-fact:io /payment/outgoing/[payreq])
+--
^- thread:spider
-|= arg=vase
+|= v=vase
=/ m (strand ,vase)
-=+ !<(=command:volt arg)
-?> ?=(%send-payment -.command)
-;< =bowl:spider bind:m get-bowl:io
-;< ~ bind:m (watch-our:io /[payreq.command] %volt /latest-invoice)
-;< ~ bind:m (poke-our:io %volt %volt-command !>(command))
-;< =cage bind:m (take-fact:io /[payreq.command])
+=+ !<(=command:volt v)
+?> ?=([%send-payment =payreq:volt who=(unit @p)] command)
+;< ~ bind:m (watch-volt payreq.command)
+;< ~ bind:m (poke-volt command)
+;< =cage bind:m (take-result payreq.command)
?> =(%volt-update p.cage)
(pure:m q.cage)
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 00000000..4c8c6bf3
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,1199 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@grpc/proto-loader@^0.7.4":
+ version "0.7.10"
+ resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.10.tgz#6bf26742b1b54d0a473067743da5d3189d06d720"
+ integrity sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==
+ dependencies:
+ lodash.camelcase "^4.3.0"
+ long "^5.0.0"
+ protobufjs "^7.2.4"
+ yargs "^17.7.2"
+
+"@mapbox/node-pre-gyp@^1.0.4":
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa"
+ integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==
+ dependencies:
+ detect-libc "^2.0.0"
+ https-proxy-agent "^5.0.0"
+ make-dir "^3.1.0"
+ node-fetch "^2.6.7"
+ nopt "^5.0.0"
+ npmlog "^5.0.1"
+ rimraf "^3.0.2"
+ semver "^7.3.5"
+ tar "^6.1.11"
+
+"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
+ integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==
+
+"@protobufjs/base64@^1.1.2":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
+ integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
+
+"@protobufjs/codegen@^2.0.4":
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb"
+ integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
+
+"@protobufjs/eventemitter@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
+ integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==
+
+"@protobufjs/fetch@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
+ integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==
+ dependencies:
+ "@protobufjs/aspromise" "^1.1.1"
+ "@protobufjs/inquire" "^1.1.0"
+
+"@protobufjs/float@^1.0.2":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
+ integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==
+
+"@protobufjs/inquire@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
+ integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==
+
+"@protobufjs/path@^1.1.2":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
+ integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==
+
+"@protobufjs/pool@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
+ integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==
+
+"@protobufjs/utf8@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
+ integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
+
+"@types/bytebuffer@^5.0.40":
+ version "5.0.48"
+ resolved "https://registry.yarnpkg.com/@types/bytebuffer/-/bytebuffer-5.0.48.tgz#0e6b0e8b8dbafde3314148ed378b8aed6eaac4f1"
+ integrity sha512-ormKm68NtTOtR8C/4jyRJEYbwKABXRkHHR/1fmkiuFbCQkltgtXSUGfldCSmJzvuyJvmBzWjBbOi79Ry/oJQug==
+ dependencies:
+ "@types/long" "^3.0.0"
+ "@types/node" "*"
+
+"@types/long@^3.0.0":
+ version "3.0.32"
+ resolved "https://registry.yarnpkg.com/@types/long/-/long-3.0.32.tgz#f4e5af31e9e9b196d8e5fca8a5e2e20aa3d60b69"
+ integrity sha512-ZXyOOm83p7X8p3s0IYM3VeueNmHpkk/yMlP8CLeOnEcu6hIwPH7YjZBvhQkR0ZFS2DqZAxKtJ/M5fcuv3OU5BA==
+
+"@types/node@*", "@types/node@>=13.7.0":
+ version "20.10.0"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.0.tgz#16ddf9c0a72b832ec4fcce35b8249cf149214617"
+ integrity sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==
+ dependencies:
+ undici-types "~5.26.4"
+
+abbrev@1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+ integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+
+accepts@~1.3.8:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
+ integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
+ dependencies:
+ mime-types "~2.1.34"
+ negotiator "0.6.3"
+
+agent-base@6:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
+ integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
+ dependencies:
+ debug "4"
+
+ansi-regex@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+ integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==
+
+ansi-regex@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+ integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+
+ansi-styles@^4.0.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+ dependencies:
+ color-convert "^2.0.1"
+
+"aproba@^1.0.3 || ^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
+ integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==
+
+are-we-there-yet@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c"
+ integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==
+ dependencies:
+ delegates "^1.0.0"
+ readable-stream "^3.6.0"
+
+array-flatten@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+ integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==
+
+ascli@~1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/ascli/-/ascli-1.0.1.tgz#bcfa5974a62f18e81cabaeb49732ab4a88f906bc"
+ integrity sha512-JGQaNxpaCJz9Bd1JvVaFIHuWn9S+l3xhN17R0V/vmUDiGE0QngNMXhjlqpwqV+91plWz9Fg+Lt28Lj7p5vjs8A==
+ dependencies:
+ colour "~0.7.1"
+ optjs "~3.2.2"
+
+balanced-match@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+bn.js@^4.11.8:
+ version "4.12.0"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
+ integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
+
+body-parser@1.20.1:
+ version "1.20.1"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668"
+ integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==
+ dependencies:
+ bytes "3.1.2"
+ content-type "~1.0.4"
+ debug "2.6.9"
+ depd "2.0.0"
+ destroy "1.2.0"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ on-finished "2.4.1"
+ qs "6.11.0"
+ raw-body "2.5.1"
+ type-is "~1.6.18"
+ unpipe "1.0.0"
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+bytebuffer@~5:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/bytebuffer/-/bytebuffer-5.0.1.tgz#582eea4b1a873b6d020a48d58df85f0bba6cfddd"
+ integrity sha512-IuzSdmADppkZ6DlpycMkm8l9zeEq16fWtLvunEwFiYciR/BHo4E8/xs5piFquG+Za8OWmMqHF8zuRviz2LHvRQ==
+ dependencies:
+ long "~3"
+
+bytes@3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
+ integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
+
+call-bind@^1.0.0:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513"
+ integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==
+ dependencies:
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.1"
+ set-function-length "^1.1.1"
+
+camelcase@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
+ integrity sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==
+
+chownr@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
+ integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
+
+cliui@^3.0.3:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
+ integrity sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==
+ dependencies:
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+ wrap-ansi "^2.0.0"
+
+cliui@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
+ integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.1"
+ wrap-ansi "^7.0.0"
+
+code-point-at@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+ integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==
+
+color-convert@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+ dependencies:
+ color-name "~1.1.4"
+
+color-name@~1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+color-support@^1.1.2:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
+ integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
+
+colour@~0.7.1:
+ version "0.7.1"
+ resolved "https://registry.yarnpkg.com/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778"
+ integrity sha512-Rel466v0EnmKPcsxHo91L4kgPs/6XF7Pu2LJNszq9lXYwi5CFWEeIiRaTX5ym7PPMdj4udDHkLSVC1//JVkZQg==
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+console-control-strings@^1.0.0, console-control-strings@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+ integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==
+
+content-disposition@0.5.4:
+ version "0.5.4"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
+ integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
+ dependencies:
+ safe-buffer "5.2.1"
+
+content-type@~1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
+ integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
+
+cookie-signature@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+ integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
+
+cookie@0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
+ integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
+
+debug@2.6.9:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
+debug@4:
+ version "4.3.4"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+ integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+ dependencies:
+ ms "2.1.2"
+
+decamelize@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+ integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==
+
+define-data-property@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3"
+ integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==
+ dependencies:
+ get-intrinsic "^1.2.1"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.0"
+
+delegates@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+ integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==
+
+depd@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
+ integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
+
+destroy@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
+ integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
+
+detect-libc@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.2.tgz#8ccf2ba9315350e1241b88d0ac3b0e1fbd99605d"
+ integrity sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==
+
+ee-first@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+ integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
+
+emoji-regex@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+encodeurl@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+ integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
+
+escalade@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+ integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+
+escape-html@~1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+ integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
+
+etag@~1.8.1:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
+ integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
+
+express@^4.18.2:
+ version "4.18.2"
+ resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59"
+ integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==
+ dependencies:
+ accepts "~1.3.8"
+ array-flatten "1.1.1"
+ body-parser "1.20.1"
+ content-disposition "0.5.4"
+ content-type "~1.0.4"
+ cookie "0.5.0"
+ cookie-signature "1.0.6"
+ debug "2.6.9"
+ depd "2.0.0"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ finalhandler "1.2.0"
+ fresh "0.5.2"
+ http-errors "2.0.0"
+ merge-descriptors "1.0.1"
+ methods "~1.1.2"
+ on-finished "2.4.1"
+ parseurl "~1.3.3"
+ path-to-regexp "0.1.7"
+ proxy-addr "~2.0.7"
+ qs "6.11.0"
+ range-parser "~1.2.1"
+ safe-buffer "5.2.1"
+ send "0.18.0"
+ serve-static "1.15.0"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ type-is "~1.6.18"
+ utils-merge "1.0.1"
+ vary "~1.1.2"
+
+finalhandler@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32"
+ integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==
+ dependencies:
+ debug "2.6.9"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ on-finished "2.4.1"
+ parseurl "~1.3.3"
+ statuses "2.0.1"
+ unpipe "~1.0.0"
+
+forwarded@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
+ integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
+
+fresh@0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+ integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
+
+fs-minipass@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
+ integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
+ dependencies:
+ minipass "^3.0.0"
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
+
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
+gauge@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395"
+ integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==
+ dependencies:
+ aproba "^1.0.3 || ^2.0.0"
+ color-support "^1.1.2"
+ console-control-strings "^1.0.0"
+ has-unicode "^2.0.1"
+ object-assign "^4.1.1"
+ signal-exit "^3.0.0"
+ string-width "^4.2.3"
+ strip-ansi "^6.0.1"
+ wide-align "^1.1.2"
+
+get-caller-file@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+ integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
+get-intrinsic@^1.0.2, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b"
+ integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==
+ dependencies:
+ function-bind "^1.1.2"
+ has-proto "^1.0.1"
+ has-symbols "^1.0.3"
+ hasown "^2.0.0"
+
+glob@^7.0.5, glob@^7.1.3:
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+ integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.1.1"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+gopd@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
+ integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
+ dependencies:
+ get-intrinsic "^1.1.3"
+
+grpc@^1.24.11:
+ version "1.24.11"
+ resolved "https://registry.yarnpkg.com/grpc/-/grpc-1.24.11.tgz#7039da9f6f22ce35168535a6d5dda618398a5966"
+ integrity sha512-8/AQdFCzCeCDWW3SoaMNp6ccbRvTQEH1O1u1uFtt29eWsg5gSZCJ3m6fbkduEIh3smY7WAPP+LgVJ5n3nZRxcA==
+ dependencies:
+ "@mapbox/node-pre-gyp" "^1.0.4"
+ "@types/bytebuffer" "^5.0.40"
+ lodash.camelcase "^4.3.0"
+ lodash.clone "^4.5.0"
+ nan "^2.13.2"
+ protobufjs "^5.0.3"
+
+has-property-descriptors@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340"
+ integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==
+ dependencies:
+ get-intrinsic "^1.2.2"
+
+has-proto@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0"
+ integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==
+
+has-symbols@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
+ integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+
+has-unicode@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+ integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==
+
+hasown@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c"
+ integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==
+ dependencies:
+ function-bind "^1.1.2"
+
+http-errors@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
+ integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
+ dependencies:
+ depd "2.0.0"
+ inherits "2.0.4"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ toidentifier "1.0.1"
+
+https-proxy-agent@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
+ integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
+ dependencies:
+ agent-base "6"
+ debug "4"
+
+iconv-lite@0.4.24:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2, inherits@2.0.4, inherits@^2.0.3:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+invert-kv@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+ integrity sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==
+
+ipaddr.js@1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
+ integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
+
+is-fullwidth-code-point@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+ integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==
+ dependencies:
+ number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
+lcid@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+ integrity sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==
+ dependencies:
+ invert-kv "^1.0.0"
+
+lodash.camelcase@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
+ integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
+
+lodash.chunk@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/lodash.chunk/-/lodash.chunk-4.2.0.tgz#66e5ce1f76ed27b4303d8c6512e8d1216e8106bc"
+ integrity sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==
+
+lodash.clone@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6"
+ integrity sha512-GhrVeweiTD6uTmmn5hV/lzgCQhccwReIVRLHp7LT4SopOjqEZ5BbX8b5WWEtAKasjmy8hR7ZPwsYlxRCku5odg==
+
+lodash.isequal@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+ integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
+
+long@^5.0.0:
+ version "5.2.3"
+ resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1"
+ integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==
+
+long@~3:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b"
+ integrity sha512-ZYvPPOMqUwPoDsbJaR10iQJYnMuZhRTvHYl62ErLIEX7RgFlziSBUUvrt3OVfc47QlHHpzPZYP17g3Fv7oeJkg==
+
+lru-cache@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+ integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+ dependencies:
+ yallist "^4.0.0"
+
+make-dir@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
+ integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
+ dependencies:
+ semver "^6.0.0"
+
+media-typer@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+ integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
+
+merge-descriptors@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
+ integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==
+
+methods@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+ integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
+
+mime-db@1.52.0:
+ version "1.52.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-types@~2.1.24, mime-types@~2.1.34:
+ version "2.1.35"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+ dependencies:
+ mime-db "1.52.0"
+
+mime@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+ integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+
+minimatch@^3.1.1:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minipass@^3.0.0:
+ version "3.3.6"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a"
+ integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==
+ dependencies:
+ yallist "^4.0.0"
+
+minipass@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d"
+ integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
+
+minizlib@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
+ integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
+ dependencies:
+ minipass "^3.0.0"
+ yallist "^4.0.0"
+
+mkdirp@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
+ integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
+
+ms@2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+ integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+ms@2.1.3:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+nan@^2.13.2:
+ version "2.18.0"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554"
+ integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==
+
+negotiator@0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
+ integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
+
+node-fetch@^2.6.7:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
+ integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
+ dependencies:
+ whatwg-url "^5.0.0"
+
+nopt@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
+ integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==
+ dependencies:
+ abbrev "1"
+
+npmlog@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0"
+ integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==
+ dependencies:
+ are-we-there-yet "^2.0.0"
+ console-control-strings "^1.1.0"
+ gauge "^3.0.0"
+ set-blocking "^2.0.0"
+
+number-is-nan@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+ integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==
+
+object-assign@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
+
+object-inspect@^1.9.0:
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
+ integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
+
+on-finished@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
+ integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
+ dependencies:
+ ee-first "1.1.1"
+
+once@^1.3.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+ dependencies:
+ wrappy "1"
+
+optjs@~3.2.2:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/optjs/-/optjs-3.2.2.tgz#69a6ce89c442a44403141ad2f9b370bd5bb6f4ee"
+ integrity sha512-f8lTJm4LKirX+45xsFhuRNjA4f46QVLQKfGoNH7e2AEWS+24eM4XNH4pQ8Tw2LISCIvbST/wNcLdtgvgcqVaxA==
+
+os-locale@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+ integrity sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==
+ dependencies:
+ lcid "^1.0.0"
+
+parseurl@~1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+ integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+
+path-to-regexp@0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
+ integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==
+
+protobufjs@^5.0.3:
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-5.0.3.tgz#e4dfe9fb67c90b2630d15868249bcc4961467a17"
+ integrity sha512-55Kcx1MhPZX0zTbVosMQEO5R6/rikNXd9b6RQK4KSPcrSIIwoXTtebIczUrXlwaSrbz4x8XUVThGPob1n8I4QA==
+ dependencies:
+ ascli "~1"
+ bytebuffer "~5"
+ glob "^7.0.5"
+ yargs "^3.10.0"
+
+protobufjs@^7.2.4:
+ version "7.2.5"
+ resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.5.tgz#45d5c57387a6d29a17aab6846dcc283f9b8e7f2d"
+ integrity sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==
+ dependencies:
+ "@protobufjs/aspromise" "^1.1.2"
+ "@protobufjs/base64" "^1.1.2"
+ "@protobufjs/codegen" "^2.0.4"
+ "@protobufjs/eventemitter" "^1.1.0"
+ "@protobufjs/fetch" "^1.1.0"
+ "@protobufjs/float" "^1.0.2"
+ "@protobufjs/inquire" "^1.1.0"
+ "@protobufjs/path" "^1.1.2"
+ "@protobufjs/pool" "^1.1.0"
+ "@protobufjs/utf8" "^1.1.0"
+ "@types/node" ">=13.7.0"
+ long "^5.0.0"
+
+proxy-addr@~2.0.7:
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
+ integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
+ dependencies:
+ forwarded "0.2.0"
+ ipaddr.js "1.9.1"
+
+qs@6.11.0:
+ version "6.11.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
+ integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
+ dependencies:
+ side-channel "^1.0.4"
+
+range-parser@~1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@2.5.1:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857"
+ integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==
+ dependencies:
+ bytes "3.1.2"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ unpipe "1.0.0"
+
+readable-stream@^3.6.0:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
+ integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
+ dependencies:
+ inherits "^2.0.3"
+ string_decoder "^1.1.1"
+ util-deprecate "^1.0.1"
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+ integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
+
+rimraf@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+ dependencies:
+ glob "^7.1.3"
+
+safe-buffer@5.2.1, safe-buffer@~5.2.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+"safer-buffer@>= 2.1.2 < 3":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+semver@^6.0.0:
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
+
+semver@^7.3.5:
+ version "7.5.4"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
+ dependencies:
+ lru-cache "^6.0.0"
+
+send@0.18.0:
+ version "0.18.0"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
+ integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==
+ dependencies:
+ debug "2.6.9"
+ depd "2.0.0"
+ destroy "1.2.0"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ fresh "0.5.2"
+ http-errors "2.0.0"
+ mime "1.6.0"
+ ms "2.1.3"
+ on-finished "2.4.1"
+ range-parser "~1.2.1"
+ statuses "2.0.1"
+
+serve-static@1.15.0:
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540"
+ integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==
+ dependencies:
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ parseurl "~1.3.3"
+ send "0.18.0"
+
+set-blocking@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+ integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==
+
+set-function-length@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed"
+ integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==
+ dependencies:
+ define-data-property "^1.1.1"
+ get-intrinsic "^1.2.1"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.0"
+
+setprototypeof@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
+ integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
+
+side-channel@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
+ integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
+ dependencies:
+ call-bind "^1.0.0"
+ get-intrinsic "^1.0.2"
+ object-inspect "^1.9.0"
+
+signal-exit@^3.0.0:
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
+ integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+
+statuses@2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
+ integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
+
+string-width@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+ integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==
+ dependencies:
+ code-point-at "^1.0.0"
+ is-fullwidth-code-point "^1.0.0"
+ strip-ansi "^3.0.0"
+
+"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+string_decoder@^1.1.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+ integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+ dependencies:
+ safe-buffer "~5.2.0"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+ integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==
+ dependencies:
+ ansi-regex "^2.0.0"
+
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
+tar@^6.1.11:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73"
+ integrity sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==
+ dependencies:
+ chownr "^2.0.0"
+ fs-minipass "^2.0.0"
+ minipass "^5.0.0"
+ minizlib "^2.1.1"
+ mkdirp "^1.0.3"
+ yallist "^4.0.0"
+
+toidentifier@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
+ integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
+
+tr46@~0.0.3:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+ integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
+
+type-is@~1.6.18:
+ version "1.6.18"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+ integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+ dependencies:
+ media-typer "0.3.0"
+ mime-types "~2.1.24"
+
+undici-types@~5.26.4:
+ version "5.26.5"
+ resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
+ integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
+
+unpipe@1.0.0, unpipe@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+ integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
+
+urbit-ob@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/urbit-ob/-/urbit-ob-5.0.1.tgz#4338580e883bcf80af91777890572f8e5001ceda"
+ integrity sha512-qGNAwu87XNkW3g8ah4fUwmh2EKXtsdhEbyEiE5qX4Op17rhLH3HSkvu8g9z+MhqX51Uz9sf8ktvqJj/IRwETIQ==
+ dependencies:
+ bn.js "^4.11.8"
+ lodash.chunk "^4.2.0"
+ lodash.isequal "^4.5.0"
+
+util-deprecate@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+
+utils-merge@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+ integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
+
+vary@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+ integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
+
+webidl-conversions@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+ integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
+
+whatwg-url@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
+ integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
+ dependencies:
+ tr46 "~0.0.3"
+ webidl-conversions "^3.0.0"
+
+wide-align@^1.1.2:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3"
+ integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==
+ dependencies:
+ string-width "^1.0.2 || 2 || 3 || 4"
+
+window-size@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876"
+ integrity sha512-2thx4pB0cV3h+Bw7QmMXcEbdmOzv9t0HFplJH/Lz6yu60hXYy5RT8rUu+wlIreVxWsGN20mo+MHeCSfUpQBwPw==
+
+wrap-ansi@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+ integrity sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==
+ dependencies:
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+
+wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+y18n@^3.2.0:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696"
+ integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==
+
+y18n@^5.0.5:
+ version "5.0.8"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+ integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
+yallist@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+ integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
+yargs-parser@^21.1.1:
+ version "21.1.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
+ integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
+
+yargs@^17.7.2:
+ version "17.7.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
+ integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
+ dependencies:
+ cliui "^8.0.1"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.3"
+ y18n "^5.0.5"
+ yargs-parser "^21.1.1"
+
+yargs@^3.10.0:
+ version "3.32.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995"
+ integrity sha512-ONJZiimStfZzhKamYvR/xvmgW3uEkAUFSP91y2caTEPhzF6uP2JfPiVZcq66b/YR0C3uitxSV7+T1x8p5bkmMg==
+ dependencies:
+ camelcase "^2.0.1"
+ cliui "^3.0.3"
+ decamelize "^1.1.1"
+ os-locale "^1.4.0"
+ string-width "^1.0.1"
+ window-size "^0.1.4"
+ y18n "^3.2.0"