2 Commits

Author SHA1 Message Date
225835e5d1 add more typesafty 2025-10-02 17:18:28 +02:00
fc841f238b generate table structs from ts in rust 2025-10-02 14:31:47 +02:00
59 changed files with 2932 additions and 8798 deletions

View File

@ -11,6 +11,7 @@
"postinstall": "nuxt prepare",
"tauri": "tauri",
"tauri:build:debug": "tauri build --debug",
"generate:rust-types": "tsx ./src-tauri/database/generate-rust-types.ts",
"drizzle:generate": "drizzle-kit generate",
"drizzle:migrate": "drizzle-kit migrate",
"eslint:fix": "eslint --fix"
@ -50,11 +51,13 @@
"@iconify/tailwind4": "^1.0.6",
"@libsql/client": "^0.15.15",
"@tauri-apps/cli": "^2.5.0",
"@types/node": "^24.6.2",
"@vitejs/plugin-vue": "6.0.1",
"@vue/compiler-sfc": "^3.5.17",
"drizzle-kit": "^0.31.2",
"globals": "^16.2.0",
"prettier": "3.6.2",
"tsx": "^4.20.6",
"tw-animate-css": "^1.3.8",
"typescript": "^5.8.3",
"vite": "7.1.3",

170
pnpm-lock.yaml generated
View File

