@uraiagent/react 0.0.4 → 0.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.
@@ -1,68 +1,197 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { HandoffPayloadType } from '.';
3
3
  import { ComponentType } from './components';
4
+ /**
5
+ * The end user chatting with the widget.
6
+ *
7
+ * Provide this only when you have an identified (logged-in) user. If omitted,
8
+ * the session is treated as anonymous. When supplied, `name` and `email` are
9
+ * required so the conversation can be attributed and followed up on; `phone`
10
+ * and everything else is optional.
11
+ */
4
12
  type User = {
5
- name?: string;
6
- email?: string;
7
- phone: string;
13
+ /** User's display name. Required when a `user` is provided. */
14
+ name: string;
15
+ /** User's email address. Required when a `user` is provided. */
16
+ email: string;
17
+ /** User's phone number. Optional. */
18
+ phone?: string;
19
+ /** URL of the user's avatar image. Optional. */
8
20
  avatar?: string;
21
+ /** Arbitrary string key/value metadata attached to the user. Optional. */
9
22
  custom?: Record<string, string>;
23
+ /**
24
+ * Identity-verification hash. HMAC-SHA256 of the user's id/email signed with
25
+ * the widget secret, computed on YOUR server (never in the browser). When
26
+ * present the backend verifies it and marks the contact as verified so it
27
+ * can't be impersonated. Optional.
28
+ */
29
+ userHash?: string;
10
30
  };
31
+ /** The agent/brand identity shown on the widget's side of the conversation. */
11
32
  type Agent = {
33
+ /** Agent display name shown in the header. Optional. */
12
34
  name?: string;
35
+ /** URL of the agent's logo/avatar. Optional. */
13
36
  logo?: string;
14
37
  };
15
- type ContainerProps = React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
38
+ /**
39
+ * Host container configuration.
40
+ *
41
+ * Only inline `style` is honored — it is merged onto the widget's host `<div>`
42
+ * (`.uraiagent-root`). Arbitrary div HTML attributes (id, className, event
43
+ * handlers, data-*, …) are intentionally NOT applied, so the widget's markup
44
+ * stays predictable. Retheme via CSS variables (`--uw-*`) instead.
45
+ */
46
+ type ContainerConfig = {
47
+ /** Inline styles merged onto the widget's host `<div>`. Optional. */
48
+ style?: React.CSSProperties;
49
+ };
50
+ /** Default backend API base URL used when `connection.api` is omitted. */
51
+ export declare const DEFAULT_API_BASE_URL = "https://api.uraiagent.com";
52
+ /**
53
+ * Typed design/branding for the widget.
54
+ *
55
+ * Every field is optional. A provided field overrides the stock theme by setting
56
+ * the matching `--uw-*` CSS variable on the widget root (see `designToStyle`);
57
+ * anything omitted keeps its default from `style.css`. This is the shape the
58
+ * dashboard's design editor produces and the backend stores on the widget, so
59
+ * changing it here is a wire contract — keep it in sync across FE ⇆ widget ⇆ API.
60
+ */
61
+ export type WidgetDesign = {
62
+ /** Brand colors (any CSS color string). */
63
+ colors?: {
64
+ /** Primary/brand color — header, launcher, user bubble. `--uw-color-primary`. */
65
+ primary?: string;
66
+ /** Foreground on top of the primary color. `--uw-color-primary-fg`. */
67
+ primaryForeground?: string;
68
+ /** Secondary accent. `--uw-color-accent`. */
69
+ accent?: string;
70
+ /** Body text color. `--uw-color-text`. */
71
+ text?: string;
72
+ /** Panel surface/background. `--uw-surface`. */
73
+ surface?: string;
74
+ };
75
+ /** Corner radius of the panel/controls, in px. `--uw-radius`. */
76
+ radius?: number;
77
+ /** Corner radius of message bubbles, in px. `--uw-radius-bubble`. */
78
+ bubbleRadius?: number;
79
+ /** Typography. */
80
+ font?: {
81
+ /** CSS font-family stack. `--uw-font`. */
82
+ family?: string;
83
+ /** Base font size, in px. `--uw-font-size`. */
84
+ size?: number;
85
+ };
86
+ };
87
+ /**
88
+ * Map a typed {@link WidgetDesign} to the inline `--uw-*` CSS custom properties
89
+ * applied on the widget root. Inline vars beat the zero-specificity
90
+ * `:where(.uraiagent-root)` defaults, so only the fields you set take effect and
91
+ * everything else keeps its stock token. Returns an empty object for empty input.
92
+ */
93
+ export declare function designToStyle(design?: WidgetDesign): React.CSSProperties;
16
94
  /**
17
95
  * Public, grouped widget configuration.
18
96
  *
19
- * Styling is NOT configured here the widget is pure namespaced CSS
20
- * (`.uraiagent-*`) + design tokens (`--uw-*`). Retheme from your own stylesheet
21
- * (e.g. `.uraiagent-root { --uw-color-primary: #6d28d9 }`). So there is no
22
- * `theme.tokens` / `theme.classNames` only the host `container` survives.
97
+ * Branding lives in `design` (typed `--uw-*` overrides, applied on the root). You
98
+ * can still retheme purely from your own stylesheet (`.uraiagent-root {
99
+ * --uw-color-primary: #6d28d9 }`) `design` is just the ergonomic, typed path and
100
+ * wins over the stock defaults. Only the host `container` survives beyond that.
23
101
  */
