[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-80393":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":13,"contributorsCount":13,"subscribersCount":13,"size":13,"stars1d":13,"stars7d":13,"stars30d":13,"stars90d":13,"forks30d":13,"starsTrendScore":13,"compositeScore":15,"rankGlobal":10,"rankLanguage":10,"license":16,"archived":17,"fork":17,"defaultBranch":18,"hasWiki":19,"hasPages":17,"topics":20,"createdAt":10,"pushedAt":10,"updatedAt":28,"readmeContent":29,"aiSummary":30,"trendingCount":13,"starSnapshotCount":13,"syncStatus":31,"lastSyncTime":32,"discoverSource":33},80393,"website-feedback-widget","Sendmux\u002Fwebsite-feedback-widget","Sendmux","📬 Drop-in feedback widget for websites & apps. Turn submissions into structured email & webhook data for AI agents. Framework-agnostic Web Component. Accessible, customisable, zero deps.","https:\u002F\u002Fsendmux.ai",null,"TypeScript",52,0,58,40,"MIT License",false,"main",true,[21,22,23,24,25,26,27],"ai-agents","customer-feedback","email","feedback-widget","javascript","saas","web-components","2026-06-12 04:01:28","\u003Cp align=\"center\">\n  \u003Cimg\n    src=\"https:\u002F\u002Fraw.githubusercontent.com\u002FSendmux\u002Fwebsite-feedback-widget\u002Fmain\u002F.github\u002Fassets\u002Fwidget-demo-clean.gif\"\n    alt=\"Animated Sendmux Feedback Widget flow showing category selection, compose, and success states\"\n    width=\"760\"\n  \u002F>\n\u003C\u002Fp>\n\n# Sendmux Feedback Widget\n\nOpen-source website and in-app feedback widget for collecting customer feedback, sending it to a webhook or secure Sendmux relay, and turning feedback email into agent-ready workflow input.\n\nSendmux is email infrastructure for AI agents: outbound sending, inbound agent mailboxes, APIs, webhooks, real-time mailbox events, tenant isolation, and usage-based billing from one control plane. This widget gives your product a small, accessible collection layer that can feed that email infrastructure.\n\n## ✨ Why Email-First Feedback\n\nFeedback is most useful when it enters a workflow, not a spreadsheet. Send each submission to a normal inbox, a Sendmux agent mailbox, or your own webhook, then let your downstream process triage it.\n\nOnce feedback arrives as email, your agent workflow can:\n\n- **Classify** issues, ideas, praise, and account-specific requests;\n- **Group duplicates** by URL, user, workspace, plan, or message content;\n- **Summarise threads** and route them to support, product, or engineering;\n- **Create or update GitHub issues** when the feedback matches your product plan;\n- **Keep a readable audit trail** in an inbox your team can inspect.\n\nThis repository does not ship the agent that reads email or creates GitHub issues. It ships the widget, payload contract, secure relay pattern, and playbook for building that workflow.\n\n## ⚡ Features\n\n- Drop-in custom element: `\u003Csendmux-feedback>`.\n- Works with package installs or a CDN bundle after release.\n- Sends JSON to your own endpoint, any webhook, or a server-side Sendmux relay.\n- Supports logged-in user context and metadata without exposing secrets.\n- Configurable position, brand colour, font family, label, heading, minimum message length, and powered-by link.\n- System font by default, with optional Google Font support if your site already uses one.\n- Accessible modal behaviour, labelled controls, keyboard support, visible focus states, dark mode, and reduced-motion support.\n- Shadow DOM styles to avoid clashing with host apps.\n- SSR-safe import for modern app frameworks.\n\n## 🚀 Install\n\n```bash\npnpm add @sendmux\u002Ffeedback-widget\n```\n\n```js\nimport \"@sendmux\u002Ffeedback-widget\";\n```\n\n```html\n\u003Csendmux-feedback endpoint=\"\u002Fapi\u002Ffeedback\" position=\"bottom-right\">\u003C\u002Fsendmux-feedback>\n```\n\nFor a CDN build after release:\n\n```html\n\u003Cscript src=\"https:\u002F\u002Funpkg.com\u002F@sendmux\u002Ffeedback-widget\u002Fdist\u002Fsendmux-feedback.iife.js\" defer>\u003C\u002Fscript>\n\u003Csendmux-feedback endpoint=\"\u002Fapi\u002Ffeedback\" position=\"bottom-right\">\u003C\u002Fsendmux-feedback>\n```\n\n## 🧩 Quick Start\n\nAdd the widget:\n\n```html\n\u003Csendmux-feedback\n  endpoint=\"\u002Fapi\u002Ffeedback\"\n  position=\"middle-right\"\n  brand-colour=\"oklch(0.556 0.19 264)\"\n>\u003C\u002Fsendmux-feedback>\n```\n\nOpen it from your own button:\n\n```html\n\u003Cbutton data-sendmux-feedback-button>Send feedback\u003C\u002Fbutton>\n```\n\nPass signed-in user context without exposing secrets:\n\n```html\n\u003Cscript>\n  window.sendmuxFeedback = {\n    config: {\n      endpoint: \"\u002Fapi\u002Ffeedback\",\n      position: \"middle-right\",\n      user: {\n        id: \"user_123\",\n        email: \"customer@example.com\",\n        name: \"Customer Name\"\n      },\n      metadata: {\n        account_id: \"acct_123\",\n        plan: \"pro\"\n      }\n    }\n  };\n\u003C\u002Fscript>\n\u003Cscript src=\"https:\u002F\u002Funpkg.com\u002F@sendmux\u002Ffeedback-widget\u002Fdist\u002Fsendmux-feedback.iife.js\" defer>\u003C\u002Fscript>\n```\n\n## 🔐 Sendmux Delivery\n\nDo not put a Sendmux API key in browser code. Keep the key on your server, receive the widget payload, validate it, and send the email from a server-only relay.\n\nYou can receive feedback in any inbox. A Sendmux mailbox is useful when you want a dedicated agent inbox with mailbox APIs, scoped credentials, webhooks, and real-time mailbox events, but it is not required.\n\nExample relay:\n\n```js\nexport async function POST(request) {\n  const feedback = await request.json();\n\n  if (!isValidFeedback(feedback)) {\n    return Response.json({ ok: false }, { status: 400 });\n  }\n\n  const response = await fetch(\"https:\u002F\u002Fsmtp.sendmux.ai\u002Fapi\u002Fv1\u002Femails\u002Fsend\", {\n    method: \"POST\",\n    headers: {\n      Authorization: `Bearer ${process.env.SENDMUX_API_KEY}`,\n      \"Content-Type\": \"application\u002Fjson\"\n    },\n    body: JSON.stringify({\n      from: { email: process.env.FEEDBACK_FROM_EMAIL, name: \"Product feedback\" },\n      to: { email: process.env.FEEDBACK_TO_EMAIL },\n      subject: `Product feedback: ${feedback.feedback_type}`,\n      text_body: [\n        feedback.message,\n        \"\",\n        `URL: ${feedback.url}`,\n        `Title: ${feedback.title}`,\n        `Submitted: ${feedback.timestamp}`,\n        `User: ${JSON.stringify(feedback.user ?? {})}`,\n        `Metadata: ${JSON.stringify(feedback.metadata ?? {})}`\n      ].join(\"\\n\"),\n      html_body: `\u003Cp>${escapeHtml(feedback.message)}\u003C\u002Fp>`\n    })\n  });\n\n  if (!response.ok) {\n    return Response.json({ ok: false }, { status: 502 });\n  }\n\n  return Response.json({ ok: true });\n}\n\nfunction isValidFeedback(feedback) {\n  return (\n    feedback &&\n    [\"issue\", \"idea\", \"praise\", \"feedback\"].includes(feedback.feedback_type) &&\n    typeof feedback.message === \"string\" &&\n    feedback.message.trim().length > 0 &&\n    feedback.message.length \u003C= 2000\n  );\n}\n\nfunction escapeHtml(value) {\n  return value.replace(\u002F[&\u003C>\"']\u002Fg, (char) => {\n    return {\n      \"&\": \"&amp;\",\n      \"\u003C\": \"&lt;\",\n      \">\": \"&gt;\",\n      '\"': \"&quot;\",\n      \"'\": \"&#039;\"\n    }[char];\n  });\n}\n```\n\nEnvironment variables:\n\n```bash\nSENDMUX_API_KEY=smx_...\nFEEDBACK_FROM_EMAIL=feedback@yourdomain.example\nFEEDBACK_TO_EMAIL=feedback-agent@yourdomain.example\n```\n\nCreate the API key in your Sendmux team and keep it server-only. Create a Sendmux mailbox if you want feedback to land in an agent inbox, or point `FEEDBACK_TO_EMAIL` at any address your team already uses.\n\n## 🪝 Webhook Mode\n\nSet `endpoint` to any webhook URL that accepts JSON:\n\n```html\n\u003Csendmux-feedback endpoint=\"https:\u002F\u002Fexample.com\u002Fwebhooks\u002Ffeedback\">\u003C\u002Fsendmux-feedback>\n```\n\nPayload:\n\n```json\n{\n  \"feedback_type\": \"issue\",\n  \"message\": \"The export button failed.\",\n  \"url\": \"https:\u002F\u002Fapp.example.com\u002Fsettings\",\n  \"title\": \"Settings\",\n  \"timestamp\": \"2026-05-25T06:38:00.000Z\",\n  \"user\": {},\n  \"metadata\": {}\n}\n```\n\n`feedback_type` is one of `issue`, `idea`, `praise`, or `feedback`.\n\n## ⚙️ Options\n\n| Option | Attribute | Default |\n| --- | --- | --- |\n| `endpoint` | `endpoint` | `\"\"` |\n| `position` | `position` | `bottom-right` |\n| `brandColor` | `brand-color` \u002F `brand-colour` | `oklch(0.556 0.19 264)` |\n| `fontFamily` | `font-family` | system font |\n| `poweredBy` | `powered-by` | `true` |\n| `buttonLabel` | `button-label` | `Feedback` |\n| `title` | `heading` | `Send feedback` |\n| `minMessageLength` | `min-message-length` | `1` |\n\nCanonical JavaScript positions: `center`, `top-left`, `top-center`, `top-right`, `middle-left`, `middle-right`, `bottom-left`, `bottom-center`, `bottom-right`.\n\nHTML attributes also accept compatibility aliases and normalise them at runtime: `centre`, `middle`, `middle-centre`, `top-centre`, `top-middle`, `left-middle`, `right-middle`, `bottom-centre`, `bottom-middle`. Use `brandColor` in JavaScript config; `brand-colour` and legacy JavaScript `brandColour` are accepted only as compatibility aliases.\n\nTo use a Google Font, load it in your page and set `font-family`:\n\n```html\n\u003Clink rel=\"stylesheet\" href=\"https:\u002F\u002Ffonts.googleapis.com\u002Fcss2?family=Nunito:wght@400;700&display=swap\">\n\u003Csendmux-feedback font-family=\"'Nunito', system-ui, sans-serif\">\u003C\u002Fsendmux-feedback>\n```\n\nDisable the powered-by link:\n\n```html\n\u003Csendmux-feedback powered-by=\"false\">\u003C\u002Fsendmux-feedback>\n```\n\n## 🤖 AI Agent Playbook\n\nUse this prompt for an AI agent adding the widget to an app:\n\n```text\nAdd Sendmux Feedback Widget using a secure server relay.\n\nRules:\n- Install `@sendmux\u002Ffeedback-widget` and import it once in the browser entrypoint.\n- Add `\u003Csendmux-feedback endpoint=\"\u002Fapi\u002Ffeedback\" position=\"middle-right\">\u003C\u002Fsendmux-feedback>`.\n- Pass only non-secret user context through `window.sendmuxFeedback.config.user`.\n- Add useful metadata such as account, workspace, plan, route, or feature flag state.\n- Create `POST \u002Fapi\u002Ffeedback` server-side.\n- Validate the payload, cap message length, and rate-limit the endpoint.\n- Store `SENDMUX_API_KEY`, `FEEDBACK_FROM_EMAIL`, and `FEEDBACK_TO_EMAIL` as server-only environment variables.\n- The browser must never receive or render the Sendmux API key.\n- The relay sends feedback through `POST https:\u002F\u002Fsmtp.sendmux.ai\u002Fapi\u002Fv1\u002Femails\u002Fsend`.\n- Route feedback to a Sendmux mailbox if an email-reading agent will triage it later.\n- Return generic success or failure JSON to the widget.\n- Do not claim email triage or GitHub issue creation exists unless that backend workflow has been built.\n```\n\n## 🛡️ Security Checklist\n\n- Keep Sendmux API keys on the server.\n- Validate `feedback_type`, `message`, URL fields, and maximum message length before sending.\n- Rate-limit by signed-in user, team, or IP address.\n- Keep CORS same-origin unless you intentionally support another origin.\n- Escape HTML before putting user content into `html_body`.\n- Return generic errors to the browser and log details server-side.\n- If your site has a strict Content Security Policy, self-host the bundle and allow only your feedback endpoint in `connect-src`.\n\n## ♿ Accessibility And Compatibility\n\n- Uses a native dialog with a non-modal fallback for older browser environments.\n- Supports keyboard open, submit, Escape close, and visible focus states.\n- Uses labelled controls, `role=\"alert\"` for errors, and `role=\"status\"` for success.\n- Respects `prefers-reduced-motion` and light\u002Fdark colour schemes.\n- Uses safe-area-aware fixed positioning for mobile devices.\n- Uses CSS fallbacks before newer colour and viewport features.\n- Uses Shadow DOM to keep widget styles isolated from host pages.\n\n## 🛠️ Development\n\n```bash\npnpm install\npnpm dev\npnpm typecheck\npnpm test\npnpm test:e2e\npnpm build\n```\n\n## 📦 Release\n\nReleases are tag-driven through GitHub Actions.\n\n1. Update `package.json` version and `CHANGELOG.md`.\n2. Run `pnpm typecheck`, `pnpm test`, `pnpm build`, `pnpm test:e2e`, and `npm pack --dry-run`.\n3. Commit manually with `chore: release vX.Y.Z`.\n4. Create and push a matching tag, such as `v0.1.0`.\n5. CI verifies the tag, builds the package, publishes to npm, and creates the GitHub Release.\n\nFor the first npm publish, add a temporary GitHub Actions secret named `NPM_TOKEN`. After `@sendmux\u002Ffeedback-widget` exists on npm, configure npm Trusted Publishing with workflow filename `publish.yml` and remove the token.\n\nIf this saves you time, star the repo and share how you are routing feedback into your own agent workflows.\n\n\u003Cp align=\"center\">\n  \u003Cpicture>\n    \u003Csource\n      media=\"(prefers-color-scheme: dark)\"\n      srcset=\"https:\u002F\u002Fraw.githubusercontent.com\u002FSendmux\u002Fwebsite-feedback-widget\u002Fmain\u002F.github\u002Fassets\u002Flogo-dark.svg\"\n    \u002F>\n    \u003Csource\n      media=\"(prefers-color-scheme: light)\"\n      srcset=\"https:\u002F\u002Fraw.githubusercontent.com\u002FSendmux\u002Fwebsite-feedback-widget\u002Fmain\u002F.github\u002Fassets\u002Flogo-light.svg\"\n    \u002F>\n    \u003Cimg\n      width=\"320\"\n      alt=\"Sendmux\"\n      src=\"https:\u002F\u002Fraw.githubusercontent.com\u002FSendmux\u002Fwebsite-feedback-widget\u002Fmain\u002F.github\u002Fassets\u002Flogo-light.svg\"\n    \u002F>\n  \u003C\u002Fpicture>\n\u003C\u002Fp>\n","Sendmux Feedback Widget 是一个用于网站和应用程序的反馈收集小部件，能够将用户提交的信息转化为结构化的电子邮件和Webhook数据，以便AI代理处理。其核心功能包括易于集成的Web组件、支持自定义样式与位置、以及无需额外依赖即可实现无障碍访问。通过配置，该小部件可以向指定邮箱或Webhook发送JSON格式的数据，并支持登录用户的上下文信息传递而不暴露敏感信息。适用于需要快速搭建客户反馈渠道且希望利用现有邮件基础设施进行问题分类、汇总及自动处理的各种在线服务场景中。",2,"2026-06-11 04:00:36","CREATED_QUERY"]