@ -13,16 +13,16 @@ importers:
dependencies:
'@nuxt/eslint':
specifier: 1.9.0
version: 1.9.0(@typescript-eslint/utils@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(@vue/compiler-sfc@3.5.21)(eslint@9.35.0(jiti@2.5.1))(magicast@0.3.5)(typescript@5.9.2)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))
version: 1.9.0(@typescript-eslint/utils@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(@vue/compiler-sfc@3.5.21)(eslint@9.35.0(jiti@2.5.1))(magicast@0.3.5)(typescript@5.9.2)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
'@nuxt/fonts':
specifier: 0.11.4
version: 0.11.4(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(ioredis@5.7.0)(magicast@0.3.5)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))
version: 0.11.4(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(ioredis@5.7.0)(magicast@0.3.5)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
'@nuxt/icon':
specifier: 2.0.0
version: 2.0.0(magicast@0.3.5)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
version: 2.0.0(magicast@0.3.5)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
'@nuxt/ui':
specifier: 4.0.0
version: 4.0.0(@babel/parser@7.28.4)(change-case@5.4.4)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(embla-carousel@8.6.0)(ioredis@5.7.0)(magicast@0.3.5)(typescript@5.9.2)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-router@4.5.1(vue@3.5.21(typescript@5.9.2)))(vue@3.5.21(typescript@5.9.2))(zod@3.25.76)
version: 4.0.0(@babel/parser@7.28.4)(change-case@5.4.4)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(embla-carousel@8.6.0)(ioredis@5.7.0)(magicast@0.3.5)(typescript@5.9.2)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue-router@4.5.1(vue@3.5.21(typescript@5.9.2)))(vue@3.5.21(typescript@5.9.2))(zod@3.25.76)
'@nuxtjs/i18n':
specifier: 10.0.6
version: 10.0.6(@vue/compiler-dom@3.5.21)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(magicast@0.3.5)(rollup@4.50.1)(vue@3.5.21(typescript@5.9.2))
@ -31,7 +31,7 @@ importers:
version: 0.11.2(magicast@0.3.5)(pinia@3.0.3(typescript@5.9.2)(vue@3.5.21(typescript@5.9.2)))
'@tailwindcss/vite':
specifier: ^4.1.10
version: 4.1.13(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))
version: 4.1.13(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
'@tauri-apps/api':
specifier: ^2.5.0
version: 2.8.0
@ -67,7 +67,7 @@ importers:
version: 13.9.0(vue@3.5.21(typescript@5.9.2))
'@vueuse/nuxt':
specifier: ^13.4.0
version: 13.9.0(magicast@0.3.5)(nuxt@4.1.1(@libsql/client@0.15.15)(@parcel/watcher@2.5.1)(@types/node@24.5.0)(@vue/compiler-sfc@3.5.21)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0))(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.1)(terser@5.44.0)(typescript@5.9.2)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-tsc@3.0.6(typescript@5.9.2))(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
version: 13.9.0(magicast@0.3.5)(nuxt@4.1.1(@libsql/client@0.15.15)(@parcel/watcher@2.5.1)(@types/node@24.6.2)(@vue/compiler-sfc@3.5.21)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0))(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.1)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.2)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue-tsc@3.0.6(typescript@5.9.2))(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
drizzle-orm:
specifier: ^0.44.2
version: 0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)
@ -79,7 +79,7 @@ importers:
version: 7.1.0
nuxt:
specifier: ^4.0.3
version: 4.1.1(@libsql/client@0.15.15)(@parcel/watcher@2.5.1)(@types/node@24.5.0)(@vue/compiler-sfc@3.5.21)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0))(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.1)(terser@5.44.0)(typescript@5.9.2)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-tsc@3.0.6(typescript@5.9.2))(yaml@2.8.1)
version: 4.1.1(@libsql/client@0.15.15)(@parcel/watcher@2.5.1)(@types/node@24.6.2)(@vue/compiler-sfc@3.5.21)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0))(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.1)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.2)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue-tsc@3.0.6(typescript@5.9.2))(yaml@2.8.1)
nuxt-zod-i18n:
specifier: ^1.12.0
version: 1.12.1(magicast@0.3.5)
@ -108,9 +108,12 @@ importers:
'@tauri-apps/cli':
specifier: ^2.5.0
version: 2.8.4
'@types/node':
specifier: ^24.6.2
version: 24.6.2
'@vitejs/plugin-vue':
specifier: 6.0.1
version: 6.0.1(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
version: 6.0.1(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
'@vue/compiler-sfc':
specifier: ^3.5.17
version: 3.5.21
@ -123,6 +126,9 @@ importers:
prettier:
specifier: 3.6.2
version: 3.6.2
tsx:
specifier: ^4.20.6
version: 4.20.6
tw-animate-css:
specifier: ^1.3.8
version: 1.3.8
@ -131,7 +137,7 @@ importers:
version: 5.9.2
vite:
specifier: 7.1.3
version: 7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
version: 7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vue-tsc:
specifier: 3.0.6
version: 3.0.6(typescript@5.9.2)
@ -2067,8 +2073,8 @@ packages:
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
'@types/node@24.5.0':
resolution: {integrity: sha512-y1dMvuvJspJiPSDZUQ+WMBvF7dpnEqN4x9DDC9ie5Fs/HUZJA3wFp7EhHoVaKX/iI0cRoECV8X2jL8zi0xrHCg==}
'@types/node@24.6.2':
resolution: {integrity: sha512-d2L25Y4j+W3ZlNAeMKcy7yDsK425ibcAOO2t7aPTz6gNMH0z2GThtwENCDc0d/Pw9wgyRqE5Px1wkV7naz8ang==}
'@types/parse-path@7.1.0':
resolution: {integrity: sha512-EULJ8LApcVEPbrfND0cRQqutIOdiIgJ1Mgrhpy755r14xMohPTEpkV/k28SJvuOs9bHRFW8x+KeDAEPiGQPB9Q==}
@ -4941,6 +4947,11 @@ packages:
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
tsx@4.20.6:
resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==}
engines: {node: '>=18.0.0'}
hasBin: true
tw-animate-css@1.3.8:
resolution: {integrity: sha512-Qrk3PZ7l7wUcGYhwZloqfkWCmaXZAoqjkdbIDvzfGshwGtexa/DAs9koXxIkrpEasyevandomzCBAV1Yyop5rw==}
@ -4972,8 +4983,8 @@ packages:
unctx@2.4.1:
resolution: {integrity: sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==}
undici-types@7.12.0:
resolution: {integrity: sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==}
undici-types@7.13.0:
resolution: {integrity: sha512-Ov2Rr9Sx+fRgagJ5AX0qvItZG/JKKoBRAVITs1zk7IqZGTJUwgUr7qoYBpWwakpWilTZFM98rG/AFRocu10iIQ==}
unenv@2.0.0-rc.20:
resolution: {integrity: sha512-8tn4tAl9vD5nWoggAAPz28vf0FY8+pQAayhU94qD+ZkIbVKCBAH/E1MWEEmhb9Whn5EgouYVfBJB20RsTLRDdg==}
@ -6336,11 +6347,11 @@ snapshots:
'@nuxt/devalue@2.0.2': {}
'@nuxt/devtools-kit@2.6.3(magicast@0.3.5)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))':
'@nuxt/devtools-kit@2.6.3(magicast@0.3.5)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))':
dependencies:
'@nuxt/kit': 3.19.1(magicast@0.3.5)
execa: 8.0.1
vite: 7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
vite: 7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
transitivePeerDependencies:
- magicast
@ -6355,12 +6366,12 @@ snapshots:
prompts: 2.4.2
semver: 7.7.2
'@nuxt/devtools@2.6.3(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))':
'@nuxt/devtools@2.6.3(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))':
dependencies:
'@nuxt/devtools-kit': 2.6.3(magicast@0.3.5)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))
'@nuxt/devtools-kit': 2.6.3(magicast@0.3.5)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
'@nuxt/devtools-wizard': 2.6.3
'@nuxt/kit': 3.19.1(magicast@0.3.5)
'@vue/devtools-core': 7.7.7(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
'@vue/devtools-core': 7.7.7(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
'@vue/devtools-kit': 7.7.7
birpc: 2.5.0
consola: 3.4.2
@ -6385,9 +6396,9 @@ snapshots:
sirv: 3.0.2
structured-clone-es: 1.0.0
tinyglobby: 0.2.14
vite: 7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
vite-plugin-inspect: 11.3.3(@nuxt/kit@3.19.1(magicast@0.3.5))(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))
vite-plugin-vue-tracer: 1.0.0(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
vite: 7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vite-plugin-inspect: 11.3.3(@nuxt/kit@3.19.1(magicast@0.3.5))(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
vite-plugin-vue-tracer: 1.0.0(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
which: 5.0.0
ws: 8.18.3
transitivePeerDependencies:
@ -6436,10 +6447,10 @@ snapshots:
- supports-color
- typescript
'@nuxt/eslint@1.9.0(@typescript-eslint/utils@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(@vue/compiler-sfc@3.5.21)(eslint@9.35.0(jiti@2.5.1))(magicast@0.3.5)(typescript@5.9.2)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))':
'@nuxt/eslint@1.9.0(@typescript-eslint/utils@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(@vue/compiler-sfc@3.5.21)(eslint@9.35.0(jiti@2.5.1))(magicast@0.3.5)(typescript@5.9.2)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))':
dependencies:
'@eslint/config-inspector': 1.2.0(eslint@9.35.0(jiti@2.5.1))
'@nuxt/devtools-kit': 2.6.3(magicast@0.3.5)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))
'@nuxt/devtools-kit': 2.6.3(magicast@0.3.5)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
'@nuxt/eslint-config': 1.9.0(@typescript-eslint/utils@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(@vue/compiler-sfc@3.5.21)(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)
'@nuxt/eslint-plugin': 1.9.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)
'@nuxt/kit': 4.1.1(magicast@0.3.5)
@ -6464,9 +6475,9 @@ snapshots:
- utf-8-validate
- vite
'@nuxt/fonts@0.11.4(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(ioredis@5.7.0)(magicast@0.3.5)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))':
'@nuxt/fonts@0.11.4(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(ioredis@5.7.0)(magicast@0.3.5)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))':
dependencies:
'@nuxt/devtools-kit': 2.6.3(magicast@0.3.5)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))
'@nuxt/devtools-kit': 2.6.3(magicast@0.3.5)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
'@nuxt/kit': 3.19.1(magicast@0.3.5)
consola: 3.4.2
css-tree: 3.1.0
@ -6510,13 +6521,13 @@ snapshots:
- uploadthing
- vite
'@nuxt/icon@2.0.0(magicast@0.3.5)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))':
'@nuxt/icon@2.0.0(magicast@0.3.5)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))':
dependencies:
'@iconify/collections': 1.0.592
'@iconify/types': 2.0.0
'@iconify/utils': 3.0.1
'@iconify/vue': 5.0.0(vue@3.5.21(typescript@5.9.2))
'@nuxt/devtools-kit': 2.6.3(magicast@0.3.5)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))
'@nuxt/devtools-kit': 2.6.3(magicast@0.3.5)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
'@nuxt/kit': 4.1.1(magicast@0.3.5)
consola: 3.4.2
local-pkg: 1.1.2
@ -6613,20 +6624,20 @@ snapshots:
transitivePeerDependencies:
- magicast
'@nuxt/ui@4.0.0(@babel/parser@7.28.4)(change-case@5.4.4)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(embla-carousel@8.6.0)(ioredis@5.7.0)(magicast@0.3.5)(typescript@5.9.2)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-router@4.5.1(vue@3.5.21(typescript@5.9.2)))(vue@3.5.21(typescript@5.9.2))(zod@3.25.76)':
'@nuxt/ui@4.0.0(@babel/parser@7.28.4)(change-case@5.4.4)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(embla-carousel@8.6.0)(ioredis@5.7.0)(magicast@0.3.5)(typescript@5.9.2)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue-router@4.5.1(vue@3.5.21(typescript@5.9.2)))(vue@3.5.21(typescript@5.9.2))(zod@3.25.76)':
dependencies:
'@ai-sdk/vue': 2.0.51(vue@3.5.21(typescript@5.9.2))(zod@3.25.76)
'@iconify/vue': 5.0.0(vue@3.5.21(typescript@5.9.2))
'@internationalized/date': 3.9.0
'@internationalized/number': 3.6.5
'@nuxt/fonts': 0.11.4(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(ioredis@5.7.0)(magicast@0.3.5)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))
'@nuxt/icon': 2.0.0(magicast@0.3.5)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
'@nuxt/fonts': 0.11.4(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(ioredis@5.7.0)(magicast@0.3.5)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
'@nuxt/icon': 2.0.0(magicast@0.3.5)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
'@nuxt/kit': 4.1.1(magicast@0.3.5)
'@nuxt/schema': 4.1.1
'@nuxtjs/color-mode': 3.5.2(magicast@0.3.5)
'@standard-schema/spec': 1.0.0
'@tailwindcss/postcss': 4.1.13
'@tailwindcss/vite': 4.1.13(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))
'@tailwindcss/vite': 4.1.13(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
'@tanstack/vue-table': 8.21.3(vue@3.5.21(typescript@5.9.2))
'@unhead/vue': 2.0.17(vue@3.5.21(typescript@5.9.2))
'@vueuse/core': 13.9.0(vue@3.5.21(typescript@5.9.2))
@ -6706,12 +6717,12 @@ snapshots:
- vite
- vue
'@nuxt/vite-builder@4.1.1(@types/node@24.5.0)(eslint@9.35.0(jiti@2.5.1))(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.1)(terser@5.44.0)(typescript@5.9.2)(vue-tsc@3.0.6(typescript@5.9.2))(vue@3.5.21(typescript@5.9.2))(yaml@2.8.1)':
'@nuxt/vite-builder@4.1.1(@types/node@24.6.2)(eslint@9.35.0(jiti@2.5.1))(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.1)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.2)(vue-tsc@3.0.6(typescript@5.9.2))(vue@3.5.21(typescript@5.9.2))(yaml@2.8.1)':
dependencies:
'@nuxt/kit': 4.1.1(magicast@0.3.5)
'@rollup/plugin-replace': 6.0.2(rollup@4.50.1)
'@vitejs/plugin-vue': 6.0.1(vite@7.1.5(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
'@vitejs/plugin-vue-jsx': 5.1.1(vite@7.1.5(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
'@vitejs/plugin-vue': 6.0.1(vite@7.1.5(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
'@vitejs/plugin-vue-jsx': 5.1.1(vite@7.1.5(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
autoprefixer: 10.4.21(postcss@8.5.6)
consola: 3.4.2
cssnano: 7.1.1(postcss@8.5.6)
@ -6733,9 +6744,9 @@ snapshots:
std-env: 3.9.0
ufo: 1.6.1
unenv: 2.0.0-rc.21
vite: 7.1.5(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
vite-node: 3.2.4(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
vite-plugin-checker: 0.10.3(eslint@9.35.0(jiti@2.5.1))(optionator@0.9.4)(typescript@5.9.2)(vite@7.1.5(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-tsc@3.0.6(typescript@5.9.2))
vite: 7.1.5(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vite-node: 3.2.4(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vite-plugin-checker: 0.10.3(eslint@9.35.0(jiti@2.5.1))(optionator@0.9.4)(typescript@5.9.2)(vite@7.1.5(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue-tsc@3.0.6(typescript@5.9.2))
vue: 3.5.21(typescript@5.9.2)
vue-bundle-renderer: 2.1.2
transitivePeerDependencies:
@ -7392,12 +7403,12 @@ snapshots:
postcss: 8.5.6
tailwindcss: 4.1.13
'@tailwindcss/vite@4.1.13(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))':
'@tailwindcss/vite@4.1.13(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))':
dependencies:
'@tailwindcss/node': 4.1.13
'@tailwindcss/oxide': 4.1.13
tailwindcss: 4.1.13
vite: 7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
vite: 7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
'@tanstack/table-core@8.21.3': {}
@ -7503,9 +7514,9 @@ snapshots:
'@types/json-schema@7.0.15': {}
'@types/node@24.5.0':
'@types/node@24.6.2':
dependencies:
undici-types: 7.12.0
undici-types: 7.13.0
'@types/parse-path@7.1.0':
dependencies:
@ -7519,7 +7530,7 @@ snapshots:
'@types/ws@8.18.1':
dependencies:
'@types/node': 24.5.0
'@types/node': 24.6.2
'@typescript-eslint/eslint-plugin@8.43.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)':
dependencies:
@ -7704,28 +7715,28 @@ snapshots:
- rollup
- supports-color
'@vitejs/plugin-vue-jsx@5.1.1(vite@7.1.5(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))':
'@vitejs/plugin-vue-jsx@5.1.1(vite@7.1.5(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))':
dependencies:
'@babel/core': 7.28.4
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4)
'@babel/plugin-transform-typescript': 7.28.0(@babel/core@7.28.4)
'@rolldown/pluginutils': 1.0.0-beta.36
'@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.28.4)
vite: 7.1.5(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
vite: 7.1.5(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vue: 3.5.21(typescript@5.9.2)
transitivePeerDependencies:
- supports-color
'@vitejs/plugin-vue@6.0.1(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))':
'@vitejs/plugin-vue@6.0.1(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))':
dependencies:
'@rolldown/pluginutils': 1.0.0-beta.29
vite: 7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
vite: 7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vue: 3.5.21(typescript@5.9.2)
'@vitejs/plugin-vue@6.0.1(vite@7.1.5(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))':
'@vitejs/plugin-vue@6.0.1(vite@7.1.5(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))':
dependencies:
'@rolldown/pluginutils': 1.0.0-beta.29
vite: 7.1.5(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
vite: 7.1.5(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vue: 3.5.21(typescript@5.9.2)
'@volar/language-core@2.4.23':
@ -7830,14 +7841,14 @@ snapshots:
dependencies:
'@vue/devtools-kit': 7.7.7
'@vue/devtools-core@7.7.7(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))':
'@vue/devtools-core@7.7.7(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))':
dependencies:
'@vue/devtools-kit': 7.7.7
'@vue/devtools-shared': 7.7.7
mitt: 3.0.1
nanoid: 5.1.5
pathe: 2.0.3
vite-hot-client: 2.1.0(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))
vite-hot-client: 2.1.0(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
vue: 3.5.21(typescript@5.9.2)
transitivePeerDependencies:
- vite
@ -7940,13 +7951,13 @@ snapshots:
'@vueuse/metadata@13.9.0': {}
'@vueuse/nuxt@13.9.0(magicast@0.3.5)(nuxt@4.1.1(@libsql/client@0.15.15)(@parcel/watcher@2.5.1)(@types/node@24.5.0)(@vue/compiler-sfc@3.5.21)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0))(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.1)(terser@5.44.0)(typescript@5.9.2)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-tsc@3.0.6(typescript@5.9.2))(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))':
'@vueuse/nuxt@13.9.0(magicast@0.3.5)(nuxt@4.1.1(@libsql/client@0.15.15)(@parcel/watcher@2.5.1)(@types/node@24.6.2)(@vue/compiler-sfc@3.5.21)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0))(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.1)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.2)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue-tsc@3.0.6(typescript@5.9.2))(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))':
dependencies:
'@nuxt/kit': 3.19.1(magicast@0.3.5)
'@vueuse/core': 13.9.0(vue@3.5.21(typescript@5.9.2))
'@vueuse/metadata': 13.9.0
local-pkg: 1.1.2
nuxt: 4.1.1(@libsql/client@0.15.15)(@parcel/watcher@2.5.1)(@types/node@24.5.0)(@vue/compiler-sfc@3.5.21)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0))(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.1)(terser@5.44.0)(typescript@5.9.2)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-tsc@3.0.6(typescript@5.9.2))(yaml@2.8.1)
nuxt: 4.1.1(@libsql/client@0.15.15)(@parcel/watcher@2.5.1)(@types/node@24.6.2)(@vue/compiler-sfc@3.5.21)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0))(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.1)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.2)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue-tsc@3.0.6(typescript@5.9.2))(yaml@2.8.1)
vue: 3.5.21(typescript@5.9.2)
transitivePeerDependencies:
- magicast
@ -9646,15 +9657,15 @@ snapshots:
transitivePeerDependencies:
- magicast
nuxt@4.1.1(@libsql/client@0.15.15)(@parcel/watcher@2.5.1)(@types/node@24.5.0)(@vue/compiler-sfc@3.5.21)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0))(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.1)(terser@5.44.0)(typescript@5.9.2)(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-tsc@3.0.6(typescript@5.9.2))(yaml@2.8.1):
nuxt@4.1.1(@libsql/client@0.15.15)(@parcel/watcher@2.5.1)(@types/node@24.6.2)(@vue/compiler-sfc@3.5.21)(db0@0.3.2(@libsql/client@0.15.15)(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0)))(drizzle-orm@0.44.5(@libsql/client@0.15.15)(@opentelemetry/api@1.9.0))(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.1)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.2)(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue-tsc@3.0.6(typescript@5.9.2))(yaml@2.8.1):
dependencies:
'@nuxt/cli': 3.28.0(magicast@0.3.5)
'@nuxt/devalue': 2.0.2
'@nuxt/devtools': 2.6.3(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
'@nuxt/devtools': 2.6.3(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
'@nuxt/kit': 4.1.1(magicast@0.3.5)
'@nuxt/schema': 4.1.1
'@nuxt/telemetry': 2.6.6(magicast@0.3.5)
'@nuxt/vite-builder': 4.1.1(@types/node@24.5.0)(eslint@9.35.0(jiti@2.5.1))(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.1)(terser@5.44.0)(typescript@5.9.2)(vue-tsc@3.0.6(typescript@5.9.2))(vue@3.5.21(typescript@5.9.2))(yaml@2.8.1)
'@nuxt/vite-builder': 4.1.1(@types/node@24.6.2)(eslint@9.35.0(jiti@2.5.1))(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.1)(terser@5.44.0)(tsx@4.20.6)(typescript@5.9.2)(vue-tsc@3.0.6(typescript@5.9.2))(vue@3.5.21(typescript@5.9.2))(yaml@2.8.1)
'@unhead/vue': 2.0.14(vue@3.5.21(typescript@5.9.2))
'@vue/shared': 3.5.21
c12: 3.2.0(magicast@0.3.5)
@ -9713,7 +9724,7 @@ snapshots:
vue-router: 4.5.1(vue@3.5.21(typescript@5.9.2))
optionalDependencies:
'@parcel/watcher': 2.5.1
'@types/node': 24.5.0
'@types/node': 24.6.2
transitivePeerDependencies:
- '@azure/app-configuration'
- '@azure/cosmos'
@ -10623,6 +10634,13 @@ snapshots:
tslib@2.8.1: {}
tsx@4.20.6:
dependencies:
esbuild: 0.25.9
get-tsconfig: 4.10.1
optionalDependencies:
fsevents: 2.3.3
tw-animate-css@1.3.8: {}
type-check@0.4.0:
@ -10648,7 +10666,7 @@ snapshots:
magic-string: 0.30.19
unplugin: 2.3.10
undici-types@7.12.0: {}
undici-types@7.13.0: {}
unenv@2.0.0-rc.20:
dependencies:
@ -10908,23 +10926,23 @@ snapshots:
transitivePeerDependencies:
- '@vue/composition-api'
vite-dev-rpc@1.1.0(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)):
vite-dev-rpc@1.1.0(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)):
dependencies:
birpc: 2.5.0
vite: 7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
vite-hot-client: 2.1.0(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))
vite: 7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vite-hot-client: 2.1.0(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
vite-hot-client@2.1.0(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)):
vite-hot-client@2.1.0(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)):
dependencies:
vite: 7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
vite: 7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vite-node@3.2.4(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1):
vite-node@3.2.4(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1):
dependencies:
cac: 6.7.14
debug: 4.4.1
es-module-lexer: 1.7.0
pathe: 2.0.3
vite: 7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
vite: 7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
transitivePeerDependencies:
- '@types/node'
- jiti
@ -10939,7 +10957,7 @@ snapshots:
- tsx
- yaml
vite-plugin-checker@0.10.3(eslint@9.35.0(jiti@2.5.1))(optionator@0.9.4)(typescript@5.9.2)(vite@7.1.5(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-tsc@3.0.6(typescript@5.9.2)):
vite-plugin-checker@0.10.3(eslint@9.35.0(jiti@2.5.1))(optionator@0.9.4)(typescript@5.9.2)(vite@7.1.5(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue-tsc@3.0.6(typescript@5.9.2)):
dependencies:
'@babel/code-frame': 7.27.1
chokidar: 4.0.3
@ -10949,7 +10967,7 @@ snapshots:
strip-ansi: 7.1.2
tiny-invariant: 1.3.3
tinyglobby: 0.2.14
vite: 7.1.5(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
vite: 7.1.5(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vscode-uri: 3.1.0
optionalDependencies:
eslint: 9.35.0(jiti@2.5.1)
@ -10957,7 +10975,7 @@ snapshots:
typescript: 5.9.2
vue-tsc: 3.0.6(typescript@5.9.2)
vite-plugin-inspect@11.3.3(@nuxt/kit@3.19.1(magicast@0.3.5))(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)):
vite-plugin-inspect@11.3.3(@nuxt/kit@3.19.1(magicast@0.3.5))(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)):
dependencies:
ansis: 4.1.0
debug: 4.4.1
@ -10967,24 +10985,24 @@ snapshots:
perfect-debounce: 2.0.0
sirv: 3.0.2
unplugin-utils: 0.3.0
vite: 7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
vite-dev-rpc: 1.1.0(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))
vite: 7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vite-dev-rpc: 1.1.0(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
optionalDependencies:
'@nuxt/kit': 3.19.1(magicast@0.3.5)
transitivePeerDependencies:
- supports-color
vite-plugin-vue-tracer@1.0.0(vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2)):
vite-plugin-vue-tracer@1.0.0(vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2)):
dependencies:
estree-walker: 3.0.3
exsolve: 1.0.7
magic-string: 0.30.19
pathe: 2.0.3
source-map-js: 1.2.1
vite: 7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)
vite: 7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vue: 3.5.21(typescript@5.9.2)
vite@7.1.3(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1):
vite@7.1.3(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1):
dependencies:
esbuild: 0.25.9
fdir: 6.5.0(picomatch@4.0.3)
@ -10993,14 +11011,15 @@ snapshots:
rollup: 4.50.1
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 24.5.0
'@types/node': 24.6.2
fsevents: 2.3.3
jiti: 2.5.1
lightningcss: 1.30.1
terser: 5.44.0
tsx: 4.20.6
yaml: 2.8.1
vite@7.1.5(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1):
vite@7.1.5(@types/node@24.6.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1):
dependencies:
esbuild: 0.25.9
fdir: 6.5.0(picomatch@4.0.3)
@ -11009,11 +11028,12 @@ snapshots:
rollup: 4.50.1
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 24.5.0
'@types/node': 24.6.2
fsevents: 2.3.3
jiti: 2.5.1
lightningcss: 1.30.1
terser: 5.44.0
tsx: 4.20.6
yaml: 2.8.1
vscode-uri@3.1.0: {}

View File

@ -16,9 +16,9 @@ crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
serde_json = "1.0.145"
tauri-build = { version = "2.2", features = [] }
serde = { version = "1.0.228", features = ["derive"] }
[dependencies]
rusqlite = { version = "0.37.0", features = [
"load_extension",

View File

@ -1,106 +1,7 @@
use serde::Deserialize;
use std::env;
use std::fs::File;
use std::io::{BufReader, Write};
use std::path::Path;
#[derive(Debug, Deserialize)]
struct Schema {
haex: Haex,
}
#[derive(Debug, Deserialize)]
struct Haex {
settings: String,
extensions: String,
extension_permissions: String,
notifications: String,
passwords: Passwords,
crdt: Crdt,
}
#[derive(Debug, Deserialize)]
struct Passwords {
groups: String,
group_items: String,
item_details: String,
item_key_values: String,
item_histories: String,
}
#[derive(Debug, Deserialize)]
struct Crdt {
logs: String,
snapshots: String,
configs: String,
}
mod generator;
fn main() {
// Pfad zur Eingabe-JSON und zur Ausgabe-Rust-Datei festlegen.
// `OUT_DIR` ist ein spezielles Verzeichnis, das Cargo für generierte Dateien bereitstellt.
let schema_path = Path::new("database/tableNames.json");
let out_dir =
env::var("OUT_DIR").expect("OUT_DIR ist nicht gesetzt. Führen Sie dies mit Cargo aus.");
let dest_path = Path::new(&out_dir).join("tableNames.rs");
// --- 2. JSON-Datei lesen und mit serde parsen ---
let file = File::open(&schema_path).expect("Konnte tableNames.json nicht öffnen");
let reader = BufReader::new(file);
let schema: Schema =
serde_json::from_reader(reader).expect("Konnte tableNames.json nicht parsen");
let haex = schema.haex;
// --- 3. Den zu generierenden Rust-Code als String erstellen ---
// Wir verwenden das `format!`-Makro, um die Werte aus den geparsten Structs
// in einen vordefinierten Code-Template-String einzufügen.
// Das `r#""#`-Format erlaubt uns, mehrzeilige Strings mit Anführungszeichen zu verwenden.
let code = format!(
r#"
// HINWEIS: Diese Datei wurde automatisch von build.rs generiert.
// Manuelle Änderungen werden bei der nächsten Kompilierung überschrieben!
pub const TABLE_SETTINGS: &str = "{settings}";
pub const TABLE_EXTENSIONS: &str = "{extensions}";
pub const TABLE_EXTENSION_PERMISSIONS: &str = "{extension_permissions}";
pub const TABLE_NOTIFICATIONS: &str = "{notifications}";
// Passwords
pub const TABLE_PASSWORDS_GROUPS: &str = "{pw_groups}";
pub const TABLE_PASSWORDS_GROUP_ITEMS: &str = "{pw_group_items}";
pub const TABLE_PASSWORDS_ITEM_DETAILS: &str = "{pw_item_details}";
pub const TABLE_PASSWORDS_ITEM_KEY_VALUES: &str = "{pw_item_key_values}";
pub const TABLE_PASSWORDS_ITEM_HISTORIES: &str = "{pw_item_histories}";
// CRDT
pub const TABLE_CRDT_LOGS: &str = "{crdt_logs}";
pub const TABLE_CRDT_SNAPSHOTS: &str = "{crdt_snapshots}";
pub const TABLE_CRDT_CONFIGS: &str = "{crdt_configs}";
"#,
// Hier werden die Werte aus dem `haex`-Struct in die Platzhalter oben eingesetzt.
settings = haex.settings,
extensions = haex.extensions,
extension_permissions = haex.extension_permissions,
notifications = haex.notifications,
pw_groups = haex.passwords.groups,
pw_group_items = haex.passwords.group_items,
pw_item_details = haex.passwords.item_details,
pw_item_key_values = haex.passwords.item_key_values,
pw_item_histories = haex.passwords.item_histories,
crdt_logs = haex.crdt.logs,
crdt_snapshots = haex.crdt.snapshots,
crdt_configs = haex.crdt.configs
);
// --- 4. Den generierten Code in die Zieldatei schreiben ---
let mut f = File::create(&dest_path).expect("Konnte die Zieldatei nicht erstellen");
f.write_all(code.as_bytes())
.expect("Konnte nicht in die Zieldatei schreiben");
// --- 5. Cargo anweisen, das Skript erneut auszuführen, wenn sich die JSON-Datei ändert ---
// Diese Zeile ist extrem wichtig für eine reibungslose Entwicklung! Ohne sie
// würde Cargo Änderungen an der JSON-Datei nicht bemerken.
println!("cargo:rerun-if-changed=database/tableNames.json");
tauri_build::build()
generator::table_names::generate_table_names();
generator::rust_types::generate_rust_types();
tauri_build::build();
}

View File

@ -0,0 +1,192 @@
import { writeFileSync, mkdirSync } from 'node:fs'
import { join, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import tablesNames from './tableNames.json'
import { schema } from './index'
import { getTableColumns } from 'drizzle-orm'
import type { AnySQLiteColumn, SQLiteTable } from 'drizzle-orm/sqlite-core'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
interface Column {
name: string
rustType: string
isOptional: boolean
}
function drizzleToRustType(colDef: AnySQLiteColumn): {
rustType: string
isOptional: boolean
} {
let baseType = 'String'
let isOptional = !colDef.notNull
if (colDef.columnType === 'SQLiteText') {
if ('mode' in colDef && colDef.mode === 'json') {
baseType = 'serde_json::Value'
} else {
baseType = 'String'
}
} else if (colDef.columnType === 'SQLiteInteger') {
baseType = 'i64'
} else if (colDef.columnType === 'SQLiteBoolean') {
baseType = 'bool'
} else if (colDef.columnType === 'SQLiteReal') {
baseType = 'f64'
} else if (colDef.columnType === 'SQLiteBlob') {
baseType = 'Vec<u8>'
}
// Drizzle verwendet 'primary' für den Primärschlüssel-Status
if (colDef.primary) {
isOptional = false
}
return { rustType: baseType, isOptional }
}
function extractColumns(table: SQLiteTable): Column[] {
const columns: Column[] = []
// getTableColumns gibt ein Record<string, AnySQLiteColumn> zurück
const tableColumns = getTableColumns(table)
// Object.values gibt uns ein Array vom Typ AnySQLiteColumn[]
for (const colDef of Object.values(tableColumns)) {
// Die relevanten Infos stehen im 'config' Property der Spalte.
// TypeScript kennt den Typ von 'config' bereits!
const { rustType, isOptional } = drizzleToRustType(colDef)
columns.push({
name: colDef.name,
rustType: isOptional ? `Option<${rustType}>` : rustType,
isOptional,
})
}
return columns
}
function toSnakeCase(str: string): string {
return str.replace(/[A-Z]/g, (letter, index) =>
index === 0 ? letter.toLowerCase() : `_${letter.toLowerCase()}`,
)
}
function toPascalCase(str: string): string {
console.log('toPascalCase:', str)
return str
.split('_')
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join('')
}
const RUST_KEYWORDS = new Set([
'type',
'struct',
'enum',
'pub',
'use',
'as',
'crate',
'super',
'self',
'let',
'mut',
])
function generateStruct(name: string, columns: Column[]): string {
let structName = toPascalCase(name)
if (RUST_KEYWORDS.has(structName.toLowerCase())) {
structName = `r#${structName}`
}
// --- Teil 1: Struct-Definition ---
let code = `#[derive(Debug, Clone, Serialize, Deserialize)]\n`
code += `#[serde(rename_all = "camelCase")]\n`
code += `pub struct ${structName} {\n`
for (const col of columns) {
let fieldName = toSnakeCase(col.name)
// Prüfen, ob der Name ein Keyword ist
if (RUST_KEYWORDS.has(fieldName)) {
fieldName = `r#${fieldName}`
}
if (col.isOptional) {
code += ` #[serde(skip_serializing_if = "Option::is_none")]\n`
}
// Wichtig: #[serde(rename = "...")] hinzufügen, falls der Feldname geändert wurde!
if (fieldName.startsWith('r#')) {
const originalName = fieldName.substring(2)
code += ` #[serde(rename = "${originalName}")]\n`
}
code += ` pub ${fieldName}: ${col.rustType},\n`
}
code += `}\n\n`
// --- Teil 2: Impl-Block ---
code += `impl ${structName} {\n`
code += ` pub fn from_row(row: &rusqlite::Row) -> rusqlite::Result<Self> {\n`
code += ` Ok(Self {\n`
columns.forEach((col, idx) => {
let fieldName = toSnakeCase(col.name)
if (RUST_KEYWORDS.has(fieldName)) {
fieldName = `r#${fieldName}`
}
code += ` ${fieldName}: row.get(${idx})?,\n`
})
code += ` })\n`
code += ` }\n`
code += `}\n\n`
return code
}
function main() {
let output = `// Auto-generated from Drizzle schema
// DO NOT EDIT MANUALLY
// Run 'pnpm generate:rust-types' to regenerate
use serde::{Deserialize, Serialize};
`
const schemas = [
{ name: tablesNames.haex.settings.name, table: schema.haexSettings },
{ name: tablesNames.haex.extensions.name, table: schema.haexExtensions },
{
name: tablesNames.haex.extension_permissions.name,
table: schema.haexExtensionPermissions,
},
{ name: tablesNames.haex.crdt.logs.name, table: schema.haexCrdtLogs },
{
name: tablesNames.haex.crdt.snapshots.name,
table: schema.haexCrdtSnapshots,
},
{ name: tablesNames.haex.crdt.configs.name, table: schema.haexCrdtConfigs },
]
for (const { name, table } of schemas) {
console.log(`\n=== Processing table: ${name} ===`)
const columns = extractColumns(table)
console.log(`Found ${columns.length} columns`)
if (columns.length > 0) {
output += generateStruct(name, columns)
}
}
const outputPath = join(__dirname, '../src/database/generated.rs')
mkdirSync(dirname(outputPath), { recursive: true })
writeFileSync(outputPath, output, 'utf-8')
console.log('\n✅ Rust types generated:', outputPath)
}
main()

View File

@ -1,6 +1,6 @@
import { drizzle } from 'drizzle-orm/sqlite-proxy' // Adapter für Query Building ohne direkte Verbindung
import * as schema from './schemas/haex' // Importiere alles aus deiner Schema-Datei
import * as schema from './schemas' // Importiere alles aus deiner Schema-Datei
export * as schema from './schemas'
// sqlite-proxy benötigt eine (dummy) Ausführungsfunktion als Argument.
// Diese wird in unserem Tauri-Workflow nie aufgerufen, da wir nur .toSQL() verwenden.
// Sie muss aber vorhanden sein, um drizzle() aufrufen zu können.

View File

@ -0,0 +1,139 @@
CREATE TABLE `haex_crdt_configs` (
`key` text PRIMARY KEY NOT NULL,
`value` text
);
--> statement-breakpoint
CREATE TABLE `haex_crdt_logs` (
`id` text PRIMARY KEY NOT NULL,
`haex_timestamp` text,
`table_name` text,
`row_pks` text,
`op_type` text,
`column_name` text,
`new_value` text,
`old_value` text
);
--> statement-breakpoint
CREATE INDEX `idx_haex_timestamp` ON `haex_crdt_logs` (`haex_timestamp`);--> statement-breakpoint
CREATE INDEX `idx_table_row` ON `haex_crdt_logs` (`table_name`,`row_pks`);--> statement-breakpoint
CREATE TABLE `haex_crdt_snapshots` (
`snapshot_id` text PRIMARY KEY NOT NULL,
`created` text,
`epoch_hlc` text,
`location_url` text,
`file_size_bytes` integer
);
--> statement-breakpoint
CREATE TABLE `haex_extension_permissions` (
`id` text PRIMARY KEY NOT NULL,
`extension_id` text,
`resource_type` text,
`action` text,
`target` text,
`constraints` text,
`status` text DEFAULT 'denied' NOT NULL,
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
`updated_at` integer,
`haex_tombstone` integer,
`haex_timestamp` text,
FOREIGN KEY (`extension_id`) REFERENCES `haex_extensions`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `haex_extension_permissions_extension_id_resource_type_action_target_unique` ON `haex_extension_permissions` (`extension_id`,`resource_type`,`action`,`target`);--> statement-breakpoint
CREATE TABLE `haex_extensions` (
`id` text PRIMARY KEY NOT NULL,
`author` text,
`description` text,
`entry` text,
`homepage` text,
`enabled` integer,
`icon` text,
`name` text,
`public_key` text,
`signature` text,
`url` text,
`version` text,
`haex_tombstone` integer,
`haex_timestamp` text
);
--> statement-breakpoint
CREATE TABLE `haex_settings` (
`id` text PRIMARY KEY NOT NULL,
`key` text,
`type` text,
`value` text,
`haex_tombstone` integer,
`haex_timestamp` text
);
--> statement-breakpoint
CREATE TABLE `haex_notifications` (
`id` text PRIMARY KEY NOT NULL,
`alt` text,
`date` text,
`icon` text,
`image` text,
`read` integer,
`source` text,
`text` text,
`title` text,
`type` text NOT NULL,
`haex_tombstone` integer
);
--> statement-breakpoint
CREATE TABLE `haex_passwords_group_items` (
`group_id` text,
`item_id` text,
`haex_tombstone` integer,
PRIMARY KEY(`item_id`, `group_id`),
FOREIGN KEY (`group_id`) REFERENCES `haex_passwords_groups`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_item_details`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE TABLE `haex_passwords_groups` (
`id` text PRIMARY KEY NOT NULL,
`name` text,
`description` text,
`icon` text,
`order` integer,
`color` text,
`parent_id` text,
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
`updated_at` integer,
`haex_tombstone` integer,
FOREIGN KEY (`parent_id`) REFERENCES `haex_passwords_groups`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE TABLE `haex_passwords_item_details` (
`id` text PRIMARY KEY NOT NULL,
`title` text,
`username` text,
`password` text,
`note` text,
`icon` text,
`tags` text,
`url` text,
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
`updated_at` integer,
`haex_tombstone` integer
);
--> statement-breakpoint
CREATE TABLE `haex_passwords_item_history` (
`id` text PRIMARY KEY NOT NULL,
`item_id` text,
`changed_property` text,
`old_value` text,
`new_value` text,
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
`haex_tombstone` integer,
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_item_details`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE TABLE `haex_passwords_item_key_values` (
`id` text PRIMARY KEY NOT NULL,
`item_id` text,
`key` text,
`value` text,
`updated_at` integer,
`haex_tombstone` integer,
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_item_details`(`id`) ON UPDATE no action ON DELETE no action
);

View File

@ -1,26 +0,0 @@
CREATE TABLE `haex_extensions` (
`id` text PRIMARY KEY NOT NULL,
`author` text,
`enabled` integer,
`name` text,
`url` text,
`version` text
);
--> statement-breakpoint
CREATE TABLE `haex_extensions_permissions` (
`id` text PRIMARY KEY NOT NULL,
`extension_id` text,
`resource` text,
`operation` text,
`path` text,
FOREIGN KEY (`extension_id`) REFERENCES `haex_extensions`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `haex_extensions_permissions_extension_id_resource_operation_path_unique` ON `haex_extensions_permissions` (`extension_id`,`resource`,`operation`,`path`);--> statement-breakpoint
CREATE TABLE `haex_settings` (
`id` text PRIMARY KEY NOT NULL,
`key` text,
`value_text` text,
`value_json` text,
`value_number` numeric
);

View File

@ -0,0 +1 @@
ALTER TABLE `haex_notifications` ADD `haex_timestamp` text;

View File

@ -1,7 +0,0 @@
CREATE TABLE `testTable` (
`id` text PRIMARY KEY NOT NULL,
`author` text,
`test` text
);
--> statement-breakpoint
ALTER TABLE `haex_extensions` ADD `icon` text;

View File

@ -1,4 +0,0 @@
ALTER TABLE `haex_settings` RENAME COLUMN "value_text" TO "value";--> statement-breakpoint
DROP TABLE `testTable`;--> statement-breakpoint
ALTER TABLE `haex_settings` DROP COLUMN `value_json`;--> statement-breakpoint
ALTER TABLE `haex_settings` DROP COLUMN `value_number`;

View File

@ -1,11 +0,0 @@
CREATE TABLE `haex_notofications` (
`id` text PRIMARY KEY NOT NULL,
`title` text,
`text` text,
`type` text NOT NULL,
`read` integer,
`date` text,
`image` text,
`alt` text,
`icon` text
);

View File

@ -1 +0,0 @@
ALTER TABLE `haex_notofications` RENAME TO `haex_notifications`;

View File

@ -1,50 +0,0 @@
CREATE TABLE `haex_passwords_group_items` (
`group_id` text,
`item_id` text,
PRIMARY KEY(`item_id`, `group_id`),
FOREIGN KEY (`group_id`) REFERENCES `haex_passwords_groups`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_items`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE TABLE `haex_passwords_groups` (
`id` text PRIMARY KEY NOT NULL,
`name` text,
`icon` text,
`order` integer,
`color` text,
`parent_id` text,
FOREIGN KEY (`parent_id`) REFERENCES `haex_passwords_groups`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE TABLE `haex_passwords_item_history` (
`id` text PRIMARY KEY NOT NULL,
`item_id` text,
`changed_property` text,
`old_value` text,
`new_value` text,
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_items`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE TABLE `haex_passwords_items` (
`id` text PRIMARY KEY NOT NULL,
`title` text,
`username` text,
`password` text,
`note` text,
`icon` text,
`tags` text,
`url` text,
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
`updated_at` integer
);
--> statement-breakpoint
CREATE TABLE `haex_passwords_items_key_values` (
`id` text PRIMARY KEY NOT NULL,
`item_id` text,
`key` text,
`value` text,
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_items`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
ALTER TABLE `haex_notifications` ADD `source` text;

View File

@ -1,5 +0,0 @@
ALTER TABLE `haex_extensions_permissions` ADD `created_at` text DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
ALTER TABLE `haex_extensions_permissions` ADD `updated_at` integer;--> statement-breakpoint
ALTER TABLE `haex_passwords_groups` ADD `created_at` text DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
ALTER TABLE `haex_passwords_groups` ADD `updated_at` integer;--> statement-breakpoint
ALTER TABLE `haex_passwords_items_key_values` ADD `updated_at` integer;

View File

@ -1 +0,0 @@
ALTER TABLE `haex_passwords_groups` ADD `description` text;

View File

@ -1,40 +0,0 @@
ALTER TABLE `haex_passwords_items` RENAME TO `haex_passwords_item_details`;--> statement-breakpoint
ALTER TABLE `haex_passwords_items_key_values` RENAME TO `haex_passwords_item_key_values`;--> statement-breakpoint
PRAGMA foreign_keys=OFF;--> statement-breakpoint
CREATE TABLE `__new_haex_passwords_item_key_values` (
`id` text PRIMARY KEY NOT NULL,
`item_id` text,
`key` text,
`value` text,
`updated_at` integer,
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_item_details`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
INSERT INTO `__new_haex_passwords_item_key_values`("id", "item_id", "key", "value", "updated_at") SELECT "id", "item_id", "key", "value", "updated_at" FROM `haex_passwords_item_key_values`;--> statement-breakpoint
DROP TABLE `haex_passwords_item_key_values`;--> statement-breakpoint
ALTER TABLE `__new_haex_passwords_item_key_values` RENAME TO `haex_passwords_item_key_values`;--> statement-breakpoint
PRAGMA foreign_keys=ON;--> statement-breakpoint
CREATE TABLE `__new_haex_passwords_group_items` (
`group_id` text,
`item_id` text,
PRIMARY KEY(`item_id`, `group_id`),
FOREIGN KEY (`group_id`) REFERENCES `haex_passwords_groups`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_item_details`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
INSERT INTO `__new_haex_passwords_group_items`("group_id", "item_id") SELECT "group_id", "item_id" FROM `haex_passwords_group_items`;--> statement-breakpoint
DROP TABLE `haex_passwords_group_items`;--> statement-breakpoint
ALTER TABLE `__new_haex_passwords_group_items` RENAME TO `haex_passwords_group_items`;--> statement-breakpoint
CREATE TABLE `__new_haex_passwords_item_history` (
`id` text PRIMARY KEY NOT NULL,
`item_id` text,
`changed_property` text,
`old_value` text,
`new_value` text,
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_item_details`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
INSERT INTO `__new_haex_passwords_item_history`("id", "item_id", "changed_property", "old_value", "new_value", "created_at") SELECT "id", "item_id", "changed_property", "old_value", "new_value", "created_at" FROM `haex_passwords_item_history`;--> statement-breakpoint
DROP TABLE `haex_passwords_item_history`;--> statement-breakpoint
ALTER TABLE `__new_haex_passwords_item_history` RENAME TO `haex_passwords_item_history`;

View File

@ -1 +0,0 @@
ALTER TABLE `haex_settings` ADD `type` text;

View File

@ -1,32 +0,0 @@
CREATE TABLE `haex_crdt_logs` (
`hlc_timestamp` text PRIMARY KEY NOT NULL,
`table_name` text,
`row_pks` text,
`op_type` text,
`column_name` text,
`new_value` text,
`old_value` text
);
--> statement-breakpoint
CREATE TABLE `haex_crdt_settings` (
`type` text PRIMARY KEY NOT NULL,
`value` text
);
--> statement-breakpoint
CREATE TABLE `haex_crdt_snapshots` (
`snapshot_id` text PRIMARY KEY NOT NULL,
`created` text,
`epoch_hlc` text,
`location_url` text,
`file_size_bytes` integer
);
--> statement-breakpoint
ALTER TABLE `haex_extensions` ADD `haex_tombstone` integer;--> statement-breakpoint
ALTER TABLE `haex_extensions_permissions` ADD `haex_tombstone` integer;--> statement-breakpoint
ALTER TABLE `haex_notifications` ADD `haex_tombstone` integer;--> statement-breakpoint
ALTER TABLE `haex_passwords_group_items` ADD `haex_tombstone` integer;--> statement-breakpoint
ALTER TABLE `haex_passwords_groups` ADD `haex_tombstone` integer;--> statement-breakpoint
ALTER TABLE `haex_passwords_item_details` ADD `haex_tombstone` integer;--> statement-breakpoint
ALTER TABLE `haex_passwords_item_history` ADD `haex_tombstone` integer;--> statement-breakpoint
ALTER TABLE `haex_passwords_item_key_values` ADD `haex_tombstone` integer;--> statement-breakpoint
ALTER TABLE `haex_settings` ADD `haex_tombstone` integer;

View File

@ -1,21 +0,0 @@
ALTER TABLE `haex_crdt_settings` RENAME TO `haex_crdt_configs`;--> statement-breakpoint
ALTER TABLE `haex_extensions_permissions` RENAME TO `haex_extension_permissions`;--> statement-breakpoint
ALTER TABLE `haex_crdt_configs` RENAME COLUMN "type" TO "key";--> statement-breakpoint
PRAGMA foreign_keys=OFF;--> statement-breakpoint
CREATE TABLE `__new_haex_extension_permissions` (
`id` text PRIMARY KEY NOT NULL,
`extension_id` text,
`resource` text,
`operation` text,
`path` text,
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
`updated_at` integer,
`haex_tombstone` integer,
FOREIGN KEY (`extension_id`) REFERENCES `haex_extensions`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
INSERT INTO `__new_haex_extension_permissions`("id", "extension_id", "resource", "operation", "path", "created_at", "updated_at", "haex_tombstone") SELECT "id", "extension_id", "resource", "operation", "path", "created_at", "updated_at", "haex_tombstone" FROM `haex_extension_permissions`;--> statement-breakpoint
DROP TABLE `haex_extension_permissions`;--> statement-breakpoint
ALTER TABLE `__new_haex_extension_permissions` RENAME TO `haex_extension_permissions`;--> statement-breakpoint
PRAGMA foreign_keys=ON;--> statement-breakpoint
CREATE UNIQUE INDEX `haex_extension_permissions_extension_id_resource_operation_path_unique` ON `haex_extension_permissions` (`extension_id`,`resource`,`operation`,`path`);

View File

@ -1,15 +0,0 @@
ALTER TABLE `haex_extension_permissions` RENAME COLUMN "resource" TO "resource_type";--> statement-breakpoint
ALTER TABLE `haex_extension_permissions` RENAME COLUMN "operation" TO "action";--> statement-breakpoint
ALTER TABLE `haex_extension_permissions` RENAME COLUMN "path" TO "target";--> statement-breakpoint
DROP INDEX `haex_extension_permissions_extension_id_resource_operation_path_unique`;--> statement-breakpoint
ALTER TABLE `haex_extension_permissions` ADD `constraints` text;--> statement-breakpoint
ALTER TABLE `haex_extension_permissions` ADD `status` text DEFAULT 'denied' NOT NULL;--> statement-breakpoint
ALTER TABLE `haex_extension_permissions` ADD `haex_timestamp` text;--> statement-breakpoint
CREATE UNIQUE INDEX `haex_extension_permissions_extension_id_resource_type_action_target_unique` ON `haex_extension_permissions` (`extension_id`,`resource_type`,`action`,`target`);--> statement-breakpoint
ALTER TABLE `haex_extensions` ADD `description` text;--> statement-breakpoint
ALTER TABLE `haex_extensions` ADD `entry` text;--> statement-breakpoint
ALTER TABLE `haex_extensions` ADD `homepage` text;--> statement-breakpoint
ALTER TABLE `haex_extensions` ADD `public_key` text;--> statement-breakpoint
ALTER TABLE `haex_extensions` ADD `signature` text;--> statement-breakpoint
ALTER TABLE `haex_extensions` ADD `haex_timestamp` text;--> statement-breakpoint
ALTER TABLE `haex_settings` ADD `haex_timestamp` text;

View File

@ -1,9 +1,274 @@
{
"version": "6",
"dialect": "sqlite",
"id": "fc5a7c9d-4846-4120-a762-cc2ea00504b9",
"id": "3bbe52b8-5933-4b21-8b24-de3927a2f9b0",
"prevId": "00000000-0000-0000-0000-000000000000",
"tables": {
"haex_crdt_configs": {
"name": "haex_crdt_configs",
"columns": {
"key": {
"name": "key",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_logs": {
"name": "haex_crdt_logs",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"table_name": {
"name": "table_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"row_pks": {
"name": "row_pks",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"op_type": {
"name": "op_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"column_name": {
"name": "column_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"idx_haex_timestamp": {
"name": "idx_haex_timestamp",
"columns": [
"haex_timestamp"
],
"isUnique": false
},
"idx_table_row": {
"name": "idx_table_row",
"columns": [
"table_name",
"row_pks"
],
"isUnique": false
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_snapshots": {
"name": "haex_crdt_snapshots",
"columns": {
"snapshot_id": {
"name": "snapshot_id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"created": {
"name": "created",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"epoch_hlc": {
"name": "epoch_hlc",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"location_url": {
"name": "location_url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"file_size_bytes": {
"name": "file_size_bytes",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extension_permissions": {
"name": "haex_extension_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource_type": {
"name": "resource_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"action": {
"name": "action",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"target": {
"name": "target",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"constraints": {
"name": "constraints",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'denied'"
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extension_permissions_extension_id_resource_type_action_target_unique": {
"name": "haex_extension_permissions_extension_id_resource_type_action_target_unique",
"columns": [
"extension_id",
"resource_type",
"action",
"target"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extension_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extension_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extension_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions": {
"name": "haex_extensions",
"columns": {
@ -21,6 +286,27 @@
"notNull": false,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"entry": {
"name": "entry",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"homepage": {
"name": "homepage",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
@ -28,6 +314,13 @@
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
@ -35,6 +328,20 @@
"notNull": false,
"autoincrement": false
},
"public_key": {
"name": "public_key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"signature": {
"name": "signature",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
@ -48,6 +355,20 @@
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
@ -56,76 +377,6 @@
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions_permissions": {
"name": "haex_extensions_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource": {
"name": "resource",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"operation": {
"name": "operation",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
"columns": [
"extension_id",
"resource",
"operation",
"path"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extensions_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
@ -143,23 +394,30 @@
"notNull": false,
"autoincrement": false
},
"value_text": {
"name": "value_text",
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value_json": {
"name": "value_json",
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value_number": {
"name": "value_number",
"type": "numeric",
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
@ -170,6 +428,482 @@
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_notifications": {
"name": "haex_notifications",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"alt": {
"name": "alt",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"date": {
"name": "date",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"read": {
"name": "read",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"source": {
"name": "source",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"text": {
"name": "text",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_group_items": {
"name": "haex_passwords_group_items",
"columns": {
"group_id": {
"name": "group_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_group_items_group_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"haex_passwords_group_items_item_id_group_id_pk": {
"columns": [
"item_id",
"group_id"
],
"name": "haex_passwords_group_items_item_id_group_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_groups": {
"name": "haex_passwords_groups",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"parent_id": {
"name": "parent_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_groups_parent_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_groups",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"parent_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_details": {
"name": "haex_passwords_item_details",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"note": {
"name": "note",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"tags": {
"name": "tags",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_history": {
"name": "haex_passwords_item_history",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"changed_property": {
"name": "changed_property",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_history",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_key_values": {
"name": "haex_passwords_item_key_values",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_key_values",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},

View File

@ -1,9 +1,274 @@
{
"version": "6",
"dialect": "sqlite",
"id": "6fb5396b-9f87-4fb5-87a2-22d4eecaa11e",
"prevId": "fc5a7c9d-4846-4120-a762-cc2ea00504b9",
"id": "862ac1d5-3065-4244-8652-2b6782254862",
"prevId": "3bbe52b8-5933-4b21-8b24-de3927a2f9b0",
"tables": {
"haex_crdt_configs": {
"name": "haex_crdt_configs",
"columns": {
"key": {
"name": "key",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_logs": {
"name": "haex_crdt_logs",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"table_name": {
"name": "table_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"row_pks": {
"name": "row_pks",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"op_type": {
"name": "op_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"column_name": {
"name": "column_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"idx_haex_timestamp": {
"name": "idx_haex_timestamp",
"columns": [
"haex_timestamp"
],
"isUnique": false
},
"idx_table_row": {
"name": "idx_table_row",
"columns": [
"table_name",
"row_pks"
],
"isUnique": false
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_snapshots": {
"name": "haex_crdt_snapshots",
"columns": {
"snapshot_id": {
"name": "snapshot_id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"created": {
"name": "created",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"epoch_hlc": {
"name": "epoch_hlc",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"location_url": {
"name": "location_url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"file_size_bytes": {
"name": "file_size_bytes",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extension_permissions": {
"name": "haex_extension_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource_type": {
"name": "resource_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"action": {
"name": "action",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"target": {
"name": "target",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"constraints": {
"name": "constraints",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'denied'"
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extension_permissions_extension_id_resource_type_action_target_unique": {
"name": "haex_extension_permissions_extension_id_resource_type_action_target_unique",
"columns": [
"extension_id",
"resource_type",
"action",
"target"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extension_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extension_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extension_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions": {
"name": "haex_extensions",
"columns": {
@ -21,6 +286,27 @@
"notNull": false,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"entry": {
"name": "entry",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"homepage": {
"name": "homepage",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
@ -42,6 +328,20 @@
"notNull": false,
"autoincrement": false
},
"public_key": {
"name": "public_key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"signature": {
"name": "signature",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
@ -55,6 +355,20 @@
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
@ -63,8 +377,8 @@
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions_permissions": {
"name": "haex_extensions_permissions",
"haex_notifications": {
"name": "haex_notifications",
"columns": {
"id": {
"name": "id",
@ -73,62 +387,86 @@
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"alt": {
"name": "alt",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource": {
"name": "resource",
"date": {
"name": "date",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"operation": {
"name": "operation",
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"path": {
"name": "path",
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"read": {
"name": "read",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"source": {
"name": "source",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"text": {
"name": "text",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
"columns": [
"extension_id",
"resource",
"operation",
"path"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extensions_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
@ -150,23 +488,30 @@
"notNull": false,
"autoincrement": false
},
"value_text": {
"name": "value_text",
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value_json": {
"name": "value_json",
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value_number": {
"name": "value_number",
"type": "numeric",
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
@ -178,8 +523,74 @@
"uniqueConstraints": {},
"checkConstraints": {}
},
"testTable": {
"name": "testTable",
"haex_passwords_group_items": {
"name": "haex_passwords_group_items",
"columns": {
"group_id": {
"name": "group_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_group_items_group_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"haex_passwords_group_items_item_id_group_id_pk": {
"columns": [
"item_id",
"group_id"
],
"name": "haex_passwords_group_items_item_id_group_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_groups": {
"name": "haex_passwords_groups",
"columns": {
"id": {
"name": "id",
@ -188,19 +599,171 @@
"notNull": true,
"autoincrement": false
},
"author": {
"name": "author",
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"test": {
"name": "test",
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"parent_id": {
"name": "parent_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_groups_parent_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_groups",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"parent_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_details": {
"name": "haex_passwords_item_details",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"note": {
"name": "note",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"tags": {
"name": "tags",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
@ -208,6 +771,146 @@
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_history": {
"name": "haex_passwords_item_history",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"changed_property": {
"name": "changed_property",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_history",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_key_values": {
"name": "haex_passwords_item_key_values",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_key_values",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},

View File

@ -1,180 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "ea3507ca-77bc-4f3c-a605-8426614f5803",
"prevId": "6fb5396b-9f87-4fb5-87a2-22d4eecaa11e",
"tables": {
"haex_extensions": {
"name": "haex_extensions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"author": {
"name": "author",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"version": {
"name": "version",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions_permissions": {
"name": "haex_extensions_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource": {
"name": "resource",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"operation": {
"name": "operation",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
"columns": [
"extension_id",
"resource",
"operation",
"path"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extensions_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {
"\"haex_settings\".\"value_text\"": "\"haex_settings\".\"value\""
}
},
"internal": {
"indexes": {}
}
}

View File

@ -1,251 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "5f413421-18a5-4c1b-9c5b-99f574b10126",
"prevId": "ea3507ca-77bc-4f3c-a605-8426614f5803",
"tables": {
"haex_extensions": {
"name": "haex_extensions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"author": {
"name": "author",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"version": {
"name": "version",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions_permissions": {
"name": "haex_extensions_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource": {
"name": "resource",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"operation": {
"name": "operation",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
"columns": [
"extension_id",
"resource",
"operation",
"path"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extensions_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_notofications": {
"name": "haex_notofications",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"text": {
"name": "text",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"read": {
"name": "read",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"date": {
"name": "date",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"alt": {
"name": "alt",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@ -1,253 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "7aaac460-00b5-4387-bef9-b189297cefb3",
"prevId": "5f413421-18a5-4c1b-9c5b-99f574b10126",
"tables": {
"haex_extensions": {
"name": "haex_extensions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"author": {
"name": "author",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"version": {
"name": "version",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions_permissions": {
"name": "haex_extensions_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource": {
"name": "resource",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"operation": {
"name": "operation",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
"columns": [
"extension_id",
"resource",
"operation",
"path"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extensions_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_notifications": {
"name": "haex_notifications",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"alt": {
"name": "alt",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"date": {
"name": "date",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"read": {
"name": "read",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"text": {
"name": "text",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {
"\"haex_notofications\"": "\"haex_notifications\""
},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@ -1,583 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "fd079acd-3b5f-4fb7-97e2-d6641620f393",
"prevId": "7aaac460-00b5-4387-bef9-b189297cefb3",
"tables": {
"haex_extensions": {
"name": "haex_extensions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"author": {
"name": "author",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"version": {
"name": "version",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions_permissions": {
"name": "haex_extensions_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource": {
"name": "resource",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"operation": {
"name": "operation",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
"columns": [
"extension_id",
"resource",
"operation",
"path"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extensions_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_notifications": {
"name": "haex_notifications",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"alt": {
"name": "alt",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"date": {
"name": "date",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"read": {
"name": "read",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"source": {
"name": "source",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"text": {
"name": "text",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_group_items": {
"name": "haex_passwords_group_items",
"columns": {
"group_id": {
"name": "group_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_group_items_group_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"haex_passwords_group_items_item_id_haex_passwords_items_id_fk": {
"name": "haex_passwords_group_items_item_id_haex_passwords_items_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_items",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"haex_passwords_group_items_item_id_group_id_pk": {
"columns": [
"item_id",
"group_id"
],
"name": "haex_passwords_group_items_item_id_group_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_groups": {
"name": "haex_passwords_groups",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"parent_id": {
"name": "parent_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_groups_parent_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_groups",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"parent_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_history": {
"name": "haex_passwords_item_history",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"changed_property": {
"name": "changed_property",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_history_item_id_haex_passwords_items_id_fk": {
"name": "haex_passwords_item_history_item_id_haex_passwords_items_id_fk",
"tableFrom": "haex_passwords_item_history",
"tableTo": "haex_passwords_items",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_items": {
"name": "haex_passwords_items",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"note": {
"name": "note",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"tags": {
"name": "tags",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_items_key_values": {
"name": "haex_passwords_items_key_values",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_items_key_values_item_id_haex_passwords_items_id_fk": {
"name": "haex_passwords_items_key_values_item_id_haex_passwords_items_id_fk",
"tableFrom": "haex_passwords_items_key_values",
"tableTo": "haex_passwords_items",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@ -1,620 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "76878f8b-9a30-4fd2-9a7b-d1a85874b1ab",
"prevId": "fd079acd-3b5f-4fb7-97e2-d6641620f393",
"tables": {
"haex_extensions": {
"name": "haex_extensions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"author": {
"name": "author",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"version": {
"name": "version",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions_permissions": {
"name": "haex_extensions_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource": {
"name": "resource",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"operation": {
"name": "operation",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
"columns": [
"extension_id",
"resource",
"operation",
"path"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extensions_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_notifications": {
"name": "haex_notifications",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"alt": {
"name": "alt",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"date": {
"name": "date",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"read": {
"name": "read",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"source": {
"name": "source",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"text": {
"name": "text",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_group_items": {
"name": "haex_passwords_group_items",
"columns": {
"group_id": {
"name": "group_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_group_items_group_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"haex_passwords_group_items_item_id_haex_passwords_items_id_fk": {
"name": "haex_passwords_group_items_item_id_haex_passwords_items_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_items",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"haex_passwords_group_items_item_id_group_id_pk": {
"columns": [
"item_id",
"group_id"
],
"name": "haex_passwords_group_items_item_id_group_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_groups": {
"name": "haex_passwords_groups",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"parent_id": {
"name": "parent_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_groups_parent_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_groups",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"parent_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_history": {
"name": "haex_passwords_item_history",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"changed_property": {
"name": "changed_property",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_history_item_id_haex_passwords_items_id_fk": {
"name": "haex_passwords_item_history_item_id_haex_passwords_items_id_fk",
"tableFrom": "haex_passwords_item_history",
"tableTo": "haex_passwords_items",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_items": {
"name": "haex_passwords_items",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"note": {
"name": "note",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"tags": {
"name": "tags",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_items_key_values": {
"name": "haex_passwords_items_key_values",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_items_key_values_item_id_haex_passwords_items_id_fk": {
"name": "haex_passwords_items_key_values_item_id_haex_passwords_items_id_fk",
"tableFrom": "haex_passwords_items_key_values",
"tableTo": "haex_passwords_items",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@ -1,627 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "47f309cf-dabd-4f19-b87a-ed73d0e97781",
"prevId": "76878f8b-9a30-4fd2-9a7b-d1a85874b1ab",
"tables": {
"haex_extensions": {
"name": "haex_extensions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"author": {
"name": "author",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"version": {
"name": "version",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions_permissions": {
"name": "haex_extensions_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource": {
"name": "resource",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"operation": {
"name": "operation",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
"columns": [
"extension_id",
"resource",
"operation",
"path"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extensions_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_notifications": {
"name": "haex_notifications",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"alt": {
"name": "alt",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"date": {
"name": "date",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"read": {
"name": "read",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"source": {
"name": "source",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"text": {
"name": "text",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_group_items": {
"name": "haex_passwords_group_items",
"columns": {
"group_id": {
"name": "group_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_group_items_group_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"haex_passwords_group_items_item_id_haex_passwords_items_id_fk": {
"name": "haex_passwords_group_items_item_id_haex_passwords_items_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_items",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"haex_passwords_group_items_item_id_group_id_pk": {
"columns": [
"item_id",
"group_id"
],
"name": "haex_passwords_group_items_item_id_group_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_groups": {
"name": "haex_passwords_groups",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"parent_id": {
"name": "parent_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_groups_parent_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_groups",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"parent_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_history": {
"name": "haex_passwords_item_history",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"changed_property": {
"name": "changed_property",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_history_item_id_haex_passwords_items_id_fk": {
"name": "haex_passwords_item_history_item_id_haex_passwords_items_id_fk",
"tableFrom": "haex_passwords_item_history",
"tableTo": "haex_passwords_items",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_items": {
"name": "haex_passwords_items",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"note": {
"name": "note",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"tags": {
"name": "tags",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_items_key_values": {
"name": "haex_passwords_items_key_values",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_items_key_values_item_id_haex_passwords_items_id_fk": {
"name": "haex_passwords_items_key_values_item_id_haex_passwords_items_id_fk",
"tableFrom": "haex_passwords_items_key_values",
"tableTo": "haex_passwords_items",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@ -1,630 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "c4edecb8-6aef-49e2-8498-0c4b74653c75",
"prevId": "47f309cf-dabd-4f19-b87a-ed73d0e97781",
"tables": {
"haex_extensions": {
"name": "haex_extensions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"author": {
"name": "author",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"version": {
"name": "version",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions_permissions": {
"name": "haex_extensions_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource": {
"name": "resource",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"operation": {
"name": "operation",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
"columns": [
"extension_id",
"resource",
"operation",
"path"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extensions_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_notifications": {
"name": "haex_notifications",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"alt": {
"name": "alt",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"date": {
"name": "date",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"read": {
"name": "read",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"source": {
"name": "source",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"text": {
"name": "text",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_group_items": {
"name": "haex_passwords_group_items",
"columns": {
"group_id": {
"name": "group_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_group_items_group_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"haex_passwords_group_items_item_id_group_id_pk": {
"columns": [
"item_id",
"group_id"
],
"name": "haex_passwords_group_items_item_id_group_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_groups": {
"name": "haex_passwords_groups",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"parent_id": {
"name": "parent_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_groups_parent_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_groups",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"parent_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_details": {
"name": "haex_passwords_item_details",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"note": {
"name": "note",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"tags": {
"name": "tags",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_history": {
"name": "haex_passwords_item_history",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"changed_property": {
"name": "changed_property",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_history",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_key_values": {
"name": "haex_passwords_item_key_values",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_key_values",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {
"\"haex_passwords_items\"": "\"haex_passwords_item_details\"",
"\"haex_passwords_items_key_values\"": "\"haex_passwords_item_key_values\""
},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@ -1,634 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "c3a688c3-9537-4aa8-be95-a8f55546caf1",
"prevId": "c4edecb8-6aef-49e2-8498-0c4b74653c75",
"tables": {
"haex_extensions": {
"name": "haex_extensions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"author": {
"name": "author",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"version": {
"name": "version",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions_permissions": {
"name": "haex_extensions_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource": {
"name": "resource",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"operation": {
"name": "operation",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
"columns": [
"extension_id",
"resource",
"operation",
"path"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extensions_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_notifications": {
"name": "haex_notifications",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"alt": {
"name": "alt",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"date": {
"name": "date",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"read": {
"name": "read",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"source": {
"name": "source",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"text": {
"name": "text",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_group_items": {
"name": "haex_passwords_group_items",
"columns": {
"group_id": {
"name": "group_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_group_items_group_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"haex_passwords_group_items_item_id_group_id_pk": {
"columns": [
"item_id",
"group_id"
],
"name": "haex_passwords_group_items_item_id_group_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_groups": {
"name": "haex_passwords_groups",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"parent_id": {
"name": "parent_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_groups_parent_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_groups",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"parent_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_details": {
"name": "haex_passwords_item_details",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"note": {
"name": "note",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"tags": {
"name": "tags",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_history": {
"name": "haex_passwords_item_history",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"changed_property": {
"name": "changed_property",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_history",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_key_values": {
"name": "haex_passwords_item_key_values",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_key_values",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@ -1,825 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "288d577f-f9c8-44e8-964e-da1fa062aff9",
"prevId": "c3a688c3-9537-4aa8-be95-a8f55546caf1",
"tables": {
"haex_crdt_logs": {
"name": "haex_crdt_logs",
"columns": {
"hlc_timestamp": {
"name": "hlc_timestamp",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"table_name": {
"name": "table_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"row_pks": {
"name": "row_pks",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"op_type": {
"name": "op_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"column_name": {
"name": "column_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_settings": {
"name": "haex_crdt_settings",
"columns": {
"type": {
"name": "type",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_snapshots": {
"name": "haex_crdt_snapshots",
"columns": {
"snapshot_id": {
"name": "snapshot_id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"created": {
"name": "created",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"epoch_hlc": {
"name": "epoch_hlc",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"location_url": {
"name": "location_url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"file_size_bytes": {
"name": "file_size_bytes",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions": {
"name": "haex_extensions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"author": {
"name": "author",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"version": {
"name": "version",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions_permissions": {
"name": "haex_extensions_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource": {
"name": "resource",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"operation": {
"name": "operation",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
"columns": [
"extension_id",
"resource",
"operation",
"path"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extensions_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_notifications": {
"name": "haex_notifications",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"alt": {
"name": "alt",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"date": {
"name": "date",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"read": {
"name": "read",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"source": {
"name": "source",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"text": {
"name": "text",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_group_items": {
"name": "haex_passwords_group_items",
"columns": {
"group_id": {
"name": "group_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_group_items_group_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"haex_passwords_group_items_item_id_group_id_pk": {
"columns": [
"item_id",
"group_id"
],
"name": "haex_passwords_group_items_item_id_group_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_groups": {
"name": "haex_passwords_groups",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"parent_id": {
"name": "parent_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_groups_parent_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_groups",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"parent_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_details": {
"name": "haex_passwords_item_details",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"note": {
"name": "note",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"tags": {
"name": "tags",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_history": {
"name": "haex_passwords_item_history",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"changed_property": {
"name": "changed_property",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_history",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_key_values": {
"name": "haex_passwords_item_key_values",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_key_values",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@ -1,830 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "c8c0825d-c435-4a42-986a-a4f70e7f9e8b",
"prevId": "288d577f-f9c8-44e8-964e-da1fa062aff9",
"tables": {
"haex_crdt_configs": {
"name": "haex_crdt_configs",
"columns": {
"key": {
"name": "key",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_logs": {
"name": "haex_crdt_logs",
"columns": {
"hlc_timestamp": {
"name": "hlc_timestamp",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"table_name": {
"name": "table_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"row_pks": {
"name": "row_pks",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"op_type": {
"name": "op_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"column_name": {
"name": "column_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_snapshots": {
"name": "haex_crdt_snapshots",
"columns": {
"snapshot_id": {
"name": "snapshot_id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"created": {
"name": "created",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"epoch_hlc": {
"name": "epoch_hlc",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"location_url": {
"name": "location_url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"file_size_bytes": {
"name": "file_size_bytes",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extension_permissions": {
"name": "haex_extension_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource": {
"name": "resource",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"operation": {
"name": "operation",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extension_permissions_extension_id_resource_operation_path_unique": {
"name": "haex_extension_permissions_extension_id_resource_operation_path_unique",
"columns": [
"extension_id",
"resource",
"operation",
"path"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extension_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extension_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extension_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions": {
"name": "haex_extensions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"author": {
"name": "author",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"version": {
"name": "version",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_notifications": {
"name": "haex_notifications",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"alt": {
"name": "alt",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"date": {
"name": "date",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"read": {
"name": "read",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"source": {
"name": "source",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"text": {
"name": "text",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_group_items": {
"name": "haex_passwords_group_items",
"columns": {
"group_id": {
"name": "group_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_group_items_group_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"haex_passwords_group_items_item_id_group_id_pk": {
"columns": [
"item_id",
"group_id"
],
"name": "haex_passwords_group_items_item_id_group_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_groups": {
"name": "haex_passwords_groups",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"parent_id": {
"name": "parent_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_groups_parent_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_groups",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"parent_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_details": {
"name": "haex_passwords_item_details",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"note": {
"name": "note",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"tags": {
"name": "tags",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_history": {
"name": "haex_passwords_item_history",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"changed_property": {
"name": "changed_property",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_history",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_key_values": {
"name": "haex_passwords_item_key_values",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_key_values",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {
"\"haex_crdt_settings\"": "\"haex_crdt_configs\"",
"\"haex_extensions_permissions\"": "\"haex_extension_permissions\""
},
"columns": {
"\"haex_crdt_configs\".\"type\"": "\"haex_crdt_configs\".\"key\""
}
},
"internal": {
"indexes": {}
}
}

View File

@ -1,900 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "e4f45178-afcf-46e9-9a07-79b7bca88d88",
"prevId": "c8c0825d-c435-4a42-986a-a4f70e7f9e8b",
"tables": {
"haex_crdt_configs": {
"name": "haex_crdt_configs",
"columns": {
"key": {
"name": "key",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_logs": {
"name": "haex_crdt_logs",
"columns": {
"hlc_timestamp": {
"name": "hlc_timestamp",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"table_name": {
"name": "table_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"row_pks": {
"name": "row_pks",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"op_type": {
"name": "op_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"column_name": {
"name": "column_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_snapshots": {
"name": "haex_crdt_snapshots",
"columns": {
"snapshot_id": {
"name": "snapshot_id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"created": {
"name": "created",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"epoch_hlc": {
"name": "epoch_hlc",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"location_url": {
"name": "location_url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"file_size_bytes": {
"name": "file_size_bytes",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extension_permissions": {
"name": "haex_extension_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource_type": {
"name": "resource_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"action": {
"name": "action",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"target": {
"name": "target",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"constraints": {
"name": "constraints",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'denied'"
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extension_permissions_extension_id_resource_type_action_target_unique": {
"name": "haex_extension_permissions_extension_id_resource_type_action_target_unique",
"columns": [
"extension_id",
"resource_type",
"action",
"target"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extension_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extension_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extension_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions": {
"name": "haex_extensions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"author": {
"name": "author",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"entry": {
"name": "entry",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"homepage": {
"name": "homepage",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"public_key": {
"name": "public_key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"signature": {
"name": "signature",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"version": {
"name": "version",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_notifications": {
"name": "haex_notifications",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"alt": {
"name": "alt",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"date": {
"name": "date",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"read": {
"name": "read",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"source": {
"name": "source",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"text": {
"name": "text",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_group_items": {
"name": "haex_passwords_group_items",
"columns": {
"group_id": {
"name": "group_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_group_items_group_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"haex_passwords_group_items_item_id_group_id_pk": {
"columns": [
"item_id",
"group_id"
],
"name": "haex_passwords_group_items_item_id_group_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_groups": {
"name": "haex_passwords_groups",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"parent_id": {
"name": "parent_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_groups_parent_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_groups",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"parent_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_details": {
"name": "haex_passwords_item_details",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"note": {
"name": "note",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"tags": {
"name": "tags",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_history": {
"name": "haex_passwords_item_history",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"changed_property": {
"name": "changed_property",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_history",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_key_values": {
"name": "haex_passwords_item_key_values",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_key_values",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {
"\"haex_extension_permissions\".\"resource\"": "\"haex_extension_permissions\".\"resource_type\"",
"\"haex_extension_permissions\".\"operation\"": "\"haex_extension_permissions\".\"action\"",
"\"haex_extension_permissions\".\"path\"": "\"haex_extension_permissions\".\"target\""
}
},
"internal": {
"indexes": {}
}
}

View File

@ -5,92 +5,15 @@
{
"idx": 0,
"version": "6",
"when": 1742903332283,
"tag": "0000_zippy_scourge",
"when": 1759402321133,
"tag": "0000_glamorous_hulk",
"breakpoints": true
},
{
"idx": 1,
"version": "6",
"when": 1746281577722,
"tag": "0001_wealthy_thaddeus_ross",
"breakpoints": true
},
{
"idx": 2,
"version": "6",
"when": 1747583956679,
"tag": "0002_married_bushwacker",
"breakpoints": true
},
{
"idx": 3,
"version": "6",
"when": 1748873820060,
"tag": "0003_familiar_doctor_faustus",
"breakpoints": true
},
{
"idx": 4,
"version": "6",
"when": 1748982377354,
"tag": "0004_wooden_lockheed",
"breakpoints": true
},
{
"idx": 5,
"version": "6",
"when": 1749073296353,
"tag": "0005_wooden_nuke",
"breakpoints": true
},
{
"idx": 6,
"version": "6",
"when": 1749128243104,
"tag": "0006_complete_martin_li",
"breakpoints": true
},
{
"idx": 7,
"version": "6",
"when": 1749244165094,
"tag": "0007_daffy_tusk",
"breakpoints": true
},
{
"idx": 8,
"version": "6",
"when": 1749727958231,
"tag": "0008_faulty_mercury",
"breakpoints": true
},
{
"idx": 9,
"version": "6",
"when": 1750158916787,
"tag": "0009_curved_selene",
"breakpoints": true
},
{
"idx": 10,
"version": "6",
"when": 1756377828646,
"tag": "0010_deep_war_machine",
"breakpoints": true
},
{
"idx": 11,
"version": "6",
"when": 1757968140525,
"tag": "0011_illegal_thor_girl",
"breakpoints": true
},
{
"idx": 12,
"version": "6",
"when": 1759362109283,
"tag": "0012_special_gwen_stacy",
"when": 1759418087677,
"tag": "0001_green_stark_industries",
"breakpoints": true
}
]

View File

@ -1,27 +1,52 @@
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'
import { integer, sqliteTable, text, index } from 'drizzle-orm/sqlite-core'
import tableNames from '../tableNames.json'
export const haexCrdtLogs = sqliteTable(tableNames.haex.crdt.logs, {
hlc_timestamp: text().primaryKey(),
table_name: text(),
row_pks: text({ mode: 'json' }),
op_type: text({ enum: ['INSERT', 'UPDATE', 'DELETE'] }),
column_name: text(),
new_value: text({ mode: 'json' }),
old_value: text({ mode: 'json' }),
})
export const haexCrdtLogs = sqliteTable(
tableNames.haex.crdt.logs.name,
{
id: text()
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
haexTimestamp: text(tableNames.haex.crdt.logs.columns.haexTimestamp),
tableName: text(tableNames.haex.crdt.logs.columns.tableName),
rowPks: text(tableNames.haex.crdt.logs.columns.rowPks, { mode: 'json' }),
opType: text(tableNames.haex.crdt.logs.columns.opType, {
enum: ['INSERT', 'UPDATE', 'DELETE'],
}),
columnName: text(tableNames.haex.crdt.logs.columns.columnName),
newValue: text(tableNames.haex.crdt.logs.columns.newValue, {
mode: 'json',
}),
oldValue: text(tableNames.haex.crdt.logs.columns.oldValue, {
mode: 'json',
}),
},
(table) => [
index('idx_haex_timestamp').on(table.haexTimestamp),
index('idx_table_row').on(table.tableName, table.rowPks),
],
)
export type InsertHaexCrdtLogs = typeof haexCrdtLogs.$inferInsert
export type SelectHaexCrdtLogs = typeof haexCrdtLogs.$inferSelect
export const haexCrdtSnapshots = sqliteTable(tableNames.haex.crdt.snapshots, {
snapshot_id: text().primaryKey(),
created: text(),
epoch_hlc: text(),
location_url: text(),
file_size_bytes: integer(),
})
export const haexCrdtSnapshots = sqliteTable(
tableNames.haex.crdt.snapshots.name,
{
snapshotId: text(tableNames.haex.crdt.snapshots.columns.snapshotId)
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
created: text(),
epochHlc: text(tableNames.haex.crdt.snapshots.columns.epochHlc),
locationUrl: text(tableNames.haex.crdt.snapshots.columns.locationUrl),
fileSizeBytes: integer(
tableNames.haex.crdt.snapshots.columns.fileSizeBytes,
),
},
)
export const haexCrdtConfigs = sqliteTable(tableNames.haex.crdt.configs, {
key: text().primaryKey(),
export const haexCrdtConfigs = sqliteTable(tableNames.haex.crdt.configs.name, {
key: text()
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
value: text(),
})

View File

@ -8,19 +8,25 @@ import {
} from 'drizzle-orm/sqlite-core'
import tableNames from '../tableNames.json'
export const haexSettings = sqliteTable(tableNames.haex.settings, {
id: text().primaryKey(),
export const haexSettings = sqliteTable(tableNames.haex.settings.name, {
id: text()
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
key: text(),
type: text(),
value: text(),
haex_tombstone: integer({ mode: 'boolean' }),
haex_timestamp: text(),
haexTombstone: integer(tableNames.haex.settings.columns.haexTombstone, {
mode: 'boolean',
}),
haexTimestamp: text(tableNames.haex.settings.columns.haexTimestamp),
})
export type InsertHaexSettings = typeof haexSettings.$inferInsert
export type SelectHaexSettings = typeof haexSettings.$inferSelect
export const haexExtensions = sqliteTable(tableNames.haex.extensions, {
id: text().primaryKey(),
export const haexExtensions = sqliteTable(tableNames.haex.extensions.name, {
id: text()
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
author: text(),
description: text(),
entry: text(),
@ -32,19 +38,23 @@ export const haexExtensions = sqliteTable(tableNames.haex.extensions, {
signature: text(),
url: text(),
version: text(),
haex_tombstone: integer({ mode: 'boolean' }),
haex_timestamp: text(),
haexTombstone: integer(tableNames.haex.extensions.columns.haexTombstone, {
mode: 'boolean',
}),
haexTimestamp: text(tableNames.haex.extensions.columns.haexTimestamp),
})
export type InsertHaexExtensions = typeof haexExtensions.$inferInsert
export type SelectHaexExtensions = typeof haexExtensions.$inferSelect
export const haexExtensionPermissions = sqliteTable(
tableNames.haex.extension_permissions,
tableNames.haex.extension_permissions.name,
{
id: text().primaryKey(),
extensionId: text('extension_id').references(
(): AnySQLiteColumn => haexExtensions.id,
),
id: text()
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
extensionId: text(
tableNames.haex.extension_permissions.columns.extensionId,
).references((): AnySQLiteColumn => haexExtensions.id),
resourceType: text('resource_type', {
enum: ['fs', 'http', 'db', 'shell'],
}),
@ -58,8 +68,13 @@ export const haexExtensionPermissions = sqliteTable(
updateAt: integer('updated_at', { mode: 'timestamp' }).$onUpdate(
() => new Date(),
),
haexTombstone: integer('haex_tombstone', { mode: 'boolean' }),
haexTimestamp: text('haex_timestamp'),
haexTombstone: integer(
tableNames.haex.extension_permissions.columns.haexTombstone,
{ mode: 'boolean' },
),
haexTimestamp: text(
tableNames.haex.extension_permissions.columns.haexTimestamp,
),
},
(table) => [
unique().on(
@ -74,3 +89,28 @@ export type InserthaexExtensionPermissions =
typeof haexExtensionPermissions.$inferInsert
export type SelecthaexExtensionPermissions =
typeof haexExtensionPermissions.$inferSelect
export const haexNotifications = sqliteTable(
tableNames.haex.notifications.name,
{
id: text().primaryKey(),
alt: text(),
date: text(),
icon: text(),
image: text(),
read: integer({ mode: 'boolean' }),
source: text(),
text: text(),
title: text(),
type: text({
enum: ['error', 'success', 'warning', 'info', 'log'],
}).notNull(),
haexTombstone: integer(
tableNames.haex.notifications.columns.haexTombstone,
{ mode: 'boolean' },
),
haexTimestamp: text(tableNames.haex.notifications.columns.haexTimestamp),
},
)
export type InsertHaexNotifications = typeof haexNotifications.$inferInsert
export type SelectHaexNotifications = typeof haexNotifications.$inferSelect

View File

@ -0,0 +1,2 @@
export * from './crdt'
export * from './haex'

View File

@ -8,24 +8,6 @@ import {
} from 'drizzle-orm/sqlite-core'
import tableNames from '../tableNames.json'
export const haexNotifications = sqliteTable(tableNames.haex.notifications, {
id: text().primaryKey(),
alt: text(),
date: text(),
icon: text(),
image: text(),
read: integer({ mode: 'boolean' }),
source: text(),
text: text(),
title: text(),
type: text({
enum: ['error', 'success', 'warning', 'info', 'log'],
}).notNull(),
haex_tombstone: integer({ mode: 'boolean' }),
})
export type InsertHaexNotifications = typeof haexNotifications.$inferInsert
export type SelectHaexNotifications = typeof haexNotifications.$inferSelect
export const haexPasswordsItemDetails = sqliteTable(
tableNames.haex.passwords.item_details,
{

View File

@ -1,9 +1,68 @@
{
"haex": {
"settings": "haex_settings",
"extensions": "haex_extensions",
"extension_permissions": "haex_extension_permissions",
"notifications": "haex_notifications",
"settings": {
"name": "haex_settings",
"columns": {
"id": "id",
"key": "key",
"type": "type",
"value": "value",
"haexTombstone": "haex_tombstone",
"haexTimestamp": "haex_timestamp"
}
},
"extensions": {
"name": "haex_extensions",
"columns": {
"id": "id",
"author": "author",
"description": "description",
"entry": "entry",
"homepage": "homepage",
"enabled": "enabled",
"icon": "icon",
"name": "name",
"public_key": "public_key",
"signature": "signature",
"url": "url",
"version": "version",
"haexTombstone": "haex_tombstone",
"haexTimestamp": "haex_timestamp"
}
},
"extension_permissions": {
"name": "haex_extension_permissions",
"columns": {
"id": "id",
"extensionId": "extension_id",
"resourceType": "resource_type",
"action": "action",
"target": "target",
"constraints": "constraints",
"status": "status",
"createdAt": "created_at",
"updateAt": "updated_at",
"haexTombstone": "haex_tombstone",
"haexTimestamp": "haex_timestamp"
}
},
"notifications": {
"name": "haex_notifications",
"columns": {
"id": "id",
"alt": "alt",
"date": "date",
"icon": "icon",
"image": "image",
"read": "read",
"source": "source",
"text": "text",
"title": "title",
"type": "type",
"haexTombstone": "haex_tombstone",
"haexTimestamp": "haex_timestamp"
}
},
"passwords": {
"groups": "haex_passwords_groups",
"group_items": "haex_passwords_group_items",
@ -12,9 +71,36 @@
"item_histories": "haex_passwords_item_history"
},
"crdt": {
"logs": "haex_crdt_logs",
"snapshots": "haex_crdt_snapshots",
"configs": "haex_crdt_configs"
"logs": {
"name": "haex_crdt_logs",
"columns": {
"id": "id",
"haexTimestamp": "haex_timestamp",
"tableName": "table_name",
"rowPks": "row_pks",
"opType": "op_type",
"columnName": "column_name",
"newValue": "new_value",
"oldValue": "old_value"
}
},
"snapshots": {
"name": "haex_crdt_snapshots",
"columns": {
"snapshotId": "snapshot_id",
"created": "created",
"epochHlc": "epoch_hlc",
"locationUrl": "location_url",
"fileSizeBytes": "file_size_bytes"
}
},
"configs": {
"name": "haex_crdt_configs",
"columns": {
"key": "key",
"value": "value"
}
}
}
}
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
// build/mod.rs
pub mod rust_types;
pub mod table_names;

View File

@ -0,0 +1,24 @@
// src-tauri/src/build/rust_types.rs
use std::fs;
use std::path::Path;
pub fn generate_rust_types() {
// Prüfe ob die generierte Datei vom TypeScript-Script existiert
let generated_path = Path::new("src/database/generated.rs");
if !generated_path.exists() {
eprintln!("⚠️ Warning: src/database/generated.rs not found!");
eprintln!(" Run 'pnpm generate:rust-types' first.");
// Erstelle eine leere Datei als Fallback
fs::write(
generated_path,
"// Run 'pnpm generate:rust-types' to generate this file\n",
)
.ok();
}
println!("cargo:rerun-if-changed=src/database/generated.rs");
println!("cargo:rerun-if-changed=src/database/schemas/crdt.ts");
println!("cargo:rerun-if-changed=src/database/schemas/haex.ts");
}

View File

@ -0,0 +1,213 @@
// src-tarui/src/build/table_names.rs
use serde::Deserialize;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::{BufReader, Write};
use std::path::Path;
#[derive(Debug, Deserialize)]
struct Schema {
haex: Haex,
}
#[derive(Debug, Deserialize)]
#[allow(non_snake_case)]
struct Haex {
settings: TableDefinition,
extensions: TableDefinition,
extension_permissions: TableDefinition,
notifications: TableDefinition,
crdt: Crdt,
}
#[derive(Debug, Deserialize)]
struct Crdt {
logs: TableDefinition,
snapshots: TableDefinition,
configs: TableDefinition,
}
#[derive(Debug, Deserialize)]
struct TableDefinition {
name: String,
columns: HashMap<String, String>,
}
pub fn generate_table_names() {
let out_dir = env::var("OUT_DIR").expect("OUT_DIR ist nicht gesetzt.");
println!("Generiere Tabellennamen nach {}", out_dir);
let schema_path = Path::new("database/tableNames.json");
let dest_path = Path::new(&out_dir).join("tableNames.rs");
let file = File::open(&schema_path).expect("Konnte tableNames.json nicht öffnen");
let reader = BufReader::new(file);
let schema: Schema =
serde_json::from_reader(reader).expect("Konnte tableNames.json nicht parsen");
let haex = schema.haex;
let code = format!(
r#"
// ==================================================================
// HINWEIS: Diese Datei wurde automatisch von build.rs generiert.
// Manuelle Änderungen werden bei der nächsten Kompilierung überschrieben!
// ==================================================================
// --- Table: haex_settings ---
pub const TABLE_SETTINGS: &str = "{t_settings}";
pub const COL_SETTINGS_ID: &str = "{c_settings_id}";
pub const COL_SETTINGS_KEY: &str = "{c_settings_key}";
pub const COL_SETTINGS_TYPE: &str = "{c_settings_type}";
pub const COL_SETTINGS_VALUE: &str = "{c_settings_value}";
pub const COL_SETTINGS_HAEX_TOMBSTONE: &str = "{c_settings_tombstone}";
pub const COL_SETTINGS_HAEX_TIMESTAMP: &str = "{c_settings_timestamp}";
// --- Table: haex_extensions ---
pub const TABLE_EXTENSIONS: &str = "{t_extensions}";
pub const COL_EXTENSIONS_ID: &str = "{c_ext_id}";
pub const COL_EXTENSIONS_AUTHOR: &str = "{c_ext_author}";
pub const COL_EXTENSIONS_DESCRIPTION: &str = "{c_ext_description}";
pub const COL_EXTENSIONS_ENTRY: &str = "{c_ext_entry}";
pub const COL_EXTENSIONS_HOMEPAGE: &str = "{c_ext_homepage}";
pub const COL_EXTENSIONS_ENABLED: &str = "{c_ext_enabled}";
pub const COL_EXTENSIONS_ICON: &str = "{c_ext_icon}";
pub const COL_EXTENSIONS_NAME: &str = "{c_ext_name}";
pub const COL_EXTENSIONS_PUBLIC_KEY: &str = "{c_ext_public_key}";
pub const COL_EXTENSIONS_SIGNATURE: &str = "{c_ext_signature}";
pub const COL_EXTENSIONS_URL: &str = "{c_ext_url}";
pub const COL_EXTENSIONS_VERSION: &str = "{c_ext_version}";
pub const COL_EXTENSIONS_HAEX_TOMBSTONE: &str = "{c_ext_tombstone}";
pub const COL_EXTENSIONS_HAEX_TIMESTAMP: &str = "{c_ext_timestamp}";
// --- Table: haex_extension_permissions ---
pub const TABLE_EXTENSION_PERMISSIONS: &str = "{t_ext_perms}";
pub const COL_EXT_PERMS_ID: &str = "{c_extp_id}";
pub const COL_EXT_PERMS_EXTENSION_ID: &str = "{c_extp_extensionId}";
pub const COL_EXT_PERMS_RESOURCE_TYPE: &str = "{c_extp_resourceType}";
pub const COL_EXT_PERMS_ACTION: &str = "{c_extp_action}";
pub const COL_EXT_PERMS_TARGET: &str = "{c_extp_target}";
pub const COL_EXT_PERMS_CONSTRAINTS: &str = "{c_extp_constraints}";
pub const COL_EXT_PERMS_STATUS: &str = "{c_extp_status}";
pub const COL_EXT_PERMS_CREATED_AT: &str = "{c_extp_createdAt}";
pub const COL_EXT_PERMS_UPDATE_AT: &str = "{c_extp_updateAt}";
pub const COL_EXT_PERMS_HAEX_TOMBSTONE: &str = "{c_extp_tombstone}";
pub const COL_EXT_PERMS_HAEX_TIMESTAMP: &str = "{c_extp_timestamp}";
// --- Table: haex_notifications ---
pub const TABLE_NOTIFICATIONS: &str = "{t_notifications}";
pub const COL_NOTIFICATIONS_ID: &str = "{c_notif_id}";
pub const COL_NOTIFICATIONS_ALT: &str = "{c_notif_alt}";
pub const COL_NOTIFICATIONS_DATE: &str = "{c_notif_date}";
pub const COL_NOTIFICATIONS_ICON: &str = "{c_notif_icon}";
pub const COL_NOTIFICATIONS_IMAGE: &str = "{c_notif_image}";
pub const COL_NOTIFICATIONS_READ: &str = "{c_notif_read}";
pub const COL_NOTIFICATIONS_SOURCE: &str = "{c_notif_source}";
pub const COL_NOTIFICATIONS_TEXT: &str = "{c_notif_text}";
pub const COL_NOTIFICATIONS_TITLE: &str = "{c_notif_title}";
pub const COL_NOTIFICATIONS_TYPE: &str = "{c_notif_type}";
pub const COL_NOTIFICATIONS_HAEX_TOMBSTONE: &str = "{c_notif_tombstone}";
// --- Table: haex_crdt_logs ---
pub const TABLE_CRDT_LOGS: &str = "{t_crdt_logs}";
pub const COL_CRDT_LOGS_ID: &str = "{c_crdt_logs_id}";
pub const COL_CRDT_LOGS_HAEX_TIMESTAMP: &str = "{c_crdt_logs_timestamp}";
pub const COL_CRDT_LOGS_TABLE_NAME: &str = "{c_crdt_logs_tableName}";
pub const COL_CRDT_LOGS_ROW_PKS: &str = "{c_crdt_logs_rowPks}";
pub const COL_CRDT_LOGS_OP_TYPE: &str = "{c_crdt_logs_opType}";
pub const COL_CRDT_LOGS_COLUMN_NAME: &str = "{c_crdt_logs_columnName}";
pub const COL_CRDT_LOGS_NEW_VALUE: &str = "{c_crdt_logs_newValue}";
pub const COL_CRDT_LOGS_OLD_VALUE: &str = "{c_crdt_logs_oldValue}";
// --- Table: haex_crdt_snapshots ---
pub const TABLE_CRDT_SNAPSHOTS: &str = "{t_crdt_snapshots}";
pub const COL_CRDT_SNAPSHOTS_ID: &str = "{c_crdt_snap_id}";
pub const COL_CRDT_SNAPSHOTS_CREATED: &str = "{c_crdt_snap_created}";
pub const COL_CRDT_SNAPSHOTS_EPOCH_HLC: &str = "{c_crdt_snap_epoch}";
pub const COL_CRDT_SNAPSHOTS_LOCATION_URL: &str = "{c_crdt_snap_location}";
pub const COL_CRDT_SNAPSHOTS_FILE_SIZE: &str = "{c_crdt_snap_size}";
// --- Table: haex_crdt_configs ---
pub const TABLE_CRDT_CONFIGS: &str = "{t_crdt_configs}";
pub const COL_CRDT_CONFIGS_KEY: &str = "{c_crdt_configs_key}";
pub const COL_CRDT_CONFIGS_VALUE: &str = "{c_crdt_configs_value}";
"#,
// Settings
t_settings = haex.settings.name,
c_settings_id = haex.settings.columns["id"],
c_settings_key = haex.settings.columns["key"],
c_settings_type = haex.settings.columns["type"],
c_settings_value = haex.settings.columns["value"],
c_settings_tombstone = haex.settings.columns["haexTombstone"],
c_settings_timestamp = haex.settings.columns["haexTimestamp"],
// Extensions
t_extensions = haex.extensions.name,
c_ext_id = haex.extensions.columns["id"],
c_ext_author = haex.extensions.columns["author"],
c_ext_description = haex.extensions.columns["description"],
c_ext_entry = haex.extensions.columns["entry"],
c_ext_homepage = haex.extensions.columns["homepage"],
c_ext_enabled = haex.extensions.columns["enabled"],
c_ext_icon = haex.extensions.columns["icon"],
c_ext_name = haex.extensions.columns["name"],
c_ext_public_key = haex.extensions.columns["public_key"],
c_ext_signature = haex.extensions.columns["signature"],
c_ext_url = haex.extensions.columns["url"],
c_ext_version = haex.extensions.columns["version"],
c_ext_tombstone = haex.extensions.columns["haexTombstone"],
c_ext_timestamp = haex.extensions.columns["haexTimestamp"],
// Extension Permissions
t_ext_perms = haex.extension_permissions.name,
c_extp_id = haex.extension_permissions.columns["id"],
c_extp_extensionId = haex.extension_permissions.columns["extensionId"],
c_extp_resourceType = haex.extension_permissions.columns["resourceType"],
c_extp_action = haex.extension_permissions.columns["action"],
c_extp_target = haex.extension_permissions.columns["target"],
c_extp_constraints = haex.extension_permissions.columns["constraints"],
c_extp_status = haex.extension_permissions.columns["status"],
c_extp_createdAt = haex.extension_permissions.columns["createdAt"],
c_extp_updateAt = haex.extension_permissions.columns["updateAt"],
c_extp_tombstone = haex.extension_permissions.columns["haexTombstone"],
c_extp_timestamp = haex.extension_permissions.columns["haexTimestamp"],
// Notifications
t_notifications = haex.notifications.name,
c_notif_id = haex.notifications.columns["id"],
c_notif_alt = haex.notifications.columns["alt"],
c_notif_date = haex.notifications.columns["date"],
c_notif_icon = haex.notifications.columns["icon"],
c_notif_image = haex.notifications.columns["image"],
c_notif_read = haex.notifications.columns["read"],
c_notif_source = haex.notifications.columns["source"],
c_notif_text = haex.notifications.columns["text"],
c_notif_title = haex.notifications.columns["title"],
c_notif_type = haex.notifications.columns["type"],
c_notif_tombstone = haex.notifications.columns["haexTombstone"],
// CRDT Logs
t_crdt_logs = haex.crdt.logs.name,
c_crdt_logs_id = haex.crdt.logs.columns["id"],
c_crdt_logs_timestamp = haex.crdt.logs.columns["haexTimestamp"],
c_crdt_logs_tableName = haex.crdt.logs.columns["tableName"],
c_crdt_logs_rowPks = haex.crdt.logs.columns["rowPks"],
c_crdt_logs_opType = haex.crdt.logs.columns["opType"],
c_crdt_logs_columnName = haex.crdt.logs.columns["columnName"],
c_crdt_logs_newValue = haex.crdt.logs.columns["newValue"],
c_crdt_logs_oldValue = haex.crdt.logs.columns["oldValue"],
// CRDT Snapshots
t_crdt_snapshots = haex.crdt.snapshots.name,
c_crdt_snap_id = haex.crdt.snapshots.columns["snapshotId"],
c_crdt_snap_created = haex.crdt.snapshots.columns["created"],
c_crdt_snap_epoch = haex.crdt.snapshots.columns["epochHlc"],
c_crdt_snap_location = haex.crdt.snapshots.columns["locationUrl"],
c_crdt_snap_size = haex.crdt.snapshots.columns["fileSizeBytes"],
// CRDT Configs
t_crdt_configs = haex.crdt.configs.name,
c_crdt_configs_key = haex.crdt.configs.columns["key"],
c_crdt_configs_value = haex.crdt.configs.columns["value"]
);
// --- Datei schreiben ---
let mut f = File::create(&dest_path).expect("Konnte Zieldatei nicht erstellen");
f.write_all(code.as_bytes())
.expect("Konnte nicht in Zieldatei schreiben");
println!("cargo:rerun-if-changed=database/tableNames.json");
}

View File

@ -259,9 +259,10 @@ fn generate_insert_trigger_sql(table_name: &str, pks: &[String], cols: &[String]
let column_inserts = if cols.is_empty() {
// Nur PKs -> einfacher Insert ins Log
format!(
"INSERT INTO {log_table} (hlc_timestamp, op_type, table_name, row_pks)
VALUES (hlc_new_timestamp(), 'INSERT', '{table}', json_object({pk_payload}));",
"INSERT INTO {log_table} (haex_timestamp, op_type, table_name, row_pks)
VALUES (NEW.\"{hlc_col}\", 'INSERT', '{table}', json_object({pk_payload}));",
log_table = TABLE_CRDT_LOGS,
hlc_col = HLC_TIMESTAMP_COLUMN,
table = table_name,
pk_payload = pk_json_payload
)
@ -269,9 +270,10 @@ fn generate_insert_trigger_sql(table_name: &str, pks: &[String], cols: &[String]
cols.iter().fold(String::new(), |mut acc, col| {
writeln!(
&mut acc,
"INSERT INTO {log_table} (hlc_timestamp, op_type, table_name, row_pks, column_name, new_value)
VALUES (hlc_new_timestamp(), 'INSERT', '{table}', json_object({pk_payload}), '{column}', json_object('value', NEW.\"{column}\"));",
"INSERT INTO {log_table} (haex_timestamp, op_type, table_name, row_pks, column_name, new_value)
VALUES (NEW.\"{hlc_col}\", 'INSERT', '{table}', json_object({pk_payload}), '{column}', json_object('value', NEW.\"{column}\"));",
log_table = TABLE_CRDT_LOGS,
hlc_col = HLC_TIMESTAMP_COLUMN,
table = table_name,
pk_payload = pk_json_payload,
column = col
@ -312,11 +314,12 @@ fn generate_update_trigger_sql(table_name: &str, pks: &[String], cols: &[String]
for col in cols {
writeln!(
&mut body,
"INSERT INTO {log_table} (hlc_timestamp, op_type, table_name, row_pks, column_name, new_value, old_value)
SELECT hlc_new_timestamp(), 'UPDATE', '{table}', json_object({pk_payload}), '{column}',
"INSERT INTO {log_table} (haex_timestamp, op_type, table_name, row_pks, column_name, new_value, old_value)
SELECT NEW.\"{hlc_col}\", 'UPDATE', '{table}', json_object({pk_payload}), '{column}',
json_object('value', NEW.\"{column}\"), json_object('value', OLD.\"{column}\")
WHERE NEW.\"{column}\" IS NOT OLD.\"{column}\";",
log_table = TABLE_CRDT_LOGS,
hlc_col = HLC_TIMESTAMP_COLUMN,
table = table_name,
pk_payload = pk_json_payload,
column = col
@ -327,10 +330,11 @@ fn generate_update_trigger_sql(table_name: &str, pks: &[String], cols: &[String]
// Soft-delete loggen
writeln!(
&mut body,
"INSERT INTO {log_table} (hlc_timestamp, op_type, table_name, row_pks)
SELECT hlc_new_timestamp(), 'DELETE', '{table}', json_object({pk_payload})
"INSERT INTO {log_table} (haex_timestamp, op_type, table_name, row_pks)
SELECT NEW.\"{hlc_col}\", 'DELETE', '{table}', json_object({pk_payload})
WHERE NEW.\"{tombstone_col}\" = 1 AND OLD.\"{tombstone_col}\" = 0;",
log_table = TABLE_CRDT_LOGS,
hlc_col = HLC_TIMESTAMP_COLUMN,
table = table_name,
pk_payload = pk_json_payload,
tombstone_col = TOMBSTONE_COLUMN

View File

@ -15,6 +15,7 @@ use sqlparser::parser::Parser;
use std::collections::HashMap;
/// Öffnet und initialisiert eine Datenbank mit Verschlüsselung
///
pub fn open_and_init_db(path: &str, key: &str, create: bool) -> Result<Connection, DatabaseError> {
let flags = if create {
OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE

View File

@ -0,0 +1,210 @@
// Auto-generated from Drizzle schema
// DO NOT EDIT MANUALLY
// Run 'pnpm generate:rust-types' to regenerate
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HaexSettings {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "type")]
pub r#type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_tombstone: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_timestamp: Option<String>,
}
impl HaexSettings {
pub fn from_row(row: &rusqlite::Row) -> rusqlite::Result<Self> {
Ok(Self {
id: row.get(0)?,
key: row.get(1)?,
r#type: row.get(2)?,
value: row.get(3)?,
haex_tombstone: row.get(4)?,
haex_timestamp: row.get(5)?,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HaexExtensions {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub author: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub entry: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub homepage: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub public_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub signature: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_tombstone: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_timestamp: Option<String>,
}
impl HaexExtensions {
pub fn from_row(row: &rusqlite::Row) -> rusqlite::Result<Self> {
Ok(Self {
id: row.get(0)?,
author: row.get(1)?,
description: row.get(2)?,
entry: row.get(3)?,
homepage: row.get(4)?,
enabled: row.get(5)?,
icon: row.get(6)?,
name: row.get(7)?,
public_key: row.get(8)?,
signature: row.get(9)?,
url: row.get(10)?,
version: row.get(11)?,
haex_tombstone: row.get(12)?,
haex_timestamp: row.get(13)?,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HaexExtensionPermissions {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub extension_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resource_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub action: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub constraints: Option<String>,
pub status: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_tombstone: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_timestamp: Option<String>,
}
impl HaexExtensionPermissions {
pub fn from_row(row: &rusqlite::Row) -> rusqlite::Result<Self> {
Ok(Self {
id: row.get(0)?,
extension_id: row.get(1)?,
resource_type: row.get(2)?,
action: row.get(3)?,
target: row.get(4)?,
constraints: row.get(5)?,
status: row.get(6)?,
created_at: row.get(7)?,
updated_at: row.get(8)?,
haex_tombstone: row.get(9)?,
haex_timestamp: row.get(10)?,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HaexCrdtLogs {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_timestamp: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub table_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub row_pks: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub op_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub column_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub old_value: Option<String>,
}
impl HaexCrdtLogs {
pub fn from_row(row: &rusqlite::Row) -> rusqlite::Result<Self> {
Ok(Self {
id: row.get(0)?,
haex_timestamp: row.get(1)?,
table_name: row.get(2)?,
row_pks: row.get(3)?,
op_type: row.get(4)?,
column_name: row.get(5)?,
new_value: row.get(6)?,
old_value: row.get(7)?,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HaexCrdtSnapshots {
pub snapshot_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub created: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub epoch_hlc: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub location_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_size_bytes: Option<i64>,
}
impl HaexCrdtSnapshots {
pub fn from_row(row: &rusqlite::Row) -> rusqlite::Result<Self> {
Ok(Self {
snapshot_id: row.get(0)?,
created: row.get(1)?,
epoch_hlc: row.get(2)?,
location_url: row.get(3)?,
file_size_bytes: row.get(4)?,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HaexCrdtConfigs {
pub key: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
}
impl HaexCrdtConfigs {
pub fn from_row(row: &rusqlite::Row) -> rusqlite::Result<Self> {
Ok(Self {
key: row.get(0)?,
value: row.get(1)?,
})
}
}

View File

@ -2,7 +2,12 @@
pub mod core;
pub mod error;
pub mod generated;
use crate::crdt::hlc::HlcService;
use crate::database::error::DatabaseError;
use crate::table_names::TABLE_CRDT_CONFIGS;
use crate::AppState;
use rusqlite::Connection;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
@ -13,13 +18,8 @@ use std::time::UNIX_EPOCH;
use std::{fs, sync::Arc};
use tauri::{path::BaseDirectory, AppHandle, Manager, State};
use tauri_plugin_fs::FsExt;
use thiserror::Error;
use ts_rs::TS;
use crate::crdt::hlc::HlcService;
use crate::database::error::DatabaseError;
use crate::table_names::TABLE_CRDT_CONFIGS;
use crate::AppState;
pub struct DbConnection(pub Arc<Mutex<Option<Connection>>>);
const VAULT_EXTENSION: &str = ".db";

View File

@ -1,973 +0,0 @@
/// src-tauri/src/extension/core.rs
use crate::extension::crypto::ExtensionCrypto;
use crate::extension::error::ExtensionError;
use crate::extension::permissions::manager::PermissionManager;
use crate::extension::permissions::types::{
Action, DbConstraints, ExtensionPermission, FsConstraints, HttpConstraints,
PermissionConstraints, PermissionStatus, ResourceType, ShellConstraints,
};
use crate::AppState;
use mime;
use serde::{Deserialize, Serialize};
use sha2::Digest;
use sha2::Sha256;
use std::collections::HashMap;
use std::fmt;
use std::fs;
use std::fs::File;
use std::path::PathBuf;
use std::sync::Mutex;
use std::time::{Duration, SystemTime};
use tauri::State;
use tauri::{
http::{Request, Response},
AppHandle, Manager, Runtime, UriSchemeContext,
};
use zip::ZipArchive;
#[derive(Serialize, Deserialize)]
pub struct ExtensionPreview {
pub manifest: ExtensionManifest,
pub is_valid_signature: bool,
pub key_hash: String,
pub editable_permissions: EditablePermissions,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct EditablePermissions {
pub permissions: Vec<EditablePermission>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct EditablePermission {
pub resource_type: String,
pub action: String,
pub target: String,
pub constraints: Option<serde_json::Value>,
pub status: String,
}
impl EditablePermissions {
/// Konvertiert EditablePermissions zu internen ExtensionPermissions
pub fn to_internal_permissions(&self, extension_id: &str) -> Vec<ExtensionPermission> {
self.permissions
.iter()
.map(|p| ExtensionPermission {
id: uuid::Uuid::new_v4().to_string(),
extension_id: extension_id.to_string(),
resource_type: match p.resource_type.as_str() {
"fs" => ResourceType::Fs,
"http" => ResourceType::Http,
"db" => ResourceType::Db,
"shell" => ResourceType::Shell,
_ => ResourceType::Fs, // Fallback
},
action: match p.action.as_str() {
"read" => Action::Read,
"write" => Action::Write,
_ => Action::Read, // Fallback
},
target: p.target.clone(),
constraints: p
.constraints
.as_ref()
.and_then(|c| Self::parse_constraints(&p.resource_type, c)),
status: match p.status.as_str() {
"granted" => PermissionStatus::Granted,
"denied" => PermissionStatus::Denied,
"ask" => PermissionStatus::Ask,
_ => PermissionStatus::Denied, // Fallback
},
haex_timestamp: None,
haex_tombstone: None,
})
.collect()
}
fn parse_constraints(
resource_type: &str,
json_value: &serde_json::Value,
) -> Option<PermissionConstraints> {
match resource_type {
"db" => serde_json::from_value::<DbConstraints>(json_value.clone())
.ok()
.map(PermissionConstraints::Database),
"fs" => serde_json::from_value::<FsConstraints>(json_value.clone())
.ok()
.map(PermissionConstraints::Filesystem),
"http" => serde_json::from_value::<HttpConstraints>(json_value.clone())
.ok()
.map(PermissionConstraints::Http),
"shell" => serde_json::from_value::<ShellConstraints>(json_value.clone())
.ok()
.map(PermissionConstraints::Shell),
_ => None,
}
}
/// Filtert nur granted Permissions
pub fn filter_granted(&self) -> Vec<EditablePermission> {
self.permissions
.iter()
.filter(|p| p.status == "granted")
.cloned()
.collect()
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ExtensionManifest {
pub id: String,
pub name: String,
pub version: String,
pub author: Option<String>,
pub entry: String,
pub icon: Option<String>,
pub public_key: String,
pub signature: String,
pub permissions: ExtensionManifestPermissions,
pub homepage: Option<String>,
pub description: Option<String>,
}
impl ExtensionManifest {
/// Berechnet den Key Hash für diese Extension
pub fn calculate_key_hash(&self) -> Result<String, ExtensionError> {
ExtensionCrypto::calculate_key_hash(&self.public_key)
.map_err(|e| ExtensionError::InvalidPublicKey { reason: e })
}
/// Generiert die vollständige Extension ID mit Key Hash Prefix
pub fn full_extension_id(&self) -> Result<String, ExtensionError> {
let key_hash = self.calculate_key_hash()?;
Ok(format!("{}-{}", key_hash, self.id))
}
pub fn to_editable_permissions(&self) -> EditablePermissions {
let mut database = Vec::new();
let mut filesystem = Vec::new();
let mut http = Vec::new();
if let Some(db) = &self.permissions.database {
for resource in &db.read {
database.push(EditableDatabasePermission {
operation: "read".to_string(),
resource: resource.clone(),
status: PermissionStatus::Granted,
});
}
for resource in &db.write {
database.push(EditableDatabasePermission {
operation: "write".to_string(),
resource: resource.clone(),
status: PermissionStatus::Granted,
});
}
}
if let Some(fs) = &self.permissions.filesystem {
for path in &fs.read {
filesystem.push(EditableFilesystemPermission {
operation: "read".to_string(),
path: path.clone(),
status: PermissionStatus::Granted,
});
}
for path in &fs.write {
filesystem.push(EditableFilesystemPermission {
operation: "write".to_string(),
path: path.clone(),
status: PermissionStatus::Granted,
});
}
}
if let Some(http_list) = &self.permissions.http {
for domain in http_list {
http.push(EditableHttpPermission {
domain: domain.clone(),
status: PermissionStatus::Granted,
});
}
}
EditablePermissions {
database,
filesystem,
http,
}
}
}
impl ExtensionManifest {
/// Konvertiert Manifest zu EditablePermissions (neue Version)
pub fn to_editable_permissions(&self) -> EditablePermissions {
let mut permissions = Vec::new();
// Database Permissions
if let Some(db) = &self.permissions.database {
for resource in &db.read {
permissions.push(EditablePermission {
resource_type: "db".to_string(),
action: "read".to_string(),
target: resource.clone(),
constraints: None,
status: "granted".to_string(),
});
}
for resource in &db.write {
permissions.push(EditablePermission {
resource_type: "db".to_string(),
action: "write".to_string(),
target: resource.clone(),
constraints: None,
status: "granted".to_string(),
});
}
}
// Filesystem Permissions
if let Some(fs) = &self.permissions.filesystem {
for path in &fs.read {
permissions.push(EditablePermission {
resource_type: "fs".to_string(),
action: "read".to_string(),
target: path.clone(),
constraints: None,
status: "granted".to_string(),
});
}
for path in &fs.write {
permissions.push(EditablePermission {
resource_type: "fs".to_string(),
action: "write".to_string(),
target: path.clone(),
constraints: None,
status: "granted".to_string(),
});
}
}
// HTTP Permissions
if let Some(http_list) = &self.permissions.http {
for domain in http_list {
permissions.push(EditablePermission {
resource_type: "http".to_string(),
action: "read".to_string(), // HTTP ist meist read
target: domain.clone(),
constraints: None,
status: "granted".to_string(),
});
}
}
// Shell Permissions
if let Some(shell_list) = &self.permissions.shell {
for command in shell_list {
permissions.push(EditablePermission {
resource_type: "shell".to_string(),
action: "read".to_string(), // Shell hat keine action mehr im Schema
target: command.clone(),
constraints: None,
status: "granted".to_string(),
});
}
}
EditablePermissions { permissions }
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ExtensionInfoResponse {
pub key_hash: String,
pub name: String,
pub full_id: String,
pub version: String,
pub display_name: Option<String>,
pub namespace: Option<String>,
pub allowed_origin: String,
}
impl ExtensionInfoResponse {
pub fn from_extension(extension: &Extension) -> Result<Self, ExtensionError> {
// Bestimme die allowed_origin basierend auf Tauri-Konfiguration
let allowed_origin = get_tauri_origin();
let key_hash = extension
.manifest
.calculate_key_hash()
.map_err(|e| ExtensionError::InvalidPublicKey { reason: e })?;
let full_id = extension
.manifest
.full_extension_id()
.map_err(|e| ExtensionError::InvalidPublicKey { reason: e })?;
Ok(Self {
key_hash,
name: extension.manifest.name.clone(),
full_id,
version: extension.manifest.version.clone(),
display_name: Some(extension.manifest.name.clone()),
namespace: extension.manifest.author.clone(),
allowed_origin,
})
}
}
fn get_tauri_origin() -> String {
#[cfg(target_os = "windows")]
{
"https://tauri.localhost".to_string()
}
#[cfg(target_os = "macos")]
{
"tauri://localhost".to_string()
}
#[cfg(target_os = "linux")]
{
"tauri://localhost".to_string()
}
#[cfg(target_os = "android")]
{
"tauri://localhost".to_string()
}
#[cfg(target_os = "ios")]
{
"tauri://localhost".to_string()
}
}
/// Extension source type (production vs development)
#[derive(Debug, Clone)]
pub enum ExtensionSource {
Production {
path: PathBuf,
version: String,
},
Development {
dev_server_url: String,
manifest_path: PathBuf,
auto_reload: bool,
},
}
/// Complete extension data structure
#[derive(Debug, Clone)]
pub struct Extension {
pub id: String,
pub name: String,
pub source: ExtensionSource,
pub manifest: ExtensionManifest,
pub enabled: bool,
pub last_accessed: SystemTime,
}
/// Cached permission data for performance
#[derive(Debug, Clone)]
pub struct CachedPermission {
pub permissions: Vec<DbExtensionPermission>,
pub cached_at: SystemTime,
pub ttl: Duration,
}
/// Enhanced extension manager
#[derive(Default)]
pub struct ExtensionManager {
pub production_extensions: Mutex<HashMap<String, Extension>>,
pub dev_extensions: Mutex<HashMap<String, Extension>>,
pub permission_cache: Mutex<HashMap<String, CachedPermission>>,
}
impl ExtensionManager {
pub fn new() -> Self {
Self::default()
}
pub fn get_base_extension_dir(&self, app_handle: AppHandle) -> Result<PathBuf, ExtensionError> {
let path = app_handle
.path()
.app_local_data_dir() // Korrekt für Ressourcen
// Wenn du stattdessen App Local Data willst: .app_local_data_dir()
.map_err(|e| ExtensionError::Filesystem {
source: std::io::Error::new(std::io::ErrorKind::NotFound, e.to_string()),
})?
.join("extensions");
Ok(path)
}
pub fn get_extension_dir(
&self,
app_handle: AppHandle,
extension_id: &str,
extension_version: &str,
) -> Result<PathBuf, ExtensionError> {
let specific_extension_dir = self
.get_base_extension_dir(app_handle)?
.join(extension_id)
.join(extension_version);
Ok(specific_extension_dir)
}
pub fn add_production_extension(&self, extension: Extension) -> Result<(), ExtensionError> {
if extension.id.is_empty() {
return Err(ExtensionError::ValidationError {
reason: "Extension ID cannot be empty".to_string(),
});
}
// Validate filesystem permissions
/* if let Some(fs_perms) = &extension.manifest.permissions.filesystem {
fs_perms.validate()?;
}
*/
match &extension.source {
ExtensionSource::Production { .. } => {
let mut extensions = self.production_extensions.lock().unwrap();
extensions.insert(extension.id.clone(), extension);
Ok(())
}
_ => Err(ExtensionError::ValidationError {
reason: "Expected Production source".to_string(),
}),
}
}
pub fn add_dev_extension(&self, extension: Extension) -> Result<(), ExtensionError> {
if extension.id.is_empty() {
return Err(ExtensionError::ValidationError {
reason: "Extension ID cannot be empty".to_string(),
});
}
// Validate filesystem permissions
/* if let Some(fs_perms) = &extension.manifest.permissions.filesystem {
fs_perms.validate()?;
} */
match &extension.source {
ExtensionSource::Development { .. } => {
let mut extensions = self.dev_extensions.lock().unwrap();
extensions.insert(extension.id.clone(), extension);
Ok(())
}
_ => Err(ExtensionError::ValidationError {
reason: "Expected Development source".to_string(),
}),
}
}
pub fn get_extension(&self, extension_id: &str) -> Option<Extension> {
// Dev extensions take priority
let dev_extensions = self.dev_extensions.lock().unwrap();
if let Some(extension) = dev_extensions.get(extension_id) {
return Some(extension.clone());
}
// Then check production
let prod_extensions = self.production_extensions.lock().unwrap();
prod_extensions.get(extension_id).cloned()
}
pub fn remove_extension(&self, extension_id: &str) -> Result<(), ExtensionError> {
{
let mut dev_extensions = self.dev_extensions.lock().unwrap();
if dev_extensions.remove(extension_id).is_some() {
return Ok(());
}
}
{
let mut prod_extensions = self.production_extensions.lock().unwrap();
if prod_extensions.remove(extension_id).is_some() {
return Ok(());
}
}
Err(ExtensionError::NotFound {
id: extension_id.to_string(),
})
}
pub async fn remove_extension_internal(
&self,
app_handle: AppHandle,
extension_id: String,
extension_version: String,
state: &State<'_, AppState>,
) -> Result<(), ExtensionError> {
// Permissions löschen (verwendet jetzt die neue Methode)
PermissionManager::delete_permissions(state, &extension_id).await?;
// Extension aus Manager entfernen
self.remove_extension(&extension_id)?;
let extension_dir =
self.get_extension_dir(app_handle, &extension_id, &extension_version)?;
// Dateien löschen
if extension_dir.exists() {
std::fs::remove_dir_all(&extension_dir)
.map_err(|e| ExtensionError::Filesystem { source: e })?;
}
Ok(())
}
pub async fn preview_extension_internal(
&self,
source_path: String,
) -> Result<ExtensionPreview, ExtensionError> {
let source = PathBuf::from(&source_path);
// ZIP in temp entpacken
let temp = std::env::temp_dir().join(format!("haexhub_preview_{}", uuid::Uuid::new_v4()));
std::fs::create_dir_all(&temp).map_err(|e| ExtensionError::Filesystem { source: e })?;
let file = File::open(&source).map_err(|e| ExtensionError::Filesystem { source: e })?;
let mut archive =
ZipArchive::new(file).map_err(|e| ExtensionError::InstallationFailed {
reason: format!("Invalid ZIP: {}", e),
})?;
archive
.extract(&temp)
.map_err(|e| ExtensionError::InstallationFailed {
reason: format!("Cannot extract ZIP: {}", e),
})?;
// Manifest laden
let manifest_path = temp.join("manifest.json");
let manifest_content =
std::fs::read_to_string(&manifest_path).map_err(|e| ExtensionError::ManifestError {
reason: format!("Cannot read manifest: {}", e),
})?;
let manifest: ExtensionManifest = serde_json::from_str(&manifest_content)?;
// Signatur verifizieren
let content_hash = ExtensionCrypto::hash_directory(&temp)
.map_err(|e| ExtensionError::SignatureVerificationFailed { reason: e })?;
let is_valid_signature = ExtensionCrypto::verify_signature(
&manifest.public_key,
&content_hash,
&manifest.signature,
)
.is_ok();
let key_hash = manifest.calculate_key_hash()?;
// Editable permissions erstellen
let editable_permissions = manifest.to_editable_permissions();
// Cleanup
std::fs::remove_dir_all(&temp).ok();
Ok(ExtensionPreview {
manifest,
is_valid_signature,
key_hash,
editable_permissions,
})
}
pub async fn install_extension_with_permissions_internal(
&self,
app_handle: AppHandle,
source_path: String,
custom_permissions: EditablePermissions,
state: &State<'_, AppState>,
) -> Result<String, ExtensionError> {
let source = PathBuf::from(&source_path);
// 1. ZIP entpacken
let temp = std::env::temp_dir().join(format!("haexhub_ext_{}", uuid::Uuid::new_v4()));
std::fs::create_dir_all(&temp).map_err(|e| ExtensionError::Filesystem { source: e })?;
let file = File::open(&source).map_err(|e| ExtensionError::Filesystem { source: e })?;
let mut archive =
ZipArchive::new(file).map_err(|e| ExtensionError::InstallationFailed {
reason: format!("Invalid ZIP: {}", e),
})?;
archive
.extract(&temp)
.map_err(|e| ExtensionError::InstallationFailed {
reason: format!("Cannot extract ZIP: {}", e),
})?;
// 2. Manifest laden
let manifest_path = temp.join("manifest.json");
let manifest_content =
std::fs::read_to_string(&manifest_path).map_err(|e| ExtensionError::ManifestError {
reason: format!("Cannot read manifest: {}", e),
})?;
let manifest: ExtensionManifest = serde_json::from_str(&manifest_content)?;
// 3. Signatur verifizieren
let content_hash = ExtensionCrypto::hash_directory(&temp)
.map_err(|e| ExtensionError::SignatureVerificationFailed { reason: e })?;
ExtensionCrypto::verify_signature(&manifest.public_key, &content_hash, &manifest.signature)
.map_err(|e| ExtensionError::SignatureVerificationFailed { reason: e })?;
// 4. Key Hash berechnen
let key_hash = manifest.calculate_key_hash()?;
let full_extension_id = format!("{}-{}", key_hash, manifest.id);
// 5. Zielverzeichnis
let extensions_dir = app_handle
.path()
.app_data_dir()
.map_err(|e| ExtensionError::Filesystem {
source: std::io::Error::new(std::io::ErrorKind::NotFound, e.to_string()),
})?
.join("extensions")
.join(&full_extension_id)
.join(&manifest.version);
std::fs::create_dir_all(&extensions_dir)
.map_err(|e| ExtensionError::Filesystem { source: e })?;
// 6. Dateien kopieren
copy_directory(
temp.to_string_lossy().to_string(),
extensions_dir.to_string_lossy().to_string(),
)?;
// 7. Temp aufräumen
std::fs::remove_dir_all(&temp).ok();
// 8. Custom Permissions konvertieren und speichern
let permissions = custom_permissions.to_internal_permissions(&full_extension_id);
let granted_permissions = permissions.filter_granted();
PermissionManager::save_permissions(&state.db, &granted_permissions).await?;
// 9. Extension registrieren
let extension = Extension {
id: full_extension_id.clone(),
name: manifest.name.clone(),
source: ExtensionSource::Production {
path: extensions_dir.clone(),
version: manifest.version.clone(),
},
manifest: manifest.clone(),
enabled: true,
last_accessed: SystemTime::now(),
};
state
.extension_manager
.add_production_extension(extension)?;
Ok(full_extension_id)
}
}
// For backward compatibility
#[derive(Default)]
pub struct ExtensionState {
pub extensions: Mutex<HashMap<String, ExtensionManifest>>,
}
impl ExtensionState {
pub fn add_extension(&self, path: String, manifest: ExtensionManifest) {
let mut extensions = self.extensions.lock().unwrap();
extensions.insert(path, manifest);
}
pub fn get_extension(&self, addon_id: &str) -> Option<ExtensionManifest> {
let extensions = self.extensions.lock().unwrap();
extensions.values().find(|p| p.name == addon_id).cloned()
}
}
#[derive(Deserialize, Debug)]
struct ExtensionInfo {
id: String,
version: String,
}
#[derive(Debug)]
enum DataProcessingError {
HexDecoding(hex::FromHexError),
Utf8Conversion(std::string::FromUtf8Error),
JsonParsing(serde_json::Error),
}
// Implementierung von Display für benutzerfreundliche Fehlermeldungen
impl fmt::Display for DataProcessingError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DataProcessingError::HexDecoding(e) => write!(f, "Hex-Dekodierungsfehler: {}", e),
DataProcessingError::Utf8Conversion(e) => {
write!(f, "UTF-8-Konvertierungsfehler: {}", e)
}
DataProcessingError::JsonParsing(e) => write!(f, "JSON-Parsing-Fehler: {}", e),
}
}
}
// Implementierung von std::error::Error (optional, aber gute Praxis für bibliotheksähnlichen Code)
impl std::error::Error for DataProcessingError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
DataProcessingError::HexDecoding(e) => Some(e),
DataProcessingError::Utf8Conversion(e) => Some(e),
DataProcessingError::JsonParsing(e) => Some(e),
}
}
}
// Implementierung von From-Traits für einfache Verwendung des '?'-Operators
impl From<hex::FromHexError> for DataProcessingError {
fn from(err: hex::FromHexError) -> Self {
DataProcessingError::HexDecoding(err)
}
}
impl From<std::string::FromUtf8Error> for DataProcessingError {
fn from(err: std::string::FromUtf8Error) -> Self {
DataProcessingError::Utf8Conversion(err)
}
}
impl From<serde_json::Error> for DataProcessingError {
fn from(err: serde_json::Error) -> Self {
DataProcessingError::JsonParsing(err)
}
}
pub fn copy_directory(source: String, destination: String) -> Result<(), ExtensionError> {
println!(
"Kopiere Verzeichnis von '{}' nach '{}'",
source, destination
);
let source_path = PathBuf::from(&source);
let destination_path = PathBuf::from(&destination);
if !source_path.exists() || !source_path.is_dir() {
return Err(ExtensionError::Filesystem {
source: std::io::Error::new(
std::io::ErrorKind::NotFound,
format!("Source directory '{}' not found", source),
),
});
}
// Optionen für fs_extra::dir::copy
let mut options = fs_extra::dir::CopyOptions::new();
options.overwrite = true; // Überschreibe Zieldateien, falls sie existieren
options.copy_inside = true; // Kopiere den *Inhalt* des Quellordners in den Zielordner
// options.content_only = true; // Alternative: nur Inhalt kopieren, Zielordner muss existieren
options.buffer_size = 64000; // Standard-Puffergröße, kann angepasst werden
// Führe die Kopieroperation aus
fs_extra::dir::copy(&source_path, &destination_path, &options).map_err(|e| {
ExtensionError::Filesystem {
source: std::io::Error::new(std::io::ErrorKind::Other, e.to_string()),
}
})?;
Ok(())
}
pub fn resolve_secure_extension_asset_path(
app_handle: AppHandle,
state: State<AppState>,
extension_id: &str,
extension_version: &str,
requested_asset_path: &str,
) -> Result<PathBuf, ExtensionError> {
// 1. Validiere die Extension ID
if extension_id.is_empty()
|| !extension_id
.chars()
.all(|c| c.is_ascii_alphanumeric() || c == '-')
{
return Err(ExtensionError::ValidationError {
reason: format!("Invalid extension ID: {}", extension_id),
});
}
if extension_version.is_empty()
|| !extension_version
.chars()
.all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '.')
{
return Err(ExtensionError::ValidationError {
reason: format!("Invalid extension version: {}", extension_version),
});
}
// 3. Verzeichnis für die spezifische Erweiterung
let specific_extension_dir =
state
.extension_manager
.get_extension_dir(app_handle, extension_id, extension_version)?;
// 4. Bereinige den angeforderten Asset-Pfad
let clean_relative_path = requested_asset_path
.replace('\\', "/")
.trim_start_matches('/')
.split('/')
.filter(|&part| !part.is_empty() && part != "." && part != "..")
.collect::<PathBuf>();
if clean_relative_path.as_os_str().is_empty() && requested_asset_path != "/" {
return Err(ExtensionError::ValidationError {
reason: "Empty or invalid asset path".to_string(),
});
}
// 5. Setze den finalen Pfad zusammen
let final_path = specific_extension_dir.join(clean_relative_path);
// 6. SICHERHEITSCHECK
match final_path.canonicalize() {
Ok(canonical_path) => {
let canonical_base = specific_extension_dir
.canonicalize()
.map_err(|e| ExtensionError::Filesystem { source: e })?;
if canonical_path.starts_with(&canonical_base) {
Ok(canonical_path)
} else {
eprintln!( /* ... Sicherheitswarnung ... */ );
Err(ExtensionError::SecurityViolation {
reason: format!("Path traversal attempt: {}", requested_asset_path),
})
}
}
Err(_) => {
// Fehler bei canonicalize (z.B. Pfad existiert nicht)
if final_path.starts_with(&specific_extension_dir) {
Ok(final_path) // Nicht-kanonisierten Pfad zurückgeben
} else {
eprintln!( /* ... Sicherheitswarnung ... */ );
Err(ExtensionError::SecurityViolation {
reason: format!("Invalid asset path: {}", requested_asset_path),
})
}
}
}
}
pub fn extension_protocol_handler<R: Runtime>(
state: State<AppState>,
app_handle: AppHandle,
request: &Request<Vec<u8>>,
) -> Result<Response<Vec<u8>>, Box<dyn std::error::Error>> {
let uri_ref = request.uri();
println!("Protokoll Handler für: {}", uri_ref);
let host = uri_ref
.host()
.ok_or("Kein Host (Extension ID) in URI gefunden")?
.to_string();
let path_str = uri_ref.path();
let segments_iter = path_str.split('/').filter(|s| !s.is_empty());
let resource_segments: Vec<&str> = segments_iter.collect();
let raw_asset_path = resource_segments.join("/");
let asset_to_load = if raw_asset_path.is_empty() {
"index.html"
} else {
&raw_asset_path
};
match process_hex_encoded_json(&host) {
Ok(info) => {
println!("Daten erfolgreich verarbeitet:");
println!(" ID: {}", info.id);
println!(" Version: {}", info.version);
let absolute_secure_path = resolve_secure_extension_asset_path(
app_handle,
state,
&info.id,
&info.version,
&asset_to_load,
)?;
println!("absolute_secure_path: {}", absolute_secure_path.display());
if absolute_secure_path.exists() && absolute_secure_path.is_file() {
match fs::read(&absolute_secure_path) {
Ok(content) => {
let mime_type = mime_guess::from_path(&absolute_secure_path)
.first_or(mime::APPLICATION_OCTET_STREAM)
.to_string();
let content_length = content.len();
println!(
"Liefere {} ({}, {} bytes) ", // Content-Length zum Log hinzugefügt
absolute_secure_path.display(),
mime_type,
content_length
);
Response::builder()
.status(200)
.header("Content-Type", mime_type)
.header("Content-Length", content_length.to_string()) // <-- HIER HINZUGEFÜGT
// Optional, aber gut für Streaming-Fähigkeit:
.header("Accept-Ranges", "bytes")
.body(content)
.map_err(|e| e.into())
}
Err(e) => {
eprintln!(
"Fehler beim Lesen der Datei {}: {}",
absolute_secure_path.display(),
e
);
let status_code = if e.kind() == std::io::ErrorKind::NotFound {
404
} else if e.kind() == std::io::ErrorKind::PermissionDenied {
403
} else {
500
};
Response::builder()
.status(status_code)
.body(Vec::new()) // Leerer Body für Fehler
.map_err(|e| e.into()) // Wandle http::Error in Box<dyn Error> um
}
}
} else {
// Datei nicht gefunden oder es ist keine Datei
eprintln!(
"Asset nicht gefunden oder ist kein File: {}",
absolute_secure_path.display()
);
Response::builder()
.status(404) // HTTP 404 Not Found
.body(Vec::new())
.map_err(|e| e.into())
}
}
Err(e) => {
eprintln!("Fehler bei der Datenverarbeitung: {}", e);
Response::builder()
.status(500)
.body(Vec::new()) // Leerer Body für Fehler
.map_err(|e| e.into())
}
}
}
fn process_hex_encoded_json(hex_input: &str) -> Result<ExtensionInfo, DataProcessingError> {
// Schritt 1: Hex-String zu Bytes dekodieren
let bytes = hex::decode(hex_input)?; // Konvertiert hex::FromHexError automatisch
// Schritt 2: Bytes zu UTF-8-String konvertieren
let json_string = String::from_utf8(bytes)?; // Konvertiert FromUtf8Error automatisch
// Schritt 3: JSON-String zu Struktur parsen
let extension_info: ExtensionInfo = serde_json::from_str(&json_string)?; // Konvertiert serde_json::Error automatisch
Ok(extension_info)
}

View File

@ -5,7 +5,7 @@ use crate::crdt::transformer::CrdtTransformer;
use crate::crdt::trigger;
use crate::database::core::{parse_sql_statements, ValueConverter};
use crate::database::error::DatabaseError;
use rusqlite::{params_from_iter, Transaction};
use rusqlite::{params_from_iter, Params, Transaction};
use serde_json::Value as JsonValue;
use sqlparser::ast::Statement;
use std::collections::HashSet;
@ -14,6 +14,62 @@ use std::collections::HashSet;
pub struct SqlExecutor;
impl SqlExecutor {
pub fn execute_internal_typed<P>(
tx: &Transaction,
hlc_service: &HlcService,
sql: &str,
params: P, // Akzeptiert jetzt alles, was rusqlite als Parameter versteht
) -> Result<HashSet<String>, DatabaseError>
where
P: Params,
{
let mut ast_vec = parse_sql_statements(sql)?;
// Wir stellen sicher, dass wir nur EIN Statement verarbeiten. Das ist sicherer.
if ast_vec.len() != 1 {
return Err(DatabaseError::ExecutionError {
sql: sql.to_string(),
reason: "execute_internal_typed sollte nur ein einzelnes SQL-Statement erhalten"
.to_string(),
table: None,
});
}
// Wir nehmen das einzige Statement aus dem Vektor.
let mut statement = ast_vec.pop().unwrap();
let transformer = CrdtTransformer::new();
let hlc_timestamp =
hlc_service
.new_timestamp_and_persist(tx)
.map_err(|e| DatabaseError::HlcError {
reason: e.to_string(),
})?;
let mut modified_schema_tables = HashSet::new();
if let Some(table_name) =
transformer.transform_execute_statement(&mut statement, &hlc_timestamp)?
{
modified_schema_tables.insert(table_name);
}
// Führe das transformierte Statement aus.
// `params` wird jetzt nur noch einmal hierher bewegt, was korrekt ist.
let sql_str = statement.to_string();
tx.execute(&sql_str, params)
.map_err(|e| DatabaseError::ExecutionError {
sql: sql_str.clone(),
table: None,
reason: e.to_string(),
})?;
// Die Trigger-Logik für CREATE TABLE bleibt erhalten.
if let Statement::CreateTable(create_table_details) = statement {
let table_name_str = create_table_details.name.to_string();
trigger::setup_triggers_for_table(tx, &table_name_str, false)?;
}
Ok(modified_schema_tables)
}
/// Führt SQL aus (mit CRDT-Transformation) - OHNE Permission-Check
pub fn execute_internal(
tx: &Transaction,

View File

@ -1,7 +1,6 @@
// src-tauri/src/extension/database/mod.rs
pub mod executor;
use crate::crdt::hlc::HlcService;
use crate::crdt::transformer::CrdtTransformer;
use crate::crdt::trigger;
use crate::database::core::{parse_sql_statements, with_connection, ValueConverter};
@ -22,15 +21,11 @@ use tauri::State;
/// Führt Statements mit korrekter Parameter-Bindung aus
pub struct StatementExecutor<'a> {
transaction: &'a Transaction<'a>,
hlc_service: &'a HlcService,
}
impl<'a> StatementExecutor<'a> {
fn new(transaction: &'a Transaction<'a>, hlc_service: &'a HlcService) -> Self {
Self {
transaction,
hlc_service,
}
fn new(transaction: &'a Transaction<'a>) -> Self {
Self { transaction }
}
/// Führt ein einzelnes Statement mit Parametern aus
@ -114,7 +109,6 @@ pub async fn extension_sql_execute(
params: Vec<JsonValue>,
extension_id: String,
state: State<'_, AppState>,
hlc_service: State<'_, HlcService>,
) -> Result<Vec<String>, ExtensionError> {
// Permission check
SqlPermissionValidator::validate_sql(&state, &extension_id, sql).await?;
@ -130,15 +124,17 @@ pub async fn extension_sql_execute(
let tx = conn.transaction().map_err(DatabaseError::from)?;
let transformer = CrdtTransformer::new();
let executor = StatementExecutor::new(&tx, &hlc_service);
let executor = StatementExecutor::new(&tx);
// Generate HLC timestamp
let hlc_timestamp =
hlc_service
.new_timestamp_and_persist(&tx)
.map_err(|e| DatabaseError::HlcError {
reason: e.to_string(),
})?;
let hlc_timestamp = state
.hlc
.lock()
.unwrap()
.new_timestamp_and_persist(&tx)
.map_err(|e| DatabaseError::HlcError {
reason: e.to_string(),
})?;
// Transform statements
let mut modified_schema_tables = HashSet::new();
@ -302,13 +298,13 @@ fn count_sql_placeholders(sql: &str) -> usize {
}
/// Kürzt SQL für Fehlermeldungen
fn truncate_sql(sql: &str, max_length: usize) -> String {
/* fn truncate_sql(sql: &str, max_length: usize) -> String {
if sql.len() <= max_length {
sql.to_string()
} else {
format!("{}...", &sql[..max_length])
}
}
} */
#[cfg(test)]
mod tests {
@ -327,12 +323,12 @@ mod tests {
assert_eq!(count_sql_placeholders("SELECT * FROM users"), 0);
}
#[test]
/* #[test]
fn test_truncate_sql() {
let sql = "SELECT * FROM very_long_table_name";
assert_eq!(truncate_sql(sql, 10), "SELECT * F...");
assert_eq!(truncate_sql(sql, 50), sql);
}
} */
#[test]
fn test_validate_params() {

View File

@ -1,14 +1,17 @@
use crate::table_names::TABLE_EXTENSION_PERMISSIONS;
use crate::AppState;
use crate::database::core::with_connection;
use crate::database::error::DatabaseError;
use crate::extension::database::executor::SqlExecutor;
use crate::extension::error::ExtensionError;
use crate::extension::permissions::types::{Action, DbConstraints, ExtensionPermission, FsConstraints, HttpConstraints, PermissionConstraints, PermissionStatus, ResourceType, ShellConstraints};
use crate::extension::permissions::types::{parse_constraints, Action, DbConstraints, ExtensionPermission, FsConstraints, HttpConstraints, PermissionConstraints, PermissionStatus, ResourceType, ShellConstraints};
use serde_json;
use serde_json::json;
use std::path::Path;
use tauri::State;
use url::Url;
use crate::database::generated::HaexExtensionPermissions;
use rusqlite::{params, ToSql};
pub struct PermissionManager;
@ -29,31 +32,29 @@ impl PermissionManager {
reason: "Failed to lock HLC service".to_string(),
})?;
let sql = format!(
"INSERT INTO {} (id, extension_id, resource_type, action, target, constraints, status) VALUES (?, ?, ?, ?, ?, ?, ?)",
TABLE_EXTENSION_PERMISSIONS
);
for perm in permissions {
let resource_type_str = format!("{:?}", perm.resource_type).to_lowercase();
let action_str = format!("{:?}", perm.action).to_lowercase();
// 1. Konvertiere App-Struct zu DB-Struct
let db_perm: HaexExtensionPermissions = perm.into();
let constraints_json = perm
.constraints
.as_ref()
.map(|c| serde_json::to_string(c).ok())
.flatten();
let sql = "INSERT INTO haex_extension_permissions
(id, extension_id, resource_type, action, target, constraints, status)
VALUES (?, ?, ?, ?, ?, ?, ?)";
let params = vec![
json!(perm.id),
json!(extension_id),
json!(resource_type_str),
json!(action_str),
json!(perm.target),
json!(constraints_json),
json!(perm.status.as_str()),
// 2. Erstelle typsichere Parameter
let params = params![
db_perm.id,
db_perm.extension_id,
db_perm.resource_type,
db_perm.action,
db_perm.target,
db_perm.constraints,
db_perm.status,
];
SqlExecutor::execute_internal(&tx, &hlc_service, sql, &params)?;
// 3. Führe mit dem typsicheren Executor aus
// HINWEIS: Du musst eine `execute_internal_typed` Funktion erstellen!
SqlExecutor::execute_internal_typed(&tx, &hlc_service, &sql, params)?;
}
tx.commit().map_err(DatabaseError::from)?;
@ -77,32 +78,24 @@ impl PermissionManager {
reason: "Failed to lock HLC service".to_string(),
})?;
let resource_type_str = format!("{:?}", permission.resource_type).to_lowercase();
let action_str = format!("{:?}", permission.action).to_lowercase();
let db_perm: HaexExtensionPermissions = permission.into();
let sql = format!(
"UPDATE {} SET resource_type = ?, action = ?, target = ?, constraints = ?, status = ? WHERE id = ?",
TABLE_EXTENSION_PERMISSIONS
);
let constraints_json = permission
.constraints
.as_ref()
.map(|c| serde_json::to_string(c).ok())
.flatten();
let sql = "UPDATE haex_extension_permissions
SET resource_type = ?, action = ?, target = ?, constraints = ?, status = ?
WHERE id = ?";
let params = vec![
json!(resource_type_str),
json!(action_str),
json!(permission.target),
json!(constraints_json),
json!(permission.status.as_str()),
json!(permission.id),
let params = params![
db_perm.resource_type,
db_perm.action,
db_perm.target,
db_perm.constraints,
db_perm.status,
db_perm.id,
];
SqlExecutor::execute_internal(&tx, &hlc_service, sql, &params)?;
tx.commit().map_err(DatabaseError::from)?;
Ok(())
SqlExecutor::execute_internal_typed(&tx, &hlc_service, &sql, params)?;
tx.commit().map_err(DatabaseError::from)
})
.map_err(ExtensionError::from)
}
@ -123,16 +116,10 @@ impl PermissionManager {
reason: "Failed to lock HLC service".to_string(),
})?;
let sql = "UPDATE haex_extension_permissions
SET status = ?
WHERE id = ?";
let params = vec![json!(new_status.as_str()), json!(permission_id)];
SqlExecutor::execute_internal(&tx, &hlc_service, sql, &params)?;
tx.commit().map_err(DatabaseError::from)?;
Ok(())
let sql = format!("UPDATE {} SET status = ? WHERE id = ?", TABLE_EXTENSION_PERMISSIONS);
let params = params![new_status.as_str(), permission_id];
SqlExecutor::execute_internal_typed(&tx, &hlc_service, &sql, params)?;
tx.commit().map_err(DatabaseError::from)
})
.map_err(ExtensionError::from)
}
@ -151,14 +138,9 @@ impl PermissionManager {
})?;
// Echtes DELETE - wird vom CrdtTransformer zu UPDATE umgewandelt
let sql = "DELETE FROM haex_extension_permissions WHERE id = ?";
let params = vec![json!(permission_id)];
SqlExecutor::execute_internal(&tx, &hlc_service, sql, &params)?;
tx.commit().map_err(DatabaseError::from)?;
Ok(())
let sql = format!("DELETE FROM {} WHERE id = ?", TABLE_EXTENSION_PERMISSIONS);
SqlExecutor::execute_internal_typed(&tx, &hlc_service, &sql, params![permission_id])?;
tx.commit().map_err(DatabaseError::from)
}).map_err(ExtensionError::from)
}
@ -175,15 +157,9 @@ impl PermissionManager {
reason: "Failed to lock HLC service".to_string(),
})?;
// Echtes DELETE - wird vom CrdtTransformer zu UPDATE umgewandelt
let sql = "DELETE FROM haex_extension_permissions WHERE extension_id = ?";
let params = vec![json!(extension_id)];
SqlExecutor::execute_internal(&tx, &hlc_service, sql, &params)?;
tx.commit().map_err(DatabaseError::from)?;
Ok(())
let sql = format!("DELETE FROM {} WHERE extension_id = ?", TABLE_EXTENSION_PERMISSIONS);
SqlExecutor::execute_internal_typed(&tx, &hlc_service, &sql, params![extension_id])?;
tx.commit().map_err(DatabaseError::from)
}).map_err(ExtensionError::from)
}
/// Lädt alle Permissions einer Extension
@ -192,92 +168,23 @@ impl PermissionManager {
extension_id: &str,
) -> Result<Vec<ExtensionPermission>, ExtensionError> {
with_connection(&app_state.db, |conn| {
let sql = "SELECT id, extension_id, resource_type, action, target, constraints, status, haex_timestamp, haex_tombstone
FROM haex_extension_permissions
WHERE extension_id = ?";
let sql = format!("SELECT * FROM {} WHERE extension_id = ?", TABLE_EXTENSION_PERMISSIONS);
let mut stmt = conn.prepare(&sql).map_err(DatabaseError::from)?;
let params = vec![json!(extension_id)];
let perms_iter = stmt.query_map(params![extension_id], |row| {
HaexExtensionPermissions::from_row(row)
})?;
// SELECT nutzt select_internal
let results = SqlExecutor::select_internal(conn, sql, &params)?;
// Parse JSON results zu ExtensionPermission
let permissions = results
.into_iter()
.map(|row| Self::parse_permission_from_json(row))
.collect::<Result<Vec<_>, _>>()?;
let permissions = perms_iter
.filter_map(Result::ok)
.map(Into::into)
.collect();
Ok(permissions)
}).map_err(ExtensionError::from)
}
// Helper für JSON -> ExtensionPermission Konvertierung
fn parse_permission_from_json(json: serde_json::Value) -> Result<ExtensionPermission, DatabaseError> {
let obj = json.as_object().ok_or_else(|| DatabaseError::SerializationError {
reason: "Expected JSON object".to_string(),
})?;
let resource_type = Self::parse_resource_type(
obj.get("resource_type")
.and_then(|v| v.as_str())
.ok_or_else(|| DatabaseError::SerializationError {
reason: "Missing resource_type".to_string(),
})?
)?;
let action = Self::parse_action(
obj.get("action")
.and_then(|v| v.as_str())
.ok_or_else(|| DatabaseError::SerializationError {
reason: "Missing action".to_string(),
})?
)?;
let status = PermissionStatus::from_str(
obj.get("status")
.and_then(|v| v.as_str())
.ok_or_else(|| DatabaseError::SerializationError {
reason: "Missing status".to_string(),
})?
)?; // Jetzt funktioniert das ?
let constraints = obj.get("constraints")
.and_then(|v| v.as_str())
.map(|json_str| Self::parse_constraints(&resource_type, json_str))
.transpose()?;
Ok(ExtensionPermission {
id: obj.get("id")
.and_then(|v| v.as_str())
.ok_or_else(|| DatabaseError::SerializationError {
reason: "Missing id".to_string(),
})?
.to_string(),
extension_id: obj.get("extension_id")
.and_then(|v| v.as_str())
.ok_or_else(|| DatabaseError::SerializationError {
reason: "Missing extension_id".to_string(),
})?
.to_string(),
resource_type,
action,
target: obj.get("target")
.and_then(|v| v.as_str())
.ok_or_else(|| DatabaseError::SerializationError {
reason: "Missing target".to_string(),
})?
.to_string(),
constraints,
status,
haex_timestamp: obj.get("haex_timestamp")
.and_then(|v| v.as_str())
.map(|s| s.to_string()),
haex_tombstone: obj.get("haex_tombstone")
.and_then(|v| v.as_i64())
.map(|i| i == 1),
})
}
/// Prüft Datenbankberechtigungen
pub async fn check_database_permission(
@ -311,7 +218,7 @@ impl PermissionManager {
Ok(())
}
/// Prüft Dateisystem-Berechtigungen
/* /// Prüft Dateisystem-Berechtigungen
pub async fn check_filesystem_permission(
app_state: &State<'_, AppState>,
extension_id: &str,
@ -471,9 +378,9 @@ impl PermissionManager {
Ok(())
}
*/
// Helper-Methoden - müssen DatabaseError statt ExtensionError zurückgeben
fn parse_resource_type(s: &str) -> Result<ResourceType, DatabaseError> {
pub fn parse_resource_type(s: &str) -> Result<ResourceType, DatabaseError> {
match s {
"fs" => Ok(ResourceType::Fs),
"http" => Ok(ResourceType::Http),
@ -485,52 +392,8 @@ impl PermissionManager {
}
}
fn parse_action(s: &str) -> Result<Action, DatabaseError> {
match s {
"read" => Ok(Action::Read),
"write" => Ok(Action::Write),
_ => Err(DatabaseError::SerializationError {
reason: format!("Unknown action: {}", s),
}),
}
}
fn parse_constraints(
resource_type: &ResourceType,
json: &str,
) -> Result<PermissionConstraints, DatabaseError> {
match resource_type {
ResourceType::Db => {
let constraints: DbConstraints = serde_json::from_str(json)
.map_err(|e| DatabaseError::SerializationError {
reason: format!("Failed to parse DB constraints: {}", e),
})?;
Ok(PermissionConstraints::Database(constraints))
}
ResourceType::Fs => {
let constraints: FsConstraints = serde_json::from_str(json)
.map_err(|e| DatabaseError::SerializationError {
reason: format!("Failed to parse FS constraints: {}", e),
})?;
Ok(PermissionConstraints::Filesystem(constraints))
}
ResourceType::Http => {
let constraints: HttpConstraints = serde_json::from_str(json)
.map_err(|e| DatabaseError::SerializationError {
reason: format!("Failed to parse HTTP constraints: {}", e),
})?;
Ok(PermissionConstraints::Http(constraints))
}
ResourceType::Shell => {
let constraints: ShellConstraints = serde_json::from_str(json)
.map_err(|e| DatabaseError::SerializationError {
reason: format!("Failed to parse Shell constraints: {}", e),
})?;
Ok(PermissionConstraints::Shell(constraints))
}
}
}
fn matches_path_pattern(pattern: &str, path: &str) -> bool {
if pattern.ends_with("/*") {
let prefix = &pattern[..pattern.len() - 2];
@ -557,7 +420,7 @@ impl PermissionManager {
}
// Convenience-Funktionen für die verschiedenen Subsysteme
impl PermissionManager {
/* impl PermissionManager {
// Convenience-Methoden
pub async fn can_read_file(
app_state: &State<'_, AppState>,
@ -647,4 +510,4 @@ impl PermissionManager {
.filter(|perm| perm.status == PermissionStatus::Ask)
.collect())
}
}
} */

View File

@ -1,6 +1,12 @@
use serde::{Deserialize, Serialize};
// src-tauri/src/extension/permissions/types.rs
use crate::database::error::DatabaseError;
use std::str::FromStr;
use crate::{
database::{error::DatabaseError, generated::HaexExtensionPermissions},
extension::permissions::manager::PermissionManager,
};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ExtensionPermission {
@ -20,6 +26,52 @@ pub struct ExtensionPermission {
pub haex_timestamp: Option<String>,
}
impl From<HaexExtensionPermissions> for ExtensionPermission {
fn from(db_perm: HaexExtensionPermissions) -> Self {
let resource_type = ResourceType::from_str(&db_perm.resource_type.unwrap_or_default())
.unwrap_or(ResourceType::Db); // Fallback
let constraints = db_perm
.constraints
.and_then(|json_str| parse_constraints(&resource_type, &json_str).ok());
ExtensionPermission {
id: db_perm.id,
extension_id: db_perm.extension_id.unwrap_or_default(),
resource_type,
action: Action::from_str(&db_perm.action.unwrap_or_default()).unwrap_or(Action::Read),
target: db_perm.target.unwrap_or_default(),
status: PermissionStatus::from_str(&db_perm.status).unwrap_or(PermissionStatus::Ask),
constraints,
haex_timestamp: db_perm.haex_timestamp,
haex_tombstone: db_perm.haex_tombstone,
}
}
}
impl From<&ExtensionPermission> for HaexExtensionPermissions {
fn from(perm: &ExtensionPermission) -> Self {
let constraints_json = perm
.constraints
.as_ref()
.and_then(|c| serde_json::to_string(c).ok());
HaexExtensionPermissions {
id: perm.id.clone(),
extension_id: Some(perm.extension_id.clone()),
resource_type: Some(format!("{:?}", perm.resource_type).to_lowercase()),
action: Some(format!("{:?}", perm.action).to_lowercase()),
target: Some(perm.target.clone()),
constraints: constraints_json,
status: perm.status.as_str().to_string(),
created_at: None, // Wird von der DB gesetzt
updated_at: None, // Wird von der DB gesetzt
haex_timestamp: perm.haex_timestamp.clone(),
haex_tombstone: perm.haex_tombstone,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ResourceType {
@ -29,13 +81,43 @@ pub enum ResourceType {
Shell,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
impl FromStr for ResourceType {
type Err = DatabaseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"fs" => Ok(ResourceType::Fs),
"http" => Ok(ResourceType::Http),
"db" => Ok(ResourceType::Db),
"shell" => Ok(ResourceType::Shell),
_ => Err(DatabaseError::SerializationError {
reason: format!("Unbekannter Ressourcentyp: {}", s),
}),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Action {
Read,
Write,
}
impl FromStr for Action {
type Err = DatabaseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"read" => Ok(Action::Read),
"write" => Ok(Action::Write),
_ => Err(DatabaseError::SerializationError {
reason: format!("Unbekannte Aktion: {}", s),
}),
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum PermissionStatus {
@ -125,7 +207,7 @@ pub struct EditablePermissions {
}
// Oder gruppiert nach Typ:
impl EditablePermissions {
/* impl EditablePermissions {
pub fn database_permissions(&self) -> Vec<&ExtensionPermission> {
self.permissions
.iter()
@ -153,4 +235,40 @@ impl EditablePermissions {
.filter(|p| p.resource_type == ResourceType::Shell)
.collect()
}
} */
pub fn parse_constraints(
resource_type: &ResourceType,
json: &str,
) -> Result<PermissionConstraints, DatabaseError> {
match resource_type {
ResourceType::Db => {
let constraints: DbConstraints =
serde_json::from_str(json).map_err(|e| DatabaseError::SerializationError {
reason: format!("Failed to parse DB constraints: {}", e),
})?;
Ok(PermissionConstraints::Database(constraints))
}
ResourceType::Fs => {
let constraints: FsConstraints =
serde_json::from_str(json).map_err(|e| DatabaseError::SerializationError {
reason: format!("Failed to parse FS constraints: {}", e),
})?;
Ok(PermissionConstraints::Filesystem(constraints))
}
ResourceType::Http => {
let constraints: HttpConstraints =
serde_json::from_str(json).map_err(|e| DatabaseError::SerializationError {
reason: format!("Failed to parse HTTP constraints: {}", e),
})?;
Ok(PermissionConstraints::Http(constraints))
}
ResourceType::Shell => {
let constraints: ShellConstraints =
serde_json::from_str(json).map_err(|e| DatabaseError::SerializationError {
reason: format!("Failed to parse Shell constraints: {}", e),
})?;
Ok(PermissionConstraints::Shell(constraints))
}
}
}

View File

@ -1,107 +0,0 @@
// src-tauri/src/models.rs
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::time::{Duration, SystemTime};
use thiserror::Error;
/* #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ExtensionManifest {
pub id: String,
pub name: String,
pub version: String,
pub author: Option<String>,
pub entry: String,
pub icon: Option<String>,
pub permissions: ExtensionPermissions,
pub homepage: Option<String>,
pub description: Option<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ExtensionPermissions {
pub database: Option<DatabasePermissions>,
pub http: Option<Vec<String>>,
pub filesystem: Option<String>,
}
/// Enum to represent the source of an extension
#[derive(Debug, Clone)]
pub enum ExtensionSource {
/// Production extension installed in app data
Production { path: PathBuf, version: String },
/// Development mode extension with live reloading
Development {
dev_server_url: String,
manifest_path: PathBuf,
auto_reload: bool,
},
} */
/*
#[derive(Default)]
pub struct ExtensionState {
pub extensions: Mutex<std::collections::HashMap<String, ExtensionManifest>>,
}
impl ExtensionState {
pub fn add_extension(&self, path: String, manifest: ExtensionManifest) {
let mut extensions = self.extensions.lock().unwrap();
extensions.insert(path, manifest);
}
pub fn get_extension(&self, addon_id: &str) -> Option<ExtensionManifest> {
let extensions = self.extensions.lock().unwrap();
extensions.values().find(|p| p.name == addon_id).cloned()
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DbExtensionPermission {
pub id: String,
pub extension_id: String,
pub resource: String,
pub operation: String,
pub path: String,
}
/// Comprehensive error type for all extension-related operations
#[derive(Error, Debug)]
pub enum ExtensionError {
/// Security violation detected
#[error("Security violation: {reason}")]
SecurityViolation { reason: String },
/// Extension not found
#[error("Extension not found: {id}")]
NotFound { id: String },
/// Permission denied
#[error("Permission denied: {extension_id} cannot {operation} on {resource}")]
PermissionDenied {
extension_id: String,
operation: String,
resource: String,
},
/// IO error during extension operations
#[error("IO error: {source}")]
Io {
#[from]
source: std::io::Error,
},
/// Error during extension manifest parsing
#[error("Manifest error: {reason}")]
ManifestError { reason: String },
/// Input validation error
#[error("Validation error: {reason}")]
ValidationError { reason: String },
/// Development server error
#[error("Dev server error: {reason}")]
DevServerError { reason: String },
}
*/

View File

@ -1,34 +0,0 @@
// models.rs
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_path_pattern() {
// Valid patterns
assert!(validate_path_pattern("$PICTURE/**").is_ok());
assert!(validate_path_pattern("$DOCUMENT/myfiles/*").is_ok());
assert!(validate_path_pattern("$APPDATA/extensions/my-ext/**").is_ok());
// Invalid patterns
assert!(validate_path_pattern("").is_err());
assert!(validate_path_pattern("$INVALID/test").is_err());
assert!(validate_path_pattern("$PICTURE/../secret").is_err());
assert!(validate_path_pattern("relative/path").is_err());
}
#[test]
fn test_filesystem_permissions() {
let mut perms = FilesystemPermissions::new();
perms.add_read("$PICTURE/**");
perms.add_write("$APPDATA/my-ext/**");
assert!(perms.validate().is_ok());
assert_eq!(perms.read.as_ref().unwrap().len(), 1);
assert_eq!(perms.write.as_ref().unwrap().len(), 1);
}
}

View File

@ -1,441 +0,0 @@
// models.rs
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::{Mutex, Arc};
use std::time::{Duration, SystemTime};
use thiserror::Error;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ExtensionManifest {
pub id: String,
pub name: String,
pub version: String,
pub author: Option<String>,
pub entry: String,
pub icon: Option<String>,
pub permissions: ExtensionPermissions,
pub homepage: Option<String>,
pub description: Option<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ExtensionPermissions {
pub database: Option<DatabasePermissions>,
pub http: Option<Vec<String>>,
pub filesystem: Option<FilesystemPermissions>,
pub shell: Option<Vec<String>>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct DatabasePermissions {
pub read: Option<Vec<String>>,
pub write: Option<Vec<String>>,
pub create: Option<Vec<String>>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct FilesystemPermissions {
/// Read access to files and directories
pub read: Option<Vec<FilesystemPath>>,
/// Write access to files and directories (includes create/delete)
pub write: Option<Vec<FilesystemPath>>,
}
/// Cross-platform filesystem path specification
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct FilesystemPath {
/// The type of path (determines base directory)
pub path_type: FilesystemPathType,
/// Relative path from the base directory
pub relative_path: String,
/// Whether subdirectories are included (recursive)
pub recursive: bool,
}
/// Platform-agnostic path types that map to appropriate directories on each OS
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum FilesystemPathType {
/// App's data directory ($APPDATA on Windows, ~/.local/share on Linux, etc.)
AppData,
/// App's cache directory
AppCache,
/// App's configuration directory
AppConfig,
/// User's documents directory
Documents,
/// User's pictures directory
Pictures,
/// User's downloads directory
Downloads,
/// Temporary directory
Temp,
/// Extension's own private directory (always allowed)
ExtensionData,
/// Shared data between extensions (requires special permission)
SharedData,
}
impl FilesystemPath {
/// Creates a new filesystem path specification
pub fn new(path_type: FilesystemPathType, relative_path: &str, recursive: bool) -> Self {
Self {
path_type,
relative_path: relative_path.to_string(),
recursive,
}
}
/// Resolves the path to an actual system path
/// This would be implemented in your Tauri backend
pub fn resolve_system_path(&self, app_handle: &tauri::AppHandle) -> Result<std::path::PathBuf, ExtensionError> {
let base_dir = match self.path_type {
FilesystemPathType::AppData => app_handle.path().app_data_dir(),
FilesystemPathType::AppCache => app_handle.path().app_cache_dir(),
FilesystemPathType::AppConfig => app_handle.path().app_config_dir(),
FilesystemPathType::Documents => app_handle.path().document_dir(),
FilesystemPathType::Pictures => app_handle.path().picture_dir(),
FilesystemPathType::Downloads => app_handle.path().download_dir(),
FilesystemPathType::Temp => app_handle.path().temp_dir(),
FilesystemPathType::ExtensionData => {
app_handle.path().app_data_dir().map(|p| p.join("extensions"))
},
FilesystemPathType::SharedData => {
app_handle.path().app_data_dir().map(|p| p.join("shared"))
},
}.map_err(|e| ExtensionError::ValidationError {
reason: format!("Failed to resolve base directory: {}", e),
})?;
let final_path = base_dir.join(&self.relative_path);
// Security check - ensure the resolved path is still within the base directory
if let (Ok(canonical_final), Ok(canonical_base)) = (final_path.canonicalize(), base_dir.canonicalize()) {
if !canonical_final.starts_with(&canonical_base) {
return Err(ExtensionError::SecurityViolation {
reason: format!("Path traversal detected: {} escapes base directory", self.relative_path),
});
}
}
Ok(final_path)
}
}
/// Enum to represent the source of an extension
#[derive(Debug, Clone)]
pub enum ExtensionSource {
/// Production extension installed in app data
Production {
path: PathBuf,
version: String,
},
/// Development mode extension with live reloading
Development {
dev_server_url: String,
manifest_path: PathBuf,
auto_reload: bool,
},
}
/// Complete extension data including source and runtime status
#[derive(Debug, Clone)]
pub struct Extension {
/// Unique extension ID
pub id: String,
/// Extension display name
pub name: String,
/// Source information (production or dev)
pub source: ExtensionSource,
/// Complete manifest data
pub manifest: ExtensionManifest,
/// Enabled status
pub enabled: bool,
/// Last access timestamp
pub last_accessed: SystemTime,
}
/// Cached permission data to avoid frequent database lookups
#[derive(Debug, Clone)]
pub struct CachedPermission {
/// The permissions that were fetched
pub permissions: Vec<DbExtensionPermission>,
/// When this cache entry was created
pub cached_at: SystemTime,
/// How long this cache entry is valid
pub ttl: Duration,
}
/// Enhanced extension manager with production/dev support and caching
#[derive(Default)]
pub struct ExtensionManager {
/// Production extensions loaded from app data directory
pub production_extensions: Mutex<HashMap<String, Extension>>,
/// Development mode extensions for live-reloading during development
pub dev_extensions: Mutex<HashMap<String, Extension>>,
/// Cache for extension permissions to improve performance
pub permission_cache: Mutex<HashMap<String, CachedPermission>>,
}
impl ExtensionManager {
/// Creates a new extension manager
pub fn new() -> Self {
Self {
production_extensions: Mutex::new(HashMap::new()),
dev_extensions: Mutex::new(HashMap::new()),
permission_cache: Mutex::new(HashMap::new()),
}
}
/// Adds a production extension to the manager
pub fn add_production_extension(&self, extension: Extension) -> Result<(), ExtensionError> {
if extension.id.is_empty() {
return Err(ExtensionError::ValidationError {
reason: "Extension ID cannot be empty".to_string(),
});
}
match &extension.source {
ExtensionSource::Production { .. } => {
let mut extensions = self.production_extensions.lock().unwrap();
extensions.insert(extension.id.clone(), extension);
Ok(())
},
_ => Err(ExtensionError::ValidationError {
reason: "Expected Production source for production extension".to_string(),
})
}
}
/// Adds a development mode extension to the manager
pub fn add_dev_extension(&self, extension: Extension) -> Result<(), ExtensionError> {
if extension.id.is_empty() {
return Err(ExtensionError::ValidationError {
reason: "Extension ID cannot be empty".to_string(),
});
}
match &extension.source {
ExtensionSource::Development { .. } => {
let mut extensions = self.dev_extensions.lock().unwrap();
extensions.insert(extension.id.clone(), extension);
Ok(())
},
_ => Err(ExtensionError::ValidationError {
reason: "Expected Development source for dev extension".to_string(),
})
}
}
/// Gets an extension by its ID
pub fn get_extension(&self, extension_id: &str) -> Option<Extension> {
// First check development extensions (they take priority)
let dev_extensions = self.dev_extensions.lock().unwrap();
if let Some(extension) = dev_extensions.get(extension_id) {
return Some(extension.clone());
}
// Then check production extensions
let prod_extensions = self.production_extensions.lock().unwrap();
prod_extensions.get(extension_id).cloned()
}
/// Removes an extension from the manager
pub fn remove_extension(&self, extension_id: &str) -> Result<(), ExtensionError> {
// Check dev extensions first
{
let mut dev_extensions = self.dev_extensions.lock().unwrap();
if dev_extensions.remove(extension_id).is_some() {
return Ok(());
}
}
// Then check production extensions
{
let mut prod_extensions = self.production_extensions.lock().unwrap();
if prod_extensions.remove(extension_id).is_some() {
return Ok(());
}
}
Err(ExtensionError::NotFound {
id: extension_id.to_string(),
})
}
/// Gets cached permissions or indicates they need to be loaded
pub fn get_cached_permissions(
&self,
extension_id: &str,
resource: &str,
operation: &str,
) -> Option<Vec<DbExtensionPermission>> {
let cache = self.permission_cache.lock().unwrap();
let cache_key = format!("{}-{}-{}", extension_id, resource, operation);
if let Some(cached) = cache.get(&cache_key) {
let now = SystemTime::now();
if now.duration_since(cached.cached_at).unwrap_or(Duration::from_secs(0)) < cached.ttl {
return Some(cached.permissions.clone());
}
}
None
}
/// Updates the permission cache
pub fn update_permission_cache(
&self,
extension_id: &str,
resource: &str,
operation: &str,
permissions: Vec<DbExtensionPermission>,
) {
let mut cache = self.permission_cache.lock().unwrap();
let cache_key = format!("{}-{}-{}", extension_id, resource, operation);
cache.insert(cache_key, CachedPermission {
permissions,
cached_at: SystemTime::now(),
ttl: Duration::from_secs(60), // Cache for 60 seconds
});
}
/// Validates a manifest for security concerns
pub fn validate_manifest_security(&self, manifest: &ExtensionManifest) -> Result<(), ExtensionError> {
// Check for suspicious permission combinations
let has_filesystem = manifest.permissions.filesystem.is_some();
let has_database = manifest.permissions.database.is_some();
let has_shell = manifest.permissions.shell.is_some();
if has_filesystem && has_database && has_shell {
// This is a powerful combination, warn or check user confirmation elsewhere
}
// Validate ID format
if !manifest.id.chars().all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_') {
return Err(ExtensionError::ValidationError {
reason: "Invalid extension ID format. Must contain only alphanumeric characters, dash or underscore.".to_string()
});
}
Ok(())
}
/// Lists all enabled extensions (both dev and production)
pub fn list_enabled_extensions(&self) -> Vec<Extension> {
let mut extensions = Vec::new();
// Add enabled dev extensions first (higher priority)
{
let dev_extensions = self.dev_extensions.lock().unwrap();
extensions.extend(
dev_extensions
.values()
.filter(|ext| ext.enabled)
.cloned()
);
}
// Add enabled production extensions (avoiding duplicates)
{
let prod_extensions = self.production_extensions.lock().unwrap();
let dev_ids: std::collections::HashSet<String> = extensions.iter().map(|e| e.id.clone()).collect();
extensions.extend(
prod_extensions
.values()
.filter(|ext| ext.enabled && !dev_ids.contains(&ext.id))
.cloned()
);
}
extensions
}
}
// For backward compatibility - will be deprecated
#[derive(Default)]
pub struct ExtensionState {
pub extensions: Mutex<HashMap<String, ExtensionManifest>>,
}
impl ExtensionState {
pub fn add_extension(&self, path: String, manifest: ExtensionManifest) {
let mut extensions = self.extensions.lock().unwrap();
extensions.insert(path, manifest);
}
pub fn get_extension(&self, addon_id: &str) -> Option<ExtensionManifest> {
let extensions = self.extensions.lock().unwrap();
extensions.values().find(|p| p.name == addon_id).cloned()
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct DbExtensionPermission {
pub id: String,
pub extension_id: String,
pub resource: String,
pub operation: String,
pub path: String,
}
/// Comprehensive error type for all extension-related operations
#[derive(Error, Debug)]
pub enum ExtensionError {
/// Security violation detected
#[error("Security violation: {reason}")]
SecurityViolation {
reason: String
},
/// Extension not found
#[error("Extension not found: {id}")]
NotFound {
id: String
},
/// Permission denied
#[error("Permission denied: {extension_id} cannot {operation} on {resource}")]
PermissionDenied {
extension_id: String,
operation: String,
resource: String
},
/// IO error during extension operations
#[error("IO error: {source}")]
Io {
#[from]
source: std::io::Error
},
/// Error during extension manifest parsing
#[error("Manifest error: {reason}")]
ManifestError {
reason: String
},
/// Input validation error
#[error("Validation error: {reason}")]
ValidationError {
reason: String
},
/// Development server error
#[error("Dev server error: {reason}")]
DevServerError {
reason: String
},
}
// For Tauri Command Serialization
impl serde::Serialize for ExtensionError {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}

View File

@ -66,9 +66,6 @@
</template>
<script setup lang="ts">
import { join } from '@tauri-apps/api/path'
import { open } from '@tauri-apps/plugin-dialog'
import { readTextFile } from '@tauri-apps/plugin-fs'
import type {
IHaexHubExtension,
IHaexHubExtensionManifest,

View File

@ -2,7 +2,7 @@
import { drizzle } from 'drizzle-orm/sqlite-proxy'
import { invoke } from '@tauri-apps/api/core'
import * as schema from '@/../src-tauri/database/schemas/vault'
import { schema } from '@/../src-tauri/database/index'
import type { SqliteRemoteDatabase } from 'drizzle-orm/sqlite-proxy'
interface IVault {

View File

@ -1,6 +1,6 @@
import { and, eq } from 'drizzle-orm'
import { z } from 'zod'
import * as schema from '@/../src-tauri/database/schemas/vault'
import * as schema from '@/../src-tauri/database/schemas/haex'
import type { Locale } from 'vue-i18n'
export enum VaultSettingsTypeEnum {
@ -148,7 +148,7 @@ export const useVaultSettingsStore = defineStore('vaultSettingsStore', () => {
}
return currentVault?.drizzle?.insert(schema.haexSettings).values({
id: crypto.randomUUID(),
//id: crypto.randomUUID(),
type: VaultSettingsTypeEnum.deviceName,
key: deviceId,
value: deviceName,