init commit
|
@ -0,0 +1,17 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = crlf
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.css]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.{js,ts,json}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.html]
|
||||||
|
indent_size = 2
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
|
@ -0,0 +1 @@
|
||||||
|
nodejs 20.11.0
|
|
@ -0,0 +1,64 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" class="no-js">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
|
<title>SURE - Secure URL Requests</title>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
document.documentElement.classList.remove("no-js");
|
||||||
|
document.documentElement.classList.add("js");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<meta name="description" content="Securely request information via SURE links" />
|
||||||
|
<meta property="og:title" content="SURE - Secure URL Requests" />
|
||||||
|
<meta property="og:description" content="Securely request information via SURE links" />
|
||||||
|
<meta property="og:image" content="https://sure.dog/img/logo.png" />
|
||||||
|
<meta property="og:image:alt" content="Abstract logo of the letter S" />
|
||||||
|
<meta property="og:locale" content="en_US" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta property="og:url" content="https://sure.dog/" />
|
||||||
|
<link rel="canonical" href="https://sure.dog/" />
|
||||||
|
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||||
|
|
||||||
|
<link rel="manifest" href="/manifest.json" />
|
||||||
|
<meta name="mobile-web-app-capable" content="yes" />
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
|
<meta name="application-name" content="SURE" />
|
||||||
|
<meta name="apple-mobile-web-app-title" content="SURE" />
|
||||||
|
<meta name="theme-color" content="#44a616" />
|
||||||
|
<meta name="msapplication-navbutton-color" content="#44a616" />
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
|
<meta name="msapplication-starturl" content="/" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<header class="container">
|
||||||
|
<hgroup>
|
||||||
|
<h1>SURE</h1>
|
||||||
|
<p>Secure URL Requests</p>
|
||||||
|
</hgroup>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- No JS Warning -->
|
||||||
|
<dialog open class="js-warning">
|
||||||
|
<article>
|
||||||
|
<header>No Javascript Detected</header>
|
||||||
|
<p>
|
||||||
|
Unfortunately, this site requires Javascript in order to generate
|
||||||
|
keypairs, save them in localstorage, and encrypt/decrypt data. Please
|
||||||
|
enable Javascript and refresh the page.
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<main id="app" class="container"></main>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,791 @@
|
||||||
|
{
|
||||||
|
"name": "sure-ts",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "sure-ts",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@picocss/pico": "^1.5.11"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.2.2",
|
||||||
|
"vite": "^5.0.8",
|
||||||
|
"vite-plugin-make-offline": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"aix"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-arm": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-arm64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-x64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/darwin-x64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/freebsd-arm64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/freebsd-x64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-arm": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-ia32": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-loong64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==",
|
||||||
|
"cpu": [
|
||||||
|
"loong64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-mips64el": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==",
|
||||||
|
"cpu": [
|
||||||
|
"mips64el"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-ppc64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-riscv64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-s390x": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==",
|
||||||
|
"cpu": [
|
||||||
|
"s390x"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-x64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/netbsd-x64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"netbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openbsd-x64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/sunos-x64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"sunos"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-arm64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-ia32": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-x64": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@picocss/pico": {
|
||||||
|
"version": "1.5.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@picocss/pico/-/pico-1.5.11.tgz",
|
||||||
|
"integrity": "sha512-cDaFiSyNPtuSTwSQt/05xsw8+g2ek4/S58tgh9Nc7miJCCdUrY9PAyl4OPWRJtYgJDdEvkUA9GuGj0J4nDP4Cw=="
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
|
"version": "4.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz",
|
||||||
|
"integrity": "sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-android-arm64": {
|
||||||
|
"version": "4.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz",
|
||||||
|
"integrity": "sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||||
|
"version": "4.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz",
|
||||||
|
"integrity": "sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-darwin-x64": {
|
||||||
|
"version": "4.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz",
|
||||||
|
"integrity": "sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||||
|
"version": "4.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz",
|
||||||
|
"integrity": "sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||||
|
"version": "4.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz",
|
||||||
|
"integrity": "sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||||
|
"version": "4.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz",
|
||||||
|
"integrity": "sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||||
|
"version": "4.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz",
|
||||||
|
"integrity": "sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||||
|
"version": "4.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz",
|
||||||
|
"integrity": "sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||||
|
"version": "4.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.6.tgz",
|
||||||
|
"integrity": "sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||||
|
"version": "4.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz",
|
||||||
|
"integrity": "sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||||
|
"version": "4.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz",
|
||||||
|
"integrity": "sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||||
|
"version": "4.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz",
|
||||||
|
"integrity": "sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@types/estree": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/esbuild": {
|
||||||
|
"version": "0.19.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
|
||||||
|
"integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"bin": {
|
||||||
|
"esbuild": "bin/esbuild"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@esbuild/aix-ppc64": "0.19.12",
|
||||||
|
"@esbuild/android-arm": "0.19.12",
|
||||||
|
"@esbuild/android-arm64": "0.19.12",
|
||||||
|
"@esbuild/android-x64": "0.19.12",
|
||||||
|
"@esbuild/darwin-arm64": "0.19.12",
|
||||||
|
"@esbuild/darwin-x64": "0.19.12",
|
||||||
|
"@esbuild/freebsd-arm64": "0.19.12",
|
||||||
|
"@esbuild/freebsd-x64": "0.19.12",
|
||||||
|
"@esbuild/linux-arm": "0.19.12",
|
||||||
|
"@esbuild/linux-arm64": "0.19.12",
|
||||||
|
"@esbuild/linux-ia32": "0.19.12",
|
||||||
|
"@esbuild/linux-loong64": "0.19.12",
|
||||||
|
"@esbuild/linux-mips64el": "0.19.12",
|
||||||
|
"@esbuild/linux-ppc64": "0.19.12",
|
||||||
|
"@esbuild/linux-riscv64": "0.19.12",
|
||||||
|
"@esbuild/linux-s390x": "0.19.12",
|
||||||
|
"@esbuild/linux-x64": "0.19.12",
|
||||||
|
"@esbuild/netbsd-x64": "0.19.12",
|
||||||
|
"@esbuild/openbsd-x64": "0.19.12",
|
||||||
|
"@esbuild/sunos-x64": "0.19.12",
|
||||||
|
"@esbuild/win32-arm64": "0.19.12",
|
||||||
|
"@esbuild/win32-ia32": "0.19.12",
|
||||||
|
"@esbuild/win32-x64": "0.19.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fsevents": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "3.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/picocolors": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/postcss": {
|
||||||
|
"version": "8.4.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
|
||||||
|
"integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "^3.3.7",
|
||||||
|
"picocolors": "^1.0.0",
|
||||||
|
"source-map-js": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rollup": {
|
||||||
|
"version": "4.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.6.tgz",
|
||||||
|
"integrity": "sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/estree": "1.0.5"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rollup": "dist/bin/rollup"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0",
|
||||||
|
"npm": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@rollup/rollup-android-arm-eabi": "4.9.6",
|
||||||
|
"@rollup/rollup-android-arm64": "4.9.6",
|
||||||
|
"@rollup/rollup-darwin-arm64": "4.9.6",
|
||||||
|
"@rollup/rollup-darwin-x64": "4.9.6",
|
||||||
|
"@rollup/rollup-linux-arm-gnueabihf": "4.9.6",
|
||||||
|
"@rollup/rollup-linux-arm64-gnu": "4.9.6",
|
||||||
|
"@rollup/rollup-linux-arm64-musl": "4.9.6",
|
||||||
|
"@rollup/rollup-linux-riscv64-gnu": "4.9.6",
|
||||||
|
"@rollup/rollup-linux-x64-gnu": "4.9.6",
|
||||||
|
"@rollup/rollup-linux-x64-musl": "4.9.6",
|
||||||
|
"@rollup/rollup-win32-arm64-msvc": "4.9.6",
|
||||||
|
"@rollup/rollup-win32-ia32-msvc": "4.9.6",
|
||||||
|
"@rollup/rollup-win32-x64-msvc": "4.9.6",
|
||||||
|
"fsevents": "~2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/source-map-js": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/typescript": {
|
||||||
|
"version": "5.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
|
||||||
|
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"tsc": "bin/tsc",
|
||||||
|
"tsserver": "bin/tsserver"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vite": {
|
||||||
|
"version": "5.0.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.0.12.tgz",
|
||||||
|
"integrity": "sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"esbuild": "^0.19.3",
|
||||||
|
"postcss": "^8.4.32",
|
||||||
|
"rollup": "^4.2.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"vite": "bin/vite.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.0.0 || >=20.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/node": "^18.0.0 || >=20.0.0",
|
||||||
|
"less": "*",
|
||||||
|
"lightningcss": "^1.21.0",
|
||||||
|
"sass": "*",
|
||||||
|
"stylus": "*",
|
||||||
|
"sugarss": "*",
|
||||||
|
"terser": "^5.4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/node": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"less": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"lightningcss": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sass": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"stylus": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sugarss": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"terser": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vite-plugin-make-offline": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vite-plugin-make-offline/-/vite-plugin-make-offline-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-iPsB4QwfvhiftIEPvc3n+ZAO93SppbMZcbX8VAjzCQWHxEmCGpa/2eRgzZZgbuY0Hljs92dOWt05mgZx/5Lvvg==",
|
||||||
|
"dev": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"rollup": ">=2.79.0",
|
||||||
|
"vite": ">=3.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "sure",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc && vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.2.2",
|
||||||
|
"vite": "^5.0.8",
|
||||||
|
"vite-plugin-make-offline": "^1.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@picocss/pico": "^1.5.11"
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 126 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 540 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 91 KiB |
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "SURE",
|
||||||
|
"short_name": "SURE",
|
||||||
|
"theme_color": "#44a616",
|
||||||
|
"background_color": "#3d006e",
|
||||||
|
"display": "minimal-ui",
|
||||||
|
"scope": "/",
|
||||||
|
"start_url": "/",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/android-chrome-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/android-chrome-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
import "@picocss/pico/css/pico.min.css";
|
||||||
|
import "./style.css";
|
||||||
|
import { setupRequestPage } from "./routes/request.ts";
|
||||||
|
import { setupSendPage } from "./routes/send.ts";
|
||||||
|
import { setupReceivePage } from "./routes/receive.ts";
|
||||||
|
|
||||||
|
const start = () => {
|
||||||
|
const fragmentData = new URLSearchParams(window.location.hash.slice(1));
|
||||||
|
const appElement = document.querySelector<HTMLElement>("#app");
|
||||||
|
|
||||||
|
if (!appElement) {
|
||||||
|
throw new Error("No app element found");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the URL contains the 'p', 'iv', and 'm' parameters, then the receiver page is set up
|
||||||
|
if (
|
||||||
|
fragmentData.has("p") &&
|
||||||
|
fragmentData.has("iv") &&
|
||||||
|
fragmentData.has("m")
|
||||||
|
) {
|
||||||
|
setupReceivePage(appElement, {
|
||||||
|
p: decodeURIComponent(fragmentData.get("p")!),
|
||||||
|
iv: decodeURIComponent(fragmentData.get("iv")!),
|
||||||
|
m: decodeURIComponent(fragmentData.get("m")!),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the URL contains the 'p' parameter, then the sender page is set up
|
||||||
|
if (fragmentData.has("p")) {
|
||||||
|
setupSendPage(appElement, fragmentData.get("p")!);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, the request page is set up
|
||||||
|
setupRequestPage(appElement);
|
||||||
|
};
|
||||||
|
|
||||||
|
start();
|
|
@ -0,0 +1,80 @@
|
||||||
|
import {
|
||||||
|
deriveSharedSecret,
|
||||||
|
decrypt,
|
||||||
|
retrieveOrGenerateKeyPair,
|
||||||
|
} from "../utils/crypto";
|
||||||
|
|
||||||
|
const MESSAGE_OUTPUT_ID = "message";
|
||||||
|
const DECRYPT_BUTTON_ID = "decrypt";
|
||||||
|
const TEMPLATE = `
|
||||||
|
<section>
|
||||||
|
<details>
|
||||||
|
<summary>How it Works</summary>
|
||||||
|
<ul>
|
||||||
|
<li>Press "Decrypt" to view the information sent by the sender.</li>
|
||||||
|
<li>The decrypted message will appear below.</li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<form>
|
||||||
|
<input
|
||||||
|
id="${DECRYPT_BUTTON_ID}"
|
||||||
|
type="submit"
|
||||||
|
value="Decrypt"
|
||||||
|
aria-label="Decrypt"
|
||||||
|
/>
|
||||||
|
<textarea
|
||||||
|
id="${MESSAGE_OUTPUT_ID}"
|
||||||
|
readonly
|
||||||
|
aria-label="Decrypted Message"
|
||||||
|
></textarea>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export async function setupReceivePage(
|
||||||
|
element: HTMLElement,
|
||||||
|
params: { p: string; iv: string; m: string }
|
||||||
|
) {
|
||||||
|
element.innerHTML = TEMPLATE;
|
||||||
|
|
||||||
|
// Add an event listener to the "Decrypt" button
|
||||||
|
const decryptButton = document.getElementById(
|
||||||
|
DECRYPT_BUTTON_ID
|
||||||
|
) as HTMLButtonElement;
|
||||||
|
decryptButton.addEventListener("click", (event: Event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
decryptData(params);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function decryptData({ p, iv, m }: { p: string; iv: string; m: string }) {
|
||||||
|
// Parse the 'p' parameter to get publicB
|
||||||
|
const publicBJwk = JSON.parse(atob(p));
|
||||||
|
|
||||||
|
// Import publicB as a CryptoKey
|
||||||
|
const publicB = await window.crypto.subtle.importKey(
|
||||||
|
"jwk",
|
||||||
|
publicBJwk,
|
||||||
|
{
|
||||||
|
name: "ECDH",
|
||||||
|
namedCurve: "P-256",
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const keyPairA = await retrieveOrGenerateKeyPair();
|
||||||
|
|
||||||
|
// Retrieve the AES key from local storage
|
||||||
|
const aesKey = await deriveSharedSecret(keyPairA.privateKey, publicB);
|
||||||
|
|
||||||
|
// Decrypt the message using the AES key and IV
|
||||||
|
const decryptedData = await decrypt(aesKey, iv, m);
|
||||||
|
|
||||||
|
// Update the message output with the decrypted message
|
||||||
|
const messageOutput = document.getElementById(
|
||||||
|
MESSAGE_OUTPUT_ID
|
||||||
|
) as HTMLTextAreaElement;
|
||||||
|
messageOutput.value = decryptedData;
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { retrieveOrGenerateKeyPair } from "../utils/crypto.ts";
|
||||||
|
|
||||||
|
const URL_INPUT_ID = "request-url";
|
||||||
|
const TEMPLATE = `<section>
|
||||||
|
<details>
|
||||||
|
<summary>How it Works</summary>
|
||||||
|
<ul>
|
||||||
|
<li>Send the generated URL below to whom you wish to request data from.</li>
|
||||||
|
<li>Upon accessing the URL, the receiver can then enter the data you'd like from them.</li>
|
||||||
|
<li>This generates a URL that they'll send back to you.</li>
|
||||||
|
<li>You can now access the encrypted data in the URL which only _your_ browser can decrypt.</li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<form>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="request-url"
|
||||||
|
id="${URL_INPUT_ID}"
|
||||||
|
placeholder=""
|
||||||
|
aria-label="Request URL"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</section>`;
|
||||||
|
|
||||||
|
export async function setupRequestPage(element: HTMLElement) {
|
||||||
|
element.innerHTML = TEMPLATE;
|
||||||
|
|
||||||
|
const url = await generateUrl();
|
||||||
|
const input = document.getElementById(URL_INPUT_ID) as HTMLInputElement;
|
||||||
|
input.value = url.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateUrl(): Promise<URL> {
|
||||||
|
const { publicKey: ecdhPublic } = await retrieveOrGenerateKeyPair();
|
||||||
|
|
||||||
|
// Generate URL with public key as the 'p' search parameter
|
||||||
|
const ecdhPublicJwk = await window.crypto.subtle.exportKey("jwk", ecdhPublic);
|
||||||
|
const url = new URL(window.location.toString());
|
||||||
|
url.hash = `p=${btoa(JSON.stringify(ecdhPublicJwk))}`;
|
||||||
|
|
||||||
|
// Return the generated URL
|
||||||
|
return url;
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
import {
|
||||||
|
deriveSharedSecret,
|
||||||
|
encrypt,
|
||||||
|
retrieveOrGenerateKeyPair,
|
||||||
|
} from "../utils/crypto";
|
||||||
|
|
||||||
|
const ENCRYPTED_URL_INPUT_ID = "encrypted-url";
|
||||||
|
const MESSAGE_INPUT_ID = "message";
|
||||||
|
const ENCRYPT_BUTTON_ID = "encrypt";
|
||||||
|
const REQUEST_PUBLIC_KEY = "requestPublicKey";
|
||||||
|
const TEMPLATE = `
|
||||||
|
<section>
|
||||||
|
<details>
|
||||||
|
<summary>How it Works</summary>
|
||||||
|
<ul>
|
||||||
|
<li>Enter the information you'd like to send to the person whom generated this link.</li>
|
||||||
|
<li>Press "Encrypt" to generate a URL that has your encrypted information.</li>
|
||||||
|
<li>Send this generated URL to the person who sent this information request.</li>
|
||||||
|
<li>Only their browser can decrypt the secret in the URL.</li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<form>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="message"
|
||||||
|
id="${MESSAGE_INPUT_ID}"
|
||||||
|
placeholder="Enter your message here..."
|
||||||
|
aria-label="Message to Encrypt"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
id="${ENCRYPT_BUTTON_ID}"
|
||||||
|
type="submit"
|
||||||
|
value="Encrypt"
|
||||||
|
aria-label="Encrypt"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="encrypted-url"
|
||||||
|
id="${ENCRYPTED_URL_INPUT_ID}"
|
||||||
|
placeholder="Generated URL will appear here..."
|
||||||
|
aria-label="Encrypted URL"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export async function setupSendPage(element: HTMLElement, key: string) {
|
||||||
|
element.innerHTML = TEMPLATE;
|
||||||
|
localStorage.setItem(REQUEST_PUBLIC_KEY, key);
|
||||||
|
|
||||||
|
// Add an event listener to the "Encrypt" button
|
||||||
|
const encryptButton = document.getElementById(
|
||||||
|
ENCRYPT_BUTTON_ID
|
||||||
|
) as HTMLButtonElement;
|
||||||
|
encryptButton.addEventListener("click", encryptData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function encryptData(event: Event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const key = localStorage.getItem(REQUEST_PUBLIC_KEY)!;
|
||||||
|
|
||||||
|
// Parse the 'p' parameter to get publicA
|
||||||
|
const publicAJwk = JSON.parse(atob(key));
|
||||||
|
|
||||||
|
// Import publicA as a CryptoKey
|
||||||
|
const publicA = await window.crypto.subtle.importKey(
|
||||||
|
"jwk",
|
||||||
|
publicAJwk,
|
||||||
|
{
|
||||||
|
name: "ECDH",
|
||||||
|
namedCurve: "P-256",
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const keyPairB = await retrieveOrGenerateKeyPair();
|
||||||
|
|
||||||
|
// Retrieve the message input
|
||||||
|
const messageInput = document.getElementById(
|
||||||
|
MESSAGE_INPUT_ID
|
||||||
|
) as HTMLInputElement;
|
||||||
|
|
||||||
|
// Retrieve the AES key from local storage
|
||||||
|
const aesKey = await deriveSharedSecret(keyPairB.privateKey, publicA);
|
||||||
|
|
||||||
|
// Encrypt the message input value using the AES key
|
||||||
|
const { encryptedData, iv } = await encrypt(aesKey, messageInput.value);
|
||||||
|
|
||||||
|
// Update the encrypted URL input with the encrypted message
|
||||||
|
const encryptedUrlInput = document.getElementById(
|
||||||
|
ENCRYPTED_URL_INPUT_ID
|
||||||
|
) as HTMLInputElement;
|
||||||
|
|
||||||
|
const ecdhPublicJwk = await window.crypto.subtle.exportKey(
|
||||||
|
"jwk",
|
||||||
|
keyPairB.publicKey
|
||||||
|
);
|
||||||
|
const url = new URL(window.location.toString());
|
||||||
|
|
||||||
|
url.hash = `p=${encodeURIComponent(
|
||||||
|
btoa(JSON.stringify(ecdhPublicJwk))
|
||||||
|
)}&iv=${encodeURIComponent(
|
||||||
|
btoa(String.fromCharCode.apply(null, Array.from(iv)))
|
||||||
|
)}&m=${encodeURIComponent(
|
||||||
|
btoa(
|
||||||
|
String.fromCharCode.apply(null, Array.from(new Uint8Array(encryptedData)))
|
||||||
|
)
|
||||||
|
)}`;
|
||||||
|
|
||||||
|
// url.hash = `p=${btoa(JSON.stringify(ecdhPublicJwk))}&iv=${btoa(
|
||||||
|
// String.fromCharCode.apply(null, Array.from(iv))
|
||||||
|
// )}&m=${btoa(
|
||||||
|
// String.fromCharCode.apply(null, Array.from(new Uint8Array(encryptedData)))
|
||||||
|
// )}`;
|
||||||
|
|
||||||
|
encryptedUrlInput.value = url.toString();
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
.js-warning {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-js .js-warning {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
|
@ -0,0 +1,143 @@
|
||||||
|
export async function generateKeyPair(): Promise<CryptoKeyPair> {
|
||||||
|
return await window.crypto.subtle.generateKey(
|
||||||
|
{
|
||||||
|
name: "ECDH",
|
||||||
|
namedCurve: "P-256",
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
["deriveKey", "deriveBits"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deriveSharedSecret(
|
||||||
|
privateKey: CryptoKey,
|
||||||
|
publicKey: CryptoKey
|
||||||
|
): Promise<CryptoKey> {
|
||||||
|
return await window.crypto.subtle.deriveKey(
|
||||||
|
{
|
||||||
|
name: "ECDH",
|
||||||
|
|
||||||
|
public: publicKey,
|
||||||
|
},
|
||||||
|
privateKey,
|
||||||
|
{
|
||||||
|
name: "AES-GCM",
|
||||||
|
length: 256,
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
["encrypt", "decrypt"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function retrieveOrGenerateKeyPair(): Promise<CryptoKeyPair> {
|
||||||
|
let ecdhPublic: CryptoKey;
|
||||||
|
let ecdhPrivate: CryptoKey;
|
||||||
|
|
||||||
|
if (
|
||||||
|
localStorage.getItem("ecdhPublic") &&
|
||||||
|
localStorage.getItem("ecdhPrivate")
|
||||||
|
) {
|
||||||
|
const ecdhPublicJwk = JSON.parse(localStorage.getItem("ecdhPublic")!);
|
||||||
|
const ecdhPrivateJwk = JSON.parse(localStorage.getItem("ecdhPrivate")!);
|
||||||
|
|
||||||
|
ecdhPrivate = await window.crypto.subtle.importKey(
|
||||||
|
"jwk",
|
||||||
|
ecdhPrivateJwk,
|
||||||
|
{
|
||||||
|
name: "ECDH",
|
||||||
|
namedCurve: "P-256",
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
["deriveKey", "deriveBits"]
|
||||||
|
);
|
||||||
|
|
||||||
|
ecdhPublic = await window.crypto.subtle.importKey(
|
||||||
|
"jwk",
|
||||||
|
ecdhPublicJwk,
|
||||||
|
{
|
||||||
|
name: "ECDH",
|
||||||
|
namedCurve: "P-256",
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const keyPair = await generateKeyPair();
|
||||||
|
ecdhPublic = keyPair.publicKey;
|
||||||
|
ecdhPrivate = keyPair.privateKey;
|
||||||
|
saveKeys(ecdhPublic, ecdhPrivate);
|
||||||
|
}
|
||||||
|
return { publicKey: ecdhPublic, privateKey: ecdhPrivate };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveKeys(ecdhPublic: CryptoKey, ecdhPrivate: CryptoKey) {
|
||||||
|
const ecdhPublicJwk = await window.crypto.subtle.exportKey("jwk", ecdhPublic);
|
||||||
|
const ecdhPrivateJwk = await window.crypto.subtle.exportKey(
|
||||||
|
"jwk",
|
||||||
|
ecdhPrivate
|
||||||
|
);
|
||||||
|
|
||||||
|
// Store ECDH key pair in local storage
|
||||||
|
localStorage.setItem("ecdhPublic", JSON.stringify(ecdhPublicJwk));
|
||||||
|
localStorage.setItem("ecdhPrivate", JSON.stringify(ecdhPrivateJwk));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function encrypt(
|
||||||
|
aesKey: CryptoKey,
|
||||||
|
data: string
|
||||||
|
): Promise<{ encryptedData: ArrayBuffer; iv: Uint8Array }> {
|
||||||
|
// Convert the data to a Uint8Array
|
||||||
|
const dataUint8Array = new TextEncoder().encode(data);
|
||||||
|
|
||||||
|
// Generate a random initialization vector (iv)
|
||||||
|
const iv = window.crypto.getRandomValues(new Uint8Array(12));
|
||||||
|
|
||||||
|
// Encrypt the data
|
||||||
|
const encryptedData = await window.crypto.subtle.encrypt(
|
||||||
|
{
|
||||||
|
name: "AES-GCM",
|
||||||
|
iv: iv,
|
||||||
|
},
|
||||||
|
aesKey,
|
||||||
|
dataUint8Array
|
||||||
|
);
|
||||||
|
|
||||||
|
// Return the combined iv and encrypted data
|
||||||
|
return { encryptedData, iv };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function decrypt(
|
||||||
|
aesKey: CryptoKey,
|
||||||
|
iv: string,
|
||||||
|
encryptedData: string
|
||||||
|
): Promise<string> {
|
||||||
|
console.log(iv);
|
||||||
|
// Decode the iv and encryptedData from base64
|
||||||
|
const ivUint8Array = base64ToUint8Array(iv);
|
||||||
|
const encryptedDataUint8Array = base64ToUint8Array(encryptedData);
|
||||||
|
|
||||||
|
// Decrypt the data
|
||||||
|
const decryptedData = await window.crypto.subtle.decrypt(
|
||||||
|
{
|
||||||
|
name: "AES-GCM",
|
||||||
|
iv: ivUint8Array,
|
||||||
|
},
|
||||||
|
aesKey,
|
||||||
|
encryptedDataUint8Array
|
||||||
|
);
|
||||||
|
|
||||||
|
// Convert the decrypted data from a Uint8Array to a string
|
||||||
|
const decryptedString = new TextDecoder().decode(decryptedData);
|
||||||
|
|
||||||
|
return decryptedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
function base64ToUint8Array(base64: string): Uint8Array {
|
||||||
|
const binaryString = atob(base64);
|
||||||
|
const len = binaryString.length;
|
||||||
|
const bytes = new Uint8Array(len);
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
bytes[i] = binaryString.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
/// <reference types="vite/client" />
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { defineConfig } from "vite";
|
||||||
|
import { makeOffline } from "vite-plugin-make-offline";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [makeOffline()], // This is the plugin 😃
|
||||||
|
});
|