{"_id":"@bodhiapp/bodhijs","_rev":"6-9b59245b7f94ca8ed00e1fd3b4f6a943","name":"@bodhiapp/bodhijs","dist-tags":{"latest":"0.0.6"},"versions":{"0.0.1":{"name":"@bodhiapp/bodhijs","version":"0.0.1","keywords":["llm","ai","browser-extension","bodhisearch"],"author":{"name":"Bodhi Search"},"license":"MIT","_id":"@bodhiapp/bodhijs@0.0.1","maintainers":[{"name":"amir36","email":"amir.nagri@gmail.com"}],"homepage":"https://github.com/BodhiSearch/bodhi-browser","dist":{"shasum":"73e72a815d42b00674f74780ecdfb2bb0c58c85b","tarball":"https://registry.npmjs.org/@bodhiapp/bodhijs/-/bodhijs-0.0.1.tgz","fileCount":12,"integrity":"sha512-9qPsKZSPv2vZlDOtDm4G3McZMFBiDSevEYe4DmfJpIyuPKlHnW6Yzc05vIVVbcVzd8wxn9a/XMXoGXAnGx1QFA==","signatures":[{"sig":"MEYCIQCmv53AhTe6JoqaMEhUPjD7tLtZGXO5wvALwuphrxQCVwIhAMqBixPfYGhRqqgyM/a8nWuKPIRYG07QKvOK0kLhTYB/","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":86804},"main":"dist/bodhi.cjs.js","type":"module","types":"dist/index.d.ts","module":"dist/bodhi.esm.js","browser":"dist/bodhi.js","gitHead":"770082aa3e51c6931a3e794e101a988458011ad7","scripts":{"dev":"rollup -c -w","lint":"eslint . --ext .js,.jsx,.ts,.tsx","test":"echo \"No tests defined yet\" && exit 0","build":"npm run clean && rollup -c","clean":"rm -rf dist","format":"prettier --write \"src/**/*.{js,jsx,ts,tsx,json,md}\"","lint:fix":"eslint . --ext .js,.jsx,.ts,.tsx --fix","validate":"npm run check-format && npm run lint && npm run build","check-format":"prettier --check \"src/**/*.{js,jsx,ts,tsx,json,md}\"","prepublishOnly":"npm run build"},"_npmUser":{"name":"amir36","email":"amir.nagri@gmail.com"},"_npmVersion":"10.9.2","description":"A JavaScript library for interacting with local LLM capabilities via Bodhi Browser Extension","directories":{},"_nodeVersion":"22.14.0","dependencies":{"@bodhiapp/ts-client":"^0.1.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"glob":"^11.0.1","tslib":"^2.6.2","eslint":"^9.22.0","rimraf":"^6.0.1","rollup":"^3.29.4","globals":"^16.0.0","prettier":"^3.1.1","@eslint/js":"^9.23.0","typescript":"^5.3.3","@types/node":"^20.11.24","rollup-plugin-dts":"^6.2.1","@rollup/plugin-terser":"^0.4.4","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@rollup/plugin-commonjs":"^28.0.2","@rollup/plugin-typescript":"^11.1.6","@typescript-eslint/parser":"^8.25.0","@rollup/plugin-node-resolve":"^15.2.3","@typescript-eslint/eslint-plugin":"^8.25.0"},"_npmOperationalInternal":{"tmp":"tmp/bodhijs_0.0.1_1743079698604_0.029386302549344157","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@bodhiapp/bodhijs","version":"0.0.2","keywords":["llm","ai","browser-extension","bodhisearch"],"author":{"name":"Bodhi Search"},"license":"MIT","_id":"@bodhiapp/bodhijs@0.0.2","maintainers":[{"name":"amir36","email":"amir.nagri@gmail.com"}],"homepage":"https://github.com/BodhiSearch/bodhi-browser","dist":{"shasum":"fa05325f8da4e81b10079b11089b8a5649e1c71a","tarball":"https://registry.npmjs.org/@bodhiapp/bodhijs/-/bodhijs-0.0.2.tgz","fileCount":12,"integrity":"sha512-T/3kmtADZoYkvi+aQJBa068ay59FUnpBoUydvPWVBz72ng8fkdhFGthElFpXqpymj0MGa14zheczGmWqlPHkqA==","signatures":[{"sig":"MEUCICIjnL6H7j5g01N5cqRQ5z9VPkqXCTThNJ5dPlKQQ08WAiEAvZ95R3pqQorqLWRu/gj5oepm37nZ5ylsaS1AFPO7pcw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":88925},"main":"dist/bodhi.cjs.js","type":"module","types":"dist/index.d.ts","module":"dist/bodhi.esm.js","browser":"dist/bodhi.js","gitHead":"ba356037ba77be05e6e0005967d45146b4871a4e","scripts":{"dev":"rollup -c -w","lint":"eslint . --ext .js,.jsx,.ts,.tsx","test":"echo \"No tests defined yet\" && exit 0","build":"rollup -c","clean":"rm -rf dist","lint:fix":"eslint . --ext .js,.jsx,.ts,.tsx --fix","prebuild":"npm run clean","validate":"npm run lint","prepublishOnly":"npm run build"},"_npmUser":{"name":"amir36","email":"amir.nagri@gmail.com"},"_npmVersion":"10.9.2","description":"A JavaScript library for interacting with local LLM capabilities via Bodhi Browser Extension","directories":{},"_nodeVersion":"22.14.0","dependencies":{"@bodhiapp/ts-client":"^0.1.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"glob":"^11.0.1","tslib":"^2.6.2","eslint":"^9.22.0","rimraf":"^6.0.1","rollup":"^3.29.4","globals":"^16.0.0","prettier":"^3.1.1","@eslint/js":"^9.23.0","typescript":"^5.3.3","@types/node":"^20.11.24","rollup-plugin-dts":"^6.2.1","@rollup/plugin-terser":"^0.4.4","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@rollup/plugin-commonjs":"^28.0.2","@rollup/plugin-typescript":"^11.1.6","@typescript-eslint/parser":"^8.25.0","@rollup/plugin-node-resolve":"^15.2.3","@typescript-eslint/eslint-plugin":"^8.25.0"},"_npmOperationalInternal":{"tmp":"tmp/bodhijs_0.0.2_1743097522556_0.04473445456121117","host":"s3://npm-registry-packages-npm-production"}},"0.0.3":{"name":"@bodhiapp/bodhijs","version":"0.0.3","keywords":["llm","ai","browser-extension","bodhisearch"],"author":{"name":"Bodhi Search"},"license":"MIT","_id":"@bodhiapp/bodhijs@0.0.3","maintainers":[{"name":"amir36","email":"amir.nagri@gmail.com"}],"homepage":"https://github.com/BodhiSearch/bodhi-browser","dist":{"shasum":"60c88e418f9d63a96dbf73d3638728708bc7c0df","tarball":"https://registry.npmjs.org/@bodhiapp/bodhijs/-/bodhijs-0.0.3.tgz","fileCount":13,"integrity":"sha512-uq4fgU/RZ/vql1WF8ihFkt/RZJBEsTK7/Na3xan9G+hGIxwMH3mGI14Tp0+OMdcfUHkdmKLthka5d/XonJdQzw==","signatures":[{"sig":"MEMCIQDgePMRrAuglFyDKdlz2K5tj5XxQNK8LFK+JahNzJNMRgIeAqDmA3+hkmiGUFGkQe7lb/1G3l2CHNmKJQWdAK9E","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":27029},"main":"dist/bodhi.cjs.js","type":"module","types":"dist/index.d.ts","module":"dist/bodhi.esm.js","browser":"dist/bodhi.js","gitHead":"a6eacedea192f2bb5628006a6bf7ba4005b8018a","scripts":{"dev":"rollup -c -w","lint":"eslint . --ext .js,.jsx,.ts,.tsx","test":"vitest run","build":"rollup -c","clean":"rimraf dist","setup":"node --loader ts-node/esm scripts/setup.js","pretest":"npm run build && npm run setup","lint:fix":"eslint . --ext .js,.jsx,.ts,.tsx --fix","prebuild":"npm run clean","validate":"npm run lint && npm run test","test:watch":"vitest","start:servers":"node --loader ts-node/esm tests/start-servers.ts","prepublishOnly":"npm run build","start:mock-llm":"node --loader ts-node/esm tests/start-mock-llm.js"},"_npmUser":{"name":"amir36","actor":{"name":"amir36","type":"user","email":"amir.nagri@gmail.com"},"email":"amir.nagri@gmail.com"},"_npmVersion":"10.9.2","description":"A JavaScript library for interacting with local LLM capabilities via Bodhi Browser Extension","directories":{},"_nodeVersion":"22.16.0","dependencies":{"@bodhiapp/ts-client":"^0.1.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.6.2","eslint":"^9.22.0","rimraf":"^6.0.1","rollup":"^3.29.4","vitest":"^3.0.8","globals":"^16.0.0","ts-node":"^10.9.2","fs-extra":"^11.2.0","prettier":"^3.1.1","happy-dom":"^17.4.4","puppeteer":"^22.3.0","@eslint/js":"^9.23.0","typescript":"^5.8.3","@types/node":"^20.11.24","@types/fs-extra":"^11.0.4","@vitest/browser":"^3.0.8","rollup-plugin-dts":"^6.2.1","eslint-plugin-html":"^8.1.2","@rollup/plugin-terser":"^0.4.4","@bodhiapp/app-bindings":"^0.0.6","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@rollup/plugin-commonjs":"^28.0.2","@bodhiapp/mock-llm-server":"file:../mock-llm-server","@rollup/plugin-typescript":"^11.1.6","@typescript-eslint/parser":"^8.25.0","@rollup/plugin-node-resolve":"^15.2.3","@typescript-eslint/eslint-plugin":"^8.25.0"},"_npmOperationalInternal":{"tmp":"tmp/bodhijs_0.0.3_1751450209314_0.987063572300704","host":"s3://npm-registry-packages-npm-production"}},"0.0.4":{"name":"@bodhiapp/bodhijs","version":"0.0.4","keywords":["llm","ai","browser-extension","bodhisearch"],"author":{"name":"Bodhi Search"},"license":"MIT","_id":"@bodhiapp/bodhijs@0.0.4","maintainers":[{"name":"amir36","email":"amir.nagri@gmail.com"}],"homepage":"https://github.com/BodhiSearch/bodhi-browser","dist":{"shasum":"bb39f6bbcbb3f94aa23b51a77275713dc966a98d","tarball":"https://registry.npmjs.org/@bodhiapp/bodhijs/-/bodhijs-0.0.4.tgz","fileCount":11,"integrity":"sha512-Ju2Cq+N9Apx5o65+/YlNc2wUSPk+MYEAUauMB7u56Fo9IzodSeJdiu0dnG2LVjSMEHZclM4NeMVW1zAdR2+6mw==","signatures":[{"sig":"MEUCIQDy892rHHB8P2Nk0XICNZeXQoyaxUaGs6B83rxHSjioOwIgC6/4wGrgQvNKKtbKikATs1wT4UrHW5eFcwE7aMIY3uE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":26458},"main":"dist/bodhi.cjs.js","type":"module","types":"dist/index.d.ts","module":"dist/bodhi.esm.js","gitHead":"28e25ed88bbe3b715ec599ce809c2db60f6fe7ca","scripts":{"dev":"rollup -c -w","lint":"eslint . --ext .js,.jsx,.ts,.tsx","test":"vitest run","build":"rollup -c","clean":"rimraf dist","pretest":"npm run build","lint:fix":"eslint . --ext .js,.jsx,.ts,.tsx --fix","prebuild":"npm run clean","validate":"npm run lint && npm run test","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"amir36","actor":{"name":"amir36","type":"user","email":"amir.nagri@gmail.com"},"email":"amir.nagri@gmail.com"},"_npmVersion":"10.9.2","description":"A JavaScript library for interacting with local LLM capabilities via Bodhi Browser Extension","directories":{},"_nodeVersion":"22.17.0","dependencies":{"@bodhiapp/ts-client":"^0.1.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.6.2","dotenv":"^17.1.0","eslint":"^9.22.0","rimraf":"^6.0.1","rollup":"^3.29.4","vitest":"^3.0.8","globals":"^16.0.0","ts-node":"^10.9.2","fs-extra":"^11.2.0","prettier":"^3.1.1","happy-dom":"^17.4.4","@eslint/js":"^9.23.0","typescript":"^5.8.3","@types/node":"^20.11.24","@types/fs-extra":"^11.0.4","@vitest/browser":"^3.0.8","@playwright/test":"^1.53.2","rollup-plugin-dts":"^6.2.1","eslint-plugin-html":"^8.1.2","@rollup/plugin-terser":"^0.4.4","@bodhiapp/app-bindings":"^0.0.13","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@rollup/plugin-commonjs":"^28.0.2","@rollup/plugin-typescript":"^11.1.6","@typescript-eslint/parser":"^8.25.0","@rollup/plugin-node-resolve":"^15.2.3","@typescript-eslint/eslint-plugin":"^8.25.0"},"_npmOperationalInternal":{"tmp":"tmp/bodhijs_0.0.4_1752058513014_0.5535428053065554","host":"s3://npm-registry-packages-npm-production"}},"0.0.5":{"name":"@bodhiapp/bodhijs","version":"0.0.5","keywords":["llm","ai","browser-extension","bodhisearch"],"author":{"name":"Bodhi Search"},"_id":"@bodhiapp/bodhijs@0.0.5","maintainers":[{"name":"amir36","email":"amir.nagri@gmail.com"}],"homepage":"https://github.com/BodhiSearch/bodhi-browser","dist":{"shasum":"665140cb12800a76ba13fc608dd2d0c2a85619ca","tarball":"https://registry.npmjs.org/@bodhiapp/bodhijs/-/bodhijs-0.0.5.tgz","fileCount":16,"integrity":"sha512-tewDKHngkbl1WWhKQ1n+CP/rW16pUaDR9z4BBTsFf7Csgu/OyPwUZ/RViTwkJFukIE/kQw5g1vqrZ3FYTseWsw==","signatures":[{"sig":"MEUCIGjiKEHCNqrn8b3bQ+5E3FOEHwOYmcw9Cai9KIXTxEaTAiEAvWQE1eNn/CbRluZpeaxKzebNiiw7b6/xRXAtQEh9dBM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":755886},"main":"dist/bodhi.cjs.js","type":"module","types":"dist/index.d.ts","module":"dist/bodhi.esm.js","gitHead":"d03e66cdbc3be5ffa4a7708136bcd1a97079b243","scripts":{"dev":"rollup -c -w","lint":"eslint . --ext .js,.jsx,.ts,.tsx","test":"vitest run","build":"npm run copy-modal && rollup -c","clean":"make clean","pretest":"make pretest","test:ci":"cross-env CI=true vitest run","lint:fix":"eslint . --ext .js,.jsx,.ts,.tsx --fix","prebuild":"make dependencies","validate":"npm run lint && npm run test","build:fast":"node ../scripts/build-fast.mjs bodhi-js 'npm run build:fast-direct' src package.json rollup.config.js scripts/copy-modal.js","build:only":"npm run copy-modal && rollup -c","copy-modal":"node scripts/copy-modal.js","pretest:ci":"make ci.pretest","prebuild:fast":"make dependencies-fast","prepublishOnly":"npm run build","build:fast-direct":"npm run prebuild:fast && npm run build:only"},"_npmUser":{"name":"amir36","email":"amir.nagri@gmail.com"},"_npmVersion":"10.9.3","description":"A JavaScript library for interacting with local LLM capabilities via Bodhi Browser Extension","directories":{},"_nodeVersion":"22.18.0","dependencies":{"ua-parser-js":"^1.0.40","@bodhiapp/ts-client":"^0.1.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"serve":"^14.2.1","tslib":"^2.6.2","dotenv":"^17.1.0","eslint":"^9.22.0","rimraf":"^6.0.1","rollup":"^3.29.4","vitest":"^3.0.8","globals":"^16.0.0","ts-node":"^10.9.2","fs-extra":"^11.2.0","prettier":"^3.1.1","cross-env":"^7.0.3","happy-dom":"^17.4.4","@eslint/js":"^9.23.0","playwright":"^1.54.0","typescript":"^5.8.3","@types/node":"^20.19.9","@types/fs-extra":"^11.0.4","@vitest/browser":"^3.0.8","@playwright/test":"1.54.2","rollup-plugin-dts":"^6.2.1","eslint-plugin-html":"^8.1.2","@types/ua-parser-js":"^0.7.39","rollup-plugin-string":"^3.0.0","@rollup/plugin-terser":"^0.4.4","@bodhiapp/app-bindings":"^0.0.15","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.3","@rollup/plugin-commonjs":"^28.0.2","@rollup/plugin-typescript":"^11.1.6","@typescript-eslint/parser":"^8.25.0","@rollup/plugin-node-resolve":"^15.2.3","@bodhiapp/integration-test-utils":"file:../integration-test-utils","@typescript-eslint/eslint-plugin":"^8.25.0"},"_npmOperationalInternal":{"tmp":"tmp/bodhijs_0.0.5_1755586375481_0.6524609033657529","host":"s3://npm-registry-packages-npm-production"}},"0.0.6":{"name":"@bodhiapp/bodhijs","version":"0.0.6","description":"A JavaScript library for interacting with local LLM capabilities via Bodhi Browser Extension","type":"module","main":"dist/bodhi.cjs.js","module":"dist/bodhi.esm.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"scripts":{"clean":"make clean","copy-modal":"node scripts/copy-modal.js","build":"npm run copy-modal && rollup -c","prebuild":"make dependencies","build:only":"npm run copy-modal && rollup -c","build:fast-direct":"npm run prebuild:fast && npm run build:only","build:fast":"node ../scripts/build-fast.mjs bodhi-js 'npm run build:fast-direct' src package.json rollup.config.js scripts/copy-modal.js","prebuild:fast":"make dependencies-fast","dev":"rollup -c -w","test":"vitest run","pretest":"make pretest","test:ci":"cross-env CI=true vitest run","pretest:ci":"make ci.pretest","prepublishOnly":"npm run build","lint":"eslint . --ext .js,.jsx,.ts,.tsx","lint:fix":"eslint . --ext .js,.jsx,.ts,.tsx --fix","validate":"npm run lint && npm run test"},"keywords":["llm","ai","browser-extension","bodhisearch"],"author":{"name":"Bodhi Search"},"homepage":"https://github.com/BodhiSearch/bodhi-browser","dependencies":{"@bodhiapp/ts-client":"^0.1.5","ua-parser-js":"^1.0.40"},"devDependencies":{"@bodhiapp/app-bindings":"0.0.17","@bodhiapp/integration-test-utils":"file:../integration-test-utils","@eslint/js":"^9.23.0","@playwright/test":"1.54.2","@rollup/plugin-commonjs":"^28.0.2","@rollup/plugin-node-resolve":"^15.2.3","@rollup/plugin-terser":"^0.4.4","@rollup/plugin-typescript":"^11.1.6","@types/fs-extra":"^11.0.4","@types/node":"^20.19.9","@types/ua-parser-js":"^0.7.39","@typescript-eslint/eslint-plugin":"^8.25.0","@typescript-eslint/parser":"^8.25.0","@vitest/browser":"^3.0.8","cross-env":"^7.0.3","dotenv":"^17.1.0","eslint":"^9.22.0","eslint-config-prettier":"^9.1.0","eslint-plugin-html":"^8.1.2","eslint-plugin-prettier":"^5.1.3","fs-extra":"^11.2.0","globals":"^16.0.0","happy-dom":"^17.4.4","playwright":"^1.54.0","prettier":"^3.1.1","rimraf":"^6.0.1","rollup":"^3.29.4","rollup-plugin-dts":"^6.2.1","rollup-plugin-string":"^3.0.0","serve":"^14.2.1","ts-node":"^10.9.2","tslib":"^2.6.2","typescript":"^5.8.3","vitest":"^3.0.8"},"_id":"@bodhiapp/bodhijs@0.0.6","gitHead":"1e08eadfaf40584a894b3d1fed61e23a3055efa3","_nodeVersion":"22.19.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-RLLYMMgafamHCZhg15mi3dWmSQG9GFed/VVtyaTyDuvnU2gcfD3QoskHKMu/dY9+bFdjoO/OqFrJ/T8l8qbJZQ==","shasum":"af2523df08ca9ae8fc1d035b4d6e73c8366d7c73","tarball":"https://registry.npmjs.org/@bodhiapp/bodhijs/-/bodhijs-0.0.6.tgz","fileCount":16,"unpackedSize":765659,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCXDlI7vqvZzk3EdXsROZCMDwwCinxiLi46ExJD7mn97wIhAJ4/U2uWcopcP/Y5CCQvSVexhGkI02kpqFCM+yqps8eN"}]},"_npmUser":{"name":"amir36","email":"amir.nagri@gmail.com"},"directories":{},"maintainers":[{"name":"amir36","email":"amir.nagri@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/bodhijs_0.0.6_1758596488117_0.9987026601441613"},"_hasShrinkwrap":false}},"time":{"created":"2025-03-27T12:48:18.520Z","modified":"2025-09-23T03:01:28.669Z","0.0.1":"2025-03-27T12:48:18.792Z","0.0.2":"2025-03-27T17:45:22.792Z","0.0.3":"2025-07-02T09:56:49.485Z","0.0.4":"2025-07-09T10:55:13.198Z","0.0.5":"2025-08-19T06:52:55.708Z","0.0.6":"2025-09-23T03:01:28.361Z"},"author":{"name":"Bodhi Search"},"homepage":"https://github.com/BodhiSearch/bodhi-browser","keywords":["llm","ai","browser-extension","bodhisearch"],"description":"A JavaScript library for interacting with local LLM capabilities via Bodhi Browser Extension","maintainers":[{"name":"amir36","email":"amir.nagri@gmail.com"}],"readme":"# @bodhiapp/bodhijs\n\nA TypeScript/JavaScript library for interacting with local LLM capabilities via the Bodhi Browser Extension. This library provides a clean, typed interface for extension detection, API communication, and streaming responses.\n\n## Features\n\n- 🔍 **Extension Detection**: Automatic detection and initialization of the Bodhi browser extension\n- 🌊 **Streaming Support**: Real-time streaming responses for chat completions and other long-running operations\n- 🛡️ **Type Safety**: Comprehensive TypeScript support with detailed type definitions\n- 🔄 **OpenAI Compatible**: Chat completion API compatible with OpenAI's format for easy migration\n- ⚡ **Error Handling**: Robust error handling with specific error types for different failure scenarios\n- 🧪 **Well Tested**: Comprehensive integration tests with real browser automation\n\n## Installation\n\nInstall the library via npm:\n\n```bash\nnpm install @bodhiapp/bodhijs\n```\n\n## Quick Start\n\n### Basic Usage\n\n```typescript\nimport { loadBodhiExtClient, ExtensionNotFoundError } from '@bodhiapp/bodhijs';\n\nasync function main() {\n  try {\n    // Initialize the client (detects extension and gets ID with default 10s timeout)\n    const client = await loadBodhiExtClient();\n\n    // Test connectivity\n    const ping = await client.ping();\n    console.log('Server status:', ping.message);\n\n    // Make a simple API request\n    const response = await client.sendApiRequest('POST', '/v1/chat/completions', {\n      model: 'llama3',\n      messages: [{ role: 'user', content: 'What is the capital of France?' }],\n    });\n\n    console.log('Response:', response.body);\n  } catch (error) {\n    if (error instanceof ExtensionNotFoundError) {\n      console.log('Please install the Bodhi browser extension');\n    } else {\n      console.error('Error:', error.message);\n    }\n  }\n}\n\nmain();\n```\n\n### Streaming Responses\n\nFor real-time streaming responses (great for chat applications):\n\n```typescript\nimport { loadBodhiExtClient } from '@bodhiapp/bodhijs';\n\nasync function streamingChat() {\n  const client = await loadBodhiExtClient();\n\n  // Create a streaming request\n  const stream = await client.sendStreamRequest('POST', '/v1/chat/completions', {\n    model: 'llama3',\n    messages: [\n      { role: 'system', content: 'You are a helpful assistant.' },\n      { role: 'user', content: 'Write a short poem about TypeScript' },\n    ],\n    stream: true,\n    temperature: 0.7,\n  });\n\n  // Process chunks as they arrive\n  console.log('Assistant: ');\n  for await (const chunk of stream) {\n    if (chunk.body?.choices?.[0]?.delta?.content) {\n      process.stdout.write(chunk.body.choices[0].delta.content);\n    }\n  }\n  console.log('\\n');\n}\n\nstreamingChat();\n```\n\n### Error Handling\n\nThe library provides specific error types for different scenarios:\n\n```typescript\nimport { loadBodhiExtClient, ExtensionNotFoundError, ExtensionTimeoutError } from '@bodhiapp/bodhijs';\n\nasync function robustInitialization() {\n  try {\n    // Try to load with a custom timeout (15 seconds)\n    const client = await loadBodhiExtClient({ timeout: 15000 });\n\n    // Verify server connectivity\n    await client.ping();\n\n    return client;\n  } catch (error) {\n    if (error instanceof ExtensionNotFoundError) {\n      // Extension not installed or not enabled\n      showInstallationInstructions();\n    } else if (error instanceof ExtensionTimeoutError) {\n      // Extension found but not ready\n      showRetryOption();\n    } else {\n      // Other errors (network, server, etc.)\n      showGenericError(error);\n    }\n    throw error;\n  }\n}\n\nfunction showInstallationInstructions() {\n  console.log(`\n    The Bodhi browser extension is required but not detected.\n    Please:\n    1. Install the extension from the Chrome Web Store\n    2. Enable the extension in your browser settings\n    3. Refresh this page\n  `);\n}\n\nfunction showRetryOption() {\n  console.log(`\n    Extension found but not ready. This can happen if:\n    1. The extension is still initializing\n    2. The page loaded before the extension was ready\n    \n    Please refresh the page or try again.\n  `);\n}\n```\n\n## API Reference\n\n### Core Classes\n\n#### `BodhiExtClient`\n\nThe main client class for interacting with the browser extension.\n\n```typescript\nclass BodhiExtClient {\n  constructor(extensionId: string);\n  getExtensionId(): string;\n  sendApiRequest(\n    method: string,\n    endpoint: string,\n    body?: any,\n    headers?: Record<string, string>\n  ): Promise<ApiResponse>;\n  sendStreamRequest(\n    method: string,\n    endpoint: string,\n    body?: any,\n    headers?: Record<string, string>\n  ): Promise<AsyncIterable<StreamChunk>>;\n  ping(): Promise<{ message: string }>;\n}\n```\n\n**Methods:**\n\n- **`getExtensionId()`**: Returns the cached extension ID\n- **`sendApiRequest()`**: Sends a standard HTTP request through the extension\n- **`sendStreamRequest()`**: Sends a streaming HTTP request, returns an AsyncIterable\n- **`ping()`**: Tests connectivity with the extension and backend server\n\n### Factory Functions\n\n#### `loadBodhiExtClient(config?: BodhiExtClientConfig): Promise<BodhiExtClient>`\n\nThe recommended way to create a BodhiExtClient instance. Handles extension detection and initialization.\n\n**Parameters:**\n\n- `config` (optional): Configuration object with the following options:\n  - `timeout` (optional): Maximum time to wait for extension detection in milliseconds (default: 10000)\n\n**Returns:** Promise resolving to a fully initialized BodhiExtClient instance\n\n**Throws:**\n\n- `ExtensionNotFoundError`: If extension is not detected within timeout\n- `ExtensionTimeoutError`: If extension is detected but fails to provide ID within timeout\n\n### Error Classes\n\n#### `ExtensionNotFoundError`\n\nThrown when the browser extension is not detected within the specified timeout.\n\n```typescript\nclass ExtensionNotFoundError extends Error {\n  constructor(public timeout: number)\n}\n```\n\n#### `ExtensionTimeoutError`\n\nThrown when the extension is detected but fails to provide its ID within the timeout.\n\n```typescript\nclass ExtensionTimeoutError extends Error {\n  constructor(public timeout: number)\n}\n```\n\n### Type Definitions\n\n#### `ApiResponse`\n\n```typescript\ninterface ApiResponse {\n  body: any; // Response body data\n  headers: Record<string, string>; // HTTP headers\n  status: number; // HTTP status code\n}\n```\n\n#### `StreamChunk`\n\n```typescript\ninterface StreamChunk {\n  body: any; // Chunk body data\n  headers?: Record<string, string>; // HTTP headers (first chunk only)\n  status?: number; // HTTP status code (first chunk only)\n}\n```\n\n#### `ChatRequest` (OpenAI Compatible)\n\n```typescript\ninterface ChatRequest {\n  model: string; // Model identifier\n  messages: ChatMessage[]; // Conversation messages\n  stream?: boolean; // Enable streaming\n  temperature?: number; // Randomness (0.0-2.0)\n  max_tokens?: number; // Maximum tokens to generate\n  top_p?: number; // Nucleus sampling (0.0-1.0)\n  frequency_penalty?: number; // Frequency penalty (-2.0-2.0)\n  presence_penalty?: number; // Presence penalty (-2.0-2.0)\n  stop?: string | string[]; // Stop sequences\n}\n```\n\n#### `ChatMessage`\n\n```typescript\ninterface ChatMessage {\n  role: 'system' | 'user' | 'assistant';\n  content: string;\n}\n```\n\n## Usage Patterns\n\n### Chat Application Pattern\n\n```typescript\nimport { loadBodhiExtClient, type ChatMessage } from '@bodhiapp/bodhijs';\n\nclass ChatApp {\n  private client: BodhiExtClient | null = null;\n  private messages: ChatMessage[] = [];\n\n  async initialize() {\n    try {\n      this.client = await loadBodhiExtClient();\n      await this.client.ping(); // Verify connectivity\n      console.log('Chat app ready!');\n    } catch (error) {\n      console.error('Failed to initialize:', error.message);\n      throw error;\n    }\n  }\n\n  async sendMessage(content: string): Promise<string> {\n    if (!this.client) throw new Error('Client not initialized');\n\n    // Add user message\n    this.messages.push({ role: 'user', content });\n\n    // Get streaming response\n    const stream = await this.client.sendStreamRequest('POST', '/v1/chat/completions', {\n      model: 'llama3',\n      messages: this.messages,\n      stream: true,\n      temperature: 0.7,\n    });\n\n    let assistantResponse = '';\n    for await (const chunk of stream) {\n      const content = chunk.body?.choices?.[0]?.delta?.content;\n      if (content) {\n        assistantResponse += content;\n        this.onStreamChunk(content); // Update UI in real-time\n      }\n    }\n\n    // Add assistant response to conversation\n    this.messages.push({ role: 'assistant', content: assistantResponse });\n    return assistantResponse;\n  }\n\n  private onStreamChunk(content: string) {\n    // Update your UI here\n    console.log(content);\n  }\n}\n```\n\n### Generic API Client Pattern\n\n```typescript\nimport { loadBodhiExtClient, type ApiResponse } from '@bodhiapp/bodhijs';\n\nclass BodhiApiClient {\n  private client: BodhiExtClient;\n\n  constructor(client: BodhiExtClient) {\n    this.client = client;\n  }\n\n  static async create(): Promise<BodhiApiClient> {\n    const client = await loadBodhiExtClient();\n    return new BodhiApiClient(client);\n  }\n\n  async get<T = any>(endpoint: string, headers?: Record<string, string>): Promise<T> {\n    const response = await this.client.sendApiRequest('GET', endpoint, undefined, headers);\n    return response.body;\n  }\n\n  async post<T = any>(endpoint: string, data?: any, headers?: Record<string, string>): Promise<T> {\n    const response = await this.client.sendApiRequest('POST', endpoint, data, {\n      'Content-Type': 'application/json',\n      ...headers,\n    });\n    return response.body;\n  }\n\n  async postStream(endpoint: string, data?: any, headers?: Record<string, string>) {\n    return this.client.sendStreamRequest('POST', endpoint, data, {\n      'Content-Type': 'application/json',\n      ...headers,\n    });\n  }\n\n  async healthCheck(): Promise<boolean> {\n    try {\n      await this.client.ping();\n      return true;\n    } catch {\n      return false;\n    }\n  }\n}\n\n// Usage\nconst api = await BodhiApiClient.create();\nconst models = await api.get('/v1/models');\nconsole.log('Available models:', models);\n```\n\n## Best Practices\n\n### 1. Always Handle Extension Detection Errors\n\n```typescript\n// ✅ Good\ntry {\n  const client = await loadBodhiExtClient();\n  // Use client...\n} catch (error) {\n  if (error instanceof ExtensionNotFoundError) {\n    // Show installation instructions\n  }\n  // Handle error appropriately\n}\n\n// ❌ Bad\nconst client = await loadBodhiExtClient(); // Unhandled errors\n```\n\n### 2. Test Connectivity Before Making Requests\n\n```typescript\n// ✅ Good\nconst client = await loadBodhiExtClient();\nawait client.ping(); // Verify server is reachable\nconst response = await client.sendApiRequest('POST', '/v1/chat/completions', data);\n\n// ❌ Bad\nconst client = await loadBodhiExtClient();\nconst response = await client.sendApiRequest('POST', '/v1/chat/completions', data); // May fail if server is down\n```\n\n### 3. Use Appropriate Timeouts\n\n```typescript\n// ✅ Good - Custom timeout for slow networks\nconst client = await loadBodhiExtClient({ timeout: 15000 }); // 15 seconds\n\n// ✅ Good - Quick timeout for fast feedback\nconst client = await loadBodhiExtClient({ timeout: 5000 }); // 5 seconds\n\n// ❌ Bad - Very short timeout may cause false negatives\nconst client = await loadBodhiExtClient({ timeout: 1000 }); // 1 second (too short)\n```\n\n### 4. Handle Streaming Errors Gracefully\n\n```typescript\n// ✅ Good\ntry {\n  const stream = await client.sendStreamRequest('POST', '/v1/chat/completions', data);\n  for await (const chunk of stream) {\n    // Process chunk\n  }\n} catch (error) {\n  console.error('Streaming failed:', error.message);\n  // Fallback to non-streaming request\n  const response = await client.sendApiRequest('POST', '/v1/chat/completions', {\n    ...data,\n    stream: false,\n  });\n}\n```\n\n## Development\n\n### Building the Library\n\n```bash\n# Install dependencies\nnpm install\n\n# Build the library\nnpm run build\n\n# Build in watch mode for development\nnpm run dev\n```\n\n### Testing\n\nThe library includes comprehensive integration tests that run against real browser instances with the extension loaded:\n\n```bash\n# Run all tests\nnpm test\n\n# Run tests in watch mode\nnpm run test:watch\n\n# Run linting\nnpm run lint\n\n# Fix linting issues\nnpm run lint:fix\n\n# Run validation (lint + test)\nnpm run validate\n```\n\n### Project Structure\n\n```\nbodhi-js/\n├── src/\n│   ├── index.ts          # Main entry point and exports\n│   ├── core.ts           # BodhiExtClient class and factory function\n│   └── types.ts          # TypeScript type definitions\n├── tests/                # Integration tests\n├── dist/                 # Built library files\n└── README.md            # This file\n```\n\n## Browser Compatibility\n\n- Chrome/Chromium-based browsers (Chrome, Edge, Brave, etc.)\n- Requires the Bodhi browser extension to be installed and enabled\n- Modern JavaScript features (ES2020+)\n- TypeScript 4.5+ for development\n\n## Migration from Legacy API\n\nIf you're migrating from an older version of the library that used function-based exports:\n\n### Before (Legacy API)\n\n```javascript\nimport { isInstalled, ping, chat } from '@bodhiapp/bodhijs';\n\nif (isInstalled()) {\n  const response = await chat.completions.create({...});\n}\n```\n\n### After (New BodhiExtClient API)\n\n```typescript\nimport { loadBodhiExtClient, ExtensionNotFoundError } from '@bodhiapp/bodhijs';\n\ntry {\n  const client = await loadBodhiExtClient();\n  const response = await client.sendApiRequest('POST', '/v1/chat/completions', {...});\n} catch (error) {\n  if (error instanceof ExtensionNotFoundError) {\n    // Handle extension not found\n  }\n}\n```\n\n## Contributing\n\nWe welcome contributions! Please see our contributing guidelines for more information.\n\n## License\n\nMIT License - see LICENSE file for details.\n\n## Support\n\n- 📖 [Documentation](https://github.com/BodhiSearch/bodhi-browser)\n- 🐛 [Issue Tracker](https://github.com/BodhiSearch/bodhi-browser/issues)\n- 💬 [Discussions](https://github.com/BodhiSearch/bodhi-browser/discussions)\n","readmeFilename":"README.md"}