trifid-api 0.3.0-alpha1 and some work on a tfweb rewrite #6

Merged
core merged 12 commits from api-and-web-rewrite into master 2023-12-28 05:44:29 +00:00
51 changed files with 1378 additions and 79 deletions
Showing only changes of commit 026d00b9cb - Show all commits

View File

@ -35,10 +35,14 @@
},
"type": "module",
"dependencies": {
"bits-ui": "^0.11.8",
"clsx": "^2.0.0",
"formsnap": "^0.4.1",
"lucide-svelte": "^0.298.0",
"mode-watcher": "^0.1.2",
"sveltekit-superforms": "^1.12.0",
"tailwind-merge": "^2.1.0",
"tailwind-variants": "^0.1.19"
"tailwind-variants": "^0.1.19",
"zod": "^3.22.4"
}
}

View File

@ -5,21 +5,33 @@ settings:
excludeLinksFromLockfile: false
dependencies:
bits-ui:
specifier: ^0.11.8
version: 0.11.8(svelte@4.2.8)
clsx:
specifier: ^2.0.0
version: 2.0.0
formsnap:
specifier: ^0.4.1
version: 0.4.1(svelte@4.2.8)(sveltekit-superforms@1.12.0)(zod@3.22.4)
lucide-svelte:
specifier: ^0.298.0
version: 0.298.0(svelte@4.2.8)
mode-watcher:
specifier: ^0.1.2
version: 0.1.2(svelte@4.2.8)
sveltekit-superforms:
specifier: ^1.12.0
version: 1.12.0(@sveltejs/kit@2.0.1)(svelte@4.2.8)(zod@3.22.4)
tailwind-merge:
specifier: ^2.1.0
version: 2.1.0
tailwind-variants:
specifier: ^0.1.19
version: 0.1.19(tailwindcss@3.3.6)
zod:
specifier: ^3.22.4
version: 3.22.4
devDependencies:
'@sveltejs/adapter-auto':
@ -114,7 +126,6 @@ packages:
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/android-arm@0.19.9:
@ -123,7 +134,6 @@ packages:
cpu: [arm]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/android-x64@0.19.9:
@ -132,7 +142,6 @@ packages:
cpu: [x64]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/darwin-arm64@0.19.9:
@ -141,7 +150,6 @@ packages:
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@esbuild/darwin-x64@0.19.9:
@ -150,7 +158,6 @@ packages:
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@esbuild/freebsd-arm64@0.19.9:
@ -159,7 +166,6 @@ packages:
cpu: [arm64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/freebsd-x64@0.19.9:
@ -168,7 +174,6 @@ packages:
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-arm64@0.19.9:
@ -177,7 +182,6 @@ packages:
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-arm@0.19.9:
@ -186,7 +190,6 @@ packages:
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-ia32@0.19.9:
@ -195,7 +198,6 @@ packages:
cpu: [ia32]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-loong64@0.19.9:
@ -204,7 +206,6 @@ packages:
cpu: [loong64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-mips64el@0.19.9:
@ -213,7 +214,6 @@ packages:
cpu: [mips64el]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-ppc64@0.19.9:
@ -222,7 +222,6 @@ packages:
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-riscv64@0.19.9:
@ -231,7 +230,6 @@ packages:
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-s390x@0.19.9:
@ -240,7 +238,6 @@ packages:
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-x64@0.19.9:
@ -249,7 +246,6 @@ packages:
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/netbsd-x64@0.19.9:
@ -258,7 +254,6 @@ packages:
cpu: [x64]
os: [netbsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/openbsd-x64@0.19.9:
@ -267,7 +262,6 @@ packages:
cpu: [x64]
os: [openbsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/sunos-x64@0.19.9:
@ -276,7 +270,6 @@ packages:
cpu: [x64]
os: [sunos]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-arm64@0.19.9:
@ -285,7 +278,6 @@ packages:
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-ia32@0.19.9:
@ -294,7 +286,6 @@ packages:
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-x64@0.19.9:
@ -303,7 +294,6 @@ packages:
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@eslint-community/eslint-utils@4.4.0(eslint@8.56.0):
@ -343,6 +333,23 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/@floating-ui/core@1.5.2:
resolution: {integrity: sha512-Ii3MrfY/GAIN3OhXNzpCKaLxHQfJF9qvwq/kEJYdqDxeIHa01K8sldugal6TmeeXl+WMvhv9cnVzUTaFFJF09A==}
dependencies:
'@floating-ui/utils': 0.1.6
dev: false
/@floating-ui/dom@1.5.3:
resolution: {integrity: sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==}
dependencies:
'@floating-ui/core': 1.5.2
'@floating-ui/utils': 0.1.6
dev: false
/@floating-ui/utils@0.1.6:
resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==}
dev: false
/@humanwhocodes/config-array@0.11.13:
resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==}
engines: {node: '>=10.10.0'}
@ -363,6 +370,12 @@ packages:
resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
dev: true
/@internationalized/date@3.5.0:
resolution: {integrity: sha512-nw0Q+oRkizBWMioseI8+2TeUPEyopJVz5YxoYVzR0W1v+2YytiYah7s/ot35F149q/xAg4F1gT/6eTd+tsUpFQ==}
dependencies:
'@swc/helpers': 0.5.3
dev: false
/@jridgewell/gen-mapping@0.3.3:
resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
engines: {node: '>=6.0.0'}
@ -388,6 +401,20 @@ packages:
'@jridgewell/resolve-uri': 3.1.1
'@jridgewell/sourcemap-codec': 1.4.15
/@melt-ui/svelte@0.65.2(svelte@4.2.8):
resolution: {integrity: sha512-BpsSl9Bjp1++8U3+LaDOFUoX/PFQ9N7QWFhlFdUEZduhrbVyU70v9A459SKrQ+esFSjvh1AvqJYkMAUJXJlAmQ==}
peerDependencies:
svelte: '>=3 <5'
dependencies:
'@floating-ui/core': 1.5.2
'@floating-ui/dom': 1.5.3
'@internationalized/date': 3.5.0
dequal: 2.0.3
focus-trap: 7.5.4
nanoid: 4.0.2
svelte: 4.2.8
dev: false
/@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@ -408,14 +435,12 @@ packages:
/@polka/url@1.0.0-next.24:
resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==}
dev: true
/@rollup/rollup-android-arm-eabi@4.9.0:
resolution: {integrity: sha512-+1ge/xmaJpm1KVBuIH38Z94zj9fBD+hp+/5WLaHgyY8XLq1ibxk/zj6dTXaqM2cAbYKq8jYlhHd6k05If1W5xA==}
cpu: [arm]
os: [android]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-android-arm64@4.9.0:
@ -423,7 +448,6 @@ packages:
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-darwin-arm64@4.9.0:
@ -431,7 +455,6 @@ packages:
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-darwin-x64@4.9.0:
@ -439,7 +462,6 @@ packages:
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-linux-arm-gnueabihf@4.9.0:
@ -447,7 +469,6 @@ packages:
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-linux-arm64-gnu@4.9.0:
@ -455,7 +476,6 @@ packages:
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-linux-arm64-musl@4.9.0:
@ -463,7 +483,6 @@ packages:
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-linux-riscv64-gnu@4.9.0:
@ -471,7 +490,6 @@ packages:
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-linux-x64-gnu@4.9.0:
@ -479,7 +497,6 @@ packages:
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-linux-x64-musl@4.9.0:
@ -487,7 +504,6 @@ packages:
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-win32-arm64-msvc@4.9.0:
@ -495,7 +511,6 @@ packages:
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-win32-ia32-msvc@4.9.0:
@ -503,7 +518,6 @@ packages:
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-win32-x64-msvc@4.9.0:
@ -511,7 +525,6 @@ packages:
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@sveltejs/adapter-auto@3.0.0(@sveltejs/kit@2.0.1):
@ -547,7 +560,6 @@ packages:
svelte: 4.2.8
tiny-glob: 0.2.9
vite: 5.0.10
dev: true
/@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.8)(vite@5.0.10):
resolution: {integrity: sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==}
@ -563,7 +575,6 @@ packages:
vite: 5.0.10
transitivePeerDependencies:
- supports-color
dev: true
/@sveltejs/vite-plugin-svelte@3.0.1(svelte@4.2.8)(vite@5.0.10):
resolution: {integrity: sha512-CGURX6Ps+TkOovK6xV+Y2rn8JKa8ZPUHPZ/NKgCxAmgBrXReavzFl8aOSCj3kQ1xqT7yGJj53hjcV/gqwDAaWA==}
@ -583,11 +594,15 @@ packages:
vitefu: 0.2.5(vite@5.0.10)
transitivePeerDependencies:
- supports-color
dev: true
/@swc/helpers@0.5.3:
resolution: {integrity: sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==}
dependencies:
tslib: 2.6.2
dev: false
/@types/cookie@0.6.0:
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
dev: true
/@types/estree@1.0.5:
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
@ -828,6 +843,17 @@ packages:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
/bits-ui@0.11.8(svelte@4.2.8):
resolution: {integrity: sha512-T3YaT88OJguBoUU/MSncf41fiIc+5/ka8Au2LUDo0nSECex+LFY40+hKWLJc5tRT56avkyHsI7x9daA2r9eS/g==}
peerDependencies:
svelte: ^4.0.0
dependencies:
'@internationalized/date': 3.5.0
'@melt-ui/svelte': 0.65.2(svelte@4.2.8)
nanoid: 5.0.4
svelte: 4.2.8
dev: false
/brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
@ -925,7 +951,6 @@ packages:
/cookie@0.6.0:
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
engines: {node: '>= 0.6'}
dev: true
/cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
@ -958,7 +983,6 @@ packages:
optional: true
dependencies:
ms: 2.1.2
dev: true
/deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@ -967,7 +991,6 @@ packages:
/deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
dev: true
/dequal@2.0.3:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
@ -980,7 +1003,6 @@ packages:
/devalue@4.3.2:
resolution: {integrity: sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==}
dev: true
/didyoumean@1.2.2:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
@ -1038,7 +1060,6 @@ packages:
'@esbuild/win32-arm64': 0.19.9
'@esbuild/win32-ia32': 0.19.9
'@esbuild/win32-x64': 0.19.9
dev: true
/escalade@3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
@ -1159,7 +1180,6 @@ packages:
/esm-env@1.0.0:
resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==}
dev: true
/espree@9.6.1:
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
@ -1260,6 +1280,24 @@ packages:
resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==}
dev: true
/focus-trap@7.5.4:
resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==}
dependencies:
tabbable: 6.2.0
dev: false
/formsnap@0.4.1(svelte@4.2.8)(sveltekit-superforms@1.12.0)(zod@3.22.4):
resolution: {integrity: sha512-hUOaDKb+KoBi4PamJRnxRqIQW3msp2BKPqohoqjHUuBb+vgBrhoaz0WYEFkXG4bzVQS3JngG55m/zX5ciZTyeA==}
peerDependencies:
svelte: ^4.0.0
sveltekit-superforms: ^1.7.1
zod: ^3.22.2
dependencies:
svelte: 4.2.8
sveltekit-superforms: 1.12.0(@sveltejs/kit@2.0.1)(svelte@4.2.8)(zod@3.22.4)
zod: 3.22.4
dev: false
/fraction.js@4.3.7:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
dev: true
@ -1319,7 +1357,6 @@ packages:
/globalyzer@0.1.0:
resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==}
dev: true
/globby@11.1.0:
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
@ -1335,7 +1372,6 @@ packages:
/globrex@0.1.2:
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
dev: true
/graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
@ -1458,7 +1494,6 @@ packages:
/kleur@4.1.5:
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
engines: {node: '>=6'}
dev: true
/known-css-properties@0.29.0:
resolution: {integrity: sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==}
@ -1571,16 +1606,13 @@ packages:
/mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
dev: true
/mrmime@1.0.1:
resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==}
engines: {node: '>=10'}
dev: true
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: true
/mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
@ -1594,6 +1626,18 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
/nanoid@4.0.2:
resolution: {integrity: sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==}
engines: {node: ^14 || ^16 || >=18}
hasBin: true
dev: false
/nanoid@5.0.4:
resolution: {integrity: sha512-vAjmBf13gsmhXSgBrtIclinISzFFy22WwCYoyilZlsrRXNIHSwgFQ1bEdjRwMT3aoadeIF6HMuDRlOxzfXV8ig==}
engines: {node: ^18 || >=20}
hasBin: true
dev: false
/natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: true
@ -1963,7 +2007,6 @@ packages:
'@rollup/rollup-win32-ia32-msvc': 4.9.0
'@rollup/rollup-win32-x64-msvc': 4.9.0
fsevents: 2.3.3
dev: true
/run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
@ -1975,7 +2018,6 @@ packages:
engines: {node: '>=6'}
dependencies:
mri: 1.2.0
dev: true
/sander@0.5.1:
resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==}
@ -1996,7 +2038,6 @@ packages:
/set-cookie-parser@2.6.0:
resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==}
dev: true
/shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
@ -2017,7 +2058,6 @@ packages:
'@polka/url': 1.0.0-next.24
mrmime: 1.0.1
totalist: 3.0.1
dev: true
/slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
@ -2132,7 +2172,6 @@ packages:
svelte: ^3.19.0 || ^4.0.0
dependencies:
svelte: 4.2.8
dev: true
/svelte-preprocess@5.1.2(postcss-load-config@5.0.2)(postcss@8.4.32)(svelte@4.2.8)(typescript@5.3.3):
resolution: {integrity: sha512-XF0aliMAcYnP4hLETvB6HRAMnaL09ASYT1Z2I1Gwu0nz6xbdg/dSgAEthtFZJA4AKrNhFDFdmUDO+H9d/6xg5g==}
@ -2201,6 +2240,22 @@ packages:
magic-string: 0.30.5
periscopic: 3.1.0
/sveltekit-superforms@1.12.0(@sveltejs/kit@2.0.1)(svelte@4.2.8)(zod@3.22.4):
resolution: {integrity: sha512-yer9YKhfWsKsDIxXahFLuGuUel32gyi96qIdxTVFAOWXZM9ZaMEP7+FL2cMYRDg6Xqlrh5SQ9oQdkVYeLNG0eA==}
peerDependencies:
'@sveltejs/kit': 1.x || 2.x
svelte: 3.x || 4.x
zod: 3.x
dependencies:
'@sveltejs/kit': 2.0.1(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.8)(vite@5.0.10)
svelte: 4.2.8
zod: 3.22.4
dev: false
/tabbable@6.2.0:
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
dev: false
/tailwind-merge@1.14.0:
resolution: {integrity: sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==}
dev: false
@ -2271,7 +2326,6 @@ packages:
dependencies:
globalyzer: 0.1.0
globrex: 0.1.2
dev: true
/to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
@ -2282,7 +2336,6 @@ packages:
/totalist@3.0.1:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
dev: true
/ts-api-utils@1.0.3(typescript@5.3.3):
resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==}
@ -2298,7 +2351,6 @@ packages:
/tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
dev: true
/type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
@ -2371,7 +2423,6 @@ packages:
rollup: 4.9.0
optionalDependencies:
fsevents: 2.3.3
dev: true
/vitefu@0.2.5(vite@5.0.10):
resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==}
@ -2382,7 +2433,6 @@ packages:
optional: true
dependencies:
vite: 5.0.10
dev: true
/which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
@ -2412,3 +2462,7 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: true
/zod@3.22.4:
resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
dev: false

