mirror of
https://github.com/haexhub/haex-hub.git
synced 2025-12-18 23:10:51 +01:00
Compare commits
107 Commits
d5670ca470
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 3897a33565 | |||
| 7487696af4 | |||
| c1ee8e6bc0 | |||
| 2202415441 | |||
| 9583e2f44b | |||
| d886fbd8bd | |||
| 9bad4008f2 | |||
| 203f81e775 | |||
| 554cb7762d | |||
| 5856a73e5b | |||
| 38cc6f36d4 | |||
| 0d4059e518 | |||
| c551641737 | |||
| 75093485bd | |||
| e1be08cb76 | |||
| 7d1f346c4b | |||
| af61972342 | |||
| 6187e32f89 | |||
| 43ba246174 | |||
| 2b739b9e79 | |||
| 63849d86e1 | |||
| 9adee46166 | |||
| be7dff72dd | |||
| b465c117b0 | |||
| 731ae7cc47 | |||
| 26ec4e2a89 | |||
| 279468eddc | |||
| cffb129e4f | |||
| 405cf25aab | |||
| b097bf211d | |||
| c71b8468df | |||
| 3a4f482021 | |||
| 88507410ed | |||
| f38cecc84b | |||
| 931d51a1e1 | |||
| c97afdee18 | |||
| 65d2770df3 | |||
| a52e1b43fa | |||
| 6ceb22f014 | |||
| 4833dee89a | |||
| a80c783576 | |||
| 4e1e4ae601 | |||
| 6a7f58a513 | |||
| 3ed8d6bc05 | |||
| 81a72da26c | |||
| 4fa3515e32 | |||
| c5c30fd4c4 | |||
| 8c7a02a019 | |||
| 465fe19542 | |||
| d2d0f8996b | |||
| f727d00639 | |||
| a946b14f69 | |||
| 471baec284 | |||
| 8298d807f3 | |||
| 42e6459fbf | |||
| 6ae87fc694 | |||
| f7867a5bde | |||
| d82599f588 | |||
| 72bb211a76 | |||
| f14ce0d6ad | |||
| af09f4524d | |||
| 102832675d | |||
| 3490de2f51 | |||
| 7c3af10938 | |||
| 5c5d0785b9 | |||
| 121dd9dd00 | |||
| 4ff6aee4d8 | |||
| dceb49ae90 | |||
| 5ea04a80e0 | |||
| 65cf2e2c3c | |||
| 68d542b4d7 | |||
| f97cd4ad97 | |||
| ef225b281f | |||
| 16b71d9ea8 | |||
| 5ee5ced8c0 | |||
| 86b65f117d | |||
| 5fdea155d1 | |||
| cb0c8d71f4 | |||
| 9281a85deb | |||
| 8f8bbb5558 | |||
| 252b8711de | |||
| 4f839aa856 | |||
| 99ccadce00 | |||
| 922ae539ba | |||
| 3d020e7dcf | |||
| f70e924cc3 | |||
| 9ea057e943 | |||
| e268947593 | |||
| df97a3cb8b | |||
| 57fb496fca | |||
| 2b8f1781f3 | |||
| a291619f63 | |||
| 033c9135c6 | |||
| 5d6acfef93 | |||
| f006927d1a | |||
| fa3348a5ad | |||
| c8c3a5c73f | |||
| 225835e5d1 | |||
| fc841f238b | |||
| fb577a8699 | |||
| 56e75977cd | |||
| f1daa6b576 | |||
| c7d29cb2be | |||
| b36b4e4280 | |||
| d025819888 | |||
| 2cfd6248bc | |||
| 1a40f9d2aa |
228
.github/workflows/build.yml
vendored
Normal file
228
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
name: Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- develop
|
||||||
|
tags-ignore:
|
||||||
|
- '**'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- develop
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-desktop:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- platform: 'macos-latest'
|
||||||
|
args: '--target aarch64-apple-darwin'
|
||||||
|
- platform: 'macos-latest'
|
||||||
|
args: '--target x86_64-apple-darwin'
|
||||||
|
- platform: 'ubuntu-22.04'
|
||||||
|
args: ''
|
||||||
|
- platform: 'windows-latest'
|
||||||
|
args: ''
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.platform }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
|
- name: Setup Rust
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
|
||||||
|
|
||||||
|
- name: Install dependencies (Ubuntu)
|
||||||
|
if: matrix.platform == 'ubuntu-22.04'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libssl-dev
|
||||||
|
|
||||||
|
- name: Get pnpm store directory
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Setup pnpm cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ${{ env.STORE_PATH }}
|
||||||
|
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pnpm-store-
|
||||||
|
|
||||||
|
- name: Setup Rust cache
|
||||||
|
uses: Swatinem/rust-cache@v2
|
||||||
|
with:
|
||||||
|
workspaces: src-tauri
|
||||||
|
|
||||||
|
- name: Install frontend dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Build Tauri app
|
||||||
|
uses: tauri-apps/tauri-action@v0
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
args: ${{ matrix.args }}
|
||||||
|
|
||||||
|
- name: Upload artifacts (macOS)
|
||||||
|
if: matrix.platform == 'macos-latest'
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: macos-${{ contains(matrix.args, 'aarch64') && 'aarch64' || 'x86_64' }}
|
||||||
|
path: |
|
||||||
|
src-tauri/target/*/release/bundle/dmg/*.dmg
|
||||||
|
src-tauri/target/*/release/bundle/macos/*.app
|
||||||
|
|
||||||
|
- name: Upload artifacts (Ubuntu)
|
||||||
|
if: matrix.platform == 'ubuntu-22.04'
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: linux
|
||||||
|
path: |
|
||||||
|
src-tauri/target/release/bundle/deb/*.deb
|
||||||
|
src-tauri/target/release/bundle/appimage/*.AppImage
|
||||||
|
src-tauri/target/release/bundle/rpm/*.rpm
|
||||||
|
|
||||||
|
- name: Upload artifacts (Windows)
|
||||||
|
if: matrix.platform == 'windows-latest'
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: windows
|
||||||
|
path: |
|
||||||
|
src-tauri/target/release/bundle/msi/*.msi
|
||||||
|
src-tauri/target/release/bundle/nsis/*.exe
|
||||||
|
|
||||||
|
build-android:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: '17'
|
||||||
|
|
||||||
|
- name: Setup Android SDK
|
||||||
|
uses: android-actions/setup-android@v3
|
||||||
|
|
||||||
|
- name: Setup Rust
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
|
- name: Install Rust Android targets
|
||||||
|
run: |
|
||||||
|
rustup target add aarch64-linux-android
|
||||||
|
rustup target add armv7-linux-androideabi
|
||||||
|
rustup target add i686-linux-android
|
||||||
|
rustup target add x86_64-linux-android
|
||||||
|
|
||||||
|
- name: Setup NDK
|
||||||
|
uses: nttld/setup-ndk@v1
|
||||||
|
with:
|
||||||
|
ndk-version: r26d
|
||||||
|
id: setup-ndk
|
||||||
|
|
||||||
|
- name: Setup Android NDK environment for OpenSSL
|
||||||
|
run: |
|
||||||
|
echo "ANDROID_NDK_HOME=${{ steps.setup-ndk.outputs.ndk-path }}" >> $GITHUB_ENV
|
||||||
|
echo "NDK_HOME=${{ steps.setup-ndk.outputs.ndk-path }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# Add all Android toolchains to PATH for OpenSSL cross-compilation
|
||||||
|
echo "${{ steps.setup-ndk.outputs.ndk-path }}/toolchains/llvm/prebuilt/linux-x86_64/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
# Set CC, AR, RANLIB for each target
|
||||||
|
echo "CC_aarch64_linux_android=aarch64-linux-android24-clang" >> $GITHUB_ENV
|
||||||
|
echo "AR_aarch64_linux_android=llvm-ar" >> $GITHUB_ENV
|
||||||
|
echo "RANLIB_aarch64_linux_android=llvm-ranlib" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
echo "CC_armv7_linux_androideabi=armv7a-linux-androideabi24-clang" >> $GITHUB_ENV
|
||||||
|
echo "AR_armv7_linux_androideabi=llvm-ar" >> $GITHUB_ENV
|
||||||
|
echo "RANLIB_armv7_linux_androideabi=llvm-ranlib" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
echo "CC_i686_linux_android=i686-linux-android24-clang" >> $GITHUB_ENV
|
||||||
|
echo "AR_i686_linux_android=llvm-ar" >> $GITHUB_ENV
|
||||||
|
echo "RANLIB_i686_linux_android=llvm-ranlib" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
echo "CC_x86_64_linux_android=x86_64-linux-android24-clang" >> $GITHUB_ENV
|
||||||
|
echo "AR_x86_64_linux_android=llvm-ar" >> $GITHUB_ENV
|
||||||
|
echo "RANLIB_x86_64_linux_android=llvm-ranlib" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install build dependencies for OpenSSL
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y perl make
|
||||||
|
|
||||||
|
- name: Get pnpm store directory
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Setup pnpm cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ${{ env.STORE_PATH }}
|
||||||
|
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pnpm-store-
|
||||||
|
|
||||||
|
- name: Setup Rust cache
|
||||||
|
uses: Swatinem/rust-cache@v2
|
||||||
|
with:
|
||||||
|
workspaces: src-tauri
|
||||||
|
|
||||||
|
- name: Install frontend dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Setup Keystore (if secrets available)
|
||||||
|
env:
|
||||||
|
ANDROID_KEYSTORE: ${{ secrets.ANDROID_KEYSTORE }}
|
||||||
|
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
||||||
|
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
||||||
|
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
if [ -n "$ANDROID_KEYSTORE" ]; then
|
||||||
|
echo "$ANDROID_KEYSTORE" | base64 -d > $HOME/keystore.jks
|
||||||
|
echo "ANDROID_KEYSTORE_PATH=$HOME/keystore.jks" >> $GITHUB_ENV
|
||||||
|
echo "ANDROID_KEYSTORE_PASSWORD=$ANDROID_KEYSTORE_PASSWORD" >> $GITHUB_ENV
|
||||||
|
echo "ANDROID_KEY_ALIAS=$ANDROID_KEY_ALIAS" >> $GITHUB_ENV
|
||||||
|
echo "ANDROID_KEY_PASSWORD=$ANDROID_KEY_PASSWORD" >> $GITHUB_ENV
|
||||||
|
echo "Keystore configured for signing"
|
||||||
|
else
|
||||||
|
echo "No keystore configured, building unsigned APK"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build Android APK and AAB (unsigned if no keystore)
|
||||||
|
run: pnpm tauri android build
|
||||||
|
|
||||||
|
- name: Upload Android artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: android
|
||||||
|
path: |
|
||||||
|
src-tauri/gen/android/app/build/outputs/apk/**/*.apk
|
||||||
|
src-tauri/gen/android/app/build/outputs/bundle/**/*.aab
|
||||||
251
.github/workflows/release.yml
vendored
Normal file
251
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
create-release:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
outputs:
|
||||||
|
release_id: ${{ steps.create-release.outputs.release_id }}
|
||||||
|
upload_url: ${{ steps.create-release.outputs.upload_url }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Get version
|
||||||
|
run: echo "PACKAGE_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Create release
|
||||||
|
id: create-release
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const { data } = await github.rest.repos.createRelease({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
tag_name: `v${process.env.PACKAGE_VERSION}`,
|
||||||
|
name: `haex-hub v${process.env.PACKAGE_VERSION}`,
|
||||||
|
body: 'Take a look at the assets to download and install this app.',
|
||||||
|
draft: true,
|
||||||
|
prerelease: false
|
||||||
|
})
|
||||||
|
core.setOutput('release_id', data.id)
|
||||||
|
core.setOutput('upload_url', data.upload_url)
|
||||||
|
return data.id
|
||||||
|
|
||||||
|
build-desktop:
|
||||||
|
needs: create-release
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- platform: 'macos-latest'
|
||||||
|
args: '--target aarch64-apple-darwin'
|
||||||
|
- platform: 'macos-latest'
|
||||||
|
args: '--target x86_64-apple-darwin'
|
||||||
|
- platform: 'ubuntu-22.04'
|
||||||
|
args: ''
|
||||||
|
- platform: 'windows-latest'
|
||||||
|
args: ''
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.platform }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
|
- name: Setup Rust
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
|
||||||
|
|
||||||
|
- name: Install dependencies (Ubuntu)
|
||||||
|
if: matrix.platform == 'ubuntu-22.04'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libssl-dev
|
||||||
|
|
||||||
|
- name: Get pnpm store directory
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Setup pnpm cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ${{ env.STORE_PATH }}
|
||||||
|
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pnpm-store-
|
||||||
|
|
||||||
|
- name: Setup Rust cache
|
||||||
|
uses: Swatinem/rust-cache@v2
|
||||||
|
with:
|
||||||
|
workspaces: src-tauri
|
||||||
|
|
||||||
|
- name: Install frontend dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Build and release Tauri app
|
||||||
|
uses: tauri-apps/tauri-action@v0
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
releaseId: ${{ needs.create-release.outputs.release_id }}
|
||||||
|
args: ${{ matrix.args }}
|
||||||
|
|
||||||
|
build-android:
|
||||||
|
needs: create-release
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: '17'
|
||||||
|
|
||||||
|
- name: Setup Android SDK
|
||||||
|
uses: android-actions/setup-android@v3
|
||||||
|
|
||||||
|
- name: Setup Rust
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
|
- name: Install Rust Android targets
|
||||||
|
run: |
|
||||||
|
rustup target add aarch64-linux-android
|
||||||
|
rustup target add armv7-linux-androideabi
|
||||||
|
rustup target add i686-linux-android
|
||||||
|
rustup target add x86_64-linux-android
|
||||||
|
|
||||||
|
- name: Setup NDK
|
||||||
|
uses: nttld/setup-ndk@v1
|
||||||
|
with:
|
||||||
|
ndk-version: r26d
|
||||||
|
id: setup-ndk
|
||||||
|
|
||||||
|
- name: Setup Android NDK environment for OpenSSL
|
||||||
|
run: |
|
||||||
|
echo "ANDROID_NDK_HOME=${{ steps.setup-ndk.outputs.ndk-path }}" >> $GITHUB_ENV
|
||||||
|
echo "NDK_HOME=${{ steps.setup-ndk.outputs.ndk-path }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# Add all Android toolchains to PATH for OpenSSL cross-compilation
|
||||||
|
echo "${{ steps.setup-ndk.outputs.ndk-path }}/toolchains/llvm/prebuilt/linux-x86_64/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
# Set CC, AR, RANLIB for each target
|
||||||
|
echo "CC_aarch64_linux_android=aarch64-linux-android24-clang" >> $GITHUB_ENV
|
||||||
|
echo "AR_aarch64_linux_android=llvm-ar" >> $GITHUB_ENV
|
||||||
|
echo "RANLIB_aarch64_linux_android=llvm-ranlib" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
echo "CC_armv7_linux_androideabi=armv7a-linux-androideabi24-clang" >> $GITHUB_ENV
|
||||||
|
echo "AR_armv7_linux_androideabi=llvm-ar" >> $GITHUB_ENV
|
||||||
|
echo "RANLIB_armv7_linux_androideabi=llvm-ranlib" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
echo "CC_i686_linux_android=i686-linux-android24-clang" >> $GITHUB_ENV
|
||||||
|
echo "AR_i686_linux_android=llvm-ar" >> $GITHUB_ENV
|
||||||
|
echo "RANLIB_i686_linux_android=llvm-ranlib" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
echo "CC_x86_64_linux_android=x86_64-linux-android24-clang" >> $GITHUB_ENV
|
||||||
|
echo "AR_x86_64_linux_android=llvm-ar" >> $GITHUB_ENV
|
||||||
|
echo "RANLIB_x86_64_linux_android=llvm-ranlib" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install build dependencies for OpenSSL
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y perl make
|
||||||
|
|
||||||
|
- name: Get pnpm store directory
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Setup pnpm cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ${{ env.STORE_PATH }}
|
||||||
|
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pnpm-store-
|
||||||
|
|
||||||
|
- name: Setup Rust cache
|
||||||
|
uses: Swatinem/rust-cache@v2
|
||||||
|
with:
|
||||||
|
workspaces: src-tauri
|
||||||
|
|
||||||
|
- name: Install frontend dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Setup Keystore (required for release)
|
||||||
|
run: |
|
||||||
|
echo "${{ secrets.ANDROID_KEYSTORE }}" | base64 -d > $HOME/keystore.jks
|
||||||
|
echo "ANDROID_KEYSTORE_PATH=$HOME/keystore.jks" >> $GITHUB_ENV
|
||||||
|
echo "ANDROID_KEYSTORE_PASSWORD=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}" >> $GITHUB_ENV
|
||||||
|
echo "ANDROID_KEY_ALIAS=${{ secrets.ANDROID_KEY_ALIAS }}" >> $GITHUB_ENV
|
||||||
|
echo "ANDROID_KEY_PASSWORD=${{ secrets.ANDROID_KEY_PASSWORD }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build Android APK and AAB (signed)
|
||||||
|
run: pnpm tauri android build
|
||||||
|
|
||||||
|
- name: Upload Android artifacts to Release
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
gh release upload ${{ github.ref_name }} \
|
||||||
|
src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release.apk \
|
||||||
|
src-tauri/gen/android/app/build/outputs/bundle/universalRelease/app-universal-release.aab \
|
||||||
|
--clobber
|
||||||
|
|
||||||
|
publish-release:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
needs: [create-release, build-desktop, build-android]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Publish release
|
||||||
|
id: publish-release
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
env:
|
||||||
|
release_id: ${{ needs.create-release.outputs.release_id }}
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
github.rest.repos.updateRelease({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
release_id: process.env.release_id,
|
||||||
|
draft: false,
|
||||||
|
prerelease: false
|
||||||
|
})
|
||||||
7
.gitignore
vendored
7
.gitignore
vendored
@ -23,4 +23,9 @@ dist-ssr
|
|||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
.nuxt
|
.nuxt
|
||||||
src-tauri/target
|
src-tauri/target
|
||||||
|
nogit*
|
||||||
|
.claude
|
||||||
|
.output
|
||||||
|
target
|
||||||
|
CLAUDE.md
|
||||||
230
README.md
230
README.md
@ -1,82 +1,206 @@
|
|||||||
# HaexHub - The European "Everything App"
|
# 🧩 HaexHub – The European “Everything App”
|
||||||
|
|
||||||
## Vision
|
## 🌍 Vision
|
||||||
|
|
||||||
Today, we undoubtedly find ourselves in the computer age. Almost everyone owns at least one computer, often even more. Most probably have at least a smartphone and a standard PC. On each of these devices (Desktop PC, Laptop, Tablet, Smartphone) and systems (Windows, macOS, Linux (all flavors), Android, iOS), there are various programs and data, which can be highly individual and sensitive. Unfortunately, interoperability between these devices and systems often proves difficult, sometimes even impossible, for a multitude of reasons. On one hand, there are the system providers themselves (like Microsoft, Apple, Google), who often design their systems to make it as easy as possible for users to enter their ecosystems, but place many hurdles in the way when users wish to leave again. The golden cage, as we say in Germany, or walled garden. However, it's not just the system providers per se who make cross-device and cross-system work difficult. Another problem lies with the software manufacturers/providers. Since it is already challenging and above all resource-intensive (time, money, and technical know-how) to provide a good and "secure" product for one device class and/or system, it's not uncommon for a program to be developed (initially) for only one platform. So, there might be a program for Windows or Apple, but not for Linux, or only in one distribution/package format. Or there might be an app for iOS and/or Android, but not for the PC. This is partly due to the fact that it would simply be too complex to develop and, especially, maintain a product for multiple systems and devices (simultaneously). This effort is almost insurmountable, particularly for startups, small businesses, and individual open-source developers working on their passion projects in their spare time.
|
We are living in the **computer age** — nearly everyone owns multiple devices: a smartphone, a laptop, perhaps even a desktop PC or tablet.
|
||||||
Let's not even start talking about application distribution. For each platform, you end up with a separate build pipeline that builds, tests, signs, packages the application into the appropriate format (msi, exe, deb, flatpak, snap, AppImage, Apk, etc.), and delivers it to the corresponding store (AppStore, PlayStore, Windows Store, and the various repositories of Linux distributions). This is a huge cascade of tasks that especially causes problems for small companies (at least if you want to serve ALL platforms simultaneously).
|
Each of these runs its own **operating system** — Windows, macOS, Linux, Android, iOS — and hosts a unique mix of **apps and data**.
|
||||||
Wouldn't it be nice if there were a simple(r) way for developers to develop and build their application just once and then be able to serve ALL\* devices and systems? PWAs were already on the right track, but there is often a lack of more in-depth access to system resources, such as file or console access.
|
|
||||||
HaexHub gives any web application/PWA superpowers.
|
|
||||||
Extensions can be used to add any functions to HaexHub, whereby almost any access to the underlying system is possible, provided that the necessary authorizations have been granted by the user beforehand.
|
|
||||||
|
|
||||||
\*In principle, the approach presented here allows an application to run on all devices and systems. However, some applications might still only be usable on certain devices or systems. For example, if an application absolutely requires an NFC device, which is typically not found on a desktop PC, then this application will probably only work on mobile devices. Or if an application requires system-specific interfaces or programs, such as the Registry on Windows or systemd on Linux, then this application will naturally only work where these dependencies are found. However, developers who create their applications without such dependencies can immediately serve all devices and systems.
|
Unfortunately, **interoperability** between these devices is often poor or even impossible.
|
||||||
|
The reasons are many:
|
||||||
|
|
||||||
## Enter HaexHub
|
- **Platform lock-in**: Vendors like Microsoft, Apple, or Google design systems that make it easy to _enter_ their ecosystem but difficult to _leave_.
|
||||||
|
- **Fragmented software development**: Developers face high technical and financial hurdles to support multiple platforms at once.
|
||||||
|
|
||||||
HaexHub provides a framework that makes it incredibly easy for the community and any developer to build extensions (web applications), which can then be easily integrated into HaexHub by users. Each extension is essentially a web application that can be loaded, executed, customized, and deleted at runtime. Each extension is confined within an IFrame, communicating with HaexHub via APIs using postMessage. HaexHub, in turn, checks these requests for the necessary permissions, executes or rejects the command, and returns a possible response to the caller – ideally, the correct result.
|
Creating and maintaining one secure, high-quality app for _all_ systems can be almost impossible — especially for small teams, startups, and indie developers.
|
||||||
Since these are purely web applications, they are initially subject to the same limitations as any other web application in any "normal" browser worldwide. Fun Fact: Extensions in HaexHub are even more restricted than that. While a "normal" web application can, for example, load additional resources (JavaScript, CSS, images, ads) (assuming CORS allows it), this is initially not possible with a HaexHub extension. Everything the extension needs to be able to do must be specified as a permission in a manifest and approved by the user before (potentially) dangerous actions are executed on the host. And loading external resources is already considered such a risk from Tauri's (and my) perspective, as it can severely compromise the user's privacy.
|
|
||||||
With the appropriate permissions, however, an extension can do almost anything possible on a computer. Thus, unlike a "normal" web application, an extension can directly access the host's file system, execute other applications and commands, make/manipulate/block web requests, or access the SQLite database. To use these interfaces, each extension must declare the corresponding permissions in a manifest, which must then be approved by the user. Otherwise, no access to the host system is possible. Extensions can be added and removed at runtime. Since the extension runs in an IFrame, it cannot cause much damage without the appropriate permissions. It would be a pure web application where routing within the application is possible (WebHistoryHash). However, as soon as it tries to load external resources, regardless of whether they are local from the host or from any server on the World Wide Web, the extension is on its own without permission.
|
|
||||||
Technically, for example, it would pose no problem to make the host system's shell available to extensions. This could give Visual Studio Code in the browser superpowers. While a web version of Visual Studio Code already exists, its usability is limited. For instance, it's not possible to directly access the shell or the file system, which significantly hinders file management. And since no commands or applications can be executed on the host, it's (unfortunately) practically useless for developers. Visual Studio Code as a HaexHub extension could be used like a native application. And thanks to HaexHub's permission concept, it can be controlled with fine granularity which extension is allowed to execute what and how, and what is not. An extension with such power over the host, which can be both advantageous and disadvantageous for the user, should naturally be handled with particular care. It would probably not be a good idea to grant this permission to any advertising and data tracking services.
|
|
||||||
|
|
||||||
The framework itself provides a platform that will be available on all common devices (Desktop PC, Laptop, Tablet, Smartphone) and systems (Windows, macOS, Linux (all flavors), Android, iOS). All extensions can then be used on all supported devices and systems (provided there are no dependencies in the extension that are only available on specific devices or systems, like NFC, Google Pay, etc.).
|
And then there’s **distribution**: each platform requires its own build, packaging, signing, and publishing process.
|
||||||
All user and extension data can be securely stored and used in the locally encrypted SQLite database. To enable comfortable use of the database across multiple devices and systems, there will be a synchronization server that allows the database to be synchronized conflict-free across devices and systems. This server can, of course, also be self-hosted, ensuring the user is never dependent on a single provider.
|
What if you could build your app **once** and deploy it **everywhere**?
|
||||||
Furthermore, the data can be encrypted beforehand, making it unreadable by third parties.
|
|
||||||
|
|
||||||
HaexHub is a cross-platform, local-first, open-source application that prioritizes user privacy, security, and digital sovereignty. The goal is for the user to have control over their data at all times and be able to independently decide what they want to disclose to whom. Additionally, they should be able to adjust this decision at any time.
|
> **HaexHub** makes that possible — giving every web app or PWA **superpowers**.
|
||||||
Through the possibility of extensions, HaexHub is also almost infinitely expandable. What Visual Studio Code is for text editors/IDEs, HaexHub will be for (web) applications and even has the potential to become the European counterpart to WeChat (the "everything app"). However, without a central authority controlling everything.
|
|
||||||
|
|
||||||
But first things first.
|
With HaexHub, developers can extend functionality via **extensions** that run securely inside the app, with carefully controlled permissions for accessing system features (files, shell, database, etc.).
|
||||||
|
|
||||||
## Technical Foundations
|
---
|
||||||
|
|
||||||
The technical foundation of the project is Tauri. This framework makes it possible to provide native applications for all common devices (Desktops, Laptops, Tablets, Smartphones) and systems (Windows, Linux, macOS, Android, iOS) with the same codebase. Tauri is comparable to Electron (the technical basis for Visual Studio Code, for example), but the applications created with it are significantly smaller because Tauri uses the native rendering engine of the respective platform (WebView2 (Windows), WKWebView (macOS), WebKitGTK (Linux)) and does not bundle a (customized Chromium) browser, as is the case with Electron. Furthermore, Tauri offers significant advantages over Electron in terms of security and resource efficiency. There is also a sophisticated permission system, which effectively shields the frontend from the host. All access to the host system is only possible with the appropriate permission. This permission concept is also used for the (HaexHub) extensions, thereby ensuring the security of third-party extensions as well.
|
## 🚀 Enter HaexHub
|
||||||
|
|
||||||
The project follows a strict local-first approach. This means that HaexHub can fundamentally be used without any form of online account or internet access. The extensions are also stored locally and can be used offline, provided, of course, that the extension itself can function without the internet. A messenger extension will likely make limited sense without internet access. An image viewer or text editor, however, should work fine without the internet.
|
HaexHub provides a **framework** for building and running modular, sandboxed **web extensions** — web apps that run in an isolated environment but can communicate securely with the host.
|
||||||
All user data can be persistently stored and used in a locally encrypted SQLite database, even across extensions, with the appropriate permissions, of course. Unlike many other applications that call themselves local-first, this project implements this approach more consistently. Most applications claiming to be local-first often aren't truly so. The data usually resides (unencrypted) on a backend server and is merely "cached" to varying degrees in the frontend. While this allows these applications to be used offline for a while, the usage is either restricted (read-only in Bitwarden, for example) or the persistence is temporary at best. Most approaches, like this project, use an SQLite (or similar) database in the frontend to achieve offline capability, but this is usually implemented in a browser via IndexedDB or OPFS. Examples include [powersync](https://www.powersync.com/) , [evolu](https://www.evolu.dev/), or [electricSql](https://electric-sql.com/). The problem here is that such persistence is never truly permanent, as the operating system and/or browser can decide when to free up storage. For instance, it's common for Apple to clear the storage of web applications that haven't been used for over a week. As long as the user's data is still present in the backend, this is only moderately tragic, as the "source of truth" residing there can be synchronized back to the frontend at any time. However, this always requires an online account and internet access. Furthermore, with these approaches, the user cannot simply copy their data onto a USB stick and take it with them to use on a completely different computer (perhaps where only intranet is available).
|
|
||||||
Moreover, all these approaches are subject to the limitations of the respective browser. The limitation on persistent storage is particularly noteworthy here. All browsers have strict limits, which is why this approach is not suitable for all requirements. Since HaexHub stores data not in the browser, but in a real SQLite database on the hard drive, it is only subject to the hardware limitations of the host system (or USB stick/storage medium).
|
|
||||||
|
|
||||||
With HaexHub, all user and extension data can be permanently stored in the local and encrypted database without requiring an online account. However, to make the user's data conveniently and securely available on multiple devices, there will be a synchronization service to synchronize the database state across the user's various devices and systems. The user can, of course, also host this service themselves on their (local) systems or servers. The database state is thus temporarily stored on a (third-party) server and can be synchronized from there with other instances of the local SQLite database. To further enhance data security, the user can also encrypt the data before sending it to the backend, making it unreadable by third parties. This will likely be enabled by default, but it can also be turned off, as there are legitimate use cases where it might be disadvantageous or undesirable. Particularly in corporate or government environments, it could be problematic if all user (employee) data were stored encrypted on the company servers. If the employee becomes unavailable (resignation, accident, death) and their database password (or the encryption key stored in the database) is unknown, there would be no way to access this data.
|
Each extension:
|
||||||
Since this use case should also be considered, backend encryption will be optional.
|
|
||||||
|
|
||||||
As HaexHub is ultimately a kind of distributed and federated system, there is no (single) authority that could control everything. Unless the user truly has only one instance of their database (perhaps on a USB stick) and always carries it with them. Part of HaexHub's charm, however, is that the user can have multiple instances of their SQLite database on multiple devices and systems without having to worry about how the correct data (source of truth) gets from A to B and B to A.
|
- Runs inside an **IFrame**.
|
||||||
To make this possible and to synchronize even conflicting data states of the SQLite database, HaexHub uses Conflict-free Replicated Data Types (CRDTs). This will make it possible to merge multiple conflicting data states, even if they are encrypted.
|
- Uses **postMessage APIs** to communicate with HaexHub.
|
||||||
|
- Declares required **permissions** in a manifest file.
|
||||||
|
- Can be added or removed at runtime.
|
||||||
|
|
||||||
## Extensions
|
Without explicit permission, extensions cannot access the file system, network, or external resources — ensuring **privacy and security** by default.
|
||||||
|
Once granted, however, extensions can unlock full desktop-like capabilities:
|
||||||
|
access files, execute commands, or interact with SQLite databases.
|
||||||
|
|
||||||
The real highlight of HaexHub, however, lies in its extensions. All end-user functionality will ultimately be provided through extensions. There will be (official/core) extensions and third-party extensions. One of the first (official) extensions will be a password manager, for example, but a file synchronization service is also planned.
|
Imagine a **web-based VS Code** that can directly access your local shell and file system — something that current web IDEs can’t do.
|
||||||
Each extension is essentially just a web application\* loaded into an IFrame. This keeps all extensions well isolated (sandboxed) from the main application (HaexHub) and the user's host system, ensuring the user's security and privacy. Of course, as with any application, a degree of trust must be placed in the extension developer that they are genuinely only doing what they claim to do. HaexHub is ingenious, but it can't perform magic.
|
With HaexHub’s permission model, such power is possible, but **always under user control**.
|
||||||
Each extension must declare the permissions it requires in a manifest, which must then be accepted by the user. This ensures that each extension can only access the resources (file system, web requests, database access, etc.) for which it has the appropriate permissions.
|
|
||||||
|
|
||||||
In principle, any (existing) web application could be integrated and run within HaexHub. Technically, each extension is just a web application, but with significantly more capabilities. Traditional web applications are restricted by the (justified) limitations of a browser. For example, a web application cannot simply access the host system's file system or manipulate network traffic. And for good reasons. With HaexHub, however, these limitations do not exist. A (HaexHub) extension can indeed access the file system if it has the corresponding permission. This opens up almost unlimited application possibilities, making the term "everything app" seem not so far-fetched. In a future iteration, a browser and later a payment option (GNU Taler?!) are planned to be added, so it could truly become a fully-fledged counterpart to WeChat. However, these aspects are not considered in the first iteration of the application.
|
HaexHub itself is **cross-platform** and runs on:
|
||||||
By providing extensions, HaexHub can truly be enhanced arbitrarily. Extension developers could use simple tools (Vite application) to immediately provide their functionality for all devices and systems and utilize the provided ecosystem, without the developer having to deal with the peculiarities of each system for development and distribution. (Provided, of course, they don't rely on dependencies that only exist on specific systems or devices).
|
|
||||||
Extensions can also access the data of other extensions (e.g., via the SQLite database) and build upon it (with appropriate permission, naturally).
|
|
||||||
I want to outline this with a concrete example. The first official extension will be a password manager.
|
|
||||||
This will be a Nuxt/Vue application. The password manager's manifest will request permission to create a few tables and to read from and write to them. The extension then provides a nice UI for creating and managing login credentials, similar to existing password managers. Each entry can also be tagged, which could later be used by other extensions.
|
|
||||||
For example, entries tagged "E-Mail" could be created, which could then be used by an email client extension to automatically connect to mail servers.
|
|
||||||
Any other extension could access specific entries in the password database (or other extensions' data) to easily provide its service.
|
|
||||||
But of course, each extension can also create its own tables as needed for its specific use case.
|
|
||||||
HaexHub takes care of secure storage and, if configured, conflict-free synchronization.
|
|
||||||
Each user can expand their HaexHub with the individual functionality they need. And since all settings for these extensions can be stored in the SQLite database, they can be easily and seamlessly synchronized and used across multiple devices. The user only needs to set up their extensions once on one device and can then use them on all other devices and systems without further action.
|
|
||||||
|
|
||||||
Another example of an extension would be file synchronization, which will also be a core extension.
|
- 💻 Windows, macOS, Linux
|
||||||
This extension allows users to easily synchronize their files across different devices and systems. It can be configured on each device which files and folders should be synchronized and how. For instance, one might want to upload pictures and videos from their smartphone to an S3 bucket/Google Drive/Dropbox and their desktop PC. However, one probably doesn't want all pictures from the S3 bucket/Google Drive/Dropbox/Desktop to be synchronized back to the smartphone. All these configurations will again be stored in the SQLite database and, where possible, synchronized across all devices and systems.
|
- 📱 Android, iOS
|
||||||
|
- 🧠 Desktops, laptops, tablets, smartphones
|
||||||
|
|
||||||
Further examples of extensions include calendars, (collaborative) document management, contacts, messengers, and in the distant future, a browser and payment service (GNU Taler perhaps?!).
|
All user and extension data is stored in a **locally encrypted SQLite database**.
|
||||||
|
To sync across devices, HaexHub can connect to a **synchronization server** — which you can even **self-host** for maximum independence.
|
||||||
|
|
||||||
\*Fundamentally, any bundler (Vite, Webpack, Rollup, etc.) and any frontend framework (Vue, React, Angular, Svelte, plain HTML) should be usable. The crucial part is that it's a JS bundle. However, initially, the focus will primarily be on Vite and Vue to demonstrate the general feasibility first.
|
> 🛡️ HaexHub is built on the principles of **privacy, security, and digital sovereignty**.
|
||||||
|
|
||||||
## Preperation
|
The user is always in control of their data — deciding what to share, and with whom.
|
||||||
|
|
||||||
install:
|
---
|
||||||
|
|
||||||
- [nodejs](https://nodejs.org/en/download)
|
## 🧠 Technical Foundations
|
||||||
- [tauri](https://v2.tauri.app/start/prerequisites/)
|
|
||||||
- [rust](https://v2.tauri.app/start/prerequisites/#rust)
|
|
||||||
|
|
||||||
- port 3003 needs to be open/free or you need to adjust it in `nuxt.config.ts` AND `src-tauri/tauri.conf.json`
|
HaexHub is powered by **[Tauri](https://v2.tauri.app/)** — a secure, efficient framework for building native apps from web technologies.
|
||||||
|
|
||||||
|
Unlike Electron (used by apps like VS Code), Tauri:
|
||||||
|
|
||||||
|
- Uses **native rendering engines** (WebView2, WKWebView, WebKitGTK)
|
||||||
|
- Produces **smaller, faster apps**
|
||||||
|
- Enforces **strong sandboxing and permission models**
|
||||||
|
|
||||||
|
HaexHub builds upon Tauri’s security features, extending them to third-party extensions.
|
||||||
|
|
||||||
|
### 🏡 Local-first by Design
|
||||||
|
|
||||||
|
HaexHub follows a **strict local-first architecture**:
|
||||||
|
|
||||||
|
- Works **offline** without accounts or internet.
|
||||||
|
- Stores data locally in **encrypted SQLite**.
|
||||||
|
- Uses **CRDTs (Conflict-free Replicated Data Types)** for safe synchronization across devices — even with encrypted data.
|
||||||
|
|
||||||
|
Unlike many “local-first” apps, HaexHub doesn’t just cache data in the browser.
|
||||||
|
Your data truly resides **on your disk**, not under a browser’s limited storage policy.
|
||||||
|
|
||||||
|
Optionally, HaexHub can sync databases via a backend service — self-hosted or external — with optional **end-to-end encryption**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 Extensions
|
||||||
|
|
||||||
|
Extensions are the heart of HaexHub.
|
||||||
|
|
||||||
|
Everything the user interacts with — from password management to file syncing — will be implemented as **extensions**.
|
||||||
|
|
||||||
|
There are two types:
|
||||||
|
|
||||||
|
- **Official/Core Extensions**
|
||||||
|
- **Third-Party Extensions**
|
||||||
|
|
||||||
|
Each extension is a **web app** bundled via your preferred frontend stack:
|
||||||
|
|
||||||
|
> Vue, React, Svelte, Angular, Vite, Webpack, Rollup — you name it.
|
||||||
|
|
||||||
|
### 🔐 Example: Password Manager
|
||||||
|
|
||||||
|
A first official extension will be a **Password Manager**, built with **Vue/Nuxt**:
|
||||||
|
|
||||||
|
- Declares database permissions via its manifest.
|
||||||
|
- Manages login credentials locally in encrypted SQLite.
|
||||||
|
- Can tag entries (e.g. “Email”) for use by other extensions — such as an email client.
|
||||||
|
|
||||||
|
### 🗂 Example: File Synchronization
|
||||||
|
|
||||||
|
Another planned core extension will handle **file synchronization**:
|
||||||
|
|
||||||
|
- Syncs files/folders between devices and cloud providers (e.g. S3, Google Drive, Dropbox).
|
||||||
|
- Lets users define sync rules per device.
|
||||||
|
- Stores configuration securely in the local database.
|
||||||
|
|
||||||
|
### 💬 Future Extensions
|
||||||
|
|
||||||
|
- Calendar & Contacts
|
||||||
|
- Collaborative document management
|
||||||
|
- Messenger
|
||||||
|
- Browser & Payment Services (e.g., GNU Taler integration)
|
||||||
|
|
||||||
|
With this modular design, HaexHub can evolve into a true **European alternative to WeChat** — but open, federated, and privacy-first.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧰 Installation & Setup
|
||||||
|
|
||||||
|
### 📦 Prerequisites
|
||||||
|
|
||||||
|
Install the following dependencies:
|
||||||
|
|
||||||
|
- [Node.js / nvm](https://nodejs.org/en/download)
|
||||||
|
- [Tauri](https://v2.tauri.app/start/prerequisites/)
|
||||||
|
- [Rust](https://v2.tauri.app/start/prerequisites/#rust)
|
||||||
|
- [Android Studio](https://developer.android.com/studio?hl=de)
|
||||||
|
- WebKit2GTK + GTK3
|
||||||
|
|
||||||
|
#### 🐧 Debian / Ubuntu
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install \
|
||||||
|
libwebkit2gtk-4.1-dev \
|
||||||
|
libgtk-3-dev \
|
||||||
|
libayatana-appindicator3-dev \
|
||||||
|
librsvg2-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 🦊 Fedora
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dnf install \
|
||||||
|
webkit2gtk4.1-devel \
|
||||||
|
gtk3-devel \
|
||||||
|
libappindicator-gtk3 \
|
||||||
|
librsvg2-devel
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ⚙️ Development
|
||||||
|
|
||||||
|
Make sure port 3003 is available (or adjust it in `nuxt.config.ts` and `src-tauri/tauri.conf.json`).
|
||||||
|
|
||||||
|
```bash
|
||||||
git clone https://github.com/haexhub/haex-vault.git
|
git clone https://github.com/haexhub/haex-vault.git
|
||||||
cd haex-vault
|
cd haex-vault
|
||||||
pnpm i
|
pnpm install
|
||||||
pnpm tauri dev
|
pnpm tauri dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 📦 Release Process
|
||||||
|
|
||||||
|
Create a new release using the automated scripts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Patch release (0.1.13 → 0.1.14)
|
||||||
|
pnpm release:patch
|
||||||
|
|
||||||
|
# Minor release (0.1.13 → 0.2.0)
|
||||||
|
pnpm release:minor
|
||||||
|
|
||||||
|
# Major release (0.1.13 → 1.0.0)
|
||||||
|
pnpm release:major
|
||||||
|
```
|
||||||
|
|
||||||
|
The script automatically:
|
||||||
|
1. Updates version in `package.json`
|
||||||
|
2. Creates a git commit
|
||||||
|
3. Creates a git tag
|
||||||
|
4. Pushes to remote
|
||||||
|
|
||||||
|
GitHub Actions will then automatically:
|
||||||
|
- Build desktop apps (macOS, Linux, Windows)
|
||||||
|
- Build Android apps (APK and AAB)
|
||||||
|
- Create and publish a GitHub release
|
||||||
|
|
||||||
|
#### 🧭 Summary
|
||||||
|
|
||||||
|
HaexHub aims to:
|
||||||
|
|
||||||
|
- Simplify cross-platform app development
|
||||||
|
- Empower users with local-first privacy
|
||||||
|
- Enable developers to create modular, permissioned extensions
|
||||||
|
- Bridge the gap between web and native worlds
|
||||||
|
|
||||||
|
HaexHub is the foundation for a decentralized, privacy-friendly, European “everything app.”
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { defineConfig } from 'drizzle-kit'
|
import { defineConfig } from 'drizzle-kit'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
schema: './src-tauri/database/schemas/**.ts',
|
schema: './src/database/schemas/**.ts',
|
||||||
out: './src-tauri/database/migrations',
|
out: './src-tauri/database/migrations',
|
||||||
dialect: 'sqlite',
|
dialect: 'sqlite',
|
||||||
dbCredentials: {
|
dbCredentials: {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import tailwindcss from '@tailwindcss/vite'
|
import { fileURLToPath } from 'node:url'
|
||||||
|
|
||||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
@ -7,7 +7,16 @@ export default defineNuxtConfig({
|
|||||||
|
|
||||||
srcDir: './src',
|
srcDir: './src',
|
||||||
|
|
||||||
|
alias: {
|
||||||
|
'@bindings': fileURLToPath(
|
||||||
|
new URL('./src-tauri/bindings', import.meta.url),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
app: {
|
app: {
|
||||||
|
head: {
|
||||||
|
viewport: 'width=device-width, initial-scale=1.0, viewport-fit=cover',
|
||||||
|
},
|
||||||
pageTransition: {
|
pageTransition: {
|
||||||
name: 'fade',
|
name: 'fade',
|
||||||
},
|
},
|
||||||
@ -20,7 +29,6 @@ export default defineNuxtConfig({
|
|||||||
'@vueuse/nuxt',
|
'@vueuse/nuxt',
|
||||||
'@nuxt/icon',
|
'@nuxt/icon',
|
||||||
'@nuxt/eslint',
|
'@nuxt/eslint',
|
||||||
//"@nuxt/image",
|
|
||||||
'@nuxt/fonts',
|
'@nuxt/fonts',
|
||||||
'@nuxt/ui',
|
'@nuxt/ui',
|
||||||
],
|
],
|
||||||
@ -33,6 +41,20 @@ export default defineNuxtConfig({
|
|||||||
'pages/**',
|
'pages/**',
|
||||||
'types/**',
|
'types/**',
|
||||||
],
|
],
|
||||||
|
presets: [
|
||||||
|
{
|
||||||
|
from: '@vueuse/gesture',
|
||||||
|
imports: [
|
||||||
|
'useDrag',
|
||||||
|
'useGesture',
|
||||||
|
'useHover',
|
||||||
|
'useMove',
|
||||||
|
'usePinch',
|
||||||
|
'useScroll',
|
||||||
|
'useWheel',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
css: ['./assets/css/main.css'],
|
css: ['./assets/css/main.css'],
|
||||||
@ -46,7 +68,7 @@ export default defineNuxtConfig({
|
|||||||
includeCustomCollections: true,
|
includeCustomCollections: true,
|
||||||
},
|
},
|
||||||
serverBundle: {
|
serverBundle: {
|
||||||
collections: ['mdi', 'line-md', 'solar', 'gg', 'emojione'],
|
collections: ['mdi', 'line-md', 'solar', 'gg', 'emojione', 'lucide', 'hugeicons'],
|
||||||
},
|
},
|
||||||
|
|
||||||
customCollections: [
|
customCollections: [
|
||||||
@ -72,6 +94,8 @@ export default defineNuxtConfig({
|
|||||||
redirectOn: 'root', // recommended
|
redirectOn: 'root', // recommended
|
||||||
},
|
},
|
||||||
types: 'composition',
|
types: 'composition',
|
||||||
|
|
||||||
|
vueI18n: './i18n.config.ts',
|
||||||
},
|
},
|
||||||
|
|
||||||
zodI18n: {
|
zodI18n: {
|
||||||
@ -84,8 +108,7 @@ export default defineNuxtConfig({
|
|||||||
runtimeConfig: {
|
runtimeConfig: {
|
||||||
public: {
|
public: {
|
||||||
haexVault: {
|
haexVault: {
|
||||||
lastVaultFileName: 'lastVaults.json',
|
deviceFileName: 'device.json',
|
||||||
instanceFileName: 'instance.json',
|
|
||||||
defaultVaultName: 'HaexHub',
|
defaultVaultName: 'HaexHub',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -99,7 +122,6 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
|
|
||||||
vite: {
|
vite: {
|
||||||
plugins: [tailwindcss()],
|
|
||||||
// Better support for Tauri CLI output
|
// Better support for Tauri CLI output
|
||||||
clearScreen: false,
|
clearScreen: false,
|
||||||
// Enable environment variables
|
// Enable environment variables
|
||||||
|
|||||||
88
package.json
88
package.json
@ -1,63 +1,73 @@
|
|||||||
{
|
{
|
||||||
"name": "tauri-app",
|
"name": "haex-hub",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.0",
|
"version": "0.1.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "nuxt build",
|
"build": "nuxt build",
|
||||||
"dev": "nuxt dev",
|
"dev": "nuxt dev",
|
||||||
"generate": "nuxt generate",
|
|
||||||
"preview": "nuxt preview",
|
|
||||||
"postinstall": "nuxt prepare",
|
|
||||||
"tauri": "tauri",
|
|
||||||
"tauri:build:debug": "tauri build --debug",
|
|
||||||
"drizzle:generate": "drizzle-kit generate",
|
"drizzle:generate": "drizzle-kit generate",
|
||||||
"drizzle:migrate": "drizzle-kit migrate",
|
"drizzle:migrate": "drizzle-kit migrate",
|
||||||
"eslint:fix": "eslint --fix"
|
"eslint:fix": "eslint --fix",
|
||||||
|
"generate:rust-types": "tsx ./src-tauri/database/generate-rust-types.ts",
|
||||||
|
"generate:ts-types": "cd src-tauri && cargo test",
|
||||||
|
"generate": "nuxt generate",
|
||||||
|
"postinstall": "nuxt prepare",
|
||||||
|
"preview": "nuxt preview",
|
||||||
|
"release:patch": "node scripts/release.js patch",
|
||||||
|
"release:minor": "node scripts/release.js minor",
|
||||||
|
"release:major": "node scripts/release.js major",
|
||||||
|
"tauri:build:debug": "tauri build --debug",
|
||||||
|
"tauri": "tauri"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@haexhub/sdk": "^1.9.10",
|
||||||
"@nuxt/eslint": "1.9.0",
|
"@nuxt/eslint": "1.9.0",
|
||||||
"@nuxt/fonts": "0.11.4",
|
"@nuxt/fonts": "0.11.4",
|
||||||
"@nuxt/icon": "2.0.0",
|
"@nuxt/icon": "2.0.0",
|
||||||
"@nuxt/ui": "^3.3.2",
|
"@nuxt/ui": "4.1.0",
|
||||||
"@nuxtjs/i18n": "10.0.6",
|
"@nuxtjs/i18n": "10.0.6",
|
||||||
"@pinia/nuxt": "^0.11.1",
|
"@pinia/nuxt": "^0.11.3",
|
||||||
"@tailwindcss/vite": "^4.1.10",
|
"@supabase/supabase-js": "^2.80.0",
|
||||||
"@tauri-apps/api": "^2.5.0",
|
"@tailwindcss/vite": "^4.1.17",
|
||||||
"@tauri-apps/plugin-dialog": "^2.2.2",
|
"@tauri-apps/api": "^2.9.0",
|
||||||
"@tauri-apps/plugin-fs": "^2.3.0",
|
"@tauri-apps/plugin-dialog": "^2.4.2",
|
||||||
"@tauri-apps/plugin-http": "2.5.2",
|
"@tauri-apps/plugin-fs": "^2.4.4",
|
||||||
"@tauri-apps/plugin-notification": "2.3.1",
|
"@tauri-apps/plugin-notification": "2.3.1",
|
||||||
"@tauri-apps/plugin-opener": "^2.3.0",
|
"@tauri-apps/plugin-opener": "^2.5.2",
|
||||||
"@tauri-apps/plugin-os": "^2.2.2",
|
"@tauri-apps/plugin-os": "^2.3.2",
|
||||||
"@tauri-apps/plugin-sql": "2.3.0",
|
"@tauri-apps/plugin-store": "^2.4.1",
|
||||||
"@tauri-apps/plugin-store": "^2.2.1",
|
|
||||||
"@vueuse/components": "^13.9.0",
|
"@vueuse/components": "^13.9.0",
|
||||||
"@vueuse/core": "^13.4.0",
|
"@vueuse/core": "^13.9.0",
|
||||||
"@vueuse/nuxt": "^13.4.0",
|
"@vueuse/gesture": "^2.0.0",
|
||||||
"drizzle-orm": "^0.44.2",
|
"@vueuse/nuxt": "^13.9.0",
|
||||||
"eslint": "^9.34.0",
|
"drizzle-orm": "^0.44.7",
|
||||||
"fuse.js": "^7.1.0",
|
"eslint": "^9.39.1",
|
||||||
"nuxt": "^4.0.3",
|
"nuxt-zod-i18n": "^1.12.1",
|
||||||
"nuxt-zod-i18n": "^1.12.0",
|
"swiper": "^12.0.3",
|
||||||
"tailwindcss": "^4.1.10",
|
"tailwindcss": "^4.1.17",
|
||||||
"vue": "^3.5.20",
|
"vue": "^3.5.24",
|
||||||
"vue-router": "^4.5.1",
|
"vue-router": "^4.6.3",
|
||||||
"zod": "4.1.5"
|
"zod": "^3.25.76"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify/json": "^2.2.351",
|
"@iconify-json/hugeicons": "^1.2.17",
|
||||||
"@iconify/tailwind4": "^1.0.6",
|
"@iconify-json/lucide": "^1.2.72",
|
||||||
|
"@iconify/json": "^2.2.404",
|
||||||
|
"@iconify/tailwind4": "^1.1.0",
|
||||||
"@libsql/client": "^0.15.15",
|
"@libsql/client": "^0.15.15",
|
||||||
"@tauri-apps/cli": "^2.5.0",
|
"@tauri-apps/cli": "^2.9.3",
|
||||||
|
"@types/node": "^24.10.0",
|
||||||
"@vitejs/plugin-vue": "6.0.1",
|
"@vitejs/plugin-vue": "6.0.1",
|
||||||
"@vue/compiler-sfc": "^3.5.17",
|
"@vue/compiler-sfc": "^3.5.24",
|
||||||
"drizzle-kit": "^0.31.2",
|
"drizzle-kit": "^0.31.6",
|
||||||
"globals": "^16.2.0",
|
"globals": "^16.5.0",
|
||||||
|
"nuxt": "^4.2.1",
|
||||||
"prettier": "3.6.2",
|
"prettier": "3.6.2",
|
||||||
"tw-animate-css": "^1.3.8",
|
"tsx": "^4.20.6",
|
||||||
"typescript": "^5.8.3",
|
"tw-animate-css": "^1.4.0",
|
||||||
"vite": "7.1.3",
|
"typescript": "^5.9.3",
|
||||||
|
"vite": "^7.2.2",
|
||||||
"vue-tsc": "3.0.6"
|
"vue-tsc": "3.0.6"
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
|
|||||||
5344
pnpm-lock.yaml
generated
5344
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
91
scripts/release.js
Executable file
91
scripts/release.js
Executable file
@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import { readFileSync, writeFileSync } from 'fs';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import { dirname, join } from 'path';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
const rootDir = join(__dirname, '..');
|
||||||
|
|
||||||
|
const versionType = process.argv[2];
|
||||||
|
|
||||||
|
if (!['patch', 'minor', 'major'].includes(versionType)) {
|
||||||
|
console.error('Usage: pnpm release <patch|minor|major>');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read current package.json
|
||||||
|
const packageJsonPath = join(rootDir, 'package.json');
|
||||||
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
||||||
|
const currentVersion = packageJson.version;
|
||||||
|
|
||||||
|
if (!currentVersion) {
|
||||||
|
console.error('No version found in package.json');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse version
|
||||||
|
const [major, minor, patch] = currentVersion.split('.').map(Number);
|
||||||
|
|
||||||
|
// Calculate new version
|
||||||
|
let newVersion;
|
||||||
|
switch (versionType) {
|
||||||
|
case 'major':
|
||||||
|
newVersion = `${major + 1}.0.0`;
|
||||||
|
break;
|
||||||
|
case 'minor':
|
||||||
|
newVersion = `${major}.${minor + 1}.0`;
|
||||||
|
break;
|
||||||
|
case 'patch':
|
||||||
|
newVersion = `${major}.${minor}.${patch + 1}`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`📦 Bumping version from ${currentVersion} to ${newVersion}`);
|
||||||
|
|
||||||
|
// Update package.json
|
||||||
|
packageJson.version = newVersion;
|
||||||
|
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
|
||||||
|
console.log('✅ Updated package.json');
|
||||||
|
|
||||||
|
// Git operations
|
||||||
|
try {
|
||||||
|
// Check if there are uncommitted changes
|
||||||
|
const status = execSync('git status --porcelain', { encoding: 'utf8' });
|
||||||
|
const hasOtherChanges = status
|
||||||
|
.split('\n')
|
||||||
|
.filter(line => line && !line.includes('package.json'))
|
||||||
|
.length > 0;
|
||||||
|
|
||||||
|
if (hasOtherChanges) {
|
||||||
|
console.error('❌ There are uncommitted changes besides package.json. Please commit or stash them first.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add and commit package.json
|
||||||
|
execSync('git add package.json', { stdio: 'inherit' });
|
||||||
|
execSync(`git commit -m "Bump version to ${newVersion}"`, { stdio: 'inherit' });
|
||||||
|
console.log('✅ Committed version bump');
|
||||||
|
|
||||||
|
// Create tag
|
||||||
|
execSync(`git tag v${newVersion}`, { stdio: 'inherit' });
|
||||||
|
console.log(`✅ Created tag v${newVersion}`);
|
||||||
|
|
||||||
|
// Push changes and tag
|
||||||
|
console.log('📤 Pushing to remote...');
|
||||||
|
execSync('git push', { stdio: 'inherit' });
|
||||||
|
execSync(`git push origin v${newVersion}`, { stdio: 'inherit' });
|
||||||
|
console.log('✅ Pushed changes and tag');
|
||||||
|
|
||||||
|
console.log('\n🎉 Release v' + newVersion + ' created successfully!');
|
||||||
|
console.log('📋 GitHub Actions will now build and publish the release.');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Git operation failed:', error.message);
|
||||||
|
// Rollback package.json changes
|
||||||
|
packageJson.version = currentVersion;
|
||||||
|
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
|
||||||
|
console.log('↩️ Rolled back package.json changes');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
1755
src-tauri/Cargo.lock
generated
1755
src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "haex-hub"
|
name = "haex-hub"
|
||||||
version = "0.1.0"
|
version = "0.1.4"
|
||||||
description = "A Tauri App"
|
description = "A Tauri App"
|
||||||
authors = ["you"]
|
authors = ["you"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@ -16,39 +16,42 @@ crate-type = ["staticlib", "cdylib", "rlib"]
|
|||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
serde_json = "1.0.145"
|
serde_json = "1.0.145"
|
||||||
|
|
||||||
tauri-build = { version = "2.2", features = [] }
|
tauri-build = { version = "2.2", features = [] }
|
||||||
serde = { version = "1.0.223", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
[dependencies]
|
|
||||||
rusqlite = { version = "0.37.0", features = [
|
|
||||||
"load_extension",
|
|
||||||
"bundled-sqlcipher-vendored-openssl",
|
|
||||||
"functions",
|
|
||||||
] }
|
|
||||||
#libsqlite3-sys = { version = "0.31", features = ["bundled-sqlcipher"] }
|
|
||||||
#sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "sqlite"] }
|
|
||||||
tokio = { version = "1.47.1", features = ["macros", "rt-multi-thread"] }
|
|
||||||
serde = { version = "1", features = ["derive"] }
|
|
||||||
hex = "0.4"
|
|
||||||
serde_json = "1.0.143"
|
|
||||||
base64 = "0.22"
|
|
||||||
mime_guess = "2.0"
|
|
||||||
mime = "0.3"
|
|
||||||
fs_extra = "1.3.0"
|
|
||||||
sqlparser = { version = "0.58.0", features = ["visitor"] }
|
|
||||||
uhlc = "0.8"
|
|
||||||
tauri = { version = "2.8.5", features = ["protocol-asset", "devtools"] }
|
|
||||||
tauri-plugin-dialog = "2.4.0"
|
|
||||||
tauri-plugin-fs = "2.4.0"
|
|
||||||
tauri-plugin-opener = "2.5.0"
|
|
||||||
tauri-plugin-os = "2.3"
|
|
||||||
tauri-plugin-store = "2.4.0"
|
|
||||||
tauri-plugin-http = "2.5.2"
|
|
||||||
tauri-plugin-notification = "2.3.1"
|
|
||||||
tauri-plugin-persisted-scope = "2.3.2"
|
|
||||||
tauri-plugin-android-fs = "12.0.1"
|
|
||||||
uuid = { version = "1.18.1", features = ["v4"] }
|
|
||||||
ts-rs = "11.0.1"
|
|
||||||
thiserror = "2.0.16"
|
|
||||||
|
|
||||||
#tauri-plugin-sql = { version = "2", features = ["sqlite"] }
|
[dependencies]
|
||||||
|
tokio = { version = "1.47.1", features = ["macros", "rt-multi-thread"] }
|
||||||
|
base64 = "0.22"
|
||||||
|
ed25519-dalek = "2.1"
|
||||||
|
fs_extra = "1.3.0"
|
||||||
|
hex = "0.4"
|
||||||
|
lazy_static = "1.5"
|
||||||
|
mime = "0.3"
|
||||||
|
mime_guess = "2.0"
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
serde_json = "1.0.143"
|
||||||
|
sha2 = "0.10.9"
|
||||||
|
sqlparser = { version = "0.59.0", features = ["visitor"] }
|
||||||
|
tauri = { version = "2.9.1", features = ["protocol-asset", "devtools"] }
|
||||||
|
tauri-plugin-dialog = "2.4.2"
|
||||||
|
tauri-plugin-fs = "2.4.0"
|
||||||
|
tauri-plugin-http = "2.5.4"
|
||||||
|
tauri-plugin-notification = "2.3.3"
|
||||||
|
tauri-plugin-opener = "2.5.2"
|
||||||
|
tauri-plugin-os = "2.3.2"
|
||||||
|
tauri-plugin-persisted-scope = "2.3.4"
|
||||||
|
tauri-plugin-store = "2.4.1"
|
||||||
|
thiserror = "2.0.17"
|
||||||
|
ts-rs = { version = "11.1.0", features = ["serde-compat"] }
|
||||||
|
uhlc = "0.8.2"
|
||||||
|
url = "2.5.7"
|
||||||
|
uuid = { version = "1.18.1", features = ["v4"] }
|
||||||
|
zip = "6.0.0"
|
||||||
|
rusqlite = { version = "0.37.0", features = [
|
||||||
|
"load_extension",
|
||||||
|
"bundled-sqlcipher-vendored-openssl",
|
||||||
|
"functions",
|
||||||
|
] }
|
||||||
|
|
||||||
|
[target.'cfg(not(target_os = "android"))'.dependencies]
|
||||||
|
trash = "5.2.5"
|
||||||
|
|||||||
10
src-tauri/bindings/Action.ts
Normal file
10
src-tauri/bindings/Action.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { DbAction } from "./DbAction";
|
||||||
|
import type { FsAction } from "./FsAction";
|
||||||
|
import type { ShellAction } from "./ShellAction";
|
||||||
|
import type { WebAction } from "./WebAction";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ein typsicherer Container, der die spezifische Aktion für einen Ressourcentyp enthält.
|
||||||
|
*/
|
||||||
|
export type Action = { "Database": DbAction } | { "Filesystem": FsAction } | { "Web": WebAction } | { "Shell": ShellAction };
|
||||||
3
src-tauri/bindings/DatabaseError.ts
Normal file
3
src-tauri/bindings/DatabaseError.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type DatabaseError = { "type": "ParseError", "details": { reason: string, sql: string, } } | { "type": "ParameterMismatchError", "details": { expected: number, provided: number, sql: string, } } | { "type": "NoTableError", "details": { sql: string, } } | { "type": "StatementError", "details": { reason: string, } } | { "type": "PrepareError", "details": { reason: string, } } | { "type": "DatabaseError", "details": { reason: string, } } | { "type": "ExecutionError", "details": { sql: string, reason: string, table: string | null, } } | { "type": "TransactionError", "details": { reason: string, } } | { "type": "UnsupportedStatement", "details": { reason: string, sql: string, } } | { "type": "HlcError", "details": { reason: string, } } | { "type": "LockError", "details": { reason: string, } } | { "type": "ConnectionError", "details": { reason: string, } } | { "type": "SerializationError", "details": { reason: string, } } | { "type": "PermissionError", "details": { extension_id: string, operation: string | null, resource: string | null, reason: string, } } | { "type": "QueryError", "details": { reason: string, } } | { "type": "RowProcessingError", "details": { reason: string, } } | { "type": "MutexPoisoned", "details": { reason: string, } } | { "type": "ConnectionFailed", "details": { path: string, reason: string, } } | { "type": "PragmaError", "details": { pragma: string, reason: string, } } | { "type": "PathResolutionError", "details": { reason: string, } } | { "type": "IoError", "details": { path: string, reason: string, } } | { "type": "CrdtSetup", "details": string };
|
||||||
6
src-tauri/bindings/DbAction.ts
Normal file
6
src-tauri/bindings/DbAction.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Definiert Aktionen, die auf eine Datenbank angewendet werden können.
|
||||||
|
*/
|
||||||
|
export type DbAction = "read" | "readWrite" | "create" | "delete" | "alterDrop";
|
||||||
3
src-tauri/bindings/DbConstraints.ts
Normal file
3
src-tauri/bindings/DbConstraints.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type DbConstraints = { where_clause: string | null, columns: Array<string> | null, limit: number | null, };
|
||||||
3
src-tauri/bindings/DisplayMode.ts
Normal file
3
src-tauri/bindings/DisplayMode.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type DisplayMode = "auto" | "window" | "iframe";
|
||||||
6
src-tauri/bindings/ExtensionErrorCode.ts
Normal file
6
src-tauri/bindings/ExtensionErrorCode.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error codes for frontend handling
|
||||||
|
*/
|
||||||
|
export type ExtensionErrorCode = "SecurityViolation" | "NotFound" | "PermissionDenied" | "MutexPoisoned" | "Database" | "Filesystem" | "FilesystemWithPath" | "Http" | "Web" | "Shell" | "Manifest" | "Validation" | "InvalidPublicKey" | "InvalidSignature" | "InvalidActionString" | "SignatureVerificationFailed" | "CalculateHash" | "Installation";
|
||||||
4
src-tauri/bindings/ExtensionInfoResponse.ts
Normal file
4
src-tauri/bindings/ExtensionInfoResponse.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { DisplayMode } from "./DisplayMode";
|
||||||
|
|
||||||
|
export type ExtensionInfoResponse = { id: string, publicKey: string, name: string, version: string, author: string | null, enabled: boolean, description: string | null, homepage: string | null, icon: string | null, entry: string | null, singleInstance: boolean | null, displayMode: DisplayMode | null, devServerUrl: string | null, };
|
||||||
5
src-tauri/bindings/ExtensionManifest.ts
Normal file
5
src-tauri/bindings/ExtensionManifest.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { DisplayMode } from "./DisplayMode";
|
||||||
|
import type { ExtensionPermissions } from "./ExtensionPermissions";
|
||||||
|
|
||||||
|
export type ExtensionManifest = { name: string, version: string, author: string | null, entry: string | null, icon: string | null, public_key: string, signature: string, permissions: ExtensionPermissions, homepage: string | null, description: string | null, single_instance: boolean | null, display_mode: DisplayMode | null, };
|
||||||
7
src-tauri/bindings/ExtensionPermissions.ts
Normal file
7
src-tauri/bindings/ExtensionPermissions.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { PermissionEntry } from "./PermissionEntry";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Definiert die einheitliche Struktur für alle Berechtigungsarten im Manifest und UI.
|
||||||
|
*/
|
||||||
|
export type ExtensionPermissions = { database: Array<PermissionEntry> | null, filesystem: Array<PermissionEntry> | null, http: Array<PermissionEntry> | null, shell: Array<PermissionEntry> | null, };
|
||||||
5
src-tauri/bindings/ExtensionPreview.ts
Normal file
5
src-tauri/bindings/ExtensionPreview.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { ExtensionManifest } from "./ExtensionManifest";
|
||||||
|
import type { ExtensionPermissions } from "./ExtensionPermissions";
|
||||||
|
|
||||||
|
export type ExtensionPreview = { manifest: ExtensionManifest, is_valid_signature: boolean, editable_permissions: ExtensionPermissions, };
|
||||||
6
src-tauri/bindings/FsAction.ts
Normal file
6
src-tauri/bindings/FsAction.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Definiert Aktionen, die auf das Dateisystem angewendet werden können.
|
||||||
|
*/
|
||||||
|
export type FsAction = "read" | "readWrite";
|
||||||
3
src-tauri/bindings/FsConstraints.ts
Normal file
3
src-tauri/bindings/FsConstraints.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type FsConstraints = { max_file_size: bigint | null, allowed_extensions: Array<string> | null, recursive: boolean | null, };
|
||||||
6
src-tauri/bindings/HttpAction.ts
Normal file
6
src-tauri/bindings/HttpAction.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Definiert Aktionen (HTTP-Methoden), die auf HTTP-Anfragen angewendet werden können.
|
||||||
|
*/
|
||||||
|
export type HttpAction = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "*";
|
||||||
4
src-tauri/bindings/HttpConstraints.ts
Normal file
4
src-tauri/bindings/HttpConstraints.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { RateLimit } from "./RateLimit";
|
||||||
|
|
||||||
|
export type HttpConstraints = { methods: Array<string> | null, rate_limit: RateLimit | null, };
|
||||||
7
src-tauri/bindings/PermissionConstraints.ts
Normal file
7
src-tauri/bindings/PermissionConstraints.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { DbConstraints } from "./DbConstraints";
|
||||||
|
import type { FsConstraints } from "./FsConstraints";
|
||||||
|
import type { ShellConstraints } from "./ShellConstraints";
|
||||||
|
import type { WebConstraints } from "./WebConstraints";
|
||||||
|
|
||||||
|
export type PermissionConstraints = DbConstraints | FsConstraints | WebConstraints | ShellConstraints;
|
||||||
19
src-tauri/bindings/PermissionEntry.ts
Normal file
19
src-tauri/bindings/PermissionEntry.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { PermissionStatus } from "./PermissionStatus";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repräsentiert einen einzelnen Berechtigungseintrag im Manifest und im UI-Modell.
|
||||||
|
*/
|
||||||
|
export type PermissionEntry = { target: string,
|
||||||
|
/**
|
||||||
|
* Die auszuführende Aktion (z.B. "read", "read_write", "GET", "execute").
|
||||||
|
*/
|
||||||
|
operation?: string | null,
|
||||||
|
/**
|
||||||
|
* Optionale, spezifische Einschränkungen für diese Berechtigung.
|
||||||
|
*/
|
||||||
|
constraints?: Record<string, unknown>,
|
||||||
|
/**
|
||||||
|
* Der Status der Berechtigung (wird nur im UI-Modell verwendet).
|
||||||
|
*/
|
||||||
|
status?: PermissionStatus | null, };
|
||||||
3
src-tauri/bindings/PermissionStatus.ts
Normal file
3
src-tauri/bindings/PermissionStatus.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type PermissionStatus = "ask" | "granted" | "denied";
|
||||||
3
src-tauri/bindings/RateLimit.ts
Normal file
3
src-tauri/bindings/RateLimit.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type RateLimit = { requests: number, per_minutes: number, };
|
||||||
3
src-tauri/bindings/ResourceType.ts
Normal file
3
src-tauri/bindings/ResourceType.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type ResourceType = "fs" | "web" | "db" | "shell";
|
||||||
6
src-tauri/bindings/SerializedExtensionError.ts
Normal file
6
src-tauri/bindings/SerializedExtensionError.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialized representation of ExtensionError for TypeScript
|
||||||
|
*/
|
||||||
|
export type SerializedExtensionError = { code: number, type: string, message: string, extension_id: string | null, };
|
||||||
6
src-tauri/bindings/ShellAction.ts
Normal file
6
src-tauri/bindings/ShellAction.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Definiert Aktionen, die auf Shell-Befehle angewendet werden können.
|
||||||
|
*/
|
||||||
|
export type ShellAction = "execute";
|
||||||
3
src-tauri/bindings/ShellConstraints.ts
Normal file
3
src-tauri/bindings/ShellConstraints.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type ShellConstraints = { allowed_subcommands: Array<string> | null, allowed_flags: Array<string> | null, forbidden_args: Array<string> | null, };
|
||||||
3
src-tauri/bindings/TriggerSetupResult.ts
Normal file
3
src-tauri/bindings/TriggerSetupResult.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type TriggerSetupResult = "Success" | "TableNotFound";
|
||||||
3
src-tauri/bindings/VaultInfo.ts
Normal file
3
src-tauri/bindings/VaultInfo.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type VaultInfo = { name: string, lastAccess: bigint, path: string, };
|
||||||
6
src-tauri/bindings/WebAction.ts
Normal file
6
src-tauri/bindings/WebAction.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Definiert Aktionen (HTTP-Methoden), die auf Web-Anfragen angewendet werden können.
|
||||||
|
*/
|
||||||
|
export type WebAction = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "*";
|
||||||
4
src-tauri/bindings/WebConstraints.ts
Normal file
4
src-tauri/bindings/WebConstraints.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { RateLimit } from "./RateLimit";
|
||||||
|
|
||||||
|
export type WebConstraints = { methods: Array<string> | null, rate_limit: RateLimit | null, };
|
||||||
@ -1,106 +1,8 @@
|
|||||||
use serde::Deserialize;
|
mod generator;
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Pfad zur Eingabe-JSON und zur Ausgabe-Rust-Datei festlegen.
|
generator::event_names::generate_event_names();
|
||||||
// `OUT_DIR` ist ein spezielles Verzeichnis, das Cargo für generierte Dateien bereitstellt.
|
generator::table_names::generate_table_names();
|
||||||
let schema_path = Path::new("database/tableNames.json");
|
generator::rust_types::generate_rust_types();
|
||||||
let out_dir =
|
tauri_build::build();
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,17 +18,27 @@
|
|||||||
"fs:allow-appconfig-write-recursive",
|
"fs:allow-appconfig-write-recursive",
|
||||||
"fs:allow-appdata-read-recursive",
|
"fs:allow-appdata-read-recursive",
|
||||||
"fs:allow-appdata-write-recursive",
|
"fs:allow-appdata-write-recursive",
|
||||||
|
"fs:allow-applocaldata-read-recursive",
|
||||||
|
"fs:allow-applocaldata-write-recursive",
|
||||||
"fs:allow-read-file",
|
"fs:allow-read-file",
|
||||||
|
"fs:allow-write-file",
|
||||||
"fs:allow-read-dir",
|
"fs:allow-read-dir",
|
||||||
|
"fs:allow-mkdir",
|
||||||
|
"fs:allow-exists",
|
||||||
|
"fs:allow-remove",
|
||||||
"fs:allow-resource-read-recursive",
|
"fs:allow-resource-read-recursive",
|
||||||
"fs:allow-resource-write-recursive",
|
"fs:allow-resource-write-recursive",
|
||||||
"fs:allow-download-read-recursive",
|
"fs:allow-download-read-recursive",
|
||||||
"fs:allow-download-write-recursive",
|
"fs:allow-download-write-recursive",
|
||||||
|
"fs:allow-temp-read-recursive",
|
||||||
|
"fs:allow-temp-write-recursive",
|
||||||
"fs:default",
|
"fs:default",
|
||||||
"android-fs:default",
|
|
||||||
{
|
{
|
||||||
"identifier": "fs:scope",
|
"identifier": "fs:scope",
|
||||||
"allow": [{ "path": "**" }]
|
"allow": [
|
||||||
|
{ "path": "**" },
|
||||||
|
{ "path": "$TEMP/**" }
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"http:allow-fetch-send",
|
"http:allow-fetch-send",
|
||||||
"http:allow-fetch",
|
"http:allow-fetch",
|
||||||
@ -36,8 +46,15 @@
|
|||||||
"notification:allow-create-channel",
|
"notification:allow-create-channel",
|
||||||
"notification:allow-list-channels",
|
"notification:allow-list-channels",
|
||||||
"notification:allow-notify",
|
"notification:allow-notify",
|
||||||
|
"notification:allow-is-permission-granted",
|
||||||
"notification:default",
|
"notification:default",
|
||||||
"opener:allow-open-url",
|
"opener:allow-open-url",
|
||||||
|
{
|
||||||
|
"identifier": "opener:allow-open-path",
|
||||||
|
"allow": [
|
||||||
|
{ "path": "$TEMP/**" }
|
||||||
|
]
|
||||||
|
},
|
||||||
"opener:default",
|
"opener:default",
|
||||||
"os:allow-hostname",
|
"os:allow-hostname",
|
||||||
"os:default",
|
"os:default",
|
||||||
|
|||||||
16
src-tauri/capabilities/extensions.json
Normal file
16
src-tauri/capabilities/extensions.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"$schema": "../gen/schemas/desktop-schema.json",
|
||||||
|
"identifier": "extensions",
|
||||||
|
"description": "Minimal capability for extension webviews - extensions have NO direct system access",
|
||||||
|
"local": true,
|
||||||
|
"webviews": ["ext_*"],
|
||||||
|
"permissions": [
|
||||||
|
"core:default",
|
||||||
|
"core:webview:default",
|
||||||
|
"notification:default",
|
||||||
|
"notification:allow-is-permission-granted"
|
||||||
|
],
|
||||||
|
"remote": {
|
||||||
|
"urls": ["http://localhost:*", "haex-extension://*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
200
src-tauri/database/generate-rust-types.ts
Normal file
200
src-tauri/database/generate-rust-types.ts
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
import { writeFileSync, mkdirSync } from 'node:fs'
|
||||||
|
import { join, dirname } from 'node:path'
|
||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
|
import tablesNames from '../../src/database/tableNames.json'
|
||||||
|
import { schema } from '../../src/database/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 },
|
||||||
|
{
|
||||||
|
name: tablesNames.haex.desktop_items.name,
|
||||||
|
table: schema.haexDesktopItems,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: tablesNames.haex.workspaces.name,
|
||||||
|
table: schema.haexWorkspaces,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
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()
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { drizzle } from 'drizzle-orm/sqlite-proxy' // Adapter für Query Building ohne direkte Verbindung
|
|
||||||
import * as schema from './schemas/vault' // Importiere alles aus deiner Schema-Datei
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
const dummyExecutor = async (
|
|
||||||
sql: string,
|
|
||||||
params: unknown[],
|
|
||||||
method: 'all' | 'run' | 'get' | 'values',
|
|
||||||
) => {
|
|
||||||
console.warn(
|
|
||||||
`Frontend Drizzle Executor wurde aufgerufen (Methode: ${method}). Das sollte im Tauri-Invoke-Workflow nicht passieren!`,
|
|
||||||
)
|
|
||||||
// Wir geben leere Ergebnisse zurück, um die Typen zufriedenzustellen, falls es doch aufgerufen wird.
|
|
||||||
return { rows: [] } // Für 'run' (z.B. bei INSERT/UPDATE)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Erstelle die Drizzle-Instanz für den SQLite-Dialekt
|
|
||||||
// Übergib den dummyExecutor und das importierte Schema
|
|
||||||
export const db = drizzle(dummyExecutor, { schema })
|
|
||||||
|
|
||||||
// Exportiere auch alle Schema-Definitionen weiter, damit man alles aus einer Datei importieren kann
|
|
||||||
105
src-tauri/database/migrations/0000_cynical_nicolaos.sql
Normal file
105
src-tauri/database/migrations/0000_cynical_nicolaos.sql
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
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_desktop_items` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`workspace_id` text NOT NULL,
|
||||||
|
`item_type` text NOT NULL,
|
||||||
|
`extension_id` text,
|
||||||
|
`system_window_id` text,
|
||||||
|
`position_x` integer DEFAULT 0 NOT NULL,
|
||||||
|
`position_y` integer DEFAULT 0 NOT NULL,
|
||||||
|
`haex_timestamp` text,
|
||||||
|
FOREIGN KEY (`workspace_id`) REFERENCES `haex_workspaces`(`id`) ON UPDATE no action ON DELETE cascade,
|
||||||
|
FOREIGN KEY (`extension_id`) REFERENCES `haex_extensions`(`id`) ON UPDATE no action ON DELETE cascade,
|
||||||
|
CONSTRAINT "item_reference" CHECK(("haex_desktop_items"."item_type" = 'extension' AND "haex_desktop_items"."extension_id" IS NOT NULL AND "haex_desktop_items"."system_window_id" IS NULL) OR ("haex_desktop_items"."item_type" = 'system' AND "haex_desktop_items"."system_window_id" IS NOT NULL AND "haex_desktop_items"."extension_id" IS NULL) OR ("haex_desktop_items"."item_type" = 'file' AND "haex_desktop_items"."system_window_id" IS NOT NULL AND "haex_desktop_items"."extension_id" IS NULL) OR ("haex_desktop_items"."item_type" = 'folder' AND "haex_desktop_items"."system_window_id" IS NOT NULL AND "haex_desktop_items"."extension_id" IS NULL))
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `haex_extension_permissions` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`extension_id` text NOT NULL,
|
||||||
|
`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_timestamp` text,
|
||||||
|
FOREIGN KEY (`extension_id`) REFERENCES `haex_extensions`(`id`) ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
--> 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,
|
||||||
|
`public_key` text NOT NULL,
|
||||||
|
`name` text NOT NULL,
|
||||||
|
`version` text NOT NULL,
|
||||||
|
`author` text,
|
||||||
|
`description` text,
|
||||||
|
`entry` text DEFAULT 'index.html',
|
||||||
|
`homepage` text,
|
||||||
|
`enabled` integer DEFAULT true,
|
||||||
|
`icon` text,
|
||||||
|
`signature` text NOT NULL,
|
||||||
|
`single_instance` integer DEFAULT false,
|
||||||
|
`haex_timestamp` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `haex_extensions_public_key_name_unique` ON `haex_extensions` (`public_key`,`name`);--> 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_timestamp` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `haex_settings` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`key` text,
|
||||||
|
`type` text,
|
||||||
|
`value` text,
|
||||||
|
`haex_timestamp` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `haex_settings_key_type_value_unique` ON `haex_settings` (`key`,`type`,`value`);--> statement-breakpoint
|
||||||
|
CREATE TABLE `haex_workspaces` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`device_id` text NOT NULL,
|
||||||
|
`name` text NOT NULL,
|
||||||
|
`position` integer DEFAULT 0 NOT NULL,
|
||||||
|
`background` blob,
|
||||||
|
`haex_timestamp` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `haex_workspaces_position_unique` ON `haex_workspaces` (`position`);
|
||||||
@ -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
|
|
||||||
);
|
|
||||||
15
src-tauri/database/migrations/0001_furry_brother_voodoo.sql
Normal file
15
src-tauri/database/migrations/0001_furry_brother_voodoo.sql
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
PRAGMA foreign_keys=OFF;--> statement-breakpoint
|
||||||
|
CREATE TABLE `__new_haex_workspaces` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`device_id` text NOT NULL,
|
||||||
|
`name` text NOT NULL,
|
||||||
|
`position` integer DEFAULT 0 NOT NULL,
|
||||||
|
`background` text,
|
||||||
|
`haex_timestamp` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
INSERT INTO `__new_haex_workspaces`("id", "device_id", "name", "position", "background", "haex_timestamp") SELECT "id", "device_id", "name", "position", "background", "haex_timestamp" FROM `haex_workspaces`;--> statement-breakpoint
|
||||||
|
DROP TABLE `haex_workspaces`;--> statement-breakpoint
|
||||||
|
ALTER TABLE `__new_haex_workspaces` RENAME TO `haex_workspaces`;--> statement-breakpoint
|
||||||
|
PRAGMA foreign_keys=ON;--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `haex_workspaces_position_unique` ON `haex_workspaces` (`position`);
|
||||||
@ -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;
|
|
||||||
13
src-tauri/database/migrations/0002_loose_quasimodo.sql
Normal file
13
src-tauri/database/migrations/0002_loose_quasimodo.sql
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
CREATE TABLE `haex_devices` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`device_id` text NOT NULL,
|
||||||
|
`name` text NOT NULL,
|
||||||
|
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
|
||||||
|
`updated_at` integer,
|
||||||
|
`haex_timestamp` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `haex_devices_device_id_unique` ON `haex_devices` (`device_id`);--> statement-breakpoint
|
||||||
|
DROP INDEX `haex_settings_key_type_value_unique`;--> statement-breakpoint
|
||||||
|
ALTER TABLE `haex_settings` ADD `device_id` text REFERENCES haex_devices(id);--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `haex_settings_device_id_key_type_unique` ON `haex_settings` (`device_id`,`key`,`type`);
|
||||||
@ -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`;
|
|
||||||
@ -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
|
|
||||||
);
|
|
||||||
10
src-tauri/database/migrations/0003_luxuriant_deathstrike.sql
Normal file
10
src-tauri/database/migrations/0003_luxuriant_deathstrike.sql
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
CREATE TABLE `haex_sync_backends` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`name` text NOT NULL,
|
||||||
|
`server_url` text NOT NULL,
|
||||||
|
`enabled` integer DEFAULT true NOT NULL,
|
||||||
|
`priority` integer DEFAULT 0 NOT NULL,
|
||||||
|
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
|
||||||
|
`updated_at` integer,
|
||||||
|
`haex_timestamp` text
|
||||||
|
);
|
||||||
10
src-tauri/database/migrations/0004_fast_epoch.sql
Normal file
10
src-tauri/database/migrations/0004_fast_epoch.sql
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
CREATE TABLE `haex_sync_status` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`backend_id` text NOT NULL,
|
||||||
|
`last_pull_sequence` integer,
|
||||||
|
`last_push_hlc_timestamp` text,
|
||||||
|
`last_sync_at` text,
|
||||||
|
`error` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE `haex_extensions` ADD `display_mode` text DEFAULT 'auto';
|
||||||
@ -1 +0,0 @@
|
|||||||
ALTER TABLE `haex_notofications` RENAME TO `haex_notifications`;
|
|
||||||
@ -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;
|
|
||||||
@ -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;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
ALTER TABLE `haex_passwords_groups` ADD `description` text;
|
|
||||||
@ -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`;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
ALTER TABLE `haex_settings` ADD `type` text;
|
|
||||||
@ -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;
|
|
||||||
@ -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`);
|
|
||||||
@ -1,49 +1,21 @@
|
|||||||
{
|
{
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"dialect": "sqlite",
|
"dialect": "sqlite",
|
||||||
"id": "fc5a7c9d-4846-4120-a762-cc2ea00504b9",
|
"id": "e3d61ad1-63be-41be-9243-41144e215f98",
|
||||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||||
"tables": {
|
"tables": {
|
||||||
"haex_extensions": {
|
"haex_crdt_configs": {
|
||||||
"name": "haex_extensions",
|
"name": "haex_crdt_configs",
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"key": {
|
||||||
"name": "id",
|
"name": "key",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"author": {
|
"value": {
|
||||||
"name": "author",
|
"name": "value",
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"autoincrement": false
|
|
||||||
},
|
|
||||||
"enabled": {
|
|
||||||
"name": "enabled",
|
|
||||||
"type": "integer",
|
|
||||||
"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",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
@ -56,8 +28,235 @@
|
|||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
"checkConstraints": {}
|
"checkConstraints": {}
|
||||||
},
|
},
|
||||||
"haex_extensions_permissions": {
|
"haex_crdt_logs": {
|
||||||
"name": "haex_extensions_permissions",
|
"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_desktop_items": {
|
||||||
|
"name": "haex_desktop_items",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"workspace_id": {
|
||||||
|
"name": "workspace_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"item_type": {
|
||||||
|
"name": "item_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"extension_id": {
|
||||||
|
"name": "extension_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"system_window_id": {
|
||||||
|
"name": "system_window_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"position_x": {
|
||||||
|
"name": "position_x",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"position_y": {
|
||||||
|
"name": "position_y",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"haex_desktop_items_workspace_id_haex_workspaces_id_fk": {
|
||||||
|
"name": "haex_desktop_items_workspace_id_haex_workspaces_id_fk",
|
||||||
|
"tableFrom": "haex_desktop_items",
|
||||||
|
"tableTo": "haex_workspaces",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workspace_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"haex_desktop_items_extension_id_haex_extensions_id_fk": {
|
||||||
|
"name": "haex_desktop_items_extension_id_haex_extensions_id_fk",
|
||||||
|
"tableFrom": "haex_desktop_items",
|
||||||
|
"tableTo": "haex_extensions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"extension_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {
|
||||||
|
"item_reference": {
|
||||||
|
"name": "item_reference",
|
||||||
|
"value": "(\"haex_desktop_items\".\"item_type\" = 'extension' AND \"haex_desktop_items\".\"extension_id\" IS NOT NULL AND \"haex_desktop_items\".\"system_window_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'system' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'file' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'folder' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"haex_extension_permissions": {
|
||||||
|
"name": "haex_extension_permissions",
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"id": {
|
||||||
"name": "id",
|
"name": "id",
|
||||||
@ -70,25 +269,62 @@
|
|||||||
"name": "extension_id",
|
"name": "extension_id",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"resource": {
|
"resource_type": {
|
||||||
"name": "resource",
|
"name": "resource_type",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"operation": {
|
"action": {
|
||||||
"name": "operation",
|
"name": "action",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"path": {
|
"target": {
|
||||||
"name": "path",
|
"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_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
@ -96,21 +332,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {
|
"indexes": {
|
||||||
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
|
"haex_extension_permissions_extension_id_resource_type_action_target_unique": {
|
||||||
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
|
"name": "haex_extension_permissions_extension_id_resource_type_action_target_unique",
|
||||||
"columns": [
|
"columns": [
|
||||||
"extension_id",
|
"extension_id",
|
||||||
"resource",
|
"resource_type",
|
||||||
"operation",
|
"action",
|
||||||
"path"
|
"target"
|
||||||
],
|
],
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"foreignKeys": {
|
"foreignKeys": {
|
||||||
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
|
"haex_extension_permissions_extension_id_haex_extensions_id_fk": {
|
||||||
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
|
"name": "haex_extension_permissions_extension_id_haex_extensions_id_fk",
|
||||||
"tableFrom": "haex_extensions_permissions",
|
"tableFrom": "haex_extension_permissions",
|
||||||
"tableTo": "haex_extensions",
|
"tableTo": "haex_extensions",
|
||||||
"columnsFrom": [
|
"columnsFrom": [
|
||||||
"extension_id"
|
"extension_id"
|
||||||
@ -118,7 +354,7 @@
|
|||||||
"columnsTo": [
|
"columnsTo": [
|
||||||
"id"
|
"id"
|
||||||
],
|
],
|
||||||
"onDelete": "no action",
|
"onDelete": "cascade",
|
||||||
"onUpdate": "no action"
|
"onUpdate": "no action"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -126,6 +362,206 @@
|
|||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
"checkConstraints": {}
|
"checkConstraints": {}
|
||||||
},
|
},
|
||||||
|
"haex_extensions": {
|
||||||
|
"name": "haex_extensions",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"public_key": {
|
||||||
|
"name": "public_key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"name": "version",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"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,
|
||||||
|
"default": "'index.html'"
|
||||||
|
},
|
||||||
|
"homepage": {
|
||||||
|
"name": "homepage",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"name": "enabled",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"name": "icon",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"name": "signature",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"single_instance": {
|
||||||
|
"name": "single_instance",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_extensions_public_key_name_unique": {
|
||||||
|
"name": "haex_extensions_public_key_name_unique",
|
||||||
|
"columns": [
|
||||||
|
"public_key",
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
"haex_settings": {
|
"haex_settings": {
|
||||||
"name": "haex_settings",
|
"name": "haex_settings",
|
||||||
"columns": {
|
"columns": {
|
||||||
@ -143,29 +579,100 @@
|
|||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"value_text": {
|
"type": {
|
||||||
"name": "value_text",
|
"name": "type",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"value_json": {
|
"value": {
|
||||||
"name": "value_json",
|
"name": "value",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"value_number": {
|
"haex_timestamp": {
|
||||||
"name": "value_number",
|
"name": "haex_timestamp",
|
||||||
"type": "numeric",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {},
|
"indexes": {
|
||||||
|
"haex_settings_key_type_value_unique": {
|
||||||
|
"name": "haex_settings_key_type_value_unique",
|
||||||
|
"columns": [
|
||||||
|
"key",
|
||||||
|
"type",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_workspaces": {
|
||||||
|
"name": "haex_workspaces",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"device_id": {
|
||||||
|
"name": "device_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"name": "position",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"name": "background",
|
||||||
|
"type": "blob",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_workspaces_position_unique": {
|
||||||
|
"name": "haex_workspaces_position_unique",
|
||||||
|
"columns": [
|
||||||
|
"position"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"foreignKeys": {},
|
"foreignKeys": {},
|
||||||
"compositePrimaryKeys": {},
|
"compositePrimaryKeys": {},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
|
|||||||
@ -1,56 +1,21 @@
|
|||||||
{
|
{
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"dialect": "sqlite",
|
"dialect": "sqlite",
|
||||||
"id": "6fb5396b-9f87-4fb5-87a2-22d4eecaa11e",
|
"id": "10bec43a-4227-483e-b1c1-fd50ae32bb96",
|
||||||
"prevId": "fc5a7c9d-4846-4120-a762-cc2ea00504b9",
|
"prevId": "e3d61ad1-63be-41be-9243-41144e215f98",
|
||||||
"tables": {
|
"tables": {
|
||||||
"haex_extensions": {
|
"haex_crdt_configs": {
|
||||||
"name": "haex_extensions",
|
"name": "haex_crdt_configs",
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"key": {
|
||||||
"name": "id",
|
"name": "key",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"author": {
|
"value": {
|
||||||
"name": "author",
|
"name": "value",
|
||||||
"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",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
@ -63,8 +28,235 @@
|
|||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
"checkConstraints": {}
|
"checkConstraints": {}
|
||||||
},
|
},
|
||||||
"haex_extensions_permissions": {
|
"haex_crdt_logs": {
|
||||||
"name": "haex_extensions_permissions",
|
"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_desktop_items": {
|
||||||
|
"name": "haex_desktop_items",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"workspace_id": {
|
||||||
|
"name": "workspace_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"item_type": {
|
||||||
|
"name": "item_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"extension_id": {
|
||||||
|
"name": "extension_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"system_window_id": {
|
||||||
|
"name": "system_window_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"position_x": {
|
||||||
|
"name": "position_x",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"position_y": {
|
||||||
|
"name": "position_y",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"haex_desktop_items_workspace_id_haex_workspaces_id_fk": {
|
||||||
|
"name": "haex_desktop_items_workspace_id_haex_workspaces_id_fk",
|
||||||
|
"tableFrom": "haex_desktop_items",
|
||||||
|
"tableTo": "haex_workspaces",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workspace_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"haex_desktop_items_extension_id_haex_extensions_id_fk": {
|
||||||
|
"name": "haex_desktop_items_extension_id_haex_extensions_id_fk",
|
||||||
|
"tableFrom": "haex_desktop_items",
|
||||||
|
"tableTo": "haex_extensions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"extension_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {
|
||||||
|
"item_reference": {
|
||||||
|
"name": "item_reference",
|
||||||
|
"value": "(\"haex_desktop_items\".\"item_type\" = 'extension' AND \"haex_desktop_items\".\"extension_id\" IS NOT NULL AND \"haex_desktop_items\".\"system_window_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'system' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'file' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'folder' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"haex_extension_permissions": {
|
||||||
|
"name": "haex_extension_permissions",
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"id": {
|
||||||
"name": "id",
|
"name": "id",
|
||||||
@ -77,25 +269,62 @@
|
|||||||
"name": "extension_id",
|
"name": "extension_id",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"resource": {
|
"resource_type": {
|
||||||
"name": "resource",
|
"name": "resource_type",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"operation": {
|
"action": {
|
||||||
"name": "operation",
|
"name": "action",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"path": {
|
"target": {
|
||||||
"name": "path",
|
"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_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
@ -103,21 +332,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {
|
"indexes": {
|
||||||
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
|
"haex_extension_permissions_extension_id_resource_type_action_target_unique": {
|
||||||
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
|
"name": "haex_extension_permissions_extension_id_resource_type_action_target_unique",
|
||||||
"columns": [
|
"columns": [
|
||||||
"extension_id",
|
"extension_id",
|
||||||
"resource",
|
"resource_type",
|
||||||
"operation",
|
"action",
|
||||||
"path"
|
"target"
|
||||||
],
|
],
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"foreignKeys": {
|
"foreignKeys": {
|
||||||
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
|
"haex_extension_permissions_extension_id_haex_extensions_id_fk": {
|
||||||
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
|
"name": "haex_extension_permissions_extension_id_haex_extensions_id_fk",
|
||||||
"tableFrom": "haex_extensions_permissions",
|
"tableFrom": "haex_extension_permissions",
|
||||||
"tableTo": "haex_extensions",
|
"tableTo": "haex_extensions",
|
||||||
"columnsFrom": [
|
"columnsFrom": [
|
||||||
"extension_id"
|
"extension_id"
|
||||||
@ -125,7 +354,7 @@
|
|||||||
"columnsTo": [
|
"columnsTo": [
|
||||||
"id"
|
"id"
|
||||||
],
|
],
|
||||||
"onDelete": "no action",
|
"onDelete": "cascade",
|
||||||
"onUpdate": "no action"
|
"onUpdate": "no action"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -133,6 +362,206 @@
|
|||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
"checkConstraints": {}
|
"checkConstraints": {}
|
||||||
},
|
},
|
||||||
|
"haex_extensions": {
|
||||||
|
"name": "haex_extensions",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"public_key": {
|
||||||
|
"name": "public_key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"name": "version",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"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,
|
||||||
|
"default": "'index.html'"
|
||||||
|
},
|
||||||
|
"homepage": {
|
||||||
|
"name": "homepage",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"name": "enabled",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"name": "icon",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"name": "signature",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"single_instance": {
|
||||||
|
"name": "single_instance",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_extensions_public_key_name_unique": {
|
||||||
|
"name": "haex_extensions_public_key_name_unique",
|
||||||
|
"columns": [
|
||||||
|
"public_key",
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
"haex_settings": {
|
"haex_settings": {
|
||||||
"name": "haex_settings",
|
"name": "haex_settings",
|
||||||
"columns": {
|
"columns": {
|
||||||
@ -150,36 +579,46 @@
|
|||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"value_text": {
|
"type": {
|
||||||
"name": "value_text",
|
"name": "type",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"value_json": {
|
"value": {
|
||||||
"name": "value_json",
|
"name": "value",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"value_number": {
|
"haex_timestamp": {
|
||||||
"name": "value_number",
|
"name": "haex_timestamp",
|
||||||
"type": "numeric",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {},
|
"indexes": {
|
||||||
|
"haex_settings_key_type_value_unique": {
|
||||||
|
"name": "haex_settings_key_type_value_unique",
|
||||||
|
"columns": [
|
||||||
|
"key",
|
||||||
|
"type",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"foreignKeys": {},
|
"foreignKeys": {},
|
||||||
"compositePrimaryKeys": {},
|
"compositePrimaryKeys": {},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
"checkConstraints": {}
|
"checkConstraints": {}
|
||||||
},
|
},
|
||||||
"testTable": {
|
"haex_workspaces": {
|
||||||
"name": "testTable",
|
"name": "haex_workspaces",
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"id": {
|
||||||
"name": "id",
|
"name": "id",
|
||||||
@ -188,22 +627,52 @@
|
|||||||
"notNull": true,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"author": {
|
"device_id": {
|
||||||
"name": "author",
|
"name": "device_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"name": "position",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"name": "background",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"test": {
|
"haex_timestamp": {
|
||||||
"name": "test",
|
"name": "haex_timestamp",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {},
|
"indexes": {
|
||||||
|
"haex_workspaces_position_unique": {
|
||||||
|
"name": "haex_workspaces_position_unique",
|
||||||
|
"columns": [
|
||||||
|
"position"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"foreignKeys": {},
|
"foreignKeys": {},
|
||||||
"compositePrimaryKeys": {},
|
"compositePrimaryKeys": {},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
|
|||||||
@ -1,153 +1,17 @@
|
|||||||
{
|
{
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"dialect": "sqlite",
|
"dialect": "sqlite",
|
||||||
"id": "ea3507ca-77bc-4f3c-a605-8426614f5803",
|
"id": "3aedf10c-2266-40f4-8549-0ff8b0588853",
|
||||||
"prevId": "6fb5396b-9f87-4fb5-87a2-22d4eecaa11e",
|
"prevId": "10bec43a-4227-483e-b1c1-fd50ae32bb96",
|
||||||
"tables": {
|
"tables": {
|
||||||
"haex_extensions": {
|
"haex_crdt_configs": {
|
||||||
"name": "haex_extensions",
|
"name": "haex_crdt_configs",
|
||||||
"columns": {
|
"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": {
|
"key": {
|
||||||
"name": "key",
|
"name": "key",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": true,
|
||||||
"notNull": false,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"value": {
|
"value": {
|
||||||
@ -163,6 +27,738 @@
|
|||||||
"compositePrimaryKeys": {},
|
"compositePrimaryKeys": {},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
"checkConstraints": {}
|
"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_desktop_items": {
|
||||||
|
"name": "haex_desktop_items",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"workspace_id": {
|
||||||
|
"name": "workspace_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"item_type": {
|
||||||
|
"name": "item_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"extension_id": {
|
||||||
|
"name": "extension_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"system_window_id": {
|
||||||
|
"name": "system_window_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"position_x": {
|
||||||
|
"name": "position_x",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"position_y": {
|
||||||
|
"name": "position_y",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"haex_desktop_items_workspace_id_haex_workspaces_id_fk": {
|
||||||
|
"name": "haex_desktop_items_workspace_id_haex_workspaces_id_fk",
|
||||||
|
"tableFrom": "haex_desktop_items",
|
||||||
|
"tableTo": "haex_workspaces",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workspace_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"haex_desktop_items_extension_id_haex_extensions_id_fk": {
|
||||||
|
"name": "haex_desktop_items_extension_id_haex_extensions_id_fk",
|
||||||
|
"tableFrom": "haex_desktop_items",
|
||||||
|
"tableTo": "haex_extensions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"extension_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {
|
||||||
|
"item_reference": {
|
||||||
|
"name": "item_reference",
|
||||||
|
"value": "(\"haex_desktop_items\".\"item_type\" = 'extension' AND \"haex_desktop_items\".\"extension_id\" IS NOT NULL AND \"haex_desktop_items\".\"system_window_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'system' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'file' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'folder' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"haex_devices": {
|
||||||
|
"name": "haex_devices",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"device_id": {
|
||||||
|
"name": "device_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"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_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_devices_device_id_unique": {
|
||||||
|
"name": "haex_devices_device_id_unique",
|
||||||
|
"columns": [
|
||||||
|
"device_id"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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": true,
|
||||||
|
"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_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": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_extensions": {
|
||||||
|
"name": "haex_extensions",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"public_key": {
|
||||||
|
"name": "public_key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"name": "version",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"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,
|
||||||
|
"default": "'index.html'"
|
||||||
|
},
|
||||||
|
"homepage": {
|
||||||
|
"name": "homepage",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"name": "enabled",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"name": "icon",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"name": "signature",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"single_instance": {
|
||||||
|
"name": "single_instance",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_extensions_public_key_name_unique": {
|
||||||
|
"name": "haex_extensions_public_key_name_unique",
|
||||||
|
"columns": [
|
||||||
|
"public_key",
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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_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
|
||||||
|
},
|
||||||
|
"device_id": {
|
||||||
|
"name": "device_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"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_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_settings_device_id_key_type_unique": {
|
||||||
|
"name": "haex_settings_device_id_key_type_unique",
|
||||||
|
"columns": [
|
||||||
|
"device_id",
|
||||||
|
"key",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"haex_settings_device_id_haex_devices_id_fk": {
|
||||||
|
"name": "haex_settings_device_id_haex_devices_id_fk",
|
||||||
|
"tableFrom": "haex_settings",
|
||||||
|
"tableTo": "haex_devices",
|
||||||
|
"columnsFrom": [
|
||||||
|
"device_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_workspaces": {
|
||||||
|
"name": "haex_workspaces",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"device_id": {
|
||||||
|
"name": "device_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"name": "position",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"name": "background",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_workspaces_position_unique": {
|
||||||
|
"name": "haex_workspaces_position_unique",
|
||||||
|
"columns": [
|
||||||
|
"position"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"views": {},
|
"views": {},
|
||||||
@ -170,9 +766,7 @@
|
|||||||
"_meta": {
|
"_meta": {
|
||||||
"schemas": {},
|
"schemas": {},
|
||||||
"tables": {},
|
"tables": {},
|
||||||
"columns": {
|
"columns": {}
|
||||||
"\"haex_settings\".\"value_text\"": "\"haex_settings\".\"value\""
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"internal": {
|
"internal": {
|
||||||
"indexes": {}
|
"indexes": {}
|
||||||
|
|||||||
@ -1,56 +1,21 @@
|
|||||||
{
|
{
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"dialect": "sqlite",
|
"dialect": "sqlite",
|
||||||
"id": "5f413421-18a5-4c1b-9c5b-99f574b10126",
|
"id": "bf82259e-9264-44e7-a60f-8cc14a1f22e2",
|
||||||
"prevId": "ea3507ca-77bc-4f3c-a605-8426614f5803",
|
"prevId": "3aedf10c-2266-40f4-8549-0ff8b0588853",
|
||||||
"tables": {
|
"tables": {
|
||||||
"haex_extensions": {
|
"haex_crdt_configs": {
|
||||||
"name": "haex_extensions",
|
"name": "haex_crdt_configs",
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"key": {
|
||||||
"name": "id",
|
"name": "key",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"name": {
|
"value": {
|
||||||
"name": "name",
|
"name": "value",
|
||||||
"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",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
@ -63,8 +28,296 @@
|
|||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
"checkConstraints": {}
|
"checkConstraints": {}
|
||||||
},
|
},
|
||||||
"haex_extensions_permissions": {
|
"haex_crdt_logs": {
|
||||||
"name": "haex_extensions_permissions",
|
"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_desktop_items": {
|
||||||
|
"name": "haex_desktop_items",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"workspace_id": {
|
||||||
|
"name": "workspace_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"item_type": {
|
||||||
|
"name": "item_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"extension_id": {
|
||||||
|
"name": "extension_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"system_window_id": {
|
||||||
|
"name": "system_window_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"position_x": {
|
||||||
|
"name": "position_x",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"position_y": {
|
||||||
|
"name": "position_y",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"haex_desktop_items_workspace_id_haex_workspaces_id_fk": {
|
||||||
|
"name": "haex_desktop_items_workspace_id_haex_workspaces_id_fk",
|
||||||
|
"tableFrom": "haex_desktop_items",
|
||||||
|
"tableTo": "haex_workspaces",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workspace_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"haex_desktop_items_extension_id_haex_extensions_id_fk": {
|
||||||
|
"name": "haex_desktop_items_extension_id_haex_extensions_id_fk",
|
||||||
|
"tableFrom": "haex_desktop_items",
|
||||||
|
"tableTo": "haex_extensions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"extension_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {
|
||||||
|
"item_reference": {
|
||||||
|
"name": "item_reference",
|
||||||
|
"value": "(\"haex_desktop_items\".\"item_type\" = 'extension' AND \"haex_desktop_items\".\"extension_id\" IS NOT NULL AND \"haex_desktop_items\".\"system_window_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'system' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'file' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'folder' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"haex_devices": {
|
||||||
|
"name": "haex_devices",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"device_id": {
|
||||||
|
"name": "device_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"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_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_devices_device_id_unique": {
|
||||||
|
"name": "haex_devices_device_id_unique",
|
||||||
|
"columns": [
|
||||||
|
"device_id"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_extension_permissions": {
|
||||||
|
"name": "haex_extension_permissions",
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"id": {
|
||||||
"name": "id",
|
"name": "id",
|
||||||
@ -77,25 +330,62 @@
|
|||||||
"name": "extension_id",
|
"name": "extension_id",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"resource": {
|
"resource_type": {
|
||||||
"name": "resource",
|
"name": "resource_type",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"operation": {
|
"action": {
|
||||||
"name": "operation",
|
"name": "action",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"path": {
|
"target": {
|
||||||
"name": "path",
|
"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_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
@ -103,21 +393,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {
|
"indexes": {
|
||||||
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
|
"haex_extension_permissions_extension_id_resource_type_action_target_unique": {
|
||||||
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
|
"name": "haex_extension_permissions_extension_id_resource_type_action_target_unique",
|
||||||
"columns": [
|
"columns": [
|
||||||
"extension_id",
|
"extension_id",
|
||||||
"resource",
|
"resource_type",
|
||||||
"operation",
|
"action",
|
||||||
"path"
|
"target"
|
||||||
],
|
],
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"foreignKeys": {
|
"foreignKeys": {
|
||||||
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
|
"haex_extension_permissions_extension_id_haex_extensions_id_fk": {
|
||||||
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
|
"name": "haex_extension_permissions_extension_id_haex_extensions_id_fk",
|
||||||
"tableFrom": "haex_extensions_permissions",
|
"tableFrom": "haex_extension_permissions",
|
||||||
"tableTo": "haex_extensions",
|
"tableTo": "haex_extensions",
|
||||||
"columnsFrom": [
|
"columnsFrom": [
|
||||||
"extension_id"
|
"extension_id"
|
||||||
@ -125,7 +415,7 @@
|
|||||||
"columnsTo": [
|
"columnsTo": [
|
||||||
"id"
|
"id"
|
||||||
],
|
],
|
||||||
"onDelete": "no action",
|
"onDelete": "cascade",
|
||||||
"onUpdate": "no action"
|
"onUpdate": "no action"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -133,8 +423,8 @@
|
|||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
"checkConstraints": {}
|
"checkConstraints": {}
|
||||||
},
|
},
|
||||||
"haex_notofications": {
|
"haex_extensions": {
|
||||||
"name": "haex_notofications",
|
"name": "haex_extensions",
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"id": {
|
||||||
"name": "id",
|
"name": "id",
|
||||||
@ -143,32 +433,124 @@
|
|||||||
"notNull": true,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"title": {
|
"public_key": {
|
||||||
"name": "title",
|
"name": "public_key",
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"autoincrement": false
|
|
||||||
},
|
|
||||||
"text": {
|
|
||||||
"name": "text",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"autoincrement": false
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"name": "type",
|
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"read": {
|
"name": {
|
||||||
"name": "read",
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"name": "version",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"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,
|
||||||
|
"default": "'index.html'"
|
||||||
|
},
|
||||||
|
"homepage": {
|
||||||
|
"name": "homepage",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"name": "enabled",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"name": "icon",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"name": "signature",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"single_instance": {
|
||||||
|
"name": "single_instance",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_extensions_public_key_name_unique": {
|
||||||
|
"name": "haex_extensions_public_key_name_unique",
|
||||||
|
"columns": [
|
||||||
|
"public_key",
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"date": {
|
"date": {
|
||||||
@ -178,6 +560,13 @@
|
|||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
|
"icon": {
|
||||||
|
"name": "icon",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
"image": {
|
"image": {
|
||||||
"name": "image",
|
"name": "image",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@ -185,15 +574,43 @@
|
|||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"alt": {
|
"read": {
|
||||||
"name": "alt",
|
"name": "read",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"name": "source",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"icon": {
|
"text": {
|
||||||
"name": "icon",
|
"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_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
@ -216,6 +633,13 @@
|
|||||||
"notNull": true,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
|
"device_id": {
|
||||||
|
"name": "device_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
"key": {
|
"key": {
|
||||||
"name": "key",
|
"name": "key",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@ -223,12 +647,119 @@
|
|||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
"value": {
|
"value": {
|
||||||
"name": "value",
|
"name": "value",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_settings_device_id_key_type_unique": {
|
||||||
|
"name": "haex_settings_device_id_key_type_unique",
|
||||||
|
"columns": [
|
||||||
|
"device_id",
|
||||||
|
"key",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"haex_settings_device_id_haex_devices_id_fk": {
|
||||||
|
"name": "haex_settings_device_id_haex_devices_id_fk",
|
||||||
|
"tableFrom": "haex_settings",
|
||||||
|
"tableTo": "haex_devices",
|
||||||
|
"columnsFrom": [
|
||||||
|
"device_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_sync_backends": {
|
||||||
|
"name": "haex_sync_backends",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"server_url": {
|
||||||
|
"name": "server_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"name": "enabled",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"name": "priority",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"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_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {},
|
"indexes": {},
|
||||||
@ -236,6 +767,67 @@
|
|||||||
"compositePrimaryKeys": {},
|
"compositePrimaryKeys": {},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
"checkConstraints": {}
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_workspaces": {
|
||||||
|
"name": "haex_workspaces",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"device_id": {
|
||||||
|
"name": "device_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"name": "position",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"name": "background",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_workspaces_position_unique": {
|
||||||
|
"name": "haex_workspaces_position_unique",
|
||||||
|
"columns": [
|
||||||
|
"position"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"views": {},
|
"views": {},
|
||||||
|
|||||||
@ -1,56 +1,21 @@
|
|||||||
{
|
{
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"dialect": "sqlite",
|
"dialect": "sqlite",
|
||||||
"id": "7aaac460-00b5-4387-bef9-b189297cefb3",
|
"id": "7ae230a2-4488-4214-9163-602018852676",
|
||||||
"prevId": "5f413421-18a5-4c1b-9c5b-99f574b10126",
|
"prevId": "bf82259e-9264-44e7-a60f-8cc14a1f22e2",
|
||||||
"tables": {
|
"tables": {
|
||||||
"haex_extensions": {
|
"haex_crdt_configs": {
|
||||||
"name": "haex_extensions",
|
"name": "haex_crdt_configs",
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"key": {
|
||||||
"name": "id",
|
"name": "key",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"author": {
|
"value": {
|
||||||
"name": "author",
|
"name": "value",
|
||||||
"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",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
@ -63,8 +28,348 @@
|
|||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
"checkConstraints": {}
|
"checkConstraints": {}
|
||||||
},
|
},
|
||||||
"haex_extensions_permissions": {
|
"haex_crdt_logs": {
|
||||||
"name": "haex_extensions_permissions",
|
"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_sync_status": {
|
||||||
|
"name": "haex_sync_status",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"backend_id": {
|
||||||
|
"name": "backend_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"last_pull_sequence": {
|
||||||
|
"name": "last_pull_sequence",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"last_push_hlc_timestamp": {
|
||||||
|
"name": "last_push_hlc_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"last_sync_at": {
|
||||||
|
"name": "last_sync_at",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"name": "error",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_desktop_items": {
|
||||||
|
"name": "haex_desktop_items",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"workspace_id": {
|
||||||
|
"name": "workspace_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"item_type": {
|
||||||
|
"name": "item_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"extension_id": {
|
||||||
|
"name": "extension_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"system_window_id": {
|
||||||
|
"name": "system_window_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"position_x": {
|
||||||
|
"name": "position_x",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"position_y": {
|
||||||
|
"name": "position_y",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"haex_desktop_items_workspace_id_haex_workspaces_id_fk": {
|
||||||
|
"name": "haex_desktop_items_workspace_id_haex_workspaces_id_fk",
|
||||||
|
"tableFrom": "haex_desktop_items",
|
||||||
|
"tableTo": "haex_workspaces",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workspace_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"haex_desktop_items_extension_id_haex_extensions_id_fk": {
|
||||||
|
"name": "haex_desktop_items_extension_id_haex_extensions_id_fk",
|
||||||
|
"tableFrom": "haex_desktop_items",
|
||||||
|
"tableTo": "haex_extensions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"extension_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {
|
||||||
|
"item_reference": {
|
||||||
|
"name": "item_reference",
|
||||||
|
"value": "(\"haex_desktop_items\".\"item_type\" = 'extension' AND \"haex_desktop_items\".\"extension_id\" IS NOT NULL AND \"haex_desktop_items\".\"system_window_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'system' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'file' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL) OR (\"haex_desktop_items\".\"item_type\" = 'folder' AND \"haex_desktop_items\".\"system_window_id\" IS NOT NULL AND \"haex_desktop_items\".\"extension_id\" IS NULL)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"haex_devices": {
|
||||||
|
"name": "haex_devices",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"device_id": {
|
||||||
|
"name": "device_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"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_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_devices_device_id_unique": {
|
||||||
|
"name": "haex_devices_device_id_unique",
|
||||||
|
"columns": [
|
||||||
|
"device_id"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_extension_permissions": {
|
||||||
|
"name": "haex_extension_permissions",
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"id": {
|
||||||
"name": "id",
|
"name": "id",
|
||||||
@ -77,25 +382,62 @@
|
|||||||
"name": "extension_id",
|
"name": "extension_id",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"resource": {
|
"resource_type": {
|
||||||
"name": "resource",
|
"name": "resource_type",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"operation": {
|
"action": {
|
||||||
"name": "operation",
|
"name": "action",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"path": {
|
"target": {
|
||||||
"name": "path",
|
"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_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
@ -103,21 +445,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {
|
"indexes": {
|
||||||
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
|
"haex_extension_permissions_extension_id_resource_type_action_target_unique": {
|
||||||
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
|
"name": "haex_extension_permissions_extension_id_resource_type_action_target_unique",
|
||||||
"columns": [
|
"columns": [
|
||||||
"extension_id",
|
"extension_id",
|
||||||
"resource",
|
"resource_type",
|
||||||
"operation",
|
"action",
|
||||||
"path"
|
"target"
|
||||||
],
|
],
|
||||||
"isUnique": true
|
"isUnique": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"foreignKeys": {
|
"foreignKeys": {
|
||||||
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
|
"haex_extension_permissions_extension_id_haex_extensions_id_fk": {
|
||||||
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
|
"name": "haex_extension_permissions_extension_id_haex_extensions_id_fk",
|
||||||
"tableFrom": "haex_extensions_permissions",
|
"tableFrom": "haex_extension_permissions",
|
||||||
"tableTo": "haex_extensions",
|
"tableTo": "haex_extensions",
|
||||||
"columnsFrom": [
|
"columnsFrom": [
|
||||||
"extension_id"
|
"extension_id"
|
||||||
@ -125,7 +467,7 @@
|
|||||||
"columnsTo": [
|
"columnsTo": [
|
||||||
"id"
|
"id"
|
||||||
],
|
],
|
||||||
"onDelete": "no action",
|
"onDelete": "cascade",
|
||||||
"onUpdate": "no action"
|
"onUpdate": "no action"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -133,6 +475,127 @@
|
|||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
"checkConstraints": {}
|
"checkConstraints": {}
|
||||||
},
|
},
|
||||||
|
"haex_extensions": {
|
||||||
|
"name": "haex_extensions",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"public_key": {
|
||||||
|
"name": "public_key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"name": "version",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"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,
|
||||||
|
"default": "'index.html'"
|
||||||
|
},
|
||||||
|
"homepage": {
|
||||||
|
"name": "homepage",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"name": "enabled",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"name": "icon",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"name": "signature",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"single_instance": {
|
||||||
|
"name": "single_instance",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"display_mode": {
|
||||||
|
"name": "display_mode",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "'auto'"
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_extensions_public_key_name_unique": {
|
||||||
|
"name": "haex_extensions_public_key_name_unique",
|
||||||
|
"columns": [
|
||||||
|
"public_key",
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
"haex_notifications": {
|
"haex_notifications": {
|
||||||
"name": "haex_notifications",
|
"name": "haex_notifications",
|
||||||
"columns": {
|
"columns": {
|
||||||
@ -178,6 +641,13 @@
|
|||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
|
"source": {
|
||||||
|
"name": "source",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
"text": {
|
"text": {
|
||||||
"name": "text",
|
"name": "text",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@ -198,6 +668,13 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {},
|
"indexes": {},
|
||||||
@ -216,6 +693,13 @@
|
|||||||
"notNull": true,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
|
"device_id": {
|
||||||
|
"name": "device_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
"key": {
|
"key": {
|
||||||
"name": "key",
|
"name": "key",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@ -223,12 +707,119 @@
|
|||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
"value": {
|
"value": {
|
||||||
"name": "value",
|
"name": "value",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_settings_device_id_key_type_unique": {
|
||||||
|
"name": "haex_settings_device_id_key_type_unique",
|
||||||
|
"columns": [
|
||||||
|
"device_id",
|
||||||
|
"key",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"haex_settings_device_id_haex_devices_id_fk": {
|
||||||
|
"name": "haex_settings_device_id_haex_devices_id_fk",
|
||||||
|
"tableFrom": "haex_settings",
|
||||||
|
"tableTo": "haex_devices",
|
||||||
|
"columnsFrom": [
|
||||||
|
"device_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_sync_backends": {
|
||||||
|
"name": "haex_sync_backends",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"server_url": {
|
||||||
|
"name": "server_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"name": "enabled",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"name": "priority",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"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_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {},
|
"indexes": {},
|
||||||
@ -236,15 +827,74 @@
|
|||||||
"compositePrimaryKeys": {},
|
"compositePrimaryKeys": {},
|
||||||
"uniqueConstraints": {},
|
"uniqueConstraints": {},
|
||||||
"checkConstraints": {}
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_workspaces": {
|
||||||
|
"name": "haex_workspaces",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"device_id": {
|
||||||
|
"name": "device_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"name": "position",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"name": "background",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"haex_timestamp": {
|
||||||
|
"name": "haex_timestamp",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_workspaces_position_unique": {
|
||||||
|
"name": "haex_workspaces_position_unique",
|
||||||
|
"columns": [
|
||||||
|
"position"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"views": {},
|
"views": {},
|
||||||
"enums": {},
|
"enums": {},
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"schemas": {},
|
"schemas": {},
|
||||||
"tables": {
|
"tables": {},
|
||||||
"\"haex_notofications\"": "\"haex_notifications\""
|
|
||||||
},
|
|
||||||
"columns": {}
|
"columns": {}
|
||||||
},
|
},
|
||||||
"internal": {
|
"internal": {
|
||||||
|
|||||||
@ -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": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,85 +5,36 @@
|
|||||||
{
|
{
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"when": 1742903332283,
|
"when": 1762119713008,
|
||||||
"tag": "0000_zippy_scourge",
|
"tag": "0000_cynical_nicolaos",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"when": 1746281577722,
|
"when": 1762122405562,
|
||||||
"tag": "0001_wealthy_thaddeus_ross",
|
"tag": "0001_furry_brother_voodoo",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 2,
|
"idx": 2,
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"when": 1747583956679,
|
"when": 1762263814375,
|
||||||
"tag": "0002_married_bushwacker",
|
"tag": "0002_loose_quasimodo",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 3,
|
"idx": 3,
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"when": 1748873820060,
|
"when": 1762300795436,
|
||||||
"tag": "0003_familiar_doctor_faustus",
|
"tag": "0003_luxuriant_deathstrike",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 4,
|
"idx": 4,
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"when": 1748982377354,
|
"when": 1762894662424,
|
||||||
"tag": "0004_wooden_lockheed",
|
"tag": "0004_fast_epoch",
|
||||||
"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
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
import { integer, sqliteTable, text } 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 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 haexCrdtConfigs = sqliteTable(tableNames.haex.crdt.configs, {
|
|
||||||
key: text().primaryKey(),
|
|
||||||
value: text(),
|
|
||||||
})
|
|
||||||
@ -1,179 +0,0 @@
|
|||||||
import { sql } from 'drizzle-orm'
|
|
||||||
import {
|
|
||||||
integer,
|
|
||||||
primaryKey,
|
|
||||||
sqliteTable,
|
|
||||||
text,
|
|
||||||
unique,
|
|
||||||
type AnySQLiteColumn,
|
|
||||||
} from 'drizzle-orm/sqlite-core'
|
|
||||||
import tableNames from '../tableNames.json'
|
|
||||||
|
|
||||||
export const haexSettings = sqliteTable(tableNames.haex.settings, {
|
|
||||||
id: text().primaryKey(),
|
|
||||||
key: text(),
|
|
||||||
type: text(),
|
|
||||||
value: text(),
|
|
||||||
haex_tombstone: integer({ mode: 'boolean' }),
|
|
||||||
})
|
|
||||||
export type InsertHaexSettings = typeof haexSettings.$inferInsert
|
|
||||||
export type SelectHaexSettings = typeof haexSettings.$inferSelect
|
|
||||||
|
|
||||||
export const haexExtensions = sqliteTable(tableNames.haex.extensions, {
|
|
||||||
id: text().primaryKey(),
|
|
||||||
author: text(),
|
|
||||||
enabled: integer({ mode: 'boolean' }),
|
|
||||||
icon: text(),
|
|
||||||
name: text(),
|
|
||||||
url: text(),
|
|
||||||
version: text(),
|
|
||||||
haex_tombstone: integer({ mode: 'boolean' }),
|
|
||||||
})
|
|
||||||
export type InsertHaexExtensions = typeof haexExtensions.$inferInsert
|
|
||||||
export type SelectHaexExtensions = typeof haexExtensions.$inferSelect
|
|
||||||
|
|
||||||
export const haexExtensionPermissions = sqliteTable(
|
|
||||||
tableNames.haex.extension_permissions,
|
|
||||||
{
|
|
||||||
id: text().primaryKey(),
|
|
||||||
extensionId: text('extension_id').references(
|
|
||||||
(): AnySQLiteColumn => haexExtensions.id,
|
|
||||||
),
|
|
||||||
resource: text({ enum: ['fs', 'http', 'db', 'shell'] }),
|
|
||||||
operation: text({ enum: ['read', 'write', 'create'] }),
|
|
||||||
path: text(),
|
|
||||||
createdAt: text('created_at').default(sql`(CURRENT_TIMESTAMP)`),
|
|
||||||
updateAt: integer('updated_at', { mode: 'timestamp' }).$onUpdate(
|
|
||||||
() => new Date(),
|
|
||||||
),
|
|
||||||
haex_tombstone: integer({ mode: 'boolean' }),
|
|
||||||
},
|
|
||||||
(table) => [
|
|
||||||
unique().on(table.extensionId, table.resource, table.operation, table.path),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
export type InserthaexExtensionPermissions =
|
|
||||||
typeof haexExtensionPermissions.$inferInsert
|
|
||||||
export type SelecthaexExtensionPermissions =
|
|
||||||
typeof haexExtensionPermissions.$inferSelect
|
|
||||||
|
|
||||||
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,
|
|
||||||
{
|
|
||||||
id: text().primaryKey(),
|
|
||||||
title: text(),
|
|
||||||
username: text(),
|
|
||||||
password: text(),
|
|
||||||
note: text(),
|
|
||||||
icon: text(),
|
|
||||||
tags: text(),
|
|
||||||
url: text(),
|
|
||||||
createdAt: text('created_at').default(sql`(CURRENT_TIMESTAMP)`),
|
|
||||||
updateAt: integer('updated_at', { mode: 'timestamp' }).$onUpdate(
|
|
||||||
() => new Date(),
|
|
||||||
),
|
|
||||||
haex_tombstone: integer({ mode: 'boolean' }),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
export type InsertHaexPasswordsItemDetails =
|
|
||||||
typeof haexPasswordsItemDetails.$inferInsert
|
|
||||||
export type SelectHaexPasswordsItemDetails =
|
|
||||||
typeof haexPasswordsItemDetails.$inferSelect
|
|
||||||
|
|
||||||
export const haexPasswordsItemKeyValues = sqliteTable(
|
|
||||||
tableNames.haex.passwords.item_key_values,
|
|
||||||
{
|
|
||||||
id: text().primaryKey(),
|
|
||||||
itemId: text('item_id').references(
|
|
||||||
(): AnySQLiteColumn => haexPasswordsItemDetails.id,
|
|
||||||
),
|
|
||||||
key: text(),
|
|
||||||
value: text(),
|
|
||||||
updateAt: integer('updated_at', { mode: 'timestamp' }).$onUpdate(
|
|
||||||
() => new Date(),
|
|
||||||
),
|
|
||||||
haex_tombstone: integer({ mode: 'boolean' }),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
export type InserthaexPasswordsItemKeyValues =
|
|
||||||
typeof haexPasswordsItemKeyValues.$inferInsert
|
|
||||||
export type SelectHaexPasswordsItemKeyValues =
|
|
||||||
typeof haexPasswordsItemKeyValues.$inferSelect
|
|
||||||
|
|
||||||
export const haexPasswordsItemHistory = sqliteTable(
|
|
||||||
tableNames.haex.passwords.item_histories,
|
|
||||||
{
|
|
||||||
id: text().primaryKey(),
|
|
||||||
itemId: text('item_id').references(
|
|
||||||
(): AnySQLiteColumn => haexPasswordsItemDetails.id,
|
|
||||||
),
|
|
||||||
changedProperty:
|
|
||||||
text('changed_property').$type<keyof typeof haexPasswordsItemDetails>(),
|
|
||||||
oldValue: text('old_value'),
|
|
||||||
newValue: text('new_value'),
|
|
||||||
createdAt: text('created_at').default(sql`(CURRENT_TIMESTAMP)`),
|
|
||||||
haex_tombstone: integer({ mode: 'boolean' }),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
export type InserthaexPasswordsItemHistory =
|
|
||||||
typeof haexPasswordsItemHistory.$inferInsert
|
|
||||||
export type SelectHaexPasswordsItemHistory =
|
|
||||||
typeof haexPasswordsItemHistory.$inferSelect
|
|
||||||
|
|
||||||
export const haexPasswordsGroups = sqliteTable(
|
|
||||||
tableNames.haex.passwords.groups,
|
|
||||||
{
|
|
||||||
id: text().primaryKey(),
|
|
||||||
name: text(),
|
|
||||||
description: text(),
|
|
||||||
icon: text(),
|
|
||||||
order: integer(),
|
|
||||||
color: text(),
|
|
||||||
parentId: text('parent_id').references(
|
|
||||||
(): AnySQLiteColumn => haexPasswordsGroups.id,
|
|
||||||
),
|
|
||||||
createdAt: text('created_at').default(sql`(CURRENT_TIMESTAMP)`),
|
|
||||||
updateAt: integer('updated_at', { mode: 'timestamp' }).$onUpdate(
|
|
||||||
() => new Date(),
|
|
||||||
),
|
|
||||||
haex_tombstone: integer({ mode: 'boolean' }),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
export type InsertHaexPasswordsGroups = typeof haexPasswordsGroups.$inferInsert
|
|
||||||
export type SelectHaexPasswordsGroups = typeof haexPasswordsGroups.$inferSelect
|
|
||||||
|
|
||||||
export const haexPasswordsGroupItems = sqliteTable(
|
|
||||||
tableNames.haex.passwords.group_items,
|
|
||||||
{
|
|
||||||
groupId: text('group_id').references(
|
|
||||||
(): AnySQLiteColumn => haexPasswordsGroups.id,
|
|
||||||
),
|
|
||||||
itemId: text('item_id').references(
|
|
||||||
(): AnySQLiteColumn => haexPasswordsItemDetails.id,
|
|
||||||
),
|
|
||||||
haex_tombstone: integer({ mode: 'boolean' }),
|
|
||||||
},
|
|
||||||
(table) => [primaryKey({ columns: [table.itemId, table.groupId] })],
|
|
||||||
)
|
|
||||||
export type InsertHaexPasswordsGroupItems =
|
|
||||||
typeof haexPasswordsGroupItems.$inferInsert
|
|
||||||
export type SelectHaexPasswordsGroupItems =
|
|
||||||
typeof haexPasswordsGroupItems.$inferSelect
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"haex": {
|
|
||||||
"settings": "haex_settings",
|
|
||||||
"extensions": "haex_extensions",
|
|
||||||
"extension_permissions": "haex_extension_permissions",
|
|
||||||
"notifications": "haex_notifications",
|
|
||||||
"passwords": {
|
|
||||||
"groups": "haex_passwords_groups",
|
|
||||||
"group_items": "haex_passwords_group_items",
|
|
||||||
"item_details": "haex_passwords_item_details",
|
|
||||||
"item_key_values": "haex_passwords_item_key_values",
|
|
||||||
"item_histories": "haex_passwords_item_history"
|
|
||||||
},
|
|
||||||
"crdt": {
|
|
||||||
"logs": "haex_crdt_logs",
|
|
||||||
"snapshots": "haex_crdt_snapshots",
|
|
||||||
"configs": "haex_crdt_configs"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
@ -24,6 +24,23 @@ android {
|
|||||||
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
||||||
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signingConfigs {
|
||||||
|
create("release") {
|
||||||
|
val keystorePath = System.getenv("ANDROID_KEYSTORE_PATH")
|
||||||
|
val keystorePassword = System.getenv("ANDROID_KEYSTORE_PASSWORD")
|
||||||
|
val keyAlias = System.getenv("ANDROID_KEY_ALIAS")
|
||||||
|
val keyPassword = System.getenv("ANDROID_KEY_PASSWORD")
|
||||||
|
|
||||||
|
if (keystorePath != null && keystorePassword != null && keyAlias != null && keyPassword != null) {
|
||||||
|
storeFile = file(keystorePath)
|
||||||
|
storePassword = keystorePassword
|
||||||
|
this.keyAlias = keyAlias
|
||||||
|
this.keyPassword = keyPassword
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
getByName("debug") {
|
getByName("debug") {
|
||||||
manifestPlaceholders["usesCleartextTraffic"] = "true"
|
manifestPlaceholders["usesCleartextTraffic"] = "true"
|
||||||
@ -43,6 +60,12 @@ android {
|
|||||||
.plus(getDefaultProguardFile("proguard-android-optimize.txt"))
|
.plus(getDefaultProguardFile("proguard-android-optimize.txt"))
|
||||||
.toList().toTypedArray()
|
.toList().toTypedArray()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Sign with release config if available
|
||||||
|
val releaseSigningConfig = signingConfigs.getByName("release")
|
||||||
|
if (releaseSigningConfig.storeFile != null) {
|
||||||
|
signingConfig = releaseSigningConfig
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -1400,10 +1400,10 @@
|
|||||||
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "An empty permission you can use to modify the global scope.",
|
"description": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "fs:scope",
|
"const": "fs:scope",
|
||||||
"markdownDescription": "An empty permission you can use to modify the global scope."
|
"markdownDescription": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
||||||
@ -2270,12 +2270,6 @@
|
|||||||
"Identifier": {
|
"Identifier": {
|
||||||
"description": "Permission identifier",
|
"description": "Permission identifier",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
|
||||||
"description": "Default permissions for the plugin",
|
|
||||||
"type": "string",
|
|
||||||
"const": "android-fs:default",
|
|
||||||
"markdownDescription": "Default permissions for the plugin"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`",
|
"description": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -2283,10 +2277,10 @@
|
|||||||
"markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`"
|
"markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`",
|
"description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "core:app:default",
|
"const": "core:app:default",
|
||||||
"markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`"
|
"markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Enables the app_hide command without any pre-configured scope.",
|
"description": "Enables the app_hide command without any pre-configured scope.",
|
||||||
@ -2330,12 +2324,24 @@
|
|||||||
"const": "core:app:allow-name",
|
"const": "core:app:allow-name",
|
||||||
"markdownDescription": "Enables the name command without any pre-configured scope."
|
"markdownDescription": "Enables the name command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Enables the register_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:allow-register-listener",
|
||||||
|
"markdownDescription": "Enables the register_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Enables the remove_data_store command without any pre-configured scope.",
|
"description": "Enables the remove_data_store command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "core:app:allow-remove-data-store",
|
"const": "core:app:allow-remove-data-store",
|
||||||
"markdownDescription": "Enables the remove_data_store command without any pre-configured scope."
|
"markdownDescription": "Enables the remove_data_store command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Enables the remove_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:allow-remove-listener",
|
||||||
|
"markdownDescription": "Enables the remove_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Enables the set_app_theme command without any pre-configured scope.",
|
"description": "Enables the set_app_theme command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -2402,12 +2408,24 @@
|
|||||||
"const": "core:app:deny-name",
|
"const": "core:app:deny-name",
|
||||||
"markdownDescription": "Denies the name command without any pre-configured scope."
|
"markdownDescription": "Denies the name command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Denies the register_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:deny-register-listener",
|
||||||
|
"markdownDescription": "Denies the register_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Denies the remove_data_store command without any pre-configured scope.",
|
"description": "Denies the remove_data_store command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "core:app:deny-remove-data-store",
|
"const": "core:app:deny-remove-data-store",
|
||||||
"markdownDescription": "Denies the remove_data_store command without any pre-configured scope."
|
"markdownDescription": "Denies the remove_data_store command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Denies the remove_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:deny-remove-listener",
|
||||||
|
"markdownDescription": "Denies the remove_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Denies the set_app_theme command without any pre-configured scope.",
|
"description": "Denies the set_app_theme command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -5547,10 +5565,10 @@
|
|||||||
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "An empty permission you can use to modify the global scope.",
|
"description": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "fs:scope",
|
"const": "fs:scope",
|
||||||
"markdownDescription": "An empty permission you can use to modify the global scope."
|
"markdownDescription": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
{"default":{"identifier":"default","description":"Capability for the main window","local":true,"windows":["main"],"permissions":["core:default","core:webview:allow-create-webview-window","core:webview:allow-create-webview","core:webview:allow-webview-show","core:webview:default","core:window:allow-create","core:window:allow-get-all-windows","core:window:allow-show","core:window:default","dialog:default","fs:allow-appconfig-read-recursive","fs:allow-appconfig-write-recursive","fs:allow-appdata-read-recursive","fs:allow-appdata-write-recursive","fs:allow-read-file","fs:allow-read-dir","fs:allow-resource-read-recursive","fs:allow-resource-write-recursive","fs:allow-download-read-recursive","fs:allow-download-write-recursive","fs:default","android-fs:default",{"identifier":"fs:scope","allow":[{"path":"**"}]},"http:allow-fetch-send","http:allow-fetch","http:default","notification:allow-create-channel","notification:allow-list-channels","notification:allow-notify","notification:default","opener:allow-open-url","opener:default","os:allow-hostname","os:default","store:default"]}}
|
{"default":{"identifier":"default","description":"Capability for the main window","local":true,"windows":["main"],"permissions":["core:default","core:webview:allow-create-webview-window","core:webview:allow-create-webview","core:webview:allow-webview-show","core:webview:default","core:window:allow-create","core:window:allow-get-all-windows","core:window:allow-show","core:window:default","dialog:default","fs:allow-appconfig-read-recursive","fs:allow-appconfig-write-recursive","fs:allow-appdata-read-recursive","fs:allow-appdata-write-recursive","fs:allow-applocaldata-read-recursive","fs:allow-applocaldata-write-recursive","fs:allow-read-file","fs:allow-write-file","fs:allow-read-dir","fs:allow-mkdir","fs:allow-exists","fs:allow-remove","fs:allow-resource-read-recursive","fs:allow-resource-write-recursive","fs:allow-download-read-recursive","fs:allow-download-write-recursive","fs:allow-temp-read-recursive","fs:allow-temp-write-recursive","fs:default",{"identifier":"fs:scope","allow":[{"path":"**"},{"path":"$TEMP/**"}]},"http:allow-fetch-send","http:allow-fetch","http:default","notification:allow-create-channel","notification:allow-list-channels","notification:allow-notify","notification:allow-is-permission-granted","notification:default","opener:allow-open-url",{"identifier":"opener:allow-open-path","allow":[{"path":"$TEMP/**"}]},"opener:default","os:allow-hostname","os:default","store:default"]},"extensions":{"identifier":"extensions","description":"Minimal capability for extension webviews - extensions have NO direct system access","remote":{"urls":["http://localhost:*","haex-extension://*"]},"local":true,"webviews":["ext_*"],"permissions":["core:default","core:webview:default","notification:default","notification:allow-is-permission-granted"]}}
|
||||||
@ -1400,10 +1400,10 @@
|
|||||||
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "An empty permission you can use to modify the global scope.",
|
"description": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "fs:scope",
|
"const": "fs:scope",
|
||||||
"markdownDescription": "An empty permission you can use to modify the global scope."
|
"markdownDescription": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
||||||
@ -2270,12 +2270,6 @@
|
|||||||
"Identifier": {
|
"Identifier": {
|
||||||
"description": "Permission identifier",
|
"description": "Permission identifier",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
|
||||||
"description": "Default permissions for the plugin",
|
|
||||||
"type": "string",
|
|
||||||
"const": "android-fs:default",
|
|
||||||
"markdownDescription": "Default permissions for the plugin"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`",
|
"description": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -2283,10 +2277,10 @@
|
|||||||
"markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`"
|
"markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`",
|
"description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "core:app:default",
|
"const": "core:app:default",
|
||||||
"markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`"
|
"markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Enables the app_hide command without any pre-configured scope.",
|
"description": "Enables the app_hide command without any pre-configured scope.",
|
||||||
@ -2330,12 +2324,24 @@
|
|||||||
"const": "core:app:allow-name",
|
"const": "core:app:allow-name",
|
||||||
"markdownDescription": "Enables the name command without any pre-configured scope."
|
"markdownDescription": "Enables the name command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Enables the register_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:allow-register-listener",
|
||||||
|
"markdownDescription": "Enables the register_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Enables the remove_data_store command without any pre-configured scope.",
|
"description": "Enables the remove_data_store command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "core:app:allow-remove-data-store",
|
"const": "core:app:allow-remove-data-store",
|
||||||
"markdownDescription": "Enables the remove_data_store command without any pre-configured scope."
|
"markdownDescription": "Enables the remove_data_store command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Enables the remove_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:allow-remove-listener",
|
||||||
|
"markdownDescription": "Enables the remove_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Enables the set_app_theme command without any pre-configured scope.",
|
"description": "Enables the set_app_theme command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -2402,12 +2408,24 @@
|
|||||||
"const": "core:app:deny-name",
|
"const": "core:app:deny-name",
|
||||||
"markdownDescription": "Denies the name command without any pre-configured scope."
|
"markdownDescription": "Denies the name command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Denies the register_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:deny-register-listener",
|
||||||
|
"markdownDescription": "Denies the register_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Denies the remove_data_store command without any pre-configured scope.",
|
"description": "Denies the remove_data_store command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "core:app:deny-remove-data-store",
|
"const": "core:app:deny-remove-data-store",
|
||||||
"markdownDescription": "Denies the remove_data_store command without any pre-configured scope."
|
"markdownDescription": "Denies the remove_data_store command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Denies the remove_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:deny-remove-listener",
|
||||||
|
"markdownDescription": "Denies the remove_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Denies the set_app_theme command without any pre-configured scope.",
|
"description": "Denies the set_app_theme command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -5547,10 +5565,10 @@
|
|||||||
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "An empty permission you can use to modify the global scope.",
|
"description": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "fs:scope",
|
"const": "fs:scope",
|
||||||
"markdownDescription": "An empty permission you can use to modify the global scope."
|
"markdownDescription": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
||||||
|
|||||||
@ -1400,10 +1400,10 @@
|
|||||||
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "An empty permission you can use to modify the global scope.",
|
"description": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "fs:scope",
|
"const": "fs:scope",
|
||||||
"markdownDescription": "An empty permission you can use to modify the global scope."
|
"markdownDescription": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
||||||
@ -2270,12 +2270,6 @@
|
|||||||
"Identifier": {
|
"Identifier": {
|
||||||
"description": "Permission identifier",
|
"description": "Permission identifier",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
|
||||||
"description": "Default permissions for the plugin",
|
|
||||||
"type": "string",
|
|
||||||
"const": "android-fs:default",
|
|
||||||
"markdownDescription": "Default permissions for the plugin"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`",
|
"description": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -2283,10 +2277,10 @@
|
|||||||
"markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`"
|
"markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`",
|
"description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "core:app:default",
|
"const": "core:app:default",
|
||||||
"markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`"
|
"markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Enables the app_hide command without any pre-configured scope.",
|
"description": "Enables the app_hide command without any pre-configured scope.",
|
||||||
@ -2330,12 +2324,24 @@
|
|||||||
"const": "core:app:allow-name",
|
"const": "core:app:allow-name",
|
||||||
"markdownDescription": "Enables the name command without any pre-configured scope."
|
"markdownDescription": "Enables the name command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Enables the register_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:allow-register-listener",
|
||||||
|
"markdownDescription": "Enables the register_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Enables the remove_data_store command without any pre-configured scope.",
|
"description": "Enables the remove_data_store command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "core:app:allow-remove-data-store",
|
"const": "core:app:allow-remove-data-store",
|
||||||
"markdownDescription": "Enables the remove_data_store command without any pre-configured scope."
|
"markdownDescription": "Enables the remove_data_store command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Enables the remove_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:allow-remove-listener",
|
||||||
|
"markdownDescription": "Enables the remove_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Enables the set_app_theme command without any pre-configured scope.",
|
"description": "Enables the set_app_theme command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -2402,12 +2408,24 @@
|
|||||||
"const": "core:app:deny-name",
|
"const": "core:app:deny-name",
|
||||||
"markdownDescription": "Denies the name command without any pre-configured scope."
|
"markdownDescription": "Denies the name command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Denies the register_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:deny-register-listener",
|
||||||
|
"markdownDescription": "Denies the register_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Denies the remove_data_store command without any pre-configured scope.",
|
"description": "Denies the remove_data_store command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "core:app:deny-remove-data-store",
|
"const": "core:app:deny-remove-data-store",
|
||||||
"markdownDescription": "Denies the remove_data_store command without any pre-configured scope."
|
"markdownDescription": "Denies the remove_data_store command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Denies the remove_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:deny-remove-listener",
|
||||||
|
"markdownDescription": "Denies the remove_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Denies the set_app_theme command without any pre-configured scope.",
|
"description": "Denies the set_app_theme command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -5547,10 +5565,10 @@
|
|||||||
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "An empty permission you can use to modify the global scope.",
|
"description": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "fs:scope",
|
"const": "fs:scope",
|
||||||
"markdownDescription": "An empty permission you can use to modify the global scope."
|
"markdownDescription": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
||||||
|
|||||||
@ -1400,10 +1400,10 @@
|
|||||||
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "An empty permission you can use to modify the global scope.",
|
"description": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "fs:scope",
|
"const": "fs:scope",
|
||||||
"markdownDescription": "An empty permission you can use to modify the global scope."
|
"markdownDescription": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
||||||
@ -2270,12 +2270,6 @@
|
|||||||
"Identifier": {
|
"Identifier": {
|
||||||
"description": "Permission identifier",
|
"description": "Permission identifier",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
|
||||||
"description": "Default permissions for the plugin",
|
|
||||||
"type": "string",
|
|
||||||
"const": "android-fs:default",
|
|
||||||
"markdownDescription": "Default permissions for the plugin"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`",
|
"description": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -2283,10 +2277,10 @@
|
|||||||
"markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`"
|
"markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`",
|
"description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "core:app:default",
|
"const": "core:app:default",
|
||||||
"markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`"
|
"markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Enables the app_hide command without any pre-configured scope.",
|
"description": "Enables the app_hide command without any pre-configured scope.",
|
||||||
@ -2330,12 +2324,24 @@
|
|||||||
"const": "core:app:allow-name",
|
"const": "core:app:allow-name",
|
||||||
"markdownDescription": "Enables the name command without any pre-configured scope."
|
"markdownDescription": "Enables the name command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Enables the register_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:allow-register-listener",
|
||||||
|
"markdownDescription": "Enables the register_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Enables the remove_data_store command without any pre-configured scope.",
|
"description": "Enables the remove_data_store command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "core:app:allow-remove-data-store",
|
"const": "core:app:allow-remove-data-store",
|
||||||
"markdownDescription": "Enables the remove_data_store command without any pre-configured scope."
|
"markdownDescription": "Enables the remove_data_store command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Enables the remove_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:allow-remove-listener",
|
||||||
|
"markdownDescription": "Enables the remove_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Enables the set_app_theme command without any pre-configured scope.",
|
"description": "Enables the set_app_theme command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -2402,12 +2408,24 @@
|
|||||||
"const": "core:app:deny-name",
|
"const": "core:app:deny-name",
|
||||||
"markdownDescription": "Denies the name command without any pre-configured scope."
|
"markdownDescription": "Denies the name command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Denies the register_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:deny-register-listener",
|
||||||
|
"markdownDescription": "Denies the register_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Denies the remove_data_store command without any pre-configured scope.",
|
"description": "Denies the remove_data_store command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "core:app:deny-remove-data-store",
|
"const": "core:app:deny-remove-data-store",
|
||||||
"markdownDescription": "Denies the remove_data_store command without any pre-configured scope."
|
"markdownDescription": "Denies the remove_data_store command without any pre-configured scope."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Denies the remove_listener command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "core:app:deny-remove-listener",
|
||||||
|
"markdownDescription": "Denies the remove_listener command without any pre-configured scope."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Denies the set_app_theme command without any pre-configured scope.",
|
"description": "Denies the set_app_theme command without any pre-configured scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -5547,10 +5565,10 @@
|
|||||||
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "An empty permission you can use to modify the global scope.",
|
"description": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "fs:scope",
|
"const": "fs:scope",
|
||||||
"markdownDescription": "An empty permission you can use to modify the global scope."
|
"markdownDescription": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
"description": "This scope permits access to all files and list content of top level directories in the application folders.",
|
||||||
|
|||||||
76
src-tauri/generator/event_names.rs
Normal file
76
src-tauri/generator/event_names.rs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// src-tauri/generator/event_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 EventNames {
|
||||||
|
extension: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_event_names() {
|
||||||
|
let out_dir = env::var("OUT_DIR").expect("OUT_DIR ist nicht gesetzt.");
|
||||||
|
println!("Generiere Event-Namen nach {out_dir}");
|
||||||
|
let events_path = Path::new("../src/constants/eventNames.json");
|
||||||
|
let dest_path = Path::new(&out_dir).join("eventNames.rs");
|
||||||
|
|
||||||
|
let file = File::open(events_path).expect("Konnte eventNames.json nicht öffnen");
|
||||||
|
let reader = BufReader::new(file);
|
||||||
|
let events: EventNames =
|
||||||
|
serde_json::from_reader(reader).expect("Konnte eventNames.json nicht parsen");
|
||||||
|
|
||||||
|
let mut code = String::from(
|
||||||
|
r#"
|
||||||
|
// ==================================================================
|
||||||
|
// HINWEIS: Diese Datei wurde automatisch von build.rs generiert.
|
||||||
|
// Manuelle Änderungen werden bei der nächsten Kompilierung überschrieben!
|
||||||
|
// ==================================================================
|
||||||
|
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Extension Events
|
||||||
|
code.push_str("// --- Extension Events ---\n");
|
||||||
|
for (key, value) in &events.extension {
|
||||||
|
let const_name = format!("EVENT_EXTENSION_{}", to_screaming_snake_case(key));
|
||||||
|
code.push_str(&format!(
|
||||||
|
"pub const {}: &str = \"{}\";\n",
|
||||||
|
const_name, value
|
||||||
|
));
|
||||||
|
}
|
||||||
|
code.push('\n');
|
||||||
|
|
||||||
|
// --- 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=../src/constants/eventNames.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Konvertiert einen String zu SCREAMING_SNAKE_CASE
|
||||||
|
fn to_screaming_snake_case(s: &str) -> String {
|
||||||
|
let mut result = String::new();
|
||||||
|
let mut prev_is_lower = false;
|
||||||
|
|
||||||
|
for (i, ch) in s.chars().enumerate() {
|
||||||
|
if ch == '_' {
|
||||||
|
result.push('_');
|
||||||
|
prev_is_lower = false;
|
||||||
|
} else if ch.is_uppercase() {
|
||||||
|
if i > 0 && prev_is_lower {
|
||||||
|
result.push('_');
|
||||||
|
}
|
||||||
|
result.push(ch);
|
||||||
|
prev_is_lower = false;
|
||||||
|
} else {
|
||||||
|
result.push(ch.to_ascii_uppercase());
|
||||||
|
prev_is_lower = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
4
src-tauri/generator/mod.rs
Normal file
4
src-tauri/generator/mod.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// build/mod.rs
|
||||||
|
pub mod event_names;
|
||||||
|
pub mod rust_types;
|
||||||
|
pub mod table_names;
|
||||||
24
src-tauri/generator/rust_types.rs
Normal file
24
src-tauri/generator/rust_types.rs
Normal 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");
|
||||||
|
}
|
||||||
117
src-tauri/generator/table_names.rs
Normal file
117
src-tauri/generator/table_names.rs
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
// src-tarui/src/build/table_names.rs
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde_json::Value;
|
||||||
|
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: HashMap<String, Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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("../src/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 mut code = String::from(
|
||||||
|
r#"
|
||||||
|
// ==================================================================
|
||||||
|
// HINWEIS: Diese Datei wurde automatisch von build.rs generiert.
|
||||||
|
// Manuelle Änderungen werden bei der nächsten Kompilierung überschrieben!
|
||||||
|
// ==================================================================
|
||||||
|
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Dynamisch über alle Einträge in haex iterieren
|
||||||
|
for (key, value) in &schema.haex {
|
||||||
|
// Spezialbehandlung für nested structures wie "crdt"
|
||||||
|
if key == "crdt" {
|
||||||
|
if let Some(crdt_obj) = value.as_object() {
|
||||||
|
for (crdt_key, crdt_value) in crdt_obj {
|
||||||
|
if let Ok(table) = serde_json::from_value::<TableDefinition>(crdt_value.clone())
|
||||||
|
{
|
||||||
|
let const_prefix = format!("CRDT_{}", to_screaming_snake_case(crdt_key));
|
||||||
|
code.push_str(&generate_table_constants(&table, &const_prefix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Normale Tabelle (settings, extensions, notifications, workspaces, desktop_items, etc.)
|
||||||
|
if let Ok(table) = serde_json::from_value::<TableDefinition>(value.clone()) {
|
||||||
|
let const_prefix = to_screaming_snake_case(key);
|
||||||
|
code.push_str(&generate_table_constants(&table, &const_prefix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 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=../src/database/tableNames.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Konvertiert einen String zu SCREAMING_SNAKE_CASE
|
||||||
|
fn to_screaming_snake_case(s: &str) -> String {
|
||||||
|
let mut result = String::new();
|
||||||
|
let mut prev_is_lower = false;
|
||||||
|
|
||||||
|
for (i, ch) in s.chars().enumerate() {
|
||||||
|
if ch == '_' {
|
||||||
|
result.push('_');
|
||||||
|
prev_is_lower = false;
|
||||||
|
} else if ch.is_uppercase() {
|
||||||
|
if i > 0 && prev_is_lower {
|
||||||
|
result.push('_');
|
||||||
|
}
|
||||||
|
result.push(ch);
|
||||||
|
prev_is_lower = false;
|
||||||
|
} else {
|
||||||
|
result.push(ch.to_ascii_uppercase());
|
||||||
|
prev_is_lower = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generiert die Konstanten für eine Tabelle
|
||||||
|
fn generate_table_constants(table: &TableDefinition, const_prefix: &str) -> String {
|
||||||
|
let mut code = String::new();
|
||||||
|
|
||||||
|
// Tabellenname
|
||||||
|
code.push_str(&format!("// --- Table: {} ---\n", table.name));
|
||||||
|
code.push_str(&format!(
|
||||||
|
"pub const TABLE_{}: &str = \"{}\";\n",
|
||||||
|
const_prefix, table.name
|
||||||
|
));
|
||||||
|
|
||||||
|
// Spalten
|
||||||
|
for (col_key, col_value) in &table.columns {
|
||||||
|
let col_const_name = format!("COL_{}_{}", const_prefix, to_screaming_snake_case(col_key));
|
||||||
|
code.push_str(&format!(
|
||||||
|
"pub const {col_const_name}: &str = \"{col_value}\";\n"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
code.push('\n');
|
||||||
|
code
|
||||||
|
}
|
||||||
@ -1,94 +0,0 @@
|
|||||||
#[cfg(target_os = "android")]
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn request_storage_permission(app_handle: tauri::AppHandle) -> Result<String, String> {
|
|
||||||
Ok("Settings opened - Enable 'Allow management of all files'".to_string())
|
|
||||||
/* use tauri_plugin_opener::OpenerExt;
|
|
||||||
|
|
||||||
// Korrekte Android Settings Intent
|
|
||||||
let intent_uri = "android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION";
|
|
||||||
|
|
||||||
match app.opener().open_url(intent_uri, None::<&str>) {
|
|
||||||
Ok(_) => Ok("Settings opened - Enable 'Allow management of all files'".to_string()),
|
|
||||||
Err(_) => {
|
|
||||||
// Fallback: App-spezifische Settings
|
|
||||||
let app_settings = format!(
|
|
||||||
"android.settings.APPLICATION_DETAILS_SETTINGS?package={}",
|
|
||||||
app.config().identifier
|
|
||||||
);
|
|
||||||
match app.opener().open_url(&app_settings, None::<&str>) {
|
|
||||||
Ok(_) => Ok("App settings opened - Go to Permissions > Files and media".to_string()),
|
|
||||||
Err(_) => Ok("Manually go to: Settings > Apps > Special app access > All files access > HaexHub > Allow".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn has_storage_permission() -> Result<bool, String> {
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
// Teste Schreibzugriff auf externen Speicher
|
|
||||||
let test_paths = [
|
|
||||||
"/storage/emulated/0/Android",
|
|
||||||
"/sdcard/Android",
|
|
||||||
"/storage/emulated/0",
|
|
||||||
];
|
|
||||||
|
|
||||||
for path in &test_paths {
|
|
||||||
if Path::new(path).exists() {
|
|
||||||
// Versuche Testdatei zu erstellen
|
|
||||||
let test_file = format!("{}/haex_test.tmp", path);
|
|
||||||
match std::fs::write(&test_file, "test") {
|
|
||||||
Ok(_) => {
|
|
||||||
let _ = std::fs::remove_file(&test_file);
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
Err(_) => continue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn get_external_storage_paths() -> Result<Vec<String>, String> {
|
|
||||||
let mut paths = Vec::new();
|
|
||||||
|
|
||||||
let common_paths = [
|
|
||||||
"/storage/emulated/0",
|
|
||||||
"/sdcard",
|
|
||||||
"/storage/emulated/0/Download",
|
|
||||||
"/storage/emulated/0/Documents",
|
|
||||||
"/storage/emulated/0/Pictures",
|
|
||||||
"/storage/emulated/0/DCIM",
|
|
||||||
];
|
|
||||||
|
|
||||||
for path in &common_paths {
|
|
||||||
if std::path::Path::new(path).exists() {
|
|
||||||
paths.push(path.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(paths)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn request_storage_permission(_app: tauri::AppHandle) -> Result<String, String> {
|
|
||||||
Ok("aaaaaaaa".to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn has_storage_permission() -> Result<bool, String> {
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn get_external_storage_paths() -> Result<Vec<String>, String> {
|
|
||||||
Ok(vec![])
|
|
||||||
}
|
|
||||||
@ -1,285 +0,0 @@
|
|||||||
//mod middleware;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use tauri::{webview, AppHandle, LogicalPosition, LogicalSize, Manager, WebviewUrl, Window};
|
|
||||||
//use uuid::Uuid;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Tab {
|
|
||||||
pub id: String,
|
|
||||||
pub webview_label: String,
|
|
||||||
pub title: String,
|
|
||||||
pub url: String,
|
|
||||||
pub is_loading: bool,
|
|
||||||
pub is_visible: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BrowserManager {
|
|
||||||
tabs: Arc<Mutex<HashMap<String, Tab>>>,
|
|
||||||
active_tab_id: Arc<Mutex<Option<String>>>,
|
|
||||||
//middleware: Arc<RoutingMiddleware>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BrowserManager {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
tabs: Arc::new(Mutex::new(HashMap::new())),
|
|
||||||
active_tab_id: Arc::new(Mutex::new(None)),
|
|
||||||
//middleware: Arc::new(RoutingMiddleware::new()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pub async fn create_window(app: tauri::AppHandle) -> Result<tauri::WebviewWindow, _> {
|
|
||||||
let webview_window = tauri::WebviewWindowBuilder::new(
|
|
||||||
&app,
|
|
||||||
"label",
|
|
||||||
tauri::WebviewUrl::App("index.html".into()),
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
Ok(webview_window);
|
|
||||||
} */
|
|
||||||
pub fn create_tab(&self, app: AppHandle, url: &str) {
|
|
||||||
// Generiere eine eindeutige ID für den Tab
|
|
||||||
/* let tab_id = Uuid::new_v4().to_string();
|
|
||||||
let webview_label = format!("webview-{}", tab_id); */
|
|
||||||
|
|
||||||
// Überprüfe URL mit Middleware
|
|
||||||
//let processed_url = self.middleware.process_url(url);
|
|
||||||
|
|
||||||
// Hole das Hauptfenster
|
|
||||||
let main_window = app.get_webview_window("main").unwrap();
|
|
||||||
|
|
||||||
// Berechne die Position und Größe für den Webview
|
|
||||||
// Hier nehmen wir an, dass wir einen Header-Bereich von 100 Pixeln haben
|
|
||||||
/* let window_size = main_window.inner_size()?;
|
|
||||||
let header_height = 100.0;
|
|
||||||
let webview_position = LogicalPosition::new(0.0, header_height);
|
|
||||||
let webview_size = LogicalSize::new(window_size.width, window_size.height - header_height);
|
|
||||||
*/
|
|
||||||
/* let webview = tauri::WebviewWindowBuilder::new(
|
|
||||||
&app,
|
|
||||||
"label",
|
|
||||||
//WebviewUrl::External(processed_url.parse().unwrap()),
|
|
||||||
WebviewUrl::External(url),
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
.unwrap() */
|
|
||||||
/* .on_navigation(move |url| {
|
|
||||||
// Middleware für Navigation anwenden
|
|
||||||
self.middleware.process_navigation(url.as_str())
|
|
||||||
})
|
|
||||||
.on_web_resource_request(move |request, response| {
|
|
||||||
// Middleware für HTTP-Anfragen anwenden
|
|
||||||
self.middleware.process_request(request, response)
|
|
||||||
}); */
|
|
||||||
|
|
||||||
// Erstelle Tab-Objekt
|
|
||||||
/* let tab = Tab {
|
|
||||||
id: tab_id.clone(),
|
|
||||||
webview_label: webview_label.clone(),
|
|
||||||
title: "Neuer Tab".to_string(),
|
|
||||||
url: processed_url.to_string(),
|
|
||||||
is_loading: true,
|
|
||||||
is_visible: false,
|
|
||||||
}; */
|
|
||||||
|
|
||||||
// Speichere Tab
|
|
||||||
/* {
|
|
||||||
let mut tabs = self.tabs.lock().unwrap();
|
|
||||||
tabs.insert(tab_id.clone(), tab.clone());
|
|
||||||
} */
|
|
||||||
|
|
||||||
// Setze als aktiven Tab
|
|
||||||
//self.activate_tab(app, &tab_id)?;
|
|
||||||
|
|
||||||
// Injiziere die Webview-Bridge
|
|
||||||
/* let script = include_str!("../assets/webview-bridge.js");
|
|
||||||
webview.evaluate_script(script)?; */
|
|
||||||
|
|
||||||
// Registriere Event-Handler für Titeländerungen
|
|
||||||
let tab_manager = self.clone();
|
|
||||||
//let tab_id_clone = tab_id.clone();
|
|
||||||
/* webview.listen("tauri://title-changed", move |event| {
|
|
||||||
if let Some(title) = event.payload().and_then(|p| p.as_str()) {
|
|
||||||
tab_manager.update_tab_title(&tab_id_clone, title);
|
|
||||||
}
|
|
||||||
}); */
|
|
||||||
|
|
||||||
// Registriere Event-Handler für Ladestatus
|
|
||||||
let tab_manager = self.clone();
|
|
||||||
//let tab_id_clone = tab_id.clone();
|
|
||||||
/* webview.listen("tauri://load-changed", move |event| {
|
|
||||||
if let Some(status) = event.payload().and_then(|p| p.as_str()) {
|
|
||||||
let is_loading = status == "loading";
|
|
||||||
tab_manager.update_tab_loading_status(&tab_id_clone, is_loading);
|
|
||||||
}
|
|
||||||
}); */
|
|
||||||
|
|
||||||
//Ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn close_tab(&self, app: &AppHandle, tab_id: &str) -> Result<(), tauri::Error> {
|
|
||||||
// Hole das Hauptfenster
|
|
||||||
let main_window = app.get_webview_window("main").unwrap();
|
|
||||||
|
|
||||||
// Entferne Tab aus der Verwaltung
|
|
||||||
let webview_label = {
|
|
||||||
let mut tabs = self.tabs.lock().unwrap();
|
|
||||||
if let Some(tab) = tabs.remove(tab_id) {
|
|
||||||
tab.webview_label
|
|
||||||
} else {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Entferne den Webview
|
|
||||||
//main_window.remove_child(&webview_label)?;
|
|
||||||
|
|
||||||
// Aktualisiere aktiven Tab, falls nötig
|
|
||||||
{
|
|
||||||
let mut active_tab_id = self.active_tab_id.lock().unwrap();
|
|
||||||
if active_tab_id.as_ref().map_or(false, |id| id == tab_id) {
|
|
||||||
// Wähle einen anderen Tab als aktiv
|
|
||||||
let tabs = self.tabs.lock().unwrap();
|
|
||||||
*active_tab_id = tabs.keys().next().cloned();
|
|
||||||
|
|
||||||
// Aktiviere den neuen Tab, falls vorhanden
|
|
||||||
if let Some(new_active_id) = active_tab_id.clone() {
|
|
||||||
drop(active_tab_id); // Mutex freigeben vor dem rekursiven Aufruf
|
|
||||||
self.activate_tab(app, &new_active_id)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn activate_tab(&self, app: &AppHandle, tab_id: &str) -> Result<(), tauri::Error> {
|
|
||||||
// Hole das Hauptfenster
|
|
||||||
let main_window = app.get_webview_window("main").unwrap();
|
|
||||||
|
|
||||||
// Setze Tab als aktiv
|
|
||||||
{
|
|
||||||
let mut active_tab_id = self.active_tab_id.lock().unwrap();
|
|
||||||
*active_tab_id = Some(tab_id.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verstecke alle anderen Tabs und zeige den aktiven
|
|
||||||
let mut tabs = self.tabs.lock().unwrap();
|
|
||||||
for (id, tab) in tabs.iter_mut() {
|
|
||||||
if id == tab_id {
|
|
||||||
// Zeige den aktiven Tab
|
|
||||||
/* main_window
|
|
||||||
.get_webview_window(&tab.webview_label)?
|
|
||||||
.set_visible(true)?; */
|
|
||||||
tab.is_visible = true;
|
|
||||||
} else {
|
|
||||||
// Verstecke alle anderen Tabs
|
|
||||||
/* main_window
|
|
||||||
.get_webview_window(&tab.webview_label)?
|
|
||||||
.set_visible(false)?; */
|
|
||||||
tab.is_visible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn navigate_to_url(
|
|
||||||
&self,
|
|
||||||
app: &AppHandle,
|
|
||||||
tab_id: &str,
|
|
||||||
url: &str,
|
|
||||||
) -> Result<(), tauri::Error> {
|
|
||||||
// Überprüfe URL mit Middleware
|
|
||||||
//let processed_url = self.middleware.process_url(url);
|
|
||||||
|
|
||||||
// Aktualisiere URL im Tab
|
|
||||||
{
|
|
||||||
let mut tabs = self.tabs.lock().unwrap();
|
|
||||||
if let Some(tab) = tabs.get_mut(tab_id) {
|
|
||||||
tab.url = url.to_string() //processed_url.to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Navigiere zum URL im Webview
|
|
||||||
let tabs = self.tabs.lock().unwrap();
|
|
||||||
if let Some(tab) = tabs.get(tab_id) {
|
|
||||||
let main_window = app.get_webview_window("main").unwrap();
|
|
||||||
/* let webview = main_window.get_webview_window(&tab.webview_label)?;
|
|
||||||
webview.navigate(&processed_url)?; */
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_all_tabs(&self) -> Vec<Tab> {
|
|
||||||
let tabs = self.tabs.lock().unwrap();
|
|
||||||
tabs.values().cloned().collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_active_tab_id(&self) -> Option<String> {
|
|
||||||
let active_tab_id = self.active_tab_id.lock().unwrap();
|
|
||||||
active_tab_id.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_tab_title(&self, tab_id: &str, title: &str) {
|
|
||||||
let mut tabs = self.tabs.lock().unwrap();
|
|
||||||
if let Some(tab) = tabs.get_mut(tab_id) {
|
|
||||||
tab.title = title.to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_tab_loading_status(&self, tab_id: &str, is_loading: bool) {
|
|
||||||
let mut tabs = self.tabs.lock().unwrap();
|
|
||||||
if let Some(tab) = tabs.get_mut(tab_id) {
|
|
||||||
tab.is_loading = is_loading;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Weitere Methoden für Browser-Navigation
|
|
||||||
pub fn go_back(&self, app: &AppHandle, tab_id: &str) -> Result<(), tauri::Error> {
|
|
||||||
let tabs = self.tabs.lock().unwrap();
|
|
||||||
if let Some(tab) = tabs.get(tab_id) {
|
|
||||||
let main_window = app.get_webview_window("main").unwrap();
|
|
||||||
/* let webview = main_window.get_webview(&tab.webview_label)?;
|
|
||||||
webview.evaluate_script("window.history.back()")?; */
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn go_forward(&self, app: &AppHandle, tab_id: &str) -> Result<(), tauri::Error> {
|
|
||||||
let tabs = self.tabs.lock().unwrap();
|
|
||||||
if let Some(tab) = tabs.get(tab_id) {
|
|
||||||
let main_window = app.get_webview_window("main").unwrap();
|
|
||||||
/* let webview = main_window.get_webview(&tab.webview_label)?;
|
|
||||||
webview.evaluate_script("window.history.forward()")?; */
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inject_content_script(
|
|
||||||
&self,
|
|
||||||
app: &AppHandle,
|
|
||||||
tab_id: &str,
|
|
||||||
script: &str,
|
|
||||||
) -> Result<(), tauri::Error> {
|
|
||||||
let tabs = self.tabs.lock().unwrap();
|
|
||||||
if let Some(tab) = tabs.get(tab_id) {
|
|
||||||
let main_window = app.get_webview_window("main").unwrap();
|
|
||||||
/* let webview = main_window.get_webview(&tab.webview_label)?;
|
|
||||||
webview.evaluate_script(script)?; */
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
tabs: Arc::clone(&self.tabs),
|
|
||||||
active_tab_id: Arc::clone(&self.active_tab_id),
|
|
||||||
//middleware: Arc::clone(&self.middleware),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,125 +0,0 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use tauri::http::{Request, Response, ResponseBuilder};
|
|
||||||
|
|
||||||
pub struct RoutingMiddleware {
|
|
||||||
extensions: Arc<Mutex<Vec<Box<dyn MiddlewareExtension + Send + Sync>>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait MiddlewareExtension: Send + Sync {
|
|
||||||
fn name(&self) -> &str;
|
|
||||||
fn process_url(&self, url: &str) -> String;
|
|
||||||
fn process_navigation(&self, url: &str) -> bool;
|
|
||||||
fn process_request(&self, request: &Request, response: &mut Response) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RoutingMiddleware {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let mut middleware = Self {
|
|
||||||
extensions: Arc::new(Mutex::new(Vec::new())),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Registriere Standard-Erweiterungen
|
|
||||||
//middleware.register_extension(Box::new(AdBlockerExtension::new()));
|
|
||||||
|
|
||||||
middleware
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register_extension(&mut self, extension: Box<dyn MiddlewareExtension + Send + Sync>) {
|
|
||||||
let mut extensions = self.extensions.lock().unwrap();
|
|
||||||
extensions.push(extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_url(&self, url: &str) -> String {
|
|
||||||
let extensions = self.extensions.lock().unwrap();
|
|
||||||
let mut processed_url = url.to_string();
|
|
||||||
|
|
||||||
for extension in extensions.iter() {
|
|
||||||
processed_url = extension.process_url(&processed_url);
|
|
||||||
}
|
|
||||||
|
|
||||||
processed_url
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_navigation(&self, url: &str) -> bool {
|
|
||||||
let extensions = self.extensions.lock().unwrap();
|
|
||||||
|
|
||||||
for extension in extensions.iter() {
|
|
||||||
if !extension.process_navigation(url) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_request(&self, request: &Request, response: &mut Response) -> bool {
|
|
||||||
let extensions = self.extensions.lock().unwrap();
|
|
||||||
|
|
||||||
for extension in extensions.iter() {
|
|
||||||
if extension.process_request(request, response) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Beispiel für eine Ad-Blocker-Erweiterung
|
|
||||||
struct AdBlockerExtension {
|
|
||||||
block_patterns: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AdBlockerExtension {
|
|
||||||
fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
block_patterns: vec![
|
|
||||||
"ads".to_string(),
|
|
||||||
"analytics".to_string(),
|
|
||||||
"tracker".to_string(),
|
|
||||||
"banner".to_string(),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_blocked_url(&self, url: &str) -> bool {
|
|
||||||
for pattern in &self.block_patterns {
|
|
||||||
if url.contains(pattern) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MiddlewareExtension for AdBlockerExtension {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"AdBlocker"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_url(&self, url: &str) -> String {
|
|
||||||
// Für vollständige Navigationen blockieren wir normalerweise nicht die ganze Seite
|
|
||||||
url.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_navigation(&self, url: &str) -> bool {
|
|
||||||
// Blockiere nur vollständige Navigationen zu Werbeseiten
|
|
||||||
let is_ad_site = url.contains("doubleclick.net")
|
|
||||||
|| url.contains("googleadservices.com")
|
|
||||||
|| url.contains("ads.example.com");
|
|
||||||
!is_ad_site
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_request(&self, request: &Request, response: &mut Response) -> bool {
|
|
||||||
let url = request.uri().to_string();
|
|
||||||
if self.is_blocked_url(&url) {
|
|
||||||
println!("AdBlocker: Blockiere Anfrage: {}", url);
|
|
||||||
*response = ResponseBuilder::new()
|
|
||||||
.status(403)
|
|
||||||
.body("Zugriff verweigert durch AdBlocker".as_bytes().to_vec())
|
|
||||||
.unwrap();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,188 +0,0 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use tauri::{AppHandle, Manager, State};
|
|
||||||
|
|
||||||
mod manager;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct TabInfo {
|
|
||||||
id: String,
|
|
||||||
title: String,
|
|
||||||
url: String,
|
|
||||||
is_loading: bool,
|
|
||||||
is_active: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Einfache Kommandos für die Tab-Verwaltung
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn create_tab(app_handle: tauri::AppHandle, tab_id: String, url: String) -> Result<(), String> {
|
|
||||||
let main_window = app_handle
|
|
||||||
.get_webview_window("main")
|
|
||||||
.ok_or("Hauptfenster nicht gefunden")?;
|
|
||||||
let window_size = main_window.inner_size().map_err(|e| e.to_string())?;
|
|
||||||
|
|
||||||
// Erstelle eine neue Webview als eigenständiges Fenster
|
|
||||||
let webview = tauri::WebviewWindowBuilder::new(
|
|
||||||
&app_handle,
|
|
||||||
tab_id.clone(),
|
|
||||||
tauri::WebviewUrl::External(url.parse::<tauri::Url>().map_err(|e| e.to_string())?),
|
|
||||||
//tauri::WebviewUrl::External("http://google.de"),
|
|
||||||
)
|
|
||||||
.title(format!("Tab: {}", tab_id))
|
|
||||||
.inner_size(window_size.width as f64, window_size.height as f64 - 50.0)
|
|
||||||
.position(0.0, 50.0)
|
|
||||||
.build()
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
|
|
||||||
// Sende die Tab-ID zurück an das Hauptfenster
|
|
||||||
/* main_window
|
|
||||||
.emit("tab-created", tab_id)
|
|
||||||
.map_err(|e| e.to_string())?; */
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn show_tab(app_handle: tauri::AppHandle, tab_id: String) -> Result<(), String> {
|
|
||||||
// Hole alle Webview-Fenster
|
|
||||||
let windows = app_handle.webview_windows();
|
|
||||||
|
|
||||||
// Zeige das ausgewählte Tab und verstecke die anderen
|
|
||||||
for (id, window) in windows {
|
|
||||||
if id != "main" {
|
|
||||||
// Hauptfenster nicht verstecken
|
|
||||||
if id == tab_id {
|
|
||||||
window.show().map_err(|e| e.to_string())?;
|
|
||||||
window.set_focus().map_err(|e| e.to_string())?;
|
|
||||||
} else {
|
|
||||||
window.hide().map_err(|e| e.to_string())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn close_tab(app_handle: tauri::AppHandle, tab_id: String) -> Result<(), String> {
|
|
||||||
if let Some(window) = app_handle.get_webview_window(&tab_id) {
|
|
||||||
window.close().map_err(|e| e.to_string())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/* #[tauri::command]
|
|
||||||
pub fn create_tab(app: AppHandle, url: String) -> Result<TabInfo, String> {
|
|
||||||
let browser_manager = app.state::<manager::BrowserManager>();
|
|
||||||
|
|
||||||
match browser_manager.create_tab(&app, &url) {
|
|
||||||
Ok(tab) => {
|
|
||||||
let active_tab_id = browser_manager.get_active_tab_id();
|
|
||||||
let is_active = active_tab_id.as_ref().map_or(false, |id| id == &tab.id);
|
|
||||||
|
|
||||||
let main = app.get_webview_window("main");
|
|
||||||
|
|
||||||
//main.unwrap().
|
|
||||||
// Sende Event an Frontend
|
|
||||||
/* app.emit_all(
|
|
||||||
"tab-created",
|
|
||||||
TabInfo {
|
|
||||||
id: tab.id.clone(),
|
|
||||||
title: tab.title.clone(),
|
|
||||||
url: tab.url.clone(),
|
|
||||||
is_loading: tab.is_loading,
|
|
||||||
is_active,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap(); */
|
|
||||||
|
|
||||||
Ok(TabInfo {
|
|
||||||
id: tab.id,
|
|
||||||
title: tab.title,
|
|
||||||
url: tab.url,
|
|
||||||
is_loading: tab.is_loading,
|
|
||||||
is_active: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Err(e) => Err(format!("Fehler beim Erstellen des Tabs: {}", e)),
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* #[tauri::command]
|
|
||||||
pub fn close_tab(app: AppHandle, tab_id: String) -> Result<(), String> {
|
|
||||||
let browser_manager = app.state::<manager::BrowserManager>();
|
|
||||||
|
|
||||||
match browser_manager.close_tab(&app, &tab_id) {
|
|
||||||
Ok(_) => {
|
|
||||||
// Sende Event an Frontend
|
|
||||||
//app.emit_all("tab-closed", tab_id).unwrap();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(e) => Err(format!("Fehler beim Schließen des Tabs: {}", e)),
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn navigate_to_url(app: AppHandle, tab_id: String, url: String) -> Result<(), String> {
|
|
||||||
let browser_manager = app.state::<manager::BrowserManager>();
|
|
||||||
|
|
||||||
match browser_manager.navigate_to_url(&app, &tab_id, &url) {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(e) => Err(format!("Fehler bei der Navigation: {}", e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn get_current_url(app: AppHandle, tab_id: String) -> Result<String, String> {
|
|
||||||
let browser_manager = app.state::<manager::BrowserManager>();
|
|
||||||
let tabs = browser_manager.get_all_tabs();
|
|
||||||
|
|
||||||
for tab in tabs {
|
|
||||||
if tab.id == tab_id {
|
|
||||||
return Ok(tab.url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err("Tab nicht gefunden".to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn go_back(app: AppHandle, tab_id: String) -> Result<(), String> {
|
|
||||||
let browser_manager = app.state::<manager::BrowserManager>();
|
|
||||||
|
|
||||||
match browser_manager.go_back(&app, &tab_id) {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(e) => Err(format!("Fehler beim Zurückgehen: {}", e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn go_forward(app: AppHandle, tab_id: String) -> Result<(), String> {
|
|
||||||
let browser_manager = app.state::<manager::BrowserManager>();
|
|
||||||
|
|
||||||
match browser_manager.go_forward(&app, &tab_id) {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(e) => Err(format!("Fehler beim Vorwärtsgehen: {}", e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn block_resource_request(url: String, resource_type: String) -> bool {
|
|
||||||
// Diese Funktion wird vom Frontend aufgerufen, um zu prüfen, ob eine Ressource blockiert werden soll
|
|
||||||
// Die eigentliche Logik wird im JavaScript-Erweiterungssystem implementiert
|
|
||||||
// Hier könnten Sie zusätzliche Rust-seitige Prüfungen durchführen
|
|
||||||
println!("Prüfe Ressourcenanfrage: {} (Typ: {})", url, resource_type);
|
|
||||||
|
|
||||||
// Einfache Prüfung für Beispielzwecke
|
|
||||||
url.contains("ads") || url.contains("analytics") || url.contains("tracker")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn inject_content_script(app: AppHandle, tab_id: String, script: String) -> Result<(), String> {
|
|
||||||
let browser_manager = app.state::<manager::BrowserManager>();
|
|
||||||
|
|
||||||
match browser_manager.inject_content_script(&app, &tab_id, &script) {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(e) => Err(format!("Fehler beim Injizieren des Scripts: {}", e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,12 +1,17 @@
|
|||||||
// src/hlc_service.rs
|
// src-tauri/src/crdt/hlc.rs
|
||||||
|
|
||||||
use crate::table_names::TABLE_CRDT_CONFIGS;
|
use crate::table_names::TABLE_CRDT_CONFIGS;
|
||||||
use rusqlite::{params, Connection, Result as RusqliteResult, Transaction};
|
use rusqlite::{params, Connection, Transaction};
|
||||||
|
use serde_json::json;
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
|
path::PathBuf,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
use tauri::AppHandle;
|
||||||
|
use tauri_plugin_store::StoreExt;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uhlc::{HLCBuilder, Timestamp, HLC, ID};
|
use uhlc::{HLCBuilder, Timestamp, HLC, ID};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@ -14,8 +19,6 @@ use uuid::Uuid;
|
|||||||
const HLC_NODE_ID_TYPE: &str = "hlc_node_id";
|
const HLC_NODE_ID_TYPE: &str = "hlc_node_id";
|
||||||
const HLC_TIMESTAMP_TYPE: &str = "hlc_timestamp";
|
const HLC_TIMESTAMP_TYPE: &str = "hlc_timestamp";
|
||||||
|
|
||||||
//pub const TABLE_CRDT_CONFIGS: &str = "haex_crdt_settings";
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum HlcError {
|
pub enum HlcError {
|
||||||
#[error("Database error: {0}")]
|
#[error("Database error: {0}")]
|
||||||
@ -24,108 +27,197 @@ pub enum HlcError {
|
|||||||
ParseTimestamp(String),
|
ParseTimestamp(String),
|
||||||
#[error("Failed to parse persisted HLC state: {0}")]
|
#[error("Failed to parse persisted HLC state: {0}")]
|
||||||
Parse(String),
|
Parse(String),
|
||||||
|
#[error("Failed to parse HLC Node ID: {0}")]
|
||||||
|
ParseNodeId(String),
|
||||||
#[error("HLC mutex was poisoned")]
|
#[error("HLC mutex was poisoned")]
|
||||||
MutexPoisoned,
|
MutexPoisoned,
|
||||||
#[error("Failed to create node ID: {0}")]
|
#[error("Failed to create node ID: {0}")]
|
||||||
CreateNodeId(#[from] uhlc::SizeError),
|
CreateNodeId(#[from] uhlc::SizeError),
|
||||||
|
#[error("No database connection available")]
|
||||||
|
NoConnection,
|
||||||
|
#[error("HLC service not initialized")]
|
||||||
|
NotInitialized,
|
||||||
|
#[error("Hex decode error: {0}")]
|
||||||
|
HexDecode(String),
|
||||||
|
#[error("UTF-8 conversion error: {0}")]
|
||||||
|
Utf8Error(String),
|
||||||
|
#[error("Failed to access device store: {0}")]
|
||||||
|
DeviceStore(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<tauri_plugin_store::Error> for HlcError {
|
||||||
|
fn from(error: tauri_plugin_store::Error) -> Self {
|
||||||
|
HlcError::DeviceStore(error.to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A thread-safe, persistent HLC service.
|
/// A thread-safe, persistent HLC service.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct HlcService(Arc<Mutex<HLC>>);
|
pub struct HlcService {
|
||||||
|
hlc: Arc<Mutex<Option<HLC>>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl HlcService {
|
impl HlcService {
|
||||||
/// Creates a new HLC service, initializing it from the database or creating a new
|
/// Creates a new HLC service. The HLC will be initialized on first database access.
|
||||||
/// persistent identity if one does not exist.
|
pub fn new() -> Self {
|
||||||
pub fn new(conn: &mut Connection) -> Result<Self, HlcError> {
|
HlcService {
|
||||||
// 1. Manage persistent node identity.
|
hlc: Arc::new(Mutex::new(None)),
|
||||||
let node_id = Self::get_or_create_node_id(conn)?;
|
|
||||||
|
|
||||||
// 2. Create HLC instance with stable identity using the HLCBuilder.
|
|
||||||
let hlc = HLCBuilder::new()
|
|
||||||
.with_id(node_id)
|
|
||||||
.with_max_delta(Duration::from_secs(1)) // Example of custom configuration
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// 3. Load the last persisted timestamp and update the clock.
|
|
||||||
let last_state_str: RusqliteResult<String> = conn.query_row(
|
|
||||||
&format!("SELECT value FROM {} WHERE key = ?1", TABLE_CRDT_CONFIGS),
|
|
||||||
params![HLC_TIMESTAMP_TYPE],
|
|
||||||
|row| row.get(0),
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Ok(state_str) = last_state_str {
|
|
||||||
let timestamp =
|
|
||||||
Timestamp::from_str(&state_str).map_err(|e| HlcError::ParseTimestamp(e.cause))?;
|
|
||||||
|
|
||||||
// Update the clock with the persisted state.
|
|
||||||
// we might want to handle the error case where the clock drifts too far.
|
|
||||||
hlc.update_with_timestamp(×tamp)
|
|
||||||
.map_err(|e| HlcError::Parse(e.to_string()))?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let hlc_arc = Arc::new(Mutex::new(hlc));
|
|
||||||
Ok(HlcService(hlc_arc))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a new timestamp and immediately persists the HLC's new state.
|
/// Factory-Funktion: Erstellt und initialisiert einen neuen HLC-Service aus einer bestehenden DB-Verbindung.
|
||||||
/// This method MUST be called within an existing database transaction (`tx`)
|
/// Dies ist die bevorzugte Methode zur Instanziierung.
|
||||||
/// along with the actual data operation that this timestamp is for.
|
pub fn try_initialize(conn: &Connection, app_handle: &AppHandle) -> Result<Self, HlcError> {
|
||||||
/// This design ensures atomicity: the data is saved with its timestamp,
|
// 1. Hole oder erstelle eine persistente Node-ID
|
||||||
/// and the clock state is updated, or none of it is.
|
let node_id_str = Self::get_or_create_device_id(app_handle)?;
|
||||||
|
|
||||||
|
// Parse den String in ein Uuid-Objekt.
|
||||||
|
let uuid = Uuid::parse_str(&node_id_str).map_err(|e| {
|
||||||
|
HlcError::ParseNodeId(format!(
|
||||||
|
"Stored device ID is not a valid UUID: {node_id_str}. Error: {e}"
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Hol dir die rohen 16 Bytes und erstelle daraus die uhlc::ID.
|
||||||
|
// Das `*` dereferenziert den `&[u8; 16]` zu `[u8; 16]`, was `try_from` erwartet.
|
||||||
|
let node_id = ID::try_from(*uuid.as_bytes()).map_err(|e| {
|
||||||
|
HlcError::ParseNodeId(format!("Invalid node ID format from device store: {e:?}"))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// 2. Erstelle eine HLC-Instanz mit stabiler Identität
|
||||||
|
let hlc = HLCBuilder::new()
|
||||||
|
.with_id(node_id)
|
||||||
|
.with_max_delta(Duration::from_secs(1))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 3. Lade und wende den letzten persistenten Zeitstempel an
|
||||||
|
if let Some(last_timestamp) = Self::load_last_timestamp(conn)? {
|
||||||
|
hlc.update_with_timestamp(&last_timestamp).map_err(|e| {
|
||||||
|
HlcError::Parse(format!(
|
||||||
|
"Failed to update HLC with persisted timestamp: {e:?}"
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(HlcService {
|
||||||
|
hlc: Arc::new(Mutex::new(Some(hlc))),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Holt die Geräte-ID aus dem Tauri Store oder erstellt eine neue, wenn keine existiert.
|
||||||
|
fn get_or_create_device_id(app_handle: &AppHandle) -> Result<String, HlcError> {
|
||||||
|
let store_path = PathBuf::from("instance.json");
|
||||||
|
let store = app_handle
|
||||||
|
.store(store_path)
|
||||||
|
.map_err(|e| HlcError::DeviceStore(e.to_string()))?;
|
||||||
|
|
||||||
|
let id_exists = match store.get("id") {
|
||||||
|
// Fall 1: Der Schlüssel "id" existiert UND sein Wert ist ein String.
|
||||||
|
Some(value) => {
|
||||||
|
if let Some(s) = value.as_str() {
|
||||||
|
// Das ist unser Erfolgsfall. Wir haben einen &str und können
|
||||||
|
// eine Kopie davon zurückgeben.
|
||||||
|
println!("Gefundene und validierte Geräte-ID: {s}");
|
||||||
|
if Uuid::parse_str(s).is_ok() {
|
||||||
|
// Erfolgsfall: Der Wert ist ein String UND eine gültige UUID.
|
||||||
|
// Wir können die Funktion direkt mit dem Wert verlassen.
|
||||||
|
return Ok(s.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Der Wert existiert, ist aber kein String (z.B. eine Zahl).
|
||||||
|
// Wir behandeln das, als gäbe es keine ID.
|
||||||
|
false
|
||||||
|
}
|
||||||
|
// Fall 2: Der Schlüssel "id" existiert nicht.
|
||||||
|
None => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wenn wir hier ankommen, bedeutet das, `id_exists` ist `false`.
|
||||||
|
// Entweder weil der Schlüssel fehlte oder weil der Wert kein String war.
|
||||||
|
// Also erstellen wir eine neue ID.
|
||||||
|
if !id_exists {
|
||||||
|
let new_id = Uuid::new_v4().to_string();
|
||||||
|
|
||||||
|
store.set("id".to_string(), json!(new_id.clone()));
|
||||||
|
|
||||||
|
store.save()?;
|
||||||
|
|
||||||
|
return Ok(new_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dieser Teil des Codes sollte nie erreicht werden, aber der Compiler
|
||||||
|
// braucht einen finalen return-Wert. Wir können hier einen Fehler werfen.
|
||||||
|
Err(HlcError::DeviceStore(
|
||||||
|
"Unreachable code: Failed to determine device ID".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generiert einen neuen Zeitstempel und persistiert den neuen Zustand des HLC sofort.
|
||||||
|
/// Muss innerhalb einer bestehenden Datenbanktransaktion aufgerufen werden.
|
||||||
pub fn new_timestamp_and_persist<'tx>(
|
pub fn new_timestamp_and_persist<'tx>(
|
||||||
&self,
|
&self,
|
||||||
tx: &Transaction<'tx>,
|
tx: &Transaction<'tx>,
|
||||||
) -> Result<Timestamp, HlcError> {
|
) -> Result<Timestamp, HlcError> {
|
||||||
let hlc = self.0.lock().map_err(|_| HlcError::MutexPoisoned)?;
|
let mut hlc_guard = self.hlc.lock().map_err(|_| HlcError::MutexPoisoned)?;
|
||||||
let new_timestamp = hlc.new_timestamp();
|
let hlc = hlc_guard.as_mut().ok_or(HlcError::NotInitialized)?;
|
||||||
let timestamp_str = new_timestamp.to_string();
|
|
||||||
|
|
||||||
tx.execute(
|
let new_timestamp = hlc.new_timestamp();
|
||||||
&format!(
|
Self::persist_timestamp(tx, &new_timestamp)?;
|
||||||
"INSERT INTO {} (key, value) VALUES (?1,?2)
|
|
||||||
ON CONFLICT(key) DO UPDATE SET value = excluded.value",
|
|
||||||
TABLE_CRDT_CONFIGS
|
|
||||||
),
|
|
||||||
params![HLC_TIMESTAMP_TYPE, timestamp_str],
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(new_timestamp)
|
Ok(new_timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves or creates and persists a stable node ID for the HLC.
|
/// Erstellt einen neuen Zeitstempel, ohne ihn zu persistieren (z.B. für Leseoperationen).
|
||||||
fn get_or_create_node_id(conn: &mut Connection) -> Result<ID, HlcError> {
|
pub fn new_timestamp(&self) -> Result<Timestamp, HlcError> {
|
||||||
let tx = conn.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?;
|
let mut hlc_guard = self.hlc.lock().map_err(|_| HlcError::MutexPoisoned)?;
|
||||||
|
let hlc = hlc_guard.as_mut().ok_or(HlcError::NotInitialized)?;
|
||||||
|
|
||||||
let query = format!("SELECT value FROM {} WHERE key =?1", TABLE_CRDT_CONFIGS);
|
Ok(hlc.new_timestamp())
|
||||||
|
}
|
||||||
|
|
||||||
match tx.query_row(&query, params![HLC_NODE_ID_TYPE], |row| {
|
/// Aktualisiert den HLC mit einem externen Zeitstempel (für die Synchronisation).
|
||||||
|
pub fn update_with_timestamp(&self, timestamp: &Timestamp) -> Result<(), HlcError> {
|
||||||
|
let mut hlc_guard = self.hlc.lock().map_err(|_| HlcError::MutexPoisoned)?;
|
||||||
|
let hlc = hlc_guard.as_mut().ok_or(HlcError::NotInitialized)?;
|
||||||
|
|
||||||
|
hlc.update_with_timestamp(timestamp)
|
||||||
|
.map_err(|e| HlcError::Parse(format!("Failed to update HLC: {e:?}")))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lädt den letzten persistierten Zeitstempel aus der Datenbank.
|
||||||
|
fn load_last_timestamp(conn: &Connection) -> Result<Option<Timestamp>, HlcError> {
|
||||||
|
let query = format!("SELECT value FROM {TABLE_CRDT_CONFIGS} WHERE key = ?1");
|
||||||
|
|
||||||
|
match conn.query_row(&query, params![HLC_TIMESTAMP_TYPE], |row| {
|
||||||
row.get::<_, String>(0)
|
row.get::<_, String>(0)
|
||||||
}) {
|
}) {
|
||||||
Ok(id_str) => {
|
Ok(state_str) => {
|
||||||
// ID exists, parse and return it.
|
let timestamp = Timestamp::from_str(&state_str).map_err(|e| {
|
||||||
let id_bytes = hex::decode(id_str).map_err(|e| HlcError::Parse(e.to_string()))?;
|
HlcError::ParseTimestamp(format!("Invalid timestamp format: {e:?}"))
|
||||||
let id = ID::try_from(id_bytes.as_slice())?;
|
})?;
|
||||||
tx.commit()?;
|
Ok(Some(timestamp))
|
||||||
Ok(id)
|
|
||||||
}
|
}
|
||||||
Err(rusqlite::Error::QueryReturnedNoRows) => {
|
Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
|
||||||
// No ID found, create, persist, and return a new one.
|
Err(e) => Err(HlcError::Database(e)),
|
||||||
let new_id_bytes = Uuid::new_v4().as_bytes().to_vec();
|
|
||||||
let new_id = ID::try_from(new_id_bytes.as_slice())?;
|
|
||||||
let new_id_str = hex::encode(new_id.to_le_bytes());
|
|
||||||
|
|
||||||
tx.execute(
|
|
||||||
&format!(
|
|
||||||
"INSERT INTO {} (key, value) VALUES (?1, ?2)",
|
|
||||||
TABLE_CRDT_CONFIGS
|
|
||||||
),
|
|
||||||
params![HLC_NODE_ID_TYPE, new_id_str],
|
|
||||||
)?;
|
|
||||||
tx.commit()?;
|
|
||||||
Ok(new_id)
|
|
||||||
}
|
|
||||||
Err(e) => Err(HlcError::from(e)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Persistiert einen Zeitstempel in der Datenbank innerhalb einer Transaktion.
|
||||||
|
fn persist_timestamp(tx: &Transaction, timestamp: &Timestamp) -> Result<(), HlcError> {
|
||||||
|
let timestamp_str = timestamp.to_string();
|
||||||
|
tx.execute(
|
||||||
|
&format!(
|
||||||
|
"INSERT INTO {TABLE_CRDT_CONFIGS} (key, value) VALUES (?1, ?2)
|
||||||
|
ON CONFLICT(key) DO UPDATE SET value = excluded.value"
|
||||||
|
),
|
||||||
|
params![HLC_TIMESTAMP_TYPE, timestamp_str],
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for HlcService {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
99
src-tauri/src/crdt/insert_transformer.rs
Normal file
99
src-tauri/src/crdt/insert_transformer.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// src-tauri/src/crdt/insert_transformer.rs
|
||||||
|
// INSERT-spezifische CRDT-Transformationen (ON CONFLICT, RETURNING)
|
||||||
|
|
||||||
|
use crate::crdt::trigger::HLC_TIMESTAMP_COLUMN;
|
||||||
|
use crate::database::error::DatabaseError;
|
||||||
|
use sqlparser::ast::{Expr, Ident, Insert, SelectItem, SetExpr, Value};
|
||||||
|
use uhlc::Timestamp;
|
||||||
|
|
||||||
|
/// Helper-Struct für INSERT-Transformationen
|
||||||
|
pub struct InsertTransformer {
|
||||||
|
hlc_timestamp_column: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InsertTransformer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
hlc_timestamp_column: HLC_TIMESTAMP_COLUMN,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_or_add_column(columns: &mut Vec<Ident>, col_name: &'static str) -> usize {
|
||||||
|
match columns.iter().position(|c| c.value == col_name) {
|
||||||
|
Some(index) => index, // Gefunden! Gib Index zurück.
|
||||||
|
None => {
|
||||||
|
// Nicht gefunden! Hinzufügen.
|
||||||
|
columns.push(Ident::new(col_name));
|
||||||
|
columns.len() - 1 // Der Index des gerade hinzugefügten Elements
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wenn der Index == der Länge ist, wird der Wert stattdessen gepusht.
|
||||||
|
fn set_or_push_value(row: &mut Vec<Expr>, index: usize, value: Expr) {
|
||||||
|
if index < row.len() {
|
||||||
|
// Spalte war vorhanden, Wert (wahrscheinlich `?` oder NULL) ersetzen
|
||||||
|
row[index] = value;
|
||||||
|
} else {
|
||||||
|
// Spalte war nicht vorhanden, Wert hinzufügen
|
||||||
|
row.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_or_push_projection(projection: &mut Vec<SelectItem>, index: usize, value: Expr) {
|
||||||
|
let item = SelectItem::UnnamedExpr(value);
|
||||||
|
if index < projection.len() {
|
||||||
|
projection[index] = item;
|
||||||
|
} else {
|
||||||
|
projection.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transformiert INSERT-Statements (fügt HLC-Timestamp hinzu)
|
||||||
|
/// Hard Delete: Kein ON CONFLICT mehr nötig - gelöschte Einträge sind wirklich weg
|
||||||
|
pub fn transform_insert(
|
||||||
|
&self,
|
||||||
|
insert_stmt: &mut Insert,
|
||||||
|
timestamp: &Timestamp,
|
||||||
|
) -> Result<(), DatabaseError> {
|
||||||
|
// Add haex_timestamp column if not exists
|
||||||
|
let hlc_col_index =
|
||||||
|
Self::find_or_add_column(&mut insert_stmt.columns, self.hlc_timestamp_column);
|
||||||
|
|
||||||
|
// ON CONFLICT Logik komplett entfernt!
|
||||||
|
// Bei Hard Deletes gibt es keine Tombstone-Einträge mehr zu reaktivieren
|
||||||
|
// UNIQUE Constraint Violations sind echte Fehler
|
||||||
|
|
||||||
|
match insert_stmt.source.as_mut() {
|
||||||
|
Some(query) => match &mut *query.body {
|
||||||
|
SetExpr::Values(values) => {
|
||||||
|
for row in &mut values.rows {
|
||||||
|
let hlc_value =
|
||||||
|
Expr::Value(Value::SingleQuotedString(timestamp.to_string()).into());
|
||||||
|
|
||||||
|
Self::set_or_push_value(row, hlc_col_index, hlc_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetExpr::Select(select) => {
|
||||||
|
let hlc_value =
|
||||||
|
Expr::Value(Value::SingleQuotedString(timestamp.to_string()).into());
|
||||||
|
|
||||||
|
Self::set_or_push_projection(&mut select.projection, hlc_col_index, hlc_value);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(DatabaseError::UnsupportedStatement {
|
||||||
|
sql: insert_stmt.to_string(),
|
||||||
|
reason: "INSERT with unsupported source type".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
return Err(DatabaseError::UnsupportedStatement {
|
||||||
|
reason: "INSERT statement has no source".to_string(),
|
||||||
|
sql: insert_stmt.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,5 @@
|
|||||||
pub mod hlc;
|
pub mod hlc;
|
||||||
pub mod proxy;
|
pub mod insert_transformer;
|
||||||
|
//pub mod query_transformer;
|
||||||
|
pub mod transformer;
|
||||||
pub mod trigger;
|
pub mod trigger;
|
||||||
|
|||||||
@ -1,416 +0,0 @@
|
|||||||
// In src-tauri/src/crdt/proxy.rs
|
|
||||||
use crate::crdt::hlc::HlcService;
|
|
||||||
use crate::crdt::trigger::{HLC_TIMESTAMP_COLUMN, TOMBSTONE_COLUMN};
|
|
||||||
use crate::table_names::{TABLE_CRDT_CONFIGS, TABLE_CRDT_LOGS};
|
|
||||||
use rusqlite::Connection;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use serde_json::Value as JsonValue;
|
|
||||||
use sqlparser::ast::{
|
|
||||||
Assignment, AssignmentTarget, BinaryOperator, ColumnDef, DataType, Expr, Ident, Insert,
|
|
||||||
ObjectName, ObjectNamePart, SelectItem, SetExpr, Statement, TableFactor, TableObject,
|
|
||||||
TableWithJoins, UpdateTableFromKind, Value, ValueWithSpan,
|
|
||||||
};
|
|
||||||
use sqlparser::dialect::SQLiteDialect;
|
|
||||||
use sqlparser::parser::Parser;
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use tauri::{path::BaseDirectory, AppHandle, Manager, State};
|
|
||||||
use ts_rs::TS;
|
|
||||||
use uhlc::Timestamp;
|
|
||||||
pub struct DbConnection(pub Arc<Mutex<Option<Connection>>>);
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, TS)]
|
|
||||||
#[ts(export)]
|
|
||||||
#[serde(tag = "type", content = "details")]
|
|
||||||
pub enum ProxyError {
|
|
||||||
/// Der SQL-Code konnte nicht geparst werden.
|
|
||||||
ParseError {
|
|
||||||
reason: String,
|
|
||||||
},
|
|
||||||
/// Ein Fehler ist während der Ausführung in der Datenbank aufgetreten.
|
|
||||||
ExecutionError {
|
|
||||||
sql: String,
|
|
||||||
reason: String,
|
|
||||||
},
|
|
||||||
/// Ein Fehler ist beim Verwalten der Transaktion aufgetreten.
|
|
||||||
TransactionError {
|
|
||||||
reason: String,
|
|
||||||
},
|
|
||||||
/// Ein SQL-Statement wird vom Proxy nicht unterstützt (z.B. DELETE von einer Subquery).
|
|
||||||
UnsupportedStatement {
|
|
||||||
description: String,
|
|
||||||
},
|
|
||||||
HlcError {
|
|
||||||
reason: String,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tabellen, die von der Proxy-Logik ausgeschlossen sind.
|
|
||||||
const EXCLUDED_TABLES: &[&str] = &[TABLE_CRDT_CONFIGS, TABLE_CRDT_LOGS];
|
|
||||||
|
|
||||||
pub struct SqlProxy;
|
|
||||||
|
|
||||||
impl SqlProxy {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Führt SQL-Anweisungen aus, nachdem sie für CRDT-Konformität transformiert wurden.
|
|
||||||
pub fn execute(
|
|
||||||
&self,
|
|
||||||
sql: &str,
|
|
||||||
params: Vec<JsonValue>,
|
|
||||||
state: State<'_, DbConnection>,
|
|
||||||
hlc_service: &HlcService,
|
|
||||||
) -> Result<Vec<String>, ProxyError> {
|
|
||||||
let dialect = SQLiteDialect {};
|
|
||||||
let mut ast_vec = Parser::parse_sql(&dialect, sql).map_err(|e| ProxyError::ParseError {
|
|
||||||
reason: e.to_string(),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let mut modified_schema_tables = HashSet::new();
|
|
||||||
|
|
||||||
let db_lock = state
|
|
||||||
.0
|
|
||||||
.lock()
|
|
||||||
.map_err(|e| format!("Mutex Lock Fehler: {}", e))?;
|
|
||||||
let conn = db_lock.as_ref().ok_or("Keine Datenbankverbindung")?;
|
|
||||||
|
|
||||||
let tx = conn
|
|
||||||
.transaction()
|
|
||||||
.map_err(|e| ProxyError::TransactionError {
|
|
||||||
reason: e.to_string(),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
/* let hlc_timestamp =
|
|
||||||
hlc_service
|
|
||||||
.new_timestamp_and_persist(&tx)
|
|
||||||
.map_err(|e| ProxyError::HlcError {
|
|
||||||
reason: e.to_string(),
|
|
||||||
})?; */
|
|
||||||
|
|
||||||
for statement in &mut ast_vec {
|
|
||||||
if let Some(table_name) = self.transform_statement(statement)? {
|
|
||||||
modified_schema_tables.insert(table_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for statement in ast_vec {
|
|
||||||
let final_sql = statement.to_string();
|
|
||||||
tx.execute(&final_sql, [])
|
|
||||||
.map_err(|e| ProxyError::ExecutionError {
|
|
||||||
sql: final_sql,
|
|
||||||
reason: e.to_string(),
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
tx.commit().map_err(|e| ProxyError::TransactionError {
|
|
||||||
reason: e.to_string(),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(modified_schema_tables.into_iter().collect())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wendet die Transformation auf ein einzelnes Statement an.
|
|
||||||
fn transform_statement(&self, stmt: &mut Statement) -> Result<Option<String>, ProxyError> {
|
|
||||||
match stmt {
|
|
||||||
Statement::Query(query) => {
|
|
||||||
if let SetExpr::Select(select) = &mut *query.body {
|
|
||||||
let mut tombstone_filters = Vec::new();
|
|
||||||
|
|
||||||
for twj in &select.from {
|
|
||||||
if let TableFactor::Table { name, alias, .. } = &twj.relation {
|
|
||||||
if self.is_audited_table(name) {
|
|
||||||
let table_idents = if let Some(a) = alias {
|
|
||||||
vec![a.name.clone()]
|
|
||||||
} else {
|
|
||||||
name.0
|
|
||||||
.iter()
|
|
||||||
.filter_map(|part| match part {
|
|
||||||
ObjectNamePart::Identifier(id) => Some(id.clone()),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
};
|
|
||||||
let column_ident = Ident::new(TOMBSTONE_COLUMN);
|
|
||||||
let full_ident = [table_idents, vec![column_ident]].concat();
|
|
||||||
let filter = Expr::BinaryOp {
|
|
||||||
left: Box::new(Expr::CompoundIdentifier(full_ident)),
|
|
||||||
op: BinaryOperator::Eq,
|
|
||||||
right: Box::new(Expr::Value(
|
|
||||||
sqlparser::ast::Value::Number("1".to_string(), false)
|
|
||||||
.into(),
|
|
||||||
)),
|
|
||||||
};
|
|
||||||
tombstone_filters.push(filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !tombstone_filters.is_empty() {
|
|
||||||
let combined_filter = tombstone_filters
|
|
||||||
.into_iter()
|
|
||||||
.reduce(|acc, expr| Expr::BinaryOp {
|
|
||||||
left: Box::new(acc),
|
|
||||||
op: BinaryOperator::And,
|
|
||||||
right: Box::new(expr),
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
match &mut select.selection {
|
|
||||||
Some(existing) => {
|
|
||||||
*existing = Expr::BinaryOp {
|
|
||||||
left: Box::new(existing.clone()),
|
|
||||||
op: BinaryOperator::And,
|
|
||||||
right: Box::new(combined_filter),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
select.selection = Some(combined_filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: UNION, EXCEPT etc. werden hier nicht behandelt
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::CreateTable(create_table) => {
|
|
||||||
if self.is_audited_table(&create_table.name) {
|
|
||||||
self.add_crdt_columns(&mut create_table.columns);
|
|
||||||
return Ok(Some(
|
|
||||||
create_table
|
|
||||||
.name
|
|
||||||
.to_string()
|
|
||||||
.trim_matches('`')
|
|
||||||
.trim_matches('"')
|
|
||||||
.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::Insert(insert_stmt) => {
|
|
||||||
if let TableObject::TableName(name) = &insert_stmt.table {
|
|
||||||
if self.is_audited_table(name) {
|
|
||||||
self.add_hlc_to_insert(insert_stmt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::Update {
|
|
||||||
table,
|
|
||||||
assignments,
|
|
||||||
from,
|
|
||||||
selection,
|
|
||||||
returning,
|
|
||||||
or,
|
|
||||||
} => {
|
|
||||||
if let TableFactor::Table { name, .. } = &table.relation {
|
|
||||||
if self.is_audited_table(&name) {
|
|
||||||
if let Some(ts) = hlc_timestamp {
|
|
||||||
assignments.push(self.create_hlc_assignment(ts));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*stmt = Statement::Update {
|
|
||||||
table: table.clone(),
|
|
||||||
assignments: assignments.clone(),
|
|
||||||
from: from.clone(),
|
|
||||||
selection: selection.clone(),
|
|
||||||
returning: returning.clone(),
|
|
||||||
or: *or,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::Delete(del_stmt) => {
|
|
||||||
let table_name = self.extract_table_name_from_from(&del_stmt.from);
|
|
||||||
if let Some(name) = table_name {
|
|
||||||
if self.is_audited_table(&name) {
|
|
||||||
// GEÄNDERT: Übergibt den Zeitstempel an die Transformationsfunktion
|
|
||||||
|
|
||||||
self.transform_delete_to_update(stmt);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(ProxyError::UnsupportedStatement {
|
|
||||||
description: "DELETE from non-table source or multiple tables".to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::AlterTable { name, .. } => {
|
|
||||||
if self.is_audited_table(name) {
|
|
||||||
return Ok(Some(
|
|
||||||
name.to_string()
|
|
||||||
.trim_matches('`')
|
|
||||||
.trim_matches('"')
|
|
||||||
.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fügt die Tombstone-Spalte zu einer Liste von Spaltendefinitionen hinzu.
|
|
||||||
fn add_tombstone_column(&self, columns: &mut Vec<ColumnDef>) {
|
|
||||||
if !columns
|
|
||||||
.iter()
|
|
||||||
.any(|c| c.name.value.to_lowercase() == TOMBSTONE_COLUMN)
|
|
||||||
{
|
|
||||||
columns.push(ColumnDef {
|
|
||||||
name: Ident::new(TOMBSTONE_COLUMN),
|
|
||||||
data_type: DataType::Integer(None),
|
|
||||||
options: vec![],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prüft, ob eine Tabelle von der Proxy-Logik betroffen sein soll.
|
|
||||||
fn is_audited_table(&self, name: &ObjectName) -> bool {
|
|
||||||
let table_name = name.to_string().to_lowercase();
|
|
||||||
let table_name = table_name.trim_matches('`').trim_matches('"');
|
|
||||||
!EXCLUDED_TABLES.contains(&table_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_table_name_from_from(&self, from: &sqlparser::ast::FromTable) -> Option<ObjectName> {
|
|
||||||
let tables = match from {
|
|
||||||
sqlparser::ast::FromTable::WithFromKeyword(from)
|
|
||||||
| sqlparser::ast::FromTable::WithoutKeyword(from) => from,
|
|
||||||
};
|
|
||||||
if tables.len() == 1 {
|
|
||||||
if let TableFactor::Table { name, .. } = &tables[0].relation {
|
|
||||||
Some(name.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_table_name(&self, from: &[TableWithJoins]) -> Option<ObjectName> {
|
|
||||||
if from.len() == 1 {
|
|
||||||
if let TableFactor::Table { name, .. } = &from[0].relation {
|
|
||||||
Some(name.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_tombstone_assignment(&self) -> Assignment {
|
|
||||||
Assignment {
|
|
||||||
target: AssignmentTarget::ColumnName(ObjectName(vec![ObjectNamePart::Identifier(
|
|
||||||
Ident::new(TOMBSTONE_COLUMN),
|
|
||||||
)])),
|
|
||||||
value: Expr::Value(sqlparser::ast::Value::Number("1".to_string(), false).into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_tombstone_filter(&self, selection: &mut Option<Expr>) {
|
|
||||||
let tombstone_expr = Expr::BinaryOp {
|
|
||||||
left: Box::new(Expr::Identifier(Ident::new(TOMBSTONE_COLUMN))),
|
|
||||||
op: BinaryOperator::Eq,
|
|
||||||
// HIER IST DIE FINALE KORREKTUR:
|
|
||||||
right: Box::new(Expr::Value(Value::Number("0".to_string(), false).into())),
|
|
||||||
};
|
|
||||||
|
|
||||||
match selection {
|
|
||||||
Some(existing) => {
|
|
||||||
// Kombiniere mit AND, wenn eine WHERE-Klausel existiert
|
|
||||||
*selection = Some(Expr::BinaryOp {
|
|
||||||
left: Box::new(existing.clone()),
|
|
||||||
op: BinaryOperator::And,
|
|
||||||
right: Box::new(tombstone_expr),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// Setze neue WHERE-Klausel, wenn keine existiert
|
|
||||||
*selection = Some(tombstone_expr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_crdt_columns(&self, columns: &mut Vec<ColumnDef>) {
|
|
||||||
if !columns.iter().any(|c| c.name.value == TOMBSTONE_COLUMN) {
|
|
||||||
columns.push(ColumnDef {
|
|
||||||
name: Ident::new(TOMBSTONE_COLUMN),
|
|
||||||
data_type: DataType::Integer(None),
|
|
||||||
options: vec![],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if !columns.iter().any(|c| c.name.value == HLC_TIMESTAMP_COLUMN) {
|
|
||||||
columns.push(ColumnDef {
|
|
||||||
name: Ident::new(HLC_TIMESTAMP_COLUMN),
|
|
||||||
data_type: DataType::String(None),
|
|
||||||
options: vec![],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transform_delete_to_update(&self, stmt: &mut Statement) {
|
|
||||||
if let Statement::Delete(del_stmt) = stmt {
|
|
||||||
let table_to_update = match &del_stmt.from {
|
|
||||||
sqlparser::ast::FromTable::WithFromKeyword(from)
|
|
||||||
| sqlparser::ast::FromTable::WithoutKeyword(from) => from[0].clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let assignments = vec![self.create_tombstone_assignment()];
|
|
||||||
|
|
||||||
*stmt = Statement::Update {
|
|
||||||
table: table_to_update,
|
|
||||||
assignments,
|
|
||||||
from: None,
|
|
||||||
selection: del_stmt.selection.clone(),
|
|
||||||
returning: None,
|
|
||||||
or: None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_hlc_to_insert(
|
|
||||||
&self,
|
|
||||||
insert_stmt: &mut sqlparser::ast::Insert,
|
|
||||||
ts: &Timestamp,
|
|
||||||
) -> Result<(), ProxyError> {
|
|
||||||
insert_stmt.columns.push(Ident::new(HLC_TIMESTAMP_COLUMN));
|
|
||||||
|
|
||||||
match insert_stmt.source.as_mut() {
|
|
||||||
Some(query) => match &mut *query.body {
|
|
||||||
// Dereferenziere die Box mit *
|
|
||||||
SetExpr::Values(values) => {
|
|
||||||
for row in &mut values.rows {
|
|
||||||
row.push(Expr::Value(
|
|
||||||
Value::SingleQuotedString(ts.to_string()).into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SetExpr::Select(select) => {
|
|
||||||
let hlc_expr = Expr::Value(Value::SingleQuotedString(ts.to_string()).into());
|
|
||||||
select.projection.push(SelectItem::UnnamedExpr(hlc_expr));
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(ProxyError::UnsupportedStatement {
|
|
||||||
description: "INSERT with unsupported source".to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
return Err(ProxyError::UnsupportedStatement {
|
|
||||||
description: "INSERT statement has no source".to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// Erstellt eine Zuweisung `haex_modified_hlc = '...'`
|
|
||||||
// NEU: Hilfsfunktion
|
|
||||||
fn create_hlc_assignment(&self, ts: &Timestamp) -> Assignment {
|
|
||||||
Assignment {
|
|
||||||
target: AssignmentTarget::ColumnName(ObjectName(vec![ObjectNamePart::Identifier(
|
|
||||||
Ident::new(HLC_TIMESTAMP_COLUMN),
|
|
||||||
)])),
|
|
||||||
value: Expr::Value(Value::SingleQuotedString(ts.to_string()).into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
187
src-tauri/src/crdt/transformer.rs
Normal file
187
src-tauri/src/crdt/transformer.rs
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
// src-tauri/src/crdt/transformer.rs
|
||||||
|
|
||||||
|
use crate::crdt::insert_transformer::InsertTransformer;
|
||||||
|
use crate::crdt::trigger::HLC_TIMESTAMP_COLUMN;
|
||||||
|
use crate::database::error::DatabaseError;
|
||||||
|
use crate::table_names::{TABLE_CRDT_CONFIGS, TABLE_CRDT_LOGS};
|
||||||
|
use sqlparser::ast::{
|
||||||
|
Assignment, AssignmentTarget, ColumnDef, DataType, Expr, Ident, ObjectName, ObjectNamePart,
|
||||||
|
Statement, TableFactor, TableObject, Value,
|
||||||
|
};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use uhlc::Timestamp;
|
||||||
|
|
||||||
|
/// Konfiguration für CRDT-Spalten
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct CrdtColumns {
|
||||||
|
hlc_timestamp: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CrdtColumns {
|
||||||
|
const DEFAULT: Self = Self {
|
||||||
|
hlc_timestamp: HLC_TIMESTAMP_COLUMN,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Erstellt eine HLC-Zuweisung für UPDATE/DELETE
|
||||||
|
fn create_hlc_assignment(&self, timestamp: &Timestamp) -> Assignment {
|
||||||
|
Assignment {
|
||||||
|
target: AssignmentTarget::ColumnName(ObjectName(vec![ObjectNamePart::Identifier(
|
||||||
|
Ident::new(self.hlc_timestamp),
|
||||||
|
)])),
|
||||||
|
value: Expr::Value(Value::SingleQuotedString(timestamp.to_string()).into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fügt CRDT-Spalten zu einer Tabellendefinition hinzu
|
||||||
|
fn add_to_table_definition(&self, columns: &mut Vec<ColumnDef>) {
|
||||||
|
if !columns.iter().any(|c| c.name.value == self.hlc_timestamp) {
|
||||||
|
columns.push(ColumnDef {
|
||||||
|
name: Ident::new(self.hlc_timestamp),
|
||||||
|
data_type: DataType::String(None),
|
||||||
|
options: vec![],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CrdtTransformer {
|
||||||
|
columns: CrdtColumns,
|
||||||
|
excluded_tables: HashSet<&'static str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CrdtTransformer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut excluded_tables = HashSet::new();
|
||||||
|
excluded_tables.insert(TABLE_CRDT_CONFIGS);
|
||||||
|
excluded_tables.insert(TABLE_CRDT_LOGS);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
columns: CrdtColumns::DEFAULT,
|
||||||
|
excluded_tables,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prüft, ob eine Tabelle CRDT-Synchronisation unterstützen soll
|
||||||
|
fn is_crdt_sync_table(&self, name: &ObjectName) -> bool {
|
||||||
|
let table_name = self.normalize_table_name(name);
|
||||||
|
!self.excluded_tables.contains(table_name.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Normalisiert Tabellennamen (entfernt Anführungszeichen)
|
||||||
|
fn normalize_table_name(&self, name: &ObjectName) -> Cow<str> {
|
||||||
|
let name_str = name.to_string().to_lowercase();
|
||||||
|
Cow::Owned(name_str.trim_matches('`').trim_matches('"').to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
// =================================================================
|
||||||
|
// ÖFFENTLICHE API-METHODEN
|
||||||
|
// =================================================================
|
||||||
|
|
||||||
|
pub fn transform_execute_statement_with_table_info(
|
||||||
|
&self,
|
||||||
|
stmt: &mut Statement,
|
||||||
|
hlc_timestamp: &Timestamp,
|
||||||
|
) -> Result<Option<String>, DatabaseError> {
|
||||||
|
match stmt {
|
||||||
|
Statement::CreateTable(create_table) => {
|
||||||
|
if self.is_crdt_sync_table(&create_table.name) {
|
||||||
|
self.columns
|
||||||
|
.add_to_table_definition(&mut create_table.columns);
|
||||||
|
Ok(Some(
|
||||||
|
self.normalize_table_name(&create_table.name).into_owned(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Statement::Insert(insert_stmt) => {
|
||||||
|
if let TableObject::TableName(name) = &insert_stmt.table {
|
||||||
|
if self.is_crdt_sync_table(name) {
|
||||||
|
// Hard Delete: Kein Schema-Lookup mehr nötig (kein ON CONFLICT)
|
||||||
|
let insert_transformer = InsertTransformer::new();
|
||||||
|
insert_transformer.transform_insert(insert_stmt, hlc_timestamp)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
Statement::Update {
|
||||||
|
table, assignments, ..
|
||||||
|
} => {
|
||||||
|
if let TableFactor::Table { name, .. } = &table.relation {
|
||||||
|
if self.is_crdt_sync_table(name) {
|
||||||
|
assignments.push(self.columns.create_hlc_assignment(hlc_timestamp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
Statement::Delete(_del_stmt) => {
|
||||||
|
// Hard Delete - keine Transformation!
|
||||||
|
// DELETE bleibt DELETE
|
||||||
|
// BEFORE DELETE Trigger schreiben die Logs
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
Statement::AlterTable { name, .. } => {
|
||||||
|
if self.is_crdt_sync_table(name) {
|
||||||
|
Ok(Some(self.normalize_table_name(name).into_owned()))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_execute_statement(
|
||||||
|
&self,
|
||||||
|
stmt: &mut Statement,
|
||||||
|
hlc_timestamp: &Timestamp,
|
||||||
|
) -> Result<Option<String>, DatabaseError> {
|
||||||
|
match stmt {
|
||||||
|
Statement::CreateTable(create_table) => {
|
||||||
|
if self.is_crdt_sync_table(&create_table.name) {
|
||||||
|
self.columns
|
||||||
|
.add_to_table_definition(&mut create_table.columns);
|
||||||
|
Ok(Some(
|
||||||
|
self.normalize_table_name(&create_table.name).into_owned(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Statement::Insert(insert_stmt) => {
|
||||||
|
if let TableObject::TableName(name) = &insert_stmt.table {
|
||||||
|
if self.is_crdt_sync_table(name) {
|
||||||
|
// Hard Delete: Keine ON CONFLICT Logik mehr nötig
|
||||||
|
let insert_transformer = InsertTransformer::new();
|
||||||
|
insert_transformer.transform_insert(insert_stmt, hlc_timestamp)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
Statement::Update {
|
||||||
|
table, assignments, ..
|
||||||
|
} => {
|
||||||
|
if let TableFactor::Table { name, .. } = &table.relation {
|
||||||
|
if self.is_crdt_sync_table(name) {
|
||||||
|
assignments.push(self.columns.create_hlc_assignment(hlc_timestamp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
Statement::Delete(_del_stmt) => {
|
||||||
|
// Hard Delete - keine Transformation!
|
||||||
|
// DELETE bleibt DELETE
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
Statement::AlterTable { name, .. } => {
|
||||||
|
if self.is_crdt_sync_table(name) {
|
||||||
|
Ok(Some(self.normalize_table_name(name).into_owned()))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
// src-tauri/src/crdt/trigger.rs
|
||||||
use crate::table_names::TABLE_CRDT_LOGS;
|
use crate::table_names::TABLE_CRDT_LOGS;
|
||||||
use rusqlite::{Connection, Result as RusqliteResult, Row, Transaction};
|
use rusqlite::{Connection, Result as RusqliteResult, Row, Transaction};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
@ -8,20 +9,17 @@ use ts_rs::TS;
|
|||||||
// Der "z_"-Präfix soll sicherstellen, dass diese Trigger als Letzte ausgeführt werden
|
// Der "z_"-Präfix soll sicherstellen, dass diese Trigger als Letzte ausgeführt werden
|
||||||
const INSERT_TRIGGER_TPL: &str = "z_crdt_{TABLE_NAME}_insert";
|
const INSERT_TRIGGER_TPL: &str = "z_crdt_{TABLE_NAME}_insert";
|
||||||
const UPDATE_TRIGGER_TPL: &str = "z_crdt_{TABLE_NAME}_update";
|
const UPDATE_TRIGGER_TPL: &str = "z_crdt_{TABLE_NAME}_update";
|
||||||
|
const DELETE_TRIGGER_TPL: &str = "z_crdt_{TABLE_NAME}_delete";
|
||||||
|
|
||||||
//const SYNC_ACTIVE_KEY: &str = "sync_active";
|
pub const HLC_TIMESTAMP_COLUMN: &str = "haex_timestamp";
|
||||||
pub const TOMBSTONE_COLUMN: &str = "haex_tombstone";
|
|
||||||
pub const HLC_TIMESTAMP_COLUMN: &str = "haex_hlc_timestamp";
|
/// Name der custom UUID-Generierungs-Funktion (registriert in database::core::open_and_init_db)
|
||||||
|
pub const UUID_FUNCTION_NAME: &str = "gen_uuid";
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CrdtSetupError {
|
pub enum CrdtSetupError {
|
||||||
/// Kapselt einen Fehler, der von der rusqlite-Bibliothek kommt.
|
/// Kapselt einen Fehler, der von der rusqlite-Bibliothek kommt.
|
||||||
DatabaseError(rusqlite::Error),
|
DatabaseError(rusqlite::Error),
|
||||||
/// Die Tabelle hat keine Tombstone-Spalte, was eine CRDT-Voraussetzung ist.
|
|
||||||
TombstoneColumnMissing {
|
|
||||||
table_name: String,
|
|
||||||
column_name: String,
|
|
||||||
},
|
|
||||||
HlcColumnMissing {
|
HlcColumnMissing {
|
||||||
table_name: String,
|
table_name: String,
|
||||||
column_name: String,
|
column_name: String,
|
||||||
@ -34,25 +32,16 @@ pub enum CrdtSetupError {
|
|||||||
impl Display for CrdtSetupError {
|
impl Display for CrdtSetupError {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
CrdtSetupError::DatabaseError(e) => write!(f, "Database error: {}", e),
|
CrdtSetupError::DatabaseError(e) => write!(f, "Database error: {e}"),
|
||||||
CrdtSetupError::TombstoneColumnMissing {
|
|
||||||
table_name,
|
|
||||||
column_name,
|
|
||||||
} => write!(
|
|
||||||
f,
|
|
||||||
"Table '{}' is missing the required tombstone column '{}'",
|
|
||||||
table_name, column_name
|
|
||||||
),
|
|
||||||
CrdtSetupError::HlcColumnMissing {
|
CrdtSetupError::HlcColumnMissing {
|
||||||
table_name,
|
table_name,
|
||||||
column_name,
|
column_name,
|
||||||
} => write!(
|
} => write!(
|
||||||
f,
|
f,
|
||||||
"Table '{}' is missing the required hlc column '{}'",
|
"Table '{table_name}' is missing the required hlc column '{column_name}'"
|
||||||
table_name, column_name
|
|
||||||
),
|
),
|
||||||
CrdtSetupError::PrimaryKeyMissing { table_name } => {
|
CrdtSetupError::PrimaryKeyMissing { table_name } => {
|
||||||
write!(f, "Table '{}' has no primary key", table_name)
|
write!(f, "Table '{table_name}' has no primary key")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,61 +66,14 @@ pub enum TriggerSetupResult {
|
|||||||
TableNotFound,
|
TableNotFound,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fn set_sync_active(conn: &mut Connection) -> RusqliteResult<()> {
|
#[derive(Debug, Clone)]
|
||||||
let sql = format!(
|
pub struct ColumnInfo {
|
||||||
"INSERT OR REPLACE INTO \"{meta_table}\" (key, value) VALUES (?, '1');",
|
pub name: String,
|
||||||
meta_table = TABLE_CRDT_CONFIGS
|
pub is_pk: bool,
|
||||||
);
|
|
||||||
conn.execute(&sql, [SYNC_ACTIVE_KEY])?;
|
|
||||||
Ok(())
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* fn clear_sync_active(conn: &mut Connection) -> RusqliteResult<()> {
|
|
||||||
let sql = format!(
|
|
||||||
"DELETE FROM \"{meta_table}\" WHERE key = ?;",
|
|
||||||
meta_table = TABLE_CRDT_CONFIGS
|
|
||||||
);
|
|
||||||
conn.execute(&sql, [SYNC_ACTIVE_KEY])?;
|
|
||||||
Ok(())
|
|
||||||
} */
|
|
||||||
|
|
||||||
/// Führt eine Aktion aus, während die Trigger temporär deaktiviert sind.
|
|
||||||
/// Diese Funktion stellt sicher, dass die Trigger auch bei einem Absturz (Panic)
|
|
||||||
/// wieder aktiviert werden.
|
|
||||||
/* pub fn with_triggers_paused<F, R>(conn: &mut Connection, action: F) -> RusqliteResult<R>
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut Connection) -> RusqliteResult<R>,
|
|
||||||
{
|
|
||||||
// AssertUnwindSafe wird benötigt, um den Mutex über eine Panic-Grenze hinweg zu verwenden.
|
|
||||||
// Wir fangen einen möglichen Panic in `action` ab.
|
|
||||||
let result = panic::catch_unwind(AssertUnwindSafe(|| action(conn)));
|
|
||||||
|
|
||||||
// Diese Aktion MUSS immer ausgeführt werden, egal ob `action` erfolgreich war oder nicht.
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(res) => res, // Alles gut, gib das Ergebnis von `action` zurück.
|
|
||||||
Err(e) => panic::resume_unwind(e), // Ein Panic ist aufgetreten, wir geben ihn weiter, nachdem wir aufgeräumt haben.
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
/// Erstellt die benötigte Meta-Tabelle, falls sie nicht existiert.
|
|
||||||
/* pub fn setup_meta_table(conn: &mut Connection) -> RusqliteResult<()> {
|
|
||||||
let sql = format!(
|
|
||||||
"CREATE TABLE IF NOT EXISTS \"{meta_table}\" (key TEXT PRIMARY KEY, value TEXT) WITHOUT ROWID;",
|
|
||||||
meta_table = TABLE_CRDT_CONFIGS
|
|
||||||
);
|
|
||||||
conn.execute(&sql, [])?;
|
|
||||||
Ok(())
|
|
||||||
} */
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct ColumnInfo {
|
|
||||||
name: String,
|
|
||||||
is_pk: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ColumnInfo {
|
impl ColumnInfo {
|
||||||
fn from_row(row: &Row) -> RusqliteResult<Self> {
|
pub fn from_row(row: &Row) -> RusqliteResult<Self> {
|
||||||
Ok(ColumnInfo {
|
Ok(ColumnInfo {
|
||||||
name: row.get("name")?,
|
name: row.get("name")?,
|
||||||
is_pk: row.get::<_, i64>("pk")? > 0,
|
is_pk: row.get::<_, i64>("pk")? > 0,
|
||||||
@ -140,36 +82,22 @@ impl ColumnInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_safe_identifier(name: &str) -> bool {
|
fn is_safe_identifier(name: &str) -> bool {
|
||||||
!name.is_empty() && name.chars().all(|c| c.is_alphanumeric() || c == '_')
|
// Allow alphanumeric characters, underscores, and hyphens (for extension names like "nuxt-app")
|
||||||
|
!name.is_empty() && name.chars().all(|c| c.is_alphanumeric() || c == '_' || c == '-')
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Richtet CRDT-Trigger für eine einzelne Tabelle ein.
|
/// Richtet CRDT-Trigger für eine einzelne Tabelle ein.
|
||||||
pub fn setup_triggers_for_table(
|
pub fn setup_triggers_for_table(
|
||||||
conn: &mut Connection,
|
tx: &Transaction,
|
||||||
table_name: &str,
|
table_name: &str,
|
||||||
recreate: &bool,
|
recreate: bool,
|
||||||
) -> Result<TriggerSetupResult, CrdtSetupError> {
|
) -> Result<TriggerSetupResult, CrdtSetupError> {
|
||||||
if !is_safe_identifier(table_name) {
|
let columns = get_table_schema(tx, table_name)?;
|
||||||
return Err(rusqlite::Error::InvalidParameterName(format!(
|
|
||||||
"Invalid or unsafe table name provided: {}",
|
|
||||||
table_name
|
|
||||||
))
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
let columns = get_table_schema(conn, table_name)?;
|
|
||||||
|
|
||||||
if columns.is_empty() {
|
if columns.is_empty() {
|
||||||
return Ok(TriggerSetupResult::TableNotFound);
|
return Ok(TriggerSetupResult::TableNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !columns.iter().any(|c| c.name == TOMBSTONE_COLUMN) {
|
|
||||||
return Err(CrdtSetupError::TombstoneColumnMissing {
|
|
||||||
table_name: table_name.to_string(),
|
|
||||||
column_name: TOMBSTONE_COLUMN.to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if !columns.iter().any(|c| c.name == HLC_TIMESTAMP_COLUMN) {
|
if !columns.iter().any(|c| c.name == HLC_TIMESTAMP_COLUMN) {
|
||||||
return Err(CrdtSetupError::HlcColumnMissing {
|
return Err(CrdtSetupError::HlcColumnMissing {
|
||||||
table_name: table_name.to_string(),
|
table_name: table_name.to_string(),
|
||||||
@ -191,44 +119,48 @@ pub fn setup_triggers_for_table(
|
|||||||
|
|
||||||
let cols_to_track: Vec<String> = columns
|
let cols_to_track: Vec<String> = columns
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|c| !c.is_pk) //&& c.name != TOMBSTONE_COLUMN && c.name != HLC_TIMESTAMP_COLUMN
|
.filter(|c| !c.is_pk)
|
||||||
.map(|c| c.name.clone())
|
.map(|c| c.name.clone())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let insert_trigger_sql = generate_insert_trigger_sql(table_name, &pks, &cols_to_track);
|
let insert_trigger_sql = generate_insert_trigger_sql(table_name, &pks, &cols_to_track);
|
||||||
let update_trigger_sql = generate_update_trigger_sql(table_name, &pks, &cols_to_track);
|
let update_trigger_sql = generate_update_trigger_sql(table_name, &pks, &cols_to_track);
|
||||||
|
let delete_trigger_sql = generate_delete_trigger_sql(table_name, &pks, &cols_to_track);
|
||||||
|
|
||||||
let sql_batch = format!("{}\n{}", insert_trigger_sql, update_trigger_sql);
|
if recreate {
|
||||||
|
drop_triggers_for_table(tx, table_name)?;
|
||||||
// Führe die Erstellung innerhalb einer Transaktion aus
|
|
||||||
let tx = conn.transaction()?;
|
|
||||||
|
|
||||||
if *recreate {
|
|
||||||
drop_triggers_for_table(&tx, table_name)?;
|
|
||||||
}
|
}
|
||||||
tx.execute_batch(&sql_batch)?;
|
|
||||||
tx.commit()?;
|
tx.execute_batch(&insert_trigger_sql)?;
|
||||||
|
tx.execute_batch(&update_trigger_sql)?;
|
||||||
|
tx.execute_batch(&delete_trigger_sql)?;
|
||||||
|
|
||||||
Ok(TriggerSetupResult::Success)
|
Ok(TriggerSetupResult::Success)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Holt das Schema für eine gegebene Tabelle.
|
/// Holt das Schema für eine gegebene Tabelle.
|
||||||
/// WICHTIG: Dies ist eine private Hilfsfunktion. Sie geht davon aus, dass `table_name`
|
pub fn get_table_schema(conn: &Connection, table_name: &str) -> RusqliteResult<Vec<ColumnInfo>> {
|
||||||
/// bereits vom öffentlichen Aufrufer (setup_triggers_for_table) validiert wurde.
|
if !is_safe_identifier(table_name) {
|
||||||
fn get_table_schema(conn: &Connection, table_name: &str) -> RusqliteResult<Vec<ColumnInfo>> {
|
return Err(rusqlite::Error::InvalidParameterName(format!(
|
||||||
let sql = format!("PRAGMA table_info(\"{}\");", table_name);
|
"Invalid or unsafe table name provided: {table_name}"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let sql = format!("PRAGMA table_info(\"{table_name}\");");
|
||||||
let mut stmt = conn.prepare(&sql)?;
|
let mut stmt = conn.prepare(&sql)?;
|
||||||
let rows = stmt.query_map([], ColumnInfo::from_row)?;
|
let rows = stmt.query_map([], ColumnInfo::from_row)?;
|
||||||
rows.collect()
|
rows.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get_foreign_key_columns() removed - not needed with hard deletes (no ON CONFLICT logic)
|
||||||
|
|
||||||
pub fn drop_triggers_for_table(
|
pub fn drop_triggers_for_table(
|
||||||
tx: &Transaction, // Arbeitet direkt auf einer Transaktion
|
tx: &Transaction, // Arbeitet direkt auf einer Transaktion
|
||||||
table_name: &str,
|
table_name: &str,
|
||||||
) -> Result<(), CrdtSetupError> {
|
) -> Result<(), CrdtSetupError> {
|
||||||
if !is_safe_identifier(table_name) {
|
if !is_safe_identifier(table_name) {
|
||||||
return Err(rusqlite::Error::InvalidParameterName(format!(
|
return Err(rusqlite::Error::InvalidParameterName(format!(
|
||||||
"Invalid or unsafe table name provided: {}",
|
"Invalid or unsafe table name provided: {table_name}"
|
||||||
table_name
|
|
||||||
))
|
))
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
@ -237,8 +169,12 @@ pub fn drop_triggers_for_table(
|
|||||||
drop_trigger_sql(INSERT_TRIGGER_TPL.replace("{TABLE_NAME}", table_name));
|
drop_trigger_sql(INSERT_TRIGGER_TPL.replace("{TABLE_NAME}", table_name));
|
||||||
let drop_update_trigger_sql =
|
let drop_update_trigger_sql =
|
||||||
drop_trigger_sql(UPDATE_TRIGGER_TPL.replace("{TABLE_NAME}", table_name));
|
drop_trigger_sql(UPDATE_TRIGGER_TPL.replace("{TABLE_NAME}", table_name));
|
||||||
|
let drop_delete_trigger_sql =
|
||||||
|
drop_trigger_sql(DELETE_TRIGGER_TPL.replace("{TABLE_NAME}", table_name));
|
||||||
|
|
||||||
let sql_batch = format!("{}\n{}", drop_insert_trigger_sql, drop_update_trigger_sql);
|
let sql_batch = format!(
|
||||||
|
"{drop_insert_trigger_sql}\n{drop_update_trigger_sql}\n{drop_delete_trigger_sql}"
|
||||||
|
);
|
||||||
|
|
||||||
tx.execute_batch(&sql_batch)?;
|
tx.execute_batch(&sql_batch)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -303,29 +239,22 @@ pub fn drop_triggers_for_table(
|
|||||||
fn generate_insert_trigger_sql(table_name: &str, pks: &[String], cols: &[String]) -> String {
|
fn generate_insert_trigger_sql(table_name: &str, pks: &[String], cols: &[String]) -> String {
|
||||||
let pk_json_payload = pks
|
let pk_json_payload = pks
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pk| format!("'{}', NEW.\"{}\"", pk, pk))
|
.map(|pk| format!("'{pk}', NEW.\"{pk}\""))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", ");
|
.join(", ");
|
||||||
|
|
||||||
let column_inserts = if cols.is_empty() {
|
let column_inserts = if cols.is_empty() {
|
||||||
// Nur PKs -> einfacher Insert ins Log
|
// Nur PKs -> einfacher Insert ins Log
|
||||||
format!(
|
format!(
|
||||||
"INSERT INTO {log_table} (hlc_timestamp, op_type, table_name, row_pks)
|
"INSERT INTO {TABLE_CRDT_LOGS} (id, haex_timestamp, op_type, table_name, row_pks)
|
||||||
VALUES (hlc_new_timestamp(), 'INSERT', '{table}', json_object({pk_payload}));",
|
VALUES ({UUID_FUNCTION_NAME}(), NEW.\"{HLC_TIMESTAMP_COLUMN}\", 'INSERT', '{table_name}', json_object({pk_json_payload}));"
|
||||||
log_table = TABLE_CRDT_LOGS,
|
|
||||||
table = table_name,
|
|
||||||
pk_payload = pk_json_payload
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
cols.iter().fold(String::new(), |mut acc, col| {
|
cols.iter().fold(String::new(), |mut acc, col| {
|
||||||
writeln!(
|
writeln!(
|
||||||
&mut acc,
|
&mut acc,
|
||||||
"INSERT INTO {log_table} (hlc_timestamp, op_type, table_name, row_pks, column_name, new_value)
|
"INSERT INTO {TABLE_CRDT_LOGS} (id, haex_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}\"));",
|
VALUES ({UUID_FUNCTION_NAME}(), NEW.\"{HLC_TIMESTAMP_COLUMN}\", 'INSERT', '{table_name}', json_object({pk_json_payload}), '{col}', json_object('value', NEW.\"{col}\"));"
|
||||||
log_table = TABLE_CRDT_LOGS,
|
|
||||||
table = table_name,
|
|
||||||
pk_payload = pk_json_payload,
|
|
||||||
column = col
|
|
||||||
).unwrap();
|
).unwrap();
|
||||||
acc
|
acc
|
||||||
})
|
})
|
||||||
@ -345,14 +274,14 @@ fn generate_insert_trigger_sql(table_name: &str, pks: &[String], cols: &[String]
|
|||||||
|
|
||||||
/// Generiert das SQL zum Löschen eines Triggers.
|
/// Generiert das SQL zum Löschen eines Triggers.
|
||||||
fn drop_trigger_sql(trigger_name: String) -> String {
|
fn drop_trigger_sql(trigger_name: String) -> String {
|
||||||
format!("DROP TRIGGER IF EXISTS \"{}\";", trigger_name)
|
format!("DROP TRIGGER IF EXISTS \"{trigger_name}\";")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generiert das SQL für den UPDATE-Trigger.
|
/// Generiert das SQL für den UPDATE-Trigger.
|
||||||
fn generate_update_trigger_sql(table_name: &str, pks: &[String], cols: &[String]) -> String {
|
fn generate_update_trigger_sql(table_name: &str, pks: &[String], cols: &[String]) -> String {
|
||||||
let pk_json_payload = pks
|
let pk_json_payload = pks
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pk| format!("'{}', NEW.\"{}\"", pk, pk))
|
.map(|pk| format!("'{pk}', NEW.\"{pk}\""))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", ");
|
.join(", ");
|
||||||
|
|
||||||
@ -363,30 +292,15 @@ fn generate_update_trigger_sql(table_name: &str, pks: &[String], cols: &[String]
|
|||||||
for col in cols {
|
for col in cols {
|
||||||
writeln!(
|
writeln!(
|
||||||
&mut body,
|
&mut body,
|
||||||
"INSERT INTO {log_table} (hlc_timestamp, op_type, table_name, row_pks, column_name, new_value, old_value)
|
"INSERT INTO {TABLE_CRDT_LOGS} (id, haex_timestamp, op_type, table_name, row_pks, column_name, new_value, old_value)
|
||||||
SELECT hlc_new_timestamp(), 'UPDATE', '{table}', json_object({pk_payload}), '{column}',
|
SELECT {UUID_FUNCTION_NAME}(), NEW.\"{HLC_TIMESTAMP_COLUMN}\", 'UPDATE', '{table_name}', json_object({pk_json_payload}), '{col}',
|
||||||
json_object('value', NEW.\"{column}\"), json_object('value', OLD.\"{column}\")
|
json_object('value', NEW.\"{col}\"), json_object('value', OLD.\"{col}\")
|
||||||
WHERE NEW.\"{column}\" IS NOT OLD.\"{column}\";",
|
WHERE NEW.\"{col}\" IS NOT OLD.\"{col}\";"
|
||||||
log_table = TABLE_CRDT_LOGS,
|
|
||||||
table = table_name,
|
|
||||||
pk_payload = pk_json_payload,
|
|
||||||
column = col
|
|
||||||
).unwrap();
|
).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Soft-delete loggen
|
// Soft-delete Logging entfernt - wir nutzen jetzt Hard Deletes mit eigenem BEFORE DELETE Trigger
|
||||||
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})
|
|
||||||
WHERE NEW.\"{tombstone_col}\" = 1 AND OLD.\"{tombstone_col}\" = 0;",
|
|
||||||
log_table = TABLE_CRDT_LOGS,
|
|
||||||
table = table_name,
|
|
||||||
pk_payload = pk_json_payload,
|
|
||||||
tombstone_col = TOMBSTONE_COLUMN
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let trigger_name = UPDATE_TRIGGER_TPL.replace("{TABLE_NAME}", table_name);
|
let trigger_name = UPDATE_TRIGGER_TPL.replace("{TABLE_NAME}", table_name);
|
||||||
|
|
||||||
@ -400,73 +314,45 @@ fn generate_update_trigger_sql(table_name: &str, pks: &[String], cols: &[String]
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fn generate_update_trigger_sql(table_name: &str, pks: &[String], cols: &[String]) -> String {
|
/// Generiert das SQL für den BEFORE DELETE-Trigger.
|
||||||
|
/// WICHTIG: BEFORE DELETE damit die Daten noch verfügbar sind!
|
||||||
|
fn generate_delete_trigger_sql(table_name: &str, pks: &[String], cols: &[String]) -> String {
|
||||||
let pk_json_payload = pks
|
let pk_json_payload = pks
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pk| format!("'{}', NEW.\"{}\"", pk, pk))
|
.map(|pk| format!("'{pk}', OLD.\"{pk}\""))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", ");
|
.join(", ");
|
||||||
|
|
||||||
let column_updates = cols.iter().fold(String::new(), |mut acc, col| {
|
let mut body = String::new();
|
||||||
writeln!(&mut acc, " IF NEW.\"{column}\" IS NOT OLD.\"{column}\" THEN INSERT INTO {log_table} (hlc_timestamp, op_type, table_name, row_pk, column_name, value, old_value) VALUES (NEW.\"{hlc_col}\", 'UPDATE', '{table}', json_object({pk_payload}), '{column}', json_object('value', NEW.\"{column}\"), json_object('value', OLD.\"{column}\")); END IF;",
|
|
||||||
log_table = TABLE_CRDT_LOGS,
|
|
||||||
hlc_col = HLC_TIMESTAMP_COLUMN,
|
|
||||||
table = table_name,
|
|
||||||
pk_payload = pk_json_payload,
|
|
||||||
column = col
|
|
||||||
).unwrap();
|
|
||||||
acc
|
|
||||||
});
|
|
||||||
|
|
||||||
let soft_delete_logic = format!(
|
// Alle Spaltenwerte speichern für mögliche Wiederherstellung
|
||||||
" IF NEW.\"{tombstone_col}\" = 1 AND OLD.\"{tombstone_col}\" = 0 THEN INSERT INTO {log_table} (hlc_timestamp, op_type, table_name, row_pk) VALUES (NEW.\"{hlc_col}\", 'DELETE', '{table}', json_object({pk_payload})); END IF;",
|
if !cols.is_empty() {
|
||||||
log_table = TABLE_CRDT_LOGS,
|
for col in cols {
|
||||||
hlc_col = HLC_TIMESTAMP_COLUMN,
|
writeln!(
|
||||||
tombstone_col = TOMBSTONE_COLUMN,
|
&mut body,
|
||||||
table = table_name,
|
"INSERT INTO {TABLE_CRDT_LOGS} (id, haex_timestamp, op_type, table_name, row_pks, column_name, old_value)
|
||||||
pk_payload = pk_json_payload
|
VALUES ({UUID_FUNCTION_NAME}(), OLD.\"{HLC_TIMESTAMP_COLUMN}\", 'DELETE', '{table_name}', json_object({pk_json_payload}), '{col}',
|
||||||
);
|
json_object('value', OLD.\"{col}\"));"
|
||||||
|
).unwrap();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Nur PKs -> minimales Delete Log
|
||||||
|
writeln!(
|
||||||
|
&mut body,
|
||||||
|
"INSERT INTO {TABLE_CRDT_LOGS} (id, haex_timestamp, op_type, table_name, row_pks)
|
||||||
|
VALUES ({UUID_FUNCTION_NAME}(), OLD.\"{HLC_TIMESTAMP_COLUMN}\", 'DELETE', '{table_name}', json_object({pk_json_payload}));"
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
let trigger_name = UPDATE_TRIGGER_TPL.replace("{TABLE_NAME}", table_name);
|
let trigger_name = DELETE_TRIGGER_TPL.replace("{TABLE_NAME}", table_name);
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
"CREATE TRIGGER IF NOT EXISTS \"{trigger_name}\"
|
"CREATE TRIGGER IF NOT EXISTS \"{trigger_name}\"
|
||||||
AFTER UPDATE ON \"{table_name}\"
|
BEFORE DELETE ON \"{table_name}\"
|
||||||
WHEN (SELECT value FROM \"{config_table}\" WHERE key = '{sync_key}') IS NOT '1'
|
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
BEGIN
|
BEGIN
|
||||||
{column_updates}
|
{body}
|
||||||
{soft_delete_logic}
|
END;"
|
||||||
END;",
|
|
||||||
config_table = TABLE_CRDT_CONFIGS,
|
|
||||||
sync_key = SYNC_ACTIVE_KEY
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
/*
|
|
||||||
/// Durchläuft alle `haex_`-Tabellen und richtet die CRDT-Trigger ein.
|
|
||||||
pub fn generate_haex_triggers(conn: &mut Connection) -> Result<(), rusqlite::Error> {
|
|
||||||
println!("🔄 Setup CRDT triggers...");
|
|
||||||
let table_names: Vec<String> = {
|
|
||||||
let mut stmt = conn.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'haex_%' AND name NOT LIKE 'haex_crdt_%';")?;
|
|
||||||
let rows = stmt.query_map([], |row| row.get::<_, String>(0))?;
|
|
||||||
rows.collect::<RusqliteResult<Vec<String>>>()?
|
|
||||||
};
|
|
||||||
for table_name in table_names {
|
|
||||||
if table_name == TABLE_CRDT_CONFIGS {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
println!("➡️ Processing table: {}", table_name);
|
|
||||||
match setup_triggers_for_table(conn, &table_name) {
|
|
||||||
Ok(TriggerSetupResult::Success) => {
|
|
||||||
println!(" ✅ Triggers created for {}", table_name)
|
|
||||||
}
|
|
||||||
Ok(TriggerSetupResult::TableNotFound) => {
|
|
||||||
println!(" ℹ️ Table {} not found, skipping.", table_name)
|
|
||||||
}
|
|
||||||
Err(e) => println!(" ❌ Could not set up triggers for {}: {}", table_name, e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!("✨ Done setting up CRDT triggers.");
|
|
||||||
Ok(())
|
|
||||||
} */
|
|
||||||
|
|||||||
@ -1,276 +0,0 @@
|
|||||||
// Wir binden die Konstanten aus unserem generierten Modul ein.
|
|
||||||
// `crate` bezieht sich auf das Wurzelverzeichnis unseres Crates (src-tauri/src).
|
|
||||||
use crate::tableNames::*;
|
|
||||||
|
|
||||||
use rusqlite::{Connection, Result as RusqliteResult, Row};
|
|
||||||
use serde::Serialize;
|
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt::{self, Display, Formatter, Write};
|
|
||||||
use std::panic::{self, AssertUnwindSafe};
|
|
||||||
use ts_rs::TS;
|
|
||||||
|
|
||||||
// Harte Konstanten, die nicht aus der JSON-Datei kommen, da sie Teil der internen Logik sind.
|
|
||||||
const SYNC_ACTIVE_KEY: &str = "sync_active";
|
|
||||||
const TOMBSTONE_COLUMN: &str = "haex_tombstone";
|
|
||||||
const HLC_TIMESTAMP_COLUMN: &str = "haex_hlc_timestamp";
|
|
||||||
const INSERT_TRIGGER_TPL: &str = "z_crdt_{TABLE_NAME}_insert";
|
|
||||||
const UPDATE_TRIGGER_TPL: &str = "z_crdt_{TABLE_NAME}_update";
|
|
||||||
|
|
||||||
// --- Eigener Error-Typ für klares Fehler-Handling ---
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum CrdtSetupError {
|
|
||||||
DatabaseError(rusqlite::Error),
|
|
||||||
TombstoneColumnMissing {
|
|
||||||
table_name: String,
|
|
||||||
column_name: String,
|
|
||||||
},
|
|
||||||
PrimaryKeyMissing {
|
|
||||||
table_name: String,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for CrdtSetupError {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
CrdtSetupError::DatabaseError(e) => write!(f, "Database error: {}", e),
|
|
||||||
CrdtSetupError::TombstoneColumnMissing {
|
|
||||||
table_name,
|
|
||||||
column_name,
|
|
||||||
} => write!(
|
|
||||||
f,
|
|
||||||
"Table '{}' is missing the required tombstone column '{}'",
|
|
||||||
table_name, column_name
|
|
||||||
),
|
|
||||||
CrdtSetupError::PrimaryKeyMissing { table_name } => {
|
|
||||||
write!(f, "Table '{}' has no primary key", table_name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Error for CrdtSetupError {}
|
|
||||||
impl From<rusqlite::Error> for CrdtSetupError {
|
|
||||||
fn from(err: rusqlite::Error) -> Self {
|
|
||||||
CrdtSetupError::DatabaseError(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Öffentliche Structs und Enums ---
|
|
||||||
#[derive(Debug, Serialize, TS)]
|
|
||||||
#[ts(export)]
|
|
||||||
pub enum TriggerSetupResult {
|
|
||||||
Success,
|
|
||||||
TableNotFound,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct ColumnInfo {
|
|
||||||
name: String,
|
|
||||||
is_pk: bool,
|
|
||||||
}
|
|
||||||
impl ColumnInfo {
|
|
||||||
fn from_row(row: &Row) -> RusqliteResult<Self> {
|
|
||||||
Ok(ColumnInfo {
|
|
||||||
name: row.get("name")?,
|
|
||||||
is_pk: row.get::<_, i64>("pk")? > 0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Öffentliche Funktionen für die Anwendungslogik ---
|
|
||||||
|
|
||||||
/// Erstellt die benötigten CRDT-Systemtabellen (z.B. die Config-Tabelle), falls sie nicht existieren.
|
|
||||||
/// Sollte beim Anwendungsstart einmalig aufgerufen werden.
|
|
||||||
pub fn setup_crdt_tables(conn: &mut Connection) -> RusqliteResult<()> {
|
|
||||||
let config_sql = format!(
|
|
||||||
"CREATE TABLE IF NOT EXISTS \"{config_table}\" (key TEXT PRIMARY KEY, value TEXT) WITHOUT ROWID;",
|
|
||||||
config_table = TABLE_CRDT_CONFIGS
|
|
||||||
);
|
|
||||||
conn.execute(&config_sql, [])?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Führt eine Aktion aus, während die Trigger temporär deaktiviert sind.
|
|
||||||
/// Stellt sicher, dass die Trigger auch bei einem Absturz (Panic) wieder aktiviert werden.
|
|
||||||
pub fn with_triggers_paused<F, R>(conn: &mut Connection, action: F) -> RusqliteResult<R>
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut Connection) -> RusqliteResult<R>,
|
|
||||||
{
|
|
||||||
set_sync_active(conn)?;
|
|
||||||
// `catch_unwind` fängt einen möglichen Panic in `action` ab.
|
|
||||||
let result = panic::catch_unwind(AssertUnwindSafe(|| action(conn)));
|
|
||||||
// Diese Aufräumaktion wird immer ausgeführt.
|
|
||||||
clear_sync_active(conn)?;
|
|
||||||
match result {
|
|
||||||
Ok(res) => res, // Alles gut, gib das Ergebnis von `action` zurück.
|
|
||||||
Err(e) => panic::resume_unwind(e), // Ein Panic ist aufgetreten, wir geben ihn weiter, nachdem wir aufgeräumt haben.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Analysiert alle `haex_`-Tabellen in der Datenbank und erstellt die notwendigen CRDT-Trigger.
|
|
||||||
pub fn generate_haex_triggers(conn: &mut Connection) -> RusqliteResult<()> {
|
|
||||||
println!("🔄 Setup CRDT triggers...");
|
|
||||||
let table_names: Vec<String> = {
|
|
||||||
let mut stmt = conn.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'haex_%' AND name NOT LIKE 'haex_crdt_%';")?;
|
|
||||||
let rows = stmt.query_map([], |row| row.get::<_, String>(0))?;
|
|
||||||
rows.collect::<RusqliteResult<Vec<String>>>()?
|
|
||||||
};
|
|
||||||
|
|
||||||
for table_name in table_names {
|
|
||||||
// Überspringe die Config-Tabelle selbst, sie braucht keine Trigger.
|
|
||||||
if table_name == TABLE_CRDT_CONFIGS {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
println!("➡️ Processing table: {}", table_name);
|
|
||||||
match setup_triggers_for_table(conn, &table_name) {
|
|
||||||
Ok(TriggerSetupResult::Success) => {
|
|
||||||
println!(" ✅ Triggers created for {}", table_name)
|
|
||||||
}
|
|
||||||
Ok(TriggerSetupResult::TableNotFound) => {
|
|
||||||
println!(" ℹ️ Table {} not found, skipping.", table_name)
|
|
||||||
}
|
|
||||||
Err(e) => println!(" ❌ Could not set up triggers for {}: {}", table_name, e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!("✨ Done setting up CRDT triggers.");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Private Hilfsfunktionen ---
|
|
||||||
|
|
||||||
fn set_sync_active(conn: &mut Connection) -> RusqliteResult<()> {
|
|
||||||
let sql = format!(
|
|
||||||
"INSERT OR REPLACE INTO \"{config_table}\" (key, value) VALUES (?, '1');",
|
|
||||||
config_table = TABLE_CRDT_CONFIGS
|
|
||||||
);
|
|
||||||
conn.execute(&sql, [SYNC_ACTIVE_KEY])?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_sync_active(conn: &mut Connection) -> RusqliteResult<()> {
|
|
||||||
let sql = format!(
|
|
||||||
"DELETE FROM \"{config_table}\" WHERE key = ?;",
|
|
||||||
config_table = TABLE_CRDT_CONFIGS
|
|
||||||
);
|
|
||||||
conn.execute(&sql, [SYNC_ACTIVE_KEY])?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_safe_identifier(name: &str) -> bool {
|
|
||||||
!name.is_empty() && name.chars().all(|c| c.is_alphanumeric() || c == '_')
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_triggers_for_table(
|
|
||||||
conn: &mut Connection,
|
|
||||||
table_name: &str,
|
|
||||||
) -> Result<TriggerSetupResult, CrdtSetupError> {
|
|
||||||
if !is_safe_identifier(table_name) {
|
|
||||||
return Err(rusqlite::Error::InvalidParameterName(format!(
|
|
||||||
"Invalid table name: {}",
|
|
||||||
table_name
|
|
||||||
))
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
let columns = get_table_schema(conn, table_name)?;
|
|
||||||
if columns.is_empty() {
|
|
||||||
return Ok(TriggerSetupResult::TableNotFound);
|
|
||||||
}
|
|
||||||
if !columns.iter().any(|c| c.name == TOMBSTONE_COLUMN) {
|
|
||||||
return Err(CrdtSetupError::TombstoneColumnMissing {
|
|
||||||
table_name: table_name.to_string(),
|
|
||||||
column_name: TOMBSTONE_COLUMN.to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let pks: Vec<String> = columns
|
|
||||||
.iter()
|
|
||||||
.filter(|c| c.is_pk)
|
|
||||||
.map(|c| c.name.clone())
|
|
||||||
.collect();
|
|
||||||
if pks.is_empty() {
|
|
||||||
return Err(CrdtSetupError::PrimaryKeyMissing {
|
|
||||||
table_name: table_name.to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let cols_to_track: Vec<String> = columns
|
|
||||||
.iter()
|
|
||||||
.filter(|c| !c.is_pk && c.name != TOMBSTONE_COLUMN && c.name != HLC_TIMESTAMP_COLUMN)
|
|
||||||
.map(|c| c.name.clone())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let insert_trigger_sql = generate_insert_trigger_sql(table_name, &pks, &cols_to_track);
|
|
||||||
let update_trigger_sql = generate_update_trigger_sql(table_name, &pks, &cols_to_track);
|
|
||||||
let drop_insert_trigger_sql =
|
|
||||||
drop_trigger_sql(INSERT_TRIGGER_TPL.replace("{TABLE_NAME}", table_name));
|
|
||||||
let drop_update_trigger_sql =
|
|
||||||
drop_trigger_sql(UPDATE_TRIGGER_TPL.replace("{TABLE_NAME}", table_name));
|
|
||||||
|
|
||||||
let tx = conn.transaction()?;
|
|
||||||
tx.execute_batch(&format!(
|
|
||||||
"{}\n{}\n{}\n{}",
|
|
||||||
drop_insert_trigger_sql, drop_update_trigger_sql, insert_trigger_sql, update_trigger_sql
|
|
||||||
))?;
|
|
||||||
tx.commit()?;
|
|
||||||
|
|
||||||
Ok(TriggerSetupResult::Success)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_table_schema(conn: &Connection, table_name: &str) -> RusqliteResult<Vec<ColumnInfo>> {
|
|
||||||
let sql = format!("PRAGMA table_info(\"{}\");", table_name);
|
|
||||||
let mut stmt = conn.prepare(&sql)?;
|
|
||||||
let rows = stmt.query_map([], ColumnInfo::from_row)?;
|
|
||||||
rows.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn drop_trigger_sql(trigger_name: String) -> String {
|
|
||||||
format!("DROP TRIGGER IF EXISTS \"{}\";", trigger_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_insert_trigger_sql(table_name: &str, pks: &[String], cols: &[String]) -> String {
|
|
||||||
let pk_json_payload = pks
|
|
||||||
.iter()
|
|
||||||
.map(|pk| format!("'{}', NEW.\"{}\"", pk, pk))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ");
|
|
||||||
let column_inserts = cols.iter().fold(String::new(), |mut acc, col| {
|
|
||||||
writeln!(&mut acc, " INSERT INTO \"{log_table}\" (hlc_timestamp, op_type, table_name, row_pk, column_name, 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).unwrap();
|
|
||||||
acc
|
|
||||||
});
|
|
||||||
let trigger_name = INSERT_TRIGGER_TPL.replace("{TABLE_NAME}", table_name);
|
|
||||||
format!(
|
|
||||||
"CREATE TRIGGER IF NOT EXISTS \"{trigger_name}\"\n"
|
|
||||||
+ " AFTER INSERT ON \"{table_name}\"\n"
|
|
||||||
+ " WHEN (SELECT value FROM \"{config_table}\" WHERE key = '{sync_key}') IS NOT '1'\n"
|
|
||||||
+ " FOR EACH ROW\n"
|
|
||||||
+ " BEGIN\n"
|
|
||||||
+ " {column_inserts}\n"
|
|
||||||
+ " END;",
|
|
||||||
config_table = TABLE_CRDT_CONFIGS,
|
|
||||||
sync_key = SYNC_ACTIVE_KEY
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_update_trigger_sql(table_name: &str, pks: &[String], cols: &[String]) -> String {
|
|
||||||
let pk_json_payload = pks
|
|
||||||
.iter()
|
|
||||||
.map(|pk| format!("'{}', NEW.\"{}\"", pk, pk))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ");
|
|
||||||
let column_updates = cols.iter().fold(String::new(), |mut acc, col| {
|
|
||||||
writeln!(&mut acc, " IF NEW.\"{column}\" IS NOT OLD.\"{column}\" THEN INSERT INTO \"{log_table}\" (hlc_timestamp, op_type, table_name, row_pk, column_name, value, old_value) VALUES (NEW.\"{hlc_col}\", 'UPDATE', '{table}', json_object({pk_payload}), '{column}', json_object('value', NEW.\"{column}\"), json_object('value', OLD.\"{column}\")); END IF;", log_table = TABLE_CRDT_LOGS, hlc_col = HLC_TIMESTAMP_COLUMN, table = table_name, pk_payload = pk_json_payload, column = col).unwrap();
|
|
||||||
acc
|
|
||||||
});
|
|
||||||
let soft_delete_logic = format!(
|
|
||||||
" IF NEW.\"{tombstone_col}\" = 1 AND OLD.\"{tombstone_col}\" = 0 THEN INSERT INTO \"{log_table}\" (hlc_timestamp, op_type, table_name, row_pk) VALUES (NEW.\"{hlc_col}\", 'DELETE', '{table}', json_object({pk_payload})); END IF;", log_table = TABLE_CRDT_LOGS, hlc_col = HLC_TIMESTAMP_COLUMN, tombstone_col = TOMBSTONE_COLUMN, table = table_name, pk_payload = pk_json_payload);
|
|
||||||
let trigger_name = UPDATE_TRIGGER_TPL.replace("{TABLE_NAME}", table_name);
|
|
||||||
format!(
|
|
||||||
"CREATE TRIGGER IF NOT EXISTS \"{trigger_name}\"\n"
|
|
||||||
+ " AFTER UPDATE ON \"{table_name}\"\n"
|
|
||||||
+ " WHEN (SELECT value FROM \"{config_table}\" WHERE key = '{sync_key}') IS NOT '1'\n"
|
|
||||||
+ " FOR EACH ROW\n"
|
|
||||||
+ " BEGIN\n"
|
|
||||||
+ " {column_updates}\n"
|
|
||||||
+ " {soft_delete_logic}\n"
|
|
||||||
+ " END;",
|
|
||||||
config_table = TABLE_CRDT_CONFIGS,
|
|
||||||
sync_key = SYNC_ACTIVE_KEY
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user