@kaifusion/widget 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaifusion/widget",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "type": "module",
5
5
  "main": "./dist/index.es.js",
6
6
  "module": "./dist/index.es.js",
@@ -19,8 +19,13 @@
19
19
  "scripts": {
20
20
  "dev": "vite",
21
21
  "build": "tsc && vite build",
22
+ "build:standalone": "vite build --config vite.config.standalone.ts",
22
23
  "preview": "vite preview"
23
24
  },
25
+ "peerDependencies": {
26
+ "react": "^18.0.0 || ^19.0.0",
27
+ "react-dom": "^18.0.0 || ^19.0.0"
28
+ },
24
29
  "dependencies": {
25
30
  "lucide-react": "^0.524.0",
26
31
  "motion": "^12.23.12",
@@ -30,14 +35,18 @@
30
35
  "rehype-raw": "^7.0.0",
31
36
  "remark-gfm": "^4.0.1",
32
37
  "remark-math": "^6.0.0",
38
+ "rollup": "^4.54.0",
33
39
  "uuid": "^11.1.0"
34
40
  },
35
41
  "devDependencies": {
42
+ "@tailwindcss/vite": "^4.1.4",
36
43
  "@types/node": "^25.0.3",
37
44
  "@types/react": "^19.1.8",
38
45
  "@types/react-dom": "^19.1.6",
39
46
  "@types/react-syntax-highlighter": "^15.5.13",
40
47
  "@vitejs/plugin-react": "^4.2.0",
48
+ "react": "^19.0.0",
49
+ "react-dom": "^19.0.0",
41
50
  "tailwindcss": "^4.1.4",
42
51
  "typescript": "^5.8.3",
43
52
  "vite": "^6.3.3",
@@ -34,7 +34,7 @@ interface Message {
34
34
  }
35
35
 
36
36
  export interface KaiChatWidgetProps {
37
- authToken: string;
37
+ authToken?: string;
38
38
  workflowId: string;
39
39
  title?: string;
40
40
  targetUrl: string;
@@ -64,6 +64,40 @@ export default function KaiChatWidget({
64
64
  ]);
65
65
  const [input, setInput] = useState("");
66
66
  const [isLoading, setIsLoading] = useState(false);
67
+ const [userProvidedToken, setUserProvidedToken] = useState<string | null>(
68
+ null
69
+ );
70
+ const [isTokenValidating, setIsTokenValidating] = useState(false);
71
+ const [tokenError, setTokenError] = useState<string | null>(null);
72
+
73
+ const effectiveToken = authToken || userProvidedToken;
74
+
75
+ const handleTokenSubmit = async (token: string) => {
76
+ if (!token.trim() || isTokenValidating) return;
77
+
78
+ setIsTokenValidating(true);
79
+ setTokenError(null);
80
+
81
+ try {
82
+ const response = await fetch(`${targetUrl}/api/v1/auth/me`, {
83
+ headers: {
84
+ Authorization: `Bearer ${token}`,
85
+ },
86
+ });
87
+
88
+ if (response.ok) {
89
+ setUserProvidedToken(token);
90
+ } else {
91
+ setTokenError("Geçersiz Erişim Anahtarı. Lütfen tekrar deneyiniz.");
92
+ }
93
+ } catch (error) {
94
+ console.error("Token validation error:", error);
95
+ setTokenError("Bağlantı hatası. Lütfen tekrar deneyiniz.");
96
+ } finally {
97
+ setIsTokenValidating(false);
98
+ }
99
+ };
100
+
67
101
  const [copiedCode, setCopiedCode] = useState<string | null>(null);
68
102
  const messagesEndRef = useRef<HTMLDivElement>(null);
69
103
  const sessionIdRef = useRef(uuidv4());
@@ -111,7 +145,7 @@ export default function KaiChatWidget({
111
145
  ]);
112
146
 
113
147
  try {
114
- const token = authToken || localStorage.getItem("auth_access_token");
148
+ const token = effectiveToken;
115
149
  const headers: Record<string, string> = {
116
150
  "Content-Type": "application/json",
117
151
  Accept: "text/event-stream",
@@ -654,39 +688,84 @@ export default function KaiChatWidget({
654
688
  </div>
655
689
 
656
690
  {/* Input Alanı */}
657
- <div className="p-4 bg-white border-t border-gray-100">
658
- <div className="flex gap-2 items-center bg-gray-50 rounded-full px-4 py-2 border border-gray-200 focus-within:border-blue-500 focus-within:ring-1 focus-within:ring-blue-500 transition-all">
659
- <input
660
- type="text"
661
- value={input}
662
- onChange={(e) => setInput(e.target.value)}
663
- onKeyDown={(e) => e.key === "Enter" && sendMessage()}
664
- placeholder="Mesajınızı yazın..."
665
- className="flex-1 bg-transparent border-none focus:ring-0 outline-none text-sm py-1"
666
- disabled={isLoading}
667
- />
668
- <button
669
- onClick={sendMessage}
670
- disabled={isLoading || !input.trim()}
671
- className={`p-2 rounded-full transition-all ${
672
- input.trim() && !isLoading
673
- ? "text-blue-600 hover:bg-blue-50"
674
- : "text-gray-400"
675
- }`}
676
- >
677
- {isLoading ? (
678
- <Loader2 className="w-5 h-5 animate-spin" />
679
- ) : (
680
- <Send className="w-5 h-5" />
681
- )}
682
- </button>
691
+ {effectiveToken ? (
692
+ <div className="p-4 bg-white border-t border-gray-100">
693
+ <div className="flex gap-2 items-center bg-gray-50 rounded-full px-4 py-2 border border-gray-200 focus-within:border-blue-500 focus-within:ring-1 focus-within:ring-blue-500 transition-all">
694
+ <input
695
+ type="text"
696
+ value={input}
697
+ onChange={(e) => setInput(e.target.value)}
698
+ onKeyDown={(e) => e.key === "Enter" && sendMessage()}
699
+ placeholder="Mesajınızı yazın..."
700
+ className="flex-1 bg-transparent border-none focus:ring-0 outline-none text-sm py-1 text-black"
701
+ disabled={isLoading}
702
+ />
703
+ <button
704
+ onClick={sendMessage}
705
+ disabled={isLoading || !input.trim()}
706
+ className={`p-2 rounded-full transition-all ${
707
+ input.trim() && !isLoading
708
+ ? "text-blue-600 hover:bg-blue-50"
709
+ : "text-gray-400"
710
+ }`}
711
+ >
712
+ {isLoading ? (
713
+ <Loader2 className="w-5 h-5 animate-spin" />
714
+ ) : (
715
+ <Send className="w-5 h-5" />
716
+ )}
717
+ </button>
718
+ </div>
719
+ <div className="text-center mt-2">
720
+ <span className="text-[10px] text-gray-400">
721
+ Powered by Agenticgro
722
+ </span>
723
+ </div>
683
724
  </div>
684
- <div className="text-center mt-2">
685
- <span className="text-[10px] text-gray-400">
686
- Powered by Agenticgro
687
- </span>
725
+ ) : (
726
+ <div className="p-4 bg-white border-t border-gray-100">
727
+ <div className="flex flex-col gap-3">
728
+ <p className="text-sm text-gray-600 text-center">
729
+ Devam etmek için lütfen Erişim Anahtarı giriniz:
730
+ </p>
731
+ <div className="flex gap-2">
732
+ <input
733
+ type="password"
734
+ placeholder="Access Token"
735
+ className={`flex-1 px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 outline-none text-sm text-gray-800 ${
736
+ tokenError ? "border-red-500" : "border-gray-300"
737
+ }`}
738
+ disabled={isTokenValidating}
739
+ onKeyDown={(e) => {
740
+ if (e.key === "Enter") {
741
+ handleTokenSubmit(e.currentTarget.value);
742
+ }
743
+ }}
744
+ />
745
+ <button
746
+ className="bg-blue-600 hover:bg-blue-700 text-white font-medium px-4 rounded-lg transition-colors text-sm disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center min-w-[60px]"
747
+ disabled={isTokenValidating}
748
+ onClick={(e) => {
749
+ const inputEl = e.currentTarget
750
+ .previousElementSibling as HTMLInputElement;
751
+ handleTokenSubmit(inputEl.value);
752
+ }}
753
+ >
754
+ {isTokenValidating ? (
755
+ <Loader2 className="w-4 h-4 animate-spin" />
756
+ ) : (
757
+ "Giriş"
758
+ )}
759
+ </button>
760
+ </div>
761
+ {tokenError && (
762
+ <p className="text-xs text-red-500 text-center">
763
+ {tokenError}
764
+ </p>
765
+ )}
766
+ </div>
688
767
  </div>
689
- </div>
768
+ )}
690
769
  </motion.div>
691
770
  )}
692
771
  </AnimatePresence>
@@ -708,4 +787,4 @@ export default function KaiChatWidget({
708
787
  </motion.button>
709
788
  </div>
710
789
  );
711
- }
790
+ }
package/src/embed.tsx ADDED
@@ -0,0 +1,94 @@
1
+ import React from "react";
2
+ import ReactDOM from "react-dom/client";
3
+ import KaiChatWidget, { KaiChatWidgetProps } from "./KaiChatWidget";
4
+ // @ts-ignore
5
+ import styles from "./index.css?inline";
6
+
7
+ declare global {
8
+ interface Window {
9
+ KaiChat: {
10
+ init: (config: KaiChatWidgetProps) => void;
11
+ };
12
+ }
13
+ }
14
+
15
+ const KAI_CHAT_HOST_ID = "kai-chat-widget-host";
16
+
17
+ function init(config: KaiChatWidgetProps) {
18
+ if (document.getElementById(KAI_CHAT_HOST_ID)) {
19
+ return;
20
+ }
21
+
22
+ const host = document.createElement("div");
23
+ host.id = KAI_CHAT_HOST_ID;
24
+
25
+ host.style.position = "fixed";
26
+ host.style.zIndex = "2147483647";
27
+ host.style.bottom = "0";
28
+ host.style.right = "0";
29
+ host.style.width = "0";
30
+ host.style.height = "0";
31
+ host.style.overflow = "visible";
32
+
33
+ document.body.appendChild(host);
34
+
35
+ const shadow = host.attachShadow({ mode: "open" });
36
+
37
+ const styleTag = document.createElement("style");
38
+ styleTag.textContent = styles;
39
+ shadow.appendChild(styleTag);
40
+
41
+ const mountPoint = document.createElement("div");
42
+ mountPoint.id = "kai-chat-root";
43
+ shadow.appendChild(mountPoint);
44
+
45
+ const root = ReactDOM.createRoot(mountPoint);
46
+ root.render(
47
+ <React.StrictMode>
48
+ <KaiChatWidget {...config} />
49
+ </React.StrictMode>
50
+ );
51
+ }
52
+
53
+ // Global scope'a bağla
54
+ window.KaiChat = { init };
55
+
56
+ // OTOMATİK BAŞLATMA MANTIĞI
57
+ // Mevcut çalışan scripti bul (genellikle son eklenen scripttir veya src ile aranabilir)
58
+ // document.currentScript modern tarayıcılarda çalışır.
59
+ const currentScript = document.currentScript as HTMLScriptElement;
60
+
61
+ if (currentScript) {
62
+ const title = currentScript.getAttribute("data-title");
63
+ const authToken = currentScript.getAttribute("data-auth-token");
64
+ const workflowId = currentScript.getAttribute("data-workflow-id");
65
+ const targetUrl = currentScript.getAttribute("data-target-url");
66
+ const position = currentScript.getAttribute("data-position") as "left" | "right" | null;
67
+ const color = currentScript.getAttribute("data-color");
68
+
69
+ // Eğer gerekli parametreler varsa otomatik başlat
70
+ if (workflowId && targetUrl) {
71
+ // DOM hazır olana kadar bekle
72
+ if (document.readyState === "loading") {
73
+ document.addEventListener("DOMContentLoaded", () => {
74
+ init({
75
+ title: title || "ChatBot",
76
+ authToken: authToken || "",
77
+ workflowId,
78
+ targetUrl,
79
+ position: position || "right",
80
+ color: color || "#526cfe",
81
+ });
82
+ });
83
+ } else {
84
+ init({
85
+ title: title || "ChatBot",
86
+ authToken: authToken || "",
87
+ workflowId,
88
+ targetUrl,
89
+ position: position || "right",
90
+ color: color || "#526cfe",
91
+ });
92
+ }
93
+ }
94
+ }
package/src/index.css ADDED
@@ -0,0 +1,2 @@
1
+ @import "tailwindcss";
2
+
@@ -1,10 +0,0 @@
1
- export interface KaiChatWidgetProps {
2
- authToken: string;
3
- workflowId: string;
4
- title?: string;
5
- targetUrl: string;
6
- position?: "left" | "right";
7
- color?: string;
8
- icon?: React.ReactNode;
9
- }
10
- export default function KaiChatWidget({ authToken, workflowId, title, targetUrl, position, color, icon, }: KaiChatWidgetProps): import("react/jsx-runtime").JSX.Element;
package/dist/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export { default as KaiChatWidget } from './KaiChatWidget';
2
- export type { KaiChatWidgetProps } from './KaiChatWidget';