@airweave/connect-react 0.9.27

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/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # @airweave/connect-react
2
+
3
+ React hook for integrating Airweave Connect into your application.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @airweave/connect-react
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```tsx
14
+ import { useAirweaveConnect } from "@airweave/connect-react";
15
+
16
+ function App() {
17
+ const { open, close, isOpen, isLoading, error, status } = useAirweaveConnect({
18
+ getSessionToken: async () => {
19
+ // Call your backend to get a session token
20
+ const response = await fetch("/api/airweave/session", {
21
+ method: "POST",
22
+ });
23
+ const data = await response.json();
24
+ return data.sessionToken;
25
+ },
26
+ theme: {
27
+ mode: "light", // or 'dark' or 'system'
28
+ },
29
+ onSuccess: (connectionId) => {
30
+ console.log("Connection created:", connectionId);
31
+ },
32
+ onError: (error) => {
33
+ console.error("Error:", error.message);
34
+ },
35
+ onClose: (reason) => {
36
+ console.log("Modal closed:", reason);
37
+ },
38
+ });
39
+
40
+ return (
41
+ <button onClick={open} disabled={isLoading}>
42
+ {isLoading ? "Loading..." : "Connect Apps"}
43
+ </button>
44
+ );
45
+ }
46
+ ```
47
+
48
+ ## API Reference
49
+
50
+ ### `useAirweaveConnect(options)`
51
+
52
+ #### Options
53
+
54
+ | Option | Type | Required | Description |
55
+ | -------------------- | ---------------------------------------------- | -------- | ---------------------------------------------- |
56
+ | `getSessionToken` | `() => Promise<string>` | Yes | Async function to fetch a session token |
57
+ | `theme` | `ConnectTheme` | No | Theme configuration for the Connect UI |
58
+ | `connectUrl` | `string` | No | URL of the hosted Connect iframe |
59
+ | `onSuccess` | `(connectionId: string) => void` | No | Called when a connection is created |
60
+ | `onError` | `(error: SessionError) => void` | No | Called when an error occurs |
61
+ | `onClose` | `(reason: 'success' \| 'cancel' \| 'error') => void` | No | Called when the modal is closed |
62
+ | `onConnectionCreated`| `(connectionId: string) => void` | No | Called when a new connection is created |
63
+ | `onStatusChange` | `(status: SessionStatus) => void` | No | Called when the session status changes |
64
+
65
+ #### Returns
66
+
67
+ | Property | Type | Description |
68
+ | ----------- | ---------------------- | ------------------------------------ |
69
+ | `open` | `() => void` | Opens the Connect modal |
70
+ | `close` | `() => void` | Closes the Connect modal |
71
+ | `isOpen` | `boolean` | Whether the modal is currently open |
72
+ | `isLoading` | `boolean` | Whether a token is being fetched |
73
+ | `error` | `SessionError \| null` | Current error, if any |
74
+ | `status` | `SessionStatus \| null`| Current session status from iframe |
75
+
76
+ ## Theme Customization
77
+
78
+ You can customize the appearance of the Connect modal by passing a theme object:
79
+
80
+ ```tsx
81
+ const { open } = useAirweaveConnect({
82
+ getSessionToken,
83
+ theme: {
84
+ mode: "dark", // 'light', 'dark', or 'system'
85
+ colors: {
86
+ dark: {
87
+ primary: "#6366f1",
88
+ background: "#0f172a",
89
+ surface: "#1e293b",
90
+ text: "#ffffff",
91
+ textMuted: "#9ca3af",
92
+ border: "#334155",
93
+ success: "#22c55e",
94
+ error: "#ef4444",
95
+ },
96
+ light: {
97
+ primary: "#4f46e5",
98
+ background: "#ffffff",
99
+ surface: "#f8fafc",
100
+ text: "#1f2937",
101
+ textMuted: "#6b7280",
102
+ border: "#e5e7eb",
103
+ success: "#22c55e",
104
+ error: "#ef4444",
105
+ },
106
+ },
107
+ },
108
+ });
109
+ ```
110
+
111
+ ## Backend Integration
112
+
113
+ Your backend needs to create session tokens by calling the Airweave API:
114
+
115
+ ```bash
116
+ POST /connect/sessions
117
+ Headers:
118
+ X-API-Key: your-api-key
119
+ Content-Type: application/json
120
+ Body:
121
+ {
122
+ "readable_collection_id": "your-collection-id",
123
+ "mode": "all",
124
+ "end_user_id": "user-123"
125
+ }
126
+ ```
127
+
128
+ The response will include a `session_token` that you return from your `getSessionToken` function.
129
+
130
+ ## License
131
+
132
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const G=require("airweave-connect/lib/types"),v=require("airweave-connect/lib/connection-utils"),re=require("airweave-connect/lib/icons"),m=require("airweave-connect/lib/theme-defaults"),l=require("react/jsx-runtime"),t=require("react"),ne=require("react-dom/client");function se({connectUrl:o,onClose:n,onIframeRef:a,modalStyle:r,showCloseButton:E=!1}){const[b,R]=t.useState(!1);t.useEffect(()=>{const c=requestAnimationFrame(()=>{R(!0)});return()=>cancelAnimationFrame(c)},[]),t.useEffect(()=>{const c=k=>{k.key==="Escape"&&n()};return document.addEventListener("keydown",c),()=>document.removeEventListener("keydown",c)},[n]);const O=c=>{c.target===c.currentTarget&&n()};return l.jsx("div",{style:{position:"fixed",top:0,left:0,right:0,bottom:0,backgroundColor:"rgba(0, 0, 0, 0.5)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:1e4,opacity:b?1:0,transition:"opacity 0.15s ease-out"},onClick:O,children:l.jsxs("div",{style:{position:"relative",width:(r==null?void 0:r.width)??"90%",maxWidth:(r==null?void 0:r.maxWidth)??"400px",height:(r==null?void 0:r.height)??"80%",maxHeight:(r==null?void 0:r.maxHeight)??"540px",backgroundColor:"white",borderRadius:(r==null?void 0:r.borderRadius)??"16px",overflow:"hidden",boxShadow:"0 25px 50px -12px rgba(0, 0, 0, 0.25)",transform:b?"scale(1) translateY(0)":"scale(0.95) translateY(10px)",opacity:b?1:0,transition:"transform 0.15s ease-out, opacity 0.15s ease-out"},children:[E&&l.jsx("button",{onClick:n,style:{position:"absolute",top:12,right:12,width:32,height:32,border:"none",background:"rgba(0, 0, 0, 0.1)",borderRadius:"50%",cursor:"pointer",fontSize:20,color:"#666",display:"flex",alignItems:"center",justifyContent:"center",zIndex:10,transition:"background 0.2s"},onMouseEnter:c=>{c.currentTarget.style.background="rgba(0, 0, 0, 0.2)"},onMouseLeave:c=>{c.currentTarget.style.background="rgba(0, 0, 0, 0.1)"},"aria-label":"Close",children:"×"}),l.jsx("iframe",{ref:a,src:o,style:{width:"100%",height:"100%",border:"none"},title:"Airweave Connect"})]})})}const W="https://connect.airweave.ai";function oe(o,n){const a=new URL(o);return n!=null&&n.mode&&a.searchParams.set("theme",n.mode),a.toString()}function ce(o){try{return new URL(o).origin}catch{return o}}const ue="airweave-connect-root";function Y(o){const{getSessionToken:n,theme:a,connectUrl:r=W,onSuccess:E,onError:b,onClose:R,onConnectionCreated:O,onStatusChange:c,initialView:k,modalStyle:I,showCloseButton:A=!1}=o,[C,L]=t.useState(!1),[B,N]=t.useState(!1),[Q,x]=t.useState(null),[J,X]=t.useState(null),U=t.useRef(null),T=t.useRef(null),f=t.useRef(null),i=t.useRef(null),w=ce(r),P=t.useRef(n);P.current=n;const g=t.useRef({onSuccess:E,onError:b,onClose:R,onConnectionCreated:O,onStatusChange:c});g.current={onSuccess:E,onError:b,onClose:R,onConnectionCreated:O,onStatusChange:c};const y=t.useRef(a);y.current=a;const j=t.useRef(k);j.current=k;const d=t.useCallback(s=>{var u,e;(e=(u=U.current)==null?void 0:u.contentWindow)==null||e.postMessage(s,w)},[w]),p=t.useCallback((s="cancel")=>{var u,e;L(!1),T.current=null,(e=(u=g.current).onClose)==null||e.call(u,s)},[]);t.useEffect(()=>{if(!C)return;const s=u=>{var h,q,D,F,M,V,S,H;if(u.origin!==w)return;const e=u.data;if(!(!e||typeof e!="object"||!("type"in e)))switch(e.type){case"CONNECT_READY":j.current&&d({type:"NAVIGATE",view:j.current});break;case"REQUEST_TOKEN":{const K=e.requestId;P.current().then(z=>{T.current=z,d({type:"TOKEN_RESPONSE",requestId:K,token:z,theme:y.current})}).catch(()=>{d({type:"TOKEN_ERROR",requestId:K,error:"Failed to refresh session token"})});break}case"STATUS_CHANGE":X(e.status),(q=(h=g.current).onStatusChange)==null||q.call(h,e.status),e.status.status==="error"&&(x(e.status.error),(F=(D=g.current).onError)==null||F.call(D,e.status.error));break;case"CONNECTION_CREATED":(V=(M=g.current).onConnectionCreated)==null||V.call(M,e.connectionId),(H=(S=g.current).onSuccess)==null||H.call(S,e.connectionId);break;case"CLOSE":p(e.reason);break}};return window.addEventListener("message",s),()=>window.removeEventListener("message",s)},[C,p,d,w]);const _=oe(r,a);t.useEffect(()=>{C?(i.current||(i.current=document.createElement("div"),i.current.id=ue,document.body.appendChild(i.current)),f.current||(f.current=ne.createRoot(i.current)),f.current.render(l.jsx(se,{connectUrl:_,onClose:()=>p("cancel"),onIframeRef:s=>{U.current=s},modalStyle:I,showCloseButton:A}))):f.current&&f.current.render(l.jsx(l.Fragment,{}))},[C,_,p,I,A]),t.useEffect(()=>()=>{f.current&&(f.current.unmount(),f.current=null),i.current&&i.current.parentNode&&(i.current.parentNode.removeChild(i.current),i.current=null)},[]);const Z=t.useCallback(async()=>{var s,u;N(!0),x(null);try{const e=await n();T.current=e,L(!0)}catch(e){const h={code:"network_error",message:e instanceof Error?e.message:"Failed to get session token"};x(h),(u=(s=g.current).onError)==null||u.call(s,h)}finally{N(!1)}},[n]),$=t.useCallback(()=>{p("cancel")},[p]),ee=t.useCallback(s=>{y.current=s,d({type:"SET_THEME",theme:s})},[d]),te=t.useCallback(s=>{d({type:"NAVIGATE",view:s})},[d]);return{open:Z,close:$,setTheme:ee,navigate:te,isOpen:C,isLoading:B,error:Q,status:J}}function ae({children:o,...n}){const a=Y(n);return l.jsx(l.Fragment,{children:o(a)})}Object.defineProperty(exports,"canConnect",{enumerable:!0,get:()=>v.canConnect});Object.defineProperty(exports,"getStatusColor",{enumerable:!0,get:()=>v.getStatusColor});Object.defineProperty(exports,"getStatusLabel",{enumerable:!0,get:()=>v.getStatusLabel});Object.defineProperty(exports,"getAppIconUrl",{enumerable:!0,get:()=>re.getAppIconUrl});Object.defineProperty(exports,"defaultDarkColors",{enumerable:!0,get:()=>m.defaultDarkColors});Object.defineProperty(exports,"defaultLabels",{enumerable:!0,get:()=>m.defaultLabels});Object.defineProperty(exports,"defaultLightColors",{enumerable:!0,get:()=>m.defaultLightColors});Object.defineProperty(exports,"defaultOptions",{enumerable:!0,get:()=>m.defaultOptions});exports.AirweaveConnect=ae;exports.DEFAULT_CONNECT_URL=W;exports.useAirweaveConnect=Y;Object.keys(G).forEach(o=>{o!=="default"&&!Object.prototype.hasOwnProperty.call(exports,o)&&Object.defineProperty(exports,o,{enumerable:!0,get:()=>G[o]})});
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/ConnectModal.tsx","../src/constants.ts","../src/iframeUrl.ts","../src/useAirweaveConnect.tsx","../src/AirweaveConnect.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { ModalStyle } from \"./useAirweaveConnect\";\n\ninterface ConnectModalProps {\n connectUrl: string;\n onClose: () => void;\n onIframeRef: (iframe: HTMLIFrameElement | null) => void;\n modalStyle?: ModalStyle;\n showCloseButton?: boolean;\n}\n\nexport function ConnectModal({\n connectUrl,\n onClose,\n onIframeRef,\n modalStyle,\n showCloseButton = false,\n}: ConnectModalProps) {\n const [isVisible, setIsVisible] = useState(false);\n\n // Trigger entry animation after mount\n useEffect(() => {\n // Small delay to ensure the initial styles are applied before transitioning\n const timer = requestAnimationFrame(() => {\n setIsVisible(true);\n });\n return () => cancelAnimationFrame(timer);\n }, []);\n\n // Handle ESC key\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n onClose();\n }\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [onClose]);\n\n // Handle click outside\n const handleOverlayClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n onClose();\n }\n };\n\n return (\n <div\n style={{\n position: \"fixed\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: \"rgba(0, 0, 0, 0.5)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n zIndex: 10000,\n opacity: isVisible ? 1 : 0,\n transition: \"opacity 0.15s ease-out\",\n }}\n onClick={handleOverlayClick}\n >\n <div\n style={{\n position: \"relative\",\n width: modalStyle?.width ?? \"90%\",\n maxWidth: modalStyle?.maxWidth ?? \"400px\",\n height: modalStyle?.height ?? \"80%\",\n maxHeight: modalStyle?.maxHeight ?? \"540px\",\n backgroundColor: \"white\",\n borderRadius: modalStyle?.borderRadius ?? \"16px\",\n overflow: \"hidden\",\n boxShadow: \"0 25px 50px -12px rgba(0, 0, 0, 0.25)\",\n transform: isVisible\n ? \"scale(1) translateY(0)\"\n : \"scale(0.95) translateY(10px)\",\n opacity: isVisible ? 1 : 0,\n transition: \"transform 0.15s ease-out, opacity 0.15s ease-out\",\n }}\n >\n {showCloseButton && (\n <button\n onClick={onClose}\n style={{\n position: \"absolute\",\n top: 12,\n right: 12,\n width: 32,\n height: 32,\n border: \"none\",\n background: \"rgba(0, 0, 0, 0.1)\",\n borderRadius: \"50%\",\n cursor: \"pointer\",\n fontSize: 20,\n color: \"#666\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n zIndex: 10,\n transition: \"background 0.2s\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.background = \"rgba(0, 0, 0, 0.2)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.background = \"rgba(0, 0, 0, 0.1)\";\n }}\n aria-label=\"Close\"\n >\n ×\n </button>\n )}\n <iframe\n ref={onIframeRef}\n src={connectUrl}\n style={{\n width: \"100%\",\n height: \"100%\",\n border: \"none\",\n }}\n title=\"Airweave Connect\"\n />\n </div>\n </div>\n );\n}\n","export const DEFAULT_CONNECT_URL = \"https://connect.airweave.ai\";\n","import type { ConnectTheme } from \"airweave-connect/lib/types\";\n\n/**\n * Builds the iframe URL with theme query parameter.\n */\nexport function buildIframeUrl(connectUrl: string, theme?: ConnectTheme): string {\n const url = new URL(connectUrl);\n if (theme?.mode) {\n url.searchParams.set(\"theme\", theme.mode);\n }\n return url.toString();\n}\n\n/**\n * Derives the expected origin from a connect URL for secure postMessage validation.\n */\nexport function getExpectedOrigin(connectUrl: string): string {\n try {\n const url = new URL(connectUrl);\n return url.origin;\n } catch {\n // Fallback for invalid URLs - will cause postMessage to fail safely\n return connectUrl;\n }\n}\n","import type {\n ChildToParentMessage,\n ConnectTheme,\n NavigateView,\n ParentToChildMessage,\n SessionError,\n SessionStatus,\n} from \"airweave-connect/lib/types\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { createRoot, Root } from \"react-dom/client\";\nimport { ConnectModal } from \"./ConnectModal\";\nimport { DEFAULT_CONNECT_URL } from \"./constants\";\nimport { buildIframeUrl, getExpectedOrigin } from \"./iframeUrl\";\nimport type {\n UseAirweaveConnectOptions,\n UseAirweaveConnectReturn,\n} from \"./useAirweaveConnect.types\";\n\n// Re-export types for consumers\nexport type { ModalStyle, UseAirweaveConnectOptions, UseAirweaveConnectReturn } from \"./useAirweaveConnect.types\";\n\nconst CONTAINER_ID = \"airweave-connect-root\";\n\nexport function useAirweaveConnect(\n options: UseAirweaveConnectOptions,\n): UseAirweaveConnectReturn {\n const {\n getSessionToken,\n theme,\n connectUrl = DEFAULT_CONNECT_URL,\n onSuccess,\n onError,\n onClose,\n onConnectionCreated,\n onStatusChange,\n initialView,\n modalStyle,\n showCloseButton = false,\n } = options;\n\n const [isOpen, setIsOpen] = useState(false);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<SessionError | null>(null);\n const [status, setStatus] = useState<SessionStatus | null>(null);\n\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const sessionTokenRef = useRef<string | null>(null);\n const rootRef = useRef<Root | null>(null);\n const containerRef = useRef<HTMLDivElement | null>(null);\n\n // Derive expected origin from connectUrl for secure postMessage\n const expectedOrigin = getExpectedOrigin(connectUrl);\n\n // Store callbacks and getSessionToken in refs to avoid re-creating message handler\n const getSessionTokenRef = useRef(getSessionToken);\n getSessionTokenRef.current = getSessionToken;\n\n const callbacksRef = useRef({\n onSuccess,\n onError,\n onClose,\n onConnectionCreated,\n onStatusChange,\n });\n callbacksRef.current = {\n onSuccess,\n onError,\n onClose,\n onConnectionCreated,\n onStatusChange,\n };\n\n // Store theme in ref to use in message handler\n const themeRef = useRef(theme);\n themeRef.current = theme;\n\n // Store initialView in ref to use on CONNECT_READY\n const initialViewRef = useRef(initialView);\n initialViewRef.current = initialView;\n\n // Send message to iframe with restricted origin\n const sendToIframe = useCallback(\n (message: ParentToChildMessage) => {\n iframeRef.current?.contentWindow?.postMessage(message, expectedOrigin);\n },\n [expectedOrigin],\n );\n\n const handleClose = useCallback(\n (reason: \"success\" | \"cancel\" | \"error\" = \"cancel\") => {\n setIsOpen(false);\n sessionTokenRef.current = null;\n callbacksRef.current.onClose?.(reason);\n },\n [],\n );\n\n // Handle messages from iframe\n useEffect(() => {\n if (!isOpen) return;\n\n const handleMessage = (event: MessageEvent) => {\n // Validate origin to prevent spoofed messages from malicious sites\n if (event.origin !== expectedOrigin) {\n return;\n }\n\n const data = event.data as ChildToParentMessage;\n if (!data || typeof data !== \"object\" || !(\"type\" in data)) {\n return;\n }\n\n switch (data.type) {\n case \"CONNECT_READY\":\n // Iframe is ready - navigate to initial view if specified\n if (initialViewRef.current) {\n sendToIframe({ type: \"NAVIGATE\", view: initialViewRef.current });\n }\n break;\n\n case \"REQUEST_TOKEN\": {\n // Re-fetch token from the customer's backend to handle expiry/refresh\n const requestId = data.requestId;\n getSessionTokenRef\n .current()\n .then((token) => {\n sessionTokenRef.current = token;\n sendToIframe({\n type: \"TOKEN_RESPONSE\",\n requestId,\n token,\n theme: themeRef.current,\n });\n })\n .catch(() => {\n sendToIframe({\n type: \"TOKEN_ERROR\",\n requestId,\n error: \"Failed to refresh session token\",\n });\n });\n break;\n }\n\n case \"STATUS_CHANGE\":\n setStatus(data.status);\n callbacksRef.current.onStatusChange?.(data.status);\n\n if (data.status.status === \"error\") {\n setError(data.status.error);\n callbacksRef.current.onError?.(data.status.error);\n }\n break;\n\n case \"CONNECTION_CREATED\":\n callbacksRef.current.onConnectionCreated?.(data.connectionId);\n callbacksRef.current.onSuccess?.(data.connectionId);\n break;\n\n case \"CLOSE\":\n handleClose(data.reason);\n break;\n }\n };\n\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [isOpen, handleClose, sendToIframe, expectedOrigin]);\n\n // Build the iframe URL with theme query parameter\n const iframeUrl = buildIframeUrl(connectUrl, theme);\n\n // Manage modal rendering via createRoot\n useEffect(() => {\n if (isOpen) {\n // Create container if it doesn't exist\n if (!containerRef.current) {\n containerRef.current = document.createElement(\"div\");\n containerRef.current.id = CONTAINER_ID;\n document.body.appendChild(containerRef.current);\n }\n\n // Create root if it doesn't exist\n if (!rootRef.current) {\n rootRef.current = createRoot(containerRef.current);\n }\n\n // Render modal\n rootRef.current.render(\n <ConnectModal\n connectUrl={iframeUrl}\n onClose={() => handleClose(\"cancel\")}\n onIframeRef={(iframe) => {\n iframeRef.current = iframe;\n }}\n modalStyle={modalStyle}\n showCloseButton={showCloseButton}\n />,\n );\n } else {\n // Unmount modal\n if (rootRef.current) {\n rootRef.current.render(<></>);\n }\n }\n }, [isOpen, iframeUrl, handleClose, modalStyle, showCloseButton]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (rootRef.current) {\n rootRef.current.unmount();\n rootRef.current = null;\n }\n if (containerRef.current && containerRef.current.parentNode) {\n containerRef.current.parentNode.removeChild(containerRef.current);\n containerRef.current = null;\n }\n };\n }, []);\n\n const open = useCallback(async () => {\n setIsLoading(true);\n setError(null);\n\n try {\n const token = await getSessionToken();\n sessionTokenRef.current = token;\n setIsOpen(true);\n } catch (err) {\n const sessionError: SessionError = {\n code: \"network_error\",\n message:\n err instanceof Error ? err.message : \"Failed to get session token\",\n };\n setError(sessionError);\n callbacksRef.current.onError?.(sessionError);\n } finally {\n setIsLoading(false);\n }\n }, [getSessionToken]);\n\n const close = useCallback(() => {\n handleClose(\"cancel\");\n }, [handleClose]);\n\n const setTheme = useCallback(\n (newTheme: ConnectTheme) => {\n themeRef.current = newTheme;\n sendToIframe({ type: \"SET_THEME\", theme: newTheme });\n },\n [sendToIframe],\n );\n\n const navigate = useCallback(\n (view: NavigateView) => {\n sendToIframe({ type: \"NAVIGATE\", view });\n },\n [sendToIframe],\n );\n\n return {\n open,\n close,\n setTheme,\n navigate,\n isOpen,\n isLoading,\n error,\n status,\n };\n}\n","import type { ReactNode } from \"react\";\nimport {\n useAirweaveConnect,\n type UseAirweaveConnectOptions,\n type UseAirweaveConnectReturn,\n} from \"./useAirweaveConnect\";\n\ntype RenderProps = UseAirweaveConnectReturn;\n\nexport interface AirweaveConnectProps extends UseAirweaveConnectOptions {\n /**\n * Render prop that receives all hook return values.\n * Use this to render your trigger button or any custom UI.\n *\n * @example\n * ```tsx\n * <AirweaveConnect getSessionToken={fetchToken}>\n * {({ open, isLoading }) => (\n * <button onClick={open} disabled={isLoading}>\n * {isLoading ? \"Loading...\" : \"Connect\"}\n * </button>\n * )}\n * </AirweaveConnect>\n * ```\n */\n children: (props: RenderProps) => ReactNode;\n}\n\n/**\n * A component wrapper for the useAirweaveConnect hook.\n * Provides a simpler API for common use cases.\n *\n * @example\n * ```tsx\n * // Simple usage\n * <AirweaveConnect\n * getSessionToken={async () => {\n * const res = await fetch(\"/api/connect-session\");\n * const data = await res.json();\n * return data.session_token;\n * }}\n * onSuccess={(connectionId) => {\n * console.log(\"New connection:\", connectionId);\n * }}\n * >\n * {({ open, isLoading }) => (\n * <button onClick={open} disabled={isLoading}>\n * {isLoading ? \"Connecting...\" : \"Connect Apps\"}\n * </button>\n * )}\n * </AirweaveConnect>\n *\n * // With all features\n * <AirweaveConnect\n * getSessionToken={fetchToken}\n * initialView=\"sources\"\n * showCloseButton\n * modalStyle={{ maxWidth: \"600px\" }}\n * onSuccess={handleSuccess}\n * onClose={(reason) => console.log(\"Closed:\", reason)}\n * >\n * {({ open, isLoading, isOpen, navigate }) => (\n * <div>\n * <button onClick={open} disabled={isLoading || isOpen}>\n * {isLoading ? \"Preparing...\" : \"Connect Apps\"}\n * </button>\n * {isOpen && (\n * <button onClick={() => navigate(\"sources\")}>\n * Browse Sources\n * </button>\n * )}\n * </div>\n * )}\n * </AirweaveConnect>\n * ```\n */\nexport function AirweaveConnect({\n children,\n ...hookOptions\n}: AirweaveConnectProps) {\n const hookReturn = useAirweaveConnect(hookOptions);\n return <>{children(hookReturn)}</>;\n}\n"],"names":["ConnectModal","connectUrl","onClose","onIframeRef","modalStyle","showCloseButton","isVisible","setIsVisible","useState","useEffect","timer","handleKeyDown","e","handleOverlayClick","jsx","jsxs","DEFAULT_CONNECT_URL","buildIframeUrl","theme","url","getExpectedOrigin","CONTAINER_ID","useAirweaveConnect","options","getSessionToken","onSuccess","onError","onConnectionCreated","onStatusChange","initialView","isOpen","setIsOpen","isLoading","setIsLoading","error","setError","status","setStatus","iframeRef","useRef","sessionTokenRef","rootRef","containerRef","expectedOrigin","getSessionTokenRef","callbacksRef","themeRef","initialViewRef","sendToIframe","useCallback","message","_b","_a","handleClose","reason","handleMessage","event","data","requestId","token","_d","_c","_f","_e","_h","_g","iframeUrl","createRoot","iframe","Fragment","open","err","sessionError","close","setTheme","newTheme","navigate","view","AirweaveConnect","children","hookOptions","hookReturn"],"mappings":"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"}
@@ -0,0 +1,168 @@
1
+ import { canConnect } from 'airweave-connect/lib/connection-utils';
2
+ import { ConnectTheme } from 'airweave-connect/lib/types';
3
+ import { defaultDarkColors } from 'airweave-connect/lib/theme-defaults';
4
+ import { defaultLabels } from 'airweave-connect/lib/theme-defaults';
5
+ import { defaultLightColors } from 'airweave-connect/lib/theme-defaults';
6
+ import { defaultOptions } from 'airweave-connect/lib/theme-defaults';
7
+ import { getAppIconUrl } from 'airweave-connect/lib/icons';
8
+ import { getStatusColor } from 'airweave-connect/lib/connection-utils';
9
+ import { getStatusLabel } from 'airweave-connect/lib/connection-utils';
10
+ import { JSX } from 'react/jsx-runtime';
11
+ import { NavigateView } from 'airweave-connect/lib/types';
12
+ import { ReactNode } from 'react';
13
+ import { SessionError } from 'airweave-connect/lib/types';
14
+ import { SessionStatus } from 'airweave-connect/lib/types';
15
+
16
+ /**
17
+ * A component wrapper for the useAirweaveConnect hook.
18
+ * Provides a simpler API for common use cases.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * // Simple usage
23
+ * <AirweaveConnect
24
+ * getSessionToken={async () => {
25
+ * const res = await fetch("/api/connect-session");
26
+ * const data = await res.json();
27
+ * return data.session_token;
28
+ * }}
29
+ * onSuccess={(connectionId) => {
30
+ * console.log("New connection:", connectionId);
31
+ * }}
32
+ * >
33
+ * {({ open, isLoading }) => (
34
+ * <button onClick={open} disabled={isLoading}>
35
+ * {isLoading ? "Connecting..." : "Connect Apps"}
36
+ * </button>
37
+ * )}
38
+ * </AirweaveConnect>
39
+ *
40
+ * // With all features
41
+ * <AirweaveConnect
42
+ * getSessionToken={fetchToken}
43
+ * initialView="sources"
44
+ * showCloseButton
45
+ * modalStyle={{ maxWidth: "600px" }}
46
+ * onSuccess={handleSuccess}
47
+ * onClose={(reason) => console.log("Closed:", reason)}
48
+ * >
49
+ * {({ open, isLoading, isOpen, navigate }) => (
50
+ * <div>
51
+ * <button onClick={open} disabled={isLoading || isOpen}>
52
+ * {isLoading ? "Preparing..." : "Connect Apps"}
53
+ * </button>
54
+ * {isOpen && (
55
+ * <button onClick={() => navigate("sources")}>
56
+ * Browse Sources
57
+ * </button>
58
+ * )}
59
+ * </div>
60
+ * )}
61
+ * </AirweaveConnect>
62
+ * ```
63
+ */
64
+ export declare function AirweaveConnect({ children, ...hookOptions }: AirweaveConnectProps): JSX.Element;
65
+
66
+ export declare interface AirweaveConnectProps extends UseAirweaveConnectOptions {
67
+ /**
68
+ * Render prop that receives all hook return values.
69
+ * Use this to render your trigger button or any custom UI.
70
+ *
71
+ * @example
72
+ * ```tsx
73
+ * <AirweaveConnect getSessionToken={fetchToken}>
74
+ * {({ open, isLoading }) => (
75
+ * <button onClick={open} disabled={isLoading}>
76
+ * {isLoading ? "Loading..." : "Connect"}
77
+ * </button>
78
+ * )}
79
+ * </AirweaveConnect>
80
+ * ```
81
+ */
82
+ children: (props: RenderProps) => ReactNode;
83
+ }
84
+
85
+ export { canConnect }
86
+
87
+ export declare const DEFAULT_CONNECT_URL = "https://connect.airweave.ai";
88
+
89
+ export { defaultDarkColors }
90
+
91
+ export { defaultLabels }
92
+
93
+ export { defaultLightColors }
94
+
95
+ export { defaultOptions }
96
+
97
+ export { getAppIconUrl }
98
+
99
+ export { getStatusColor }
100
+
101
+ export { getStatusLabel }
102
+
103
+ /** Modal styling options */
104
+ export declare interface ModalStyle {
105
+ /** Modal width (default: "90%") */
106
+ width?: string;
107
+ /** Modal max width (default: "400px") */
108
+ maxWidth?: string;
109
+ /** Modal height (default: "80%") */
110
+ height?: string;
111
+ /** Modal max height (default: "540px") */
112
+ maxHeight?: string;
113
+ /** Modal border radius (default: "16px") */
114
+ borderRadius?: string;
115
+ }
116
+
117
+ declare type RenderProps = UseAirweaveConnectReturn;
118
+
119
+ export declare function useAirweaveConnect(options: UseAirweaveConnectOptions): UseAirweaveConnectReturn;
120
+
121
+ export declare interface UseAirweaveConnectOptions {
122
+ /** Async function to get a session token from your backend */
123
+ getSessionToken: () => Promise<string>;
124
+ /** Theme configuration for the Connect UI */
125
+ theme?: ConnectTheme;
126
+ /** URL of the hosted Connect iframe (defaults to Airweave hosted) */
127
+ connectUrl?: string;
128
+ /** Called when a connection is successfully created */
129
+ onSuccess?: (connectionId: string) => void;
130
+ /** Called when an error occurs */
131
+ onError?: (error: SessionError) => void;
132
+ /** Called when the modal is closed */
133
+ onClose?: (reason: "success" | "cancel" | "error") => void;
134
+ /** Called when a new connection is created */
135
+ onConnectionCreated?: (connectionId: string) => void;
136
+ /** Called when the session status changes */
137
+ onStatusChange?: (status: SessionStatus) => void;
138
+ /** Initial view to show when modal opens (default: shows connections or sources based on mode) */
139
+ initialView?: NavigateView;
140
+ /** Custom modal styling */
141
+ modalStyle?: ModalStyle;
142
+ /** Show a close button in the modal (default: false) */
143
+ showCloseButton?: boolean;
144
+ }
145
+
146
+ export declare interface UseAirweaveConnectReturn {
147
+ /** Open the Connect modal */
148
+ open: () => void;
149
+ /** Close the Connect modal */
150
+ close: () => void;
151
+ /** Dynamically update theme/labels while modal is open */
152
+ setTheme: (theme: ConnectTheme) => void;
153
+ /** Navigate to a specific view within the modal */
154
+ navigate: (view: NavigateView) => void;
155
+ /** Whether the modal is currently open */
156
+ isOpen: boolean;
157
+ /** Whether a token is being fetched */
158
+ isLoading: boolean;
159
+ /** Current error, if any */
160
+ error: SessionError | null;
161
+ /** Current session status from the iframe */
162
+ status: SessionStatus | null;
163
+ }
164
+
165
+
166
+ export * from "airweave-connect/lib/types";
167
+
168
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,295 @@
1
+ export * from "airweave-connect/lib/types";
2
+ import { canConnect as Ce, getStatusColor as Ee, getStatusLabel as be } from "airweave-connect/lib/connection-utils";
3
+ import { getAppIconUrl as we } from "airweave-connect/lib/icons";
4
+ import { defaultDarkColors as Re, defaultLabels as me, defaultLightColors as Te, defaultOptions as ve } from "airweave-connect/lib/theme-defaults";
5
+ import { jsx as C, jsxs as re, Fragment as P } from "react/jsx-runtime";
6
+ import { useState as k, useEffect as w, useRef as l, useCallback as h } from "react";
7
+ import { createRoot as te } from "react-dom/client";
8
+ function ne({
9
+ connectUrl: c,
10
+ onClose: t,
11
+ onIframeRef: i,
12
+ modalStyle: r,
13
+ showCloseButton: x = !1
14
+ }) {
15
+ const [g, R] = k(!1);
16
+ return w(() => {
17
+ const o = requestAnimationFrame(() => {
18
+ R(!0);
19
+ });
20
+ return () => cancelAnimationFrame(o);
21
+ }, []), w(() => {
22
+ const o = (m) => {
23
+ m.key === "Escape" && t();
24
+ };
25
+ return document.addEventListener("keydown", o), () => document.removeEventListener("keydown", o);
26
+ }, [t]), /* @__PURE__ */ C(
27
+ "div",
28
+ {
29
+ style: {
30
+ position: "fixed",
31
+ top: 0,
32
+ left: 0,
33
+ right: 0,
34
+ bottom: 0,
35
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
36
+ display: "flex",
37
+ alignItems: "center",
38
+ justifyContent: "center",
39
+ zIndex: 1e4,
40
+ opacity: g ? 1 : 0,
41
+ transition: "opacity 0.15s ease-out"
42
+ },
43
+ onClick: (o) => {
44
+ o.target === o.currentTarget && t();
45
+ },
46
+ children: /* @__PURE__ */ re(
47
+ "div",
48
+ {
49
+ style: {
50
+ position: "relative",
51
+ width: (r == null ? void 0 : r.width) ?? "90%",
52
+ maxWidth: (r == null ? void 0 : r.maxWidth) ?? "400px",
53
+ height: (r == null ? void 0 : r.height) ?? "80%",
54
+ maxHeight: (r == null ? void 0 : r.maxHeight) ?? "540px",
55
+ backgroundColor: "white",
56
+ borderRadius: (r == null ? void 0 : r.borderRadius) ?? "16px",
57
+ overflow: "hidden",
58
+ boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
59
+ transform: g ? "scale(1) translateY(0)" : "scale(0.95) translateY(10px)",
60
+ opacity: g ? 1 : 0,
61
+ transition: "transform 0.15s ease-out, opacity 0.15s ease-out"
62
+ },
63
+ children: [
64
+ x && /* @__PURE__ */ C(
65
+ "button",
66
+ {
67
+ onClick: t,
68
+ style: {
69
+ position: "absolute",
70
+ top: 12,
71
+ right: 12,
72
+ width: 32,
73
+ height: 32,
74
+ border: "none",
75
+ background: "rgba(0, 0, 0, 0.1)",
76
+ borderRadius: "50%",
77
+ cursor: "pointer",
78
+ fontSize: 20,
79
+ color: "#666",
80
+ display: "flex",
81
+ alignItems: "center",
82
+ justifyContent: "center",
83
+ zIndex: 10,
84
+ transition: "background 0.2s"
85
+ },
86
+ onMouseEnter: (o) => {
87
+ o.currentTarget.style.background = "rgba(0, 0, 0, 0.2)";
88
+ },
89
+ onMouseLeave: (o) => {
90
+ o.currentTarget.style.background = "rgba(0, 0, 0, 0.1)";
91
+ },
92
+ "aria-label": "Close",
93
+ children: "×"
94
+ }
95
+ ),
96
+ /* @__PURE__ */ C(
97
+ "iframe",
98
+ {
99
+ ref: i,
100
+ src: c,
101
+ style: {
102
+ width: "100%",
103
+ height: "100%",
104
+ border: "none"
105
+ },
106
+ title: "Airweave Connect"
107
+ }
108
+ )
109
+ ]
110
+ }
111
+ )
112
+ }
113
+ );
114
+ }
115
+ const oe = "https://connect.airweave.ai";
116
+ function se(c, t) {
117
+ const i = new URL(c);
118
+ return t != null && t.mode && i.searchParams.set("theme", t.mode), i.toString();
119
+ }
120
+ function ce(c) {
121
+ try {
122
+ return new URL(c).origin;
123
+ } catch {
124
+ return c;
125
+ }
126
+ }
127
+ const ie = "airweave-connect-root";
128
+ function ae(c) {
129
+ const {
130
+ getSessionToken: t,
131
+ theme: i,
132
+ connectUrl: r = oe,
133
+ onSuccess: x,
134
+ onError: g,
135
+ onClose: R,
136
+ onConnectionCreated: v,
137
+ onStatusChange: o,
138
+ initialView: m,
139
+ modalStyle: L,
140
+ showCloseButton: _ = !1
141
+ } = c, [E, y] = k(!1), [B, U] = k(!1), [Q, I] = k(null), [J, X] = k(null), D = l(null), N = l(null), u = l(null), a = l(null), T = ce(r), F = l(t);
142
+ F.current = t;
143
+ const d = l({
144
+ onSuccess: x,
145
+ onError: g,
146
+ onClose: R,
147
+ onConnectionCreated: v,
148
+ onStatusChange: o
149
+ });
150
+ d.current = {
151
+ onSuccess: x,
152
+ onError: g,
153
+ onClose: R,
154
+ onConnectionCreated: v,
155
+ onStatusChange: o
156
+ };
157
+ const O = l(i);
158
+ O.current = i;
159
+ const A = l(m);
160
+ A.current = m;
161
+ const f = h(
162
+ (n) => {
163
+ var s, e;
164
+ (e = (s = D.current) == null ? void 0 : s.contentWindow) == null || e.postMessage(n, T);
165
+ },
166
+ [T]
167
+ ), p = h(
168
+ (n = "cancel") => {
169
+ var s, e;
170
+ y(!1), N.current = null, (e = (s = d.current).onClose) == null || e.call(s, n);
171
+ },
172
+ []
173
+ );
174
+ w(() => {
175
+ if (!E) return;
176
+ const n = (s) => {
177
+ var b, V, j, H, K, q, z, G;
178
+ if (s.origin !== T)
179
+ return;
180
+ const e = s.data;
181
+ if (!(!e || typeof e != "object" || !("type" in e)))
182
+ switch (e.type) {
183
+ case "CONNECT_READY":
184
+ A.current && f({ type: "NAVIGATE", view: A.current });
185
+ break;
186
+ case "REQUEST_TOKEN": {
187
+ const W = e.requestId;
188
+ F.current().then((Y) => {
189
+ N.current = Y, f({
190
+ type: "TOKEN_RESPONSE",
191
+ requestId: W,
192
+ token: Y,
193
+ theme: O.current
194
+ });
195
+ }).catch(() => {
196
+ f({
197
+ type: "TOKEN_ERROR",
198
+ requestId: W,
199
+ error: "Failed to refresh session token"
200
+ });
201
+ });
202
+ break;
203
+ }
204
+ case "STATUS_CHANGE":
205
+ X(e.status), (V = (b = d.current).onStatusChange) == null || V.call(b, e.status), e.status.status === "error" && (I(e.status.error), (H = (j = d.current).onError) == null || H.call(j, e.status.error));
206
+ break;
207
+ case "CONNECTION_CREATED":
208
+ (q = (K = d.current).onConnectionCreated) == null || q.call(K, e.connectionId), (G = (z = d.current).onSuccess) == null || G.call(z, e.connectionId);
209
+ break;
210
+ case "CLOSE":
211
+ p(e.reason);
212
+ break;
213
+ }
214
+ };
215
+ return window.addEventListener("message", n), () => window.removeEventListener("message", n);
216
+ }, [E, p, f, T]);
217
+ const M = se(r, i);
218
+ w(() => {
219
+ E ? (a.current || (a.current = document.createElement("div"), a.current.id = ie, document.body.appendChild(a.current)), u.current || (u.current = te(a.current)), u.current.render(
220
+ /* @__PURE__ */ C(
221
+ ne,
222
+ {
223
+ connectUrl: M,
224
+ onClose: () => p("cancel"),
225
+ onIframeRef: (n) => {
226
+ D.current = n;
227
+ },
228
+ modalStyle: L,
229
+ showCloseButton: _
230
+ }
231
+ )
232
+ )) : u.current && u.current.render(/* @__PURE__ */ C(P, {}));
233
+ }, [E, M, p, L, _]), w(() => () => {
234
+ u.current && (u.current.unmount(), u.current = null), a.current && a.current.parentNode && (a.current.parentNode.removeChild(a.current), a.current = null);
235
+ }, []);
236
+ const Z = h(async () => {
237
+ var n, s;
238
+ U(!0), I(null);
239
+ try {
240
+ const e = await t();
241
+ N.current = e, y(!0);
242
+ } catch (e) {
243
+ const b = {
244
+ code: "network_error",
245
+ message: e instanceof Error ? e.message : "Failed to get session token"
246
+ };
247
+ I(b), (s = (n = d.current).onError) == null || s.call(n, b);
248
+ } finally {
249
+ U(!1);
250
+ }
251
+ }, [t]), $ = h(() => {
252
+ p("cancel");
253
+ }, [p]), S = h(
254
+ (n) => {
255
+ O.current = n, f({ type: "SET_THEME", theme: n });
256
+ },
257
+ [f]
258
+ ), ee = h(
259
+ (n) => {
260
+ f({ type: "NAVIGATE", view: n });
261
+ },
262
+ [f]
263
+ );
264
+ return {
265
+ open: Z,
266
+ close: $,
267
+ setTheme: S,
268
+ navigate: ee,
269
+ isOpen: E,
270
+ isLoading: B,
271
+ error: Q,
272
+ status: J
273
+ };
274
+ }
275
+ function de({
276
+ children: c,
277
+ ...t
278
+ }) {
279
+ const i = ae(t);
280
+ return /* @__PURE__ */ C(P, { children: c(i) });
281
+ }
282
+ export {
283
+ de as AirweaveConnect,
284
+ oe as DEFAULT_CONNECT_URL,
285
+ Ce as canConnect,
286
+ Re as defaultDarkColors,
287
+ me as defaultLabels,
288
+ Te as defaultLightColors,
289
+ ve as defaultOptions,
290
+ we as getAppIconUrl,
291
+ Ee as getStatusColor,
292
+ be as getStatusLabel,
293
+ ae as useAirweaveConnect
294
+ };
295
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/ConnectModal.tsx","../src/constants.ts","../src/iframeUrl.ts","../src/useAirweaveConnect.tsx","../src/AirweaveConnect.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { ModalStyle } from \"./useAirweaveConnect\";\n\ninterface ConnectModalProps {\n connectUrl: string;\n onClose: () => void;\n onIframeRef: (iframe: HTMLIFrameElement | null) => void;\n modalStyle?: ModalStyle;\n showCloseButton?: boolean;\n}\n\nexport function ConnectModal({\n connectUrl,\n onClose,\n onIframeRef,\n modalStyle,\n showCloseButton = false,\n}: ConnectModalProps) {\n const [isVisible, setIsVisible] = useState(false);\n\n // Trigger entry animation after mount\n useEffect(() => {\n // Small delay to ensure the initial styles are applied before transitioning\n const timer = requestAnimationFrame(() => {\n setIsVisible(true);\n });\n return () => cancelAnimationFrame(timer);\n }, []);\n\n // Handle ESC key\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n onClose();\n }\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [onClose]);\n\n // Handle click outside\n const handleOverlayClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n onClose();\n }\n };\n\n return (\n <div\n style={{\n position: \"fixed\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: \"rgba(0, 0, 0, 0.5)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n zIndex: 10000,\n opacity: isVisible ? 1 : 0,\n transition: \"opacity 0.15s ease-out\",\n }}\n onClick={handleOverlayClick}\n >\n <div\n style={{\n position: \"relative\",\n width: modalStyle?.width ?? \"90%\",\n maxWidth: modalStyle?.maxWidth ?? \"400px\",\n height: modalStyle?.height ?? \"80%\",\n maxHeight: modalStyle?.maxHeight ?? \"540px\",\n backgroundColor: \"white\",\n borderRadius: modalStyle?.borderRadius ?? \"16px\",\n overflow: \"hidden\",\n boxShadow: \"0 25px 50px -12px rgba(0, 0, 0, 0.25)\",\n transform: isVisible\n ? \"scale(1) translateY(0)\"\n : \"scale(0.95) translateY(10px)\",\n opacity: isVisible ? 1 : 0,\n transition: \"transform 0.15s ease-out, opacity 0.15s ease-out\",\n }}\n >\n {showCloseButton && (\n <button\n onClick={onClose}\n style={{\n position: \"absolute\",\n top: 12,\n right: 12,\n width: 32,\n height: 32,\n border: \"none\",\n background: \"rgba(0, 0, 0, 0.1)\",\n borderRadius: \"50%\",\n cursor: \"pointer\",\n fontSize: 20,\n color: \"#666\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n zIndex: 10,\n transition: \"background 0.2s\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.background = \"rgba(0, 0, 0, 0.2)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.background = \"rgba(0, 0, 0, 0.1)\";\n }}\n aria-label=\"Close\"\n >\n ×\n </button>\n )}\n <iframe\n ref={onIframeRef}\n src={connectUrl}\n style={{\n width: \"100%\",\n height: \"100%\",\n border: \"none\",\n }}\n title=\"Airweave Connect\"\n />\n </div>\n </div>\n );\n}\n","export const DEFAULT_CONNECT_URL = \"https://connect.airweave.ai\";\n","import type { ConnectTheme } from \"airweave-connect/lib/types\";\n\n/**\n * Builds the iframe URL with theme query parameter.\n */\nexport function buildIframeUrl(connectUrl: string, theme?: ConnectTheme): string {\n const url = new URL(connectUrl);\n if (theme?.mode) {\n url.searchParams.set(\"theme\", theme.mode);\n }\n return url.toString();\n}\n\n/**\n * Derives the expected origin from a connect URL for secure postMessage validation.\n */\nexport function getExpectedOrigin(connectUrl: string): string {\n try {\n const url = new URL(connectUrl);\n return url.origin;\n } catch {\n // Fallback for invalid URLs - will cause postMessage to fail safely\n return connectUrl;\n }\n}\n","import type {\n ChildToParentMessage,\n ConnectTheme,\n NavigateView,\n ParentToChildMessage,\n SessionError,\n SessionStatus,\n} from \"airweave-connect/lib/types\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { createRoot, Root } from \"react-dom/client\";\nimport { ConnectModal } from \"./ConnectModal\";\nimport { DEFAULT_CONNECT_URL } from \"./constants\";\nimport { buildIframeUrl, getExpectedOrigin } from \"./iframeUrl\";\nimport type {\n UseAirweaveConnectOptions,\n UseAirweaveConnectReturn,\n} from \"./useAirweaveConnect.types\";\n\n// Re-export types for consumers\nexport type { ModalStyle, UseAirweaveConnectOptions, UseAirweaveConnectReturn } from \"./useAirweaveConnect.types\";\n\nconst CONTAINER_ID = \"airweave-connect-root\";\n\nexport function useAirweaveConnect(\n options: UseAirweaveConnectOptions,\n): UseAirweaveConnectReturn {\n const {\n getSessionToken,\n theme,\n connectUrl = DEFAULT_CONNECT_URL,\n onSuccess,\n onError,\n onClose,\n onConnectionCreated,\n onStatusChange,\n initialView,\n modalStyle,\n showCloseButton = false,\n } = options;\n\n const [isOpen, setIsOpen] = useState(false);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<SessionError | null>(null);\n const [status, setStatus] = useState<SessionStatus | null>(null);\n\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const sessionTokenRef = useRef<string | null>(null);\n const rootRef = useRef<Root | null>(null);\n const containerRef = useRef<HTMLDivElement | null>(null);\n\n // Derive expected origin from connectUrl for secure postMessage\n const expectedOrigin = getExpectedOrigin(connectUrl);\n\n // Store callbacks and getSessionToken in refs to avoid re-creating message handler\n const getSessionTokenRef = useRef(getSessionToken);\n getSessionTokenRef.current = getSessionToken;\n\n const callbacksRef = useRef({\n onSuccess,\n onError,\n onClose,\n onConnectionCreated,\n onStatusChange,\n });\n callbacksRef.current = {\n onSuccess,\n onError,\n onClose,\n onConnectionCreated,\n onStatusChange,\n };\n\n // Store theme in ref to use in message handler\n const themeRef = useRef(theme);\n themeRef.current = theme;\n\n // Store initialView in ref to use on CONNECT_READY\n const initialViewRef = useRef(initialView);\n initialViewRef.current = initialView;\n\n // Send message to iframe with restricted origin\n const sendToIframe = useCallback(\n (message: ParentToChildMessage) => {\n iframeRef.current?.contentWindow?.postMessage(message, expectedOrigin);\n },\n [expectedOrigin],\n );\n\n const handleClose = useCallback(\n (reason: \"success\" | \"cancel\" | \"error\" = \"cancel\") => {\n setIsOpen(false);\n sessionTokenRef.current = null;\n callbacksRef.current.onClose?.(reason);\n },\n [],\n );\n\n // Handle messages from iframe\n useEffect(() => {\n if (!isOpen) return;\n\n const handleMessage = (event: MessageEvent) => {\n // Validate origin to prevent spoofed messages from malicious sites\n if (event.origin !== expectedOrigin) {\n return;\n }\n\n const data = event.data as ChildToParentMessage;\n if (!data || typeof data !== \"object\" || !(\"type\" in data)) {\n return;\n }\n\n switch (data.type) {\n case \"CONNECT_READY\":\n // Iframe is ready - navigate to initial view if specified\n if (initialViewRef.current) {\n sendToIframe({ type: \"NAVIGATE\", view: initialViewRef.current });\n }\n break;\n\n case \"REQUEST_TOKEN\": {\n // Re-fetch token from the customer's backend to handle expiry/refresh\n const requestId = data.requestId;\n getSessionTokenRef\n .current()\n .then((token) => {\n sessionTokenRef.current = token;\n sendToIframe({\n type: \"TOKEN_RESPONSE\",\n requestId,\n token,\n theme: themeRef.current,\n });\n })\n .catch(() => {\n sendToIframe({\n type: \"TOKEN_ERROR\",\n requestId,\n error: \"Failed to refresh session token\",\n });\n });\n break;\n }\n\n case \"STATUS_CHANGE\":\n setStatus(data.status);\n callbacksRef.current.onStatusChange?.(data.status);\n\n if (data.status.status === \"error\") {\n setError(data.status.error);\n callbacksRef.current.onError?.(data.status.error);\n }\n break;\n\n case \"CONNECTION_CREATED\":\n callbacksRef.current.onConnectionCreated?.(data.connectionId);\n callbacksRef.current.onSuccess?.(data.connectionId);\n break;\n\n case \"CLOSE\":\n handleClose(data.reason);\n break;\n }\n };\n\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [isOpen, handleClose, sendToIframe, expectedOrigin]);\n\n // Build the iframe URL with theme query parameter\n const iframeUrl = buildIframeUrl(connectUrl, theme);\n\n // Manage modal rendering via createRoot\n useEffect(() => {\n if (isOpen) {\n // Create container if it doesn't exist\n if (!containerRef.current) {\n containerRef.current = document.createElement(\"div\");\n containerRef.current.id = CONTAINER_ID;\n document.body.appendChild(containerRef.current);\n }\n\n // Create root if it doesn't exist\n if (!rootRef.current) {\n rootRef.current = createRoot(containerRef.current);\n }\n\n // Render modal\n rootRef.current.render(\n <ConnectModal\n connectUrl={iframeUrl}\n onClose={() => handleClose(\"cancel\")}\n onIframeRef={(iframe) => {\n iframeRef.current = iframe;\n }}\n modalStyle={modalStyle}\n showCloseButton={showCloseButton}\n />,\n );\n } else {\n // Unmount modal\n if (rootRef.current) {\n rootRef.current.render(<></>);\n }\n }\n }, [isOpen, iframeUrl, handleClose, modalStyle, showCloseButton]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (rootRef.current) {\n rootRef.current.unmount();\n rootRef.current = null;\n }\n if (containerRef.current && containerRef.current.parentNode) {\n containerRef.current.parentNode.removeChild(containerRef.current);\n containerRef.current = null;\n }\n };\n }, []);\n\n const open = useCallback(async () => {\n setIsLoading(true);\n setError(null);\n\n try {\n const token = await getSessionToken();\n sessionTokenRef.current = token;\n setIsOpen(true);\n } catch (err) {\n const sessionError: SessionError = {\n code: \"network_error\",\n message:\n err instanceof Error ? err.message : \"Failed to get session token\",\n };\n setError(sessionError);\n callbacksRef.current.onError?.(sessionError);\n } finally {\n setIsLoading(false);\n }\n }, [getSessionToken]);\n\n const close = useCallback(() => {\n handleClose(\"cancel\");\n }, [handleClose]);\n\n const setTheme = useCallback(\n (newTheme: ConnectTheme) => {\n themeRef.current = newTheme;\n sendToIframe({ type: \"SET_THEME\", theme: newTheme });\n },\n [sendToIframe],\n );\n\n const navigate = useCallback(\n (view: NavigateView) => {\n sendToIframe({ type: \"NAVIGATE\", view });\n },\n [sendToIframe],\n );\n\n return {\n open,\n close,\n setTheme,\n navigate,\n isOpen,\n isLoading,\n error,\n status,\n };\n}\n","import type { ReactNode } from \"react\";\nimport {\n useAirweaveConnect,\n type UseAirweaveConnectOptions,\n type UseAirweaveConnectReturn,\n} from \"./useAirweaveConnect\";\n\ntype RenderProps = UseAirweaveConnectReturn;\n\nexport interface AirweaveConnectProps extends UseAirweaveConnectOptions {\n /**\n * Render prop that receives all hook return values.\n * Use this to render your trigger button or any custom UI.\n *\n * @example\n * ```tsx\n * <AirweaveConnect getSessionToken={fetchToken}>\n * {({ open, isLoading }) => (\n * <button onClick={open} disabled={isLoading}>\n * {isLoading ? \"Loading...\" : \"Connect\"}\n * </button>\n * )}\n * </AirweaveConnect>\n * ```\n */\n children: (props: RenderProps) => ReactNode;\n}\n\n/**\n * A component wrapper for the useAirweaveConnect hook.\n * Provides a simpler API for common use cases.\n *\n * @example\n * ```tsx\n * // Simple usage\n * <AirweaveConnect\n * getSessionToken={async () => {\n * const res = await fetch(\"/api/connect-session\");\n * const data = await res.json();\n * return data.session_token;\n * }}\n * onSuccess={(connectionId) => {\n * console.log(\"New connection:\", connectionId);\n * }}\n * >\n * {({ open, isLoading }) => (\n * <button onClick={open} disabled={isLoading}>\n * {isLoading ? \"Connecting...\" : \"Connect Apps\"}\n * </button>\n * )}\n * </AirweaveConnect>\n *\n * // With all features\n * <AirweaveConnect\n * getSessionToken={fetchToken}\n * initialView=\"sources\"\n * showCloseButton\n * modalStyle={{ maxWidth: \"600px\" }}\n * onSuccess={handleSuccess}\n * onClose={(reason) => console.log(\"Closed:\", reason)}\n * >\n * {({ open, isLoading, isOpen, navigate }) => (\n * <div>\n * <button onClick={open} disabled={isLoading || isOpen}>\n * {isLoading ? \"Preparing...\" : \"Connect Apps\"}\n * </button>\n * {isOpen && (\n * <button onClick={() => navigate(\"sources\")}>\n * Browse Sources\n * </button>\n * )}\n * </div>\n * )}\n * </AirweaveConnect>\n * ```\n */\nexport function AirweaveConnect({\n children,\n ...hookOptions\n}: AirweaveConnectProps) {\n const hookReturn = useAirweaveConnect(hookOptions);\n return <>{children(hookReturn)}</>;\n}\n"],"names":["ConnectModal","connectUrl","onClose","onIframeRef","modalStyle","showCloseButton","isVisible","setIsVisible","useState","useEffect","timer","handleKeyDown","e","jsx","jsxs","DEFAULT_CONNECT_URL","buildIframeUrl","theme","url","getExpectedOrigin","CONTAINER_ID","useAirweaveConnect","options","getSessionToken","onSuccess","onError","onConnectionCreated","onStatusChange","initialView","isOpen","setIsOpen","isLoading","setIsLoading","error","setError","status","setStatus","iframeRef","useRef","sessionTokenRef","rootRef","containerRef","expectedOrigin","getSessionTokenRef","callbacksRef","themeRef","initialViewRef","sendToIframe","useCallback","message","_b","_a","handleClose","reason","handleMessage","event","data","requestId","token","_d","_c","_f","_e","_h","_g","iframeUrl","createRoot","iframe","Fragment","open","err","sessionError","close","setTheme","newTheme","navigate","view","AirweaveConnect","children","hookOptions","hookReturn"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@airweave/connect-react",
3
+ "version": "0.9.27",
4
+ "description": "React hook for Airweave Connect",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "sideEffects": false,
25
+ "scripts": {
26
+ "dev": "vite build --watch",
27
+ "build": "tsc && vite build",
28
+ "lint": "eslint .",
29
+ "prepublishOnly": "npm run build"
30
+ },
31
+ "peerDependencies": {
32
+ "react": ">=19.0.0",
33
+ "react-dom": ">=19.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "airweave-connect": "file:../..",
37
+ "@types/react": "^19.2.0",
38
+ "@types/react-dom": "^19.2.0",
39
+ "@vitejs/plugin-react": "^4.5.2",
40
+ "react": "^19.2.0",
41
+ "react-dom": "^19.2.0",
42
+ "typescript": "^5.8.3",
43
+ "vite": "^6.3.5",
44
+ "vite-plugin-dts": "^4.5.4"
45
+ },
46
+ "keywords": [
47
+ "airweave",
48
+ "connect",
49
+ "react",
50
+ "integrations",
51
+ "oauth"
52
+ ],
53
+ "license": "MIT",
54
+ "repository": {
55
+ "type": "git",
56
+ "url": "https://github.com/airweave-ai/airweave"
57
+ },
58
+ "publishConfig": {
59
+ "access": "public"
60
+ }
61
+ }