24
102
  export type WidgetConfig = {
103
+ /** Identifiers that bind the widget to a dashboard-configured agent. Required. */
25
104
  identity: {
26
- /** Widget ID from the dashboard. */
105
+ /** Widget embed token from the dashboard. Required. */
27
106
  token: string;
28
- organizationId: string;
29
- agentId: string;
107
+ /**
108
+ * Organization ID that owns the widget. Optional — resolved from the token via
109
+ * `GET /chat/config` on load. Provide it only to skip/override the remote lookup.
110
+ */
111
+ organizationId?: string;
112
+ /**
113
+ * Agent ID that conversations are routed to. Optional — resolved from the token via
114
+ * `GET /chat/config` on load. Provide it only to skip/override the remote lookup.
115
+ */
116
+ agentId?: string;
30
117
  };
118
+ /** Backend connection settings. Required (but every field has a sensible default). */
31
119
  connection: {
32
- /** Backend API base URL, e.g. "https://api.example.com". */
33
- api: string;
120
+ /**
121
+ * Backend API base URL, e.g. "https://api.example.com".
122
+ * Optional — defaults to `https://api.uraiagent.com` when omitted.
123
+ */
124
+ api?: string;
125
+ /** Extra HTTP headers sent with every widget API request. Optional. */
34
126
  headers?: Record<string, string>;
127
+ /** Extra query-string params appended to widget API requests. Optional. */
35
128
  queryParams?: Record<string, string>;
36
129
  };
130
+ /** Copy and content shown inside the widget. Optional. */
37
131
  content?: {
132
+ /** Message shown when the conversation first opens. Optional. */
38
133
  initialMessage?: string;
134
+ /** Placeholder text for the message input. Optional. */
39
135
  inputPlaceholder?: string;
136
+ /** Sub-header description block. Optional. */
40
137
  description?: {
138
+ /** Whether the description is visible. Optional. */
41
139
  visible?: boolean;
140
+ /** The description text. Optional. */
42
141
  text?: string;
43
142
  };
44
- /** Custom node rendered inside the trigger button. */
143
+ /** Custom node rendered inside the trigger button. Optional. */
45
144
  triggerIcon?: ReactNode;
46
145
  };
146
+ /** Runtime behavior toggles. Optional. */
47
147
  behavior?: {
148
+ /** Open the widget automatically on load. Optional (default: false). */
48
149
  defaultOpen?: boolean;
150
+ /** Close the widget when the user clicks outside it. Optional (default: true). */
49
151
  closeOutside?: boolean;
152
+ /** Enable verbose debug logging. Optional (default: false). */
50
153
  debug?: boolean;
154
+ /** Enable non-fatal configuration warnings. Optional. */
51
155
  warn?: boolean;
156
+ /** UI language code, e.g. "en", "fr". Optional (falls back to browser/default locale). */
52
157
  language?: string;
158
+ /**
159
+ * Preview/offline mode. When true the widget renders from the given config
160
+ * WITHOUT binding to the backend: no `GET /chat/config` lookup, no session
161
+ * creation, no realtime socket. Use it to render a live, inert preview (e.g.
162
+ * the dashboard design editor). Optional (default: false). Not for production.
163
+ */
164
+ preview?: boolean;
53
165
  };
166
+ /**
167
+ * Typed design/branding overrides. Optional. Wins over the stock theme and over
168
+ * the remote design resolved from `GET /chat/config`.
169
+ */
170
+ design?: WidgetDesign;
171
+ /** Participants in the conversation. Optional. */
54
172
  people?: {
173
+ /**
174
+ * The identified end user. Optional — omit for an anonymous session.
175
+ * When provided, `name` and `email` are required.
176
+ */
55
177
  user?: User;
178
+ /** The agent/brand identity. Optional. */
56
179
  agent?: Agent;
57
180
  };
181
+ /** Lifecycle event callbacks. Optional. */
58
182
  on?: {
183
+ /** Called when the widget is closed. Optional. */
59
184
  close?: () => void;
185
+ /** Called when the conversation is handed off to a human. Optional. */
60
186
  handoff?: (handout: HandoffPayloadType) => void;
61
187
  };
62
- /** Custom message/event components. */
188
+ /** Custom message/event components. Optional. */
63
189
  components?: ComponentType[];
64
- /** Props spread onto the widget's host container <div>. */
65
- container?: ContainerProps;
190
+ /**
191
+ * Host container configuration. Optional.
192
+ * Only `style` is applied to the widget's host `<div>`.
193
+ */
194
+ container?: ContainerConfig;
66
195
  };
