20 Commits

Author SHA1 Message Date
8956317197 bump: v0.0.4 -> v0.0.5 2025-03-18 21:42:25 -04:00
2361602b62 fix: use different release action 2025-03-18 21:40:43 -04:00
eba0067e1e bump: 0.0.3 -> 0.0.4 2025-03-18 21:25:42 -04:00
8d78f79fe2 fix: use nix develop in build action 2025-03-18 21:24:19 -04:00
5328e5b4a1 bump: 0.0.2 -> 0.0.3 2025-03-18 21:23:13 -04:00
81855d079f feat: release workflow 2025-03-18 21:21:16 -04:00
e857a14fd7 fix: add git dep 2025-03-18 19:25:18 -04:00
5e5a2cbaaa refactor: seperate default from trevstack in nix packages 2025-03-18 19:13:15 -04:00
267d293927 feat: linting 2025-03-18 19:02:50 -04:00
d8de02f789 refactor: move handlers into versioned dirs 2025-03-18 18:25:37 -04:00
be0981f7b7 feat: auth redirect 2025-03-18 17:46:54 -04:00
86b74e0ebc fix: conditional client build 2025-03-18 17:41:29 -04:00
21cd91156c fix: select dropdown transition 2025-03-18 17:05:21 -04:00
2abd44990f release: v0.0.1 -> v0.0.2 2025-03-18 16:40:01 -04:00
3915ecbdf9 refactor: ts-bump -> ts-release 2025-03-18 16:35:29 -04:00
5e90aec95b build(nix): updated nix hashes 2025-03-18 16:32:54 -04:00
617a96febd build(server): updated go dependencies 2025-03-18 16:32:14 -04:00
553f9e9073 build(client): updated npm dependencies 2025-03-18 16:32:13 -04:00
2b21243335 feat: ts-update, ts-bump 2025-03-18 16:31:10 -04:00
fb5b2af8ea fix: version fix 2025-03-18 14:23:31 -04:00
41 changed files with 1020 additions and 790 deletions

29
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,29 @@
name: Release Workflow
on:
push:
tags:
- '*'
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: Build
run: nix develop --command ts-build
- name: Create release
uses: softprops/action-gh-release@v2
with:
files: build/.

View File

@ -2,3 +2,13 @@
package-lock.json
pnpm-lock.yaml
yarn.lock
# Build output
.svelte-kit
node_modules
# Static
static
# Generated
src/lib/services

View File

@ -3,10 +3,7 @@
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": [
"prettier-plugin-svelte",
"prettier-plugin-tailwindcss"
],
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
"overrides": [
{
"files": "*.svelte",

View File

@ -6,7 +6,7 @@ import globals from 'globals';
import { fileURLToPath } from 'node:url';
import ts from 'typescript-eslint';
import svelteConfig from './svelte.config.js';
const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url));
const gitignorePath = fileURLToPath(new URL('./.prettierignore', import.meta.url));
export default ts.config(
includeIgnoreFile(gitignorePath),

230
client/package-lock.json generated
View File

@ -1,41 +1,41 @@
{
"name": "trevstack",
"version": "0.0.1",
"version": "0.0.5",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "trevstack",
"version": "0.0.1",
"version": "0.0.5",
"devDependencies": {
"@connectrpc/connect": "^2.0.2",
"@connectrpc/connect-web": "^2.0.2",
"@eslint/compat": "^1.2.5",
"@eslint/compat": "^1.2.7",
"@eslint/js": "^9.18.0",
"@lucide/svelte": "^0.479.0",
"@scalar/api-reference": "^1.28.1",
"@scalar/api-reference": "^1.28.5",
"@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/kit": "^2.16.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"@tailwindcss/vite": "^4.0.13",
"bits-ui": "^1.3.11",
"@sveltejs/kit": "^2.20.1",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@tailwindcss/vite": "^4.0.14",
"bits-ui": "^1.3.13",
"clsx": "^2.1.1",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-svelte": "^3.0.0",
"eslint": "^9.22.0",
"eslint-config-prettier": "^10.1.1",
"eslint-plugin-svelte": "^3.3.2",
"globals": "^16.0.0",
"prettier": "^3.4.2",
"prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.11",
"svelte": "^5.0.0",
"svelte-check": "^4.0.0",
"svelte": "^5.23.2",
"svelte-check": "^4.1.5",
"svelte-sonner": "^0.3.28",
"tailwind-merge": "^3.0.2",
"tailwindcss": "^4.0.13",
"tw-animate-css": "^1.2.0",
"typescript": "^5.0.0",
"typescript-eslint": "^8.20.0",
"vite": "^6.0.0"
"tw-animate-css": "^1.2.3",
"typescript": "^5.8.2",
"typescript-eslint": "^8.26.1",
"vite": "^6.2.2"
}
},
"node_modules/@ampproject/remapping": {
@ -103,9 +103,9 @@
}
},
"node_modules/@bufbuild/protobuf": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.2.3.tgz",
"integrity": "sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg==",
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.2.4.tgz",
"integrity": "sha512-P9xQgtMh71TA7tHTnbDe68zcI+TPnkyyfBIhGaUr4iUEIXN7yI01DyjmmdEwXTk5OlISBJYkoxCVj2dwmHqIkA==",
"dev": true,
"license": "(Apache-2.0 AND BSD-3-Clause)",
"peer": true
@ -1424,9 +1424,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz",
"integrity": "sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.36.0.tgz",
"integrity": "sha512-jgrXjjcEwN6XpZXL0HUeOVGfjXhPyxAbbhD0BlXUB+abTOpbPiN5Wb3kOT7yb+uEtATNYF5x5gIfwutmuBA26w==",
"cpu": [
"arm"
],
@ -1438,9 +1438,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.35.0.tgz",
"integrity": "sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.36.0.tgz",
"integrity": "sha512-NyfuLvdPdNUfUNeYKUwPwKsE5SXa2J6bCt2LdB/N+AxShnkpiczi3tcLJrm5mA+eqpy0HmaIY9F6XCa32N5yzg==",
"cpu": [
"arm64"
],
@ -1452,9 +1452,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz",
"integrity": "sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.36.0.tgz",
"integrity": "sha512-JQ1Jk5G4bGrD4pWJQzWsD8I1n1mgPXq33+/vP4sk8j/z/C2siRuxZtaUA7yMTf71TCZTZl/4e1bfzwUmFb3+rw==",
"cpu": [
"arm64"
],
@ -1466,9 +1466,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.35.0.tgz",
"integrity": "sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.36.0.tgz",
"integrity": "sha512-6c6wMZa1lrtiRsbDziCmjE53YbTkxMYhhnWnSW8R/yqsM7a6mSJ3uAVT0t8Y/DGt7gxUWYuFM4bwWk9XCJrFKA==",
"cpu": [
"x64"
],
@ -1480,9 +1480,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.35.0.tgz",
"integrity": "sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.36.0.tgz",
"integrity": "sha512-KXVsijKeJXOl8QzXTsA+sHVDsFOmMCdBRgFmBb+mfEb/7geR7+C8ypAml4fquUt14ZyVXaw2o1FWhqAfOvA4sg==",
"cpu": [
"arm64"
],
@ -1494,9 +1494,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.35.0.tgz",
"integrity": "sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.36.0.tgz",
"integrity": "sha512-dVeWq1ebbvByI+ndz4IJcD4a09RJgRYmLccwlQ8bPd4olz3Y213uf1iwvc7ZaxNn2ab7bjc08PrtBgMu6nb4pQ==",
"cpu": [
"x64"
],
@ -1508,9 +1508,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.35.0.tgz",
"integrity": "sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.36.0.tgz",
"integrity": "sha512-bvXVU42mOVcF4le6XSjscdXjqx8okv4n5vmwgzcmtvFdifQ5U4dXFYaCB87namDRKlUL9ybVtLQ9ztnawaSzvg==",
"cpu": [
"arm"
],
@ -1522,9 +1522,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.35.0.tgz",
"integrity": "sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.36.0.tgz",
"integrity": "sha512-JFIQrDJYrxOnyDQGYkqnNBtjDwTgbasdbUiQvcU8JmGDfValfH1lNpng+4FWlhaVIR4KPkeddYjsVVbmJYvDcg==",
"cpu": [
"arm"
],
@ -1536,9 +1536,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.35.0.tgz",
"integrity": "sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.36.0.tgz",
"integrity": "sha512-KqjYVh3oM1bj//5X7k79PSCZ6CvaVzb7Qs7VMWS+SlWB5M8p3FqufLP9VNp4CazJ0CsPDLwVD9r3vX7Ci4J56A==",
"cpu": [
"arm64"
],
@ -1550,9 +1550,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.35.0.tgz",
"integrity": "sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.36.0.tgz",
"integrity": "sha512-QiGnhScND+mAAtfHqeT+cB1S9yFnNQ/EwCg5yE3MzoaZZnIV0RV9O5alJAoJKX/sBONVKeZdMfO8QSaWEygMhw==",
"cpu": [
"arm64"
],
@ -1564,9 +1564,9 @@
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.35.0.tgz",
"integrity": "sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.36.0.tgz",
"integrity": "sha512-1ZPyEDWF8phd4FQtTzMh8FQwqzvIjLsl6/84gzUxnMNFBtExBtpL51H67mV9xipuxl1AEAerRBgBwFNpkw8+Lg==",
"cpu": [
"loong64"
],
@ -1578,9 +1578,9 @@
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.35.0.tgz",
"integrity": "sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.36.0.tgz",
"integrity": "sha512-VMPMEIUpPFKpPI9GZMhJrtu8rxnp6mJR3ZzQPykq4xc2GmdHj3Q4cA+7avMyegXy4n1v+Qynr9fR88BmyO74tg==",
"cpu": [
"ppc64"
],
@ -1592,9 +1592,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.35.0.tgz",
"integrity": "sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.36.0.tgz",
"integrity": "sha512-ttE6ayb/kHwNRJGYLpuAvB7SMtOeQnVXEIpMtAvx3kepFQeowVED0n1K9nAdraHUPJ5hydEMxBpIR7o4nrm8uA==",
"cpu": [
"riscv64"
],
@ -1606,9 +1606,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.35.0.tgz",
"integrity": "sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.36.0.tgz",
"integrity": "sha512-4a5gf2jpS0AIe7uBjxDeUMNcFmaRTbNv7NxI5xOCs4lhzsVyGR/0qBXduPnoWf6dGC365saTiwag8hP1imTgag==",
"cpu": [
"s390x"
],
@ -1620,9 +1620,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz",
"integrity": "sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.36.0.tgz",
"integrity": "sha512-5KtoW8UWmwFKQ96aQL3LlRXX16IMwyzMq/jSSVIIyAANiE1doaQsx/KRyhAvpHlPjPiSU/AYX/8m+lQ9VToxFQ==",
"cpu": [
"x64"
],
@ -1634,9 +1634,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.35.0.tgz",
"integrity": "sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.36.0.tgz",
"integrity": "sha512-sycrYZPrv2ag4OCvaN5js+f01eoZ2U+RmT5as8vhxiFz+kxwlHrsxOwKPSA8WyS+Wc6Epid9QeI/IkQ9NkgYyQ==",
"cpu": [
"x64"
],
@ -1648,9 +1648,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.35.0.tgz",
"integrity": "sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.36.0.tgz",
"integrity": "sha512-qbqt4N7tokFwwSVlWDsjfoHgviS3n/vZ8LK0h1uLG9TYIRuUTJC88E1xb3LM2iqZ/WTqNQjYrtmtGmrmmawB6A==",
"cpu": [
"arm64"
],
@ -1662,9 +1662,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.35.0.tgz",
"integrity": "sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.36.0.tgz",
"integrity": "sha512-t+RY0JuRamIocMuQcfwYSOkmdX9dtkr1PbhKW42AMvaDQa+jOdpUYysroTF/nuPpAaQMWp7ye+ndlmmthieJrQ==",
"cpu": [
"ia32"
],
@ -1676,9 +1676,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.35.0.tgz",
"integrity": "sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.36.0.tgz",
"integrity": "sha512-aRXd7tRZkWLqGbChgcMMDEHjOKudo1kChb1Jt1IfR8cY/KIpgNviLeJy5FUb9IpSuQj8dU2fAYNMPW/hLKOSTw==",
"cpu": [
"x64"
],
@ -2090,9 +2090,9 @@
}
},
"node_modules/@sveltejs/kit": {
"version": "2.19.2",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.19.2.tgz",
"integrity": "sha512-OkW7MMGkjXtdfqdHWlyPozh/Ct1X3pthXAKTSqHm+mwmvmTBASmPE6FhwlvUgsqlCceRYL+5QUGiIJfOy0xIjQ==",
"version": "2.20.1",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.20.1.tgz",
"integrity": "sha512-XXd6hQKi9le+8rYIKsxTfgABjB3b8S21qZmMUTvAC5kuVA1AXvYPVEmxrMhRqyOacXu3e6P3ag5HtJi6j9K7UQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3272,9 +3272,9 @@
"license": "MIT"
},
"node_modules/bits-ui": {
"version": "1.3.12",
"resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-1.3.12.tgz",
"integrity": "sha512-RhPvg2e7mTQSXR9WMdsyR5eTC2DSa4ch5MT/TjIaN3suMJ3RGlbzYPNvf4n56Lgck3W4Xm+L4jSgrzTdynuM8Q==",
"version": "1.3.13",
"resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-1.3.13.tgz",
"integrity": "sha512-0ysKdvHBIArfFBe+MYVAvu5OANOsivk+UJftdiW+e6lGHzf+EW/TZpLh69Vf0n8pYTjkH+33CHlVIImxTZRIMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3824,9 +3824,9 @@
}
},
"node_modules/eslint-plugin-svelte": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.2.0.tgz",
"integrity": "sha512-cxRkiF5XrydmLertOWoJ2LPqu0DItX3bbbJRFqzZ9MsRy3+3tPtQUsfsSuSxFTyDWWWAT1errzNhDLHehir9bw==",
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.3.2.tgz",
"integrity": "sha512-b2IJ2w0hJw5M3mj4aBLc6Gk6nMG3LFecUuPYV628G8Je/8ewJb80LR8fwTX9gOlqykTBNM18IGL7Hkz8K+WLkQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -6927,9 +6927,9 @@
}
},
"node_modules/rollup": {
"version": "4.35.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz",
"integrity": "sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==",
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.36.0.tgz",
"integrity": "sha512-zwATAXNQxUcd40zgtQG0ZafcRK4g004WtEl7kbuhTWPvf07PsfohXl39jVUvPF7jvNAIkKPQ2XrsDlWuxBd++Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -6943,25 +6943,25 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.35.0",
"@rollup/rollup-android-arm64": "4.35.0",
"@rollup/rollup-darwin-arm64": "4.35.0",
"@rollup/rollup-darwin-x64": "4.35.0",
"@rollup/rollup-freebsd-arm64": "4.35.0",
"@rollup/rollup-freebsd-x64": "4.35.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.35.0",
"@rollup/rollup-linux-arm-musleabihf": "4.35.0",
"@rollup/rollup-linux-arm64-gnu": "4.35.0",
"@rollup/rollup-linux-arm64-musl": "4.35.0",
"@rollup/rollup-linux-loongarch64-gnu": "4.35.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.35.0",
"@rollup/rollup-linux-riscv64-gnu": "4.35.0",
"@rollup/rollup-linux-s390x-gnu": "4.35.0",
"@rollup/rollup-linux-x64-gnu": "4.35.0",
"@rollup/rollup-linux-x64-musl": "4.35.0",
"@rollup/rollup-win32-arm64-msvc": "4.35.0",
"@rollup/rollup-win32-ia32-msvc": "4.35.0",
"@rollup/rollup-win32-x64-msvc": "4.35.0",
"@rollup/rollup-android-arm-eabi": "4.36.0",
"@rollup/rollup-android-arm64": "4.36.0",
"@rollup/rollup-darwin-arm64": "4.36.0",
"@rollup/rollup-darwin-x64": "4.36.0",
"@rollup/rollup-freebsd-arm64": "4.36.0",
"@rollup/rollup-freebsd-x64": "4.36.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.36.0",
"@rollup/rollup-linux-arm-musleabihf": "4.36.0",
"@rollup/rollup-linux-arm64-gnu": "4.36.0",
"@rollup/rollup-linux-arm64-musl": "4.36.0",
"@rollup/rollup-linux-loongarch64-gnu": "4.36.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.36.0",
"@rollup/rollup-linux-riscv64-gnu": "4.36.0",
"@rollup/rollup-linux-s390x-gnu": "4.36.0",
"@rollup/rollup-linux-x64-gnu": "4.36.0",
"@rollup/rollup-linux-x64-musl": "4.36.0",
"@rollup/rollup-win32-arm64-msvc": "4.36.0",
"@rollup/rollup-win32-ia32-msvc": "4.36.0",
"@rollup/rollup-win32-x64-msvc": "4.36.0",
"fsevents": "~2.3.2"
}
},
@ -7187,9 +7187,9 @@
}
},
"node_modules/svelte": {
"version": "5.23.1",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.23.1.tgz",
"integrity": "sha512-DUu3e5tQDO+PtKffjqJ548YfeKtw2Rqc9/+nlP26DZ0AopWTJNylkNnTOP/wcgIt1JSnovyISxEZ/lDR1OhbOw==",
"version": "5.23.2",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.23.2.tgz",
"integrity": "sha512-PHP1o0aYJNMatiZ+0nq1W/Z1W1/l5Z94B9nhMIo7gsuTBbxC454g4O5SQMjQpZBUZi5ANYUrXJOE4gPzcN/VQw==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -7417,9 +7417,9 @@
"license": "0BSD"
},
"node_modules/tw-animate-css": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.2.2.tgz",
"integrity": "sha512-TdSaQcV+V8MypECoXr6Nnv3EQFz05kxfTUaOHtpWTQZp8r5Bx2OmTnkSZVlOTaRiS20a6wYw0RaAnNX2D8ywrQ==",
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.2.3.tgz",
"integrity": "sha512-G2p4jSSGH21vb/slt1iCAqPL2XmFM2/9LT/I8Z2XHUcHbLGaN7YPx3tg8PkU0QAVgG9hzkAGh0cTrCwFjbZrkg==",
"dev": true,
"license": "MIT"
},

