Repository: librocco/librocco
Pull request #958: add nuke-and-resync (db) functionality:
Author: login: ikusteu
Created: 2025-05-16T12:14:40Z | Merged: 2025-05-21T15:13:55Z

Fixes #955 
There's some additional functionality to be added (and that's already WIP), but I've opened a new ticket for that: #957 


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **New Features**
  - Added a "Nuke and resync" button in the settings page, allowing users to clear all local database data and trigger a full resynchronisation.
- **Bug Fixes**
  - Ensured that synchronisation is properly stopped and restarted during the database reset process for improved reliability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Linked issue #955: New "nuke and resync" button on the settings page
Sometimes the local DB has a different schema than the remote.

Sometimes it might get corrupted.

The new button should clear up the local db. It should be resistant to a broken db, so it should act at a lower level than SQL queries.

Currently the initial sync is slow and blocks sqlite access. Closing the window before it's finished often corrupts the db.

The new button action could be developed together with the sync server to get an initial state of the db and apply it efficiently.

It could be anything that is convenient. If we're using OPFS we can maybe transfer the binary sqlite file.

In summary, maybe a `.dump` or `.backup` applied to a fresh db with an updated client id would work and be more efficient than the CRDT resolution.

Diff:
diff --git a/apps/web-client/src/lib/db/cr-sqlite/db.ts b/apps/web-client/src/lib/db/cr-sqlite/db.ts
index fcac218d1..0ed9c7c65 100644
--- a/apps/web-client/src/lib/db/cr-sqlite/db.ts
+++ b/apps/web-client/src/lib/db/cr-sqlite/db.ts
@@ -109,3 +109,67 @@ export const getPeerDBVersion = async (db: DB, siteId: Uint8Array): Promise<bigi
 	const version = (await db.execA(`SELECT max(db_version) FROM crsql_changes WHERE site_id = ?`, [siteId]))[0][0];
 	return version ? BigInt(version) : BigInt(0);
 };
+
+/**
+ * Promisified version of the `indexedDB.open`
+ */
+function openIndexedDB(dbName: string) {
+	return new Promise<IDBDatabase>((resolve, reject) => {
+		const req = indexedDB.open(dbName);
+
+		req.onerror = () => {
+			reject(new Error(`Failed to open database '${dbName}': ${req.error}`));
+		};
+
+		req.onsuccess = () => {
+			resolve(req.result);
+		};
+	});
+}
+
+/**
+ * Takes an indexed DB file handle and clears all data in it.
+ * We're using this to "delete" the database.
+ *
+ * NOTE: It doesn't actually delete the database itself, but rather clears all the data (leaving the empty DB)
+ * as the former produced some problems flakiness.
+ */
+function clearIndexedDB(db: IDBDatabase) {
+	return new Promise<void>((resolve, reject) => {
+		const transaction = db.transaction(db.objectStoreNames, "readwrite");
+
+		transaction.oncomplete = () => {
+			db.close();
+			resolve();
+		};
+
+		transaction.onerror = () => {
+			db.close();
+			reject(new Error(`Failed to clear data: ${transaction.error}`));
+		};
+
+		for (const storeName of db.objectStoreNames) {
+			transaction.objectStore(storeName).clear();
+		}
+	});
+}
+
+/**
+ * Clears the current cr-sqlite DB (in IndexedDB)
+ *
+ * NOTE: It doesn't actually delete the database itself, but rather clears all the data (leaving the empty DB)
+ * as the former produced some problems flakiness.
+ *
+ * NOTE: Currently it clears all data for the DB - this deletes all DBs created using the current cr-sqlite stack
+ * (e.g. we could have multiple DBs "dev", "foo", "bar-122", etc. created by cr-sqlite and all stored in "idb-batch-atomic" - this will delete them all)
+ * TODO: Implement a more fine-grained approach - delete only the chunks associated with a particular DB name, e.g. "dev"
+ */
+export async function clearDb() {
+	const dbName = "idb-batch-atomic";
+
+	const db = await openIndexedDB(dbName);
+	await clearIndexedDB(db);
+
+	// TODO: This is a bit inconsistent -- maybe clear only the "dev" db
+	delete dbCache["dev"];
+}
diff --git a/apps/web-client/src/routes/settings/+page.svelte b/apps/web-client/src/routes/settings/+page.svelte
index 4edb56361..1c66eaba9 100644
--- a/apps/web-client/src/routes/settings/+page.svelte
+++ b/apps/web-client/src/routes/settings/+page.svelte
@@ -22,6 +22,7 @@
 	import { invalidateAll } from "$app/navigation";
 	import { deviceSettingsStore } from "$lib/stores/app";
 	import { LL } from "@librocco/shared/i18n-svelte";
+	import { clearDb } from "$lib/db/cr-sqlite/db";
 
 	export let data: PageData;
 
@@ -148,6 +149,20 @@
 	let deleteDatabase = { name: "" };
 
 	let dialogContent: (DialogContent & { type: "create" | "delete" }) | null = null;
