fixed trigger

This commit is contained in:
2025-10-23 13:17:58 +02:00
parent 99ccadce00
commit 4f839aa856
42 changed files with 535 additions and 10695 deletions

View File

@ -1,227 +0,0 @@
{
"session_date": "2025-10-20",
"project": "haex-hub System Windows Architecture + Drizzle CRDT RETURNING Fix + PK-Remapping Refactor",
"status": "system_windows_ui_integration_completed",
"context": {
"main_work_today": [
"Fixed Drizzle CRDT integration with RETURNING support",
"Implemented System Windows architecture (Settings, Marketplace as Desktop Windows)",
"Refactored executor functions: Split execute/query paths for cleaner code",
"Integrated System Windows UI: Launcher, Window Component, Placeholder Components"
],
"completed_today": [
"Added AST-based statement_has_returning() for safe RETURNING detection",
"Created SqlExecutor::query_internal() for INSERT/UPDATE/DELETE with RETURNING",
"Simplified execute_internal to use execute_internal_typed (now with PK-Remapping!)",
"Added sql_query_with_crdt Tauri command",
"Updated drizzleCallback in index.ts to route correctly",
"Extended IWindow interface: type ('system' | 'extension'), sourceId",
"Added SystemWindowDefinition interface",
"Created system windows registry in windowManager store",
"Extended openWindow() to support both system and extension windows",
"Added singleton support for system windows",
"Split execute_internal_typed_with_context into two functions (execute vs query)",
"Created query_internal_typed_with_context with full PK-Remapping support",
"Updated query_internal to use new typed function with PK-Remapping",
"Fixed manager.rs to use query_internal_typed_with_context for INSERT RETURNING",
"Extended Launcher to show System Windows + Extensions alphabetically",
"Adapted Window Component to render System Windows as Vue Components, Extensions as iFrames",
"Created placeholder components: Settings.vue and Marketplace.vue"
],
"tech_stack": "Vue 3, TypeScript, Pinia, Nuxt UI, Tauri, Rust, Drizzle ORM, SQLite"
},
"drizzle_crdt_implementation": {
"problem": "Drizzle .insert().returning() executed SQL twice and lost RETURNING data",
"solution": "Separate execute and query paths based on RETURNING clause",
"typescript_side": {
"file": "src/stores/vault/index.ts",
"drizzleCallback_logic": {
"select": "sql_select (unchanged)",
"with_returning": "sql_query_with_crdt (NEW)",
"without_returning": "sql_execute_with_crdt (unchanged)"
},
"hasReturning_check": "String-based RETURNING regex (safe enough for generated SQL)"
},
"rust_side": {
"files": [
"src-tauri/src/database/core.rs",
"src-tauri/src/extension/database/executor.rs",
"src-tauri/src/database/mod.rs"
],
"core_rs_changes": {
"statement_has_returning": {
"line": 84,
"purpose": "AST-based RETURNING check (INSERT, UPDATE, DELETE)",
"safety": "Checks actual AST, not string matching"
},
"convert_value_ref_to_json": {
"line": 333,
"visibility": "Made public for reuse"
},
"removed": "query_with_crdt function (replaced by SqlExecutor::query_internal)"
},
"executor_rs_changes": {
"execute_internal_typed_with_context": {
"line": 100,
"purpose": "Execute SQL WITHOUT RETURNING (with CRDT and FK-Remapping)",
"returns": "Result<HashSet<String>, DatabaseError>",
"behavior": "Handles INSERTs with FK-Remapping, uses execute()"
},
"query_internal_typed_with_context": {
"line": 186,
"purpose": "Execute SQL WITH RETURNING (with CRDT, PK-Remapping, FK-Remapping)",
"returns": "Result<(HashSet<String>, Vec<Vec<JsonValue>>), DatabaseError>",
"behavior": "Handles INSERTs with full PK-Remapping + FK-Remapping, returns all RETURNING columns"
},
"query_internal": {
"line": 454,
"purpose": "Execute with CRDT + return full RETURNING results (JsonValue params)",
"behavior": "Wrapper around query_internal_typed_with_context"
},
"execute_internal_refactor": {
"line": 345,
"change": "Now wrapper around execute_internal_typed",
"benefit": "Drizzle now gets PK-Remapping for ON CONFLICT!"
}
},
"mod_rs_changes": {
"sql_query_with_crdt": {
"line": 59,
"calls": "SqlExecutor::query_internal",
"returns": "Vec<Vec<JsonValue>>"
}
},
"lib_rs_changes": {
"registered_command": "sql_query_with_crdt added to invoke_handler"
}
},
"benefits": [
"SQL executed only once (not twice)",
"Full RETURNING results available to Drizzle",
"PK-Remapping now works for Drizzle (both execute and query paths)",
"AST-based RETURNING detection (safe)",
"Less code duplication",
"Cleaner code separation: execute vs query functions",
"FK-Remapping works across transactions with PkRemappingContext"
]
},
"system_windows_architecture": {
"concept": "ALL UI (Settings, Marketplace, etc.) as DesktopWindows, same as Extensions",
"status": "Store completed, UI integration pending",
"window_manager_store": {
"file": "src/stores/desktop/windowManager.ts",
"changes": {
"IWindow_interface": {
"added_fields": [
"type: 'system' | 'extension'",
"sourceId: string (replaces extensionId)"
],
"removed_fields": ["extensionId"]
},
"SystemWindowDefinition": {
"fields": "id, name, icon, component, defaultWidth, defaultHeight, resizable, singleton"
},
"system_windows_registry": {
"line": 46,
"entries": ["settings", "marketplace"],
"structure": "Record<string, SystemWindowDefinition>"
},
"openWindow_function": {
"line": 101,
"signature": "(type, sourceId, title?, icon?, width?, height?, sourcePosition?)",
"features": [
"Type-based handling (system vs extension)",
"Singleton check for system windows",
"Auto-loads defaults from registry",
"Activates existing singleton if already open"
]
},
"new_exports": ["getAllSystemWindows", "getSystemWindow"]
}
},
"ui_integration": {
"launcher": {
"file": "src/components/haex/extension/launcher.vue",
"changes": [
"Combined system windows and extensions in unified launcherItems computed",
"Alphabetically sorted by name",
"openItem() function handles both types with correct openWindow() signature",
"Uses windowManagerStore.getAllSystemWindows()"
]
},
"desktop_window_component": {
"file": "src/components/haex/desktop/index.vue",
"changes": [
"Dynamic component rendering: <component :is='getSystemWindowComponent()'> for system windows",
"HaexDesktopExtensionFrame for extensions (iFrame)",
"getSystemWindowComponent() function to retrieve Vue component from registry",
"Applied to both normal mode and overview mode"
]
},
"placeholder_components": {
"created": [
"src/components/haex/system/settings.vue",
"src/components/haex/system/marketplace.vue"
],
"description": "Simple placeholder UI with sections and styling"
}
},
"next_steps": {
"priority": [
"Desktop Icons: Support system window icons (alongside extension icons)",
"Drag & Drop: Launcher → Desktop for all types (system + extension)"
]
}
},
"workspace_overview_context": {
"still_active": "GNOME-style workspace overview with UDrawer, implemented yesterday",
"file": "src/components/haex/desktop/index.vue",
"status": "Working, workspace switching functional"
},
"file_changes_today": {
"modified": [
"src/stores/vault/index.ts (drizzleCallback with hasReturning)",
"src-tauri/src/database/core.rs (statement_has_returning, removed query_with_crdt)",
"src-tauri/src/extension/database/executor.rs (split execute/query functions, PK-Remapping)",
"src-tauri/src/database/mod.rs (sql_query_with_crdt command)",
"src-tauri/src/lib.rs (registered sql_query_with_crdt)",
"src/stores/desktop/windowManager.ts (system windows support)",
"src-tauri/src/extension/core/manager.rs (updated to use query_internal_typed_with_context)",
"src/components/haex/extension/launcher.vue (unified launcher for system + extensions)",
"src/components/haex/desktop/index.vue (dynamic component rendering)"
],
"created": [
"src/components/haex/system/settings.vue",
"src/components/haex/system/marketplace.vue"
],
"deleted": []
},
"important_notes": [
"Drizzle RETURNING now fully functional with CRDT",
"System windows use Vue components, Extensions use iFrame",
"sourceId is generic: extensionId for extensions, systemWindowId for system windows",
"Singleton system windows auto-activate if already open",
"PK-Remapping now works for both execute and query paths",
"executor.rs: Two separate functions for execute (no RETURNING) vs query (with RETURNING)",
"query_internal_typed_with_context returns full RETURNING results as Vec<Vec<JsonValue>>",
"FK-Remapping works across transaction using PkRemappingContext",
"Next session: Implement Launcher UI integration for system windows"
],
"todos_remaining": [
"Desktop Icons für System Windows unterstützen (neben Extension Icons)",
"Drag & Drop vom Launcher zum Desktop implementieren (für beide Typen)"
]
}

View File

