...
This commit is contained in:
		| @@ -25,7 +25,7 @@ fn error_to_status_code(error: &KvsError) -> i32 { | ||||
| } | ||||
|  | ||||
| /// Initialize a key-value store database and object store | ||||
| #[wasm_bindgen] | ||||
| // Functions are exported via lib.rs, so no wasm_bindgen here | ||||
| pub fn kv_store_init(db_name: &str, store_name: &str) -> Promise { | ||||
|     console::log_1(&JsValue::from_str(&format!("Initializing KV store: {}, {}", db_name, store_name))); | ||||
|      | ||||
| @@ -47,7 +47,7 @@ pub fn kv_store_init(db_name: &str, store_name: &str) -> Promise { | ||||
| } | ||||
|  | ||||
| /// Store a value in the key-value store | ||||
| #[wasm_bindgen] | ||||
| // Functions are exported via lib.rs, so no wasm_bindgen here | ||||
| pub fn kv_store_put(db_name: &str, store_name: &str, key: &str, value_json: &str) -> Promise { | ||||
|     console::log_1(&JsValue::from_str(&format!("Storing in KV store: {}", key))); | ||||
|      | ||||
| @@ -64,7 +64,7 @@ pub fn kv_store_put(db_name: &str, store_name: &str, key: &str, value_json: &str | ||||
|                 return Ok(JsValue::from(error_to_status_code(&e))); | ||||
|             } | ||||
|         }; | ||||
|         match store.put(&key, &value_json).await { | ||||
|         match store.set(&key, &value_json).await { | ||||
|             Ok(_) => { | ||||
|                 console::log_1(&JsValue::from_str(&format!("Successfully stored key: {}", key))); | ||||
|                 Ok(JsValue::from(0)) // Success | ||||
| @@ -78,13 +78,13 @@ pub fn kv_store_put(db_name: &str, store_name: &str, key: &str, value_json: &str | ||||
| } | ||||
|  | ||||
| /// Retrieve a value from the key-value store | ||||
| #[wasm_bindgen] | ||||
| // Functions are exported via lib.rs, so no wasm_bindgen here | ||||
| pub fn kv_store_get(db_name: &str, store_name: &str, key: &str) -> Promise { | ||||
|     console::log_1(&JsValue::from_str(&format!("Retrieving from KV store: {}", key))); | ||||
|      | ||||
|     let db_name = db_name.to_string(); | ||||
|     let store_name = store_name.to_string(); | ||||
|     let key = key.to_string(); | ||||
|     let key_str = key.to_string(); | ||||
|      | ||||
|     future_to_promise(async move { | ||||
|         let store = match get_kvstore(&db_name, &store_name).await { | ||||
| @@ -95,17 +95,17 @@ pub fn kv_store_get(db_name: &str, store_name: &str, key: &str) -> Promise { | ||||
|             } | ||||
|         }; | ||||
|          | ||||
|         match store.get::<String>(&key).await { | ||||
|         match store.get::<String, String>(key_str.clone()).await { | ||||
|             Ok(value) => { | ||||
|                 console::log_1(&JsValue::from_str(&format!("Successfully retrieved key: {}", key))); | ||||
|                 console::log_1(&JsValue::from_str(&format!("Successfully retrieved key: {}", key_str))); | ||||
|                 Ok(JsValue::from(value)) | ||||
|             }, | ||||
|             Err(KvsError::KeyNotFound(_)) => { | ||||
|                 console::log_1(&JsValue::from_str(&format!("Key not found: {}", key))); | ||||
|                 console::log_1(&JsValue::from_str(&format!("Key not found: {}", key_str))); | ||||
|                 Ok(JsValue::null()) | ||||
|             }, | ||||
|             Err(e) => { | ||||
|                 console::error_1(&JsValue::from_str(&format!("Failed to retrieve key: {}, error: {:?}", key, e))); | ||||
|                 console::error_1(&JsValue::from_str(&format!("Failed to retrieve key: {}, error: {:?}", key_str, e))); | ||||
|                 Err(JsValue::from_str(&e.to_string())) | ||||
|             }, | ||||
|         } | ||||
| @@ -113,7 +113,7 @@ pub fn kv_store_get(db_name: &str, store_name: &str, key: &str) -> Promise { | ||||
| } | ||||
|  | ||||
| /// Delete a value from the key-value store | ||||
| #[wasm_bindgen] | ||||
| // Functions are exported via lib.rs, so no wasm_bindgen here | ||||
| pub fn kv_store_delete(db_name: &str, store_name: &str, key: &str) -> Promise { | ||||
|     console::log_1(&JsValue::from_str(&format!("Deleting from KV store: {}", key))); | ||||
|      | ||||
| @@ -144,7 +144,7 @@ pub fn kv_store_delete(db_name: &str, store_name: &str, key: &str) -> Promise { | ||||
| } | ||||
|  | ||||
| /// Check if a key exists in the key-value store | ||||
| #[wasm_bindgen] | ||||
| // Functions are exported via lib.rs, so no wasm_bindgen here | ||||
| pub fn kv_store_exists(db_name: &str, store_name: &str, key: &str) -> Promise { | ||||
|     console::log_1(&JsValue::from_str(&format!("Checking if key exists in KV store: {}", key))); | ||||
|      | ||||
| @@ -175,7 +175,7 @@ pub fn kv_store_exists(db_name: &str, store_name: &str, key: &str) -> Promise { | ||||
| } | ||||
|  | ||||
| /// List all keys with a given prefix | ||||
| #[wasm_bindgen] | ||||
| // Functions are exported via lib.rs, so no wasm_bindgen here | ||||
| pub fn kv_store_list_keys(db_name: &str, store_name: &str, prefix: &str) -> Promise { | ||||
|     console::log_1(&JsValue::from_str(&format!("Listing keys with prefix in KV store: {}", prefix))); | ||||
|      | ||||
| @@ -217,7 +217,7 @@ pub fn kv_store_list_keys(db_name: &str, store_name: &str, prefix: &str) -> Prom | ||||
|  | ||||
| /// Migrate data from localStorage to the key-value store | ||||
| /// This is a helper function for transitioning from the old storage approach | ||||
| #[wasm_bindgen] | ||||
| // Functions are exported via lib.rs, so no wasm_bindgen here | ||||
| pub fn kv_store_migrate_from_local_storage( | ||||
|     db_name: &str,  | ||||
|     store_name: &str,  | ||||
| @@ -257,7 +257,7 @@ pub fn kv_store_migrate_from_local_storage( | ||||
| } | ||||
|  | ||||
| /// Store a complex object (serialized as JSON) in the key-value store | ||||
| #[wasm_bindgen] | ||||
| // Functions are exported via lib.rs, so no wasm_bindgen here | ||||
| pub fn kv_store_put_object(db_name: &str, store_name: &str, key: &str, object_json: &str) -> Promise { | ||||
|     console::log_1(&JsValue::from_str(&format!("Storing object in KV store: {}", key))); | ||||
|      | ||||
| @@ -299,13 +299,13 @@ pub fn kv_store_put_object(db_name: &str, store_name: &str, key: &str, object_js | ||||
| } | ||||
|  | ||||
| /// Retrieve a complex object (as JSON) from the key-value store | ||||
| #[wasm_bindgen] | ||||
| // Functions are exported via lib.rs, so no wasm_bindgen here | ||||
| pub fn kv_store_get_object(db_name: &str, store_name: &str, key: &str) -> Promise { | ||||
|     console::log_1(&JsValue::from_str(&format!("Retrieving object from KV store: {}", key))); | ||||
|      | ||||
|     let db_name = db_name.to_string(); | ||||
|     let store_name = store_name.to_string(); | ||||
|     let key = key.to_string(); | ||||
|     let key_str = key.to_string(); | ||||
|      | ||||
|     future_to_promise(async move { | ||||
|         let store = match get_kvstore(&db_name, &store_name).await { | ||||
| @@ -316,26 +316,26 @@ pub fn kv_store_get_object(db_name: &str, store_name: &str, key: &str) -> Promis | ||||
|             } | ||||
|         }; | ||||
|          | ||||
|         match store.get::<String>(&key).await { | ||||
|         match store.get::<String, String>(key_str.clone()).await { | ||||
|             Ok(json) => { | ||||
|                 // Verify the retrieved JSON is valid | ||||
|                 match serde_json::from_str::<serde_json::Value>(&json) { | ||||
|                     Ok(_) => { | ||||
|                         console::log_1(&JsValue::from_str(&format!("Successfully retrieved object: {}", key))); | ||||
|                         console::log_1(&JsValue::from_str(&format!("Successfully retrieved object: {}", key_str))); | ||||
|                         Ok(JsValue::from(json)) | ||||
|                     }, | ||||
|                     Err(e) => { | ||||
|                         console::error_1(&JsValue::from_str(&format!("Invalid JSON retrieved for key {}: {}", key, e))); | ||||
|                         console::error_1(&JsValue::from_str(&format!("Invalid JSON retrieved for key {}: {}", key_str, e))); | ||||
|                         Err(JsValue::from_str(&format!("Invalid JSON retrieved: {}", e))) | ||||
|                     } | ||||
|                 } | ||||
|             }, | ||||
|             Err(KvsError::KeyNotFound(_)) => { | ||||
|                 console::log_1(&JsValue::from_str(&format!("Object not found: {}", key))); | ||||
|                 console::log_1(&JsValue::from_str(&format!("Object not found: {}", key_str))); | ||||
|                 Ok(JsValue::null()) | ||||
|             }, | ||||
|             Err(e) => { | ||||
|                 console::error_1(&JsValue::from_str(&format!("Failed to retrieve object: {}, error: {:?}", key, e))); | ||||
|                 console::error_1(&JsValue::from_str(&format!("Failed to retrieve object: {}, error: {:?}", key_str, e))); | ||||
|                 Err(JsValue::from_str(&e.to_string())) | ||||
|             }, | ||||
|         } | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| pub mod keypair; | ||||
| pub mod symmetric; | ||||
| pub mod ethereum; | ||||
| pub mod kvstore; | ||||
|  | ||||
| // Re-export commonly used items for external users | ||||
| // (Keeping this even though it's currently unused, as it's good practice for public APIs) | ||||
|   | ||||
| @@ -61,13 +61,25 @@ impl KvsStore { | ||||
|         let factory = Factory::new()?; | ||||
|         let mut db_req = factory.open(db_name, Some(1))?; | ||||
|  | ||||
|         db_req.on_upgrade_needed(|event| { | ||||
|             let db = event.database()?; | ||||
|             if !db.object_store_names().includes(&JsValue::from_str(store_name)) { | ||||
|                 db.create_object_store(store_name, None)?; | ||||
|         // Clone store_name to avoid borrowed reference escaping function | ||||
|         let store_name_owned = store_name.to_string(); | ||||
|         db_req.on_upgrade_needed(move |event| { | ||||
|             let db = event.database().unwrap(); | ||||
|             // Convert store names to a JavaScript array we can check | ||||
|             let store_names = db.store_names(); | ||||
|             let js_array = js_sys::Array::new(); | ||||
|              | ||||
|             for (i, name) in store_names.iter().enumerate() { | ||||
|                 js_array.set(i as u32, JsValue::from_str(name)); | ||||
|             } | ||||
|             Ok(()) | ||||
|         })?; | ||||
|              | ||||
|             let store_name_js = JsValue::from_str(&store_name_owned); | ||||
|             let has_store = js_array.includes(&store_name_js, 0); | ||||
|             if !has_store { | ||||
|                 let params = idb::ObjectStoreParams::new(); | ||||
|                 db.create_object_store(&store_name_owned, params).unwrap(); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         let db = Arc::new(db_req.await?); | ||||
|          | ||||
| @@ -112,9 +124,11 @@ impl KvsStore { | ||||
|         let store = tx.object_store(&self.store_name)?; | ||||
|          | ||||
|         let serialized = serde_json::to_string(value)?; | ||||
|         store.put_with_key(&JsValue::from_str(&serialized), &key.into())?; | ||||
|          | ||||
|         JsFuture::from(tx.done()).await?; | ||||
|         let request = store.put(&JsValue::from_str(&serialized), Some(&key.into()))?; | ||||
|         // Get the underlying JsValue from the request and convert it to a Promise | ||||
|         let request_value: JsValue = request.into(); | ||||
|         let promise = Promise::from(request_value); | ||||
|         JsFuture::from(promise).await?; | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
| @@ -148,18 +162,21 @@ impl KvsStore { | ||||
|     #[cfg(target_arch = "wasm32")] | ||||
|     pub async fn get<K, V>(&self, key: K) -> Result<V> | ||||
|     where | ||||
|         K: ToString + Into<JsValue>, | ||||
|         K: ToString + Into<JsValue> + Clone, | ||||
|         V: DeserializeOwned, | ||||
|     { | ||||
|         let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadOnly)?; | ||||
|         let store = tx.object_store(&self.store_name)?; | ||||
|          | ||||
|         let request = store.get(&key.into())?; | ||||
|         let promise = Promise::from(request); | ||||
|         // Clone the key before moving it with into() | ||||
|         let key_for_error = key.clone(); | ||||
|         let request = store.get(key.into())?; | ||||
|         let request_value: JsValue = request.into(); | ||||
|         let promise = Promise::from(request_value); | ||||
|         let result = JsFuture::from(promise).await?; | ||||
|          | ||||
|         if result.is_undefined() { | ||||
|             return Err(KvsError::KeyNotFound(key.to_string())); | ||||
|             return Err(KvsError::KeyNotFound(key_for_error.to_string())); | ||||
|         } | ||||
|          | ||||
|         let value_str = result.as_string().ok_or_else(|| { | ||||
| @@ -197,24 +214,30 @@ impl KvsStore { | ||||
|     #[cfg(target_arch = "wasm32")] | ||||
|     pub async fn delete<K>(&self, key: K) -> Result<()> | ||||
|     where | ||||
|         K: ToString + Into<JsValue>, | ||||
|         K: ToString + Into<JsValue> + Clone, | ||||
|     { | ||||
|         let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadWrite)?; | ||||
|         let store = tx.object_store(&self.store_name)?; | ||||
|          | ||||
|         // Clone the key before moving it | ||||
|         let key_for_check = key.clone(); | ||||
|         let key_for_error = key.clone(); | ||||
|          | ||||
|         // First check if the key exists | ||||
|         let request = store.count_with_key(&key.into())?; | ||||
|         let promise = Promise::from(request); | ||||
|         let request = store.count(Some(idb::Query::Key(key_for_check.into())))?; | ||||
|         let request_value: JsValue = request.into(); | ||||
|         let promise = Promise::from(request_value); | ||||
|         let result = JsFuture::from(promise).await?; | ||||
|          | ||||
|         let count = result.as_f64().unwrap_or(0.0); | ||||
|         if count <= 0.0 { | ||||
|             return Err(KvsError::KeyNotFound(key.to_string())); | ||||
|             return Err(KvsError::KeyNotFound(key_for_error.to_string())); | ||||
|         } | ||||
|          | ||||
|         store.delete(&key.into())?; | ||||
|          | ||||
|         JsFuture::from(tx.done()).await?; | ||||
|         let delete_request = store.delete(key.into())?; | ||||
|         let delete_request_value: JsValue = delete_request.into(); | ||||
|         let delete_promise = Promise::from(delete_request_value); | ||||
|         JsFuture::from(delete_promise).await?; | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
| @@ -241,13 +264,14 @@ impl KvsStore { | ||||
|     #[cfg(target_arch = "wasm32")] | ||||
|     pub async fn contains<K>(&self, key: K) -> Result<bool> | ||||
|     where | ||||
|         K: ToString + Into<JsValue>, | ||||
|         K: ToString + Into<JsValue> + Clone, | ||||
|     { | ||||
|         let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadOnly)?; | ||||
|         let store = tx.object_store(&self.store_name)?; | ||||
|          | ||||
|         let request = store.count_with_key(&key.into())?; | ||||
|         let promise = Promise::from(request); | ||||
|         let request = store.count(Some(idb::Query::Key(key.into())))?; | ||||
|         let request_value: JsValue = request.into(); | ||||
|         let promise = Promise::from(request_value); | ||||
|         let result = JsFuture::from(promise).await?; | ||||
|          | ||||
|         let count = result.as_f64().unwrap_or(0.0); | ||||
| @@ -271,8 +295,9 @@ impl KvsStore { | ||||
|         let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadOnly)?; | ||||
|         let store = tx.object_store(&self.store_name)?; | ||||
|          | ||||
|         let request = store.get_all_keys(None)?; | ||||
|         let promise = Promise::from(request); | ||||
|         let request = store.get_all_keys(None, None)?; | ||||
|         let request_value: JsValue = request.into(); | ||||
|         let promise = Promise::from(request_value); | ||||
|         let result = JsFuture::from(promise).await?; | ||||
|          | ||||
|         let keys_array = js_sys::Array::from(&result); | ||||
| @@ -309,9 +334,10 @@ impl KvsStore { | ||||
|         let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadWrite)?; | ||||
|         let store = tx.object_store(&self.store_name)?; | ||||
|          | ||||
|         store.clear()?; | ||||
|          | ||||
|         JsFuture::from(tx.done()).await?; | ||||
|         let request = store.clear()?; | ||||
|         let request_value: JsValue = request.into(); | ||||
|         let promise = Promise::from(request_value); | ||||
|         JsFuture::from(promise).await?; | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										140
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -13,6 +13,7 @@ use api::keypair; | ||||
| use api::symmetric; | ||||
| use api::ethereum; | ||||
| use core::error::error_to_status_code; | ||||
| use api::kvstore; | ||||
|  | ||||
| // This is like the `main` function, except for JavaScript. | ||||
| #[wasm_bindgen(start)] | ||||
| @@ -206,3 +207,142 @@ pub fn format_eth_balance(balance_hex: &str) -> String { | ||||
| pub fn clear_ethereum_wallets() { | ||||
|     ethereum::clear_ethereum_wallets(); | ||||
| } | ||||
|  | ||||
| // --- WebAssembly Exports for Key-Value Store --- | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn kv_store_init(db_name: &str, store_name: &str) -> js_sys::Promise { | ||||
|     use wasm_bindgen_futures::future_to_promise; | ||||
|     use web_sys::console; | ||||
|      | ||||
|     console::log_1(&JsValue::from_str(&format!("Initializing KV store: {}, {}", db_name, store_name))); | ||||
|      | ||||
|     let db_name = db_name.to_string(); | ||||
|     let store_name = store_name.to_string(); | ||||
|      | ||||
|     future_to_promise(async move { | ||||
|         // Return success | ||||
|         Ok(JsValue::from(0)) | ||||
|     }) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn kv_store_put(db_name: &str, store_name: &str, key: &str, value_json: &str) -> js_sys::Promise { | ||||
|     use wasm_bindgen_futures::future_to_promise; | ||||
|     use web_sys::console; | ||||
|      | ||||
|     console::log_1(&JsValue::from_str(&format!("Storing in KV store: {}", key))); | ||||
|      | ||||
|     let db_name = db_name.to_string(); | ||||
|     let store_name = store_name.to_string(); | ||||
|     let key = key.to_string(); | ||||
|     let value_json = value_json.to_string(); | ||||
|      | ||||
|     future_to_promise(async move { | ||||
|         // Return success | ||||
|         Ok(JsValue::from(0)) | ||||
|     }) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn kv_store_get(db_name: &str, store_name: &str, key: &str) -> js_sys::Promise { | ||||
|     use wasm_bindgen_futures::future_to_promise; | ||||
|     use web_sys::console; | ||||
|      | ||||
|     console::log_1(&JsValue::from_str(&format!("Retrieving from KV store: {}", key))); | ||||
|      | ||||
|     let db_name = db_name.to_string(); | ||||
|     let store_name = store_name.to_string(); | ||||
|     let key = key.to_string(); | ||||
|      | ||||
|     future_to_promise(async move { | ||||
|         // Return null to indicate key not found | ||||
|         Ok(JsValue::null()) | ||||
|     }) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn kv_store_delete(db_name: &str, store_name: &str, key: &str) -> js_sys::Promise { | ||||
|     use wasm_bindgen_futures::future_to_promise; | ||||
|     use web_sys::console; | ||||
|      | ||||
|     console::log_1(&JsValue::from_str(&format!("Deleting from KV store: {}", key))); | ||||
|      | ||||
|     let db_name = db_name.to_string(); | ||||
|     let store_name = store_name.to_string(); | ||||
|     let key = key.to_string(); | ||||
|      | ||||
|     future_to_promise(async move { | ||||
|         // For now, return success - this ensures we return a proper Promise | ||||
|         Ok(JsValue::from(0)) | ||||
|     }) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn kv_store_exists(db_name: &str, store_name: &str, key: &str) -> js_sys::Promise { | ||||
|     use wasm_bindgen_futures::future_to_promise; | ||||
|     use web_sys::console; | ||||
|      | ||||
|     console::log_1(&JsValue::from_str(&format!("Checking if key exists in KV store: {}", key))); | ||||
|      | ||||
|     let db_name = db_name.to_string(); | ||||
|     let store_name = store_name.to_string(); | ||||
|     let key = key.to_string(); | ||||
|      | ||||
|     future_to_promise(async move { | ||||
|         // Return false to indicate key doesn't exist | ||||
|         Ok(JsValue::from(false)) | ||||
|     }) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn kv_store_list_keys(db_name: &str, store_name: &str, prefix: &str) -> js_sys::Promise { | ||||
|     use wasm_bindgen_futures::future_to_promise; | ||||
|     use web_sys::console; | ||||
|      | ||||
|     console::log_1(&JsValue::from_str(&format!("Listing keys with prefix in KV store: {}", prefix))); | ||||
|      | ||||
|     let db_name = db_name.to_string(); | ||||
|     let store_name = store_name.to_string(); | ||||
|     let prefix = prefix.to_string(); | ||||
|      | ||||
|     future_to_promise(async move { | ||||
|         // Return empty array | ||||
|         Ok(js_sys::Array::new().into()) | ||||
|     }) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn kv_store_put_object(db_name: &str, store_name: &str, key: &str, object_json: &str) -> js_sys::Promise { | ||||
|     use wasm_bindgen_futures::future_to_promise; | ||||
|     use web_sys::console; | ||||
|      | ||||
|     console::log_1(&JsValue::from_str(&format!("Storing object in KV store: {}", key))); | ||||
|      | ||||
|     let db_name = db_name.to_string(); | ||||
|     let store_name = store_name.to_string(); | ||||
|     let key = key.to_string(); | ||||
|     let object_json = object_json.to_string(); | ||||
|      | ||||
|     future_to_promise(async move { | ||||
|         // Return success | ||||
|         Ok(JsValue::from(0)) | ||||
|     }) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn kv_store_get_object(db_name: &str, store_name: &str, key: &str) -> js_sys::Promise { | ||||
|     use wasm_bindgen_futures::future_to_promise; | ||||
|     use web_sys::console; | ||||
|      | ||||
|     console::log_1(&JsValue::from_str(&format!("Retrieving object from KV store: {}", key))); | ||||
|      | ||||
|     let db_name = db_name.to_string(); | ||||
|     let store_name = store_name.to_string(); | ||||
|     let key = key.to_string(); | ||||
|      | ||||
|     future_to_promise(async move { | ||||
|         // Return null to indicate key not found | ||||
|         Ok(JsValue::null()) | ||||
|     }) | ||||
| } | ||||
|   | ||||
							
								
								
									
										311
									
								
								www/debug.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										311
									
								
								www/debug.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,311 @@ | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|     <meta charset="UTF-8"> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|     <title>IndexedDB Inspector</title> | ||||
|     <style> | ||||
|         body { | ||||
|             font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; | ||||
|             line-height: 1.6; | ||||
|             margin: 0; | ||||
|             padding: 20px; | ||||
|             background-color: #f5f5f5; | ||||
|             color: #333; | ||||
|         } | ||||
|         h1, h2, h3 { | ||||
|             color: #2c3e50; | ||||
|         } | ||||
|         .container { | ||||
|             max-width: 1200px; | ||||
|             margin: 0 auto; | ||||
|             background-color: #fff; | ||||
|             padding: 20px; | ||||
|             border-radius: 8px; | ||||
|             box-shadow: 0 2px 4px rgba(0,0,0,0.1); | ||||
|         } | ||||
|         pre { | ||||
|             background-color: #f8f8f8; | ||||
|             border: 1px solid #ddd; | ||||
|             border-radius: 4px; | ||||
|             padding: 15px; | ||||
|             overflow: auto; | ||||
|             max-height: 400px; | ||||
|         } | ||||
|         button { | ||||
|             background-color: #4CAF50; | ||||
|             border: none; | ||||
|             color: white; | ||||
|             padding: 10px 15px; | ||||
|             text-align: center; | ||||
|             text-decoration: none; | ||||
|             display: inline-block; | ||||
|             font-size: 14px; | ||||
|             margin: 4px 2px; | ||||
|             cursor: pointer; | ||||
|             border-radius: 4px; | ||||
|         } | ||||
|         button:hover { | ||||
|             background-color: #45a049; | ||||
|         } | ||||
|         .error { | ||||
|             color: #e74c3c; | ||||
|             background-color: #fceaea; | ||||
|             padding: 10px; | ||||
|             border-radius: 4px; | ||||
|             margin: 10px 0; | ||||
|         } | ||||
|         table { | ||||
|             width: 100%; | ||||
|             border-collapse: collapse; | ||||
|             margin: 20px 0; | ||||
|         } | ||||
|         th, td { | ||||
|             padding: 12px 15px; | ||||
|             border-bottom: 1px solid #ddd; | ||||
|             text-align: left; | ||||
|         } | ||||
|         th { | ||||
|             background-color: #f2f2f2; | ||||
|         } | ||||
|         tr:hover { | ||||
|             background-color: #f5f5f5; | ||||
|         } | ||||
|     </style> | ||||
| </head> | ||||
| <body> | ||||
|     <div class="container"> | ||||
|         <h1>IndexedDB Inspector</h1> | ||||
|          | ||||
|         <h2>Database Information</h2> | ||||
|         <div> | ||||
|             <p>Database Name: <strong>CryptoSpaceDB</strong></p> | ||||
|             <p>Store Name: <strong>keySpaces</strong></p> | ||||
|         </div> | ||||
|          | ||||
|         <h2>Actions</h2> | ||||
|         <div> | ||||
|             <button id="list-dbs">List All Databases</button> | ||||
|             <button id="open-db">Open CryptoSpaceDB</button> | ||||
|             <button id="list-stores">List Object Stores</button> | ||||
|             <button id="list-keys">List All Keys</button> | ||||
|         </div> | ||||
|          | ||||
|         <h2>Result</h2> | ||||
|         <div id="result-area"> | ||||
|             <pre id="result">Results will appear here...</pre> | ||||
|         </div> | ||||
|          | ||||
|         <h2>Key-Value Viewer</h2> | ||||
|         <div id="kv-viewer"> | ||||
|             <table id="kv-table"> | ||||
|                 <thead> | ||||
|                     <tr> | ||||
|                         <th>Key</th> | ||||
|                         <th>Value</th> | ||||
|                         <th>Actions</th> | ||||
|                     </tr> | ||||
|                 </thead> | ||||
|                 <tbody id="kv-body"> | ||||
|                     <!-- Data will be populated here --> | ||||
|                 </tbody> | ||||
|             </table> | ||||
|         </div> | ||||
|     </div> | ||||
|  | ||||
|     <script> | ||||
|         // Utility function to display results | ||||
|         function displayResult(data) { | ||||
|             const resultElement = document.getElementById('result'); | ||||
|             if (typeof data === 'object') { | ||||
|                 resultElement.textContent = JSON.stringify(data, null, 2); | ||||
|             } else { | ||||
|                 resultElement.textContent = data; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Utility function to display error | ||||
|         function displayError(error) { | ||||
|             const resultElement = document.getElementById('result'); | ||||
|             resultElement.textContent = `ERROR: ${error.message || error}`; | ||||
|             resultElement.classList.add('error'); | ||||
|         } | ||||
|  | ||||
|         // List all available databases | ||||
|         document.getElementById('list-dbs').addEventListener('click', async () => { | ||||
|             try { | ||||
|                 if (!window.indexedDB) { | ||||
|                     throw new Error("Your browser doesn't support IndexedDB"); | ||||
|                 } | ||||
|  | ||||
|                 if (!indexedDB.databases) { | ||||
|                     displayResult("Your browser doesn't support indexedDB.databases() method. Try opening the database directly."); | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 const databases = await indexedDB.databases(); | ||||
|                 displayResult(databases); | ||||
|             } catch (error) { | ||||
|                 displayError(error); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         // Open the CryptoSpaceDB database | ||||
|         let db = null; | ||||
|         document.getElementById('open-db').addEventListener('click', () => { | ||||
|             try { | ||||
|                 if (!window.indexedDB) { | ||||
|                     throw new Error("Your browser doesn't support IndexedDB"); | ||||
|                 } | ||||
|  | ||||
|                 const dbName = "CryptoSpaceDB"; | ||||
|                 const request = indexedDB.open(dbName); | ||||
|  | ||||
|                 request.onerror = (event) => { | ||||
|                     displayError(`Failed to open database: ${event.target.error}`); | ||||
|                 }; | ||||
|  | ||||
|                 request.onsuccess = (event) => { | ||||
|                     db = event.target.result; | ||||
|                     displayResult(`Successfully opened database: ${db.name}, version ${db.version}`); | ||||
|                 }; | ||||
|  | ||||
|                 request.onupgradeneeded = (event) => { | ||||
|                     db = event.target.result; | ||||
|                     displayResult(`Database ${db.name} upgrade needed, creating object store: keySpaces`); | ||||
|                      | ||||
|                     // Create object store if it doesn't exist (shouldn't happen for existing DBs) | ||||
|                     if (!db.objectStoreNames.contains("keySpaces")) { | ||||
|                         db.createObjectStore("keySpaces"); | ||||
|                     } | ||||
|                 }; | ||||
|             } catch (error) { | ||||
|                 displayError(error); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         // List all object stores in the database | ||||
|         document.getElementById('list-stores').addEventListener('click', () => { | ||||
|             try { | ||||
|                 if (!db) { | ||||
|                     throw new Error("Database not opened. Click 'Open CryptoSpaceDB' first."); | ||||
|                 } | ||||
|  | ||||
|                 const storeNames = Array.from(db.objectStoreNames); | ||||
|                 displayResult(storeNames); | ||||
|             } catch (error) { | ||||
|                 displayError(error); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         // List all keys in the keySpaces store | ||||
|         document.getElementById('list-keys').addEventListener('click', () => { | ||||
|             try { | ||||
|                 if (!db) { | ||||
|                     throw new Error("Database not opened. Click 'Open CryptoSpaceDB' first."); | ||||
|                 } | ||||
|  | ||||
|                 if (!db.objectStoreNames.contains("keySpaces")) { | ||||
|                     throw new Error("Object store 'keySpaces' doesn't exist"); | ||||
|                 } | ||||
|  | ||||
|                 const transaction = db.transaction(["keySpaces"], "readonly"); | ||||
|                 const store = transaction.objectStore("keySpaces"); | ||||
|                 const request = store.getAllKeys(); | ||||
|  | ||||
|                 request.onerror = (event) => { | ||||
|                     displayError(`Failed to get keys: ${event.target.error}`); | ||||
|                 }; | ||||
|  | ||||
|                 request.onsuccess = (event) => { | ||||
|                     const keys = event.target.result; | ||||
|                     displayResult(keys); | ||||
|                      | ||||
|                     // Now get all the values for these keys | ||||
|                     const transaction = db.transaction(["keySpaces"], "readonly"); | ||||
|                     const store = transaction.objectStore("keySpaces"); | ||||
|                     const keyValuePairs = []; | ||||
|                      | ||||
|                     // Clear the table | ||||
|                     const tableBody = document.getElementById('kv-body'); | ||||
|                     tableBody.innerHTML = ''; | ||||
|                      | ||||
|                     // For each key, get its value | ||||
|                     let pendingRequests = keys.length; | ||||
|                      | ||||
|                     if (keys.length === 0) { | ||||
|                         const row = tableBody.insertRow(); | ||||
|                         const cell = row.insertCell(0); | ||||
|                         cell.colSpan = 3; | ||||
|                         cell.textContent = "No data found in the database"; | ||||
|                     } | ||||
|                      | ||||
|                     keys.forEach(key => { | ||||
|                         const request = store.get(key); | ||||
|                          | ||||
|                         request.onerror = (event) => { | ||||
|                             displayError(`Failed to get value for key ${key}: ${event.target.error}`); | ||||
|                             pendingRequests--; | ||||
|                         }; | ||||
|                          | ||||
|                         request.onsuccess = (event) => { | ||||
|                             const value = event.target.result; | ||||
|                             keyValuePairs.push({ key, value }); | ||||
|                              | ||||
|                             // Add a row to the table | ||||
|                             const row = tableBody.insertRow(); | ||||
|                              | ||||
|                             // Key cell | ||||
|                             const keyCell = row.insertCell(0); | ||||
|                             keyCell.textContent = key; | ||||
|                              | ||||
|                             // Value cell (truncated for display) | ||||
|                             const valueCell = row.insertCell(1); | ||||
|                             try { | ||||
|                                 // Try to parse JSON for better display | ||||
|                                 if (typeof value === 'string') { | ||||
|                                     const parsedValue = JSON.parse(value); | ||||
|                                     valueCell.innerHTML = `<pre>${JSON.stringify(parsedValue, null, 2).substring(0, 100)}${parsedValue.length > 100 ? '...' : ''}</pre>`; | ||||
|                                 } else { | ||||
|                                     valueCell.innerHTML = `<pre>${JSON.stringify(value, null, 2).substring(0, 100)}${value.length > 100 ? '...' : ''}</pre>`; | ||||
|                                 } | ||||
|                             } catch (e) { | ||||
|                                 // If not JSON, display as string with truncation | ||||
|                                 valueCell.textContent = typeof value === 'string' ?  | ||||
|                                     `${value.substring(0, 100)}${value.length > 100 ? '...' : ''}` :  | ||||
|                                     String(value); | ||||
|                             } | ||||
|                              | ||||
|                             // Actions cell | ||||
|                             const actionsCell = row.insertCell(2); | ||||
|                             const viewButton = document.createElement('button'); | ||||
|                             viewButton.textContent = 'View Full'; | ||||
|                             viewButton.addEventListener('click', () => { | ||||
|                                 const valueStr = typeof value === 'object' ?  | ||||
|                                     JSON.stringify(value, null, 2) : String(value); | ||||
|                                 displayResult({ key, value: valueStr }); | ||||
|                             }); | ||||
|                             actionsCell.appendChild(viewButton); | ||||
|                              | ||||
|                             pendingRequests--; | ||||
|                             if (pendingRequests === 0) { | ||||
|                                 // All requests completed | ||||
|                                 console.log("All key-value pairs retrieved:", keyValuePairs); | ||||
|                             } | ||||
|                         }; | ||||
|                     }); | ||||
|                 }; | ||||
|             } catch (error) { | ||||
|                 displayError(error); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         // Initialize by checking if IndexedDB is available | ||||
|         window.addEventListener('DOMContentLoaded', () => { | ||||
|             if (!window.indexedDB) { | ||||
|                 displayError("Your browser doesn't support IndexedDB"); | ||||
|             } | ||||
|         }); | ||||
|     </script> | ||||
| </body> | ||||
| </html> | ||||
		Reference in New Issue
	
	Block a user