+
+	const nukeAndResyncDB = async () => {
+		// Stop the ongoing sync
+		syncActive.set(false);
+
+		// Clear all the data in CR-SQLite IndexedDB
+		await clearDb();
+
+		// Invalidate all - reinitialise the DB
+		await invalidateAll();
+
+		// Reset the sync
+		syncActive.set(true);
+	};
 </script>
 
 <Page title="Settings" view="settings" {db} {plugins}>
@@ -263,6 +278,7 @@
 					</ul>
 
 					<div class="flex justify-end gap-x-2 px-4 py-6">
+						<button on:click={nukeAndResyncDB} type="button" class="btn-secondary btn"> Nuke and resync </button>
 						<button on:click={toggleImport} type="button" class="btn-secondary btn">
 							{importOn ? "Cancel" : "Import"}
 						</button>


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 3**

<details>
<summary>📜 Review details</summary>

**Configuration used: .coderabbit.yaml**
**Review profile: CHILL**
**Plan: Pro**
**Cache: Disabled due to data retention organization setting**
**Knowledge Base: Disabled due to data retention organization setting**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between cf2a80cf2641ad25b4b32be3a8da833e932f022c and 1d5b50748b42596fa9a0cc67e4176d9b23c515be.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `apps/web-client/src/lib/db/cr-sqlite/db.ts` (1 hunks)
* `apps/web-client/src/routes/settings/+page.svelte` (3 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>apps/web-client/src/lib/db/cr-sqlite/db.ts</summary>

[error] 174-174: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.


(lint/performance/noDelete)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (3)</summary><blockquote>

<details>
<summary>apps/web-client/src/lib/db/cr-sqlite/db.ts (2)</summary>

`113-128`: **Well-structured promise wrapper for IndexedDB operations.**

The function provides a clean promisified interface for opening IndexedDB databases, with proper error handling included.

---

`130-155`: **Clear implementation of database clearing functionality.**

The implementation handles transaction lifecycle well and properly closes the database connection regardless of outcome.

</details>
<details>
<summary>apps/web-client/src/routes/settings/+page.svelte (1)</summary>

`25-25`: **Clean import of the new functionality.**

The import statement is correctly positioned and follows the project's import structure.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T09:46:12Z
user: login: silviot
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T12:15:09Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T12:17:13Z
user: login: silviot
body: I don't think coderabbit's suggestions should be blockers. I think the confirmation window is a good idea, but not strictly necessary.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T15:13:43Z

Review comments:
diff_hunk: @@ -109,3 +109,67 @@ export const getPeerDBVersion = async (db: DB, siteId: Uint8Array): Promise<bigi
 	const version = (await db.execA(`SELECT max(db_version) FROM crsql_changes WHERE site_id = ?`, [siteId]))[0][0];
 	return version ? BigInt(version) : BigInt(0);
 };
+
+/**
+ * Promisified version of the `indexedDB.open`
+ */
+function openIndexedDB(dbName: string) {
+	return new Promise<IDBDatabase>((resolve, reject) => {
+		const req = indexedDB.open(dbName);
+
+		req.onerror = () => {
+			reject(new Error(`Failed to open database '${dbName}': ${req.error}`));
+		};
+
+		req.onsuccess = () => {
+			resolve(req.result);
+		};
+	});
+}
+
+/**
+ * Takes an indexed DB file handle and clears all data in it.
+ * We're using this to "delete" the database.
+ *
+ * NOTE: It doesn't actually delete the database itself, but rather clears all the data (leaving the empty DB)
+ * as the former produced some problems flakiness.
+ */
+function clearIndexedDB(db: IDBDatabase) {
+	return new Promise<void>((resolve, reject) => {
+		const transaction = db.transaction(db.objectStoreNames, "readwrite");
+
+		transaction.oncomplete = () => {
+			db.close();
+			resolve();
+		};
+
+		transaction.onerror = () => {
+			db.close();
+			reject(new Error(`Failed to clear data: ${transaction.error}`));
+		};
+
+		for (const storeName of db.objectStoreNames) {
+			transaction.objectStore(storeName).clear();
+		}
+	});
+}
+
+/**
+ * Clears the current cr-sqlite DB (in IndexedDB)
+ *
+ * NOTE: It doesn't actually delete the database itself, but rather clears all the data (leaving the empty DB)
+ * as the former produced some problems flakiness.
+ *
+ * NOTE: Currently it clears all data for the DB - this deletes all DBs created using the current cr-sqlite stack
+ * (e.g. we could have multiple DBs "dev", "foo", "bar-122", etc. created by cr-sqlite and all stored in "idb-batch-atomic" - this will delete them all)
+ * TODO: Implement a more fine-grained approach - delete only the chunks associated with a particular DB name, e.g. "dev"
+ */
+export async function clearDb() {
+	const dbName = "idb-batch-atomic";
+
+	const db = await openIndexedDB(dbName);
+	await clearIndexedDB(db);
+
+	// TODO: This is a bit inconsistent -- maybe clear only the "dev" db
+	delete dbCache["dev"];
+}
path: apps/web-client/src/lib/db/cr-sqlite/db.ts
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Consider more robust error handling and caching consistency.**

The function implements the core clearing functionality, but there are some improvements to consider:

