{"_id":"@duct-ui/cloudflare-search-provider","_rev":"5-15ee4a15a90a94d5d69f4303c9d291a1","name":"@duct-ui/cloudflare-search-provider","dist-tags":{"latest":"0.8.4"},"versions":{"0.8.0":{"name":"@duct-ui/cloudflare-search-provider","version":"0.8.0","keywords":["duct-ui","search","cloudflare","worker"],"author":{"name":"navilan","email":"navilan@folds.in"},"license":"MIT","_id":"@duct-ui/cloudflare-search-provider@0.8.0","maintainers":[{"name":"navilan.puthir","email":"navilan@puthir.in"}],"homepage":"https://github.com/navilan/duct-ui#readme","bugs":{"url":"https://github.com/navilan/duct-ui/issues"},"bin":{"duct-cf-search":"dist/cli.js"},"dist":{"shasum":"93f8573d46aa13ffbea74a1e9b148f1482823ed9","tarball":"https://registry.npmjs.org/@duct-ui/cloudflare-search-provider/-/cloudflare-search-provider-0.8.0.tgz","fileCount":20,"integrity":"sha512-Vph87z3jPjX2nVIDYWYW5NvM1uppLaxeQ7KBSZUoPG+0OjL9NLkbg9XngjZFjJO0V+mKhUvuXcE58RBilFujNQ==","signatures":[{"sig":"MEUCIQDbY/qRHvXh0vItv+5OqiamsK1OUkSFY/8dA7aTVQsmVwIgNFdySLKvNmFBQG2mdj28shuUYGdgc0G9qrBUacNRzVc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37372},"main":"dist/index.js","type":"module","_from":"file:duct-ui-cloudflare-search-provider-0.8.0.tgz","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./worker":{"types":"./dist/worker.d.ts","import":"./dist/worker.js"}},"scripts":{"build":"tsc","clean":"rm -rf dist"},"_npmUser":{"name":"navilan.puthir","email":"navilan@puthir.in"},"_resolved":"/private/var/folders/mm/7tvfnj1n4kjbgbjpd8rp3ypw0000gn/T/7daf0190bc8604691f4cabe6515e2daa/duct-ui-cloudflare-search-provider-0.8.0.tgz","_integrity":"sha512-Vph87z3jPjX2nVIDYWYW5NvM1uppLaxeQ7KBSZUoPG+0OjL9NLkbg9XngjZFjJO0V+mKhUvuXcE58RBilFujNQ==","repository":{"url":"git+https://github.com/navilan/duct-ui.git","type":"git","directory":"packages/cloudflare-search-provider"},"_npmVersion":"10.9.2","description":"Cloudflare Worker search provider for Duct UI","directories":{},"_nodeVersion":"22.16.0","dependencies":{"commander":"^12.1.0","@duct-ui/search-core":"1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"wrangler":"^4.32.0","typescript":"^5.9.2","@types/node":"^24.3.0","@cloudflare/workers-types":"^4.20250823.0"},"peerDependencies":{"wrangler":"^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/cloudflare-search-provider_0.8.0_1756487784681_0.4385780373989201","host":"s3://npm-registry-packages-npm-production"}},"0.8.1":{"name":"@duct-ui/cloudflare-search-provider","version":"0.8.1","keywords":["duct-ui","search","cloudflare","worker"],"author":{"name":"navilan","email":"navilan@folds.in"},"license":"MIT","_id":"@duct-ui/cloudflare-search-provider@0.8.1","maintainers":[{"name":"navilan.puthir","email":"navilan@puthir.in"}],"homepage":"https://github.com/navilan/duct-ui#readme","bugs":{"url":"https://github.com/navilan/duct-ui/issues"},"bin":{"duct-cf-search":"dist/cli.js"},"dist":{"shasum":"acfc203723bdb4962bbcc81e8adaf653ecb2e1c4","tarball":"https://registry.npmjs.org/@duct-ui/cloudflare-search-provider/-/cloudflare-search-provider-0.8.1.tgz","fileCount":20,"integrity":"sha512-iCuz1SXsiJO45ncsGISMTbltWSsJzzvgDIV+KjPVBRCmhXf9NO81FLF3UKIswdPQAtnS9gds8XdJJk+2fBpyEA==","signatures":[{"sig":"MEYCIQC/ge5UXpvlv3K5hHobqT/C7KW5/Bp+zh+Ut9iNSUzJJgIhAJzcA0jmm+ooGOCK/ESUNjP16cLKrlq/zAh6up55mXm5","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37372},"main":"dist/index.js","type":"module","_from":"file:duct-ui-cloudflare-search-provider-0.8.1.tgz","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./worker":{"types":"./dist/worker.d.ts","import":"./dist/worker.js"}},"scripts":{"build":"tsc","clean":"rm -rf dist"},"_npmUser":{"name":"navilan.puthir","email":"navilan@puthir.in"},"_resolved":"/private/var/folders/mm/7tvfnj1n4kjbgbjpd8rp3ypw0000gn/T/0a64d43db620249b41240616c010c76f/duct-ui-cloudflare-search-provider-0.8.1.tgz","_integrity":"sha512-iCuz1SXsiJO45ncsGISMTbltWSsJzzvgDIV+KjPVBRCmhXf9NO81FLF3UKIswdPQAtnS9gds8XdJJk+2fBpyEA==","repository":{"url":"git+https://github.com/navilan/duct-ui.git","type":"git","directory":"packages/cloudflare-search-provider"},"_npmVersion":"10.9.2","description":"Cloudflare Worker search provider for Duct UI","directories":{},"_nodeVersion":"22.16.0","dependencies":{"commander":"^12.1.0","@duct-ui/search-core":"0.8.1"},"_hasShrinkwrap":false,"devDependencies":{"wrangler":"^4.32.0","typescript":"^5.9.2","@types/node":"^24.3.0","@cloudflare/workers-types":"^4.20250823.0"},"peerDependencies":{"wrangler":"^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/cloudflare-search-provider_0.8.1_1756548908435_0.7742640383640407","host":"s3://npm-registry-packages-npm-production"}},"0.8.2":{"name":"@duct-ui/cloudflare-search-provider","version":"0.8.2","keywords":["duct-ui","search","cloudflare","worker"],"author":{"name":"navilan","email":"navilan@folds.in"},"license":"MIT","_id":"@duct-ui/cloudflare-search-provider@0.8.2","maintainers":[{"name":"navilan.puthir","email":"navilan@puthir.in"}],"homepage":"https://github.com/navilan/duct-ui#readme","bugs":{"url":"https://github.com/navilan/duct-ui/issues"},"bin":{"duct-cf-search":"dist/cli.js"},"dist":{"shasum":"b535efc093f93f3ebe3555c619310350195bd1ff","tarball":"https://registry.npmjs.org/@duct-ui/cloudflare-search-provider/-/cloudflare-search-provider-0.8.2.tgz","fileCount":20,"integrity":"sha512-5MbnUd7LhYlMRyn5F1Qa8ONU9kVz/UDcCQa0ZZKtsvos0W98/BpM4mYHzSNyLjbGf7pb+Cs2WxMPMI/X/+6Egg==","signatures":[{"sig":"MEUCIGx4yNl4lj9M93E7NJXV0awQUvQBAk1EE9HxbkATQBcAAiEAp5OorVy18V4rNC+PSjKp3tYMMP+eJ0H3HocA2Xk9hhg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37372},"main":"dist/index.js","type":"module","_from":"file:duct-ui-cloudflare-search-provider-0.8.2.tgz","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./worker":{"types":"./dist/worker.d.ts","import":"./dist/worker.js"}},"scripts":{"build":"tsc","clean":"rm -rf dist"},"_npmUser":{"name":"navilan.puthir","email":"navilan@puthir.in"},"_resolved":"/private/var/folders/mm/7tvfnj1n4kjbgbjpd8rp3ypw0000gn/T/dfa77fe618014666979149c271e0a162/duct-ui-cloudflare-search-provider-0.8.2.tgz","_integrity":"sha512-5MbnUd7LhYlMRyn5F1Qa8ONU9kVz/UDcCQa0ZZKtsvos0W98/BpM4mYHzSNyLjbGf7pb+Cs2WxMPMI/X/+6Egg==","repository":{"url":"git+https://github.com/navilan/duct-ui.git","type":"git","directory":"packages/cloudflare-search-provider"},"_npmVersion":"10.9.2","description":"Cloudflare Worker search provider for Duct UI","directories":{},"_nodeVersion":"22.16.0","dependencies":{"commander":"^12.1.0","@duct-ui/search-core":"0.8.2"},"_hasShrinkwrap":false,"devDependencies":{"wrangler":"^4.32.0","typescript":"^5.9.2","@types/node":"^24.3.0","@cloudflare/workers-types":"^4.20250823.0"},"peerDependencies":{"wrangler":"^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/cloudflare-search-provider_0.8.2_1756561788593_0.3011671876712918","host":"s3://npm-registry-packages-npm-production"}},"0.8.3":{"name":"@duct-ui/cloudflare-search-provider","version":"0.8.3","keywords":["duct-ui","search","cloudflare","worker"],"author":{"name":"navilan","email":"navilan@folds.in"},"license":"MIT","_id":"@duct-ui/cloudflare-search-provider@0.8.3","maintainers":[{"name":"navilan.puthir","email":"navilan@puthir.in"}],"homepage":"https://github.com/navilan/duct-ui#readme","bugs":{"url":"https://github.com/navilan/duct-ui/issues"},"bin":{"duct-cf-search":"dist/cli.js"},"dist":{"shasum":"3edfa473c2b7b94827718c485274203051837282","tarball":"https://registry.npmjs.org/@duct-ui/cloudflare-search-provider/-/cloudflare-search-provider-0.8.3.tgz","fileCount":20,"integrity":"sha512-825aoIudBF+07lMJyg4upuE9EsjQhp76S3rWI0UKihcTY4HGmzy3q/dygGS9foVK0mhUNdtO12VB3woSxDjY+A==","signatures":[{"sig":"MEQCIAchxICl/hqPxppdSlX6FvFnSK51xqQQDO7zIGMaz8DTAiBbhPougUeMR75ml/8+BZMUXGvtqzcbk7R4AGTVi/sowg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37372},"main":"dist/index.js","type":"module","_from":"file:duct-ui-cloudflare-search-provider-0.8.3.tgz","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./worker":{"types":"./dist/worker.d.ts","import":"./dist/worker.js"}},"scripts":{"build":"tsc","clean":"rm -rf dist"},"_npmUser":{"name":"navilan.puthir","email":"navilan@puthir.in"},"_resolved":"/private/var/folders/mm/7tvfnj1n4kjbgbjpd8rp3ypw0000gn/T/9d26bc0e5dbc4606071e8c2108eb5ed1/duct-ui-cloudflare-search-provider-0.8.3.tgz","_integrity":"sha512-825aoIudBF+07lMJyg4upuE9EsjQhp76S3rWI0UKihcTY4HGmzy3q/dygGS9foVK0mhUNdtO12VB3woSxDjY+A==","repository":{"url":"git+https://github.com/navilan/duct-ui.git","type":"git","directory":"packages/cloudflare-search-provider"},"_npmVersion":"10.9.2","description":"Cloudflare Worker search provider for Duct UI","directories":{},"_nodeVersion":"22.16.0","dependencies":{"commander":"^12.1.0","@duct-ui/search-core":"0.8.3"},"_hasShrinkwrap":false,"devDependencies":{"wrangler":"^4.32.0","typescript":"^5.9.2","@types/node":"^24.3.0","@cloudflare/workers-types":"^4.20250823.0"},"peerDependencies":{"wrangler":"^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/cloudflare-search-provider_0.8.3_1758281740273_0.21024540731439023","host":"s3://npm-registry-packages-npm-production"}},"0.8.4":{"name":"@duct-ui/cloudflare-search-provider","version":"0.8.4","description":"Cloudflare Worker search provider for Duct UI","type":"module","main":"dist/index.js","types":"dist/index.d.ts","bin":{"duct-cf-search":"dist/cli.js"},"exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"},"./worker":{"import":"./dist/worker.js","types":"./dist/worker.d.ts"}},"keywords":["duct-ui","search","cloudflare","worker"],"author":{"name":"navilan","email":"navilan@folds.in"},"license":"MIT","dependencies":{"commander":"^12.1.0","@duct-ui/search-core":"0.8.4"},"devDependencies":{"@cloudflare/workers-types":"^4.20250823.0","@types/node":"^24.3.0","typescript":"^5.9.2","wrangler":"^4.32.0"},"peerDependencies":{"wrangler":"^3.0.0"},"repository":{"type":"git","url":"git+https://github.com/navilan/duct-ui.git","directory":"packages/cloudflare-search-provider"},"scripts":{"build":"tsc","clean":"rm -rf dist"},"_id":"@duct-ui/cloudflare-search-provider@0.8.4","bugs":{"url":"https://github.com/navilan/duct-ui/issues"},"homepage":"https://github.com/navilan/duct-ui#readme","_integrity":"sha512-W3Sa0rMeb2uzmJs4UpC1CJIkwzpbgVdVw4YtrtjjzQScll9HXaxnGW8rH/nP6MgjYTNCfSsDeTNqnz79+Mmkiw==","_resolved":"/private/var/folders/mm/7tvfnj1n4kjbgbjpd8rp3ypw0000gn/T/921036980f397e37f3e907a242bc89b5/duct-ui-cloudflare-search-provider-0.8.4.tgz","_from":"file:duct-ui-cloudflare-search-provider-0.8.4.tgz","_nodeVersion":"22.16.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-W3Sa0rMeb2uzmJs4UpC1CJIkwzpbgVdVw4YtrtjjzQScll9HXaxnGW8rH/nP6MgjYTNCfSsDeTNqnz79+Mmkiw==","shasum":"49cb126d1e0074d90ae92a4235f4bd812e139370","tarball":"https://registry.npmjs.org/@duct-ui/cloudflare-search-provider/-/cloudflare-search-provider-0.8.4.tgz","fileCount":20,"unpackedSize":37372,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGhpqhdjzDL56lFRK8XV8GPoPUCKrclJ8T3JJgqBjiP2AiEA7wtQORqpNtPLDPFsEkphoUS+o64RqWP/BqJF8ytsPVU="}]},"_npmUser":{"name":"navilan.puthir","email":"navilan@puthir.in"},"directories":{},"maintainers":[{"name":"navilan.puthir","email":"navilan@puthir.in"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/cloudflare-search-provider_0.8.4_1758960526009_0.5412267763598533"},"_hasShrinkwrap":false}},"time":{"created":"2025-08-29T17:16:24.607Z","modified":"2025-09-27T08:08:46.382Z","0.8.0":"2025-08-29T17:16:24.886Z","0.8.1":"2025-08-30T10:15:08.622Z","0.8.2":"2025-08-30T13:49:48.796Z","0.8.3":"2025-09-19T11:35:40.461Z","0.8.4":"2025-09-27T08:08:46.193Z"},"bugs":{"url":"https://github.com/navilan/duct-ui/issues"},"author":{"name":"navilan","email":"navilan@folds.in"},"license":"MIT","homepage":"https://github.com/navilan/duct-ui#readme","keywords":["duct-ui","search","cloudflare","worker"],"repository":{"type":"git","url":"git+https://github.com/navilan/duct-ui.git","directory":"packages/cloudflare-search-provider"},"description":"Cloudflare Worker search provider for Duct UI","maintainers":[{"name":"navilan.puthir","email":"navilan@puthir.in"}],"readme":"# @duct-ui/cloudflare-search-provider\n\nServer-side search provider for Duct UI applications using Cloudflare Workers, KV, and R2 storage.\n\n## Features\n\n- **Server-side Search**: Offload search to Cloudflare Workers for better performance with large indexes\n- **Distributed Storage**: Uses KV for metadata and R2 for index storage\n- **REST API**: Simple HTTP API for search operations\n- **Index Management**: Support for syncing and appending search indexes\n- **CORS Support**: Built-in CORS headers for cross-origin requests\n- **Authentication**: Token-based authentication for index updates\n- **CLI Tool**: Built-in CLI for generating worker templates\n\n## Quick Start with CLI\n\nThe package includes a CLI tool to generate Cloudflare Worker templates:\n\n```bash\n# Generate worker files in ./worker directory\nnpx @duct-ui/cloudflare-search-provider init\n\n# Generate in custom directory\nnpx @duct-ui/cloudflare-search-provider init --output ./my-worker\n\n# Specify project name\nnpx @duct-ui/cloudflare-search-provider init --name my-search-app\n```\n\nThis generates:\n- `search-worker.template.ts` - Worker implementation with /api prefix support\n- `wrangler.toml.template` - Cloudflare configuration\n- `SEARCH-PROVIDER-README.md` - Complete integration guide\n\n## Installation\n\n```bash\nnpm install @duct-ui/cloudflare-search-provider\n# or\npnpm add @duct-ui/cloudflare-search-provider\n```\n\n## Setup\n\n### 1. Create Worker Configuration\n\nCreate `worker/wrangler.toml`:\n\n```toml\nname = \"search-worker\"\nmain = \"worker.ts\"\ncompatibility_date = \"2024-04-03\"\n\n# KV namespace for search metadata\n[[kv_namespaces]]\nbinding = \"SEARCH_METADATA\"\nid = \"search-metadata-kv\"\n\n# R2 bucket for search index storage\n[[r2_buckets]]\nbinding = \"SEARCH_INDEX\"\nbucket_name = \"search-index-bucket\"\n```\n\n### 2. Create Worker Entry Point\n\nCreate `worker/worker.ts`:\n\n```typescript\nimport { SearchWorkerHandler } from '@duct-ui/cloudflare-search-provider/worker'\n\nexport default {\n  async fetch(request, env) {\n    const url = new URL(request.url)\n    const pathname = url.pathname\n    \n    // Mount on /api prefix\n    if (pathname.startsWith('/api/')) {\n      const newUrl = new URL(request.url)\n      newUrl.pathname = pathname.substring(4) // Remove '/api'\n      const newRequest = new Request(newUrl, request)\n      \n      const handler = new SearchWorkerHandler(env)\n      return handler.handleRequest(newRequest)\n    }\n    \n    return new Response('Not Found', { status: 404 })\n  }\n}\n```\n\n### 3. Environment Variables\n\nCreate `.env` file for local development:\n\n```bash\nSEARCH_INDEX_AUTH_TOKEN=your-secure-token-here\n```\n\nFor production, set via Cloudflare dashboard or:\n```bash\nwrangler secret put SEARCH_INDEX_AUTH_TOKEN\n```\n\n### 4. Development\n\nAdd to `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"worker:dev\": \"wrangler dev -c worker/wrangler.toml --port 8788 --local\"\n  }\n}\n```\n\nRun the worker:\n```bash\nnpm run worker:dev\n```\n\n## Client Usage\n\n### Initialize Provider\n\n```typescript\nimport { CloudflareSearchProvider } from '@duct-ui/cloudflare-search-provider'\n\nconst searchProvider = new CloudflareSearchProvider()\n\n// Initialize the provider\nawait searchProvider.initialize({\n  workerUrl: 'http://localhost:8788/api', // or your production URL\n  timeout: 5000\n})\n```\n\n### Search\n\n```typescript\nconst results = await searchProvider.search('your search query', {\n  limit: 10,\n  offset: 0\n})\n\n// Results format:\n// [\n//   {\n//     url: '/page-url',\n//     title: 'Page Title',\n//     excerpt: 'Page excerpt...',\n//     score: 95\n//   }\n// ]\n```\n\n### With Fallback\n\n```typescript\nimport { CloudflareSearchProvider } from '@duct-ui/cloudflare-search-provider'\nimport { ClientSearchProvider } from '@duct-ui/client-search-provider'\n\nlet activeProvider\n\n// Try server-side search first\ntry {\n  const cloudflareProvider = new CloudflareSearchProvider()\n  await cloudflareProvider.initialize({ \n    workerUrl: '/api',\n    timeout: 5000\n  })\n  activeProvider = cloudflareProvider\n} catch (error) {\n  // Fallback to client-side search\n  const clientProvider = new ClientSearchProvider()\n  await clientProvider.initialize({ indexUrl: '/search-index.json' })\n  activeProvider = clientProvider\n}\n\n// Use the active provider\nconst results = await activeProvider.search(query)\n```\n\n## API Endpoints\n\n### GET /search/health\nCheck worker health and index status.\n\n**Response:**\n```json\n{\n  \"status\": \"healthy\",\n  \"indexSize\": 100,\n  \"lastUpdate\": 1234567890,\n  \"version\": \"1.0\"\n}\n```\n\n### GET /search/execute?q=query\nExecute a search query.\n\n**Parameters:**\n- `q` (required): Search query\n- `limit` (optional): Maximum results (default: 10)\n- `offset` (optional): Result offset for pagination\n\n**Response:**\n```json\n{\n  \"results\": [\n    {\n      \"url\": \"/page\",\n      \"title\": \"Page Title\",\n      \"excerpt\": \"Matching excerpt...\",\n      \"score\": 95\n    }\n  ]\n}\n```\n\n### GET /search/stats\nGet index statistics.\n\n**Response:**\n```json\n{\n  \"size\": 100,\n  \"lastUpdate\": 1234567890,\n  \"version\": \"1.0\",\n  \"indexSize\": 50000\n}\n```\n\n### POST /search/sync-index\nSync search index from a URL.\n\n**Headers:**\n- `Authorization: Bearer <token>`\n\n**Body (optional):**\n```json\n{\n  \"url\": \"https://example.com/search-index.json\"\n}\n```\n\nDefault URL: `/search-index.json`\n\n**Response:**\n```json\n{\n  \"success\": true,\n  \"entriesCount\": 100,\n  \"timestamp\": 1234567890,\n  \"indexSize\": 50000,\n  \"indexUrl\": \"https://example.com/search-index.json\"\n}\n```\n\n### POST /search/index\nAppend entries to the search index.\n\n**Headers:**\n- `Authorization: Bearer <token>`\n- `Content-Type: application/json`\n\n**Body:**\n```json\n{\n  \"entries\": [\n    {\n      \"url\": \"/page\",\n      \"title\": \"Page Title\",\n      \"description\": \"Page description\",\n      \"content\": \"Full page content\",\n      \"tags\": [\"tag1\", \"tag2\"],\n      \"keywords\": [\"keyword1\", \"keyword2\"]\n    }\n  ],\n  \"timestamp\": 1234567890,\n  \"version\": \"1.0\"\n}\n```\n\n**Response:**\n```json\n{\n  \"success\": true,\n  \"entriesCount\": 101,\n  \"newEntriesAdded\": 1,\n  \"timestamp\": 1234567890,\n  \"indexSize\": 51000\n}\n```\n\n## Index Management\n\n### Sync from Static Index\n\n```bash\n# Sync from default location (/search-index.json)\ncurl -X POST \"https://your-worker.workers.dev/api/search/sync-index\" \\\n  -H \"Authorization: Bearer your-token\"\n\n# Sync from custom URL\ncurl -X POST \"https://your-worker.workers.dev/api/search/sync-index\" \\\n  -H \"Authorization: Bearer your-token\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.com/custom-index.json\"}'\n```\n\n### Append New Entries\n\n```typescript\nconst config = {\n  authToken: 'your-secure-token',\n  workerUrl: 'https://your-worker.workers.dev/api'\n}\n\nawait searchProvider.appendIndex([\n  {\n    url: '/new-page',\n    title: 'New Page',\n    description: 'Description',\n    content: 'Page content',\n    tags: ['new'],\n    keywords: ['new', 'page']\n  }\n], config)\n```\n\n## Production Deployment\n\n### Deploy to Cloudflare Workers\n\n```bash\n# Deploy from your project root (TypeScript is compiled automatically by Wrangler)\nwrangler deploy -c worker/wrangler.toml\n\n# Or if you have a package.json script\nnpm run worker:deploy\n```\n\n**Note**: Wrangler automatically compiles TypeScript files. You don't need to compile `.ts` files to `.js` before deployment.\n\n### Configure Production Secrets\n\n```bash\nwrangler secret put SEARCH_INDEX_AUTH_TOKEN\n```\n\n### Use with Cloudflare Pages\n\nIn your Duct UI application:\n\n```typescript\nconst searchProvider = new CloudflareSearchProvider()\n\nawait searchProvider.initialize({\n  workerUrl: 'https://search-api.your-domain.workers.dev',\n  apiKey: process.env.SEARCH_API_KEY, // Optional additional security\n  timeout: 5000\n})\n```\n\n## Security Considerations\n\n1. **Authentication**: Always use secure tokens for index updates\n2. **CORS**: Configure allowed origins in production\n3. **Rate Limiting**: Consider adding rate limiting for public endpoints\n4. **Token Rotation**: Regularly rotate authentication tokens\n5. **HTTPS**: Always use HTTPS in production\n\n## Performance Tips\n\n1. **Index Size**: Keep indexes under 10MB for optimal performance\n2. **Caching**: Worker responses are cached at edge locations\n3. **Pagination**: Use limit/offset for large result sets\n4. **Fallback**: Implement client-side fallback for resilience\n\n## TypeScript Support\n\nFull TypeScript support with exported types:\n\n```typescript\nimport type {\n  CloudflareSearchConfig,\n  CloudflareIndexConfig\n} from '@duct-ui/cloudflare-search-provider'\n```\n\n## License\n\nMIT","readmeFilename":"README.md"}