View File

@ -1,7 +1,7 @@
{
"name": "trevstack",
"private": true,
"version": "0.0.1",
"version": "0.0.5",
"type": "module",
"scripts": {
"dev": "vite dev",
@ -16,31 +16,31 @@
"devDependencies": {
"@connectrpc/connect": "^2.0.2",
"@connectrpc/connect-web": "^2.0.2",
"@eslint/compat": "^1.2.5",
"@eslint/compat": "^1.2.7",
"@eslint/js": "^9.18.0",
"@lucide/svelte": "^0.479.0",
"@scalar/api-reference": "^1.28.1",
"@scalar/api-reference": "^1.28.5",
"@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/kit": "^2.16.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"@tailwindcss/vite": "^4.0.13",
"bits-ui": "^1.3.11",
"@sveltejs/kit": "^2.20.1",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@tailwindcss/vite": "^4.0.14",
"bits-ui": "^1.3.13",
"clsx": "^2.1.1",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-svelte": "^3.0.0",
"eslint": "^9.22.0",
"eslint-config-prettier": "^10.1.1",
"eslint-plugin-svelte": "^3.3.2",
"globals": "^16.0.0",
"prettier": "^3.4.2",
"prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.11",
"svelte": "^5.0.0",
"svelte-check": "^4.0.0",
"svelte": "^5.23.2",
"svelte-check": "^4.1.5",
"svelte-sonner": "^0.3.28",
"tailwind-merge": "^3.0.2",
"tailwindcss": "^4.0.13",
"tw-animate-css": "^1.2.0",
"typescript": "^5.0.0",
"typescript-eslint": "^8.20.0",
"vite": "^6.0.0"
"tw-animate-css": "^1.2.3",
"typescript": "^5.8.2",
"typescript-eslint": "^8.26.1",
"vite": "^6.2.2"
}
}

View File

@ -1,24 +1,24 @@
@import "tailwindcss";
@import "tw-animate-css";
@import 'tailwindcss';
@import 'tw-animate-css';
@theme {
--color-crust: #11111b;
--color-mantle: #181825;
--color-base: #1e1e2e;
--color-crust: #11111b;
--color-mantle: #181825;
--color-base: #1e1e2e;
--color-surface-0: #313244;
--color-surface-1: #45475a;
--color-surface-2: #585b70;
--color-surface-0: #313244;
--color-surface-1: #45475a;
--color-surface-2: #585b70;
--color-overlay-0: #6c7086;
--color-overlay-1: #7f849c;
--color-overlay-2: #9399b2;
--color-overlay-0: #6c7086;
--color-overlay-1: #7f849c;
--color-overlay-2: #9399b2;
--color-subtext-0: #a6adc8;
--color-subtext-1: #bac2de;
--color-subtext-0: #a6adc8;
--color-subtext-1: #bac2de;
--color-text: #cdd6f4;
--color-text: #cdd6f4;
--color-sky: #89dceb;
--color-red: #f38ba8;
--color-sky: #89dceb;
--color-red: #f38ba8;
}

View File

@ -8,7 +8,7 @@
<title>TrevStack</title>
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="tap" class="min-h-screen bg-base text-text">
<body data-sveltekit-preload-data="tap" class="bg-base text-text min-h-screen">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

View File

@ -2,295 +2,305 @@
// @generated from file item/v1/item.proto (package item.v1, syntax proto3)
/* eslint-disable */
import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv1";
import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv1";
import type { Timestamp } from "@bufbuild/protobuf/wkt";
import { file_google_protobuf_timestamp } from "@bufbuild/protobuf/wkt";
import type { Message } from "@bufbuild/protobuf";
import type { GenFile, GenMessage, GenService } from '@bufbuild/protobuf/codegenv1';
import { fileDesc, messageDesc, serviceDesc } from '@bufbuild/protobuf/codegenv1';
import type { Timestamp } from '@bufbuild/protobuf/wkt';
import { file_google_protobuf_timestamp } from '@bufbuild/protobuf/wkt';
import type { Message } from '@bufbuild/protobuf';
/**
* Describes the file item/v1/item.proto.
*/
export const file_item_v1_item: GenFile = /*@__PURE__*/
fileDesc("ChJpdGVtL3YxL2l0ZW0ucHJvdG8SB2l0ZW0udjEinAEKBEl0ZW0SDwoCaWQYASABKA1IAIgBARIMCgRuYW1lGAIgASgJEhMKC2Rlc2NyaXB0aW9uGAMgASgJEg0KBXByaWNlGAQgASgCEhAKCHF1YW50aXR5GAUgASgNEi4KBWFkZGVkGAYgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEgBiAEBQgUKA19pZEIICgZfYWRkZWQiHAoOR2V0SXRlbVJlcXVlc3QSCgoCaWQYASABKA0iLgoPR2V0SXRlbVJlc3BvbnNlEhsKBGl0ZW0YASABKAsyDS5pdGVtLnYxLkl0ZW0i3wEKD0dldEl0ZW1zUmVxdWVzdBIuCgVzdGFydBgBIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBIAIgBARIsCgNlbmQYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wSAGIAQESEwoGZmlsdGVyGAMgASgJSAKIAQESEgoFbGltaXQYBCABKA1IA4gBARITCgZvZmZzZXQYBSABKA1IBIgBAUIICgZfc3RhcnRCBgoEX2VuZEIJCgdfZmlsdGVyQggKBl9saW1pdEIJCgdfb2Zmc2V0Ij8KEEdldEl0ZW1zUmVzcG9uc2USHAoFaXRlbXMYASADKAsyDS5pdGVtLnYxLkl0ZW0SDQoFY291bnQYAiABKAQiMAoRQ3JlYXRlSXRlbVJlcXVlc3QSGwoEaXRlbRgBIAEoCzINLml0ZW0udjEuSXRlbSIxChJDcmVhdGVJdGVtUmVzcG9uc2USGwoEaXRlbRgBIAEoCzINLml0ZW0udjEuSXRlbSIwChFVcGRhdGVJdGVtUmVxdWVzdBIbCgRpdGVtGAEgASgLMg0uaXRlbS52MS5JdGVtIjEKElVwZGF0ZUl0ZW1SZXNwb25zZRIbCgRpdGVtGAEgASgLMg0uaXRlbS52MS5JdGVtIh8KEURlbGV0ZUl0ZW1SZXF1ZXN0EgoKAmlkGAEgASgNIhQKEkRlbGV0ZUl0ZW1SZXNwb25zZTLrAgoLSXRlbVNlcnZpY2USPgoHR2V0SXRlbRIXLml0ZW0udjEuR2V0SXRlbVJlcXVlc3QaGC5pdGVtLnYxLkdldEl0ZW1SZXNwb25zZSIAEkEKCEdldEl0ZW1zEhguaXRlbS52MS5HZXRJdGVtc1JlcXVlc3QaGS5pdGVtLnYxLkdldEl0ZW1zUmVzcG9uc2UiABJHCgpDcmVhdGVJdGVtEhouaXRlbS52MS5DcmVhdGVJdGVtUmVxdWVzdBobLml0ZW0udjEuQ3JlYXRlSXRlbVJlc3BvbnNlIgASRwoKVXBkYXRlSXRlbRIaLml0ZW0udjEuVXBkYXRlSXRlbVJlcXVlc3QaGy5pdGVtLnYxLlVwZGF0ZUl0ZW1SZXNwb25zZSIAEkcKCkRlbGV0ZUl0ZW0SGi5pdGVtLnYxLkRlbGV0ZUl0ZW1SZXF1ZXN0GhsuaXRlbS52MS5EZWxldGVJdGVtUmVzcG9uc2UiAEKdAQoLY29tLml0ZW0udjFCCUl0ZW1Qcm90b1ABWkZnaXRodWIuY29tL3Nwb3RkZW1vNC90cmV2c3RhY2svc2VydmVyL2ludGVybmFsL3NlcnZpY2VzL2l0ZW0vdjE7aXRlbXYxogIDSVhYqgIHSXRlbS5WMcoCB0l0ZW1cVjHiAhNJdGVtXFYxXEdQQk1ldGFkYXRh6gIISXRlbTo6VjFiBnByb3RvMw", [file_google_protobuf_timestamp]);
export const file_item_v1_item: GenFile =
/*@__PURE__*/
fileDesc(
'ChJpdGVtL3YxL2l0ZW0ucHJvdG8SB2l0ZW0udjEinAEKBEl0ZW0SDwoCaWQYASABKA1IAIgBARIMCgRuYW1lGAIgASgJEhMKC2Rlc2NyaXB0aW9uGAMgASgJEg0KBXByaWNlGAQgASgCEhAKCHF1YW50aXR5GAUgASgNEi4KBWFkZGVkGAYgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEgBiAEBQgUKA19pZEIICgZfYWRkZWQiHAoOR2V0SXRlbVJlcXVlc3QSCgoCaWQYASABKA0iLgoPR2V0SXRlbVJlc3BvbnNlEhsKBGl0ZW0YASABKAsyDS5pdGVtLnYxLkl0ZW0i3wEKD0dldEl0ZW1zUmVxdWVzdBIuCgVzdGFydBgBIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBIAIgBARIsCgNlbmQYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wSAGIAQESEwoGZmlsdGVyGAMgASgJSAKIAQESEgoFbGltaXQYBCABKA1IA4gBARITCgZvZmZzZXQYBSABKA1IBIgBAUIICgZfc3RhcnRCBgoEX2VuZEIJCgdfZmlsdGVyQggKBl9saW1pdEIJCgdfb2Zmc2V0Ij8KEEdldEl0ZW1zUmVzcG9uc2USHAoFaXRlbXMYASADKAsyDS5pdGVtLnYxLkl0ZW0SDQoFY291bnQYAiABKAQiMAoRQ3JlYXRlSXRlbVJlcXVlc3QSGwoEaXRlbRgBIAEoCzINLml0ZW0udjEuSXRlbSIxChJDcmVhdGVJdGVtUmVzcG9uc2USGwoEaXRlbRgBIAEoCzINLml0ZW0udjEuSXRlbSIwChFVcGRhdGVJdGVtUmVxdWVzdBIbCgRpdGVtGAEgASgLMg0uaXRlbS52MS5JdGVtIjEKElVwZGF0ZUl0ZW1SZXNwb25zZRIbCgRpdGVtGAEgASgLMg0uaXRlbS52MS5JdGVtIh8KEURlbGV0ZUl0ZW1SZXF1ZXN0EgoKAmlkGAEgASgNIhQKEkRlbGV0ZUl0ZW1SZXNwb25zZTLrAgoLSXRlbVNlcnZpY2USPgoHR2V0SXRlbRIXLml0ZW0udjEuR2V0SXRlbVJlcXVlc3QaGC5pdGVtLnYxLkdldEl0ZW1SZXNwb25zZSIAEkEKCEdldEl0ZW1zEhguaXRlbS52MS5HZXRJdGVtc1JlcXVlc3QaGS5pdGVtLnYxLkdldEl0ZW1zUmVzcG9uc2UiABJHCgpDcmVhdGVJdGVtEhouaXRlbS52MS5DcmVhdGVJdGVtUmVxdWVzdBobLml0ZW0udjEuQ3JlYXRlSXRlbVJlc3BvbnNlIgASRwoKVXBkYXRlSXRlbRIaLml0ZW0udjEuVXBkYXRlSXRlbVJlcXVlc3QaGy5pdGVtLnYxLlVwZGF0ZUl0ZW1SZXNwb25zZSIAEkcKCkRlbGV0ZUl0ZW0SGi5pdGVtLnYxLkRlbGV0ZUl0ZW1SZXF1ZXN0GhsuaXRlbS52MS5EZWxldGVJdGVtUmVzcG9uc2UiAEKdAQoLY29tLml0ZW0udjFCCUl0ZW1Qcm90b1ABWkZnaXRodWIuY29tL3Nwb3RkZW1vNC90cmV2c3RhY2svc2VydmVyL2ludGVybmFsL3NlcnZpY2VzL2l0ZW0vdjE7aXRlbXYxogIDSVhYqgIHSXRlbS5WMcoCB0l0ZW1cVjHiAhNJdGVtXFYxXEdQQk1ldGFkYXRh6gIISXRlbTo6VjFiBnByb3RvMw',
[file_google_protobuf_timestamp]
);
/**
* @generated from message item.v1.Item
*/
export type Item = Message<"item.v1.Item"> & {
/**
* @generated from field: optional uint32 id = 1;
*/
id?: number;
export type Item = Message<'item.v1.Item'> & {
/**
* @generated from field: optional uint32 id = 1;
*/
id?: number;
/**
* @generated from field: string name = 2;
*/
name: string;
/**
* @generated from field: string name = 2;
*/
name: string;
/**
* @generated from field: string description = 3;
*/
description: string;
/**
* @generated from field: string description = 3;
*/
description: string;
/**
* @generated from field: float price = 4;
*/
price: number;
/**
* @generated from field: float price = 4;
*/
price: number;
/**
* @generated from field: uint32 quantity = 5;
*/
quantity: number;
/**
* @generated from field: uint32 quantity = 5;
*/
quantity: number;
/**
* @generated from field: optional google.protobuf.Timestamp added = 6;
*/
added?: Timestamp;
/**
* @generated from field: optional google.protobuf.Timestamp added = 6;
*/
added?: Timestamp;
};
/**
* Describes the message item.v1.Item.
* Use `create(ItemSchema)` to create a new message.
*/
export const ItemSchema: GenMessage<Item> = /*@__PURE__*/
messageDesc(file_item_v1_item, 0);
export const ItemSchema: GenMessage<Item> = /*@__PURE__*/ messageDesc(file_item_v1_item, 0);
/**
* @generated from message item.v1.GetItemRequest
*/
export type GetItemRequest = Message<"item.v1.GetItemRequest"> & {
/**
* @generated from field: uint32 id = 1;
*/
id: number;
export type GetItemRequest = Message<'item.v1.GetItemRequest'> & {
/**
* @generated from field: uint32 id = 1;
*/
id: number;
};
/**
* Describes the message item.v1.GetItemRequest.
* Use `create(GetItemRequestSchema)` to create a new message.
*/
export const GetItemRequestSchema: GenMessage<GetItemRequest> = /*@__PURE__*/
messageDesc(file_item_v1_item, 1);
export const GetItemRequestSchema: GenMessage<GetItemRequest> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 1);
/**
* @generated from message item.v1.GetItemResponse
*/
export type GetItemResponse = Message<"item.v1.GetItemResponse"> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
export type GetItemResponse = Message<'item.v1.GetItemResponse'> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
};
/**
* Describes the message item.v1.GetItemResponse.
* Use `create(GetItemResponseSchema)` to create a new message.
*/
export const GetItemResponseSchema: GenMessage<GetItemResponse> = /*@__PURE__*/
messageDesc(file_item_v1_item, 2);
export const GetItemResponseSchema: GenMessage<GetItemResponse> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 2);
/**
* @generated from message item.v1.GetItemsRequest
*/
export type GetItemsRequest = Message<"item.v1.GetItemsRequest"> & {
/**
* @generated from field: optional google.protobuf.Timestamp start = 1;
*/
start?: Timestamp;
export type GetItemsRequest = Message<'item.v1.GetItemsRequest'> & {
/**
* @generated from field: optional google.protobuf.Timestamp start = 1;
*/
start?: Timestamp;
/**
* @generated from field: optional google.protobuf.Timestamp end = 2;
*/
end?: Timestamp;
/**
* @generated from field: optional google.protobuf.Timestamp end = 2;
*/
end?: Timestamp;
/**
* @generated from field: optional string filter = 3;
*/
filter?: string;
/**
* @generated from field: optional string filter = 3;
*/
filter?: string;
/**
* @generated from field: optional uint32 limit = 4;
*/
limit?: number;
/**
* @generated from field: optional uint32 limit = 4;
*/
limit?: number;
/**
* @generated from field: optional uint32 offset = 5;
*/
offset?: number;
/**
* @generated from field: optional uint32 offset = 5;
*/
offset?: number;
};
/**
* Describes the message item.v1.GetItemsRequest.
* Use `create(GetItemsRequestSchema)` to create a new message.
*/
export const GetItemsRequestSchema: GenMessage<GetItemsRequest> = /*@__PURE__*/
messageDesc(file_item_v1_item, 3);
export const GetItemsRequestSchema: GenMessage<GetItemsRequest> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 3);
/**
* @generated from message item.v1.GetItemsResponse
*/
export type GetItemsResponse = Message<"item.v1.GetItemsResponse"> & {
/**
* @generated from field: repeated item.v1.Item items = 1;
*/
items: Item[];
export type GetItemsResponse = Message<'item.v1.GetItemsResponse'> & {
/**
* @generated from field: repeated item.v1.Item items = 1;
*/
items: Item[];
/**
* @generated from field: uint64 count = 2;
*/
count: bigint;
/**
* @generated from field: uint64 count = 2;
*/
count: bigint;
};
/**
* Describes the message item.v1.GetItemsResponse.
* Use `create(GetItemsResponseSchema)` to create a new message.
*/
export const GetItemsResponseSchema: GenMessage<GetItemsResponse> = /*@__PURE__*/
messageDesc(file_item_v1_item, 4);
export const GetItemsResponseSchema: GenMessage<GetItemsResponse> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 4);
/**
* @generated from message item.v1.CreateItemRequest
*/
export type CreateItemRequest = Message<"item.v1.CreateItemRequest"> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
export type CreateItemRequest = Message<'item.v1.CreateItemRequest'> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
};
/**
* Describes the message item.v1.CreateItemRequest.
* Use `create(CreateItemRequestSchema)` to create a new message.
*/
export const CreateItemRequestSchema: GenMessage<CreateItemRequest> = /*@__PURE__*/
messageDesc(file_item_v1_item, 5);
export const CreateItemRequestSchema: GenMessage<CreateItemRequest> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 5);
/**
* @generated from message item.v1.CreateItemResponse
*/
export type CreateItemResponse = Message<"item.v1.CreateItemResponse"> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
export type CreateItemResponse = Message<'item.v1.CreateItemResponse'> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
};
/**
* Describes the message item.v1.CreateItemResponse.
* Use `create(CreateItemResponseSchema)` to create a new message.
*/
export const CreateItemResponseSchema: GenMessage<CreateItemResponse> = /*@__PURE__*/
messageDesc(file_item_v1_item, 6);
export const CreateItemResponseSchema: GenMessage<CreateItemResponse> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 6);
/**
* @generated from message item.v1.UpdateItemRequest
*/
export type UpdateItemRequest = Message<"item.v1.UpdateItemRequest"> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
export type UpdateItemRequest = Message<'item.v1.UpdateItemRequest'> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
};
/**
* Describes the message item.v1.UpdateItemRequest.
* Use `create(UpdateItemRequestSchema)` to create a new message.
*/
export const UpdateItemRequestSchema: GenMessage<UpdateItemRequest> = /*@__PURE__*/
messageDesc(file_item_v1_item, 7);
export const UpdateItemRequestSchema: GenMessage<UpdateItemRequest> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 7);
/**
* @generated from message item.v1.UpdateItemResponse
*/
export type UpdateItemResponse = Message<"item.v1.UpdateItemResponse"> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
export type UpdateItemResponse = Message<'item.v1.UpdateItemResponse'> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
};
/**
* Describes the message item.v1.UpdateItemResponse.
* Use `create(UpdateItemResponseSchema)` to create a new message.
*/
export const UpdateItemResponseSchema: GenMessage<UpdateItemResponse> = /*@__PURE__*/
messageDesc(file_item_v1_item, 8);
export const UpdateItemResponseSchema: GenMessage<UpdateItemResponse> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 8);
/**
* @generated from message item.v1.DeleteItemRequest
*/
export type DeleteItemRequest = Message<"item.v1.DeleteItemRequest"> & {
/**
* @generated from field: uint32 id = 1;
*/
id: number;
export type DeleteItemRequest = Message<'item.v1.DeleteItemRequest'> & {
/**
* @generated from field: uint32 id = 1;
*/
id: number;
};
/**
* Describes the message item.v1.DeleteItemRequest.
* Use `create(DeleteItemRequestSchema)` to create a new message.
*/
export const DeleteItemRequestSchema: GenMessage<DeleteItemRequest> = /*@__PURE__*/
messageDesc(file_item_v1_item, 9);
export const DeleteItemRequestSchema: GenMessage<DeleteItemRequest> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 9);
/**
* @generated from message item.v1.DeleteItemResponse
*/
export type DeleteItemResponse = Message<"item.v1.DeleteItemResponse"> & {
};
export type DeleteItemResponse = Message<'item.v1.DeleteItemResponse'> & {};
/**
* Describes the message item.v1.DeleteItemResponse.
* Use `create(DeleteItemResponseSchema)` to create a new message.
*/
export const DeleteItemResponseSchema: GenMessage<DeleteItemResponse> = /*@__PURE__*/
messageDesc(file_item_v1_item, 10);
export const DeleteItemResponseSchema: GenMessage<DeleteItemResponse> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 10);
/**
* @generated from service item.v1.ItemService
*/
export const ItemService: GenService<{
/**
* @generated from rpc item.v1.ItemService.GetItem
*/
getItem: {
methodKind: "unary";
input: typeof GetItemRequestSchema;
output: typeof GetItemResponseSchema;
},
/**
* @generated from rpc item.v1.ItemService.GetItems
*/
getItems: {
methodKind: "unary";
input: typeof GetItemsRequestSchema;
output: typeof GetItemsResponseSchema;
},
/**
* @generated from rpc item.v1.ItemService.CreateItem
*/
createItem: {
methodKind: "unary";
input: typeof CreateItemRequestSchema;
output: typeof CreateItemResponseSchema;
},
/**
* @generated from rpc item.v1.ItemService.UpdateItem
*/
updateItem: {
methodKind: "unary";
input: typeof UpdateItemRequestSchema;
output: typeof UpdateItemResponseSchema;
},
/**
* @generated from rpc item.v1.ItemService.DeleteItem
*/
deleteItem: {
methodKind: "unary";
input: typeof DeleteItemRequestSchema;
output: typeof DeleteItemResponseSchema;
},
}> = /*@__PURE__*/
serviceDesc(file_item_v1_item, 0);
/**
* @generated from rpc item.v1.ItemService.GetItem
*/
getItem: {
methodKind: 'unary';
input: typeof GetItemRequestSchema;
output: typeof GetItemResponseSchema;
};
/**
* @generated from rpc item.v1.ItemService.GetItems
*/
getItems: {
methodKind: 'unary';
input: typeof GetItemsRequestSchema;
output: typeof GetItemsResponseSchema;
};
/**
* @generated from rpc item.v1.ItemService.CreateItem
*/
createItem: {
methodKind: 'unary';
input: typeof CreateItemRequestSchema;
output: typeof CreateItemResponseSchema;
};
/**
* @generated from rpc item.v1.ItemService.UpdateItem
*/
updateItem: {
methodKind: 'unary';
input: typeof UpdateItemRequestSchema;
output: typeof UpdateItemResponseSchema;
};
/**
* @generated from rpc item.v1.ItemService.DeleteItem
*/
deleteItem: {
methodKind: 'unary';
input: typeof DeleteItemRequestSchema;
output: typeof DeleteItemResponseSchema;
};
}> = /*@__PURE__*/ serviceDesc(file_item_v1_item, 0);

