From bb376c3f1624f2f8871f700b6fc190be3b7493ee Mon Sep 17 00:00:00 2001 From: Aarav Sharma Date: Sun, 13 Sep 2026 08:55:47 -0600 Subject: [PATCH 1/2] fix(website): handle synchronous Orama v3 search API in docs search Orama v3 returns search results synchronously in the browser, so calling .then() on the result threw 'then is not a function' and crashed the search dialog. Call search() directly with a Promise guard and try/catch. --- website/src/components/react/Search.tsx | 31 ++++++++++++++----------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/website/src/components/react/Search.tsx b/website/src/components/react/Search.tsx index c53cd83..5e2c8a0 100644 --- a/website/src/components/react/Search.tsx +++ b/website/src/components/react/Search.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react'; -import { create, insertMultiple, search } from '@orama/orama'; +import { create, insertMultiple, search, type AnyOrama } from '@orama/orama'; interface Hit { url: string; @@ -11,7 +11,7 @@ export default function Search() { const [open, setOpen] = useState(false); const [query, setQuery] = useState(''); const [hits, setHits] = useState([]); - const [db, setDb] = useState> | null>(null); + const [db, setDb] = useState(null); useEffect(() => { const onKey = (e: KeyboardEvent) => { @@ -45,17 +45,22 @@ export default function Search() { setHits([]); return; } - search(db, { term: query, properties: ['title', 'description', 'content'] }) - .then((res: any) => { - setHits( - (res.hits ?? []).slice(0, 8).map((h: any) => ({ - url: h.document.url, - title: h.document.title, - description: h.document.description, - })), - ); - }) - .catch(() => setHits([])); + try { + const res = search(db, { + term: query, + properties: ['title', 'description', 'content'], + }); + if (res instanceof Promise) return; + setHits( + (res.hits ?? []).slice(0, 8).map((h: any) => ({ + url: h.document.url, + title: h.document.title, + description: h.document.description, + })), + ); + } catch { + setHits([]); + } }, [query, db]); return ( From c97ae6a3170c09fba7e2b18a7b7f0969d0a07a86 Mon Sep 17 00:00:00 2001 From: Aarav Sharma Date: Sun, 13 Sep 2026 09:06:41 -0600 Subject: [PATCH 2/2] fix(website): await search results via Promise.resolve per review Replace the instanceof Promise guard, which silently dropped results on any async path and is unreliable across realms, with a Promise.resolve(...).then(apply) chain that handles both sync (v3) and async (v2) shapes. Add a cancelled flag so stale async responses from a previous query cannot overwrite newer results. Bump @orama/orama floor to ^3.1.18, the version already locked and tested. --- website/package-lock.json | 62 ++++++++++++++++++++++++- website/package.json | 2 +- website/src/components/react/Search.tsx | 26 ++++++++--- 3 files changed, 81 insertions(+), 9 deletions(-) diff --git a/website/package-lock.json b/website/package-lock.json index 2cc2b47..cc6155d 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -14,7 +14,7 @@ "@fontsource-variable/geist": "^5.3.0", "@fontsource-variable/jetbrains-mono": "^5.3.0", "@fontsource-variable/sora": "^5.3.0", - "@orama/orama": "^3.0.4", + "@orama/orama": "^3.1.18", "@tailwindcss/vite": "^4.0.0", "astro": "^5.1.0", "class-variance-authority": "^0.7.1", @@ -4471,6 +4471,66 @@ "node": ">=14.0.0" } }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.1", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.1", + "inBundle": true, + "license": "0BSD", + "optional": true + }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", diff --git a/website/package.json b/website/package.json index 02849ce..9fa99f9 100644 --- a/website/package.json +++ b/website/package.json @@ -20,7 +20,7 @@ "@fontsource-variable/geist": "^5.3.0", "@fontsource-variable/jetbrains-mono": "^5.3.0", "@fontsource-variable/sora": "^5.3.0", - "@orama/orama": "^3.0.4", + "@orama/orama": "^3.1.18", "@tailwindcss/vite": "^4.0.0", "astro": "^5.1.0", "class-variance-authority": "^0.7.1", diff --git a/website/src/components/react/Search.tsx b/website/src/components/react/Search.tsx index 5e2c8a0..8f02b8f 100644 --- a/website/src/components/react/Search.tsx +++ b/website/src/components/react/Search.tsx @@ -45,22 +45,34 @@ export default function Search() { setHits([]); return; } - try { - const res = search(db, { - term: query, - properties: ['title', 'description', 'content'], - }); - if (res instanceof Promise) return; + let cancelled = false; + const apply = (res: any) => setHits( - (res.hits ?? []).slice(0, 8).map((h: any) => ({ + (res?.hits ?? []).slice(0, 8).map((h: any) => ({ url: h.document.url, title: h.document.title, description: h.document.description, })), ); + try { + Promise.resolve( + search(db, { + term: query, + properties: ['title', 'description', 'content'], + }), + ) + .then((res) => { + if (!cancelled) apply(res); + }) + .catch(() => { + if (!cancelled) setHits([]); + }); } catch { setHits([]); } + return () => { + cancelled = true; + }; }, [query, db]); return (