cache with service worker

This commit is contained in:
Paul Miller
2023-11-17 17:16:30 -06:00
parent f1e80cc475
commit 43faf46eb7
7 changed files with 171 additions and 137 deletions

View File

@@ -2,6 +2,7 @@ import { ManifestOptions } from "vite-plugin-pwa";
const manifest: Partial<ManifestOptions> = {
name: "Mutiny Wallet",
orientation: "portrait",
short_name: "Mutiny",
description: "A lightning wallet",
theme_color: "#000",
@@ -489,7 +490,7 @@ const manifest: Partial<ManifestOptions> = {
src: "/images/send.png",
sizes: "192x192",
type: "image/png"
},
}
]
},
{
@@ -501,7 +502,7 @@ const manifest: Partial<ManifestOptions> = {
src: "/images/receive.png",
sizes: "192x192",
type: "image/png"
},
}
]
},
{
@@ -513,7 +514,7 @@ const manifest: Partial<ManifestOptions> = {
src: "/images/activity.png",
sizes: "192x192",
type: "image/png"
},
}
]
}
]

View File

@@ -34,10 +34,10 @@
"tailwindcss": "^3.3.5",
"typescript": "^5.2.2",
"vite": "^4.5.0",
"vite-plugin-pwa": "^0.14.7",
"vite-plugin-pwa": "^0.16.7",
"vite-plugin-solid": "^2.7.0",
"vite-plugin-wasm": "^3.2.2",
"workbox-window": "^6.6.0"
"workbox-window": "^7.0.0"
},
"dependencies": {
"@capacitor-mlkit/barcode-scanning": "^5.3.0",

184
pnpm-lock.yaml generated
View File

@@ -154,8 +154,8 @@ importers:
specifier: ^4.5.0
version: 4.5.0(@types/node@20.8.10)
vite-plugin-pwa:
specifier: ^0.14.7
version: 0.14.7(vite@4.5.0)(workbox-build@6.6.0)(workbox-window@6.6.0)
specifier: ^0.16.7
version: 0.16.7(vite@4.5.0)(workbox-build@7.0.0)(workbox-window@7.0.0)
vite-plugin-solid:
specifier: ^2.7.0
version: 2.7.0(solid-js@1.8.5)(vite@4.5.0)
@@ -163,8 +163,8 @@ importers:
specifier: ^3.2.2
version: 3.2.2(vite@4.5.0)
workbox-window:
specifier: ^6.6.0
version: 6.6.0
specifier: ^7.0.0
version: 7.0.0
packages/ui:
dependencies:
@@ -3283,20 +3283,6 @@ packages:
rollup: 2.79.1
dev: true
/@rollup/plugin-replace@5.0.2(rollup@3.28.0):
resolution: {integrity: sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0||^3.0.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
'@rollup/pluginutils': 5.0.3(rollup@3.28.0)
magic-string: 0.27.0
rollup: 3.28.0
dev: true
/@rollup/plugin-terser@0.1.0(rollup@3.28.0):
resolution: {integrity: sha512-N2KK+qUfHX2hBzVzM41UWGLrEmcjVC37spC8R3c9mt3oEDFKh3N2e12/lLp9aVSt86veR0TQiCNQXrm8C6aiUQ==}
engines: {node: '>=14.0.0'}
@@ -13276,21 +13262,20 @@ packages:
- rollup
- supports-color
/vite-plugin-pwa@0.14.7(vite@4.5.0)(workbox-build@6.6.0)(workbox-window@6.6.0):
resolution: {integrity: sha512-dNJaf0fYOWncmjxv9HiSa2xrSjipjff7IkYE5oIUJ2x5HKu3cXgA8LRgzOwTc5MhwyFYRSU0xyN0Phbx3NsQYw==}
/vite-plugin-pwa@0.16.7(vite@4.5.0)(workbox-build@7.0.0)(workbox-window@7.0.0):
resolution: {integrity: sha512-4WMA5unuKlHs+koNoykeuCfTcqEGbiTRr8sVYUQMhc6tWxZpSRnv9Ojk4LKmqVhoPGHfBVCdGaMo8t9Qidkc1Q==}
engines: {node: '>=16.0.0'}
peerDependencies:
vite: ^3.1.0 || ^4.0.0
workbox-build: ^6.5.4
workbox-window: ^6.5.4
vite: ^3.1.0 || ^4.0.0 || ^5.0.0-0
workbox-build: ^7.0.0
workbox-window: ^7.0.0
dependencies:
'@rollup/plugin-replace': 5.0.2(rollup@3.28.0)
debug: 4.3.4
fast-glob: 3.3.1
pretty-bytes: 6.1.1
rollup: 3.28.0
vite: 4.5.0(@types/node@20.8.10)
workbox-build: 6.6.0
workbox-window: 6.6.0
workbox-build: 7.0.0
workbox-window: 7.0.0
transitivePeerDependencies:
- supports-color
dev: true
@@ -13618,22 +13603,22 @@ packages:
resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
dev: true
/workbox-background-sync@6.6.0:
resolution: {integrity: sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==}
/workbox-background-sync@7.0.0:
resolution: {integrity: sha512-S+m1+84gjdueM+jIKZ+I0Lx0BDHkk5Nu6a3kTVxP4fdj3gKouRNmhO8H290ybnJTOPfBDtTMXSQA/QLTvr7PeA==}
dependencies:
idb: 7.1.1
workbox-core: 6.6.0
workbox-core: 7.0.0
dev: true
/workbox-broadcast-update@6.6.0:
resolution: {integrity: sha512-nm+v6QmrIFaB/yokJmQ/93qIJ7n72NICxIwQwe5xsZiV2aI93MGGyEyzOzDPVz5THEr5rC3FJSsO3346cId64Q==}
/workbox-broadcast-update@7.0.0:
resolution: {integrity: sha512-oUuh4jzZrLySOo0tC0WoKiSg90bVAcnE98uW7F8GFiSOXnhogfNDGZelPJa+6KpGBO5+Qelv04Hqx2UD+BJqNQ==}
dependencies:
workbox-core: 6.6.0
workbox-core: 7.0.0
dev: true
/workbox-build@6.6.0:
resolution: {integrity: sha512-Tjf+gBwOTuGyZwMz2Nk/B13Fuyeo0Q84W++bebbVsfr9iLkDSo6j6PST8tET9HYA58mlRXwlMGpyWO8ETJiXdQ==}
engines: {node: '>=10.0.0'}
/workbox-build@7.0.0:
resolution: {integrity: sha512-CttE7WCYW9sZC+nUYhQg3WzzGPr4IHmrPnjKiu3AMXsiNQKx+l4hHl63WTrnicLmKEKHScWDH8xsGBdrYgtBzg==}
engines: {node: '>=16.0.0'}
dependencies:
'@apideck/better-ajv-errors': 0.3.6(ajv@8.12.0)
'@babel/core': 7.22.10
@@ -13657,112 +13642,111 @@ packages:
strip-comments: 2.0.1
tempy: 0.6.0
upath: 1.2.0
workbox-background-sync: 6.6.0
workbox-broadcast-update: 6.6.0
workbox-cacheable-response: 6.6.0
workbox-core: 6.6.0
workbox-expiration: 6.6.0
workbox-google-analytics: 6.6.0
workbox-navigation-preload: 6.6.0
workbox-precaching: 6.6.0
workbox-range-requests: 6.6.0
workbox-recipes: 6.6.0
workbox-routing: 6.6.0
workbox-strategies: 6.6.0
workbox-streams: 6.6.0
workbox-sw: 6.6.0
workbox-window: 6.6.0
workbox-background-sync: 7.0.0
workbox-broadcast-update: 7.0.0
workbox-cacheable-response: 7.0.0
workbox-core: 7.0.0
workbox-expiration: 7.0.0
workbox-google-analytics: 7.0.0
workbox-navigation-preload: 7.0.0
workbox-precaching: 7.0.0
workbox-range-requests: 7.0.0
workbox-recipes: 7.0.0
workbox-routing: 7.0.0
workbox-strategies: 7.0.0
workbox-streams: 7.0.0
workbox-sw: 7.0.0
workbox-window: 7.0.0
transitivePeerDependencies:
- '@types/babel__core'
- supports-color
dev: true
/workbox-cacheable-response@6.6.0:
resolution: {integrity: sha512-JfhJUSQDwsF1Xv3EV1vWzSsCOZn4mQ38bWEBR3LdvOxSPgB65gAM6cS2CX8rkkKHRgiLrN7Wxoyu+TuH67kHrw==}
deprecated: workbox-background-sync@6.6.0
/workbox-cacheable-response@7.0.0:
resolution: {integrity: sha512-0lrtyGHn/LH8kKAJVOQfSu3/80WDc9Ma8ng0p2i/5HuUndGttH+mGMSvOskjOdFImLs2XZIimErp7tSOPmu/6g==}
dependencies:
workbox-core: 6.6.0
workbox-core: 7.0.0
dev: true
/workbox-core@6.6.0:
resolution: {integrity: sha512-GDtFRF7Yg3DD859PMbPAYPeJyg5gJYXuBQAC+wyrWuuXgpfoOrIQIvFRZnQ7+czTIQjIr1DhLEGFzZanAT/3bQ==}
/workbox-core@7.0.0:
resolution: {integrity: sha512-81JkAAZtfVP8darBpfRTovHg8DGAVrKFgHpOArZbdFd78VqHr5Iw65f2guwjE2NlCFbPFDoez3D3/6ZvhI/rwQ==}
dev: true
/workbox-expiration@6.6.0:
resolution: {integrity: sha512-baplYXcDHbe8vAo7GYvyAmlS4f6998Jff513L4XvlzAOxcl8F620O91guoJ5EOf5qeXG4cGdNZHkkVAPouFCpw==}
/workbox-expiration@7.0.0:
resolution: {integrity: sha512-MLK+fogW+pC3IWU9SFE+FRStvDVutwJMR5if1g7oBJx3qwmO69BNoJQVaMXq41R0gg3MzxVfwOGKx3i9P6sOLQ==}
dependencies:
idb: 7.1.1
workbox-core: 6.6.0
workbox-core: 7.0.0
dev: true
/workbox-google-analytics@6.6.0:
resolution: {integrity: sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==}
/workbox-google-analytics@7.0.0:
resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==}
dependencies:
workbox-background-sync: 6.6.0
workbox-core: 6.6.0
workbox-routing: 6.6.0
workbox-strategies: 6.6.0
workbox-background-sync: 7.0.0
workbox-core: 7.0.0
workbox-routing: 7.0.0
workbox-strategies: 7.0.0
dev: true
/workbox-navigation-preload@6.6.0:
resolution: {integrity: sha512-utNEWG+uOfXdaZmvhshrh7KzhDu/1iMHyQOV6Aqup8Mm78D286ugu5k9MFD9SzBT5TcwgwSORVvInaXWbvKz9Q==}
/workbox-navigation-preload@7.0.0:
resolution: {integrity: sha512-juWCSrxo/fiMz3RsvDspeSLGmbgC0U9tKqcUPZBCf35s64wlaLXyn2KdHHXVQrb2cqF7I0Hc9siQalainmnXJA==}
dependencies:
workbox-core: 6.6.0
workbox-core: 7.0.0
dev: true
/workbox-precaching@6.6.0:
resolution: {integrity: sha512-eYu/7MqtRZN1IDttl/UQcSZFkHP7dnvr/X3Vn6Iw6OsPMruQHiVjjomDFCNtd8k2RdjLs0xiz9nq+t3YVBcWPw==}
/workbox-precaching@7.0.0:
resolution: {integrity: sha512-EC0vol623LJqTJo1mkhD9DZmMP604vHqni3EohhQVwhJlTgyKyOkMrZNy5/QHfOby+39xqC01gv4LjOm4HSfnA==}
dependencies:
workbox-core: 6.6.0
workbox-routing: 6.6.0
workbox-strategies: 6.6.0
workbox-core: 7.0.0
workbox-routing: 7.0.0
workbox-strategies: 7.0.0
dev: true
/workbox-range-requests@6.6.0:
resolution: {integrity: sha512-V3aICz5fLGq5DpSYEU8LxeXvsT//mRWzKrfBOIxzIdQnV/Wj7R+LyJVTczi4CQ4NwKhAaBVaSujI1cEjXW+hTw==}
/workbox-range-requests@7.0.0:
resolution: {integrity: sha512-SxAzoVl9j/zRU9OT5+IQs7pbJBOUOlriB8Gn9YMvi38BNZRbM+RvkujHMo8FOe9IWrqqwYgDFBfv6sk76I1yaQ==}
dependencies:
workbox-core: 6.6.0
workbox-core: 7.0.0
dev: true
/workbox-recipes@6.6.0:
resolution: {integrity: sha512-TFi3kTgYw73t5tg73yPVqQC8QQjxJSeqjXRO4ouE/CeypmP2O/xqmB/ZFBBQazLTPxILUQ0b8aeh0IuxVn9a6A==}
/workbox-recipes@7.0.0:
resolution: {integrity: sha512-DntcK9wuG3rYQOONWC0PejxYYIDHyWWZB/ueTbOUDQgefaeIj1kJ7pdP3LZV2lfrj8XXXBWt+JDRSw1lLLOnww==}
dependencies:
workbox-cacheable-response: 6.6.0
workbox-core: 6.6.0
workbox-expiration: 6.6.0
workbox-precaching: 6.6.0
workbox-routing: 6.6.0
workbox-strategies: 6.6.0
workbox-cacheable-response: 7.0.0
workbox-core: 7.0.0
workbox-expiration: 7.0.0
workbox-precaching: 7.0.0
workbox-routing: 7.0.0
workbox-strategies: 7.0.0
dev: true
/workbox-routing@6.6.0:
resolution: {integrity: sha512-x8gdN7VDBiLC03izAZRfU+WKUXJnbqt6PG9Uh0XuPRzJPpZGLKce/FkOX95dWHRpOHWLEq8RXzjW0O+POSkKvw==}
/workbox-routing@7.0.0:
resolution: {integrity: sha512-8YxLr3xvqidnbVeGyRGkaV4YdlKkn5qZ1LfEePW3dq+ydE73hUUJJuLmGEykW3fMX8x8mNdL0XrWgotcuZjIvA==}
dependencies:
workbox-core: 6.6.0
workbox-core: 7.0.0
dev: true
/workbox-strategies@6.6.0:
resolution: {integrity: sha512-eC07XGuINAKUWDnZeIPdRdVja4JQtTuc35TZ8SwMb1ztjp7Ddq2CJ4yqLvWzFWGlYI7CG/YGqaETntTxBGdKgQ==}
/workbox-strategies@7.0.0:
resolution: {integrity: sha512-dg3qJU7tR/Gcd/XXOOo7x9QoCI9nk74JopaJaYAQ+ugLi57gPsXycVdBnYbayVj34m6Y8ppPwIuecrzkpBVwbA==}
dependencies:
workbox-core: 6.6.0
workbox-core: 7.0.0
dev: true
/workbox-streams@6.6.0:
resolution: {integrity: sha512-rfMJLVvwuED09CnH1RnIep7L9+mj4ufkTyDPVaXPKlhi9+0czCu+SJggWCIFbPpJaAZmp2iyVGLqS3RUmY3fxg==}
/workbox-streams@7.0.0:
resolution: {integrity: sha512-moVsh+5to//l6IERWceYKGiftc+prNnqOp2sgALJJFbnNVpTXzKISlTIsrWY+ogMqt+x1oMazIdHj25kBSq/HQ==}
dependencies:
workbox-core: 6.6.0
workbox-routing: 6.6.0
workbox-core: 7.0.0
workbox-routing: 7.0.0
dev: true
/workbox-sw@6.6.0:
resolution: {integrity: sha512-R2IkwDokbtHUE4Kus8pKO5+VkPHD2oqTgl+XJwh4zbF1HyjAbgNmK/FneZHVU7p03XUt9ICfuGDYISWG9qV/CQ==}
/workbox-sw@7.0.0:
resolution: {integrity: sha512-SWfEouQfjRiZ7GNABzHUKUyj8pCoe+RwjfOIajcx6J5mtgKkN+t8UToHnpaJL5UVVOf5YhJh+OHhbVNIHe+LVA==}
dev: true
/workbox-window@6.6.0:
resolution: {integrity: sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==}
/workbox-window@7.0.0:
resolution: {integrity: sha512-j7P/bsAWE/a7sxqTzXo3P2ALb1reTfZdvVp6OJ/uLr/C2kZAMvjeWGm8V4htQhor7DOvYg0sSbFN2+flT5U0qA==}
dependencies:
'@types/trusted-types': 2.0.3
workbox-core: 6.6.0
workbox-core: 7.0.0
dev: true
/wrap-ansi@6.2.0:

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.6493 6.34989C16.8111 5.50416 15.7937 4.8575 14.6721 4.45768C13.5505 4.05786 12.3534 3.91508 11.1693 4.03989C7.49929 4.40989 4.47929 7.38989 4.06929 11.0599C3.51929 15.9099 7.26929 19.9999 11.9993 19.9999C13.5094 19.9999 14.9885 19.5714 16.2648 18.7642C17.5411 17.957 18.5621 16.8043 19.2093 15.4399C19.5293 14.7699 19.0493 13.9999 18.3093 13.9999C17.9393 13.9999 17.5893 14.1999 17.4293 14.5299C16.8487 15.7789 15.8557 16.7899 14.6172 17.3927C13.3788 17.9955 11.9705 18.1534 10.6293 17.8399C8.40929 17.3499 6.61929 15.5399 6.14929 13.3199C5.95172 12.4422 5.95401 11.5312 6.15598 10.6545C6.35796 9.77775 6.75445 8.95764 7.31614 8.25481C7.87783 7.55198 8.59033 6.98442 9.40096 6.59411C10.2116 6.20379 11.0996 6.00071 11.9993 5.99989C13.6593 5.99989 15.1393 6.68989 16.2193 7.77989L14.7093 9.28989C14.0793 9.91989 14.5193 10.9999 15.4093 10.9999H18.9993C19.5493 10.9999 19.9993 10.5499 19.9993 9.99989V6.40989C19.9993 5.51989 18.9193 5.06989 18.2893 5.69989L17.6493 6.34989Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -2,11 +2,20 @@ import { Show } from "solid-js";
// eslint-disable-next-line import/no-unresolved
import { useRegisterSW } from "virtual:pwa-register/solid";
import close from "~/assets/icons/close.svg";
import refresh from "~/assets/icons/refresh.svg";
import { useI18n } from "~/i18n/context";
import { SmallHeader } from "./layout";
import { Button } from "./layout/Button";
export function ReloadPrompt() {
const i18n = useI18n();
// useRegisterSW can also return an offlineReady thingy
const {
offlineReady: [offlineReady, _setOfflineReady],
needRefresh: [needRefresh, _setNeedRefresh],
updateServiceWorker: _update
needRefresh: [needRefresh, setNeedRefresh],
updateServiceWorker
} = useRegisterSW({
immediate: true,
onRegisteredSW(swUrl, r) {
@@ -17,27 +26,48 @@ export function ReloadPrompt() {
}
});
// const close = () => {
// setOfflineReady(false)
// setNeedRefresh(false)
// }
const dismissPrompt = () => {
setNeedRefresh(false);
};
async function updateSw() {
await updateServiceWorker();
}
return (
<Show when={offlineReady() || needRefresh()}>
{/* <Card title="PWA settings">
<div>
<Show
fallback={<span>New content available, click on reload button to update.</span>}
when={offlineReady()}
>
<span>App ready to work offline</span>
</Show>
<Show when={needRefresh()}>
<div class="grid grid-cols-[auto_minmax(0,_1fr)_auto] gap-4 rounded-xl bg-neutral-950/50 p-4">
<div class="self-center">
<img src={refresh} alt="refresh" class="h-8 w-8" />
</div>
<Show when={needRefresh()}>
<Button onClick={() => updateServiceWorker(true)}>Reload</Button>
</Show>
<Button onClick={() => close()}>Close</Button>
</Card> */}
<div class="flex flex-row justify-between gap-4 max-md:items-center">
<div class="flex flex-col">
<SmallHeader>
{i18n.t("reload.mutiny_update")}
</SmallHeader>
<p class="text-base font-light max-md:hidden">
{i18n.t("reload.new_version_description")}
</p>
</div>
<div class="flex items-center">
<Button
intent="blue"
layout="xs"
class="self-auto"
onClick={updateSw}
>
{i18n.t("reload.reload")}
</Button>
</div>
</div>
<button
tabindex="-1"
onClick={dismissPrompt}
class="w-8 self-center rounded-lg hover:bg-white/10 active:bg-m-blue"
>
<img src={close} alt="Close" />
</button>
</div>
</Show>
);
}

View File

@@ -580,6 +580,12 @@ export default {
connecting: "Connecting...",
confirm_swap: "Confirm Swap"
},
reload: {
mutiny_update: "Mutiny Update",
new_version_description:
"New version of Mutiny has been cached, reload to start using it.",
reload: "Reload"
},
error: {
title: "Error",
emergency_link: "emergency kit.",

View File

@@ -1,22 +1,30 @@
import { defineConfig } from "vite";
import solid from "vite-plugin-solid";
import { VitePWA, VitePWAOptions } from "vite-plugin-pwa";
import wasm from "vite-plugin-wasm";
import * as child from "child_process";
import * as path from "path";
import autoprefixer from "autoprefixer";
import tailwindcss from "tailwindcss";
import { defineConfig } from "vite";
import { VitePWA, VitePWAOptions } from "vite-plugin-pwa";
import solid from "vite-plugin-solid";
import wasm from "vite-plugin-wasm";
import manifest from "./manifest";
import * as path from "path";
import * as child from "child_process";
const commitHash = process.env.VITE_COMMIT_HASH ?? child.execSync("git rev-parse --short HEAD").toString().trim();
const commitHash =
process.env.VITE_COMMIT_HASH ??
child.execSync("git rev-parse --short HEAD").toString().trim();
const pwaOptions: Partial<VitePWAOptions> = {
base: "/",
registerType: "autoUpdate",
registerType: "prompt",
devOptions: {
enabled: false
},
workbox: {
navigateFallback: "/index.html",
globPatterns: ["**/*.{js,css,html,svg,png,gif,wasm}"],
// mutiny_wasm is 10mb, so we'll do 25mb to be safe
maximumFileSizeToCacheInBytes: 25 * 1024 * 1024
},
includeAssets: ["favicon.ico", "robots.txt"],
manifest: manifest
};
@@ -37,7 +45,9 @@ export default defineConfig({
plugins: [wasm(), solid(), VitePWA(pwaOptions)],
define: {
"import.meta.env.__COMMIT_HASH__": JSON.stringify(commitHash),
"import.meta.env.__RELEASE_VERSION__": JSON.stringify(process.env.npm_package_version)
"import.meta.env.__RELEASE_VERSION__": JSON.stringify(
process.env.npm_package_version
)
},
resolve: {
alias: [{ find: "~", replacement: path.resolve(__dirname, "./src") }]
@@ -58,7 +68,7 @@ export default defineConfig({
"@capacitor/haptics",
"@capacitor/share",
"@capacitor/status-bar",
"@capacitor/toast",
"@capacitor/toast"
],
// This is necessary because otherwise `vite dev` can't find the wasm
exclude: ["@mutinywallet/mutiny-wasm", "@mutinywallet/waila-wasm"]