View File

@ -2,149 +2,153 @@
// @generated from file user/v1/auth.proto (package user.v1, syntax proto3)
/* eslint-disable */
import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv1";
import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv1";
import type { Message } from "@bufbuild/protobuf";
import type { GenFile, GenMessage, GenService } from '@bufbuild/protobuf/codegenv1';
import { fileDesc, messageDesc, serviceDesc } from '@bufbuild/protobuf/codegenv1';
import type { Message } from '@bufbuild/protobuf';
/**
* Describes the file user/v1/auth.proto.
*/
export const file_user_v1_auth: GenFile = /*@__PURE__*/
fileDesc("ChJ1c2VyL3YxL2F1dGgucHJvdG8SB3VzZXIudjEiMgoMTG9naW5SZXF1ZXN0EhAKCHVzZXJuYW1lGAEgASgJEhAKCHBhc3N3b3JkGAIgASgJIh4KDUxvZ2luUmVzcG9uc2USDQoFdG9rZW4YASABKAkiTQoNU2lnblVwUmVxdWVzdBIQCgh1c2VybmFtZRgBIAEoCRIQCghwYXNzd29yZBgCIAEoCRIYChBjb25maXJtX3Bhc3N3b3JkGAMgASgJIhAKDlNpZ25VcFJlc3BvbnNlIg8KDUxvZ291dFJlcXVlc3QiEAoOTG9nb3V0UmVzcG9uc2UywQEKC0F1dGhTZXJ2aWNlEjgKBUxvZ2luEhUudXNlci52MS5Mb2dpblJlcXVlc3QaFi51c2VyLnYxLkxvZ2luUmVzcG9uc2UiABI7CgZTaWduVXASFi51c2VyLnYxLlNpZ25VcFJlcXVlc3QaFy51c2VyLnYxLlNpZ25VcFJlc3BvbnNlIgASOwoGTG9nb3V0EhYudXNlci52MS5Mb2dvdXRSZXF1ZXN0GhcudXNlci52MS5Mb2dvdXRSZXNwb25zZSIAQp0BCgtjb20udXNlci52MUIJQXV0aFByb3RvUAFaRmdpdGh1Yi5jb20vc3BvdGRlbW80L3RyZXZzdGFjay9zZXJ2ZXIvaW50ZXJuYWwvc2VydmljZXMvdXNlci92MTt1c2VydjGiAgNVWFiqAgdVc2VyLlYxygIHVXNlclxWMeICE1VzZXJcVjFcR1BCTWV0YWRhdGHqAghVc2VyOjpWMWIGcHJvdG8z");
export const file_user_v1_auth: GenFile =
/*@__PURE__*/
fileDesc(
'ChJ1c2VyL3YxL2F1dGgucHJvdG8SB3VzZXIudjEiMgoMTG9naW5SZXF1ZXN0EhAKCHVzZXJuYW1lGAEgASgJEhAKCHBhc3N3b3JkGAIgASgJIh4KDUxvZ2luUmVzcG9uc2USDQoFdG9rZW4YASABKAkiTQoNU2lnblVwUmVxdWVzdBIQCgh1c2VybmFtZRgBIAEoCRIQCghwYXNzd29yZBgCIAEoCRIYChBjb25maXJtX3Bhc3N3b3JkGAMgASgJIhAKDlNpZ25VcFJlc3BvbnNlIg8KDUxvZ291dFJlcXVlc3QiEAoOTG9nb3V0UmVzcG9uc2UywQEKC0F1dGhTZXJ2aWNlEjgKBUxvZ2luEhUudXNlci52MS5Mb2dpblJlcXVlc3QaFi51c2VyLnYxLkxvZ2luUmVzcG9uc2UiABI7CgZTaWduVXASFi51c2VyLnYxLlNpZ25VcFJlcXVlc3QaFy51c2VyLnYxLlNpZ25VcFJlc3BvbnNlIgASOwoGTG9nb3V0EhYudXNlci52MS5Mb2dvdXRSZXF1ZXN0GhcudXNlci52MS5Mb2dvdXRSZXNwb25zZSIAQp0BCgtjb20udXNlci52MUIJQXV0aFByb3RvUAFaRmdpdGh1Yi5jb20vc3BvdGRlbW80L3RyZXZzdGFjay9zZXJ2ZXIvaW50ZXJuYWwvc2VydmljZXMvdXNlci92MTt1c2VydjGiAgNVWFiqAgdVc2VyLlYxygIHVXNlclxWMeICE1VzZXJcVjFcR1BCTWV0YWRhdGHqAghVc2VyOjpWMWIGcHJvdG8z'
);
/**
* @generated from message user.v1.LoginRequest
*/
export type LoginRequest = Message<"user.v1.LoginRequest"> & {
/**
* @generated from field: string username = 1;
*/
username: string;
export type LoginRequest = Message<'user.v1.LoginRequest'> & {
/**
* @generated from field: string username = 1;
*/
username: string;
/**
* @generated from field: string password = 2;
*/
password: string;
/**
* @generated from field: string password = 2;
*/
password: string;
};
/**
* Describes the message user.v1.LoginRequest.
* Use `create(LoginRequestSchema)` to create a new message.
*/
export const LoginRequestSchema: GenMessage<LoginRequest> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 0);
export const LoginRequestSchema: GenMessage<LoginRequest> =
/*@__PURE__*/
messageDesc(file_user_v1_auth, 0);
/**
* @generated from message user.v1.LoginResponse
*/
export type LoginResponse = Message<"user.v1.LoginResponse"> & {
/**
* @generated from field: string token = 1;
*/
token: string;
export type LoginResponse = Message<'user.v1.LoginResponse'> & {
/**
* @generated from field: string token = 1;
*/
token: string;
};
/**
* Describes the message user.v1.LoginResponse.
* Use `create(LoginResponseSchema)` to create a new message.
*/
export const LoginResponseSchema: GenMessage<LoginResponse> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 1);
export const LoginResponseSchema: GenMessage<LoginResponse> =
/*@__PURE__*/
messageDesc(file_user_v1_auth, 1);
/**
* @generated from message user.v1.SignUpRequest
*/
export type SignUpRequest = Message<"user.v1.SignUpRequest"> & {
/**
* @generated from field: string username = 1;
*/
username: string;
export type SignUpRequest = Message<'user.v1.SignUpRequest'> & {
/**
* @generated from field: string username = 1;
*/
username: string;
/**
* @generated from field: string password = 2;
*/
password: string;
/**
* @generated from field: string password = 2;
*/
password: string;
/**
* @generated from field: string confirm_password = 3;
*/
confirmPassword: string;
/**
* @generated from field: string confirm_password = 3;
*/
confirmPassword: string;
};
/**
* Describes the message user.v1.SignUpRequest.
* Use `create(SignUpRequestSchema)` to create a new message.
*/
export const SignUpRequestSchema: GenMessage<SignUpRequest> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 2);
export const SignUpRequestSchema: GenMessage<SignUpRequest> =
/*@__PURE__*/
messageDesc(file_user_v1_auth, 2);
/**
* @generated from message user.v1.SignUpResponse
*/
export type SignUpResponse = Message<"user.v1.SignUpResponse"> & {
};
export type SignUpResponse = Message<'user.v1.SignUpResponse'> & {};
/**
* Describes the message user.v1.SignUpResponse.
* Use `create(SignUpResponseSchema)` to create a new message.
*/
export const SignUpResponseSchema: GenMessage<SignUpResponse> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 3);
export const SignUpResponseSchema: GenMessage<SignUpResponse> =
/*@__PURE__*/
messageDesc(file_user_v1_auth, 3);
/**
* @generated from message user.v1.LogoutRequest
*/
export type LogoutRequest = Message<"user.v1.LogoutRequest"> & {
};
export type LogoutRequest = Message<'user.v1.LogoutRequest'> & {};
/**
* Describes the message user.v1.LogoutRequest.
* Use `create(LogoutRequestSchema)` to create a new message.
*/
export const LogoutRequestSchema: GenMessage<LogoutRequest> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 4);
export const LogoutRequestSchema: GenMessage<LogoutRequest> =
/*@__PURE__*/
messageDesc(file_user_v1_auth, 4);
/**
* @generated from message user.v1.LogoutResponse
*/
export type LogoutResponse = Message<"user.v1.LogoutResponse"> & {
};
export type LogoutResponse = Message<'user.v1.LogoutResponse'> & {};
/**
* Describes the message user.v1.LogoutResponse.
* Use `create(LogoutResponseSchema)` to create a new message.
*/
export const LogoutResponseSchema: GenMessage<LogoutResponse> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 5);
export const LogoutResponseSchema: GenMessage<LogoutResponse> =
/*@__PURE__*/
messageDesc(file_user_v1_auth, 5);
/**
* @generated from service user.v1.AuthService
*/
export const AuthService: GenService<{
/**
* @generated from rpc user.v1.AuthService.Login
*/
login: {
methodKind: "unary";
input: typeof LoginRequestSchema;
output: typeof LoginResponseSchema;
},
/**
* @generated from rpc user.v1.AuthService.SignUp
*/
signUp: {
methodKind: "unary";
input: typeof SignUpRequestSchema;
output: typeof SignUpResponseSchema;
},
/**
* @generated from rpc user.v1.AuthService.Logout
*/
logout: {
methodKind: "unary";
input: typeof LogoutRequestSchema;
output: typeof LogoutResponseSchema;
},
}> = /*@__PURE__*/
serviceDesc(file_user_v1_auth, 0);
/**
* @generated from rpc user.v1.AuthService.Login
*/
login: {
methodKind: 'unary';
input: typeof LoginRequestSchema;
output: typeof LoginResponseSchema;
};
/**
* @generated from rpc user.v1.AuthService.SignUp
*/
signUp: {
methodKind: 'unary';
input: typeof SignUpRequestSchema;
output: typeof SignUpResponseSchema;
};
/**
* @generated from rpc user.v1.AuthService.Logout
*/
logout: {
methodKind: 'unary';
input: typeof LogoutRequestSchema;
output: typeof LogoutResponseSchema;
};
}> = /*@__PURE__*/ serviceDesc(file_user_v1_auth, 0);

View File

@ -2,231 +2,238 @@
// @generated from file user/v1/user.proto (package user.v1, syntax proto3)
/* eslint-disable */
import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv1";
import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv1";
import type { Message } from "@bufbuild/protobuf";
import type { GenFile, GenMessage, GenService } from '@bufbuild/protobuf/codegenv1';
import { fileDesc, messageDesc, serviceDesc } from '@bufbuild/protobuf/codegenv1';
import type { Message } from '@bufbuild/protobuf';
/**
* Describes the file user/v1/user.proto.
*/
export const file_user_v1_user: GenFile = /*@__PURE__*/
fileDesc("ChJ1c2VyL3YxL3VzZXIucHJvdG8SB3VzZXIudjEiVgoEVXNlchIKCgJpZBgBIAEoDRIQCgh1c2VybmFtZRgCIAEoCRIcCg9wcm9maWxlX3BpY3R1cmUYAyABKAlIAIgBAUISChBfcHJvZmlsZV9waWN0dXJlIhAKDkdldFVzZXJSZXF1ZXN0Ii4KD0dldFVzZXJSZXNwb25zZRIbCgR1c2VyGAEgASgLMg0udXNlci52MS5Vc2VyIl0KFVVwZGF0ZVBhc3N3b3JkUmVxdWVzdBIUCgxvbGRfcGFzc3dvcmQYASABKAkSFAoMbmV3X3Bhc3N3b3JkGAIgASgJEhgKEGNvbmZpcm1fcGFzc3dvcmQYAyABKAkiNQoWVXBkYXRlUGFzc3dvcmRSZXNwb25zZRIbCgR1c2VyGAEgASgLMg0udXNlci52MS5Vc2VyIj4KEEdldEFQSUtleVJlcXVlc3QSEAoIcGFzc3dvcmQYASABKAkSGAoQY29uZmlybV9wYXNzd29yZBgCIAEoCSIgChFHZXRBUElLZXlSZXNwb25zZRILCgNrZXkYASABKAkiPgobVXBkYXRlUHJvZmlsZVBpY3R1cmVSZXF1ZXN0EhEKCWZpbGVfbmFtZRgBIAEoCRIMCgRkYXRhGAIgASgMIjsKHFVwZGF0ZVByb2ZpbGVQaWN0dXJlUmVzcG9uc2USGwoEdXNlchgBIAEoCzINLnVzZXIudjEuVXNlcjLPAgoLVXNlclNlcnZpY2USPgoHR2V0VXNlchIXLnVzZXIudjEuR2V0VXNlclJlcXVlc3QaGC51c2VyLnYxLkdldFVzZXJSZXNwb25zZSIAElMKDlVwZGF0ZVBhc3N3b3JkEh4udXNlci52MS5VcGRhdGVQYXNzd29yZFJlcXVlc3QaHy51c2VyLnYxLlVwZGF0ZVBhc3N3b3JkUmVzcG9uc2UiABJECglHZXRBUElLZXkSGS51c2VyLnYxLkdldEFQSUtleVJlcXVlc3QaGi51c2VyLnYxLkdldEFQSUtleVJlc3BvbnNlIgASZQoUVXBkYXRlUHJvZmlsZVBpY3R1cmUSJC51c2VyLnYxLlVwZGF0ZVByb2ZpbGVQaWN0dXJlUmVxdWVzdBolLnVzZXIudjEuVXBkYXRlUHJvZmlsZVBpY3R1cmVSZXNwb25zZSIAQp0BCgtjb20udXNlci52MUIJVXNlclByb3RvUAFaRmdpdGh1Yi5jb20vc3BvdGRlbW80L3RyZXZzdGFjay9zZXJ2ZXIvaW50ZXJuYWwvc2VydmljZXMvdXNlci92MTt1c2VydjGiAgNVWFiqAgdVc2VyLlYxygIHVXNlclxWMeICE1VzZXJcVjFcR1BCTWV0YWRhdGHqAghVc2VyOjpWMWIGcHJvdG8z");
export const file_user_v1_user: GenFile =
/*@__PURE__*/
fileDesc(
'ChJ1c2VyL3YxL3VzZXIucHJvdG8SB3VzZXIudjEiVgoEVXNlchIKCgJpZBgBIAEoDRIQCgh1c2VybmFtZRgCIAEoCRIcCg9wcm9maWxlX3BpY3R1cmUYAyABKAlIAIgBAUISChBfcHJvZmlsZV9waWN0dXJlIhAKDkdldFVzZXJSZXF1ZXN0Ii4KD0dldFVzZXJSZXNwb25zZRIbCgR1c2VyGAEgASgLMg0udXNlci52MS5Vc2VyIl0KFVVwZGF0ZVBhc3N3b3JkUmVxdWVzdBIUCgxvbGRfcGFzc3dvcmQYASABKAkSFAoMbmV3X3Bhc3N3b3JkGAIgASgJEhgKEGNvbmZpcm1fcGFzc3dvcmQYAyABKAkiNQoWVXBkYXRlUGFzc3dvcmRSZXNwb25zZRIbCgR1c2VyGAEgASgLMg0udXNlci52MS5Vc2VyIj4KEEdldEFQSUtleVJlcXVlc3QSEAoIcGFzc3dvcmQYASABKAkSGAoQY29uZmlybV9wYXNzd29yZBgCIAEoCSIgChFHZXRBUElLZXlSZXNwb25zZRILCgNrZXkYASABKAkiPgobVXBkYXRlUHJvZmlsZVBpY3R1cmVSZXF1ZXN0EhEKCWZpbGVfbmFtZRgBIAEoCRIMCgRkYXRhGAIgASgMIjsKHFVwZGF0ZVByb2ZpbGVQaWN0dXJlUmVzcG9uc2USGwoEdXNlchgBIAEoCzINLnVzZXIudjEuVXNlcjLPAgoLVXNlclNlcnZpY2USPgoHR2V0VXNlchIXLnVzZXIudjEuR2V0VXNlclJlcXVlc3QaGC51c2VyLnYxLkdldFVzZXJSZXNwb25zZSIAElMKDlVwZGF0ZVBhc3N3b3JkEh4udXNlci52MS5VcGRhdGVQYXNzd29yZFJlcXVlc3QaHy51c2VyLnYxLlVwZGF0ZVBhc3N3b3JkUmVzcG9uc2UiABJECglHZXRBUElLZXkSGS51c2VyLnYxLkdldEFQSUtleVJlcXVlc3QaGi51c2VyLnYxLkdldEFQSUtleVJlc3BvbnNlIgASZQoUVXBkYXRlUHJvZmlsZVBpY3R1cmUSJC51c2VyLnYxLlVwZGF0ZVByb2ZpbGVQaWN0dXJlUmVxdWVzdBolLnVzZXIudjEuVXBkYXRlUHJvZmlsZVBpY3R1cmVSZXNwb25zZSIAQp0BCgtjb20udXNlci52MUIJVXNlclByb3RvUAFaRmdpdGh1Yi5jb20vc3BvdGRlbW80L3RyZXZzdGFjay9zZXJ2ZXIvaW50ZXJuYWwvc2VydmljZXMvdXNlci92MTt1c2VydjGiAgNVWFiqAgdVc2VyLlYxygIHVXNlclxWMeICE1VzZXJcVjFcR1BCTWV0YWRhdGHqAghVc2VyOjpWMWIGcHJvdG8z'
);
/**
* @generated from message user.v1.User
*/
export type User = Message<"user.v1.User"> & {
/**
* @generated from field: uint32 id = 1;
*/
id: number;
export type User = Message<'user.v1.User'> & {
/**
* @generated from field: uint32 id = 1;
*/
id: number;
/**
* @generated from field: string username = 2;
*/
username: string;
/**
* @generated from field: string username = 2;
*/
username: string;
/**
* @generated from field: optional string profile_picture = 3;
*/
profilePicture?: string;
/**
* @generated from field: optional string profile_picture = 3;
*/
profilePicture?: string;
};
/**
* Describes the message user.v1.User.
* Use `create(UserSchema)` to create a new message.
*/
export const UserSchema: GenMessage<User> = /*@__PURE__*/
messageDesc(file_user_v1_user, 0);
export const UserSchema: GenMessage<User> = /*@__PURE__*/ messageDesc(file_user_v1_user, 0);
/**
* @generated from message user.v1.GetUserRequest
*/
export type GetUserRequest = Message<"user.v1.GetUserRequest"> & {
};
export type GetUserRequest = Message<'user.v1.GetUserRequest'> & {};
/**
* Describes the message user.v1.GetUserRequest.
* Use `create(GetUserRequestSchema)` to create a new message.
*/
export const GetUserRequestSchema: GenMessage<GetUserRequest> = /*@__PURE__*/
messageDesc(file_user_v1_user, 1);
export const GetUserRequestSchema: GenMessage<GetUserRequest> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 1);
/**
* @generated from message user.v1.GetUserResponse
*/
export type GetUserResponse = Message<"user.v1.GetUserResponse"> & {
/**
* @generated from field: user.v1.User user = 1;
*/
user?: User;
export type GetUserResponse = Message<'user.v1.GetUserResponse'> & {
/**
* @generated from field: user.v1.User user = 1;
*/
user?: User;
};
/**
* Describes the message user.v1.GetUserResponse.
* Use `create(GetUserResponseSchema)` to create a new message.
*/
export const GetUserResponseSchema: GenMessage<GetUserResponse> = /*@__PURE__*/
messageDesc(file_user_v1_user, 2);
export const GetUserResponseSchema: GenMessage<GetUserResponse> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 2);
/**
* @generated from message user.v1.UpdatePasswordRequest
*/
export type UpdatePasswordRequest = Message<"user.v1.UpdatePasswordRequest"> & {
/**
* @generated from field: string old_password = 1;
*/
oldPassword: string;
export type UpdatePasswordRequest = Message<'user.v1.UpdatePasswordRequest'> & {
/**
* @generated from field: string old_password = 1;
*/
oldPassword: string;
/**
* @generated from field: string new_password = 2;
*/
newPassword: string;
/**
* @generated from field: string new_password = 2;
*/
newPassword: string;
/**
* @generated from field: string confirm_password = 3;
*/
confirmPassword: string;
/**
* @generated from field: string confirm_password = 3;
*/
confirmPassword: string;
};
/**
* Describes the message user.v1.UpdatePasswordRequest.
* Use `create(UpdatePasswordRequestSchema)` to create a new message.
*/
export const UpdatePasswordRequestSchema: GenMessage<UpdatePasswordRequest> = /*@__PURE__*/
messageDesc(file_user_v1_user, 3);
export const UpdatePasswordRequestSchema: GenMessage<UpdatePasswordRequest> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 3);
/**
* @generated from message user.v1.UpdatePasswordResponse
*/
export type UpdatePasswordResponse = Message<"user.v1.UpdatePasswordResponse"> & {
/**
* @generated from field: user.v1.User user = 1;
*/
user?: User;
export type UpdatePasswordResponse = Message<'user.v1.UpdatePasswordResponse'> & {
/**
* @generated from field: user.v1.User user = 1;
*/
user?: User;
};
/**
* Describes the message user.v1.UpdatePasswordResponse.
* Use `create(UpdatePasswordResponseSchema)` to create a new message.
*/
export const UpdatePasswordResponseSchema: GenMessage<UpdatePasswordResponse> = /*@__PURE__*/
messageDesc(file_user_v1_user, 4);
export const UpdatePasswordResponseSchema: GenMessage<UpdatePasswordResponse> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 4);
/**
* @generated from message user.v1.GetAPIKeyRequest
*/
export type GetAPIKeyRequest = Message<"user.v1.GetAPIKeyRequest"> & {
/**
* @generated from field: string password = 1;
*/
password: string;
export type GetAPIKeyRequest = Message<'user.v1.GetAPIKeyRequest'> & {
/**
* @generated from field: string password = 1;
*/
password: string;
/**
* @generated from field: string confirm_password = 2;
*/
confirmPassword: string;
/**
* @generated from field: string confirm_password = 2;
*/
confirmPassword: string;
};
/**
* Describes the message user.v1.GetAPIKeyRequest.
* Use `create(GetAPIKeyRequestSchema)` to create a new message.
*/
export const GetAPIKeyRequestSchema: GenMessage<GetAPIKeyRequest> = /*@__PURE__*/
messageDesc(file_user_v1_user, 5);
export const GetAPIKeyRequestSchema: GenMessage<GetAPIKeyRequest> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 5);
/**
* @generated from message user.v1.GetAPIKeyResponse
*/
export type GetAPIKeyResponse = Message<"user.v1.GetAPIKeyResponse"> & {
/**
* @generated from field: string key = 1;
*/
key: string;
export type GetAPIKeyResponse = Message<'user.v1.GetAPIKeyResponse'> & {
/**
* @generated from field: string key = 1;
*/
key: string;
};
/**
* Describes the message user.v1.GetAPIKeyResponse.
* Use `create(GetAPIKeyResponseSchema)` to create a new message.
*/
export const GetAPIKeyResponseSchema: GenMessage<GetAPIKeyResponse> = /*@__PURE__*/
messageDesc(file_user_v1_user, 6);
export const GetAPIKeyResponseSchema: GenMessage<GetAPIKeyResponse> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 6);
/**
* @generated from message user.v1.UpdateProfilePictureRequest
*/
export type UpdateProfilePictureRequest = Message<"user.v1.UpdateProfilePictureRequest"> & {
/**
* @generated from field: string file_name = 1;
*/
fileName: string;
export type UpdateProfilePictureRequest = Message<'user.v1.UpdateProfilePictureRequest'> & {
/**
* @generated from field: string file_name = 1;
*/
fileName: string;
/**
* @generated from field: bytes data = 2;
*/
data: Uint8Array;
/**
* @generated from field: bytes data = 2;
*/
data: Uint8Array;
};
/**
* Describes the message user.v1.UpdateProfilePictureRequest.
* Use `create(UpdateProfilePictureRequestSchema)` to create a new message.
*/
export const UpdateProfilePictureRequestSchema: GenMessage<UpdateProfilePictureRequest> = /*@__PURE__*/
messageDesc(file_user_v1_user, 7);
export const UpdateProfilePictureRequestSchema: GenMessage<UpdateProfilePictureRequest> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 7);
/**
* @generated from message user.v1.UpdateProfilePictureResponse
*/
export type UpdateProfilePictureResponse = Message<"user.v1.UpdateProfilePictureResponse"> & {
/**
* @generated from field: user.v1.User user = 1;
*/
user?: User;
export type UpdateProfilePictureResponse = Message<'user.v1.UpdateProfilePictureResponse'> & {
/**
* @generated from field: user.v1.User user = 1;
*/
user?: User;
};
/**
* Describes the message user.v1.UpdateProfilePictureResponse.
* Use `create(UpdateProfilePictureResponseSchema)` to create a new message.
*/
export const UpdateProfilePictureResponseSchema: GenMessage<UpdateProfilePictureResponse> = /*@__PURE__*/
messageDesc(file_user_v1_user, 8);
export const UpdateProfilePictureResponseSchema: GenMessage<UpdateProfilePictureResponse> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 8);
/**
* @generated from service user.v1.UserService
*/
export const UserService: GenService<{
/**
* @generated from rpc user.v1.UserService.GetUser
*/
getUser: {
methodKind: "unary";
input: typeof GetUserRequestSchema;
output: typeof GetUserResponseSchema;
},
/**
* @generated from rpc user.v1.UserService.UpdatePassword
*/
updatePassword: {
methodKind: "unary";
input: typeof UpdatePasswordRequestSchema;
output: typeof UpdatePasswordResponseSchema;
},
/**
* @generated from rpc user.v1.UserService.GetAPIKey
*/
getAPIKey: {
methodKind: "unary";
input: typeof GetAPIKeyRequestSchema;
output: typeof GetAPIKeyResponseSchema;
},
/**
* @generated from rpc user.v1.UserService.UpdateProfilePicture
*/
updateProfilePicture: {
methodKind: "unary";
input: typeof UpdateProfilePictureRequestSchema;
output: typeof UpdateProfilePictureResponseSchema;
},
}> = /*@__PURE__*/
serviceDesc(file_user_v1_user, 0);
/**
* @generated from rpc user.v1.UserService.GetUser
*/
getUser: {
methodKind: 'unary';
input: typeof GetUserRequestSchema;
output: typeof GetUserResponseSchema;
};
/**
* @generated from rpc user.v1.UserService.UpdatePassword
*/
updatePassword: {
methodKind: 'unary';
input: typeof UpdatePasswordRequestSchema;
output: typeof UpdatePasswordResponseSchema;
};
/**
* @generated from rpc user.v1.UserService.GetAPIKey
*/
getAPIKey: {
methodKind: 'unary';
input: typeof GetAPIKeyRequestSchema;
output: typeof GetAPIKeyResponseSchema;
};
/**
* @generated from rpc user.v1.UserService.UpdateProfilePicture
*/
updateProfilePicture: {
methodKind: 'unary';
input: typeof UpdateProfilePictureRequestSchema;
output: typeof UpdateProfilePictureResponseSchema;
};
}> = /*@__PURE__*/ serviceDesc(file_user_v1_user, 0);