1. There's no error handling if the IndexedDB operations fail
2. Only the "dev" cache entry is removed while comments indicate all databases are being cleared
3. There's a static analysis hint about the performance of the `delete` operator


Suggested improvements:

```diff
export async function clearDb() {
	const dbName = "idb-batch-atomic";

+	try {
		const db = await openIndexedDB(dbName);
		await clearIndexedDB(db);

		// TODO: This is a bit inconsistent -- maybe clear only the "dev" db
-		delete dbCache["dev"];
+		dbCache["dev"] = undefined; // Alternative: assign undefined instead of using delete
+	} catch (error) {
+		console.error("Failed to clear database:", error);
+		throw error; // Re-throw to allow caller to handle
+	}
}
```

Additionally, consider adding confirmation before allowing this destructive operation and documenting the recovery path if this operation fails.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check if there are other database names in the cache that should be cleared
rg -n "dbCache\[.+\] ?= ?" --include="*.ts" --include="*.js"
```

Length of output: 504

---

🏁 Script executed:

```shell
#!/bin/bash
# Search for all mentions of dbCache to determine its keys and usage
rg -n 'dbCache' -C3 --glob '*.ts' --glob '*.js'
```

Length of output: 2937

---



</details>

**Improve clearDb error handling and cache invalidation**

The current implementation clears all IndexedDB data but only removes a hard-coded `"dev"` entry from `dbCache`. To ensure robustness and consistency:

- Wrap the IndexedDB operations in a `try/catch` to surface failures.
- Invalidate the correct cache key (`dbName`), not just `"dev"`, or clear all entries dynamically.
- Prefer assigning `undefined` (or resetting the cache object) over `delete` for better minifier/runtime performance.
- (Optional) Prompt before this destructive action and document rollback/recovery steps.

Locations:
- apps/web-client/src/lib/db/cr-sqlite/db.ts, lines 157–175

Suggested diff:
```diff
 export async function clearDb() {
-	const dbName = "idb-batch-atomic";
+	const dbName = "idb-batch-atomic";
+
+	try {
 		const db = await openIndexedDB(dbName);
 		await clearIndexedDB(db);
-
-	// TODO: This is a bit inconsistent -- maybe clear only the "dev" db
-	delete dbCache["dev"];
+		// Invalidate the cache for the cleared DB
+		dbCache[dbName] = undefined;
+
+		// Or, to be thorough, clear every entry:
+		// Object.keys(dbCache).forEach(k => { dbCache[k] = undefined });
+	} catch (error) {
+		console.error("Failed to clear database:", error);
+		throw error; // allow callers to handle or surface the failure
  }
 }
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
export async function clearDb() {
	const dbName = "idb-batch-atomic";

	try {
		const db = await openIndexedDB(dbName);
		await clearIndexedDB(db);

		// Invalidate the cache for the cleared DB
		dbCache[dbName] = undefined;

		// Or, to be thorough, clear every entry:
		// Object.keys(dbCache).forEach(k => { dbCache[k] = undefined });
	} catch (error) {
		console.error("Failed to clear database:", error);
		throw error; // allow callers to handle or surface the failure
	}
}
```

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 174-174: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.


(lint/performance/noDelete)

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In apps/web-client/src/lib/db/cr-sqlite/db.ts around lines 157 to 175, the
clearDb function lacks error handling for IndexedDB operations and only removes
the hard-coded "dev" entry from dbCache despite clearing all databases. To fix
this, wrap the IndexedDB open and clear calls in a try/catch block to handle and
surface errors properly. Replace the delete dbCache["dev"] with resetting or
assigning undefined to the cache key corresponding to dbName or clear all
relevant cache entries dynamically for consistency. Avoid using delete for
better performance and consider adding a confirmation step before clearing the
database, documenting recovery steps if the operation fails.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-19T09:46:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -263,6 +278,7 @@
 					</ul>
 
 					<div class="flex justify-end gap-x-2 px-4 py-6">
+						<button on:click={nukeAndResyncDB} type="button" class="btn-secondary btn"> Nuke and resync </button>
path: apps/web-client/src/routes/settings/+page.svelte
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Add confirmation dialog and loading state to the "Nuke and resync" button.**

This button triggers a potentially destructive action that erases all user data without confirmation. Additionally, it lacks a loading state indicator during the operation.


I recommend:
1. Adding a confirmation dialog before proceeding
2. Using the button's built-in loading state
3. Adding a test ID for easier testing
4. Implementing internationalization (i18n) for the button text

```diff
-<button on:click={nukeAndResyncDB} type="button" class="btn-secondary btn"> Nuke and resync </button>
+<button 
+  on:click={() => {
+    if (confirm($LL.settings_page.confirmations.nuke_and_resync())) {
+      nukeAndResyncDB();
+    }
+  }}
+  data-testid={testId("db-action-nuke-resync")}
+  type="button" 
+  class="btn-secondary btn" 
+>
+  {$LL.settings_page.labels.nuke_and_resync()}
+</button>
```

Make sure to add the corresponding translation keys to your i18n files.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In apps/web-client/src/routes/settings/+page.svelte at line 281, the "Nuke and
resync" button lacks a confirmation dialog and loading state, which is risky for
destructive actions. Add a confirmation dialog that prompts the user before
executing nukeAndResyncDB. Implement a loading state on the button to indicate
the operation is in progress. Add a test ID attribute to the button for testing
purposes. Replace the button text with an i18n key and ensure the corresponding
translation keys are added to the i18n files.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-19T09:46:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -148,6 +149,20 @@
 	let deleteDatabase = { name: "" };
 
 	let dialogContent: (DialogContent & { type: "create" | "delete" }) | null = null;
+
+	const nukeAndResyncDB = async () => {
+		// Stop the ongoing sync
+		syncActive.set(false);
+
+		// Clear all the data in CR-SQLite IndexedDB
+		await clearDb();
+
+		// Invalidate all - reinitialise the DB
+		await invalidateAll();
+
+		// Reset the sync
+		syncActive.set(true);
+	};
path: apps/web-client/src/routes/settings/+page.svelte
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add error handling and user feedback to the database reset function.**

While the function follows a logical sequence (stop sync → clear DB → invalidate → restart sync), it lacks error handling and user feedback during this potentially time-consuming operation.


Consider enhancing with error handling and user feedback:

```diff
const nukeAndResyncDB = async () => {
+	// Track loading state
+	let isResetting = true;
+
+	try {
		// Stop the ongoing sync
		syncActive.set(false);

		// Clear all the data in CR-SQLite IndexedDB
		await clearDb();

		// Invalidate all - reinitialise the DB
		await invalidateAll();

		// Reset the sync
		syncActive.set(true);
+	} catch (error) {
+		console.error("Failed to reset database:", error);
+		// Ensure sync is restarted even if there's an error
+		syncActive.set(true);
+		// Notify the user of the error
+		// alert($LL.settings_page.errors.db_reset_failed());
+	} finally {
+		isResetting = false;
+	}
};
```

Then use the `isResetting` variable in the UI to show loading state.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
	const nukeAndResyncDB = async () => {
		// Track loading state
		let isResetting = true;

		try {
			// Stop the ongoing sync
			syncActive.set(false);

			// Clear all the data in CR-SQLite IndexedDB
			await clearDb();

			// Invalidate all - reinitialise the DB
			await invalidateAll();

			// Reset the sync
			syncActive.set(true);
		} catch (error) {
			console.error("Failed to reset database:", error);
			// Ensure sync is restarted even if there's an error
			syncActive.set(true);
			// Notify the user of the error
			// alert($LL.settings_page.errors.db_reset_failed());
		} finally {
			isResetting = false;
		}
	};
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In apps/web-client/src/routes/settings/+page.svelte around lines 153 to 165, the
nukeAndResyncDB function lacks error handling and user feedback during the
database reset process. Wrap the async operations in a try-catch block to catch
any errors, set an isResetting state variable to true at the start and false at
the end to indicate loading, and provide user feedback such as error messages or
success confirmation. Use the isResetting variable in the UI to show a loading
state while the reset is in progress.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-19T09:46:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -109,3 +109,67 @@ export const getPeerDBVersion = async (db: DB, siteId: Uint8Array): Promise<bigi
 	const version = (await db.execA(`SELECT max(db_version) FROM crsql_changes WHERE site_id = ?`, [siteId]))[0][0];
 	return version ? BigInt(version) : BigInt(0);
 };
+
+/**
+ * Promisified version of the `indexedDB.open`
+ */
+function openIndexedDB(dbName: string) {
+	return new Promise<IDBDatabase>((resolve, reject) => {
+		const req = indexedDB.open(dbName);
+
+		req.onerror = () => {
+			reject(new Error(`Failed to open database '${dbName}': ${req.error}`));
+		};
+
+		req.onsuccess = () => {
+			resolve(req.result);
+		};
+	});
+}
+
+/**
+ * Takes an indexed DB file handle and clears all data in it.
+ * We're using this to "delete" the database.
+ *
+ * NOTE: It doesn't actually delete the database itself, but rather clears all the data (leaving the empty DB)
+ * as the former produced some problems flakiness.
+ */
+function clearIndexedDB(db: IDBDatabase) {
+	return new Promise<void>((resolve, reject) => {
+		const transaction = db.transaction(db.objectStoreNames, "readwrite");
+
+		transaction.oncomplete = () => {
+			db.close();
+			resolve();
+		};
+
+		transaction.onerror = () => {
+			db.close();
+			reject(new Error(`Failed to clear data: ${transaction.error}`));
+		};
+
+		for (const storeName of db.objectStoreNames) {
+			transaction.objectStore(storeName).clear();
+		}
+	});
+}
+
+/**
+ * Clears the current cr-sqlite DB (in IndexedDB)
+ *
+ * NOTE: It doesn't actually delete the database itself, but rather clears all the data (leaving the empty DB)
+ * as the former produced some problems flakiness.
+ *
+ * NOTE: Currently it clears all data for the DB - this deletes all DBs created using the current cr-sqlite stack
+ * (e.g. we could have multiple DBs "dev", "foo", "bar-122", etc. created by cr-sqlite and all stored in "idb-batch-atomic" - this will delete them all)
+ * TODO: Implement a more fine-grained approach - delete only the chunks associated with a particular DB name, e.g. "dev"
+ */
+export async function clearDb() {
+	const dbName = "idb-batch-atomic";
+
+	const db = await openIndexedDB(dbName);
+	await clearIndexedDB(db);
+
+	// TODO: This is a bit inconsistent -- maybe clear only the "dev" db
+	delete dbCache["dev"];
+}
path: apps/web-client/src/lib/db/cr-sqlite/db.ts
user: login: silviot
body: @coderabbit actually we only need the currently enabled db to be deleted. Deleting the other ones is not requested.
created_at: 2025-05-19T12:15:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -109,3 +109,67 @@ export const getPeerDBVersion = async (db: DB, siteId: Uint8Array): Promise<bigi
 	const version = (await db.execA(`SELECT max(db_version) FROM crsql_changes WHERE site_id = ?`, [siteId]))[0][0];
 	return version ? BigInt(version) : BigInt(0);
 };
+
+/**
+ * Promisified version of the `indexedDB.open`
+ */
+function openIndexedDB(dbName: string) {
+	return new Promise<IDBDatabase>((resolve, reject) => {
+		const req = indexedDB.open(dbName);
+
+		req.onerror = () => {
+			reject(new Error(`Failed to open database '${dbName}': ${req.error}`));
+		};
+
+		req.onsuccess = () => {
+			resolve(req.result);
+		};
+	});
+}
+
+/**
+ * Takes an indexed DB file handle and clears all data in it.
+ * We're using this to "delete" the database.
+ *
+ * NOTE: It doesn't actually delete the database itself, but rather clears all the data (leaving the empty DB)
+ * as the former produced some problems flakiness.
+ */
+function clearIndexedDB(db: IDBDatabase) {
+	return new Promise<void>((resolve, reject) => {
+		const transaction = db.transaction(db.objectStoreNames, "readwrite");
+
+		transaction.oncomplete = () => {
+			db.close();
+			resolve();
+		};
+
+		transaction.onerror = () => {
+			db.close();
+			reject(new Error(`Failed to clear data: ${transaction.error}`));
+		};
+
+		for (const storeName of db.objectStoreNames) {
+			transaction.objectStore(storeName).clear();
+		}
+	});
+}
+
+/**
+ * Clears the current cr-sqlite DB (in IndexedDB)
+ *
+ * NOTE: It doesn't actually delete the database itself, but rather clears all the data (leaving the empty DB)
+ * as the former produced some problems flakiness.
+ *
+ * NOTE: Currently it clears all data for the DB - this deletes all DBs created using the current cr-sqlite stack
+ * (e.g. we could have multiple DBs "dev", "foo", "bar-122", etc. created by cr-sqlite and all stored in "idb-batch-atomic" - this will delete them all)
+ * TODO: Implement a more fine-grained approach - delete only the chunks associated with a particular DB name, e.g. "dev"
+ */
+export async function clearDb() {
+	const dbName = "idb-batch-atomic";
+
+	const db = await openIndexedDB(dbName);
+	await clearIndexedDB(db);
+
+	// TODO: This is a bit inconsistent -- maybe clear only the "dev" db
+	delete dbCache["dev"];
+}
path: apps/web-client/src/lib/db/cr-sqlite/db.ts
user: login: coderabbitai[bot]
body: <details>
<summary>🧩 Analysis chain</summary>

@silviot Thank you for the clarification. I understand that you only want to clear the currently enabled database (which appears to be "dev" based on the code).

The current implementation actually does clear all cr-sqlite databases stored in the "idb-batch-atomic" IndexedDB database, while only invalidating the "dev" entry in the cache. If selectively clearing only the "dev" database isn't currently possible at the IndexedDB level (which would require a more complex implementation), then the current approach is reasonable.

I'd still recommend adding error handling to the function, but keeping the focus on just invalidating the "dev" cache entry:

```typescript
export async function clearDb() {
    const dbName = "idb-batch-atomic";

    try {
        const db = await openIndexedDB(dbName);
        await clearIndexedDB(db);
        
        // Only invalidate the cache for "dev" as requested
        dbCache["dev"] = undefined;
    } catch (error) {
        console.error("Failed to clear database:", error);
        throw error; // allow callers to handle or surface the failure
    }
}
```

This maintains your current behavior of only affecting the "dev" cache entry while adding error handling. The TODO comment can remain to indicate that a more selective clearing approach might be implemented in the future.

---

🏁 Script executed:
```
#!/bin/bash
# Search for patterns related to database selection/identification
rg "getInitializedDB|dbname" --include="*.ts" --include="*.js" -C2
```

Length of output: 510

---

🏁 Script executed:
```
#!/bin/bash
# Look for references to the idb-batch-atomic database
rg "idb-batch-atomic" --include="*.ts" --include="*.js" -C2
```

Length of output: 501

---

🏁 Script executed:
```
#!/bin/bash
# Look for database usage patterns and configuration
rg "const\s+db\s*=\s*await\s*getInitializedDB" --include="*.ts" --include="*.js" -C2
```

Length of output: 528

---

🏁 Script executed:
```
#!/bin/bash
# Check the settings page implementation
cat apps/web-client/src/routes/settings/+page.svelte
```

Length of output: 12726

---

🏁 Script executed:
```
#!/bin/bash
# Look for stores or configuration related to database settings
rg "dbName|db.*name|database.*name|current.*db" --include="*.ts" --include="*.svelte" -C2
```

Length of output: 533

---

@silviot Thank you for the clarification. I understand that you only want to delete the currently enabled database, not all of them.

Looking at the code, I see that the current implementation in `clearDb()` clears all data from the IndexedDB database, but only invalidates the hardcoded "dev" entry in the cache. Based on your settings page implementation, it seems the currently enabled database is tracked in the `dbid` store.

Here's what I'd suggest to focus on only the currently enabled database:

```typescript
export async function clearDb() {
    const dbName = "idb-batch-atomic";

    try {
        const db = await openIndexedDB(dbName);
        await clearIndexedDB(db);

        // Get the currently enabled database from the store
        // and only invalidate that cache entry
        import { get } from 'svelte/store';
        import { dbid } from "$lib/db";
        const currentDbId = get(dbid);
        dbCache[currentDbId] = undefined;
    } catch (error) {
        console.error("Failed to clear database:", error);
        throw error;
    }
}
```

This way, you'll still clear all databases at the IndexedDB level (as noted in your TODO as a future enhancement to make more selective), but only invalidate the cache for the currently enabled database from the `dbid` store.

---

🏁 Script executed:
```
#!/bin/bash
# Let's search for dbid and dbCache patterns correctly
rg "dbid" 
```

Length of output: 5049

---

🏁 Script executed:
```
#!/bin/bash
# Let's search for dbCache usage
rg "dbCache"
```

Length of output: 580

---

🏁 Script executed:
```
#!/bin/bash
# Look for dbid store implementation
cat $(rg -l "export const dbid" --type ts)
```

Length of output: 1897

---



</details>

@silviot I understand your request now. Looking at the codebase, I see that all databases are currently stored in the same IndexedDB database ("idb-batch-atomic"), but you only want to invalidate the cache for the currently enabled database.

Here's an improved implementation with error handling that retrieves the current database ID from the store:

```typescript
export async function clearDb() {
    const dbName = "idb-batch-atomic";

    try {
        const db = await openIndexedDB(dbName);
        await clearIndexedDB(db);

        // Import from svelte/store and get the current database ID
        import { get } from 'svelte/store';
        import { dbid } from "$lib/db";
        
        // Only invalidate the currently enabled database in the cache
        const currentDbId = get(dbid);
        dbCache[currentDbId] = undefined;
    } catch (error) {
        console.error("Failed to clear database:", error);
        throw error; // Re-throw to allow caller to handle
    }
}
```

This keeps the IndexedDB clearing operation unchanged (clearing all databases stored there) but only invalidates the cache for the currently enabled database from the `dbid` store. The TODO comment can remain as a reminder for future improvement to selectively clear only specific databases at the IndexedDB level.

---

<details>
<summary>🧬 Code Graph Analysis Results</summary>

### Relevant snippets from `apps/web-client/src/lib/db/cr-sqlite/db.ts` (lines 1-130)

The entire file content is relevant, but especially the following parts are directly related to the user comment about deleting only the currently enabled DB:

- The `clearDb` function (lines ~110-130) which currently clears all data in the IndexedDB database named `"idb-batch-atomic"`. The comment explicitly states that it clears all DBs created using the current cr-sqlite stack, and there is a TODO to implement a more fine-grained approach to delete only the chunks associated with a particular DB name.

- The `dbCache` object (lines ~12-15) which caches DB contexts by name, relevant for identifying the currently enabled DB.

- The `getInitializedDB` function (lines ~50-85) which opens or initializes a DB by name and caches it.

- The helper functions `openIndexedDB` and `clearIndexedDB` (lines ~90-110) which handle opening and clearing IndexedDB databases.

---

### Possibly relevant snippets from `apps/web-client/src/lib/db/cr-sqlite/index.ts`

- `getDB` (line 1): Function to open a DB by name, used in `getInitializedDB`.
- `initializeDB` (line 1): Function to initialize a DB schema.
- `getInitializedDB` (line 1): Function to get or initialize a DB context by name.

These are relevant as they relate to DB initialization and retrieval by name, which is important context for selectively deleting a DB.

---

### Possibly relevant snippets from `apps/web-client/src/lib/db/cr-sqlite/types.ts`

- `export type DB = _DB | TXAsync;` (line 300): Defines the DB type used in the main file.
- `export type Change = readonly [...]` (lines 321-334): Defines the Change type used in change tracking functions.

These type definitions provide context on the DB and Change types used throughout the main file.

---

### Summary

The main relevant code is the `clearDb` function and related DB opening and clearing helpers in `db.ts`, plus the DB caching and initialization functions that manage DB instances by name. The user comment about deleting only the currently enabled DB relates directly to the TODO and current behavior in `clearDb`. The other snippets from `index.ts` and `types.ts` provide supporting context on DB handling and types.

</details>


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer><details>
<summary>🧩 Analysis chain</summary>

@silviot Thank you for the clarification. I understand that you only want to clear the currently enabled database (which appears to be "dev" based on the code).

The current implementation actually does clear all cr-sqlite databases stored in the "idb-batch-atomic" IndexedDB database, while only invalidating the "dev" entry in the cache. If selectively clearing only the "dev" database isn't currently possible at the IndexedDB level (which would require a more complex implementation), then the current approach is reasonable.

I'd still recommend adding error handling to the function, but keeping the focus on just invalidating the "dev" cache entry:

```typescript
export async function clearDb() {
    const dbName = "idb-batch-atomic";

    try {
        const db = await openIndexedDB(dbName);
        await clearIndexedDB(db);
        
        // Only invalidate the cache for "dev" as requested
        dbCache["dev"] = undefined;
    } catch (error) {
        console.error("Failed to clear database:", error);
        throw error; // allow callers to handle or surface the failure
    }
}
```

This maintains your current behavior of only affecting the "dev" cache entry while adding error handling. The TODO comment can remain to indicate that a more selective clearing approach might be implemented in the future.

---

🏁 Script executed:
```
#!/bin/bash
# Search for patterns related to database selection/identification
rg "getInitializedDB|dbname" --include="*.ts" --include="*.js" -C2
```

Length of output: 510

---

🏁 Script executed:
```
#!/bin/bash
# Look for references to the idb-batch-atomic database
rg "idb-batch-atomic" --include="*.ts" --include="*.js" -C2
```

Length of output: 501

---

🏁 Script executed:
```
#!/bin/bash
# Look for database usage patterns and configuration
rg "const\s+db\s*=\s*await\s*getInitializedDB" --include="*.ts" --include="*.js" -C2
```

Length of output: 528

---

🏁 Script executed:
```
#!/bin/bash
# Check the settings page implementation
cat apps/web-client/src/routes/settings/+page.svelte
```

Length of output: 12726

---

🏁 Script executed:
```
#!/bin/bash
# Look for stores or configuration related to database settings
rg "dbName|db.*name|database.*name|current.*db" --include="*.ts" --include="*.svelte" -C2
```

Length of output: 533

---

@silviot Thank you for the clarification. I understand that you only want to delete the currently enabled database, not all of them.

Looking at the code, I see that the current implementation in `clearDb()` clears all data from the IndexedDB database, but only invalidates the hardcoded "dev" entry in the cache. Based on your settings page implementation, it seems the currently enabled database is tracked in the `dbid` store.

Here's what I'd suggest to focus on only the currently enabled database:

```typescript
export async function clearDb() {
    const dbName = "idb-batch-atomic";

    try {
        const db = await openIndexedDB(dbName);
        await clearIndexedDB(db);

        // Get the currently enabled database from the store
        // and only invalidate that cache entry
        import { get } from 'svelte/store';
        import { dbid } from "$lib/db";
        const currentDbId = get(dbid);
        dbCache[currentDbId] = undefined;
    } catch (error) {
        console.error("Failed to clear database:", error);
        throw error;
    }
}
```

This way, you'll still clear all databases at the IndexedDB level (as noted in your TODO as a future enhancement to make more selective), but only invalidate the cache for the currently enabled database from the `dbid` store.

---

🏁 Script executed:
```
#!/bin/bash
# Let's search for dbid and dbCache patterns correctly
rg "dbid" 
```

Length of output: 5049

---

🏁 Script executed:
```
#!/bin/bash
# Let's search for dbCache usage
rg "dbCache"
```

Length of output: 580

---

🏁 Script executed:
```
#!/bin/bash
# Look for dbid store implementation
cat $(rg -l "export const dbid" --type ts)
```

Length of output: 1897

---



</details>

@silviot I understand your request now. Looking at the codebase, I see that all databases are currently stored in the same IndexedDB database ("idb-batch-atomic"), but you only want to invalidate the cache for the currently enabled database.

Here's an improved implementation with error handling that retrieves the current database ID from the store:

```typescript
export async function clearDb() {
    const dbName = "idb-batch-atomic";

    try {
        const db = await openIndexedDB(dbName);
        await clearIndexedDB(db);

        // Import from svelte/store and get the current database ID
        import { get } from 'svelte/store';
        import { dbid } from "$lib/db";
        
        // Only invalidate the currently enabled database in the cache
        const currentDbId = get(dbid);
        dbCache[currentDbId] = undefined;
    } catch (error) {
        console.error("Failed to clear database:", error);
        throw error; // Re-throw to allow caller to handle
    }
}
```

This keeps the IndexedDB clearing operation unchanged (clearing all databases stored there) but only invalidates the cache for the currently enabled database from the `dbid` store. The TODO comment can remain as a reminder for future improvement to selectively clear only specific databases at the IndexedDB level.

---

<details>
<summary>🧬 Code Graph Analysis Results</summary>

### Relevant snippets from `apps/web-client/src/lib/db/cr-sqlite/db.ts` (lines 1-130)

The entire file content is relevant, but especially the following parts are directly related to the user comment about deleting only the currently enabled DB:

- The `clearDb` function (lines ~110-130) which currently clears all data in the IndexedDB database named `"idb-batch-atomic"`. The comment explicitly states that it clears all DBs created using the current cr-sqlite stack, and there is a TODO to implement a more fine-grained approach to delete only the chunks associated with a particular DB name.

- The `dbCache` object (lines ~12-15) which caches DB contexts by name, relevant for identifying the currently enabled DB.

- The `getInitializedDB` function (lines ~50-85) which opens or initializes a DB by name and caches it.

- The helper functions `openIndexedDB` and `clearIndexedDB` (lines ~90-110) which handle opening and clearing IndexedDB databases.

---

### Possibly relevant snippets from `apps/web-client/src/lib/db/cr-sqlite/index.ts`

- `getDB` (line 1): Function to open a DB by name, used in `getInitializedDB`.
- `initializeDB` (line 1): Function to initialize a DB schema.
- `getInitializedDB` (line 1): Function to get or initialize a DB context by name.

These are relevant as they relate to DB initialization and retrieval by name, which is important context for selectively deleting a DB.

---

### Possibly relevant snippets from `apps/web-client/src/lib/db/cr-sqlite/types.ts`

- `export type DB = _DB | TXAsync;` (line 300): Defines the DB type used in the main file.
- `export type Change = readonly [...]` (lines 321-334): Defines the Change type used in change tracking functions.

These type definitions provide context on the DB and Change types used throughout the main file.

---

### Summary

The main relevant code is the `clearDb` function and related DB opening and clearing helpers in `db.ts`, plus the DB caching and initialization functions that manage DB instances by name. The user comment about deleting only the currently enabled DB relates directly to the TODO and current behavior in `clearDb`. The other snippets from `index.ts` and `types.ts` provide supporting context on DB handling and types.

</details>

</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-19T12:17:13Z
author_association: CONTRIBUTOR

PR comments:
user: login: silviot
created_at: 2025-05-19T09:43:16Z
body: @coderabbit review
author_association: CONTRIBUTOR
user: login: coderabbitai[bot]
created_at: 2025-05-19T09:46:08Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

<details>
<summary>📝 Walkthrough</summary>

## Walkthrough

The changes introduce a new utility to clear all data from the cr-sqlite database stored in IndexedDB and expose this functionality via a new `clearDb` function. A "Nuke and resync" button is added to the settings page, which invokes this utility, resets synchronisation, and reloads the application state.

## Changes

| File(s)                                                                                   | Change Summary                                                                                          |
|------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------|
| apps/web-client/src/lib/db/cr-sqlite/db.ts                                               | Added `clearDb` function to clear all data from the cr-sqlite IndexedDB and remove cached DB context.  |
| apps/web-client/src/routes/settings/+page.svelte                                         | Added `nukeAndResyncDB` function and "Nuke and resync" button to the UI, invoking `clearDb`.           |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant SettingsPage
    participant DBModule
    participant IndexedDB
    participant AppCache

    User->>SettingsPage: Click "Nuke and resync"
    SettingsPage->>SettingsPage: Set syncActive = false
    SettingsPage->>DBModule: clearDb()
    DBModule->>IndexedDB: Open and clear all object stores
    DBModule->>AppCache: Remove cached DB context
    DBModule-->>SettingsPage: Promise resolved
    SettingsPage->>SettingsPage: invalidateAll()
    SettingsPage->>SettingsPage: Set syncActive = true
```