View File

@ -0,0 +1,25 @@
<script lang="ts">
import { Button as ButtonPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
import { buttonVariants, type Props, type Events } from ".";
type $$Props = Props;
type $$Events = Events;
let className: $$Props["class"] = undefined;
export let variant: $$Props["variant"] = "default";
export let size: $$Props["size"] = "default";
export let builders: $$Props["builders"] = [];
export { className as class };
</script>
<ButtonPrimitive.Root
{builders}
class={cn(buttonVariants({ variant, size, className }))}
type="button"
{...$$restProps}
on:click
on:keydown
>
<slot />
</ButtonPrimitive.Root>

View File

@ -0,0 +1,51 @@
import Root from "./button.svelte";
import { tv, type VariantProps } from "tailwind-variants";
import type { Button as ButtonPrimitive } from "bits-ui";
const buttonVariants = tv({
base: "inline-flex items-center justify-center rounded-md text-sm font-medium whitespace-nowrap ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline"
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10"
}
},
defaultVariants: {
variant: "default",
size: "default"
}
});
type Variant = VariantProps<typeof buttonVariants>["variant"];
type Size = VariantProps<typeof buttonVariants>["size"];
type Props = ButtonPrimitive.Props & {
variant?: Variant;
size?: Size;
};
type Events = ButtonPrimitive.Events;
export {
Root,
type Props,
type Events,
//
Root as Button,
type Props as ButtonProps,
type Events as ButtonEvents,
buttonVariants
};