View File

@ -1,5 +1,5 @@
import type { User } from "./services/user/v1/user_pb"
import type { User } from './services/user/v1/user_pb';
export let userState: { user: User | undefined } = $state({
export const userState: { user: User | undefined } = $state({
user: undefined
});

View File

@ -1,25 +1,25 @@
import { createConnectTransport } from "@connectrpc/connect-web"
import { Code, ConnectError, createClient, type Interceptor } from "@connectrpc/connect"
import { AuthService } from "$lib/services/user/v1/auth_pb";
import { UserService } from "$lib/services/user/v1/user_pb";
import { ItemService } from "$lib/services/item/v1/item_pb";
import { goto } from "$app/navigation";
import { createConnectTransport } from '@connectrpc/connect-web';
import { Code, ConnectError, createClient, type Interceptor } from '@connectrpc/connect';
import { AuthService } from '$lib/services/user/v1/auth_pb';
import { UserService } from '$lib/services/user/v1/user_pb';
import { ItemService } from '$lib/services/item/v1/item_pb';
import { goto } from '$app/navigation';
const redirector: Interceptor = (next) => async (req) => {
try {
return await next(req);
} catch (e) {
const error = ConnectError.from(e);
if (error.code === Code.Unauthenticated) {
await goto('/auth');
}
throw e;
}
try {
return await next(req);
} catch (e) {
const error = ConnectError.from(e);
if (error.code === Code.Unauthenticated) {
await goto('/auth');
}
throw e;
}
};
const transport = createConnectTransport({
baseUrl: `${window.location.origin}/grpc`,
interceptors: [redirector],
baseUrl: `${window.location.origin}/grpc`,
interceptors: [redirector]
});
export const AuthClient = createClient(AuthService, transport);

View File

@ -20,7 +20,7 @@
<Button.Root
{type}
class={cn(
'bg-sky text-crust flex justify-center items-center hover:brightness-120 focus:outline-sky w-fit cursor-pointer rounded p-2 px-4 text-sm font-medium transition-all focus:outline-2 focus:outline-offset-1',
'bg-sky text-crust focus:outline-sky flex w-fit cursor-pointer items-center justify-center rounded p-2 px-4 text-sm font-medium transition-all hover:brightness-120 focus:outline-2 focus:outline-offset-1',
className
)}
{onclick}

View File

@ -42,11 +42,11 @@
<div
class="bg-mantle border-surface-0 hover:border-surface-2 flex items-center rounded border pl-2 text-sm drop-shadow-md transition-all"
>
<div class="grow flex items-center justify-center">
{#each ['start', 'end'] as const as type}
<div class="flex grow items-center justify-center">
{#each ['start', 'end'] as const as type (type)}
<DateRangePicker.Input {type}>
{#snippet children({ segments })}
{#each segments as { part, value }}
{#each segments as { part, value } (value)}
<div class="inline-block select-none">
{#if part === 'literal'}
<DateRangePicker.Segment {part} class="text-overlay-0 p-1">
@ -72,7 +72,7 @@
{/each}
</div>
<DateRangePicker.Trigger
class="text-overlay-2 hover:bg-surface-0 grow flex justify-center items-center focus:outline-sky ml-1 cursor-pointer p-2 transition-all focus:outline focus:outline-offset-1"
class="text-overlay-2 hover:bg-surface-0 focus:outline-sky ml-1 flex grow cursor-pointer items-center justify-center p-2 transition-all focus:outline focus:outline-offset-1"
>
<Calendar size="20" />
</DateRangePicker.Trigger>
@ -114,21 +114,21 @@
>
<ArrowLeft />
</DateRangePicker.PrevButton>
<DateRangePicker.Heading class="select-none font-medium" />
<DateRangePicker.Heading class="font-medium select-none" />
<DateRangePicker.NextButton
class="hover:bg-surface-0 inline-flex size-10 cursor-pointer items-center justify-center rounded transition-all active:scale-[0.98]"
>
<ArrowRight />
</DateRangePicker.NextButton>
</DateRangePicker.Header>
<div class="flex flex-col space-y-4 pt-4 sm:flex-row sm:space-x-4 sm:space-y-0">
{#each months as month}
<DateRangePicker.Grid class="w-full border-collapse select-none space-y-1">
<div class="flex flex-col space-y-4 pt-4 sm:flex-row sm:space-y-0 sm:space-x-4">
{#each months as month (month)}
<DateRangePicker.Grid class="w-full border-collapse space-y-1 select-none">
<DateRangePicker.GridHead>
<DateRangePicker.GridRow class="mb-1 flex w-full justify-between">
{#each weekdays as day}
{#each weekdays as day (day)}
<DateRangePicker.HeadCell
class="text-overlay-0 font-normal! w-10 rounded text-xs"
class="text-overlay-0 w-10 rounded text-xs font-normal!"
>
{day.slice(0, 2)}
</DateRangePicker.HeadCell>
@ -136,19 +136,19 @@
</DateRangePicker.GridRow>
</DateRangePicker.GridHead>
<DateRangePicker.GridBody>
{#each month.weeks as weekDates}
{#each month.weeks as weekDates (weekDates)}
<DateRangePicker.GridRow class="flex w-full">
{#each weekDates as date}
{#each weekDates as date (date)}
<DateRangePicker.Cell
{date}
month={month.value}
class="p-0! relative m-0 size-10 overflow-visible text-center text-sm focus-within:relative focus-within:z-20"
class="relative m-0 size-10 overflow-visible p-0! text-center text-sm focus-within:relative focus-within:z-20"
>
<DateRangePicker.Day
class={'hover:border-sky focus-visible:ring-foreground! data-selected:rounded-none data-selection-end:rounded-r data-selection-start:rounded-l data-highlighted:bg-surface-0 data-selected:bg-surface-1 data-selection-end:bg-surface-2 data-selection-start:bg-surface-2 data-disabled:text-text/30 data-unavailable:text-overlay-0 data-disabled:pointer-events-none data-outside-month:pointer-events-none data-highlighted:rounded-none data-unavailable:line-through group relative inline-flex size-10 items-center justify-center overflow-visible whitespace-nowrap rounded border border-transparent bg-transparent p-0 text-sm font-normal transition-all'}
class="hover:border-sky focus-visible:ring-foreground! data-highlighted:bg-surface-0 data-selected:bg-surface-1 data-selection-end:bg-surface-2 data-selection-start:bg-surface-2 data-disabled:text-text/30 data-unavailable:text-overlay-0 group relative inline-flex size-10 items-center justify-center overflow-visible rounded border border-transparent bg-transparent p-0 text-sm font-normal whitespace-nowrap transition-all data-disabled:pointer-events-none data-highlighted:rounded-none data-outside-month:pointer-events-none data-selected:rounded-none data-selection-end:rounded-r data-selection-start:rounded-l data-unavailable:line-through"
>
<div
class="bg-sky group-data-selected:bg-background group-data-today:block absolute top-[5px] hidden size-1 rounded-full transition-all"
class="bg-sky group-data-selected:bg-background absolute top-[5px] hidden size-1 rounded-full transition-all group-data-today:block"
></div>
{date.day}
</DateRangePicker.Day>

View File

@ -48,7 +48,7 @@
}}
>
<div
class="bg-mantle border-surface-0 fixed inset-0 left-[50%] top-[50%] z-50 size-fit w-96 -translate-x-1/2 -translate-y-1/2 transform overflow-y-auto rounded-xl border pb-1 drop-shadow-md"
class="bg-mantle border-surface-0 fixed inset-0 top-[50%] left-[50%] z-50 size-fit w-96 -translate-x-1/2 -translate-y-1/2 transform overflow-y-auto rounded-xl border pb-1 drop-shadow-md"
>
<div class="border-surface-0 flex justify-between border-b p-2">
<h1 class="grow truncate p-1 text-center text-xl font-bold">

View File

@ -24,7 +24,7 @@
perPage={limit}
onPageChange={(e) => {
offset = (e - 1) * limit;
window.scrollTo(0, 0);
window.scrollTo(0, 0);
onchange?.(e);
}}
>
@ -38,11 +38,11 @@
<div class="flex items-center gap-2">
{#each pages as page (page.key)}
{#if page.type === 'ellipsis'}
<div class="select-none font-medium">...</div>
<div class="font-medium select-none">...</div>
{:else}
<Pagination.Page
{page}
class="hover:bg-surface-0 data-selected:bg-surface-0 data-selected:text-background inline-flex size-10 cursor-pointer select-none items-center justify-center rounded bg-transparent font-medium transition-all disabled:cursor-not-allowed disabled:opacity-50 hover:disabled:bg-transparent"
class="hover:bg-surface-0 data-selected:bg-surface-0 data-selected:text-background inline-flex size-10 cursor-pointer items-center justify-center rounded bg-transparent font-medium transition-all select-none disabled:cursor-not-allowed disabled:opacity-50 hover:disabled:bg-transparent"
>
{page.value}
</Pagination.Page>

View File

@ -2,19 +2,20 @@
import { cn } from '$lib/utils';
import { Check, ChevronsDown, ChevronsUp, ChevronsUpDown, X } from '@lucide/svelte';
import { Select } from 'bits-ui';
import { fade } from 'svelte/transition';
let {
value = $bindable('10'),
placeholder = 'Select an item',
items = [],
defaultValue = '',
defaultValue = '',
className,
onchange
}: {
value?: string;
placeholder?: string;
items: { value: string; label: string; disabled?: boolean }[];
defaultValue?: string;
defaultValue?: string;
className?: string;
onchange?: (e: string) => void;
} = $props();
@ -30,42 +31,53 @@
>
<Select.Root type="single" {items} bind:value onValueChange={onchange}>
<Select.Trigger
class="focus:outline-sky data-placeholder:text-overlay-0 gap-2 inline-flex grow cursor-pointer select-none items-center justify-between rounded-l py-2 pl-2 text-sm transition-colors focus:outline focus:outline-offset-1"
class="focus:outline-sky data-placeholder:text-overlay-0 inline-flex grow cursor-pointer items-center justify-between gap-2 rounded-l py-2 pl-2 text-sm transition-colors select-none focus:outline focus:outline-offset-1"
aria-label={placeholder}
>
{selectedLabel}
<ChevronsUpDown class="text-overlay-0" size="20" />
</Select.Trigger>
<Select.Portal>
<Select.Content
class="focus-override border-surface-0 bg-mantle shadow-popover data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 outline-hidden z-50 select-none rounded border p-1"
sideOffset={10}
>
<Select.ScrollUpButton class="flex w-full items-center justify-center">
<ChevronsUp size="20" />
</Select.ScrollUpButton>
<Select.Viewport class="p-1">
{#each items as item, i (i + item.value)}
<Select.Item
class="data-disabled:cursor-not-allowed data-highlighted:bg-surface-0 outline-hidden data-disabled:opacity-50 flex h-10 w-full cursor-pointer select-none items-center gap-4 rounded px-5 py-3 text-sm capitalize"
value={item.value}
label={item.label}
disabled={item.disabled}
>
{#snippet children({ selected })}
{item.label}
{#if selected}
<div class="ml-auto">
<Check size="20" />
</div>
{/if}
{/snippet}
</Select.Item>
{/each}
</Select.Viewport>
<Select.ScrollDownButton class="flex w-full items-center justify-center">
<ChevronsDown size="20" />
</Select.ScrollDownButton>
<Select.Content forceMount>
{#snippet child({ wrapperProps, props, open })}
{#if open}
<div {...wrapperProps}>
<div
{...props}
class="border-surface-0 bg-mantle shadow-popover z-50 mt-1 rounded border p-1 outline-hidden select-none"
transition:fade={{
duration: 100
}}
>
<Select.ScrollUpButton class="flex w-full items-center justify-center">
<ChevronsUp size="20" />
</Select.ScrollUpButton>
<Select.Viewport class="p-1">
{#each items as item, i (i + item.value)}
<Select.Item
class="data-highlighted:bg-surface-0 flex h-10 w-full cursor-pointer items-center gap-4 rounded px-5 py-3 text-sm capitalize outline-hidden select-none data-disabled:cursor-not-allowed data-disabled:opacity-50"
value={item.value}
label={item.label}
disabled={item.disabled}
>
{#snippet children({ selected })}
{item.label}
{#if selected}
<div class="ml-auto">
<Check size="20" />
</div>
{/if}
{/snippet}
</Select.Item>
{/each}
</Select.Viewport>
<Select.ScrollDownButton class="flex w-full items-center justify-center">
<ChevronsDown size="20" />
</Select.ScrollDownButton>
</div>
</div>
{/if}
{/snippet}
</Select.Content>
</Select.Portal>
</Select.Root>
@ -74,7 +86,7 @@
type="button"
onclick={() => {
value = defaultValue;
onchange?.(value);
onchange?.(value);
}}
>
<X size="20" />

View File

@ -1,5 +1,5 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));

View File

@ -98,14 +98,14 @@
>
<NavigationMenu.Root orientation="vertical">
<NavigationMenu.List
class="flex w-full flex-col gap-2 overflow-y-auto overflow-x-hidden p-2"
class="flex w-full flex-col gap-2 overflow-x-hidden overflow-y-auto p-2"
>
{#each menuItems as item}
{#each menuItems as item (item.name)}
{@const Icon = item.icon}
<NavigationMenu.Item>
<NavigationMenu.Link
class={cn(
'hover:bg-surface-0 flex select-none gap-2 whitespace-nowrap rounded-lg p-2 transition-all',
'hover:bg-surface-0 flex gap-2 rounded-lg p-2 whitespace-nowrap transition-all select-none',
page.url.pathname === item.href && 'bg-surface-0'
)}
href={item.href}
@ -126,7 +126,7 @@
<div class="border-surface-0 flex flex-col gap-2 border-t p-2">
<a
href="/settings"
class="hover:bg-surface-0 flex select-none items-center gap-2 rounded-lg p-2 transition-all"
class="hover:bg-surface-0 flex items-center gap-2 rounded-lg p-2 transition-all select-none"
onclick={() => {
if (sidebarOpen) {
sidebarOpen = false;
@ -138,7 +138,7 @@
</a>
<button
class="hover:bg-surface-0 flex w-full cursor-pointer items-center gap-2 whitespace-nowrap rounded-lg p-2 transition-all"
class="hover:bg-surface-0 flex w-full cursor-pointer items-center gap-2 rounded-lg p-2 whitespace-nowrap transition-all"
onclick={logout}
>
<LogOut size="20" />
@ -152,7 +152,7 @@
</Dialog.Portal>
</Dialog.Root>
<a href="/" class="flex select-none items-center gap-2 text-2xl font-bold tracking-wider">
<a href="/" class="flex items-center gap-2 text-2xl font-bold tracking-wider select-none">
TrevStack
<LayoutGrid />
</a>
@ -160,11 +160,11 @@
<NavigationMenu.Root class="hidden md:block">
<NavigationMenu.List class="flex gap-2">
{#each menuItems as item}
{#each menuItems as item (item.name)}
<NavigationMenu.Item>
<NavigationMenu.Link
class={cn(
'hover:bg-surface-0 flex select-none gap-2 rounded-lg p-1 px-2 transition-all',
'hover:bg-surface-0 flex gap-2 rounded-lg p-1 px-2 transition-all select-none',
page.url.pathname === item.href && 'bg-surface-0'
)}
href={item.href}
@ -179,7 +179,7 @@
<Popover.Root bind:open={popupOpen}>
<Popover.Trigger
class="outline-surface-2 hover:brightness-120 bg-text text-crust h-9 w-9 cursor-pointer rounded-full text-sm outline outline-offset-2 transition-all"
class="outline-surface-2 bg-text text-crust h-9 w-9 cursor-pointer rounded-full text-sm outline outline-offset-2 transition-all hover:brightness-120"
>
<Avatar />
</Popover.Trigger>

View File

@ -50,12 +50,7 @@
</script>
<div class="mx-4 my-2 flex flex-wrap items-center justify-center gap-2">
<Input
bind:value={filter}
className="bg-mantle"
placeholder="Filter"
onchange={updateItems}
/>
<Input bind:value={filter} className="bg-mantle" placeholder="Filter" onchange={updateItems} />
<Select
items={[
{
@ -238,7 +233,7 @@
<td class="w-8"></td>
</tr>
{:then items}
{#each items as item}
{#each items as item (item.id)}
<tr class="border-surface-0 border-b">
<td class="px-6 py-3">
{item.added ? timestampDate(item.added).toLocaleString() : ''}
@ -287,7 +282,7 @@
</div>
</div>
{:then items}
{#each items as item}
{#each items as item (item.id)}
<div
class="border-surface-0 bg-mantle flex w-full flex-wrap gap-6 rounded border p-5 drop-shadow-md"
>
@ -313,7 +308,7 @@
<span class="text-subtext-0 text-sm">Quantity</span>
<span class="truncate">{item.quantity}</span>
</div>
<div class="flex justify-end ml-auto gap-2">
<div class="ml-auto flex justify-end gap-2">
{@render editModal(item)}
{@render deleteModal(item)}
</div>
@ -322,7 +317,7 @@
{/await}
</div>
<div class="mx-4 mb-4 mt-2 flex justify-end sm:mt-1">
<div class="mx-4 mt-2 mb-4 flex justify-end sm:mt-1">
<Modal bind:open={addedOpen}>
{#snippet trigger(props)}
<Button {...props} className="bg-sky">

View File

@ -17,7 +17,7 @@
<div class="m-auto flex w-96 flex-col gap-4 p-4">
<div class="flex items-center justify-center gap-4">
<div
class="outline-surface-2 bg-text text-crust h-9 w-9 select-none rounded-full text-sm outline outline-offset-2"
class="outline-surface-2 bg-text text-crust h-9 w-9 rounded-full text-sm outline outline-offset-2 select-none"
>
<Avatar />
</div>

View File

@ -5,10 +5,12 @@
let { children } = $props();
</script>
<Toaster toastOptions={{
classes: {
toast: '!bg-mantle !text-text !border-surface-0',
}
}} />
<Toaster
toastOptions={{
classes: {
toast: '!bg-mantle !text-text !border-surface-0'
}
}}
/>
{@render children()}

View File

@ -7,6 +7,7 @@
import { toast } from 'svelte-sonner';
import Button from '$lib/ui/Button.svelte';
import Input from '$lib/ui/Input.svelte';
import { page } from '$app/state';
let tab = $state('login');
</script>
@ -41,6 +42,7 @@
const formData = new FormData(e.target as HTMLFormElement);
const username = formData.get('login-username')?.toString();
const password = formData.get('login-password')?.toString();
const redir = page.url.searchParams.get('redir') || '/';
try {
const response = await AuthClient.login({
@ -49,7 +51,7 @@
});
if (response.token && username) {
goto('/');
goto(redir);
}
} catch (err) {
const error = ConnectError.from(err);

View File

@ -5,76 +5,76 @@ import { build, files, version } from '$service-worker';
const CACHE = `cache-${version}`;
const ASSETS = [
...build, // the app itself
...files // everything in `static`
...build, // the app itself
...files // everything in `static`
];
self.addEventListener('install', (event) => {
// Create a new cache and add all files to it
async function addFilesToCache() {
const cache = await caches.open(CACHE);
await cache.addAll(ASSETS);
}
// Create a new cache and add all files to it
async function addFilesToCache() {
const cache = await caches.open(CACHE);
await cache.addAll(ASSETS);
}
event.waitUntil(addFilesToCache());
event.waitUntil(addFilesToCache());
});
self.addEventListener('activate', (event) => {
// Remove previous cached data from disk
async function deleteOldCaches() {
for (const key of await caches.keys()) {
if (key !== CACHE) await caches.delete(key);
}
}
// Remove previous cached data from disk
async function deleteOldCaches() {
for (const key of await caches.keys()) {
if (key !== CACHE) await caches.delete(key);
}
}
event.waitUntil(deleteOldCaches());
event.waitUntil(deleteOldCaches());
});
self.addEventListener('fetch', (event) => {
// ignore POST requests etc
if (event.request.method !== 'GET') return;
// ignore POST requests etc
if (event.request.method !== 'GET') return;
async function respond() {
const url = new URL(event.request.url);
const cache = await caches.open(CACHE);
async function respond() {
const url = new URL(event.request.url);
const cache = await caches.open(CACHE);
// `build`/`files` can always be served from the cache
if (ASSETS.includes(url.pathname)) {
const response = await cache.match(url.pathname);
// `build`/`files` can always be served from the cache
if (ASSETS.includes(url.pathname)) {
const response = await cache.match(url.pathname);
if (response) {
return response;
}
}
if (response) {
return response;
}
}
// for everything else, try the network first, but
// fall back to the cache if we're offline
try {
const response = await fetch(event.request);
// for everything else, try the network first, but
// fall back to the cache if we're offline
try {
const response = await fetch(event.request);
// if we're offline, fetch can return a value that is not a Response
// instead of throwing - and we can't pass this non-Response to respondWith
if (!(response instanceof Response)) {
throw new Error('invalid response from fetch');
}
// if we're offline, fetch can return a value that is not a Response
// instead of throwing - and we can't pass this non-Response to respondWith
if (!(response instanceof Response)) {
throw new Error('invalid response from fetch');
}
if (response.status === 200) {
cache.put(event.request, response.clone());
}
if (response.status === 200) {
cache.put(event.request, response.clone());
}
return response;
} catch (err) {
const response = await cache.match(event.request);
return response;
} catch (err) {
const response = await cache.match(event.request);
if (response) {
return response;
}
if (response) {
return response;
}
// if there's no cache, then just error out
// as there is nothing we can do to respond to this request
throw err;
}
}
// if there's no cache, then just error out
// as there is nothing we can do to respond to this request
throw err;
}
}
event.respondWith(respond());
event.respondWith(respond());
});

View File

@ -5,7 +5,7 @@
"display": "standalone",
"start_url": "/",
"background_color": "#181825",
"theme_color": "#89dceb",
"theme_color": "#11111b",
"icons": [
{
"src": "icon.png",

View File

@ -1,23 +1,20 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import tailwindcss from '@tailwindcss/vite'
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({
plugins: [
tailwindcss(),
sveltekit()
],
plugins: [tailwindcss(), sveltekit()],
server: {
proxy: {
'/grpc': {
target: 'http://localhost:8080',
changeOrigin: true,
changeOrigin: true
},
'/file': {
target: 'http://localhost:8080',
changeOrigin: true,
},
changeOrigin: true
}
},
host: '0.0.0.0',
host: '0.0.0.0'
}
});

143
flake.nix
View File

@ -1,5 +1,5 @@
{
description = "A trevstack development environment";
description = "A template for trevstack";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
@ -15,7 +15,7 @@
let
pname = "trevstack";
version = "0.1.1";
version = "0.0.5";
pkgs = import nixpkgs {
inherit system;
@ -38,7 +38,7 @@
pname = "${pname}-client";
inherit version;
src = gitignore.lib.gitignoreSource ./client;
npmDepsHash = "sha256-TO7eumSEJdmG4wZ5B/k8gChmmSDvfYKEtExHLLYHjj4=";
npmDepsHash = "sha256-19sYDoA0nX3XteC0jKrqhnE7050+on3gDg72QqNR080=";
nodejs = pkgs.nodejs_22;
npmFlags = [ "--legacy-peer-deps" ];
@ -52,11 +52,15 @@
{
devShells.default = pkgs.mkShell {
packages = with pkgs; [
git
nix-update
# Go backend
go
gotools
gopls
air
revive
# Protobuf middleware
buf
@ -69,23 +73,20 @@
# Svelte frontend
nodejs_22
# Nix
nix-update
# Helper scripts
(writeShellApplication {
name = "run";
name = "ts-run";
text = ''
gitroot=$(git rev-parse --show-toplevel)
git_root=$(git rev-parse --show-toplevel)
(cd "''${gitroot}/server" && air) &
(cd "''${git_root}/server" && air) &
P1=$!
(cd "''${gitroot}/client" && npm run dev) &
(cd "''${git_root}/client" && npm run dev) &
P2=$!
(cd "''${gitroot}" && protobufwatch) &
(cd "''${git_root}" && ts-pbwatch) &
P3=$!
trap 'kill $P1 $P2 $P3' SIGINT SIGTERM
@ -98,7 +99,7 @@
})
(writeShellApplication {
name = "protobufwatch";
name = "ts-pbwatch";
text = ''
inotifywait -mre close_write,moved_to,create proto | while read -r _ _ basename;
@ -111,17 +112,121 @@
done
'';
})
(writeShellApplication {
name = "ts-update";
text = ''
git_root=$(git rev-parse --show-toplevel)
cd "''${git_root}/client"
npm update --save
if ! git diff --exit-code package.json package-lock.json; then
git add package-lock.json
git add package.json
git commit -m "build(client): updated npm dependencies"
fi
cd "''${git_root}/server"
go get -u
go mod tidy
if ! git diff --exit-code go.mod go.sum; then
git add go.mod
git add go.sum
git commit -m "build(server): updated go dependencies"
fi
cd "''${git_root}"
nix-update --flake --version=skip --subpackage client default
if ! git diff --exit-code flake.nix; then
git add flake.nix
git commit -m "build(nix): updated nix hashes"
fi
'';
})
(writeShellApplication {
name = "ts-bump";
text = ''
git_root=$(git rev-parse --show-toplevel)
next_version=$(echo "${version}" | awk -F. -v OFS=. '{$NF += 1 ; print}')
cd "''${git_root}/client"
npm version "''${next_version}"
git add package-lock.json
git add package.json
cd "''${git_root}"
nix-update --flake --version "''${next_version}" --subpackage client default
git add flake.nix
git commit -m "bump: v${version} -> v''${next_version}"
git push origin main
git tag -a "v''${next_version}" -m "bump: v${version} -> v''${next_version}"
git push origin "v''${next_version}"
'';
})
(writeShellApplication {
name = "ts-lint";
text = ''
git_root=$(git rev-parse --show-toplevel)
cd "''${git_root}/client"
npm run check
npm run lint
cd "''${git_root}/server"
revive -config revive.toml -formatter friendly ./...
'';
})
(writeShellApplication {
name = "ts-build";
text = ''
git_root=$(git rev-parse --show-toplevel)
cd "''${git_root}"
echo "Building client"
nix build .#trevstack-client
cp -a result/. server/internal/handlers/client/client
chmod -R u+w server/internal/handlers/client/client
cd "''${git_root}/server"
echo "Building ${pname}-windows-amd64-${version}.exe"
GOOS=windows GOARCH=amd64 go build -o "../build/${pname}-windows-amd64-${version}.exe" .
echo "Building ${pname}-linux-amd64-${version}"
GOOS=linux GOARCH=amd64 go build -o "../build/${pname}-linux-amd64-${version}" .
echo "Building ${pname}-linux-amd64-${version}"
GOOS=linux GOARCH=arm64 go build -o "../build/${pname}-linux-arm64-${version}" .
echo "Building ${pname}-linux-arm-${version}"
GOOS=linux GOARCH=arm go build -o "../build/${pname}-linux-arm-${version}" .
'';
})
];
};
packages.default = pkgs.buildGoModule {
inherit pname version;
src = gitignore.lib.gitignoreSource ./server;
vendorHash = "sha256-FyqcKhJy58uL3UiGA9tg7pSt0OQ1NIZw+khTictyzcw=";
packages = rec {
default = trevstack;
preBuild = ''
cp -r ${client} internal/handlers/client/client
'';
trevstack = pkgs.buildGoModule {
inherit client pname version;
src = gitignore.lib.gitignoreSource ./server;
vendorHash = "sha256-sANPwYLGwMcWyMR7Veho81aAMfIQpVzZS5Q9eveR8o8=";
env.CGO_ENABLED = 0;
preBuild = ''
cp -r ${client} internal/handlers/client/client
'';
};
trevstack-client = client;
};
}
);

View File

@ -5,7 +5,7 @@ tmp_dir = "tmp"
[build]
args_bin = []
bin = "./tmp/main"
cmd = "go build -o ./tmp/main ."
cmd = "go build -tags dev -o ./tmp/main ."
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = []

View File

@ -19,21 +19,23 @@ require (
require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/glebarez/go-sqlite v1.21.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/glebarez/go-sqlite v1.22.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.5.5 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.2 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
modernc.org/libc v1.22.5 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.5.0 // indirect
modernc.org/sqlite v1.23.1 // indirect
modernc.org/libc v1.61.13 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.9.0 // indirect
modernc.org/sqlite v1.36.1 // indirect
)

View File

@ -7,37 +7,38 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI=
github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
@ -49,17 +50,23 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -70,11 +77,27 @@ gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314=
gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=
modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=
modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0=
modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo=
modernc.org/ccgo/v4 v4.23.16/go.mod h1:nNma8goMTY7aQZQNTyN9AIoJfxav4nvTnvKThAeMDdo=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/gc/v2 v2.6.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw=
modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8=
modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.9.0 h1:smV8d5mrOAvj5QIYbc2XLSRWvAIyPI+kQHqxZaxEqCM=
modernc.org/memory v1.9.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.36.1 h1:bDa8BJUH4lg6EGkLbahKe/8QqoF8p9gArSc6fTqYhyQ=
modernc.org/sqlite v1.36.1/go.mod h1:7MPwH7Z6bREicF9ZVUR78P1IKuxfZ8mRIDHD0iD+8TU=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=

View File

@ -1,16 +1,24 @@
// go:build !dev
//go:build !dev
package client
import (
"embed"
"io/fs"
"log"
"net/http"
)
//go:embed client
//go:embed all:client
var eclient embed.FS
func init() {
fs := http.FS(eclient)
log.Println("Initializing client for production")
client, err := fs.Sub(eclient, "client")
if err != nil {
log.Fatalf("failed to get client: %v", err)
}
fs := http.FS(client)
embedfs = &fs
}

View File

@ -48,10 +48,8 @@ func (h *FileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
w.Header().Set("Content-Type", http.DetectContentType(file.Data))
w.Write(file.Data)
return
} else {
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
return
}
}

View File

@ -1,4 +1,4 @@
package handlers
package item
import (
"context"
@ -15,12 +15,12 @@ import (
"gorm.io/gorm"
)
type ItemHandler struct {
type Handler struct {
db *gorm.DB
key []byte
}
func (h *ItemHandler) GetItem(ctx context.Context, req *connect.Request[itemv1.GetItemRequest]) (*connect.Response[itemv1.GetItemResponse], error) {
func (h *Handler) GetItem(ctx context.Context, req *connect.Request[itemv1.GetItemRequest]) (*connect.Response[itemv1.GetItemResponse], error) {
userid, ok := interceptors.GetUserContext(ctx)
if !ok {
return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("unauthenticated"))
@ -38,7 +38,7 @@ func (h *ItemHandler) GetItem(ctx context.Context, req *connect.Request[itemv1.G
return res, nil
}
func (h *ItemHandler) GetItems(ctx context.Context, req *connect.Request[itemv1.GetItemsRequest]) (*connect.Response[itemv1.GetItemsResponse], error) {
func (h *Handler) GetItems(ctx context.Context, req *connect.Request[itemv1.GetItemsRequest]) (*connect.Response[itemv1.GetItemsResponse], error) {
userid, ok := interceptors.GetUserContext(ctx)
if !ok {
return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("unauthenticated"))
@ -88,7 +88,7 @@ func (h *ItemHandler) GetItems(ctx context.Context, req *connect.Request[itemv1.
return res, nil
}
func (h *ItemHandler) CreateItem(ctx context.Context, req *connect.Request[itemv1.CreateItemRequest]) (*connect.Response[itemv1.CreateItemResponse], error) {
func (h *Handler) CreateItem(ctx context.Context, req *connect.Request[itemv1.CreateItemRequest]) (*connect.Response[itemv1.CreateItemResponse], error) {
userid, ok := interceptors.GetUserContext(ctx)
if !ok {
return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("unauthenticated"))
@ -113,7 +113,7 @@ func (h *ItemHandler) CreateItem(ctx context.Context, req *connect.Request[itemv
return res, nil
}
func (h *ItemHandler) UpdateItem(ctx context.Context, req *connect.Request[itemv1.UpdateItemRequest]) (*connect.Response[itemv1.UpdateItemResponse], error) {
func (h *Handler) UpdateItem(ctx context.Context, req *connect.Request[itemv1.UpdateItemRequest]) (*connect.Response[itemv1.UpdateItemResponse], error) {
userid, ok := interceptors.GetUserContext(ctx)
if !ok {
return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("unauthenticated"))
@ -143,7 +143,7 @@ func (h *ItemHandler) UpdateItem(ctx context.Context, req *connect.Request[itemv
return res, nil
}
func (h *ItemHandler) DeleteItem(ctx context.Context, req *connect.Request[itemv1.DeleteItemRequest]) (*connect.Response[itemv1.DeleteItemResponse], error) {
func (h *Handler) DeleteItem(ctx context.Context, req *connect.Request[itemv1.DeleteItemRequest]) (*connect.Response[itemv1.DeleteItemResponse], error) {
userid, ok := interceptors.GetUserContext(ctx)
if !ok {
return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("unauthenticated"))
@ -158,11 +158,11 @@ func (h *ItemHandler) DeleteItem(ctx context.Context, req *connect.Request[itemv
return res, nil
}
func NewItemHandler(db *gorm.DB, key string) (string, http.Handler) {
func NewHandler(db *gorm.DB, key string) (string, http.Handler) {
interceptors := connect.WithInterceptors(interceptors.NewAuthInterceptor(key))
return itemv1connect.NewItemServiceHandler(
&ItemHandler{
&Handler{
db: db,
key: []byte(key),
},

View File

@ -1,4 +1,4 @@
package handlers
package user
import (
"context"
@ -22,7 +22,7 @@ type AuthHandler struct {
key []byte
}
func (h *AuthHandler) Login(ctx context.Context, req *connect.Request[userv1.LoginRequest]) (*connect.Response[userv1.LoginResponse], error) {
func (h *AuthHandler) Login(_ context.Context, req *connect.Request[userv1.LoginRequest]) (*connect.Response[userv1.LoginResponse], error) {
// Validate
user := models.User{}
if err := h.db.First(&user, "username = ?", req.Msg.Username).Error; err != nil {
@ -69,7 +69,7 @@ func (h *AuthHandler) Login(ctx context.Context, req *connect.Request[userv1.Log
return res, nil
}
func (h *AuthHandler) SignUp(ctx context.Context, req *connect.Request[userv1.SignUpRequest]) (*connect.Response[userv1.SignUpResponse], error) {
func (h *AuthHandler) SignUp(_ context.Context, req *connect.Request[userv1.SignUpRequest]) (*connect.Response[userv1.SignUpResponse], error) {
// Validate
if err := h.db.First(&models.User{}, "username = ?", req.Msg.Username).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
@ -101,7 +101,7 @@ func (h *AuthHandler) SignUp(ctx context.Context, req *connect.Request[userv1.Si
return res, nil
}
func (h *AuthHandler) Logout(ctx context.Context, req *connect.Request[userv1.LogoutRequest]) (*connect.Response[userv1.LogoutResponse], error) {
func (h *AuthHandler) Logout(_ context.Context, _ *connect.Request[userv1.LogoutRequest]) (*connect.Response[userv1.LogoutResponse], error) {
// Clear cookie
cookie := http.Cookie{
Name: "token",

View File

@ -1,4 +1,4 @@
package handlers
package user
import (
"context"
@ -17,12 +17,12 @@ import (
"gorm.io/gorm"
)
type UserHandler struct {
type Handler struct {
db *gorm.DB
key []byte
}
func (h *UserHandler) GetUser(ctx context.Context, req *connect.Request[userv1.GetUserRequest]) (*connect.Response[userv1.GetUserResponse], error) {
func (h *Handler) GetUser(ctx context.Context, _ *connect.Request[userv1.GetUserRequest]) (*connect.Response[userv1.GetUserResponse], error) {
userid, ok := interceptors.GetUserContext(ctx)
if !ok {
return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("unauthenticated"))
@ -40,7 +40,7 @@ func (h *UserHandler) GetUser(ctx context.Context, req *connect.Request[userv1.G
return res, nil
}
func (h *UserHandler) UpdatePassword(ctx context.Context, req *connect.Request[userv1.UpdatePasswordRequest]) (*connect.Response[userv1.UpdatePasswordResponse], error) {
func (h *Handler) UpdatePassword(ctx context.Context, req *connect.Request[userv1.UpdatePasswordRequest]) (*connect.Response[userv1.UpdatePasswordResponse], error) {
userid, ok := interceptors.GetUserContext(ctx)
if !ok {
return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("unauthenticated"))
@ -75,7 +75,7 @@ func (h *UserHandler) UpdatePassword(ctx context.Context, req *connect.Request[u
return res, nil
}
func (h *UserHandler) GetAPIKey(ctx context.Context, req *connect.Request[userv1.GetAPIKeyRequest]) (*connect.Response[userv1.GetAPIKeyResponse], error) {
func (h *Handler) GetAPIKey(ctx context.Context, req *connect.Request[userv1.GetAPIKeyRequest]) (*connect.Response[userv1.GetAPIKeyResponse], error) {
userid, ok := interceptors.GetUserContext(ctx)
if !ok {
return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("unauthenticated"))
@ -114,7 +114,7 @@ func (h *UserHandler) GetAPIKey(ctx context.Context, req *connect.Request[userv1
return res, nil
}
func (h *UserHandler) UpdateProfilePicture(ctx context.Context, req *connect.Request[userv1.UpdateProfilePictureRequest]) (*connect.Response[userv1.UpdateProfilePictureResponse], error) {
func (h *Handler) UpdateProfilePicture(ctx context.Context, req *connect.Request[userv1.UpdateProfilePictureRequest]) (*connect.Response[userv1.UpdateProfilePictureResponse], error) {
userid, ok := interceptors.GetUserContext(ctx)
if !ok {
return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("unauthenticated"))
@ -169,11 +169,11 @@ func (h *UserHandler) UpdateProfilePicture(ctx context.Context, req *connect.Req
return res, nil
}
func NewUserHandler(db *gorm.DB, key string) (string, http.Handler) {
func NewHandler(db *gorm.DB, key string) (string, http.Handler) {
interceptors := connect.WithInterceptors(interceptors.NewAuthInterceptor(key))
return userv1connect.NewUserServiceHandler(
&UserHandler{
&Handler{
db: db,
key: []byte(key),
},

View File

@ -6,6 +6,7 @@ import (
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"strings"
@ -49,10 +50,7 @@ func WithAuthRedirect(next http.Handler, key string) http.Handler {
}
next.ServeHTTP(w, r)
case "_app":
next.ServeHTTP(w, r)
case "favicon.png":
case "_app", "favicon.png", "icon.png":
next.ServeHTTP(w, r)
default:
@ -62,22 +60,23 @@ func WithAuthRedirect(next http.Handler, key string) http.Handler {
}
// Redirect if not authenticated
http.Redirect(w, r, "/auth", http.StatusFound)
pathRedir := url.QueryEscape(r.URL.Path)
http.Redirect(w, r, fmt.Sprintf("/auth?redir=%s", pathRedir), http.StatusFound)
}
})
}
type authInterceptor struct {
type AuthInterceptor struct {
key string
}
func NewAuthInterceptor(key string) *authInterceptor {
return &authInterceptor{
func NewAuthInterceptor(key string) *AuthInterceptor {
return &AuthInterceptor{
key: key,
}
}
func (i *authInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc {
func (i *AuthInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc {
// Same as previous UnaryInterceptorFunc.
return connect.UnaryFunc(func(
ctx context.Context,
@ -121,7 +120,7 @@ func (i *authInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc {
})
}
func (*authInterceptor) WrapStreamingClient(next connect.StreamingClientFunc) connect.StreamingClientFunc {
func (*AuthInterceptor) WrapStreamingClient(next connect.StreamingClientFunc) connect.StreamingClientFunc {
return connect.StreamingClientFunc(func(
ctx context.Context,
spec connect.Spec,
@ -130,7 +129,7 @@ func (*authInterceptor) WrapStreamingClient(next connect.StreamingClientFunc) co
})
}
func (i *authInterceptor) WrapStreamingHandler(next connect.StreamingHandlerFunc) connect.StreamingHandlerFunc {
func (i *AuthInterceptor) WrapStreamingHandler(next connect.StreamingHandlerFunc) connect.StreamingHandlerFunc {
return connect.StreamingHandlerFunc(func(
ctx context.Context,
conn connect.StreamingHandlerConn,

View File

@ -15,14 +15,14 @@ type visitor struct {
lastSeen time.Time
}
type ratelimitInterceptor struct {
type RatelimitInterceptor struct {
key string
visitors map[string]*visitor
mu sync.Mutex
}
func NewRateLimitInterceptor(key string) *ratelimitInterceptor {
rl := &ratelimitInterceptor{
func NewRateLimitInterceptor(key string) *RatelimitInterceptor {
rl := &RatelimitInterceptor{
key: key,
visitors: make(map[string]*visitor),
mu: sync.Mutex{},
@ -33,7 +33,7 @@ func NewRateLimitInterceptor(key string) *ratelimitInterceptor {
return rl
}
func (i *ratelimitInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc {
func (i *RatelimitInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc {
// Same as previous UnaryInterceptorFunc.
return connect.UnaryFunc(func(
ctx context.Context,
@ -54,7 +54,7 @@ func (i *ratelimitInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFu
})
}
func (*ratelimitInterceptor) WrapStreamingClient(next connect.StreamingClientFunc) connect.StreamingClientFunc {
func (*RatelimitInterceptor) WrapStreamingClient(next connect.StreamingClientFunc) connect.StreamingClientFunc {
return connect.StreamingClientFunc(func(
ctx context.Context,
spec connect.Spec,
@ -63,7 +63,7 @@ func (*ratelimitInterceptor) WrapStreamingClient(next connect.StreamingClientFun
})
}
func (i *ratelimitInterceptor) WrapStreamingHandler(next connect.StreamingHandlerFunc) connect.StreamingHandlerFunc {
func (i *RatelimitInterceptor) WrapStreamingHandler(next connect.StreamingHandlerFunc) connect.StreamingHandlerFunc {
return connect.StreamingHandlerFunc(func(
ctx context.Context,
conn connect.StreamingHandlerConn,
@ -78,7 +78,7 @@ func (i *ratelimitInterceptor) WrapStreamingHandler(next connect.StreamingHandle
})
}
func (i *ratelimitInterceptor) getVisitor(userAgent string) *rate.Limiter {
func (i *RatelimitInterceptor) getVisitor(userAgent string) *rate.Limiter {
i.mu.Lock()
defer i.mu.Unlock()
@ -97,7 +97,7 @@ func (i *ratelimitInterceptor) getVisitor(userAgent string) *rate.Limiter {
// Every minute check the map for visitors that haven't been seen for
// more than 3 minutes and delete the entries.
func (i *ratelimitInterceptor) cleanupVisitors() {
func (i *RatelimitInterceptor) cleanupVisitors() {
for {
time.Sleep(time.Minute)

View File

@ -1,3 +1,4 @@
// TrevStack HTTP Server
package main
import (
@ -20,6 +21,8 @@ import (
"github.com/spotdemo4/trevstack/server/internal/database"
"github.com/spotdemo4/trevstack/server/internal/handlers"
"github.com/spotdemo4/trevstack/server/internal/handlers/client"
"github.com/spotdemo4/trevstack/server/internal/handlers/item/v1"
"github.com/spotdemo4/trevstack/server/internal/handlers/user/v1"
)
type env struct {
@ -107,9 +110,9 @@ func main() {
// Serve GRPC Handlers
api := http.NewServeMux()
api.Handle(withCORS(handlers.NewAuthHandler(db, env.Key)))
api.Handle(withCORS(handlers.NewUserHandler(db, env.Key)))
api.Handle(withCORS(handlers.NewItemHandler(db, env.Key)))
api.Handle(withCORS(user.NewAuthHandler(db, env.Key)))
api.Handle(withCORS(user.NewHandler(db, env.Key)))
api.Handle(withCORS(item.NewHandler(db, env.Key)))
// Serve web interface
mux := http.NewServeMux()

27
server/revive.toml Normal file
View File

@ -0,0 +1,27 @@
ignoreGeneratedHeader = false
severity = "warning"
confidence = 0.8
errorCode = 0
warningCode = 0
[rule.blank-imports]
[rule.context-as-argument]
[rule.context-keys-type]
[rule.dot-imports]
[rule.error-return]
[rule.error-strings]
[rule.error-naming]
[rule.increment-decrement]
[rule.var-naming]
[rule.var-declaration]
[rule.range]
[rule.receiver-naming]
[rule.time-naming]
[rule.unexported-return]
[rule.indent-error-flow]
[rule.errorf]
[rule.empty-block]
[rule.superfluous-else]
[rule.unused-parameter]
[rule.unreachable-code]
[rule.redefines-builtin-id]