## Assessment against linked issues

| Objective                                                                                               | Addressed | Explanation                                                                                   |
|---------------------------------------------------------------------------------------------------------|-----------|-----------------------------------------------------------------------------------------------|
| Add "nuke and resync" button to settings page to clear local db at a low level (#955)                   | ✅        |                                                                                               |
| Ensure the clearing is resistant to a broken db and operates below SQL level (#955)                     | ✅        |                                                                                               |
| Button should trigger a full reload and reinitialisation of the local db and sync (#955)                | ✅        |                                                                                               |
| Efficiently clear all cr-sqlite data in IndexedDB, not just via SQL queries (#955)                      | ✅        |                                                                                               |

</details>

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!NOTE]
> <details>
> <summary>⚡️ AI Code Reviews for VS Code, Cursor, Windsurf</summary>
> 
> CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
> Learn more [here](http://coderabbit.ai/ide).
> 
> </details>

---

> [!NOTE]
> <details>
> <summary>⚡️ Faster reviews with caching</summary>
> 
> CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure `Review - Disable Cache` at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the `Data Retention` setting under your Organization Settings.
> Enjoy the performance boost—your workflow just got faster.
> 
> </details>

<!-- announcements_end -->
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings
<details open="true">
<summary>🧪 Generate Unit Tests</summary>

- [ ] <!-- {"checkboxId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "radioGroupId": "utg-output-choice-group-2890360932"} -->   Create PR with Unit Tests
- [ ] <!-- {"checkboxId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8", "radioGroupId": "utg-output-choice-group-2890360932"} -->   Commit Unit Tests in branch `feat/nuke-resync`
- [ ] <!-- {"checkboxId": "07f1e7d6-8a8e-4e23-9900-8731c2c87f58", "radioGroupId": "utg-output-choice-group-2890360932"} -->   Post Copyable Unit Tests in Comment

</details>

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=librocco/librocco&utm_content=958):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai generate unit tests` to generate unit tests for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR