-
Notifications
You must be signed in to change notification settings - Fork 1
Created chatbot widgets UI and modified CORS policy #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds CORS preflight handling, host-based allowlist, and standardized JSON responses to the chatbot prompt API; extends the Chatbot DB query and replaces in-file OpenRouter usage with an axios-based call; introduces a new embed-widget (React + TypeScript + Vite) as an embeddable chat widget; removes the Assistants page and a Home page test file. Changes
Sequence Diagram(s)sequenceDiagram
participant Browser
participant OPTIONS as OPTIONS Handler
participant POST as POST Handler
participant DB as Database
participant OpenRouter as OpenRouter API
Note over Browser,OPTIONS: CORS preflight
Browser->>OPTIONS: OPTIONS /api/chatbots/[id]/prompt (Origin)
OPTIONS->>OPTIONS: Validate origin, set CORS headers
alt Origin allowed
OPTIONS->>Browser: 204 + CORS headers
else Origin not allowed
OPTIONS->>Browser: 204 + CORS headers (no allow-origin)
end
Note over Browser,POST: Chat message flow
Browser->>POST: POST /api/chatbots/[id]/prompt (body incl. conversation_id)
POST->>DB: Fetch chatbot (personality, Users, allowed_domains)
POST->>POST: Parse origin -> requestHostname -> check allowlist
alt Origin not allowed
POST->>Browser: 403 JSON (createResponse)
else Origin allowed
POST->>OpenRouter: axios POST (body, headers: Authorization, Content-Type, Referer, X-Title)
OpenRouter-->>POST: AI response
POST->>DB: create/update conversation record (if applicable)
POST->>Browser: 200 JSON { reply, conversation_id } (createResponse)
end
sequenceDiagram
participant Page
participant Main as main.tsx
participant Widget as Widget.tsx
participant Backend as /api/chatbots/{id}/prompt
participant DeepChat
Page->>Main: load embed script (data-chatbot-id)
Main->>Main: extract chatbotId, create mount node
Main->>Widget: render Widget(chatbotId)
Widget->>DeepChat: render UI (floating button/panel)
DeepChat->>Widget: user sends message
Widget->>Backend: POST message with conversation_id
Backend-->>Widget: { reply, conversation_id }
Widget->>DeepChat: signals.onResponse(reply)
Widget->>Widget: update conversation_id
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Pre-merge checks and finishing touches✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🧹 Nitpick comments (8)
app/api/chatbots/[id]/prompt/route.ts (1)
109-109: Consider making max_tokens configurable.The hardcoded value of 1024 tokens may be restrictive for some use cases. Consider making this configurable per chatbot or at least adding a comment explaining the choice.
Example:
const openrouterResponse = await axios.post( 'https://openrouter.ai/api/v1/chat/completions', { model: 'openai/gpt-5', messages: messagesForAPI, - max_tokens: 1024, + max_tokens: chatbot.max_tokens || 1024, // Default to 1024 for cost control },embed-widget/src/main.tsx (1)
11-13: Consider preventing multiple widget instances.If the embed script is accidentally included multiple times, this code will create multiple chat widgets. Consider checking for an existing container or using a singleton pattern.
+ const existingContainer = document.getElementById('chatbot-embed-root'); + if (existingContainer) { + console.warn('Chatbot widget already initialized'); + return; + } + const container = document.createElement('div'); container.id = 'chatbot-embed-root'; document.body.appendChild(container);embed-widget/README.md (1)
1-73: Update README with project-specific documentation.This README contains the default Vite template documentation. Consider replacing it with embed-widget-specific instructions, including:
- Purpose of the widget
- Build and deployment steps (as mentioned in the PR description)
- How to integrate the embed script into external websites
- Configuration options (chatbot-id attribute)
embed-widget/vite.config.ts (1)
11-23: Consider externalizing React dependencies to reduce bundle conflicts.The current UMD build bundles React and ReactDOM into the output. If the host website also uses React, this could cause conflicts (multiple React instances, version mismatches, context issues).
Consider externalizing React:
build: { outDir: '../public/embed', lib: { entry: 'src/main.tsx', name: 'ChatbotWidget', formats: ['umd'], }, rollupOptions: { + external: ['react', 'react-dom'], + output: { + entryFileNames: 'embed.js', + globals: { + react: 'React', + 'react-dom': 'ReactDOM', + }, + }, - output: { - entryFileNames: 'embed.js', - }, }, },If externalizing, document that host pages must include React before loading the widget, or use a separate build strategy that includes React for self-contained deployment.
embed-widget/eslint.config.js (1)
19-19: Consider aligning ECMAScript version with TypeScript target.The
ecmaVersion: 2020is older than the TypeScript targets (ES2022/ES2023). While not critical, aligning these values prevents potential parser inconsistencies.Apply this diff to align with the TypeScript app target:
languageOptions: { - ecmaVersion: 2020, + ecmaVersion: 2022, globals: globals.browser, },embed-widget/src/Widget.tsx (3)
37-39: Enhance error handling with specific error messages.The generic error message doesn't provide context about what failed. Consider extracting error details from the response to help users understand issues like invalid chatbot IDs, rate limits, or authentication failures.
Apply this diff to provide more specific error feedback:
if (!response.ok) { - throw new Error('API request failed'); + const errorData = await response.json().catch(() => ({ error: 'Unknown error' })); + throw new Error(errorData.error || `API request failed with status ${response.status}`); }Then update the catch block to use the error message:
} catch (error) { console.error(error); signals.onResponse({ - error: 'Sorry, I had trouble connecting.', + error: error instanceof Error ? error.message : 'Sorry, I had trouble connecting.', role: 'assistant', }); }
60-76: Add visual indicator or label to the chat button.The button is empty (line 76) with no text, icon, or ARIA label, making it unclear to users what the button does and inaccessible to screen readers.
Apply this diff to add a chat icon and accessibility label:
<button onClick={() => setIsOpen(true)} + aria-label="Open chat assistant" style={{ width: '60px', height: '60px', borderRadius: '50%', backgroundColor: '#0070f3', color: 'white', border: 'none', fontSize: '28px', cursor: 'pointer', boxShadow: '0 4px 14px 0 rgba(0, 118, 255, 0.39)', display: 'flex', alignItems: 'center', justifyContent: 'center', }} - ></button> + > + 💬 + </button>
24-55: Consider adding loading state during API calls.Users receive no feedback while waiting for the API response, which can lead to confusion or duplicate message submissions on slow connections.
Add a loading state to provide visual feedback:
export function Widget({ chatbotId }: WidgetProps) { const [isOpen, setIsOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); const chatHandler = async (body: DeepChatRequestBody, signals: DeepChatResponseSignals) => { const userMessage = body.messages[body.messages.length - 1].text; try { + setIsLoading(true); const response = await fetch(`http://localhost:3000/api/chatbots/${chatbotId}/prompt`, { // ... rest of the code }); // ... rest of the code } catch (error) { console.error(error); signals.onResponse({ error: 'Sorry, I had trouble connecting.', role: 'assistant', }); + } finally { + setIsLoading(false); } };Then pass
isLoadingto DeepChat or display a loading indicator in the UI.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (8)
embed-widget/package-lock.jsonis excluded by!**/package-lock.jsonembed-widget/public/vite.svgis excluded by!**/*.svgpublic/embed/vite.svgis excluded by!**/*.svgpublic/file.svgis excluded by!**/*.svgpublic/globe.svgis excluded by!**/*.svgpublic/next.svgis excluded by!**/*.svgpublic/vercel.svgis excluded by!**/*.svgpublic/window.svgis excluded by!**/*.svg
📒 Files selected for processing (12)
app/api/chatbots/[id]/prompt/route.ts(5 hunks)embed-widget/.gitignore(1 hunks)embed-widget/README.md(1 hunks)embed-widget/eslint.config.js(1 hunks)embed-widget/index.html(1 hunks)embed-widget/package.json(1 hunks)embed-widget/src/Widget.tsx(1 hunks)embed-widget/src/main.tsx(1 hunks)embed-widget/tsconfig.app.json(1 hunks)embed-widget/tsconfig.json(1 hunks)embed-widget/tsconfig.node.json(1 hunks)embed-widget/vite.config.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
embed-widget/src/main.tsx (1)
embed-widget/src/Widget.tsx (1)
Widget(21-131)
app/api/chatbots/[id]/prompt/route.ts (2)
app/api/chatbots/route.ts (1)
POST(5-45)lib/supabase_admin.ts (1)
supabase_admin(3-3)
🔇 Additional comments (8)
embed-widget/.gitignore (1)
1-24: LGTM!Standard gitignore patterns appropriate for a Node.js/Vite project.
embed-widget/index.html (1)
1-13: LGTM!Standard HTML5 structure appropriate for a React application entry point.
embed-widget/tsconfig.json (1)
1-7: LGTM!Standard TypeScript project references configuration for composite builds.
embed-widget/package.json (1)
12-16: Verify React 19 compatibility and test thoroughly before deploying embed widget.React 19 is production-ready but includes opt‑in new features and removal/cleanup of older APIs, requiring testing and migration work. Real-world issues include TypeScript/tooling breakages and third-party library incompatibilities, plus some performance regressions reported in certain scenarios.
For an embed widget distributed to external sites:
- Test in staging with StrictMode and run React codemods; audit for usage of removed APIs and verify all dependencies support React 19
- Profile for performance regressions (INP, flamegraphs) and adjust code or enable React compiler if needed
- Consider pinning exact versions (remove
^) forreactandreact-domto ensure build consistency across all external deployments and reduce risk of unexpected updates introducing issuesapp/api/chatbots/[id]/prompt/route.ts (1)
104-119: openrouter model is valid — replace hardcoded localhost headersopenai/gpt-5 is present in OpenRouter's model list (so the model-name objection is incorrect). Still update the request headers in app/api/chatbots/[id]/prompt/route.ts to avoid hardcoding. Minimal actions:
- Replace the hardcoded referer/title headers (around lines 104–119):
- 'HTTP-Referer': 'http://localhost:3000' → 'Referer': origin || process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
- 'X-Title': 'Chatbot app' → 'X-Title': process.env.NEXT_PUBLIC_APP_NAME || 'Chatbot app'
Location: app/api/chatbots/[id]/prompt/route.ts (axios headers block).
Likely an incorrect or invalid review comment.
embed-widget/tsconfig.node.json (1)
1-26: LGTM! Standard Vite TypeScript configuration.The configuration is appropriate for a Vite bundler setup with strict type checking and modern ESNext features enabled.
embed-widget/tsconfig.app.json (1)
1-28: LGTM! Appropriate TypeScript configuration for React application.The ES2022 target (vs ES2023 in the node config) provides better browser compatibility for the embedded widget while maintaining modern features.
embed-widget/eslint.config.js (1)
6-6: The ESLint config import is correct.The imports
defineConfigandglobalIgnoresfrom'eslint/config'are valid in ESLint v9 and follow the official flat config pattern. Both utilities can be imported from "eslint/config" and used together in ESLint v9 flat config. The current code in embed-widget/eslint.config.js matches the documented approach for ESLint v9.36.0.Likely an incorrect or invalid review comment.
| const userMessage = body.messages[body.messages.length - 1].text; | ||
|
|
||
| try { | ||
| const response = await fetch(`http://localhost:3000/api/chatbots/${chatbotId}/prompt`, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoded localhost URL prevents production deployment.
The API URL is hardcoded to http://localhost:3000, which will fail when the widget is embedded on external websites in production environments.
Add an apiBaseUrl prop to the Widget component and pass it through from the embed script:
interface WidgetProps {
chatbotId: string;
+ apiBaseUrl: string;
}
export function Widget({ chatbotId }: WidgetProps) {
const [isOpen, setIsOpen] = useState(false);
const chatHandler = async (body: DeepChatRequestBody, signals: DeepChatResponseSignals) => {
const userMessage = body.messages[body.messages.length - 1].text;
try {
- const response = await fetch(`http://localhost:3000/api/chatbots/${chatbotId}/prompt`, {
+ const response = await fetch(`${apiBaseUrl}/api/chatbots/${chatbotId}/prompt`, {
method: 'POST',Then update embed-widget/src/main.tsx to read the API URL from a script data attribute (e.g., data-api-url) or use window.location.origin if the widget is served from the same domain as the API.
Committable suggestion skipped: line range outside the PR's diff.
b4d5771 to
87b0507
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (1)
app/api/chatbots/[id]/prompt/route.ts (1)
75-80: Unconfigured allowed_domains blocks all requests.When
allowed_domainsisnull,undefined, or an empty array, line 75 defaults to[], and line 77 will always reject requests (assumingrequestHostnameis not null). This blocks all legitimate traffic when a user hasn't yet configured their allowed domains.Consider this approach to handle unconfigured domains:
- const allowedDomains = userData?.allowed_domains || []; + const allowedDomains = userData.allowed_domains; - if (!requestHostname || !allowedDomains.includes(requestHostname)) { + if (allowedDomains && allowedDomains.length > 0) { + if (!requestHostname || !allowedDomains.includes(requestHostname)) { - console.error(`Website'${requestHostname}' not in allowed list [${allowedDomains.join(', ')}]`); + console.error(`Website '${requestHostname}' not in allowed list [${allowedDomains.join(', ')}]`); - return createResponse({ error: 'Host not allowed' }, 403); + return createResponse({ error: 'Host not allowed' }, 403); + } + }This way, if
allowed_domainsisnull,undefined, or empty, the validation is skipped, and requests are allowed. Only when domains are explicitly configured is the allowlist enforced.
🧹 Nitpick comments (1)
embed-widget/.gitignore (1)
1-24: Solid .gitignore coverage for a Vite + React project.The file comprehensively excludes logs, build artifacts, editor config, and node_modules. The exception for
.vscode/extensions.jsonis good practice for sharing editor recommendations.Consider adding explicit patterns for environment variables to prevent accidental secrets leakage:
*.local +.env +.env.local +.env.*.localThis is a best practice for projects that use environment variables or
.envfiles.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (8)
embed-widget/package-lock.jsonis excluded by!**/package-lock.jsonembed-widget/public/vite.svgis excluded by!**/*.svgpublic/embed/vite.svgis excluded by!**/*.svgpublic/file.svgis excluded by!**/*.svgpublic/globe.svgis excluded by!**/*.svgpublic/next.svgis excluded by!**/*.svgpublic/vercel.svgis excluded by!**/*.svgpublic/window.svgis excluded by!**/*.svg
📒 Files selected for processing (14)
app/api/chatbots/[id]/prompt/route.ts(1 hunks)app/assistant/page.tsx(0 hunks)app/page.test.tsx(0 hunks)embed-widget/.gitignore(1 hunks)embed-widget/README.md(1 hunks)embed-widget/eslint.config.js(1 hunks)embed-widget/index.html(1 hunks)embed-widget/package.json(1 hunks)embed-widget/src/Widget.tsx(1 hunks)embed-widget/src/main.tsx(1 hunks)embed-widget/tsconfig.app.json(1 hunks)embed-widget/tsconfig.json(1 hunks)embed-widget/tsconfig.node.json(1 hunks)embed-widget/vite.config.ts(1 hunks)
💤 Files with no reviewable changes (2)
- app/page.test.tsx
- app/assistant/page.tsx
🚧 Files skipped from review as they are similar to previous changes (9)
- embed-widget/vite.config.ts
- embed-widget/src/main.tsx
- embed-widget/tsconfig.app.json
- embed-widget/src/Widget.tsx
- embed-widget/tsconfig.node.json
- embed-widget/README.md
- embed-widget/index.html
- embed-widget/package.json
- embed-widget/tsconfig.json
🧰 Additional context used
🧬 Code graph analysis (1)
app/api/chatbots/[id]/prompt/route.ts (2)
app/api/chatbots/route.ts (1)
POST(31-73)lib/supabase_admin.ts (1)
supabase_admin(13-15)
🔇 Additional comments (8)
app/api/chatbots/[id]/prompt/route.ts (8)
5-9: LGTM!The Message type definition properly constrains the role field to valid OpenAI-compatible values and provides clear structure for conversation history.
10-24: LGTM! Previous CORS security issue resolved.The OPTIONS handler now correctly rejects preflight requests without an Origin header and avoids the wildcard fallback that was previously flagged. This prevents unauthorized origins from bypassing CORS restrictions.
37-45: LGTM! CORS fallback security issue resolved.The createResponse helper now uses an empty string fallback instead of the wildcard, ensuring browsers will correctly block requests from unauthorized origins.
71-74: LGTM!Good defensive check for missing user configuration. This prevents downstream null pointer issues and provides a clear error message.
85-97: LGTM!Conversation history retrieval properly validates that the conversation belongs to the specified chatbot before using it, preventing cross-chatbot data leakage.
108-110: LGTM!Good defensive check for the required API key before attempting the OpenRouter call.
138-155: LGTM!The conversation persistence logic correctly handles both updating existing conversations and creating new ones, returning the appropriate response shape in each case.
156-159: LGTM!The catch-all error handler provides a consistent response format and logs errors for debugging while avoiding sensitive information leakage.
| const openrouterResponse = await axios.post( | ||
| 'https://openrouter.ai/api/v1/chat/completions', | ||
| { | ||
| model: 'openai/gpt-5', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify the model name is valid.
The model 'openai/gpt-5' does not appear to be a valid OpenRouter model identifier. This will likely cause API calls to fail.
Please verify the correct model name. Common valid models include:
'openai/gpt-4-turbo''openai/gpt-4''openai/gpt-3.5-turbo'
You can check the latest available models by searching OpenRouter's documentation:
🌐 Web query:
What are the available OpenAI models on OpenRouter API?
💡 Result:
OpenRouter exposes a marketplace of 400+ models from many providers (OpenAI, Anthropic, Google, Meta, Mistral, xAI, Amazon, etc.), and you can list them via the OpenRouter “list available models” endpoint or browse their models page. Example popular IDs available through OpenRouter include (but are not limited to):
- OpenAI: openai/gpt-4, openai/gpt-4-32k, openai/gpt-4o, openai/gpt-3.5-turbo (and variants).
- Anthropic: anthropic/claude-3-opus, anthropic/claude-3-haiku, claude-instant variants.
- Google: google/palm-2-chat-bison, google/palm-2-codechat-bison, google/gemini (various).
- Meta: meta-llama/llama-2-13b-chat, meta-llama/llama-2-70b-chat (and newer Llama versions where listed).
- Other providers: mistralai, deepseek, cohere, xAI (grok), amazon (nova), etc.
For the definitive, up-to-date list use the OpenRouter API endpoint “List available models” or their models catalog (they keep the catalog updated). [1][2]
Sources:
[1] OpenRouter API — List available models (docs).
[2] OpenRouter — Models overview / catalog.
Fix invalid model identifier to use valid OpenRouter model.
The model 'openai/gpt-5' is not available on OpenRouter API and will cause API calls to fail. Valid OpenAI models on OpenRouter include openai/gpt-4, openai/gpt-4-32k, openai/gpt-4o, and openai/gpt-3.5-turbo. Update line 115 to use one of these valid identifiers (e.g., 'openai/gpt-4' or 'openai/gpt-4o').
🤖 Prompt for AI Agents
In app/api/chatbots/[id]/prompt/route.ts around line 115 the model identifier is
set to 'openai/gpt-5', which is invalid for OpenRouter; change it to a supported
OpenRouter model such as 'openai/gpt-4' or 'openai/gpt-4o' (e.g., replace
'openai/gpt-5' with 'openai/gpt-4') so API calls use a valid model identifier.
| headers: { | ||
| Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`, | ||
| 'Content-Type': 'application/json', | ||
| 'HTTP-Referer': 'http://localhost:3000', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace hardcoded localhost with dynamic referer.
The HTTP-Referer header is hardcoded to 'http://localhost:3000', which will be incorrect in production environments and may affect request attribution or rate limiting.
Consider using the actual request origin or a configurable environment variable:
- 'HTTP-Referer': 'http://localhost:3000',
+ 'HTTP-Referer': origin || process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000',📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 'HTTP-Referer': 'http://localhost:3000', | |
| 'HTTP-Referer': origin || process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000', |
🤖 Prompt for AI Agents
In app/api/chatbots/[id]/prompt/route.ts around line 123, the 'HTTP-Referer'
header is hardcoded to 'http://localhost:3000'; change it to use a dynamic value
by reading the request origin (e.g., request.headers.get('origin') or
reconstructing from request URL) or falling back to a configurable env var
(e.g., process.env.NEXT_PUBLIC_APP_URL) so production deployments send the
correct referer; ensure you validate or normalize the value before setting the
header and keep localhost as a fallback only when no origin/env is available.
| import js from '@eslint/js'; | ||
| import globals from 'globals'; | ||
| import reactHooks from 'eslint-plugin-react-hooks'; | ||
| import reactRefresh from 'eslint-plugin-react-refresh'; | ||
| import tseslint from 'typescript-eslint'; | ||
| import { defineConfig, globalIgnores } from 'eslint/config'; | ||
|
|
||
| export default defineConfig([ | ||
| globalIgnores(['dist']), | ||
| { | ||
| files: ['**/*.{ts,tsx}'], | ||
| extends: [ | ||
| js.configs.recommended, | ||
| tseslint.configs.recommended, | ||
| reactHooks.configs['recommended-latest'], | ||
| reactRefresh.configs.vite, | ||
| ], | ||
| languageOptions: { | ||
| ecmaVersion: 2020, | ||
| globals: globals.browser, | ||
| }, | ||
| }, | ||
| ]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix ESLint flat config syntax errors.
This configuration contains multiple syntax errors that will prevent ESLint from loading:
- Line 6:
eslint/configis not a valid import path. ESLint 9.x flat config doesn't exportdefineConfigorglobalIgnoresfrom that path. - Line 9: The
globalIgnores()function doesn't exist in flat config. Use{ ignores: ['dist'] }instead. - Lines 12-17: The
extendsproperty doesn't exist in flat config. Configs should be spread directly into the top-level array.
Apply this diff to use correct ESLint 9.x flat config syntax:
-import js from '@eslint/js';
-import globals from 'globals';
-import reactHooks from 'eslint-plugin-react-hooks';
-import reactRefresh from 'eslint-plugin-react-refresh';
-import tseslint from 'typescript-eslint';
-import { defineConfig, globalIgnores } from 'eslint/config';
-
-export default defineConfig([
- globalIgnores(['dist']),
- {
- files: ['**/*.{ts,tsx}'],
- extends: [
- js.configs.recommended,
- tseslint.configs.recommended,
- reactHooks.configs['recommended-latest'],
- reactRefresh.configs.vite,
- ],
- languageOptions: {
- ecmaVersion: 2020,
- globals: globals.browser,
- },
- },
-]);
+import js from '@eslint/js';
+import globals from 'globals';
+import reactHooks from 'eslint-plugin-react-hooks';
+import reactRefresh from 'eslint-plugin-react-refresh';
+import tseslint from 'typescript-eslint';
+
+export default [
+ { ignores: ['dist'] },
+ js.configs.recommended,
+ ...tseslint.configs.recommended,
+ {
+ files: ['**/*.{ts,tsx}'],
+ plugins: {
+ 'react-hooks': reactHooks,
+ 'react-refresh': reactRefresh,
+ },
+ rules: {
+ ...reactHooks.configs.recommended.rules,
+ 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
+ },
+ languageOptions: {
+ ecmaVersion: 2020,
+ globals: globals.browser,
+ },
+ },
+];📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import js from '@eslint/js'; | |
| import globals from 'globals'; | |
| import reactHooks from 'eslint-plugin-react-hooks'; | |
| import reactRefresh from 'eslint-plugin-react-refresh'; | |
| import tseslint from 'typescript-eslint'; | |
| import { defineConfig, globalIgnores } from 'eslint/config'; | |
| export default defineConfig([ | |
| globalIgnores(['dist']), | |
| { | |
| files: ['**/*.{ts,tsx}'], | |
| extends: [ | |
| js.configs.recommended, | |
| tseslint.configs.recommended, | |
| reactHooks.configs['recommended-latest'], | |
| reactRefresh.configs.vite, | |
| ], | |
| languageOptions: { | |
| ecmaVersion: 2020, | |
| globals: globals.browser, | |
| }, | |
| }, | |
| ]); | |
| import js from '@eslint/js'; | |
| import globals from 'globals'; | |
| import reactHooks from 'eslint-plugin-react-hooks'; | |
| import reactRefresh from 'eslint-plugin-react-refresh'; | |
| import tseslint from 'typescript-eslint'; | |
| export default [ | |
| { ignores: ['dist'] }, | |
| js.configs.recommended, | |
| ...tseslint.configs.recommended, | |
| { | |
| files: ['**/*.{ts,tsx}'], | |
| plugins: { | |
| 'react-hooks': reactHooks, | |
| 'react-refresh': reactRefresh, | |
| }, | |
| rules: { | |
| ...reactHooks.configs.recommended.rules, | |
| 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], | |
| }, | |
| languageOptions: { | |
| ecmaVersion: 2020, | |
| globals: globals.browser, | |
| }, | |
| }, | |
| ]; |
Chatbot widgets UI and CORS policy implemented
Type of Change
Description
Added widgets UI with deep chat react, configured header for responses for CORS policy.
How to Test / Verification Steps
- Go to embed-widgets and run "npm run build", this creates an embed.js file in public/embed/
- Go to any other website, and insert the script inside your html file:
<script src="http://localhost:3000/embed/embed.js" data-chatbot-id="chatbot-uuid" defer> </script>Screenshots / GIFs (if applicable)
Impact of Changes
Users of chatbots can prompt it externally
Summary by CodeRabbit
New Features
Chores