{"_id":"@aifindr/agent-widget","_rev":"3-8f6505b61693039ffbcae704b2d5302c","name":"@aifindr/agent-widget","dist-tags":{"latest":"0.0.3"},"versions":{"0.0.1":{"name":"@aifindr/agent-widget","version":"0.0.1","keywords":["aifindr","widget","commerce","iframe","postMessage"],"author":{"name":"AIFindr"},"license":"Apache-2.0","_id":"@aifindr/agent-widget@0.0.1","maintainers":[{"name":"javiertoledo","email":"javier@booster.cloud"}],"homepage":"https://github.com/aifindr/agent-widget#readme","bugs":{"url":"https://github.com/aifindr/agent-widget/issues"},"dist":{"shasum":"14936b1d3cf7e92f058c35c9a7241279d463eefa","tarball":"https://registry.npmjs.org/@aifindr/agent-widget/-/agent-widget-0.0.1.tgz","fileCount":32,"integrity":"sha512-u3Tu02tRbXHyzII4La76QlFAwio7cjgfCb024F3w7nAUzjYlaWGwubQrv3K1MwfGRW6mdR87R1GoxICv+l5TVA==","signatures":[{"sig":"MEUCIQD8a0vC489n6yTePsqrktS+Fw8bgNTVabIRN+Z3CN20gAIgJpMj3Z2GUFZgmyF2ogTQBniP0EMGU91gtscSdfO2ISE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":4972189},"main":"dist/embed/widget.cjs","type":"module","types":"dist/embed/widget.d.ts","module":"dist/embed/widget.esm.js","exports":{".":{"types":"./dist/embed/widget.d.ts","import":"./dist/embed/widget.esm.js","default":"./dist/embed/widget.iife.js","require":"./dist/embed/widget.cjs"},"./dist/*":"./dist/*","./iframe":{"types":"./dist/iframe/client.d.ts","import":"./dist/iframe/client.esm.js","require":"./dist/iframe/client.cjs"}},"gitHead":"9dfe8c9dfb732a3b2148888194edd7d07c47a0ba","scripts":{"dev":"vite --config vite.config.ts","build":"tsup && node scripts/copy-demo.mjs","clean":"rm -rf dist","prepublishOnly":"npm run clean && npm run build"},"_npmUser":{"name":"javiertoledo","email":"javier@booster.cloud"},"repository":{"url":"git+https://github.com/aifindr/agent-widget.git","type":"git"},"_npmVersion":"10.9.3","description":"Embeddable AIFindr Agent Widget and iframe bridge.","directories":{},"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^7.2.0","vite":"^5.2.11","typescript":"^5.4.3"},"_npmOperationalInternal":{"tmp":"tmp/agent-widget_0.0.1_1760559898715_0.5858223832923903","host":"s3://npm-registry-packages-npm-production"}},"0.0.3":{"name":"@aifindr/agent-widget","version":"0.0.3","description":"Embeddable AIFindr Agent Widget and iframe bridge.","license":"Apache-2.0","type":"module","repository":{"type":"git","url":"git+https://github.com/aifindr/agent-widget.git"},"homepage":"https://github.com/aifindr/agent-widget#readme","bugs":{"url":"https://github.com/aifindr/agent-widget/issues"},"publishConfig":{"access":"public"},"main":"dist/embed/widget.cjs","module":"dist/embed/widget.esm.js","types":"dist/embed/widget.d.ts","exports":{".":{"import":"./dist/embed/widget.esm.js","require":"./dist/embed/widget.cjs","default":"./dist/embed/widget.iife.js","types":"./dist/embed/widget.d.ts"},"./iframe":{"import":"./dist/iframe/client.esm.js","require":"./dist/iframe/client.cjs","types":"./dist/iframe/client.d.ts"},"./dist/*":"./dist/*"},"scripts":{"build":"tsup && vite build && node scripts/copy-demo.mjs","clean":"rm -rf dist","dev":"vite --config vite.config.ts","prepublishOnly":"npm run clean && npm run build"},"keywords":["aifindr","widget","commerce","iframe","postMessage"],"author":{"name":"AIFindr"},"devDependencies":{"tsup":"^7.2.0","typescript":"^5.4.3","vite":"^5.2.11"},"_id":"@aifindr/agent-widget@0.0.3","gitHead":"99312ec36baafb83de8051a9398331b639583e03","_nodeVersion":"20.19.5","_npmVersion":"10.8.2","dist":{"integrity":"sha512-KXD9CA+k1mSVJu15zhOxDxwNKyDfKXDVA232dqyvt77z6SQ1HfWyxNsXMEUDiIXepa8tSw0RMQz0ctJoIGNNvQ==","shasum":"95bc962a0abf2120b657f3213d44c8f0d9fc888e","tarball":"https://registry.npmjs.org/@aifindr/agent-widget/-/agent-widget-0.0.3.tgz","fileCount":32,"unpackedSize":4982928,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIALzDtvP1PB9/dstAukRhh6EGnZX8Bu7pohB9l0Qut+7AiEAwhB2QgoEvJ5qx01kbjaUk3po5wilfTORWFabM+eVbc4="}]},"_npmUser":{"name":"javiertoledo","email":"javier@booster.cloud"},"directories":{},"maintainers":[{"name":"javiertoledo","email":"javier@booster.cloud"},{"name":"jfsagasti","email":"juan@theagilemonkeys.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/agent-widget_0.0.3_1761169603736_0.49541458305755737"},"_hasShrinkwrap":false}},"time":{"created":"2025-10-15T20:24:58.555Z","modified":"2025-10-22T21:46:44.267Z","0.0.1":"2025-10-15T20:24:58.963Z","0.0.3":"2025-10-22T21:46:44.024Z"},"bugs":{"url":"https://github.com/aifindr/agent-widget/issues"},"author":{"name":"AIFindr"},"license":"Apache-2.0","homepage":"https://github.com/aifindr/agent-widget#readme","keywords":["aifindr","widget","commerce","iframe","postMessage"],"repository":{"type":"git","url":"git+https://github.com/aifindr/agent-widget.git"},"description":"Embeddable AIFindr Agent Widget and iframe bridge.","maintainers":[{"name":"javiertoledo","email":"javier@booster.cloud"},{"name":"jfsagasti","email":"juan@theagilemonkeys.com"}],"readme":"# AIFindr Agent Widget\n\nEmbeddable JavaScript widget that renders the AIFindr conversational agent experience inside any website and a companion iframe client to integrate the widget UI. The package supports both static script distribution for simple website integration and npm package distribution for modern build tools.\n\n## Distribution Methods\n\nThis package provides two integration approaches:\n\n### 1. Static Distribution (CDN/Script Tag)\n\nUse prebuilt JavaScript files for direct integration into any website without a build system.\n\n### 2. npm Package Distribution\n\nInstall via npm/pnpm for projects using modern bundlers (Vite, Webpack, etc.).\n\n```bash\nnpm install @aifindr/agent-widget\n# or\npnpm add @aifindr/agent-widget\n```\n\n## Build Artifacts\n\nAfter `npm run build` the following distributables are generated:\n\n- `dist/embed/widget.iife.js` – browser-ready bundle exposing the global `AIFindrCommerceWidget`\n- `dist/embed/widget.esm.js` / `widget.cjs` – module builds for bundlers or CommonJS environments\n- `dist/iframe/client.esm.js` / `client.cjs` – iframe-side bridge for the hosted widget UI\n- Type definitions are emitted next to each build (`.d.ts`)\n\n---\n\n## Host Page Integration (Embedding the Widget)\n\nThe host page is where you want the widget to appear. Choose the integration method that fits your project:\n\n### Option A: Static Script Integration (No Build Tools)\n\nInclude the CDN bundle on the page where the widget must appear, then instantiate the widget once the DOM is ready:\n\n```html\n<!-- Load from your CDN bucket -->\n<script src=\"/path/to/widget.iife.js\" data-client-id=\"TU_CLIENT_ID\" defer></script>\n<script>\n  window.addEventListener('DOMContentLoaded', () => {\n    const widget = new AIFindrCommerceWidget({\n      renderTo: '#aifindr-widget-container',\n      clientId: 'TU_CLIENT_ID',\n      baseUrl: 'https://client.aifindrcommerce.ai/widget.html'\n    });\n\n    widget\n      .ready(() => console.log('Widget ready!'))\n      .on(AIFindrCommerceWidget.EVENTS.PRODUCT_SELECTED, (data) => {\n        console.log('Product selected:', data.productId);\n      });\n  });\n</script>\n```\n\n### Option B: npm Package Integration (With Build Tools)\n\nInstall the package and import it in your JavaScript/TypeScript project:\n\n```typescript\nimport AIFindrCommerceWidget from '@aifindr/agent-widget';\n\n// Initialize the widget\nconst widget = new AIFindrCommerceWidget({\n  renderTo: '#aifindr-widget-container',\n  clientId: 'YOUR_CLIENT_ID',\n  baseUrl: 'https://client.aifindrcommerce.ai/widget.html',\n  context: { /* optional initial context */ }\n});\n\n// Listen to events\nwidget.ready(() => {\n  console.log('Widget ready!');\n});\n\nwidget.on(AIFindrCommerceWidget.EVENTS.PRODUCT_SELECTED, (data) => {\n  console.log('Product selected:', data.productId);\n});\n\nwidget.on(AIFindrCommerceWidget.EVENTS.MESSAGE_SENT, (data) => {\n  console.log('Message sent:', data.message);\n});\n\n// Cleanup when done\n// widget.destroy();\n```\n\n### Widget API Overview\n\n- `new AIFindrCommerceWidget(options)` – renders the iframe inside `options.renderTo`\n  - `renderTo` *(string | HTMLElement)* – CSS selector or element that will host the iframe\n  - `clientId` *(string)* – AIFindr Commerce client id\n  - `baseUrl` *(string)* – URL of the iframe application; the widget appends `?client_id=…&handshake=…`\n  - `context` *(object, optional)* – initial contextual data propagated to the iframe\n- `widget.ready(callback?)` – returns a promise or accepts a callback triggered after the iframe handshake completes\n- `widget.isReady()` – boolean flag for the handshake state\n- `widget.on(event, listener)` / `widget.off(event, listener)` – subscribe/unsubscribe to widget lifecycle & commerce events\n- `widget.destroy()` – dispose the widget instance and remove the iframe\n\nAll available event names are exposed through `AIFindrCommerceWidget.EVENTS`:\n\n| Event | Description |\n|-------|-------------|\n| `widget.ready` | Widget initialised and handshake completed |\n| `widget.error` | An error was reported by the iframe |\n| `conversation.started` | New conversation initiated |\n| `message.sent` | User sent a message |\n| `message.received` | AI reply received |\n| `commerce.product.selected` | Product selected inside the conversation |\n| `commerce.product.cta` | Product CTA triggered |\n\n---\n\n## Iframe Application Integration (Widget UI)\n\nThe iframe application is the actual widget UI that runs inside the iframe. This is where you build your conversational agent interface. Choose the integration method that fits your project:\n\n### Option A: Static Script Integration (No Build Tools)\n\nLoad the client bundle from your CDN and use it as an ES module:\n\n```html\n<script type=\"module\">\n  import AIFindrCommerceWidgetClient from '/assets/iframe/client.esm.js';\n\n  const client = new AIFindrCommerceWidgetClient();\n\n  client.ready(() => {\n    console.log('Client ready! Initial context:', client.getContext());\n    console.log('Client ID:', client.getClientId());\n  });\n\n  // Emit events to the host page\n  function sendMessage(content) {\n    client.emitEvent(AIFindrCommerceWidgetClient.EVENTS.MESSAGE_SENT, {\n      message: content,\n      timestamp: Date.now()\n    });\n  }\n\n  function selectProduct(productId) {\n    client.emitEvent(AIFindrCommerceWidgetClient.EVENTS.PRODUCT_SELECTED, {\n      productId,\n      timestamp: Date.now()\n    });\n  }\n</script>\n```\n\n### Option B: npm Package Integration (With Build Tools)\n\nInstall the package and import the iframe client in your project:\n\n```typescript\nimport AIFindrCommerceWidgetClient from '@aifindr/agent-widget/iframe';\n\nconst client = new AIFindrCommerceWidgetClient();\n\nclient.ready(() => {\n  console.log('Client ready! Initial context:', client.getContext());\n  console.log('Client ID:', client.getClientId());\n});\n\n// Emit events to the host page\nexport function sendMessage(content: string) {\n  client.emitEvent(AIFindrCommerceWidgetClient.EVENTS.MESSAGE_SENT, {\n    message: content,\n    timestamp: Date.now()\n  });\n}\n\nexport function selectProduct(productId: string) {\n  client.emitEvent(AIFindrCommerceWidgetClient.EVENTS.PRODUCT_SELECTED, {\n    productId,\n    timestamp: Date.now()\n  });\n}\n\n// Handle errors\nexport function reportError(error: Error) {\n  client.emitError(error);\n}\n```\n\n### Client API Overview\n\nThe client library handles the handshake protocol, validates the origin, and relays events back to the host. It exposes these methods:\n\n- `client.getClientId()` – fetch the client id provided by the embed script\n- `client.getContext()` – get the current context payload\n- `client.emitEvent(event, data)` – send events to the host page\n- `client.emitError(error)` – report recoverable or fatal errors back to the host page\n- `client.ready(callback?)` – returns a promise or accepts a callback triggered after handshake completes\n- `client.destroy()` – detach listeners if the iframe app tears down\n\n---\n\n## Usage Examples\n\n### Example: Using in a React Application\n\nIf you're building your iframe application with React, here's how to use the plain JavaScript client library:\n\n```tsx\nimport { useEffect, useRef, useState } from 'react';\nimport AIFindrCommerceWidgetClient from '@aifindr/agent-widget/iframe';\n\nfunction App() {\n  const clientRef = useRef<AIFindrCommerceWidgetClient | null>(null);\n  const [context, setContext] = useState<any>(null);\n  const [isReady, setIsReady] = useState(false);\n\n  useEffect(() => {\n    // Initialize the client\n    const client = new AIFindrCommerceWidgetClient();\n    clientRef.current = client;\n\n    client.ready(() => {\n      console.log('Client ready');\n      setIsReady(true);\n      setContext(client.getContext());\n    });\n\n    // Cleanup on unmount\n    return () => {\n      client.destroy();\n    };\n  }, []);\n\n  const handleProductSelected = (productId: string) => {\n    if (clientRef.current) {\n      clientRef.current.emitEvent(\n        AIFindrCommerceWidgetClient.EVENTS.PRODUCT_SELECTED,\n        { productId, timestamp: Date.now() }\n      );\n    }\n  };\n\n  const handleSendMessage = (message: string) => {\n    if (clientRef.current) {\n      clientRef.current.emitEvent(\n        AIFindrCommerceWidgetClient.EVENTS.MESSAGE_SENT,\n        { message, timestamp: Date.now() }\n      );\n    }\n  };\n\n  if (!isReady) {\n    return <div>Loading...</div>;\n  }\n\n  return (\n    <div>\n      <h1>AIFindr Widget (clientId: {clientRef.current?.getClientId()})</h1>\n      {/* Your React components here */}\n    </div>\n  );\n}\n\nexport default App;\n```\n\n### Example: Custom React Hook\n\nFor better reusability, you can create a custom hook:\n\n```tsx\nimport { useEffect, useRef, useState } from 'react';\nimport AIFindrCommerceWidgetClient from '@aifindr/agent-widget/iframe';\n\nexport function useAIFindrClient() {\n  const clientRef = useRef<AIFindrCommerceWidgetClient | null>(null);\n  const [isReady, setIsReady] = useState(false);\n  const [context, setContext] = useState<any>(null);\n\n  useEffect(() => {\n    const client = new AIFindrCommerceWidgetClient();\n    clientRef.current = client;\n\n    client.ready(() => {\n      setIsReady(true);\n      setContext(client.getContext());\n    });\n\n    return () => {\n      client.destroy();\n    };\n  }, []);\n\n  const emitEvent = (event: string, data: any) => {\n    if (clientRef.current && isReady) {\n      clientRef.current.emitEvent(event, data);\n    }\n  };\n\n  const emitError = (error: Error) => {\n    if (clientRef.current) {\n      clientRef.current.emitError(error);\n    }\n  };\n\n  return {\n    client: clientRef.current,\n    isReady,\n    context,\n    clientId: clientRef.current?.getClientId(),\n    emitEvent,\n    emitError,\n  };\n}\n\n// Usage in a component:\nfunction ProductCard({ product }) {\n  const { emitEvent, isReady } = useAIFindrClient();\n\n  const handleClick = () => {\n    if (isReady) {\n      emitEvent(AIFindrCommerceWidgetClient.EVENTS.PRODUCT_SELECTED, {\n        productId: product.id,\n        timestamp: Date.now(),\n      });\n    }\n  };\n\n  return <button onClick={handleClick}>Select Product</button>;\n}\n```\n\n---\n\n## Development Workflow\n\n```bash\nnpm install\nnpm run build      # generates dist/ bundles and type definitions\n# During local iteration with demo pages\nnpm run dev        # abre http://localhost:5173 con el flujo host/iframe\n```\n\nFor local iteration, point a static server at `/dist/embed/widget.iife.js` for the host page and `/dist/iframe/client.esm.js` for the iframe UI. All assets are pure ES2019 JavaScript and require no runtime dependencies.\n\n## Interactive Demo\n\nEjecuta `npm run dev` para arrancar un servidor Vite que expone dos páginas:\n\n- `/index.html` – página host que renderiza el widget dentro del contenedor `#aifindr-widget-container` y muestra los eventos recibidos en tiempo real.\n- `/content.html` – página que simula la interfaz del widget dentro del iframe. Contiene tarjetas de productos con CTAs que disparan los eventos `commerce.product.selected` y `commerce.product.cta`. Todas las acciones muestran `alert()` para visualizar el flujo.\n\nEl host escucha los eventos publicados mediante `postMessage`. El iframe, implementado con `AIFindrCommerceWidgetClient`, emite esos eventos cuando el usuario interactúa con la UI de muestra.\n\n## CI/CD & Publishing\n\n### Automated Workflows\n\nThis repository includes GitHub Actions workflows for continuous integration and automated publishing:\n\n#### PR Check Workflow\nEvery pull request automatically runs:\n- Clean build verification (`npm run clean && npm run build`)\n- Build artifact validation (ensures all expected files are generated)\n- Package validity check (`npm pack --dry-run`)\n\nThis ensures that no PR can be merged if it would cause publishing issues.\n\n#### Automated npm Publishing\nWhen code is merged to `main`, the package is automatically published to npm with:\n\n**Semantic Versioning (Conventional Commits):**\n- Commits starting with `major:` or `breaking:` trigger a **major** version bump (1.0.0 → 2.0.0)\n- Commits starting with `feat:`, `feature:`, or `minor:` trigger a **minor** version bump (1.0.0 → 1.1.0)\n- All other commits trigger a **patch** version bump (1.0.0 → 1.0.1)\n\n**Manual Publishing:**\nYou can also trigger a release manually from the Actions tab with your choice of version bump type.\n\n**What happens automatically:**\n1. Version bump in package.json based on commit messages\n2. Git tag creation (e.g., `v1.2.3`)\n3. GitHub Release with auto-generated changelog\n4. npm package publication\n5. Summary with links to npm and GitHub release\n\n### How to Trigger a Release\n\nTo publish a new version to npm and GitHub, follow these steps:\n\n#### 1. Create your feature branch and make changes\n\n```bash\ngit checkout -b feature/your-feature-name\n# Make your changes...\ngit add .\n```\n\n#### 2. Commit with the appropriate prefix\n\nUse conventional commit prefixes to control the version bump:\n\n**For Patch Release (1.0.0 → 1.0.1)** - Bug fixes, documentation, chores:\n\n```bash\ngit commit -m \"fix: resolve iframe handshake timeout issue\"\ngit commit -m \"docs: update integration examples\"\ngit commit -m \"chore: update dependencies\"\ngit commit -m \"style: improve code formatting\"\n```\n\n**For Minor Release (1.0.0 → 1.1.0)** - New features (backwards-compatible):\n\n```bash\ngit commit -m \"feat: add support for custom event handlers\"\ngit commit -m \"feature: implement lazy loading for iframe\"\ngit commit -m \"minor: add new widget configuration option\"\n```\n\n**For Major Release (1.0.0 → 2.0.0)** - Breaking changes:\n\n```bash\ngit commit -m \"breaking: change widget initialization API signature\"\ngit commit -m \"major: remove deprecated methods from client API\"\ngit commit -m \"breaking: require clientId parameter in constructor\"\n```\n\n#### 3. Create a Pull Request\n\n```bash\ngit push origin feature/your-feature-name\n```\n\nOpen a PR on GitHub. The PR checks will automatically verify that your changes build correctly.\n\n#### 4. Merge to main\n\nOnce approved and merged to `main`, the publish workflow will automatically:\n- Detect the version bump type from your commit message\n- Bump the version in package.json\n- Build the project\n- Create a git tag (e.g., `v1.2.3`)\n- Generate a changelog from commits\n- Create a GitHub Release\n- Publish to npm\n\n#### 5. Verify the Release\n\nAfter the workflow completes, verify:\n- **npm package**: https://www.npmjs.com/package/@aifindr/agent-widget\n- **GitHub Release**: Check the Releases page for the new version\n\n### Examples\n\n**Example 1: Bug fix for patch release**\n```bash\ngit checkout -b fix/event-listener-memory-leak\n# Fix the memory leak...\ngit add .\ngit commit -m \"fix: prevent memory leak in event listener cleanup\"\ngit push origin fix/event-listener-memory-leak\n# Create PR, merge to main → triggers 1.0.0 → 1.0.1\n```\n\n**Example 2: New feature for minor release**\n```bash\ngit checkout -b feature/custom-styles\n# Add custom styling support...\ngit add .\ngit commit -m \"feat: add customStyles option to widget configuration\"\ngit push origin feature/custom-styles\n# Create PR, merge to main → triggers 1.0.1 → 1.1.0\n```\n\n**Example 3: Breaking change for major release**\n```bash\ngit checkout -b breaking/new-init-api\n# Refactor initialization API...\ngit add .\ngit commit -m \"breaking: replace options object with required parameters\n\nBREAKING CHANGE: Widget constructor now requires clientId and baseUrl\nas separate parameters instead of an options object.\"\ngit push origin breaking/new-init-api\n# Create PR, merge to main → triggers 1.1.0 → 2.0.0\n```\n\n**Example 4: Multiple commits in one PR**\n\nIf your PR has multiple commits, the workflow will use the **first non-release commit** to determine the version bump:\n\n```bash\ngit checkout -b feature/accessibility-improvements\ngit commit -m \"feat: add ARIA labels to widget controls\"\ngit commit -m \"fix: improve keyboard navigation\"\ngit commit -m \"docs: update accessibility section in README\"\n# The \"feat:\" commit determines the bump → minor release\n```\n\n### Manual Release Trigger\n\nTo manually trigger a release without merging to `main`:\n\n1. Go to the **Actions** tab in GitHub\n2. Select the **\"Publish to npm\"** workflow\n3. Click **\"Run workflow\"**\n4. Choose the branch (usually `main`)\n5. Select the release type: `patch`, `minor`, or `major`\n6. Click **\"Run workflow\"**\n\nThis is useful for hotfixes or when you need to override the automatic version detection.\n\n### Setup Requirements\n\nTo enable automated publishing, configure the npm token secret in your GitHub repository:\n\n1. **NPM_TOKEN**: Create a personal automation token\n   - Go to https://www.npmjs.com/settings/YOUR_USERNAME/tokens\n   - Click \"Generate New Token\" → Select **\"Automation\"** type\n   - Copy the token\n   - Add it to GitHub: Repository Settings → Secrets and variables → Actions → New repository secret\n   - Name: `NPM_TOKEN`, Value: (paste token)\n\n**Important:** The token must be created by a user who is a member of the **theagilemonkeys** organization with publish permissions. The token will inherit your organization member permissions, allowing it to publish packages to the `@aifindr` scope.\n\nThe workflow uses GitHub's built-in `GITHUB_TOKEN` for creating releases and tags.\n\n## License\n\nApache-2.0\n\nCopyright 2025 The Agile Monkeys Inc.\n","readmeFilename":"README.md"}