diff --git a/ui/package.json b/ui/package.json index 3e86e45..44e8d0b 100644 --- a/ui/package.json +++ b/ui/package.json @@ -49,6 +49,8 @@ "regenerator-runtime": "0.13.7" }, "devDependencies": { + "@agoric/notifier": "^0.3.32", + "@agoric/wallet-connection": "^0.1.2", "agoric": "*", "caniuse-lite": "1.0.30001251", "eslint": "^7.23.0", @@ -60,6 +62,7 @@ "eslint-plugin-prettier": "^3.1.4", "eslint-plugin-react": "^7.21.4", "eslint-plugin-react-hooks": "^4.1.2", + "lit": "^2.0.2", "prettier": "^2.1.2", "rimraf": "^3.0.2", "ses": "^0.14.2" diff --git a/ui/public/conf/defaults.js b/ui/public/conf/defaults.js index c6be2d5..b1ee3da 100644 --- a/ui/public/conf/defaults.js +++ b/ui/public/conf/defaults.js @@ -1,13 +1,13 @@ -// GENERATED FROM /Users/katesills/code/dapp-fungible-faucet/api/deploy.js +// GENERATED FROM /home/samsiegart/dapp-fungible-faucet/api/deploy.js export default { - INSTANCE_BOARD_ID: '794977354', - INSTALLATION_BOARD_ID: '1530295560', - INVITE_BRAND_BOARD_ID: '500716545', + INSTANCE_BOARD_ID: '379944443', + INSTALLATION_BOARD_ID: '1221243446', + INVITE_BRAND_BOARD_ID: '1265655452', brandBoardIds: { - Token: '529406044', + Token: '1530295560', }, issuerBoardIds: { - Token: '715805464', + Token: '794977354', }, BRIDGE_URL: 'http://127.0.0.1:8000', API_URL: 'http://127.0.0.1:8000', diff --git a/ui/public/conf/installationConstants.js b/ui/public/conf/installationConstants.js index b23f2af..25506ec 100644 --- a/ui/public/conf/installationConstants.js +++ b/ui/public/conf/installationConstants.js @@ -1,5 +1,5 @@ -// GENERATED FROM /Users/katesills/code/dapp-fungible-faucet/contract/deploy.js +// GENERATED FROM /home/samsiegart/dapp-fungible-faucet/contract/deploy.js export default { CONTRACT_NAME: 'fungibleFaucet', - INSTALLATION_BOARD_ID: '1530295560', + INSTALLATION_BOARD_ID: '1221243446', }; diff --git a/ui/public/index.html b/ui/public/index.html index 3bc3811..aa15033 100644 --- a/ui/public/index.html +++ b/ui/public/index.html @@ -8,22 +8,29 @@ - - - + + +
-
- Fungible Token Faucet
-
- - power_settings_new - +
+ Fungible Token Faucet +
+
+ power_settings_new
Agoric wallet: Unknown
@@ -34,73 +41,100 @@
- +
-
-
-
- -
-
-
- -
+
+
+
+
+
+
-

Fungible Faucet

+

+ Fungible Faucet +

+
+
+ Mint 1000 fungible tokens and send them to your wallet.
-
Mint 1000 fungible tokens and - send them to your wallet.
+
- -
-
-

Fungible Token Faucet

-
Instructions
-
-

First, please enable this dapp in your wallet. To open your - wallet, enter `agoric open` in your terminal.

- -

Then click on the button below to mint fungible tokens and send - the resulting payment to your wallet.

+
+

Fungible Token Faucet

+
Instructions
+
+

+ First, please enable this dapp in your wallet. To open your + wallet, enter `agoric open` in your terminal. +

+ +

+ Then click on the button below to mint fungible tokens and send + the resulting payment to your wallet. +

+
+
+ + +
-
- - -
-
-
-
-
-
-
-
-
- +
+
+
+
+
+
+
+ +
+ +
- -
-
- - -
-
+
Please approve the offer in your wallet to receive the payment.
@@ -108,36 +142,38 @@

Fungible Token Faucet

-
- You just got 1000 more tokens! Check your token purse in - your wallet to see the current balance. +
+ You just got 1000 more tokens! Check your token purse in your wallet + to see the current balance.
-
-
- Enable the Fungible Faucet Dapp -
+ aria-describedby="my-dialog-content" + > +
Enable the Fungible Faucet Dapp
Before using the dapp, you must enable it. To enable the dapp, - please open your wallet by using the agoric - open + please open your wallet by using the + agoric open command in your terminal. Then, under "Dapps", enable FungibleFaucet. - - +
- @@ -147,10 +183,9 @@

Fungible Token Faucet

+ + - - - - + diff --git a/ui/public/lib/agoric-wallet.html b/ui/public/lib/agoric-wallet.html deleted file mode 100644 index ed60569..0000000 --- a/ui/public/lib/agoric-wallet.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - Connect to Agoric bridge - - - - - - - diff --git a/ui/public/lib/api-client.js b/ui/public/lib/api-client.js index 2f8f266..c832b54 100644 --- a/ui/public/lib/api-client.js +++ b/ui/public/lib/api-client.js @@ -1,6 +1,5 @@ // @ts-check /* globals window, WebSocket */ - import { registerSocket, closeSocket, getActiveSocket } from './socket.js'; import dappConstants from './constants.js'; diff --git a/ui/public/lib/wallet-client.js b/ui/public/lib/wallet-client.js deleted file mode 100644 index 34d0871..0000000 --- a/ui/public/lib/wallet-client.js +++ /dev/null @@ -1,145 +0,0 @@ -// @ts-check -/* globals window document */ - -import { registerSocket, getActiveSocket, closeSocket } from './socket.js'; - -// Wallet bridge - -/** - * @typedef {Object} SocketHandler - * @property {() => void} [onConnect] - * @property {(msg: Record) => void} [onMessage] - * @property {() => void} [onDisconnect] - */ - -const walletBridgeId = 'walletBridgeIFrame'; -let walletLoaded = false; -const connectSubscriptions = new Set(); -const messageSubscriptions = new Set(); -let initializedIframe = false; - -/** - * Make a new wallet bridge "socket", via postMessage to an iframe. - * - * @param {SocketHandler} handler - * @param {string} endpoint - */ -function createSocket( - { onConnect, onDisconnect, onMessage }, - endpoint = '/private/wallet-bridge', -) { - let ifr = /** @type {HTMLIFrameElement} */ (document.getElementById( - walletBridgeId, - )); - if (!ifr) { - ifr = document.querySelector(`#${walletBridgeId}`); - } - if (!initializedIframe) { - initializedIframe = true; - window.addEventListener('message', (ev) => { - // console.log('dapp ui got', ev); - if (ev.data && ev.data.type === 'walletBridgeLoaded') { - walletLoaded = true; - for (const sub of connectSubscriptions.keys()) { - sub(); - } - connectSubscriptions.clear(); - } else { - const obj = ev.data; - for (const sub of messageSubscriptions.keys()) { - sub(obj); - } - } - }); - } - - let ifrQueue = []; - const flushQueue = () => { - const q = ifrQueue; - ifrQueue = undefined; - ifr.removeEventListener('load', flushQueue); - while (q.length) { - const obj = q.shift(); - ifr.contentWindow.postMessage(obj, window.origin); - } - }; - ifr.addEventListener('load', flushQueue); - - // FIXME: Don't assume our location. - const queryPos = endpoint.indexOf('?'); - if (queryPos >= 0) { - ifr.src = `lib/agoric-wallet.html${endpoint.substr(queryPos)}`; - } else { - ifr.src = 'lib/agoric-wallet.html'; - } - if (onMessage) { - messageSubscriptions.add(onMessage); - } - const messageListeners = new Set(); - registerSocket(endpoint, { - send(obj) { - if (ifrQueue) { - ifrQueue.push(obj); - } else { - ifr.contentWindow.postMessage(obj, window.origin); - } - }, - addHandler(handler) { - messageListeners.add(handler); - messageSubscriptions.add(handler); - }, - removeHandler(handler) { - messageSubscriptions.delete(handler); - messageListeners.delete(handler); - }, - close() { - walletLoaded = false; - if (onConnect) { - connectSubscriptions.delete(onConnect); - } - if (onMessage) { - messageSubscriptions.delete(onMessage); - } - for (const sub of messageListeners.keys()) { - messageSubscriptions.delete(sub); - } - ifr = /** @type {HTMLIFrameElement} */ (document.getElementById( - walletBridgeId, - )); - if (ifr) { - ifr.src = ''; - } - - if (onDisconnect) { - onDisconnect(); - } - }, - }); - - if (onConnect) { - if (walletLoaded) { - onConnect(); - } else { - connectSubscriptions.add(onConnect); - } - } -} - -/** - * Start a given socket connection. - * - * @param {SocketHandler} socketListeners - * @param {*} endpoint - */ -export function activateSocket( - socketListeners = {}, - endpoint = '/private/wallet-bridge', -) { - if (getActiveSocket(endpoint)) return; - createSocket(socketListeners, endpoint); -} - -export function deactivateSocket(endpoint = '/private/wallet-bridge') { - if (!getActiveSocket(endpoint)) return; - closeSocket(endpoint); -} diff --git a/ui/public/src/connect.js b/ui/public/src/connect.js index 5763084..886f0da 100644 --- a/ui/public/src/connect.js +++ b/ui/public/src/connect.js @@ -2,7 +2,6 @@ /* globals document */ import { rpc } from '../lib/socket.js'; import { activateSocket as startApi } from '../lib/api-client.js'; -import { activateSocket as startBridge } from '../lib/wallet-client.js'; const $messages = /** @type {HTMLDivElement} */ (document.getElementById( `messages`, @@ -85,7 +84,7 @@ export const connect = (endpointPath, recv, query = '') => { resolve = res; reject = rej; }); - const activator = endpointPath === 'wallet' ? startBridge : startApi; + const activator = startApi; activator( { onConnect() { diff --git a/ui/public/src/main.js b/ui/public/src/main.js index a0ea109..19b2a11 100644 --- a/ui/public/src/main.js +++ b/ui/public/src/main.js @@ -1,8 +1,12 @@ +/* eslint-disable import/no-extraneous-dependencies */ // @ts-check /* globals document mdc */ import './install-ses-lockdown.js'; +import { E } from '@agoric/eventual-send'; +import { observeNotifier } from '@agoric/notifier'; import dappConstants from '../lib/constants.js'; import { connect } from './connect.js'; +import '@agoric/wallet-connection/agoric-wallet-connection.js'; const { INVITE_BRAND_BOARD_ID, @@ -16,11 +20,17 @@ export default async function main() { let zoeInvitationDepositFacetId; let apiSend; let tokenPursePetname = ['FungibleFaucet', 'Token']; + let walletP; + const offers = new Set(); const $mintFungible = /** @type {HTMLInputElement} */ (document.getElementById( 'mintFungible', )); + const $walletStatus = /** @type {HTMLInputElement} */ (document.getElementById( + 'wallet-status', + )); + const maybeEnableButtons = () => { if (!apiSend || !zoeInvitationDepositFacetId) { return; @@ -57,8 +67,7 @@ export default async function main() { document.querySelector('#approve-offer'), ); - // The snackbar to approve the offer will be closed by code not timeout. - approveOfferSB.timeoutMs = -1; + approveOfferSB.timeoutMs = 4000; const gotPaymentSB = mdc.snackbar.MDCSnackbar.attachTo( document.querySelector('#got-payment'), @@ -68,72 +77,89 @@ export default async function main() { document.querySelector('#open-wallet'), ); - // eslint-disable-next-line no-unused-vars - const debugSwitch = new mdc.switchControl.MDCSwitch( - document.querySelector('.mdc-switch'), - ); + const addOffer = async (offer) => { + const offerId = await E(walletP).addOffer(offer); + approveOfferSB.open(); + offers.add(offerId); + }; - /** - * @param {{ type: string; data: any; walletURL: string }} obj - */ - const walletRecv = (obj) => { - switch (obj.type) { - case 'walletDepositFacetIdResponse': { - zoeInvitationDepositFacetId = obj.data; - maybeEnableButtons(); - break; - } - case 'walletNeedDappApproval': { - approveDappDialog.open(); - break; - } - case 'walletURL': { - // TODO: handle appropriately - break; - } - case 'walletUpdatePurses': { - // We find the first purse that can accept our token. - const purses = JSON.parse(obj.data); - const tokenPurse = purses.find( - // Does the purse's brand match our token brand? - ({ brandBoardId }) => brandBoardId === TOKEN_BRAND_BOARD_ID, - ); - if (tokenPurse && tokenPurse.pursePetname) { - // If we got a petname for that purse, use it in the offers we create. - tokenPursePetname = tokenPurse.pursePetname; - } - break; - } - case 'walletSuggestIssuerResponse': { - // TODO: handle appropriately - break; - } - case 'walletSuggestInstallationResponse': { - // TODO: handle appropriately - break; - } - case 'walletSuggestInstanceResponse': { - // TODO: handle appropriately - break; + // Gets the petname for the token purse that holds our token brand for use in offers. + const updateTokenPursePetname = (purses) => { + const tokenPurse = purses.find( + // Does the purse's brand match our token brand? + ({ brandBoardId }) => brandBoardId === TOKEN_BRAND_BOARD_ID, + ); + if (tokenPurse && tokenPurse.pursePetname) { + // If we got a petname for that purse, use it in the offers we create. + tokenPursePetname = tokenPurse.pursePetname; + } + }; + + const getDepositFacetId = async () => { + zoeInvitationDepositFacetId = await E(walletP).getDepositFacetId( + INVITE_BRAND_BOARD_ID, + ); + maybeEnableButtons(); + }; + + const updateOfferSnackbars = (walletOffers) => { + for (const offerId of offers) { + const walletOffer = walletOffers.find((offer) => offer.id === offerId); + + if (walletOffer && walletOffer.status === 'accept') { + gotPaymentSB.open(); + offers.delete(offerId); } - case 'walletOfferAdded': { - approveOfferSB.open(); + } + }; + + const setWalletP = (bridge) => { + if (walletP) { + return; + } + walletP = bridge; + + observeNotifier(E(walletP).getPursesNotifier(), { + updateState: updateTokenPursePetname, + }); + + observeNotifier(E(walletP).getOffersNotifier(), { + updateState: updateOfferSnackbars, + }); + + getDepositFacetId(); + + E(walletP).suggestInstallation('Installation', INSTALLATION_BOARD_ID); + E(walletP).suggestInstance('Instance', INSTANCE_BOARD_ID); + E(walletP).suggestIssuer('Token', TOKEN_ISSUER_BOARD_ID); + }; + + const onWalletState = (ev) => { + const { walletConnection, state } = ev.detail; + $walletStatus.innerText = state; + switch (state) { + case 'idle': { + setWalletP(E(walletConnection).getScopedBridge('FungibleFaucet')); break; } - case 'walletOfferHandled': { - approveOfferSB.close(); + case 'approving': { + approveDappDialog.open(); break; } - case 'walletOfferResult': { - gotPaymentSB.open(); + case 'error': { + console.log('error', ev.detail); + // In case of an error, reset to 'idle'. + // Backoff or other retry strategies would go here instead of immediate reset. + E(walletConnection).reset(); break; } - default: { - throw Error(`unexpected walletRecv obj.type ${obj.type}`); - } + default: } }; + const awc = document.querySelector('agoric-wallet-connection'); + awc.addEventListener('state', onWalletState); + /** * @param {{ type: string; data: any; }} obj */ @@ -146,10 +172,7 @@ export default async function main() { // acceptance/rejection. const { offer } = obj.data; // eslint-disable-next-line no-use-before-define - walletSend({ - type: 'walletAddOffer', - data: offer, - }); + addOffer(offer); break; } case 'CTP_DISCONNECT': { @@ -162,38 +185,6 @@ export default async function main() { } }; - // All the "suggest" messages below are backward-compatible: - // the new wallet will confirm them with the user, but the old - // wallet will just ignore the messages and allow access immediately. - const walletSend = await connect( - 'wallet', - walletRecv, - '?suggestedDappPetname=FungibleFaucet', - // eslint-disable-next-line no-shadow - ).then((walletSend) => { - walletSend({ type: 'walletGetPurses' }); - walletSend({ - type: 'walletGetDepositFacetId', - brandBoardId: INVITE_BRAND_BOARD_ID, - }); - walletSend({ - type: 'walletSuggestInstallation', - petname: 'Installation', - boardId: INSTALLATION_BOARD_ID, - }); - walletSend({ - type: 'walletSuggestInstance', - petname: 'Instance', - boardId: INSTANCE_BOARD_ID, - }); - walletSend({ - type: 'walletSuggestIssuer', - petname: 'Token', - boardId: TOKEN_ISSUER_BOARD_ID, - }); - return walletSend; - }); - await connect('/api/fungible-faucet', apiRecv).then((rawApiSend) => { apiSend = rawApiSend; maybeEnableButtons(); diff --git a/yarn.lock b/yarn.lock index 72eb2ca..11f969c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24,6 +24,11 @@ dependencies: ses "^0.14.1" +"@agoric/assert@^0.3.15": + version "0.3.15" + resolved "https://registry.yarnpkg.com/@agoric/assert/-/assert-0.3.15.tgz#149d120790b76bb79ca9a02f265d8e7a8a904a87" + integrity sha512-6Kb0mtRoAd3O3VwnEXnGpy+ldqD+nB4OSZdgfKZkGn+apN9nLQP4OStEZKeG+jWsgBIzpNE61LrXv6HnBMCX+Q== + "@agoric/babel-parser@^7.6.4": version "7.9.4" resolved "https://registry.yarnpkg.com/@agoric/babel-parser/-/babel-parser-7.9.4.tgz#2f9fd67f75a4a00bd1853e9d625bcc8ed479a564" @@ -71,6 +76,17 @@ rollup "^1.32.0" source-map "^0.7.3" +"@agoric/captp@^1.10.7": + version "1.10.7" + resolved "https://registry.yarnpkg.com/@agoric/captp/-/captp-1.10.7.tgz#ec55ba550f21886fcf9a1eeb6abebecbdedf6dfc" + integrity sha512-fJirXSIR+OOp97wpaJ6LXS/E5mmFSoQypPQeKdYdERV8wQsY7bSjDMa2mfbqVKNDZ+txAzVvVXieASYet+GaUg== + dependencies: + "@agoric/assert" "^0.3.15" + "@agoric/eventual-send" "^0.14.0" + "@agoric/marshal" "^0.5.0" + "@agoric/nat" "^4.1.0" + "@agoric/promise-kit" "^0.2.29" + "@agoric/captp@^1.5.1": version "1.5.1" resolved "https://registry.yarnpkg.com/@agoric/captp/-/captp-1.5.1.tgz#ae9853e2352c0a46c9ff3ed8096665d5419225b1" @@ -173,6 +189,11 @@ resolved "https://registry.yarnpkg.com/@agoric/eventual-send/-/eventual-send-0.13.27.tgz#9b917e6663ac84783b07bc0f03bdecd2b024870d" integrity sha512-6m/H1SaRJxVzEH/1vW/DAHDjjg1ZgdeEVSIx5gT54/jcyvbaZSdT75WEqTx1GAaTAyH62qLUiCmTyvZX7GA1LA== +"@agoric/eventual-send@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@agoric/eventual-send/-/eventual-send-0.14.0.tgz#72412cc5d84dcac78077f92a43d5bd58401e3938" + integrity sha512-3AqRLLftV+YVYtPyQ2JV/ulK8RRRrYJNyK1R34jNUGMnlfokTjIf5iEQO+YAUof5xycwlmyqd9BZd8BEDOq2sg== + "@agoric/import-bundle@^0.0.11": version "0.0.11" resolved "https://registry.yarnpkg.com/@agoric/import-bundle/-/import-bundle-0.0.11.tgz#edc9bb20de3202f0bfde9acc687865701f44c8a9" @@ -232,6 +253,16 @@ "@agoric/nat" "^2.0.1" "@agoric/promise-kit" "^0.1.6" +"@agoric/marshal@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@agoric/marshal/-/marshal-0.5.0.tgz#f3beb3d53b99c0198cd8df4b5cd97a4ba2c468c3" + integrity sha512-NAl7RMkElWJBtgFkD3aAkQRpGedatns2OWbBMgDXV2iVWSpxJPf1s1Ufcr5enJLKjpRlGzXGewCN4Q+BkWp1FA== + dependencies: + "@agoric/assert" "^0.3.15" + "@agoric/eventual-send" "^0.14.0" + "@agoric/nat" "^4.1.0" + "@agoric/promise-kit" "^0.2.29" + "@agoric/nat@2.0.1", "@agoric/nat@^2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@agoric/nat/-/nat-2.0.1.tgz#28aba18367deba354bdd424bdf6daa48f5e7d37f" @@ -251,6 +282,16 @@ "@agoric/eventual-send" "^0.11.1" "@agoric/promise-kit" "^0.1.6" +"@agoric/notifier@^0.3.32": + version "0.3.32" + resolved "https://registry.yarnpkg.com/@agoric/notifier/-/notifier-0.3.32.tgz#62be82f43564ec3ab986e6ea1c7d2021adbb5d51" + integrity sha512-Z/1Azmis9V7pxSlMBCuJE7fXA0zXLc30S0tkJShp9WpyX0wZduLh6eeBqF1HS1JwE793BawIY1nvRNvGpJkr8Q== + dependencies: + "@agoric/assert" "^0.3.15" + "@agoric/eventual-send" "^0.14.0" + "@agoric/marshal" "^0.5.0" + "@agoric/promise-kit" "^0.2.29" + "@agoric/promise-kit@^0.1.6": version "0.1.6" resolved "https://registry.yarnpkg.com/@agoric/promise-kit/-/promise-kit-0.1.6.tgz#183121a0f6d399422f761e61e26d25b1cb0fd0ff" @@ -265,6 +306,13 @@ dependencies: "@agoric/eventual-send" "^0.13.27" +"@agoric/promise-kit@^0.2.29": + version "0.2.29" + resolved "https://registry.yarnpkg.com/@agoric/promise-kit/-/promise-kit-0.2.29.tgz#fcbbf68835808e613bf356b38ea21421eb309701" + integrity sha512-DjHYcXDfmw5Vq6WhhgLVtli43W+OhfqN6n9FwYl3q7jayuh34YI5WJznyZnMxT6esRBpPO+JMDXb96thgXS0KA== + dependencies: + "@agoric/eventual-send" "^0.14.0" + "@agoric/registrar@^0.1.6": version "0.1.6" resolved "https://registry.yarnpkg.com/@agoric/registrar/-/registrar-0.1.6.tgz#8886ce198fa60ccabf28f8459df9ec6a4d6b21e2" @@ -391,6 +439,17 @@ resolved "https://registry.yarnpkg.com/@agoric/transform-module/-/transform-module-0.4.1.tgz#9fb152364faf372e1bda535cb4ef89717724f57c" integrity sha512-4TJJHXeXAWu1FCA7yXCAZmhBNoGTB/BEAe2pv+J2X8W/mJTr9b395OkDCSRMpzvmSshLfBx6wT0D7dqWIWEC1w== +"@agoric/wallet-connection@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@agoric/wallet-connection/-/wallet-connection-0.1.2.tgz#b306eea3a9af460b26cc9ec314a5d11e46af1d8d" + integrity sha512-jxserbswPmv7YYnHdeIdemlR44pA1SsqVkdOKVGkINF+GWWmqDSoWtfKmHkdc3DQ/avcjQWUq91lha7GVYClcA== + dependencies: + "@agoric/assert" "^0.3.15" + "@agoric/captp" "^1.10.7" + "@agoric/marshal" "^0.5.0" + "@agoric/promise-kit" "^0.2.29" + robot3 "^0.2.19" + "@agoric/xs-vat-worker@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@agoric/xs-vat-worker/-/xs-vat-worker-0.2.3.tgz#a8e02ca6983c5b381abe588d6d040796020d270b" @@ -1362,6 +1421,11 @@ dependencies: requireindex "~1.1.0" +"@lit/reactive-element@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-1.0.2.tgz#daa7a7c7a6c63d735f0c9634de6b7dbd70a702ab" + integrity sha512-oz3d3MKjQ2tXynQgyaQaMpGTDNyNDeBdo6dXf1AbjTwhA1IRINHmA7kSaVYv9ttKweNkEoNqp9DqteDdgWzPEg== + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -1530,6 +1594,11 @@ dependencies: "@types/node" "*" +"@types/trusted-types@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756" + integrity sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg== + abab@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" @@ -5330,6 +5399,30 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= +lit-element@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-3.0.2.tgz#6422b68ba166a32695f524d6f3eb41712610bf50" + integrity sha512-9vTJ47D2DSE4Jwhle7aMzEwO2ZcOPRikqfT3CVG7Qol2c9/I4KZwinZNW5Xv8hNm+G/enSSfIwqQhIXi6ioAUg== + dependencies: + "@lit/reactive-element" "^1.0.0" + lit-html "^2.0.0" + +lit-html@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-2.0.2.tgz#6a17caac4135757710c5fb3e4becc622c476e431" + integrity sha512-dON7Zg8btb14/fWohQLQBdSgkoiQA4mIUy87evmyJHtxRq7zS6LlC32bT5EPWiof5PUQaDpF45v2OlrxHA5Clg== + dependencies: + "@types/trusted-types" "^2.0.2" + +lit@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lit/-/lit-2.0.2.tgz#5e6f422924e0732258629fb379556b6d23f7179c" + integrity sha512-hKA/1YaSB+P+DvKWuR2q1Xzy/iayhNrJ3aveD0OQ9CKn6wUjsdnF/7LavDOJsKP/K5jzW/kXsuduPgRvTFrFJw== + dependencies: + "@lit/reactive-element" "^1.0.0" + lit-element "^3.0.0" + lit-html "^2.0.0" + load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" @@ -7441,6 +7534,11 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +robot3@^0.2.19: + version "0.2.21" + resolved "https://registry.yarnpkg.com/robot3/-/robot3-0.2.21.tgz#f65a341e66dc674648851fa8261c6c40eddb853c" + integrity sha512-nfUKTrBunRORgP42ovwwJ0MFkkN4V4Cw53zGJvihhWRCm9c5HzgBNh3qZz0UDVBd9WrOj4mEbovkqMkoOwtv1Q== + rollup-plugin-node-resolve@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz#730f93d10ed202473b1fb54a5997a7db8c6d8523"