@ -170,6 +170,14 @@ use serde::{Deserialize, Serialize};
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) {

View File

@ -24,9 +24,20 @@ CREATE TABLE `haex_crdt_snapshots` (
`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,
`reference_id` text NOT NULL,
`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
);
--> statement-breakpoint
CREATE TABLE `haex_extension_permissions` (
`id` text PRIMARY KEY NOT NULL,
`extension_id` text,
`extension_id` text NOT NULL,
`resource_type` text,
`action` text,
`target` text,
@ -34,38 +45,27 @@ CREATE TABLE `haex_extension_permissions` (
`status` text DEFAULT 'denied' NOT NULL,
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
`updated_at` integer,
`haex_tombstone` integer,
`haex_timestamp` text,
FOREIGN KEY (`extension_id`) REFERENCES `haex_extensions`(`id`) ON UPDATE no action ON DELETE no action
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,
`entry` text DEFAULT 'index.html' NOT NULL,
`homepage` text,
`enabled` integer,
`enabled` integer DEFAULT true,
`icon` text,
`name` text,
`public_key` text,
`signature` text,
`url` text,
`version` text,
`haex_tombstone` integer,
`haex_timestamp` text
);
--> statement-breakpoint
CREATE TABLE `haex_settings` (
`id` text PRIMARY KEY NOT NULL,
`key` text,
`type` text,
`value` text,
`haex_tombstone` integer,
`signature` text NOT NULL,
`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,
@ -77,63 +77,23 @@ CREATE TABLE `haex_notifications` (
`text` text,
`title` text,
`type` text NOT NULL,
`haex_tombstone` integer
`haex_timestamp` text
);
--> statement-breakpoint
CREATE TABLE `haex_passwords_group_items` (
`group_id` text,
`item_id` text,
`haex_tombstone` integer,
PRIMARY KEY(`item_id`, `group_id`),
FOREIGN KEY (`group_id`) REFERENCES `haex_passwords_groups`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_item_details`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE TABLE `haex_passwords_groups` (
CREATE TABLE `haex_settings` (
`id` text PRIMARY KEY NOT NULL,
`name` text,
`description` text,
`icon` text,
`order` integer,
`color` text,
`parent_id` text,
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
`updated_at` integer,
`haex_tombstone` integer,
FOREIGN KEY (`parent_id`) REFERENCES `haex_passwords_groups`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE TABLE `haex_passwords_item_details` (
`id` text PRIMARY KEY NOT NULL,
`title` text,
`username` text,
`password` text,
`note` text,
`icon` text,
`tags` text,
`url` text,
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
`updated_at` integer,
`haex_tombstone` integer
);
--> statement-breakpoint
CREATE TABLE `haex_passwords_item_history` (
`id` text PRIMARY KEY NOT NULL,
`item_id` text,
`changed_property` text,
`old_value` text,
`new_value` text,
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
`haex_tombstone` integer,
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_item_details`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE TABLE `haex_passwords_item_key_values` (
`id` text PRIMARY KEY NOT NULL,
`item_id` text,
`key` text,
`type` text,
`value` text,
`updated_at` integer,
`haex_tombstone` integer,
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_item_details`(`id`) ON UPDATE no action ON DELETE no action
`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,
`name` text NOT NULL,
`position` integer DEFAULT 0 NOT NULL,
`haex_timestamp` text
);
--> statement-breakpoint
CREATE UNIQUE INDEX `haex_workspaces_position_unique` ON `haex_workspaces` (`position`);

View File

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

View File

@ -1,22 +0,0 @@
PRAGMA foreign_keys=OFF;--> statement-breakpoint
CREATE TABLE `__new_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' NOT NULL,
`homepage` text,
`enabled` integer DEFAULT true,
`icon` text,
`signature` text NOT NULL,
`haex_tombstone` integer,
`haex_timestamp` text
);
--> statement-breakpoint
INSERT INTO `__new_haex_extensions`("id", "public_key", "name", "version", "author", "description", "entry", "homepage", "enabled", "icon", "signature", "haex_tombstone", "haex_timestamp") SELECT "id", "public_key", "name", "version", "author", "description", "entry", "homepage", "enabled", "icon", "signature", "haex_tombstone", "haex_timestamp" FROM `haex_extensions`;--> statement-breakpoint
DROP TABLE `haex_extensions`;--> statement-breakpoint
ALTER TABLE `__new_haex_extensions` RENAME TO `haex_extensions`;--> statement-breakpoint
PRAGMA foreign_keys=ON;--> statement-breakpoint
CREATE UNIQUE INDEX `haex_extensions_public_key_name_unique` ON `haex_extensions` (`public_key`,`name`);

View File

@ -1,9 +0,0 @@
CREATE TABLE `haex_desktop_items` (
`id` text PRIMARY KEY NOT NULL,
`item_type` text NOT NULL,
`reference_id` text NOT NULL,
`position_x` integer DEFAULT 0 NOT NULL,
`position_y` integer DEFAULT 0 NOT NULL,
`haex_tombstone` integer,
`haex_timestamp` text
);

View File

@ -1,10 +0,0 @@
CREATE TABLE `haex_workspaces` (
`id` text PRIMARY KEY NOT NULL,
`name` text NOT NULL,
`position` integer DEFAULT 0 NOT NULL,
`created_at` integer NOT NULL,
`haex_tombstone` integer,
`haex_timestamp` text
);
--> statement-breakpoint
ALTER TABLE `haex_desktop_items` ADD `workspace_id` text NOT NULL REFERENCES haex_workspaces(id);

View File

@ -1 +0,0 @@
CREATE UNIQUE INDEX `haex_workspaces_name_unique` ON `haex_workspaces` (`name`);

View File

@ -1,3 +0,0 @@
DROP INDEX `haex_workspaces_name_unique`;--> statement-breakpoint
CREATE UNIQUE INDEX `haex_workspaces_position_unique` ON `haex_workspaces` (`position`);--> statement-breakpoint
CREATE UNIQUE INDEX `haex_settings_key_type_value_unique` ON `haex_settings` (`key`,`type`,`value`);

View File

@ -1,2 +0,0 @@
DROP INDEX `haex_workspaces_position_unique`;--> statement-breakpoint
ALTER TABLE `haex_workspaces` DROP COLUMN `created_at`;

View File

@ -1 +0,0 @@
CREATE UNIQUE INDEX `haex_workspaces_position_unique` ON `haex_workspaces` (`position`);

View File

@ -1,92 +0,0 @@
PRAGMA foreign_keys=OFF;--> statement-breakpoint
CREATE TABLE `__new_haex_desktop_items` (
`id` text PRIMARY KEY NOT NULL,
`workspace_id` text NOT NULL,
`item_type` text NOT NULL,
`reference_id` text NOT NULL,
`position_x` integer DEFAULT 0 NOT NULL,
`position_y` integer DEFAULT 0 NOT NULL,
`haex_tombstone` integer,
`haex_timestamp` text,
FOREIGN KEY (`workspace_id`) REFERENCES `haex_workspaces`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
INSERT INTO `__new_haex_desktop_items`("id", "workspace_id", "item_type", "reference_id", "position_x", "position_y", "haex_tombstone", "haex_timestamp") SELECT "id", "workspace_id", "item_type", "reference_id", "position_x", "position_y", "haex_tombstone", "haex_timestamp" FROM `haex_desktop_items`;--> statement-breakpoint
DROP TABLE `haex_desktop_items`;--> statement-breakpoint
ALTER TABLE `__new_haex_desktop_items` RENAME TO `haex_desktop_items`;--> statement-breakpoint
PRAGMA foreign_keys=ON;--> statement-breakpoint
CREATE TABLE `__new_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_tombstone` integer,
`haex_timestamp` text,
FOREIGN KEY (`extension_id`) REFERENCES `haex_extensions`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
INSERT INTO `__new_haex_extension_permissions`("id", "extension_id", "resource_type", "action", "target", "constraints", "status", "created_at", "updated_at", "haex_tombstone", "haex_timestamp") SELECT "id", "extension_id", "resource_type", "action", "target", "constraints", "status", "created_at", "updated_at", "haex_tombstone", "haex_timestamp" 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
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 `__new_haex_passwords_group_items` (
`group_id` text NOT NULL,
`item_id` text NOT NULL,
`haex_tombstone` integer,
PRIMARY KEY(`item_id`, `group_id`),
FOREIGN KEY (`group_id`) REFERENCES `haex_passwords_groups`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_item_details`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
INSERT INTO `__new_haex_passwords_group_items`("group_id", "item_id", "haex_tombstone") SELECT "group_id", "item_id", "haex_tombstone" 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_groups` (
`id` text PRIMARY KEY NOT NULL,
`name` text,
`description` text,
`icon` text,
`order` integer,
`color` text,
`parent_id` text,
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
`updated_at` integer,
`haex_tombstone` integer,
FOREIGN KEY (`parent_id`) REFERENCES `haex_passwords_groups`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
INSERT INTO `__new_haex_passwords_groups`("id", "name", "description", "icon", "order", "color", "parent_id", "created_at", "updated_at", "haex_tombstone") SELECT "id", "name", "description", "icon", "order", "color", "parent_id", "created_at", "updated_at", "haex_tombstone" FROM `haex_passwords_groups`;--> statement-breakpoint
DROP TABLE `haex_passwords_groups`;--> statement-breakpoint
ALTER TABLE `__new_haex_passwords_groups` RENAME TO `haex_passwords_groups`;--> statement-breakpoint
CREATE TABLE `__new_haex_passwords_item_history` (
`id` text PRIMARY KEY NOT NULL,
`item_id` text NOT NULL,
`changed_property` text,
`old_value` text,
`new_value` text,
`created_at` text DEFAULT (CURRENT_TIMESTAMP),
`haex_tombstone` integer,
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_item_details`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
INSERT INTO `__new_haex_passwords_item_history`("id", "item_id", "changed_property", "old_value", "new_value", "created_at", "haex_tombstone") SELECT "id", "item_id", "changed_property", "old_value", "new_value", "created_at", "haex_tombstone" 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`;--> statement-breakpoint
CREATE TABLE `__new_haex_passwords_item_key_values` (
`id` text PRIMARY KEY NOT NULL,
`item_id` text NOT NULL,
`key` text,
`value` text,
`updated_at` integer,
`haex_tombstone` integer,
FOREIGN KEY (`item_id`) REFERENCES `haex_passwords_item_details`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
INSERT INTO `__new_haex_passwords_item_key_values`("id", "item_id", "key", "value", "updated_at", "haex_tombstone") SELECT "id", "item_id", "key", "value", "updated_at", "haex_tombstone" 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`;

View File

@ -1,7 +1,7 @@
{
"version": "6",
"dialect": "sqlite",
"id": "3bbe52b8-5933-4b21-8b24-de3927a2f9b0",
"id": "21ca1268-1057-48c1-8647-29bd7cb67d49",
"prevId": "00000000-0000-0000-0000-000000000000",
"tables": {
"haex_crdt_configs": {
@ -155,6 +155,81 @@
"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
},
"reference_id": {
"name": "reference_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"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"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extension_permissions": {
"name": "haex_extension_permissions",
"columns": {
@ -169,7 +244,7 @@
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"notNull": true,
"autoincrement": false
},
"resource_type": {
@ -223,13 +298,6 @@
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
@ -261,7 +329,7 @@
"columnsTo": [
"id"
],
"onDelete": "no action",
"onDelete": "cascade",
"onUpdate": "no action"
}
},
@ -279,6 +347,27 @@
"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",
@ -297,8 +386,9 @@
"name": "entry",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
"notNull": true,
"autoincrement": false,
"default": "'index.html'"
},
"homepage": {
"name": "homepage",
@ -312,7 +402,8 @@
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
"autoincrement": false,
"default": true
},
"icon": {
"name": "icon",
@ -321,100 +412,13 @@
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"public_key": {
"name": "public_key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"signature": {
"name": "signature",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"version": {
"name": "version",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
@ -423,7 +427,16 @@
"autoincrement": false
}
},
"indexes": {},
"indexes": {
"haex_extensions_public_key_name_unique": {
"name": "haex_extensions_public_key_name_unique",
"columns": [
"public_key",
"name"
],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
@ -502,9 +515,9 @@
"notNull": true,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
@ -516,74 +529,8 @@
"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",
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
@ -592,270 +539,6 @@
"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",
@ -863,6 +546,13 @@
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
@ -870,37 +560,73 @@
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"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
},
"haex_tombstone": {
"name": "haex_tombstone",
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"position": {
"name": "position",
"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_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"
"indexes": {
"haex_workspaces_position_unique": {
"name": "haex_workspaces_position_unique",
"columns": [
"position"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}

View File

@ -1,926 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "862ac1d5-3065-4244-8652-2b6782254862",
"prevId": "3bbe52b8-5933-4b21-8b24-de3927a2f9b0",
"tables": {
"haex_crdt_configs": {
"name": "haex_crdt_configs",
"columns": {
"key": {
"name": "key",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_logs": {
"name": "haex_crdt_logs",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"table_name": {
"name": "table_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"row_pks": {
"name": "row_pks",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"op_type": {
"name": "op_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"column_name": {
"name": "column_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"idx_haex_timestamp": {
"name": "idx_haex_timestamp",
"columns": [
"haex_timestamp"
],
"isUnique": false
},
"idx_table_row": {
"name": "idx_table_row",
"columns": [
"table_name",
"row_pks"
],
"isUnique": false
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_snapshots": {
"name": "haex_crdt_snapshots",
"columns": {
"snapshot_id": {
"name": "snapshot_id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"created": {
"name": "created",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"epoch_hlc": {
"name": "epoch_hlc",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"location_url": {
"name": "location_url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"file_size_bytes": {
"name": "file_size_bytes",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extension_permissions": {
"name": "haex_extension_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource_type": {
"name": "resource_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"action": {
"name": "action",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"target": {
"name": "target",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"constraints": {
"name": "constraints",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'denied'"
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extension_permissions_extension_id_resource_type_action_target_unique": {
"name": "haex_extension_permissions_extension_id_resource_type_action_target_unique",
"columns": [
"extension_id",
"resource_type",
"action",
"target"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extension_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extension_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extension_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions": {
"name": "haex_extensions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"author": {
"name": "author",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"entry": {
"name": "entry",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"homepage": {
"name": "homepage",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"public_key": {
"name": "public_key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"signature": {
"name": "signature",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"version": {
"name": "version",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_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
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_group_items": {
"name": "haex_passwords_group_items",
"columns": {
"group_id": {
"name": "group_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_group_items_group_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"haex_passwords_group_items_item_id_group_id_pk": {
"columns": [
"item_id",
"group_id"
],
"name": "haex_passwords_group_items_item_id_group_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_groups": {
"name": "haex_passwords_groups",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"parent_id": {
"name": "parent_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_groups_parent_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_groups",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"parent_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_details": {
"name": "haex_passwords_item_details",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"note": {
"name": "note",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"tags": {
"name": "tags",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_history": {
"name": "haex_passwords_item_history",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"changed_property": {
"name": "changed_property",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_history",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_key_values": {
"name": "haex_passwords_item_key_values",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_key_values",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@ -1,930 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "5387568f-75b3-4a85-86c5-67f539c3fedf",
"prevId": "862ac1d5-3065-4244-8652-2b6782254862",
"tables": {
"haex_crdt_configs": {
"name": "haex_crdt_configs",
"columns": {
"key": {
"name": "key",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_logs": {
"name": "haex_crdt_logs",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"table_name": {
"name": "table_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"row_pks": {
"name": "row_pks",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"op_type": {
"name": "op_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"column_name": {
"name": "column_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"idx_haex_timestamp": {
"name": "idx_haex_timestamp",
"columns": [
"haex_timestamp"
],
"isUnique": false
},
"idx_table_row": {
"name": "idx_table_row",
"columns": [
"table_name",
"row_pks"
],
"isUnique": false
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_snapshots": {
"name": "haex_crdt_snapshots",
"columns": {
"snapshot_id": {
"name": "snapshot_id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"created": {
"name": "created",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"epoch_hlc": {
"name": "epoch_hlc",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"location_url": {
"name": "location_url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"file_size_bytes": {
"name": "file_size_bytes",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extension_permissions": {
"name": "haex_extension_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource_type": {
"name": "resource_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"action": {
"name": "action",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"target": {
"name": "target",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"constraints": {
"name": "constraints",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'denied'"
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extension_permissions_extension_id_resource_type_action_target_unique": {
"name": "haex_extension_permissions_extension_id_resource_type_action_target_unique",
"columns": [
"extension_id",
"resource_type",
"action",
"target"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extension_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extension_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extension_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions": {
"name": "haex_extensions",
"columns": {
"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": true,
"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
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extensions_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_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_group_items": {
"name": "haex_passwords_group_items",
"columns": {
"group_id": {
"name": "group_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_group_items_group_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"haex_passwords_group_items_item_id_group_id_pk": {
"columns": [
"item_id",
"group_id"
],
"name": "haex_passwords_group_items_item_id_group_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_groups": {
"name": "haex_passwords_groups",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"parent_id": {
"name": "parent_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_groups_parent_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_groups",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"parent_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_details": {
"name": "haex_passwords_item_details",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"note": {
"name": "note",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"tags": {
"name": "tags",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_history": {
"name": "haex_passwords_item_history",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"changed_property": {
"name": "changed_property",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_history",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_key_values": {
"name": "haex_passwords_item_key_values",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_key_values",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@ -1,991 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "2f40a42e-9b3f-42be-8951-8e94baadcd65",
"prevId": "5387568f-75b3-4a85-86c5-67f539c3fedf",
"tables": {
"haex_crdt_configs": {
"name": "haex_crdt_configs",
"columns": {
"key": {
"name": "key",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_logs": {
"name": "haex_crdt_logs",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"table_name": {
"name": "table_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"row_pks": {
"name": "row_pks",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"op_type": {
"name": "op_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"column_name": {
"name": "column_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"idx_haex_timestamp": {
"name": "idx_haex_timestamp",
"columns": [
"haex_timestamp"
],
"isUnique": false
},
"idx_table_row": {
"name": "idx_table_row",
"columns": [
"table_name",
"row_pks"
],
"isUnique": false
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_crdt_snapshots": {
"name": "haex_crdt_snapshots",
"columns": {
"snapshot_id": {
"name": "snapshot_id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"created": {
"name": "created",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"epoch_hlc": {
"name": "epoch_hlc",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"location_url": {
"name": "location_url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"file_size_bytes": {
"name": "file_size_bytes",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_desktop_items": {
"name": "haex_desktop_items",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_type": {
"name": "item_type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reference_id": {
"name": "reference_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"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_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extension_permissions": {
"name": "haex_extension_permissions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"extension_id": {
"name": "extension_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"resource_type": {
"name": "resource_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"action": {
"name": "action",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"target": {
"name": "target",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"constraints": {
"name": "constraints",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'denied'"
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extension_permissions_extension_id_resource_type_action_target_unique": {
"name": "haex_extension_permissions_extension_id_resource_type_action_target_unique",
"columns": [
"extension_id",
"resource_type",
"action",
"target"
],
"isUnique": true
}
},
"foreignKeys": {
"haex_extension_permissions_extension_id_haex_extensions_id_fk": {
"name": "haex_extension_permissions_extension_id_haex_extensions_id_fk",
"tableFrom": "haex_extension_permissions",
"tableTo": "haex_extensions",
"columnsFrom": [
"extension_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_extensions": {
"name": "haex_extensions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"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": true,
"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
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"haex_extensions_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_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_settings": {
"name": "haex_settings",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_timestamp": {
"name": "haex_timestamp",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_group_items": {
"name": "haex_passwords_group_items",
"columns": {
"group_id": {
"name": "group_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_group_items_group_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_group_items_group_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_group_items_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_group_items",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"haex_passwords_group_items_item_id_group_id_pk": {
"columns": [
"item_id",
"group_id"
],
"name": "haex_passwords_group_items_item_id_group_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_groups": {
"name": "haex_passwords_groups",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"parent_id": {
"name": "parent_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_groups_parent_id_haex_passwords_groups_id_fk": {
"name": "haex_passwords_groups_parent_id_haex_passwords_groups_id_fk",
"tableFrom": "haex_passwords_groups",
"tableTo": "haex_passwords_groups",
"columnsFrom": [
"parent_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_details": {
"name": "haex_passwords_item_details",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"note": {
"name": "note",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"icon": {
"name": "icon",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"tags": {
"name": "tags",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_history": {
"name": "haex_passwords_item_history",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"changed_property": {
"name": "changed_property",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"old_value": {
"name": "old_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"new_value": {
"name": "new_value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_history_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_history",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"haex_passwords_item_key_values": {
"name": "haex_passwords_item_key_values",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"haex_tombstone": {
"name": "haex_tombstone",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk": {
"name": "haex_passwords_item_key_values_item_id_haex_passwords_item_details_id_fk",
"tableFrom": "haex_passwords_item_key_values",
"tableTo": "haex_passwords_item_details",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,71 +5,8 @@
{
"idx": 0,
"version": "6",
"when": 1759402321133,
"tag": "0000_glamorous_hulk",
"breakpoints": true
},
{
"idx": 1,
"version": "6",
"when": 1759418087677,
"tag": "0001_green_stark_industries",
"breakpoints": true
},
{
"idx": 2,
"version": "6",
"when": 1760272083150,
"tag": "0002_amazing_iron_fist",
"breakpoints": true
},
{
"idx": 3,
"version": "6",
"when": 1760611690801,
"tag": "0003_daily_polaris",
"breakpoints": true
},
{
"idx": 4,
"version": "6",
"when": 1760817142340,
"tag": "0004_mature_viper",
"breakpoints": true
},
{
"idx": 5,
"version": "6",
"when": 1760964548034,
"tag": "0005_tidy_yellowjacket",
"breakpoints": true
},
{
"idx": 6,
"version": "6",
"when": 1761137108127,
"tag": "0006_gigantic_bloodaxe",
"breakpoints": true
},
{
"idx": 7,
"version": "6",
"when": 1761141111765,
"tag": "0007_stale_longshot",
"breakpoints": true
},
{
"idx": 8,
"version": "6",
"when": 1761145177028,
"tag": "0008_dizzy_blue_shield",
"breakpoints": true
},
{
"idx": 9,
"version": "6",
"when": 1761203548348,
"tag": "0009_boring_arclight",
"when": 1761216357702,
"tag": "0000_bumpy_valkyrie",
"breakpoints": true
}
]

View File

@ -9,15 +9,14 @@ import {
} from 'drizzle-orm/sqlite-core'
import tableNames from '../tableNames.json'
// Helper function to add common CRDT columns (haexTombstone and haexTimestamp)
// Helper function to add common CRDT columns ( haexTimestamp)
export const withCrdtColumns = <
T extends Record<string, SQLiteColumnBuilderBase>,
>(
columns: T,
columnNames: { haexTombstone: string; haexTimestamp: string },
columnNames: { haexTimestamp: string },
) => ({
...columns,
haexTombstone: integer(columnNames.haexTombstone, { mode: 'boolean' }),
haexTimestamp: text(columnNames.haexTimestamp),
})
@ -30,9 +29,7 @@ export const haexSettings = sqliteTable(
key: text(),
type: text(),
value: text(),
haexTombstone: integer(tableNames.haex.settings.columns.haexTombstone, {
mode: 'boolean',
}),
haexTimestamp: text(tableNames.haex.settings.columns.haexTimestamp),
},
(table) => [unique().on(table.key, table.type, table.value)],
@ -56,9 +53,6 @@ export const haexExtensions = sqliteTable(
enabled: integer({ mode: 'boolean' }).default(true),
icon: text(),
signature: text().notNull(),
haexTombstone: integer(tableNames.haex.extensions.columns.haexTombstone, {
mode: 'boolean',
}),
haexTimestamp: text(tableNames.haex.extensions.columns.haexTimestamp),
},
(table) => [
@ -75,9 +69,7 @@ export const haexExtensionPermissions = sqliteTable(
id: text()
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
extensionId: text(
tableNames.haex.extension_permissions.columns.extensionId,
)
extensionId: text(tableNames.haex.extension_permissions.columns.extensionId)
.notNull()
.references((): AnySQLiteColumn => haexExtensions.id, {
onDelete: 'cascade',
@ -95,10 +87,6 @@ export const haexExtensionPermissions = sqliteTable(
updateAt: integer('updated_at', { mode: 'timestamp' }).$onUpdate(
() => new Date(),
),
haexTombstone: integer(
tableNames.haex.extension_permissions.columns.haexTombstone,
{ mode: 'boolean' },
),
haexTimestamp: text(
tableNames.haex.extension_permissions.columns.haexTimestamp,
),
@ -132,10 +120,6 @@ export const haexNotifications = sqliteTable(
type: text({
enum: ['error', 'success', 'warning', 'info', 'log'],
}).notNull(),
haexTombstone: integer(
tableNames.haex.notifications.columns.haexTombstone,
{ mode: 'boolean' },
),
haexTimestamp: text(tableNames.haex.notifications.columns.haexTimestamp),
},
)

View File

@ -1,121 +0,0 @@
import { sql } from 'drizzle-orm'
import {
integer,
primaryKey,
sqliteTable,
text,
type AnySQLiteColumn,
} from 'drizzle-orm/sqlite-core'
import tableNames from '../tableNames.json'
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')
.notNull()
.references((): AnySQLiteColumn => haexPasswordsItemDetails.id, {
onDelete: 'cascade',
}),
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')
.notNull()
.references((): AnySQLiteColumn => haexPasswordsItemDetails.id, {
onDelete: 'cascade',
}),
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,
{ onDelete: 'cascade' },
),
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')
.notNull()
.references((): AnySQLiteColumn => haexPasswordsGroups.id, {
onDelete: 'cascade',
}),
itemId: text('item_id')
.notNull()
.references((): AnySQLiteColumn => haexPasswordsItemDetails.id, {
onDelete: 'cascade',
}),
haex_tombstone: integer({ mode: 'boolean' }),
},
(table) => [primaryKey({ columns: [table.itemId, table.groupId] })],
)
export type InsertHaexPasswordsGroupItems =
typeof haexPasswordsGroupItems.$inferInsert
export type SelectHaexPasswordsGroupItems =
typeof haexPasswordsGroupItems.$inferSelect

View File

@ -7,7 +7,7 @@
"key": "key",
"type": "type",
"value": "value",
"haexTombstone": "haex_tombstone",
"haexTimestamp": "haex_timestamp"
}
},
@ -26,7 +26,7 @@
"signature": "signature",
"url": "url",
"version": "version",
"haexTombstone": "haex_tombstone",
"haexTimestamp": "haex_timestamp"
}
},
@ -42,7 +42,7 @@
"status": "status",
"createdAt": "created_at",
"updateAt": "updated_at",
"haexTombstone": "haex_tombstone",
"haexTimestamp": "haex_timestamp"
}
},
@ -59,7 +59,7 @@
"text": "text",
"title": "title",
"type": "type",
"haexTombstone": "haex_tombstone",
"haexTimestamp": "haex_timestamp"
}
},
@ -70,7 +70,7 @@
"name": "name",
"position": "position",
"createdAt": "created_at",
"haexTombstone": "haex_tombstone",
"haexTimestamp": "haex_timestamp"
}
},
@ -83,17 +83,11 @@
"referenceId": "reference_id",
"positionX": "position_x",
"positionY": "position_y",
"haexTombstone": "haex_tombstone",
"haexTimestamp": "haex_timestamp"
}
},
"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": {
"name": "haex_crdt_logs",

Binary file not shown.

View File

@ -1,5 +1,6 @@
// 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;
@ -8,25 +9,7 @@ use std::path::Path;
#[derive(Debug, Deserialize)]
struct Schema {
haex: Haex,
}
#[derive(Debug, Deserialize)]
#[allow(non_snake_case)]
struct Haex {
settings: TableDefinition,
extensions: TableDefinition,
extension_permissions: TableDefinition,
notifications: TableDefinition,
desktop_items: TableDefinition,
crdt: Crdt,
}
#[derive(Debug, Deserialize)]
struct Crdt {
logs: TableDefinition,
snapshots: TableDefinition,
configs: TableDefinition,
haex: HashMap<String, Value>,
}
#[derive(Debug, Deserialize)]
@ -45,185 +28,39 @@ pub fn generate_table_names() {
let reader = BufReader::new(file);
let schema: Schema =
serde_json::from_reader(reader).expect("Konnte tableNames.json nicht parsen");
let haex = schema.haex;
let code = format!(
let mut code = String::from(
r#"
// ==================================================================
// HINWEIS: Diese Datei wurde automatisch von build.rs generiert.
// Manuelle Änderungen werden bei der nächsten Kompilierung überschrieben!
// ==================================================================
// --- Table: haex_settings ---
pub const TABLE_SETTINGS: &str = "{t_settings}";
pub const COL_SETTINGS_ID: &str = "{c_settings_id}";
pub const COL_SETTINGS_KEY: &str = "{c_settings_key}";
pub const COL_SETTINGS_TYPE: &str = "{c_settings_type}";
pub const COL_SETTINGS_VALUE: &str = "{c_settings_value}";
pub const COL_SETTINGS_HAEX_TOMBSTONE: &str = "{c_settings_tombstone}";
pub const COL_SETTINGS_HAEX_TIMESTAMP: &str = "{c_settings_timestamp}";
// --- Table: haex_extensions ---
pub const TABLE_EXTENSIONS: &str = "{t_extensions}";
pub const COL_EXTENSIONS_ID: &str = "{c_ext_id}";
pub const COL_EXTENSIONS_AUTHOR: &str = "{c_ext_author}";
pub const COL_EXTENSIONS_DESCRIPTION: &str = "{c_ext_description}";
pub const COL_EXTENSIONS_ENTRY: &str = "{c_ext_entry}";
pub const COL_EXTENSIONS_HOMEPAGE: &str = "{c_ext_homepage}";
pub const COL_EXTENSIONS_ENABLED: &str = "{c_ext_enabled}";
pub const COL_EXTENSIONS_ICON: &str = "{c_ext_icon}";
pub const COL_EXTENSIONS_NAME: &str = "{c_ext_name}";
pub const COL_EXTENSIONS_PUBLIC_KEY: &str = "{c_ext_public_key}";
pub const COL_EXTENSIONS_SIGNATURE: &str = "{c_ext_signature}";
pub const COL_EXTENSIONS_URL: &str = "{c_ext_url}";
pub const COL_EXTENSIONS_VERSION: &str = "{c_ext_version}";
pub const COL_EXTENSIONS_HAEX_TOMBSTONE: &str = "{c_ext_tombstone}";
pub const COL_EXTENSIONS_HAEX_TIMESTAMP: &str = "{c_ext_timestamp}";
// --- Table: haex_extension_permissions ---
pub const TABLE_EXTENSION_PERMISSIONS: &str = "{t_ext_perms}";
pub const COL_EXT_PERMS_ID: &str = "{c_extp_id}";
pub const COL_EXT_PERMS_EXTENSION_ID: &str = "{c_extp_extensionId}";
pub const COL_EXT_PERMS_RESOURCE_TYPE: &str = "{c_extp_resourceType}";
pub const COL_EXT_PERMS_ACTION: &str = "{c_extp_action}";
pub const COL_EXT_PERMS_TARGET: &str = "{c_extp_target}";
pub const COL_EXT_PERMS_CONSTRAINTS: &str = "{c_extp_constraints}";
pub const COL_EXT_PERMS_STATUS: &str = "{c_extp_status}";
pub const COL_EXT_PERMS_CREATED_AT: &str = "{c_extp_createdAt}";
pub const COL_EXT_PERMS_UPDATE_AT: &str = "{c_extp_updateAt}";
pub const COL_EXT_PERMS_HAEX_TOMBSTONE: &str = "{c_extp_tombstone}";
pub const COL_EXT_PERMS_HAEX_TIMESTAMP: &str = "{c_extp_timestamp}";
// --- Table: haex_notifications ---
pub const TABLE_NOTIFICATIONS: &str = "{t_notifications}";
pub const COL_NOTIFICATIONS_ID: &str = "{c_notif_id}";
pub const COL_NOTIFICATIONS_ALT: &str = "{c_notif_alt}";
pub const COL_NOTIFICATIONS_DATE: &str = "{c_notif_date}";
pub const COL_NOTIFICATIONS_ICON: &str = "{c_notif_icon}";
pub const COL_NOTIFICATIONS_IMAGE: &str = "{c_notif_image}";
pub const COL_NOTIFICATIONS_READ: &str = "{c_notif_read}";
pub const COL_NOTIFICATIONS_SOURCE: &str = "{c_notif_source}";
pub const COL_NOTIFICATIONS_TEXT: &str = "{c_notif_text}";
pub const COL_NOTIFICATIONS_TITLE: &str = "{c_notif_title}";
pub const COL_NOTIFICATIONS_TYPE: &str = "{c_notif_type}";
pub const COL_NOTIFICATIONS_HAEX_TOMBSTONE: &str = "{c_notif_tombstone}";
// --- Table: haex_desktop_items ---
pub const TABLE_DESKTOP_ITEMS: &str = "{t_desktop_items}";
pub const COL_DESKTOP_ITEMS_ID: &str = "{c_desktop_id}";
pub const COL_DESKTOP_ITEMS_ITEM_TYPE: &str = "{c_desktop_itemType}";
pub const COL_DESKTOP_ITEMS_REFERENCE_ID: &str = "{c_desktop_referenceId}";
pub const COL_DESKTOP_ITEMS_POSITION_X: &str = "{c_desktop_positionX}";
pub const COL_DESKTOP_ITEMS_POSITION_Y: &str = "{c_desktop_positionY}";
pub const COL_DESKTOP_ITEMS_HAEX_TOMBSTONE: &str = "{c_desktop_tombstone}";
pub const COL_DESKTOP_ITEMS_HAEX_TIMESTAMP: &str = "{c_desktop_timestamp}";
// --- Table: haex_crdt_logs ---
pub const TABLE_CRDT_LOGS: &str = "{t_crdt_logs}";
pub const COL_CRDT_LOGS_ID: &str = "{c_crdt_logs_id}";
pub const COL_CRDT_LOGS_HAEX_TIMESTAMP: &str = "{c_crdt_logs_timestamp}";
pub const COL_CRDT_LOGS_TABLE_NAME: &str = "{c_crdt_logs_tableName}";
pub const COL_CRDT_LOGS_ROW_PKS: &str = "{c_crdt_logs_rowPks}";
pub const COL_CRDT_LOGS_OP_TYPE: &str = "{c_crdt_logs_opType}";
pub const COL_CRDT_LOGS_COLUMN_NAME: &str = "{c_crdt_logs_columnName}";
pub const COL_CRDT_LOGS_NEW_VALUE: &str = "{c_crdt_logs_newValue}";
pub const COL_CRDT_LOGS_OLD_VALUE: &str = "{c_crdt_logs_oldValue}";
// --- Table: haex_crdt_snapshots ---
pub const TABLE_CRDT_SNAPSHOTS: &str = "{t_crdt_snapshots}";
pub const COL_CRDT_SNAPSHOTS_ID: &str = "{c_crdt_snap_id}";
pub const COL_CRDT_SNAPSHOTS_CREATED: &str = "{c_crdt_snap_created}";
pub const COL_CRDT_SNAPSHOTS_EPOCH_HLC: &str = "{c_crdt_snap_epoch}";
pub const COL_CRDT_SNAPSHOTS_LOCATION_URL: &str = "{c_crdt_snap_location}";
pub const COL_CRDT_SNAPSHOTS_FILE_SIZE: &str = "{c_crdt_snap_size}";
// --- Table: haex_crdt_configs ---
pub const TABLE_CRDT_CONFIGS: &str = "{t_crdt_configs}";
pub const COL_CRDT_CONFIGS_KEY: &str = "{c_crdt_configs_key}";
pub const COL_CRDT_CONFIGS_VALUE: &str = "{c_crdt_configs_value}";
"#,
// Settings
t_settings = haex.settings.name,
c_settings_id = haex.settings.columns["id"],
c_settings_key = haex.settings.columns["key"],
c_settings_type = haex.settings.columns["type"],
c_settings_value = haex.settings.columns["value"],
c_settings_tombstone = haex.settings.columns["haexTombstone"],
c_settings_timestamp = haex.settings.columns["haexTimestamp"],
// Extensions
t_extensions = haex.extensions.name,
c_ext_id = haex.extensions.columns["id"],
c_ext_author = haex.extensions.columns["author"],
c_ext_description = haex.extensions.columns["description"],
c_ext_entry = haex.extensions.columns["entry"],
c_ext_homepage = haex.extensions.columns["homepage"],
c_ext_enabled = haex.extensions.columns["enabled"],
c_ext_icon = haex.extensions.columns["icon"],
c_ext_name = haex.extensions.columns["name"],
c_ext_public_key = haex.extensions.columns["public_key"],
c_ext_signature = haex.extensions.columns["signature"],
c_ext_url = haex.extensions.columns["url"],
c_ext_version = haex.extensions.columns["version"],
c_ext_tombstone = haex.extensions.columns["haexTombstone"],
c_ext_timestamp = haex.extensions.columns["haexTimestamp"],
// Extension Permissions
t_ext_perms = haex.extension_permissions.name,
c_extp_id = haex.extension_permissions.columns["id"],
c_extp_extensionId = haex.extension_permissions.columns["extensionId"],
c_extp_resourceType = haex.extension_permissions.columns["resourceType"],
c_extp_action = haex.extension_permissions.columns["action"],
c_extp_target = haex.extension_permissions.columns["target"],
c_extp_constraints = haex.extension_permissions.columns["constraints"],
c_extp_status = haex.extension_permissions.columns["status"],
c_extp_createdAt = haex.extension_permissions.columns["createdAt"],
c_extp_updateAt = haex.extension_permissions.columns["updateAt"],
c_extp_tombstone = haex.extension_permissions.columns["haexTombstone"],
c_extp_timestamp = haex.extension_permissions.columns["haexTimestamp"],
// Notifications
t_notifications = haex.notifications.name,
c_notif_id = haex.notifications.columns["id"],
c_notif_alt = haex.notifications.columns["alt"],
c_notif_date = haex.notifications.columns["date"],
c_notif_icon = haex.notifications.columns["icon"],
c_notif_image = haex.notifications.columns["image"],
c_notif_read = haex.notifications.columns["read"],
c_notif_source = haex.notifications.columns["source"],
c_notif_text = haex.notifications.columns["text"],
c_notif_title = haex.notifications.columns["title"],
c_notif_type = haex.notifications.columns["type"],
c_notif_tombstone = haex.notifications.columns["haexTombstone"],
// Desktop Items
t_desktop_items = haex.desktop_items.name,
c_desktop_id = haex.desktop_items.columns["id"],
c_desktop_itemType = haex.desktop_items.columns["itemType"],
c_desktop_referenceId = haex.desktop_items.columns["referenceId"],
c_desktop_positionX = haex.desktop_items.columns["positionX"],
c_desktop_positionY = haex.desktop_items.columns["positionY"],
c_desktop_tombstone = haex.desktop_items.columns["haexTombstone"],
c_desktop_timestamp = haex.desktop_items.columns["haexTimestamp"],
// CRDT Logs
t_crdt_logs = haex.crdt.logs.name,
c_crdt_logs_id = haex.crdt.logs.columns["id"],
c_crdt_logs_timestamp = haex.crdt.logs.columns["haexTimestamp"],
c_crdt_logs_tableName = haex.crdt.logs.columns["tableName"],
c_crdt_logs_rowPks = haex.crdt.logs.columns["rowPks"],
c_crdt_logs_opType = haex.crdt.logs.columns["opType"],
c_crdt_logs_columnName = haex.crdt.logs.columns["columnName"],
c_crdt_logs_newValue = haex.crdt.logs.columns["newValue"],
c_crdt_logs_oldValue = haex.crdt.logs.columns["oldValue"],
// CRDT Snapshots
t_crdt_snapshots = haex.crdt.snapshots.name,
c_crdt_snap_id = haex.crdt.snapshots.columns["snapshotId"],
c_crdt_snap_created = haex.crdt.snapshots.columns["created"],
c_crdt_snap_epoch = haex.crdt.snapshots.columns["epochHlc"],
c_crdt_snap_location = haex.crdt.snapshots.columns["locationUrl"],
c_crdt_snap_size = haex.crdt.snapshots.columns["fileSizeBytes"],
// CRDT Configs
t_crdt_configs = haex.crdt.configs.name,
c_crdt_configs_key = haex.crdt.configs.columns["key"],
c_crdt_configs_value = haex.crdt.configs.columns["value"]
);
// 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())
@ -231,3 +68,51 @@ pub const COL_CRDT_CONFIGS_VALUE: &str = "{c_crdt_configs_value}";
println!("cargo:rerun-if-changed=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 {}: &str = \"{}\";\n",
col_const_name, col_value
));
}
code.push('\n');
code
}

View File

@ -1,21 +1,19 @@
// src-tauri/src/crdt/insert_transformer.rs
// INSERT-spezifische CRDT-Transformationen (ON CONFLICT, RETURNING)
use crate::crdt::trigger::{HLC_TIMESTAMP_COLUMN, TOMBSTONE_COLUMN};
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 {
tombstone_column: &'static str,
hlc_timestamp_column: &'static str,
}
impl InsertTransformer {
pub fn new() -> Self {
Self {
tombstone_column: TOMBSTONE_COLUMN,
hlc_timestamp_column: HLC_TIMESTAMP_COLUMN,
}
}
@ -58,11 +56,9 @@ impl InsertTransformer {
insert_stmt: &mut Insert,
timestamp: &Timestamp,
) -> Result<(), DatabaseError> {
// Add both haex_timestamp and haex_tombstone columns if not exists
// Add haex_timestamp column if not exists
let hlc_col_index =
Self::find_or_add_column(&mut insert_stmt.columns, self.hlc_timestamp_column);
let tombstone_col_index =
Self::find_or_add_column(&mut insert_stmt.columns, self.tombstone_column);
// ON CONFLICT Logik komplett entfernt!
// Bei Hard Deletes gibt es keine Tombstone-Einträge mehr zu reaktivieren
@ -74,24 +70,15 @@ impl InsertTransformer {
for row in &mut values.rows {
let hlc_value =
Expr::Value(Value::SingleQuotedString(timestamp.to_string()).into());
let tombstone_value =
Expr::Value(Value::Number("0".to_string(), false).into());
Self::set_or_push_value(row, hlc_col_index, hlc_value);
Self::set_or_push_value(row, tombstone_col_index, tombstone_value);
}
}
SetExpr::Select(select) => {
let hlc_value =
Expr::Value(Value::SingleQuotedString(timestamp.to_string()).into());
let tombstone_value = Expr::Value(Value::Number("0".to_string(), false).into());
Self::set_or_push_projection(&mut select.projection, hlc_col_index, hlc_value);
Self::set_or_push_projection(
&mut select.projection,
tombstone_col_index,
tombstone_value,
);
}
_ => {
return Err(DatabaseError::UnsupportedStatement {

View File

@ -1,12 +1,12 @@
// src-tauri/src/crdt/transformer.rs
use crate::crdt::insert_transformer::InsertTransformer;
use crate::crdt::trigger::{HLC_TIMESTAMP_COLUMN, TOMBSTONE_COLUMN};
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,
Assignment, AssignmentTarget, ColumnDef, DataType, Expr, Ident, ObjectName, ObjectNamePart,
Statement, TableFactor, TableObject, Value,
};
use std::borrow::Cow;
use std::collections::HashSet;
@ -15,13 +15,11 @@ use uhlc::Timestamp;
/// Konfiguration für CRDT-Spalten
#[derive(Clone)]
struct CrdtColumns {
tombstone: &'static str,
hlc_timestamp: &'static str,
}
impl CrdtColumns {
const DEFAULT: Self = Self {
tombstone: TOMBSTONE_COLUMN,
hlc_timestamp: HLC_TIMESTAMP_COLUMN,
};
@ -37,13 +35,6 @@ impl CrdtColumns {
/// 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.tombstone) {
columns.push(ColumnDef {
name: Ident::new(self.tombstone),
data_type: DataType::Integer(None),
options: vec![],
});
}
if !columns.iter().any(|c| c.name.value == self.hlc_timestamp) {
columns.push(ColumnDef {
name: Ident::new(self.hlc_timestamp),
@ -86,7 +77,7 @@ impl CrdtTransformer {
// =================================================================
// ÖFFENTLICHE API-METHODEN
// =================================================================
pub fn transform_execute_statement_with_table_info(
&self,
stmt: &mut Statement,
@ -171,7 +162,7 @@ impl CrdtTransformer {
Statement::Update {
table, assignments, ..
} => {
if let TableFactor::Table { name, ..} = &table.relation {
if let TableFactor::Table { name, .. } = &table.relation {
if self.is_crdt_sync_table(name) {
assignments.push(self.columns.create_hlc_assignment(hlc_timestamp));
}

View File

@ -12,18 +12,16 @@ 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 TOMBSTONE_COLUMN: &str = "haex_tombstone";
pub const HLC_TIMESTAMP_COLUMN: &str = "haex_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)]
pub enum CrdtSetupError {
/// Kapselt einen Fehler, der von der rusqlite-Bibliothek kommt.
DatabaseError(rusqlite::Error),
/// Die Tabelle hat keine Tombstone-Spalte, was eine CRDT-Voraussetzung ist.
TombstoneColumnMissing {
table_name: String,
column_name: String,
},
HlcColumnMissing {
table_name: String,
column_name: String,
@ -37,14 +35,6 @@ 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::HlcColumnMissing {
table_name,
column_name,
@ -110,13 +100,6 @@ pub fn setup_triggers_for_table(
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) {
return Err(CrdtSetupError::HlcColumnMissing {
table_name: table_name.to_string(),
@ -138,7 +121,7 @@ pub fn setup_triggers_for_table(
let cols_to_track: Vec<String> = columns
.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())
.collect();
@ -269,9 +252,10 @@ fn generate_insert_trigger_sql(table_name: &str, pks: &[String], cols: &[String]
let column_inserts = if cols.is_empty() {
// Nur PKs -> einfacher Insert ins Log
format!(
"INSERT INTO {log_table} (haex_timestamp, op_type, table_name, row_pks)
VALUES (NEW.\"{hlc_col}\", 'INSERT', '{table}', json_object({pk_payload}));",
"INSERT INTO {log_table} (id, haex_timestamp, op_type, table_name, row_pks)
VALUES ({uuid_fn}(), NEW.\"{hlc_col}\", 'INSERT', '{table}', json_object({pk_payload}));",
log_table = TABLE_CRDT_LOGS,
uuid_fn = UUID_FUNCTION_NAME,
hlc_col = HLC_TIMESTAMP_COLUMN,
table = table_name,
pk_payload = pk_json_payload
@ -280,9 +264,10 @@ fn generate_insert_trigger_sql(table_name: &str, pks: &[String], cols: &[String]
cols.iter().fold(String::new(), |mut acc, col| {
writeln!(
&mut acc,
"INSERT INTO {log_table} (haex_timestamp, op_type, table_name, row_pks, column_name, new_value)
VALUES (NEW.\"{hlc_col}\", 'INSERT', '{table}', json_object({pk_payload}), '{column}', json_object('value', NEW.\"{column}\"));",
"INSERT INTO {log_table} (id, haex_timestamp, op_type, table_name, row_pks, column_name, new_value)
VALUES ({uuid_fn}(), NEW.\"{hlc_col}\", 'INSERT', '{table}', json_object({pk_payload}), '{column}', json_object('value', NEW.\"{column}\"));",
log_table = TABLE_CRDT_LOGS,
uuid_fn = UUID_FUNCTION_NAME,
hlc_col = HLC_TIMESTAMP_COLUMN,
table = table_name,
pk_payload = pk_json_payload,
@ -324,11 +309,12 @@ fn generate_update_trigger_sql(table_name: &str, pks: &[String], cols: &[String]
for col in cols {
writeln!(
&mut body,
"INSERT INTO {log_table} (haex_timestamp, op_type, table_name, row_pks, column_name, new_value, old_value)
SELECT NEW.\"{hlc_col}\", 'UPDATE', '{table}', json_object({pk_payload}), '{column}',
"INSERT INTO {log_table} (id, haex_timestamp, op_type, table_name, row_pks, column_name, new_value, old_value)
SELECT {uuid_fn}(), NEW.\"{hlc_col}\", 'UPDATE', '{table}', json_object({pk_payload}), '{column}',
json_object('value', NEW.\"{column}\"), json_object('value', OLD.\"{column}\")
WHERE NEW.\"{column}\" IS NOT OLD.\"{column}\";",
log_table = TABLE_CRDT_LOGS,
uuid_fn = UUID_FUNCTION_NAME,
hlc_col = HLC_TIMESTAMP_COLUMN,
table = table_name,
pk_payload = pk_json_payload,
@ -367,10 +353,11 @@ fn generate_delete_trigger_sql(table_name: &str, pks: &[String], cols: &[String]
for col in cols {
writeln!(
&mut body,
"INSERT INTO {log_table} (haex_timestamp, op_type, table_name, row_pks, column_name, old_value)
VALUES (OLD.\"{hlc_col}\", 'DELETE', '{table}', json_object({pk_payload}), '{column}',
"INSERT INTO {log_table} (id, haex_timestamp, op_type, table_name, row_pks, column_name, old_value)
VALUES ({uuid_fn}(), OLD.\"{hlc_col}\", 'DELETE', '{table}', json_object({pk_payload}), '{column}',
json_object('value', OLD.\"{column}\"));",
log_table = TABLE_CRDT_LOGS,
uuid_fn = UUID_FUNCTION_NAME,
hlc_col = HLC_TIMESTAMP_COLUMN,
table = table_name,
pk_payload = pk_json_payload,
@ -381,13 +368,15 @@ fn generate_delete_trigger_sql(table_name: &str, pks: &[String], cols: &[String]
// Nur PKs -> minimales Delete Log
writeln!(
&mut body,
"INSERT INTO {log_table} (haex_timestamp, op_type, table_name, row_pks)
VALUES (OLD.\"{hlc_col}\", 'DELETE', '{table}', json_object({pk_payload}));",
"INSERT INTO {log_table} (id, haex_timestamp, op_type, table_name, row_pks)
VALUES ({uuid_fn}(), OLD.\"{hlc_col}\", 'DELETE', '{table}', json_object({pk_payload}));",
log_table = TABLE_CRDT_LOGS,
uuid_fn = UUID_FUNCTION_NAME,
hlc_col = HLC_TIMESTAMP_COLUMN,
table = table_name,
pk_payload = pk_json_payload
).unwrap();
)
.unwrap();
}
let trigger_name = DELETE_TRIGGER_TPL.replace("{TABLE_NAME}", table_name);

View File

@ -1,9 +1,11 @@
// src-tauri/src/database/core.rs
use crate::crdt::trigger::UUID_FUNCTION_NAME;
use crate::database::error::DatabaseError;
use crate::database::DbConnection;
use crate::extension::database::executor::SqlExecutor;
use base64::{engine::general_purpose::STANDARD, Engine as _};
use rusqlite::functions::FunctionFlags;
use rusqlite::types::Value as SqlValue;
use rusqlite::{
types::{Value as RusqliteValue, ValueRef},
@ -13,6 +15,7 @@ use serde_json::Value as JsonValue;
use sqlparser::ast::{Expr, Query, Select, SetExpr, Statement, TableFactor, TableObject};
use sqlparser::dialect::SQLiteDialect;
use sqlparser::parser::Parser;
use uuid::Uuid;
/// Öffnet und initialisiert eine Datenbank mit Verschlüsselung
pub fn open_and_init_db(path: &str, key: &str, create: bool) -> Result<Connection, DatabaseError> {
@ -34,6 +37,19 @@ pub fn open_and_init_db(path: &str, key: &str, create: bool) -> Result<Connectio
reason: e.to_string(),
})?;
// Register custom UUID function for SQLite triggers
conn.create_scalar_function(
UUID_FUNCTION_NAME,
0,
FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC,
|_ctx| {
Ok(Uuid::new_v4().to_string())
},
)
.map_err(|e| DatabaseError::DatabaseError {
reason: format!("Failed to register {} function: {}", UUID_FUNCTION_NAME, e),
})?;
let journal_mode: String = conn
.query_row("PRAGMA journal_mode=WAL;", [], |row| row.get(0))
.map_err(|e| DatabaseError::PragmaError {

View File

@ -16,8 +16,6 @@ pub struct HaexSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_tombstone: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_timestamp: Option<String>,
}
@ -28,8 +26,7 @@ impl HaexSettings {
key: row.get(1)?,
r#type: row.get(2)?,
value: row.get(3)?,
haex_tombstone: row.get(4)?,
haex_timestamp: row.get(5)?,
haex_timestamp: row.get(4)?,
})
}
}
@ -54,8 +51,6 @@ pub struct HaexExtensions {
pub icon: Option<String>,
pub signature: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_tombstone: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_timestamp: Option<String>,
}
@ -73,8 +68,7 @@ impl HaexExtensions {
enabled: row.get(8)?,
icon: row.get(9)?,
signature: row.get(10)?,
haex_tombstone: row.get(11)?,
haex_timestamp: row.get(12)?,
haex_timestamp: row.get(11)?,
})
}
}
@ -83,8 +77,7 @@ impl HaexExtensions {
#[serde(rename_all = "camelCase")]
pub struct HaexExtensionPermissions {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub extension_id: Option<String>,
pub extension_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub resource_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
@ -99,8 +92,6 @@ pub struct HaexExtensionPermissions {
#[serde(skip_serializing_if = "Option::is_none")]
pub updated_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_tombstone: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_timestamp: Option<String>,
}
@ -116,8 +107,7 @@ impl HaexExtensionPermissions {
status: row.get(6)?,
created_at: row.get(7)?,
updated_at: row.get(8)?,
haex_tombstone: row.get(9)?,
haex_timestamp: row.get(10)?,
haex_timestamp: row.get(9)?,
})
}
}
@ -200,3 +190,51 @@ impl HaexCrdtConfigs {
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HaexDesktopItems {
pub id: String,
pub workspace_id: String,
pub item_type: String,
pub reference_id: String,
pub position_x: i64,
pub position_y: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_timestamp: Option<String>,
}
impl HaexDesktopItems {
pub fn from_row(row: &rusqlite::Row) -> rusqlite::Result<Self> {
Ok(Self {
id: row.get(0)?,
workspace_id: row.get(1)?,
item_type: row.get(2)?,
reference_id: row.get(3)?,
position_x: row.get(4)?,
position_y: row.get(5)?,
haex_timestamp: row.get(6)?,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HaexWorkspaces {
pub id: String,
pub name: String,
pub position: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_timestamp: Option<String>,
}
impl HaexWorkspaces {
pub fn from_row(row: &rusqlite::Row) -> rusqlite::Result<Self> {
Ok(Self {
id: row.get(0)?,
name: row.get(1)?,
position: row.get(2)?,
haex_timestamp: row.get(3)?,
})
}
}

View File

@ -0,0 +1,67 @@
// src-tauri/src/database/init.rs
// Database initialization utilities (trigger setup, etc.)
use crate::crdt::trigger;
use crate::database::error::DatabaseError;
use crate::table_names::{
TABLE_DESKTOP_ITEMS,
TABLE_EXTENSIONS,
TABLE_EXTENSION_PERMISSIONS,
TABLE_NOTIFICATIONS,
TABLE_SETTINGS,
TABLE_WORKSPACES,
};
use rusqlite::{params, Connection};
/// Liste aller CRDT-Tabellen die Trigger benötigen (ohne Password-Tabellen - die kommen in Extension)
const CRDT_TABLES: &[&str] = &[
TABLE_SETTINGS,
TABLE_EXTENSIONS,
TABLE_EXTENSION_PERMISSIONS,
TABLE_NOTIFICATIONS,
TABLE_WORKSPACES,
TABLE_DESKTOP_ITEMS,
];
/// Prüft ob Trigger bereits initialisiert wurden und erstellt sie falls nötig
///
/// Diese Funktion wird beim ersten Öffnen einer Template-DB aufgerufen.
/// Sie erstellt alle CRDT-Trigger für die definierten Tabellen und markiert
/// die Initialisierung in haex_settings.
///
/// Bei Migrations (ALTER TABLE) werden Trigger automatisch neu erstellt,
/// daher ist kein Versioning nötig.
pub fn ensure_triggers_initialized(conn: &mut Connection) -> Result<bool, DatabaseError> {
let tx = conn.transaction()?;
// Check if triggers already initialized
let check_sql = format!(
"SELECT value FROM {} WHERE key = ? AND type = ?",
TABLE_SETTINGS
);
let initialized: Option<String> = tx
.query_row(
&check_sql,
params!["triggers_initialized", "system"],
|row| row.get(0),
)
.ok();
if initialized.is_some() {
eprintln!("DEBUG: Triggers already initialized, skipping");
tx.commit()?; // Wichtig: Transaktion trotzdem abschließen
return Ok(true); // true = war schon initialisiert
}
eprintln!("INFO: Initializing CRDT triggers for database...");
// Create triggers for all CRDT tables
for table_name in CRDT_TABLES {
eprintln!(" - Setting up triggers for: {}", table_name);
trigger::setup_triggers_for_table(&tx, table_name, false)?;
}
tx.commit()?;
eprintln!("INFO: ✓ CRDT triggers created successfully (flag pending)");
Ok(false) // false = wurde gerade initialisiert
}

View File

@ -3,11 +3,13 @@
pub mod core;
pub mod error;
pub mod generated;
pub mod init;
use crate::crdt::hlc::HlcService;
use crate::database::core::execute_with_crdt;
use crate::database::error::DatabaseError;
use crate::extension::database::executor::SqlExecutor;
use crate::table_names::TABLE_CRDT_CONFIGS;
use crate::table_names::{TABLE_CRDT_CONFIGS, TABLE_SETTINGS};
use crate::AppState;
use rusqlite::Connection;
use serde::{Deserialize, Serialize};
@ -76,7 +78,8 @@ pub fn sql_query_with_crdt(
core::with_connection(&state.db, |conn| {
let tx = conn.transaction().map_err(DatabaseError::from)?;
let (_modified_tables, result) = SqlExecutor::query_internal(&tx, &hlc_service, &sql, &params)?;
let (_modified_tables, result) =
SqlExecutor::query_internal(&tx, &hlc_service, &sql, &params)?;
tx.commit().map_err(DatabaseError::from)?;
Ok(result)
})
@ -417,9 +420,12 @@ fn initialize_session(
state: &State<'_, AppState>,
) -> Result<(), DatabaseError> {
// 1. Establish the raw database connection
let conn = core::open_and_init_db(path, key, false)?;
let mut conn = core::open_and_init_db(path, key, false)?;
// 2. Initialize the HLC service
// 2. Ensure CRDT triggers are initialized (for template DB)
let triggers_were_already_initialized = init::ensure_triggers_initialized(&mut conn)?;
// 3. Initialize the HLC service
let hlc_service = HlcService::try_initialize(&conn, app_handle).map_err(|e| {
// We convert the HlcError into a DatabaseError
DatabaseError::ExecutionError {
@ -429,16 +435,53 @@ fn initialize_session(
}
})?;
// 3. Store everything in the global AppState
// 4. Store everything in the global AppState
let mut db_guard = state.db.0.lock().map_err(|e| DatabaseError::LockError {
reason: e.to_string(),
})?;
// Wichtig: Wir brauchen den db_guard gleich nicht mehr,
// da 'execute_with_crdt' 'with_connection' aufruft, was
// 'state.db' selbst locken muss.
// Wir müssen den Guard freigeben, *bevor* wir 'execute_with_crdt' rufen,
// um einen Deadlock zu verhindern.
// Aber wir müssen die 'conn' erst hineinbewegen.
*db_guard = Some(conn);
drop(db_guard);
let mut hlc_guard = state.hlc.lock().map_err(|e| DatabaseError::LockError {
reason: e.to_string(),
})?;
*hlc_guard = hlc_service;
// WICHTIG: hlc_guard *nicht* freigeben, da 'execute_with_crdt'
// eine Referenz auf die Guard erwartet.
// 5. NEUER SCHRITT: Setze das Flag via CRDT, falls nötig
if !triggers_were_already_initialized {
eprintln!("INFO: Setting 'triggers_initialized' flag via CRDT...");
let insert_sql = format!(
"INSERT INTO {} (id, key, type, value) VALUES (?, ?, ?, ?)",
TABLE_SETTINGS
);
// execute_with_crdt erwartet Vec<JsonValue>, kein params!-Makro
let params_vec: Vec<JsonValue> = vec![
JsonValue::String(uuid::Uuid::new_v4().to_string()),
JsonValue::String("triggers_initialized".to_string()),
JsonValue::String("system".to_string()),
JsonValue::String("1".to_string()),
];
// Jetzt können wir 'execute_with_crdt' sicher aufrufen,
// da der AppState initialisiert ist.
execute_with_crdt(
insert_sql, params_vec, &state.db, // Das &DbConnection (der Mutex)
&hlc_guard, // Die gehaltene MutexGuard
)?;
eprintln!("INFO: ✓ 'triggers_initialized' flag set.");
}
Ok(())
}

View File

@ -155,7 +155,6 @@ impl ExtensionPermissions {
.and_then(|c| serde_json::from_value::<PermissionConstraints>(c.clone()).ok()),
status: p.status.clone().unwrap_or(PermissionStatus::Ask),
haex_timestamp: None,
haex_tombstone: None,
})
}
}

View File

@ -52,7 +52,7 @@ impl SqlExecutor {
}
let sql_str = statement.to_string();
eprintln!("DEBUG: Transformed SQL: {}", sql_str);
eprintln!("DEBUG: Transformed execute SQL: {}", sql_str);
// Führe Statement aus
tx.execute(&sql_str, params)

View File

@ -165,8 +165,6 @@ pub struct ExtensionPermission {
pub constraints: Option<PermissionConstraints>,
pub status: PermissionStatus,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_tombstone: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub haex_timestamp: Option<String>,
}
@ -341,9 +339,9 @@ impl From<&ExtensionPermission> for crate::database::generated::HaexExtensionPer
fn from(perm: &ExtensionPermission) -> Self {
Self {
id: perm.id.clone(),
extension_id: Some(perm.extension_id.clone()),
extension_id: perm.extension_id.clone(),
resource_type: Some(perm.resource_type.as_str().to_string()),
action: Some(perm.action.as_str()),
action: Some(perm.action.as_str().to_string()),
target: Some(perm.target.clone()),
constraints: perm
.constraints
@ -352,7 +350,6 @@ impl From<&ExtensionPermission> for crate::database::generated::HaexExtensionPer
status: perm.status.as_str().to_string(),
created_at: None,
updated_at: None,
haex_tombstone: perm.haex_tombstone,
haex_timestamp: perm.haex_timestamp.clone(),
}
}
@ -382,13 +379,12 @@ impl From<crate::database::generated::HaexExtensionPermissions> for ExtensionPer
Self {
id: db_perm.id,
extension_id: db_perm.extension_id.unwrap_or_default(),
extension_id: db_perm.extension_id,
resource_type,
action,
target: db_perm.target.unwrap_or_default(),
constraints,
status,
haex_tombstone: db_perm.haex_tombstone,
haex_timestamp: db_perm.haex_timestamp,
}
}

View File

@ -100,9 +100,6 @@ const vault = reactive<{
}
} */
const { syncLocaleAsync, syncThemeAsync, syncVaultNameAsync } =
useVaultSettingsStore()
const check = ref(false)
const initVault = () => {
@ -156,11 +153,6 @@ const onOpenDatabase = async () => {
},
}),
)
await Promise.allSettled([
syncLocaleAsync(),
syncThemeAsync(),
syncVaultNameAsync(),
])
} catch (error) {
open.value = false
console.error('handleError', error, typeof error)

View File

@ -50,12 +50,20 @@ const { isKnownDeviceAsync } = useDeviceStore()
const { loadExtensionsAsync } = useExtensionsStore()
const { setDeviceIdIfNotExistsAsync, addDeviceNameAsync } = useDeviceStore()
const { deviceId } = storeToRefs(useDeviceStore())
const { syncLocaleAsync, syncThemeAsync, syncVaultNameAsync } =
useVaultSettingsStore()
onMounted(async () => {
try {
await setDeviceIdIfNotExistsAsync()
await loadExtensionsAsync()
await readNotificationsAsync()
// Sync settings first before other initialization
await Promise.allSettled([
syncLocaleAsync(),
syncThemeAsync(),
syncVaultNameAsync(),
setDeviceIdIfNotExistsAsync(),
loadExtensionsAsync(),
readNotificationsAsync(),
])
const knownDevice = await isKnownDeviceAsync()

View File

@ -66,7 +66,6 @@ export const useWorkspaceStore = defineStore('workspaceStore', () => {
name: name || `Workspace ${newIndex}`,
position: workspaces.value.length,
haexTimestamp: '',
haexTombstone: false,
}
workspaces.value.push(newWorkspace)
currentWorkspaceIndex.value = workspaces.value.length - 1

View File

@ -71,7 +71,6 @@ export const useVaultSettingsStore = defineStore('vaultSettingsStore', () => {
where: eq(schema.haexSettings.key, VaultSettingsKeyEnum.theme),
})
console.log('found currentThemeRow', currentThemeRow)
if (currentThemeRow?.value) {
const theme = availableThemes.value.find(
(theme) => theme.value === currentThemeRow.value,
@ -100,7 +99,6 @@ export const useVaultSettingsStore = defineStore('vaultSettingsStore', () => {
where: eq(schema.haexSettings.key, VaultSettingsKeyEnum.vaultName),
})
console.log('found currentVaultNameRow', currentVaultNameRow)
if (currentVaultNameRow?.value) {
currentVaultName.value =
currentVaultNameRow.value || haexVault.defaultVaultName || 'HaexHub'