67
196
  /**
68
197
  * Flat, resolved config — the shape every internal component reads via
@@ -72,6 +201,10 @@ export type OptionsProps = {
72
201
  token: string;
73
202
  organizationId: string;
74
203
  agentId: string;
204
+ /** Typed design/branding — from props or resolved from `GET /chat/config`. */
205
+ design?: WidgetDesign;
206
+ /** Preview/offline mode: render from config without binding to the backend. */
207
+ preview?: boolean;
75
208
  api: string;
76
209
  headers?: Record<string, string>;
77
210
  queryParams?: Record<string, string>;
@@ -92,7 +225,7 @@ export type OptionsProps = {
92
225
  components?: ComponentType[];
93
226
  onClose?: () => void;
94
227
  onHandoff?: (handout: HandoffPayloadType) => void;
95
- container?: ContainerProps;
228
+ container?: ContainerConfig;
96
229
  };
97
230
  /** Flatten the grouped public config into the internal flat shape. */
98
231
  export declare function normalizeConfig(c: WidgetConfig): OptionsProps;
@@ -7,6 +7,15 @@ export type Meta = {
7
7
  has_next: boolean;
8
8
  has_previous: boolean;
9
9
  };
10
+ /** A file attached to a message (uploaded via POST /chat/upload). `url` is a permanent public URL
11
+ * (object stored public-read under an unguessable randomized key). */
12
+ export type AttachmentRef = {
13
+ id: string;
14
+ url: string;
15
+ filename: string;
16
+ mimeType: string;
17
+ size: number;
18
+ };
10
19
  export type AgentMessageProps<TData = Record<string, unknown>> = {
11
20
  _id: string;
12
21
  from: "agent";
@@ -14,20 +23,14 @@ export type AgentMessageProps<TData = Record<string, unknown>> = {
14
23
  data: TData;
15
24
  senderName?: string;
16
25
  senderAvatarUrl?: string;
17
- attachement?: {
18
- type: string;
19
- value: string;
20
- };
26
+ attachments?: AttachmentRef[];
21
27
  createdAt: string;
22
28
  };
23
29
  export type UserMessageProps = {
24
30
  _id: string;
25
31
  from: "user";
26
32
  message: string;
27
- attachement?: {
28
- type: string;
29
- value: string;
30
- };
33
+ attachments?: AttachmentRef[];
31
34
  createdAt: string;
32
35
  };
33
36
  export type EventMessageProps<TData = Record<string, unknown>> = {
@@ -0,0 +1,32 @@
1
+ import { ReactNode } from 'react';
2
+ import { AgentEventName, IdentifyInput } from './agent-store';
3
+ export interface AgentApi {
4
+ /** Stable anonymous visitor id (localStorage). */
5
+ visitorId: string;
6
+ /** Merge identity + link the visitor to a contact (optionally verified). */
7
+ identify: (user: IdentifyInput) => Promise<void>;
8
+ /** Record a custom activity event. */
9
+ track: (name: string, data?: Record<string, unknown>) => void;
10
+ /** Open the widget. */
11
+ open: () => void;
12
+ /** Close the widget. */
13
+ close: () => void;
14
+ /** Send a message (creating a conversation if needed). */
15
+ sendMessage: (text: string) => Promise<void>;
16
+ /** Subscribe to widget lifecycle events. Returns an unsubscribe fn. */
17
+ on: (event: AgentEventName, cb: (payload?: unknown) => void) => () => void;
18
+ }
19
+ /**
20
+ * Wrap your app in this to (a) capture visitor activity and (b) use
21
+ * `useAgent()` anywhere. It does NOT own widget config — render the widget
22
+ * (`<AgentWidget config={…} />`) as usual; config stays on the widget. This
23
+ * provider only adds the activity + imperative SDK layer, bridged through the
24
+ * shared store.
25
+ */
26
+ export declare function AgentProvider({ children }: {
27
+ children: ReactNode;
28
+ }): import("react/jsx-runtime").JSX.Element;
29
+ /**
30
+ * Access the widget SDK. Must be used inside `<AgentProvider>`.
31
+ */
32
+ export declare function useAgent(): AgentApi;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Invisible bridge rendered inside Root. Feeds the singleton store the config
3
+ * Root already resolved (so config stays on Root) and registers the imperative
4
+ * controls the SDK exposes via `useAgent`.
5
+ */
6
+ export declare function AgentControls(): null;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Start framework-agnostic activity capture: sessionStarted, initial + SPA
3
+ * pageViews (via a history.pushState monkey-patch), and unload flushing.
4
+ * Returns a cleanup fn that restores history and removes listeners.
5
+ */
6
+ export declare function startActivityCapture(): () => void;
@@ -0,0 +1,59 @@
1
+ import { StoredIdentity } from '../contexts/identity/identity.storage';
2
+ export interface ActivityEvent {
3
+ name: string;
4
+ date: string;
5
+ data?: Record<string, unknown>;
6
+ }
7
+ export type IdentifyInput = {
8
+ email?: string;
9
+ name?: string;
10
+ phone?: string;
11
+ userHash?: string;
12
+ custom?: Record<string, string>;
13
+ };
14
+ /** Imperative hooks the widget (inside Root) registers so the SDK can drive it. */
15
+ export interface AgentControls {
16
+ open: () => void;
17
+ close: () => void;
18
+ sendMessage: (text: string) => Promise<void>;
19
+ }
20
+ export type AgentEventName = "open" | "close" | "message" | "handoff";
21
+ type Listener = (payload?: unknown) => void;
22
+ /**
23
+ * Process-wide singleton bridging the host app (via `useAgent`) and the
24
+ * widget (mounted inside `Root`). Root feeds it the connection config + controls;
25
+ * the SDK provider feeds it activity. Config stays on Root — the store just
26
+ * receives what Root already resolved.
27
+ */
28
+ declare class AgentStore {
29
+ private api?;
30
+ private organizationId?;
31
+ private visitorId?;
32
+ private token?;
33
+ private controls;
34
+ private buffer;
35
+ private timer;
36
+ private startedAt;
37
+ private readonly listeners;
38
+ /** Called by Root once config + identity resolve. Idempotent. */
39
+ configure(cfg: {
40
+ api: string;
41
+ organizationId: string;
42
+ visitorId: string;
43
+ token?: string;
44
+ }): void;
45
+ getVisitorId(): string;
46
+ attachControls(controls: AgentControls): void;
47
+ detachControls(controls: AgentControls): void;
48
+ track(name: string, data?: Record<string, unknown>): void;
49
+ /** Send buffered events. `useBeacon` for unload (best-effort, keepalive). */
50
+ flush(useBeacon?: boolean): Promise<void>;
51
+ open(): void;
52
+ close(): void;
53
+ sendMessage(text: string): Promise<void>;
54
+ identify(input: IdentifyInput): Promise<StoredIdentity>;
55
+ on(event: AgentEventName, cb: Listener): () => void;
56
+ emit(event: AgentEventName, payload?: unknown): void;
57
+ }
58
+ export declare const agentStore: AgentStore;
59
+ export {};
@@ -0,0 +1,5 @@
1
+ export { AgentProvider, useAgent } from './AgentContext';
2
+ export type { AgentApi } from './AgentContext';
3
+ export { AgentControls } from './AgentControls';
4
+ export { agentStore } from './agent-store';
5
+ export type { ActivityEvent, AgentEventName, IdentifyInput, } from './agent-store';
@@ -78,7 +78,6 @@ declare const get: <K extends keyof typeof json>(key: K) => {
78
78
  nanoid: string;
79
79
  "pusher-js": string;
80
80
  "react-markdown": string;
81
- "react-textarea-autosize": string;
82
81
  "remark-gfm": string;
83
82
  zod: string;
84
83
  };