View File

@ -0,0 +1,34 @@
<script lang="ts">
import { Checkbox as CheckboxPrimitive } from "bits-ui";
import { Check, Minus } from "lucide-svelte";
import { cn } from "$lib/utils";
type $$Props = CheckboxPrimitive.Props;
type $$Events = CheckboxPrimitive.Events;
let className: $$Props["class"] = undefined;
export let checked: $$Props["checked"] = false;
export { className as class };
</script>
<CheckboxPrimitive.Root
class={cn(
"box-content peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50",
className
)}
bind:checked
{...$$restProps}
on:click
>
<CheckboxPrimitive.Indicator
class={cn("flex items-center justify-center text-current h-4 w-4")}
let:isChecked
let:isIndeterminate
>
{#if isChecked}
<Check class="h-3.5 w-3.5" />
{:else if isIndeterminate}
<Minus class="h-3.5 w-3.5" />
{/if}
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>

View File

@ -0,0 +1,6 @@
import Root from "./checkbox.svelte";
export {
Root,
//
Root as Checkbox
};

View File

@ -0,0 +1,9 @@
<script lang="ts">
import * as Button from "$lib/components/ui/button";
type $$Props = Button.Props;
type $$Events = Button.Events;
</script>
<Button.Root type="submit" {...$$restProps} on:click on:keydown>
<slot />
</Button.Root>

View File

@ -0,0 +1,26 @@
<script lang="ts">
import { getFormField } from "formsnap";
import type { Checkbox as CheckboxPrimitive } from "bits-ui";
import { Checkbox } from "$lib/components/ui/checkbox";
type $$Props = CheckboxPrimitive.Props;
type $$Events = CheckboxPrimitive.Events;
export let onCheckedChange: $$Props["onCheckedChange"] = undefined;
const { name, setValue, attrStore, value } = getFormField();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { name: nameAttr, value: valueAttr, ...rest } = $attrStore;
</script>
<Checkbox
{...rest}
checked={typeof $value === "boolean" ? $value : false}
onCheckedChange={(v) => {
onCheckedChange?.(v);
setValue(v);
}}
{...$$restProps}
on:click
on:keydown
/>
<input hidden {name} value={$value} />

View File

@ -0,0 +1,16 @@
<script lang="ts">
import { Form as FormPrimitive } from "formsnap";
import { cn } from "$lib/utils";
import type { HTMLAttributes } from "svelte/elements";
type $$Props = HTMLAttributes<HTMLSpanElement>;
let className: string | undefined | null = undefined;
export { className as class };
</script>
<FormPrimitive.Description
class={cn("text-sm text-muted-foreground", className)}
{...$$restProps}
>
<slot />
</FormPrimitive.Description>

View File

@ -0,0 +1,28 @@
<script lang="ts">
import { getFormField } from "formsnap";
import type { HTMLInputAttributes } from "svelte/elements";
import { Input, type InputEvents } from "$lib/components/ui/input";
type $$Props = HTMLInputAttributes;
type $$Events = InputEvents;
const { attrStore, value } = getFormField();
</script>
<Input
{...$attrStore}
bind:value={$value}
{...$$restProps}
on:blur
on:change
on:click
on:focus
on:keydown
on:keypress
on:keyup
on:mouseover
on:mouseenter
on:mouseleave
on:paste
on:input
/>

View File

@ -0,0 +1,12 @@
<script lang="ts">
import { cn } from "$lib/utils";
import type { HTMLAttributes } from "svelte/elements";
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: string | undefined | null = undefined;
export { className as class };
</script>
<div class={cn("space-y-2", className)} {...$$restProps}>
<slot />
</div>

View File

@ -0,0 +1,21 @@
<script lang="ts">
import type { Label as LabelPrimitive } from "bits-ui";
import { getFormField } from "formsnap";
import { cn } from "$lib/utils";
import { Label } from "$lib/components/ui/label";
type $$Props = LabelPrimitive.Props;
let className: $$Props["class"] = undefined;
export { className as class };
const { errors, ids } = getFormField();
</script>
<Label
for={$ids.input}
class={cn($errors && "text-destructive", className)}
{...$$restProps}
>
<slot />
</Label>

View File

@ -0,0 +1,26 @@
<script lang="ts">
import { Form as FormPrimitive } from "formsnap";
import { buttonVariants } from "$lib/components/ui/button";
import { cn } from "$lib/utils";
import { ChevronDown } from "lucide-svelte";
import type { HTMLSelectAttributes } from "svelte/elements";
type $$Props = HTMLSelectAttributes;
let className: string | undefined | null = undefined;
export { className as class };
</script>
<div class="relative">
<FormPrimitive.Select
class={cn(
buttonVariants({ variant: "outline" }),
"appearance-none bg-transparent font-normal",
className
)}
{...$$restProps}
>
<slot />
</FormPrimitive.Select>
<ChevronDown class="absolute right-3 top-2.5 h-4 w-4 opacity-50" />
</div>

View File

@ -0,0 +1,22 @@
<script lang="ts">
import { getFormField } from "formsnap";
import type { RadioGroup as RadioGroupPrimitive } from "bits-ui";
import * as RadioGroup from "$lib/components/ui/radio-group";
type $$Props = RadioGroupPrimitive.Props;
const { attrStore, setValue, name, value } = getFormField();
export let onValueChange: $$Props["onValueChange"] = undefined;
</script>
<RadioGroup.Root
{...$attrStore}
onValueChange={(v) => {
onValueChange?.(v);
setValue(v);
}}
{...$$restProps}
>
<slot />
<input hidden {name} value={$value} />
</RadioGroup.Root>

View File

@ -0,0 +1,23 @@
<script lang="ts">
import * as Select from "$lib/components/ui/select";
import type { Select as SelectPrimitive } from "bits-ui";
import { getFormField } from "formsnap";
type $$Props = SelectPrimitive.TriggerProps & {
placeholder?: string;
};
type $$Events = SelectPrimitive.TriggerEvents;
const { attrStore } = getFormField();
export let placeholder = "";
</script>
<Select.Trigger
{...$$restProps}
{...$attrStore}
on:click
on:keydown
type="button"
>
<Select.Value {placeholder} />
<slot />
</Select.Trigger>

View File

@ -0,0 +1,20 @@
<script lang="ts">
import * as Select from "$lib/components/ui/select";
import { getFormField } from "formsnap";
import type { Select as SelectPrimitive } from "bits-ui";
type $$Props = SelectPrimitive.Props<unknown>;
const { setValue, name, value } = getFormField();
export let onSelectedChange: $$Props["onSelectedChange"] = undefined;
</script>
<Select.Root
onSelectedChange={(v) => {
onSelectedChange?.(v);
setValue(v ? v.value : undefined);
}}
{...$$restProps}
>
<slot />
<input hidden {name} value={$value} />
</Select.Root>

View File

@ -0,0 +1,24 @@
<script lang="ts">
import { getFormField } from "formsnap";
import type { Switch as SwitchPrimitive } from "bits-ui";
import { Switch } from "$lib/components/ui/switch";
type $$Props = SwitchPrimitive.Props;
type $$Events = SwitchPrimitive.Events;
export let onCheckedChange: $$Props["onCheckedChange"] = undefined;
const { name, setValue, attrStore, value } = getFormField();
</script>
<Switch
{...$attrStore}
checked={typeof $value === "boolean" ? $value : false}
onCheckedChange={(v) => {
onCheckedChange?.(v);
setValue(v);
}}
{...$$restProps}
on:click
on:keydown
/>
<input hidden {name} value={$value} />

View File

@ -0,0 +1,32 @@
<script lang="ts">
import { getFormField } from "formsnap";
import type { HTMLTextareaAttributes } from "svelte/elements";
import type { TextareaGetFormField } from ".";
import {
Textarea,
type TextareaEvents
} from "$lib/components/ui/textarea";
type $$Props = HTMLTextareaAttributes;
type $$Events = TextareaEvents;
const { attrStore, value } = getFormField() as TextareaGetFormField;
</script>
<Textarea
{...$attrStore}
bind:value={$value}
{...$$restProps}
on:blur
on:change
on:click
on:focus
on:keydown
on:keypress
on:keyup
on:mouseover
on:mouseenter
on:mouseleave
on:paste
on:input
/>

View File

@ -0,0 +1,14 @@
<script lang="ts">
import { Form as FormPrimitive } from "formsnap";
import { cn } from "$lib/utils";
import type { HTMLAttributes } from "svelte/elements";
type $$Props = HTMLAttributes<HTMLParagraphElement>;
let className: string | undefined | null = undefined;
export { className as class };
</script>
<FormPrimitive.Validation
class={cn("text-sm font-medium text-destructive", className)}
{...$$restProps}
/>

View File

@ -0,0 +1,85 @@
import { Form as FormPrimitive, getFormField } from "formsnap";
import * as RadioGroupComp from "$lib/components/ui/radio-group";
import * as SelectComp from "$lib/components/ui/select";
import type { Writable } from "svelte/store";
import Item from "./form-item.svelte";
import Input from "./form-input.svelte";
import Textarea from "./form-textarea.svelte";
import Description from "./form-description.svelte";
import Label from "./form-label.svelte";
import Validation from "./form-validation.svelte";
import Checkbox from "./form-checkbox.svelte";
import Switch from "./form-switch.svelte";
import NativeSelect from "./form-native-select.svelte";
import RadioGroup from "./form-radio-group.svelte";
import Select from "./form-select.svelte";
import SelectTrigger from "./form-select-trigger.svelte";
import Button from "./form-button.svelte";
const Root = FormPrimitive.Root;
const Field = FormPrimitive.Field;
const Control = FormPrimitive.Control;
const RadioItem = RadioGroupComp.Item;
const NativeRadio = FormPrimitive.Radio;
const SelectContent = SelectComp.Content;
const SelectLabel = SelectComp.Label;
const SelectGroup = SelectComp.Group;
const SelectItem = SelectComp.Item;
const SelectSeparator = SelectComp.Separator;
export type TextareaGetFormField = Omit<
ReturnType<typeof getFormField>,
"value"
> & {
value: Writable<string>;
};
export {
Root,
Field,
Control,
Item,
Input,
Label,
Button,
Switch,
Select,
Checkbox,
Textarea,
Validation,
RadioGroup,
RadioItem,
Description,
SelectContent,
SelectLabel,
SelectGroup,
SelectItem,
SelectSeparator,
SelectTrigger,
NativeSelect,
NativeRadio,
//
Root as Form,
Field as FormField,
Control as FormControl,
Item as FormItem,
Input as FormInput,
Textarea as FormTextarea,
Description as FormDescription,
Label as FormLabel,
Validation as FormValidation,
NativeSelect as FormNativeSelect,
NativeRadio as FormNativeRadio,
Checkbox as FormCheckbox,
Switch as FormSwitch,
RadioGroup as FormRadioGroup,
RadioItem as FormRadioItem,
Select as FormSelect,
SelectContent as FormSelectContent,
SelectLabel as FormSelectLabel,
SelectGroup as FormSelectGroup,
SelectItem as FormSelectItem,
SelectSeparator as FormSelectSeparator,
SelectTrigger as FormSelectTrigger,
Button as FormButton
};

View File

@ -0,0 +1,25 @@
import Root from "./input.svelte";
type FormInputEvent<T extends Event = Event> = T & {
currentTarget: EventTarget & HTMLInputElement;
};
export type InputEvents = {
blur: FormInputEvent<FocusEvent>;
change: FormInputEvent<Event>;
click: FormInputEvent<MouseEvent>;
focus: FormInputEvent<FocusEvent>;
keydown: FormInputEvent<KeyboardEvent>;
keypress: FormInputEvent<KeyboardEvent>;
keyup: FormInputEvent<KeyboardEvent>;
mouseover: FormInputEvent<MouseEvent>;
mouseenter: FormInputEvent<MouseEvent>;
mouseleave: FormInputEvent<MouseEvent>;
paste: FormInputEvent<ClipboardEvent>;
input: FormInputEvent<InputEvent>;
};
export {
Root,
//
Root as Input
};

View File

@ -0,0 +1,33 @@
<script lang="ts">
import type { HTMLInputAttributes } from "svelte/elements";
import { cn } from "$lib/utils";
import type { InputEvents } from ".";
type $$Props = HTMLInputAttributes;
type $$Events = InputEvents;
let className: $$Props["class"] = undefined;
export let value: $$Props["value"] = undefined;
export { className as class };
</script>
<input
class={cn(
"flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-foreground file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
bind:value
on:blur
on:change
on:click
on:focus
on:keydown
on:keypress
on:keyup
on:mouseover
on:mouseenter
on:mouseleave
on:paste
on:input
{...$$restProps}
/>

View File

@ -0,0 +1,7 @@
import Root from "./label.svelte";
export {
Root,
//
Root as Label
};

View File

@ -0,0 +1,21 @@
<script lang="ts">
import { Label as LabelPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = LabelPrimitive.Props;
type $$Events = LabelPrimitive.Events;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<LabelPrimitive.Root
class={cn(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
className
)}
{...$$restProps}
on:mousedown
>
<slot />
</LabelPrimitive.Root>

View File

@ -0,0 +1,15 @@
import { RadioGroup as RadioGroupPrimitive } from "bits-ui";
import Root from "./radio-group.svelte";
import Item from "./radio-group-item.svelte";
const Input = RadioGroupPrimitive.Input;
export {
Root,
Input,
Item,
//
Root as RadioGroup,
Input as RadioGroupInput,
Item as RadioGroupItem
};

View File

@ -0,0 +1,28 @@
<script lang="ts">
import { RadioGroup as RadioGroupPrimitive } from "bits-ui";
import { Circle } from "lucide-svelte";
import { cn } from "$lib/utils";
type $$Props = RadioGroupPrimitive.ItemProps;
type $$Events = RadioGroupPrimitive.ItemEvents;
let className: $$Props["class"] = undefined;
export let value: $$Props["value"];
export { className as class };
</script>
<RadioGroupPrimitive.Item
{value}
class={cn(
"aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...$$restProps}
on:click
>
<div class="flex items-center justify-center">
<RadioGroupPrimitive.ItemIndicator>
<Circle class="h-2.5 w-2.5 fill-current text-current" />
</RadioGroupPrimitive.ItemIndicator>
</div>
</RadioGroupPrimitive.Item>

View File

@ -0,0 +1,18 @@
<script lang="ts">
import { RadioGroup as RadioGroupPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = RadioGroupPrimitive.Props;
let className: $$Props["class"] = undefined;
export let value: $$Props["value"] = undefined;
export { className as class };
</script>
<RadioGroupPrimitive.Root
bind:value
class={cn("grid gap-2", className)}
{...$$restProps}
>
<slot />
</RadioGroupPrimitive.Root>

View File

@ -0,0 +1,34 @@
import { Select as SelectPrimitive } from "bits-ui";
import Label from "./select-label.svelte";
import Item from "./select-item.svelte";
import Content from "./select-content.svelte";
import Trigger from "./select-trigger.svelte";
import Separator from "./select-separator.svelte";
const Root = SelectPrimitive.Root;
const Group = SelectPrimitive.Group;
const Input = SelectPrimitive.Input;
const Value = SelectPrimitive.Value;
export {
Root,
Group,
Input,
Label,
Item,
Value,
Content,
Trigger,
Separator,
//
Root as Select,
Group as SelectGroup,
Input as SelectInput,
Label as SelectLabel,
Item as SelectItem,
Value as SelectValue,
Content as SelectContent,
Trigger as SelectTrigger,
Separator as SelectSeparator
};

View File

@ -0,0 +1,39 @@
<script lang="ts">
import { Select as SelectPrimitive } from "bits-ui";
import { cn, flyAndScale } from "$lib/utils";
import { scale } from "svelte/transition";
type $$Props = SelectPrimitive.ContentProps;
type $$Events = SelectPrimitive.ContentEvents;
export let sideOffset: $$Props["sideOffset"] = 4;
export let inTransition: $$Props["inTransition"] = flyAndScale;
export let inTransitionConfig: $$Props["inTransitionConfig"] = undefined;
export let outTransition: $$Props["outTransition"] = scale;
export let outTransitionConfig: $$Props["outTransitionConfig"] = {
start: 0.95,
opacity: 0,
duration: 50
};
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<SelectPrimitive.Content
{inTransition}
{inTransitionConfig}
{outTransition}
{outTransitionConfig}
{sideOffset}
class={cn(
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md outline-none",
className
)}
{...$$restProps}
on:keydown
>
<div class="w-full p-1">
<slot />
</div>
</SelectPrimitive.Content>

View File

@ -0,0 +1,38 @@
<script lang="ts">
import { cn } from "$lib/utils";
import { Select as SelectPrimitive } from "bits-ui";
import { Check } from "lucide-svelte";
type $$Props = SelectPrimitive.ItemProps;
type $$Events = SelectPrimitive.ItemEvents;
let className: $$Props["class"] = undefined;
export let value: $$Props["value"];
export let label: $$Props["label"] = undefined;
export let disabled: $$Props["disabled"] = undefined;
export { className as class };
</script>
<SelectPrimitive.Item
{value}
{disabled}
{label}
class={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerleave
on:pointermove
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check class="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>
<slot />
</SelectPrimitive.Item>

View File

@ -0,0 +1,16 @@
<script lang="ts">
import { Select as SelectPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = SelectPrimitive.LabelProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<SelectPrimitive.Label
class={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
{...$$restProps}
>
<slot />
</SelectPrimitive.Label>

View File

@ -0,0 +1,14 @@
<script lang="ts">
import { Select as SelectPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = SelectPrimitive.SeparatorProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<SelectPrimitive.Separator
class={cn("-mx-1 my-1 h-px bg-muted", className)}
{...$$restProps}
/>

View File

@ -0,0 +1,27 @@
<script lang="ts">
import { Select as SelectPrimitive } from "bits-ui";
import { ChevronDown } from "lucide-svelte";
import { cn } from "$lib/utils";
type $$Props = SelectPrimitive.TriggerProps;
type $$Events = SelectPrimitive.TriggerEvents;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<SelectPrimitive.Trigger
class={cn(
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...$$restProps}
let:builder
on:click
on:keydown
>
<slot {builder} />
<div>
<ChevronDown class="h-4 w-4 opacity-50" />
</div>
</SelectPrimitive.Trigger>

View File

@ -0,0 +1,7 @@
import Root from "./switch.svelte";
export {
Root,
//
Root as Switch
};

View File

@ -0,0 +1,25 @@
<script lang="ts">
import { Switch as SwitchPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = SwitchPrimitive.Props;
let className: $$Props["class"] = undefined;
export let checked: $$Props["checked"] = undefined;
export { className as class };
</script>
<SwitchPrimitive.Root
bind:checked
class={cn(
"peer inline-flex h-[24px] w-[44px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
className
)}
{...$$restProps}
>
<SwitchPrimitive.Thumb
class={cn(
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
)}
/>
</SwitchPrimitive.Root>

View File

@ -0,0 +1,28 @@
import Root from "./textarea.svelte";
type FormTextareaEvent<T extends Event = Event> = T & {
currentTarget: EventTarget & HTMLTextAreaElement;
};
type TextareaEvents = {
blur: FormTextareaEvent<FocusEvent>;
change: FormTextareaEvent<Event>;
click: FormTextareaEvent<MouseEvent>;
focus: FormTextareaEvent<FocusEvent>;
keydown: FormTextareaEvent<KeyboardEvent>;
keypress: FormTextareaEvent<KeyboardEvent>;
keyup: FormTextareaEvent<KeyboardEvent>;
mouseover: FormTextareaEvent<MouseEvent>;
mouseenter: FormTextareaEvent<MouseEvent>;
mouseleave: FormTextareaEvent<MouseEvent>;
paste: FormTextareaEvent<ClipboardEvent>;
input: FormTextareaEvent<InputEvent>;
};
export {
Root,
//
Root as Textarea,
type TextareaEvents,
type FormTextareaEvent
};

View File

@ -0,0 +1,31 @@
<script lang="ts">
import type { HTMLTextareaAttributes } from "svelte/elements";
import { cn } from "$lib/utils";
type $$Props = HTMLTextareaAttributes;
let className: $$Props["class"] = undefined;
export let value: $$Props["value"] = undefined;
export { className as class };
</script>
<textarea
class={cn(
"flex min-h-[80px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
bind:value
on:blur
on:change
on:click
on:focus
on:keydown
on:keypress
on:keyup
on:mouseover
on:mouseenter
on:mouseleave
on:paste
on:input
{...$$restProps}
/>

View File

@ -1,33 +1,139 @@
<script lang="ts">
import { env } from "$env/dynamic/public";
import { env } from '$env/dynamic/public';
import { CheckCircle, XCircle } from 'lucide-svelte';
let public_base_url_set = Object.keys(env).includes("PUBLIC_BASE_URL");
const public_base_url_set = Object.keys(env).includes('PUBLIC_BASE_URL');
const public_session_token_expiry_time_set = Object.keys(env).includes('PUBLIC_SESSION_TOKEN_EXPIRY_TIME');
const public_auth_token_expiry_time_set = Object.keys(env).includes('PUBLIC_AUTH_TOKEN_EXPIRY_TIME');
const config_ok = public_base_url_set && public_auth_token_expiry_time_set && public_session_token_expiry_time_set;
</script>
<div class="w-screen h-screen p-4">
<h1 class="scroll-m-20 text-3xl font-extrabold tracking-tight lg:text-4xl">
Welcome to Trifid!
</h1>
{#if public_base_url_set}
{#if config_ok}
<p class="leading-7 [&:not(:first-child)]:mt-6">
If you're seeing this page, Trifid's web interface is <b
class="font-medium text-green-400 underline underline-offset-4">correctly configured</b> and ready to
class="font-medium text-green-400 underline underline-offset-4">correctly configured</b> and ready to
go! Perhaps you meant to visit the <a class="font-medium text-primary underline underline-offset-4"
href="/dashboard">dashboard</a>, or read the <a
class="font-medium text-primary underline underline-offset-4"
href="https://trifid.e3t.cc">documentation</a>.
class="font-medium text-primary underline underline-offset-4"
href="https://trifid.e3t.cc">documentation</a>.
</p>
{:else}
<p class="leading-7 [&:not(:first-child)]:mt-6">
If you're seeing this page, Trifid's web interface is installed and running, but <b
class="font-medium text-yellow-400 underline underline-offset-4">not correctly configured.</b> The <code
class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">PUBLIC_BASE_URL</code>
environment variable is not set. Set this variable to the publicly accessible base URL of your trifid-api
instance, and restart the web interface. Reload this page once you are done. Consult the <a
class="font-medium text-primary underline underline-offset-4"
href="https://trifid.e3t.cc">documentation</a> for more information.
class="font-medium text-yellow-400 underline underline-offset-4">not correctly configured.</b> One or more
environment variables are not set. See the table below for what variables need to be updated. Reload this
page once you are done. Consult the <a
class="font-medium text-primary underline underline-offset-4"
href="https://trifid.e3t.cc">documentation</a> for more information.
</p>
{/if}
<div class="my-6 w-full overflow-y-auto">
<table class="w-full">
<thead>
<tr class="m-0 border-t p-0">
<th
class="border px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right"
>
Environment Variable
</th>
<th
class="border px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right"
>
Set?
</th>
</tr>
</thead>
<tbody>
<tr class="m-0 border-t p-0">
<td
class="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right"
>
<code class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">
PUBLIC_BASE_URL
</code>
</td>
<td
class="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right"
>
{#if public_base_url_set}
<span class="text-green-500"><CheckCircle /></span>
{:else}
<span>
<span class="text-red-500 align-middle display-inline-block">
<XCircle />
</span>
<span class="text-red-500 align-middle display-inline-block">
Set <code class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">PUBLIC_BASE_URL</code> to the publicly accessible root URL of your API server.
</span>
</span>
{/if}
</td>
</tr>
<tr class="m-0 border-t p-0">
<td
class="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right"
>
<code class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">
PUBLIC_SESSION_TOKEN_EXPIRY_TIME
</code>
</td>
<td
class="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right"
>
{#if public_session_token_expiry_time_set}
<span class="text-green-500"><CheckCircle /></span>
{:else}
<span>
<span class="text-red-500 align-middle display-inline-block">
<XCircle />
</span>
<span class="text-red-500 align-middle display-inline-block">
Set <code class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">PUBLIC_SESSION_TOKEN_EXPIRY_TIME</code> to the same value you set in <code class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">tokens.session_token_expiry_seconds</code> in your trifid-api config.
</span>
</span>
{/if}
</td>
</tr>
<tr class="m-0 border-t p-0">
<td
class="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right"
>
<code class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">
PUBLIC_AUTH_TOKEN_EXPIRY_TIME
</code>
</td>
<td
class="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right"
>
{#if public_auth_token_expiry_time_set}
<span class="text-green-500"><CheckCircle /></span>
{:else}
<span>
<span class="text-red-500 align-middle display-inline-block">
<XCircle />
</span>
<span class="text-red-500 align-middle display-inline-block">
Set <code class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">PUBLIC_AUTH_TOKEN_EXPIRY_TIME</code> to the same value you set in <code class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">tokens.auth_token_expiry_seconds</code> in your trifid-api config.
</span>
</span>
{/if}
</td>
</tr>
</tbody>
</table>
</div>
</div>
<style lang="postcss">
:global(.lucide) {
display: inline-block !important;
}
</style>

View File

@ -0,0 +1,16 @@
import { redirect } from "@sveltejs/kit";
import { env } from "$env/dynamic/public";
export function load({ cookies, fetch }) {
const session = cookies.get("tfsession");
if (session === undefined) {
redirect(301, "/login");
}
const mfa = cookies.get("tfmfa");
if (mfa === undefined) {
redirect(301, "/mfa");
}
fetch(`${env.PUBLIC_BASE_URL}/`)
}

View File

@ -0,0 +1 @@
<slot></slot>

View File

View File

@ -0,0 +1,61 @@
import { redirect, fail } from "@sveltejs/kit";
import type { PageServerLoad, Actions } from "./$types";
import { superValidate, setError } from "sveltekit-superforms/server";
import { formSchema } from "./schema";
import { env } from "$env/dynamic/public";
export const load: PageServerLoad = async ({cookies}) => {
const session = cookies.get("tfsession");
const mfa = cookies.get("tfmfa");
if (session !== undefined) {
if (mfa === undefined) {
redirect(301, "/mfa");
} else {
redirect(301, "/login");
}
}
return {
form: await superValidate(formSchema)
};
};
export const actions: Actions = {
default: async (event) => {
const form = await superValidate(event, formSchema);
if (!form.valid) {
return fail(400, {form});
}
let resp;
try {
resp = await fetch(`${env.PUBLIC_BASE_URL}/v1/auth/magic-link`, {
method: 'POST',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
email: form.data.username
})
});
} catch (e) {
console.error(e);
setError(form, 'username', `Error contacting the API: ${e}`);
return fail(500, { form });
}
if (!resp.ok) {
let resp2 = await resp.json();
if (resp2.errors[0].code === "ERR_INVALID_EMAIL") {
return setError(form, 'username', 'User does not exist');
} else {
setError(form, 'username', `Server returned error response: ${resp2.errors[0].code} ${resp2.errors[0].message}`);
return fail(resp.code, { form });
}
}
redirect(301, "/login/sent");
}
}

View File

@ -0,0 +1,35 @@
<script lang="ts">
import * as Card from '$lib/components/ui/card';
import * as Form from '$lib/components/ui/form';
import type { PageData } from './$types';
import { formSchema, type FormSchema } from './schema';
import type { SuperValidated } from 'sveltekit-superforms';
export let data;
</script>
<div class="h-screen flex flex-col p-6 space-y-4 items-center justify-center">
<Card.Root class="w-[20em] justify-center content-center pt-5">
<Card.Header class="space-y-2 pb-0 pt-0">
<Card.Title>Login via email</Card.Title>
<Card.Description>Enter your email address, and we'll send you a link to log in.</Card.Description>
</Card.Header>
<Card.Content class="mt-2">
<Form.Root method="POST" form={data.form} schema={formSchema} let:config>
<Form.Field {config} name="username">
<Form.Item>
<Form.Label>Email</Form.Label>
<Form.Input placeholder="john.doe@yourdomain.com" />
<Form.Description>The email your Trifid account is associated with.</Form.Description>
<Form.Validation />
</Form.Item>
</Form.Field>
<Form.Button class="mt-2">Login</Form.Button>
</Form.Root>
</Card.Content>
<Card.Footer>
<span class="text-xs text-foreground/70">Don't have an account? <a
class="font-medium text-primary underline underline-offset-4" href="/signup">Create one!</a></span>
</Card.Footer>
</Card.Root>
</div>

View File

@ -0,0 +1,7 @@
import { z } from "zod";
export const formSchema = z.object({
username: z.string().email()
});
export type FormSchema = typeof formSchema;

View File

@ -0,0 +1,16 @@
<script lang="ts">
import * as Card from "$lib/components/ui/card";
</script>
<div class="h-screen flex flex-col p-6 space-y-4 items-center justify-center">
<Card.Root class="w-[20em] justify-center content-center pt-5">
<Card.Header class="space-y-2 pb-0 pt-0">
<Card.Title>Check your inbox</Card.Title>
<Card.Description>We sent you an email to finish logging in. Click the link in the email to complete the login process.</Card.Description>
</Card.Header>
<Card.Content class="mt-2">
<span class="text-xs text-foreground/70">Didn't get an email? <a
class="font-medium text-primary underline underline-offset-4" href="/login">Try again</a></span>
</Card.Content>
</Card.Root>
</div>

View File

@ -0,0 +1,61 @@
import { redirect, fail } from "@sveltejs/kit";
import type { PageServerLoad, Actions } from "./$types";
import { superValidate, setError } from "sveltekit-superforms/server";
import { formSchema } from "./schema";
import { env } from "$env/dynamic/public";
export const load: PageServerLoad = async ({cookies}) => {
const session = cookies.get("tfsession");
const mfa = cookies.get("tfmfa");
if (session !== undefined) {
if (mfa === undefined) {
redirect(301, "/mfa");
} else {
redirect(301, "/login");
}
}
return {
form: await superValidate(formSchema)
};
};
export const actions: Actions = {
default: async (event) => {
const form = await superValidate(event, formSchema);
if (!form.valid) {
return fail(400, {form});
}
let resp;
try {
resp = await fetch(`${env.PUBLIC_BASE_URL}/v1/signup`, {
method: 'POST',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
email: form.data.username
})
});
} catch (e) {
console.error(e);
setError(form, 'username', `Error contacting the API: ${e}`);
return fail(500, { form });
}
if (!resp.ok) {
let resp2 = await resp.json();
if (resp2.errors[0].code === "ERR_INVALID_EMAIL") {
return setError(form, 'username', 'User does not exist');
} else {
setError(form, 'username', `Server returned error response: ${resp2.errors[0].code} ${resp2.errors[0].message}`);
return fail(resp.code, { form });
}
}
redirect(301, "/signup/sent");
}
}

View File

@ -0,0 +1,35 @@
<script lang="ts">
import * as Card from '$lib/components/ui/card';
import * as Form from '$lib/components/ui/form';
import type { PageData } from './$types';
import { formSchema, type FormSchema } from './schema';
import type { SuperValidated } from 'sveltekit-superforms';
export let data;
</script>
<div class="h-screen flex flex-col p-6 space-y-4 items-center justify-center">
<Card.Root class="w-[20em] justify-center content-center pt-5">
<Card.Header class="space-y-2 pb-0 pt-0">
<Card.Title>Sign up with email</Card.Title>
<Card.Description>Enter your email address, and we'll send you a link to finish creating your account.</Card.Description>
</Card.Header>
<Card.Content class="mt-2">
<Form.Root method="POST" form={data.form} schema={formSchema} let:config>
<Form.Field {config} name="username">
<Form.Item>
<Form.Label>Email</Form.Label>
<Form.Input placeholder="john.doe@yourdomain.com" />
<Form.Description>The email to create your Trifid account with.</Form.Description>
<Form.Validation />
</Form.Item>
</Form.Field>
<Form.Button class="mt-2">Login</Form.Button>
</Form.Root>
</Card.Content>
<Card.Footer>
<span class="text-xs text-foreground/70">Already have an account? <a
class="font-medium text-primary underline underline-offset-4" href="/login">Log in!</a></span>
</Card.Footer>
</Card.Root>
</div>

View File

@ -0,0 +1,7 @@
import { z } from "zod";
export const formSchema = z.object({
username: z.string().email()
});
export type FormSchema = typeof formSchema;

View File

@ -0,0 +1,16 @@
<script lang="ts">
import * as Card from "$lib/components/ui/card";
</script>
<div class="h-screen flex flex-col p-6 space-y-4 items-center justify-center">
<Card.Root class="w-[20em] justify-center content-center pt-5">
<Card.Header class="space-y-2 pb-0 pt-0">
<Card.Title>Check your inbox</Card.Title>
<Card.Description>We sent you an email to finish signup. Click the link in the email to complete the registration process.</Card.Description>
</Card.Header>
<Card.Content class="mt-2">
<span class="text-xs text-foreground/70">Didn't get an email? <a
class="font-medium text-primary underline underline-offset-4" href="/signup">Try again</a></span>
</Card.Content>
</Card.Root>
</div>

View File

@ -6,7 +6,7 @@
# [server] contains options for the HTTP server used to serve the API.
[server]
# (Required) What IP and port to bind the HTTP listener to.
bind = { ip = "127.0.0.1", port = 8080 }
bind = { ip = "::", port = 8080 }
# How many worker threads to start. The higher the number, the more resources trifid-api will use while idle, but
# the more parallel requests it can handle.
# Optional. Defaults to the number of physical CPUs in the system.
@ -49,4 +49,4 @@ auth_token_expiry_seconds = 86400 # 24 hours
# (Required) (VERY IMPORTANT!) The per-instance encryption key used to encrypt sensitive data in the database.
# It is INCREDIBLY IMPORTANT that you change this value! It should be a 32-byte/256-bit hex-encoded randomly generated
# key.
data_encryption_key = "dd5aa62f0fd9b7fb4ff65567493f889557212f3a8e9587a79268161f9ae070a6"
data_encryption_key = "dd5aa62f0fd9b7fb4ff65567493f889557212f3a8e9587a79268161f9ae070a6"

View File

@ -66,7 +66,7 @@ pub fn create_signing_ca(
.map_err(|e| CryptographyError::PemSerializeError(e))?;
let cert_value =
serde_json::to_value(cert).map_err(|e| CryptographyError::JsonSerializeError(e))?;
serde_json::to_value(&cert).map_err(|e| CryptographyError::JsonSerializeError(e))?;
let lockbox_key = XChaCha20Poly1305::new_from_slice(
&hex::decode(&config.tokens.data_encryption_key)
@ -112,7 +112,7 @@ pub fn sign_cert_with_ca(
.map_err(|_| CryptographyError::InvalidKeyLength)?;
let salt_u24: [u8; 24] = ca
.salt
.salt.clone()
.try_into()
.map_err(|_| CryptographyError::InvalidSaltLength)?;