@firstflow/react 0.0.1
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 +315 -0
- package/dist/index.css +360 -0
- package/dist/index.d.mts +668 -0
- package/dist/index.d.ts +668 -0
- package/dist/index.js +1812 -0
- package/dist/index.mjs +1754 -0
- package/package.json +49 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React, { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface CreateFirstflowOptions {
|
|
5
|
+
agentId: string;
|
|
6
|
+
apiUrl: string;
|
|
7
|
+
/** Jitsu host for analytics; defaults to shared Firstflow Jitsu if omitted */
|
|
8
|
+
jitsuHost?: string;
|
|
9
|
+
/** Jitsu write key for analytics; defaults to shared key if omitted */
|
|
10
|
+
jitsuWriteKey?: string;
|
|
11
|
+
/** When set without fetchConfig, seeds message feedback UI (agents.feedback_config shape). */
|
|
12
|
+
feedbackConfig?: RawFeedbackConfig | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Public API for the issue module only (open, submit, getConfig, destroy).
|
|
16
|
+
* Internal wiring (setConfig, setOpenHandler) is not exposed.
|
|
17
|
+
*/
|
|
18
|
+
interface IssueModulePublic {
|
|
19
|
+
open(options?: OpenOptions): void;
|
|
20
|
+
submit(data: IssueReportData): Promise<void>;
|
|
21
|
+
getConfig(): NormalizedConfig;
|
|
22
|
+
destroy(): void;
|
|
23
|
+
}
|
|
24
|
+
/** Analytics API exposed on the platform instance. Used by all feature modules. */
|
|
25
|
+
interface AnalyticsModulePublic {
|
|
26
|
+
track(eventName: string, properties?: Record<string, unknown>): void;
|
|
27
|
+
identify(userId?: string, traits?: Record<string, unknown>): void;
|
|
28
|
+
page(name?: string, properties?: Record<string, unknown>): void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Root platform instance: agent identity, analytics, and feature modules.
|
|
32
|
+
* Represents the runtime context for this agent at this API.
|
|
33
|
+
*/
|
|
34
|
+
interface FirstflowInstance {
|
|
35
|
+
readonly agentId: string;
|
|
36
|
+
readonly apiUrl: string;
|
|
37
|
+
analytics: AnalyticsModulePublic;
|
|
38
|
+
issue: IssueModulePublic;
|
|
39
|
+
feedback: FeedbackModulePublic;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Raw issues config as received from API (e.g. agent.issues_config).
|
|
43
|
+
*/
|
|
44
|
+
interface RawIssueFieldConfig {
|
|
45
|
+
id?: string;
|
|
46
|
+
allowed?: boolean;
|
|
47
|
+
label?: string;
|
|
48
|
+
type?: "text" | "textarea" | "select";
|
|
49
|
+
required?: boolean;
|
|
50
|
+
options?: string[];
|
|
51
|
+
}
|
|
52
|
+
interface RawIssuesConfig {
|
|
53
|
+
enabled?: boolean;
|
|
54
|
+
promptText?: string;
|
|
55
|
+
fields?: RawIssueFieldConfig[];
|
|
56
|
+
}
|
|
57
|
+
interface RawFeedbackFormConfig {
|
|
58
|
+
tags?: string[];
|
|
59
|
+
heading?: string;
|
|
60
|
+
placeholder?: string;
|
|
61
|
+
showTags?: boolean;
|
|
62
|
+
showComment?: boolean;
|
|
63
|
+
}
|
|
64
|
+
interface RawFeedbackConfig {
|
|
65
|
+
enabled?: boolean;
|
|
66
|
+
like?: RawFeedbackFormConfig;
|
|
67
|
+
dislike?: RawFeedbackFormConfig;
|
|
68
|
+
}
|
|
69
|
+
interface NormalizedFeedbackFormConfig {
|
|
70
|
+
tags: string[];
|
|
71
|
+
heading: string;
|
|
72
|
+
placeholder: string;
|
|
73
|
+
showTags: boolean;
|
|
74
|
+
showComment: boolean;
|
|
75
|
+
}
|
|
76
|
+
interface NormalizedFeedbackConfig {
|
|
77
|
+
enabled: boolean;
|
|
78
|
+
like: NormalizedFeedbackFormConfig;
|
|
79
|
+
dislike: NormalizedFeedbackFormConfig;
|
|
80
|
+
}
|
|
81
|
+
interface MessageFeedbackSubmitPayload {
|
|
82
|
+
conversationId: string;
|
|
83
|
+
messageId: string;
|
|
84
|
+
rating: "like" | "dislike";
|
|
85
|
+
/** Used by MessageFeedback UI only; not included on the Jitsu event. */
|
|
86
|
+
tags?: string[];
|
|
87
|
+
comment?: string;
|
|
88
|
+
/** Mirrors config: whether tags/comment were enabled for this sentiment at submit time. */
|
|
89
|
+
showTags?: boolean;
|
|
90
|
+
showComment?: boolean;
|
|
91
|
+
messagePreview?: string;
|
|
92
|
+
/**
|
|
93
|
+
* Arbitrary JSON-serializable key/value bag (e.g. locale, page_url, model, experiment_id).
|
|
94
|
+
* Sent on the Jitsu event as property `metadata` after JSON round-trip (max ~32KB serialized).
|
|
95
|
+
*/
|
|
96
|
+
metadata?: Record<string, unknown>;
|
|
97
|
+
}
|
|
98
|
+
interface FeedbackModulePublic {
|
|
99
|
+
submit(payload: MessageFeedbackSubmitPayload): Promise<void>;
|
|
100
|
+
getConfig(): NormalizedFeedbackConfig;
|
|
101
|
+
isEnabled(): boolean;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Normalized field config used internally (after filtering allowed, defaulting type/label).
|
|
105
|
+
*/
|
|
106
|
+
interface NormalizedFieldConfig {
|
|
107
|
+
id: string;
|
|
108
|
+
type: "text" | "textarea" | "select";
|
|
109
|
+
label: string;
|
|
110
|
+
required: boolean;
|
|
111
|
+
options?: string[];
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Normalized config: single source of truth for the SDK.
|
|
115
|
+
*/
|
|
116
|
+
interface NormalizedConfig {
|
|
117
|
+
agentId: string;
|
|
118
|
+
apiUrl: string;
|
|
119
|
+
enabled: boolean;
|
|
120
|
+
promptText: string;
|
|
121
|
+
fields: NormalizedFieldConfig[];
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Form field values only (keys = field ids). Validated before submit.
|
|
125
|
+
* Validation applies to this only.
|
|
126
|
+
*/
|
|
127
|
+
type IssueFormValues = Record<string, string | undefined>;
|
|
128
|
+
/**
|
|
129
|
+
* Context metadata: set programmatically (e.g. open({ messageId })). Never validated.
|
|
130
|
+
* Merged with form values at submit time. Users can add arbitrary JSON-serializable keys/values.
|
|
131
|
+
*/
|
|
132
|
+
type IssueContextMetadata = {
|
|
133
|
+
conversationId?: string;
|
|
134
|
+
messageId?: string;
|
|
135
|
+
sessionId?: string;
|
|
136
|
+
agentId?: string;
|
|
137
|
+
model?: string;
|
|
138
|
+
} & Record<string, unknown>;
|
|
139
|
+
/**
|
|
140
|
+
* Options passed to open() (e.g. "Report this response").
|
|
141
|
+
*/
|
|
142
|
+
type OpenOptions = IssueContextMetadata;
|
|
143
|
+
/**
|
|
144
|
+
* Final submission payload: form values + context metadata. Sent to transport.
|
|
145
|
+
* Values can be primitives (form fields) or arbitrary JSON-serializable metadata.
|
|
146
|
+
*/
|
|
147
|
+
type IssuePayload = Record<string, unknown>;
|
|
148
|
+
/**
|
|
149
|
+
* Options for createIssueReporter. Config is optional; when omitted, defaults are used.
|
|
150
|
+
* When analytics is omitted, a default analytics instance is created (same Jitsu config).
|
|
151
|
+
*/
|
|
152
|
+
interface CreateIssueReporterOptions {
|
|
153
|
+
agentId: string;
|
|
154
|
+
apiUrl: string;
|
|
155
|
+
config?: Partial<RawIssuesConfig>;
|
|
156
|
+
/** Platform analytics; issue module calls analytics.track('issue_submitted', payload). Defaults to createAnalytics({ agentId }) when omitted. */
|
|
157
|
+
analytics?: AnalyticsModulePublic;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Validation result.
|
|
161
|
+
*/
|
|
162
|
+
interface ValidationResult {
|
|
163
|
+
valid: boolean;
|
|
164
|
+
errors?: Record<string, string>;
|
|
165
|
+
}
|
|
166
|
+
type IssueReportData = Record<string, unknown>;
|
|
167
|
+
/**
|
|
168
|
+
* Instance returned by createIssueReporter.
|
|
169
|
+
* setConfig is used internally when config is loaded asynchronously (e.g. via useCreateFirstflow + fetchConfig).
|
|
170
|
+
*/
|
|
171
|
+
interface IssueReporterInstance {
|
|
172
|
+
getConfig(): NormalizedConfig;
|
|
173
|
+
setConfig(config: NormalizedConfig): void;
|
|
174
|
+
reportIssue(data: IssueReportData): Promise<void>;
|
|
175
|
+
open(options?: OpenOptions): void;
|
|
176
|
+
setOpenHandler(handler: ((options?: OpenOptions) => void) | undefined): void;
|
|
177
|
+
destroy(): void;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Platform event names. Feature modules use these when calling analytics.track().
|
|
182
|
+
* Do not rename existing events (e.g. issue_submitted) to avoid breaking pipelines.
|
|
183
|
+
*/
|
|
184
|
+
/** Issue module — backward compatible */
|
|
185
|
+
declare const ISSUE_SUBMITTED = "issue_submitted";
|
|
186
|
+
/** Future modules */
|
|
187
|
+
declare const FEEDBACK_SUBMITTED = "feedback_submitted";
|
|
188
|
+
declare const SURVEY_COMPLETED = "survey_completed";
|
|
189
|
+
declare const EXPERIENCE_SHOWN = "experience_shown";
|
|
190
|
+
declare const EXPERIENCE_CLICKED = "experience_clicked";
|
|
191
|
+
declare const CHAT_MESSAGE_SENT = "chat_message_sent";
|
|
192
|
+
|
|
193
|
+
declare function createFirstflow(options: CreateFirstflowOptions): FirstflowInstance;
|
|
194
|
+
|
|
195
|
+
/** Active experience row as returned on public agent config (subset of DB). */
|
|
196
|
+
type SdkAgentConfigExperience = {
|
|
197
|
+
id?: string;
|
|
198
|
+
name?: string | null;
|
|
199
|
+
status?: string | null;
|
|
200
|
+
flow?: {
|
|
201
|
+
nodes?: unknown[];
|
|
202
|
+
edges?: unknown[];
|
|
203
|
+
} | null;
|
|
204
|
+
};
|
|
205
|
+
type SdkAgentConfigPayload = {
|
|
206
|
+
issues_config?: RawIssuesConfig;
|
|
207
|
+
feedback_config?: RawFeedbackConfig;
|
|
208
|
+
/** Active experiences including saved flow (nodes/edges from canvas). */
|
|
209
|
+
experiences?: SdkAgentConfigExperience[];
|
|
210
|
+
};
|
|
211
|
+
declare function fetchSdkAgentConfig(apiUrl: string, agentId: string): Promise<SdkAgentConfigPayload>;
|
|
212
|
+
|
|
213
|
+
type FirstflowProviderProps = {
|
|
214
|
+
firstflow: FirstflowInstance;
|
|
215
|
+
children: ReactNode;
|
|
216
|
+
/** Optional payload from `fetchSdkAgentConfig` / `useCreateFirstflow` (issues, feedback, experiences). */
|
|
217
|
+
config?: SdkAgentConfigPayload | null;
|
|
218
|
+
};
|
|
219
|
+
/**
|
|
220
|
+
* Provides the platform instance to the tree. Transitional: delegates to
|
|
221
|
+
* IssueReporterProvider with the internal issue instance so that
|
|
222
|
+
* firstflow.issue.open() opens the modal. This is a migration/composition step;
|
|
223
|
+
* the final architecture may use a single provider for multiple feature modules.
|
|
224
|
+
*/
|
|
225
|
+
declare function FirstflowProvider({ firstflow, children, config }: FirstflowProviderProps): react_jsx_runtime.JSX.Element;
|
|
226
|
+
declare function useFirstflow(): FirstflowInstance;
|
|
227
|
+
/** SDK agent config (including `experiences`) when passed to `FirstflowProvider`; otherwise null. */
|
|
228
|
+
declare function useFirstflowConfig(): SdkAgentConfigPayload | null;
|
|
229
|
+
|
|
230
|
+
type UseCreateFirstflowOptions = {
|
|
231
|
+
fetchConfig?: boolean;
|
|
232
|
+
};
|
|
233
|
+
type UseCreateFirstflowResult = {
|
|
234
|
+
firstflow: FirstflowInstance | null;
|
|
235
|
+
loading: boolean;
|
|
236
|
+
error: Error | null;
|
|
237
|
+
/** Full SDK config from `GET /agents/:id/config` when `fetchConfig: true`; otherwise null. */
|
|
238
|
+
config: SdkAgentConfigPayload | null;
|
|
239
|
+
};
|
|
240
|
+
declare function useCreateFirstflow(agentId: string, apiUrl: string, options?: UseCreateFirstflowOptions): UseCreateFirstflowResult;
|
|
241
|
+
|
|
242
|
+
type UseFeedbackMessageResult = {
|
|
243
|
+
rating: 'like' | 'dislike' | null;
|
|
244
|
+
selectedTags: string[];
|
|
245
|
+
comment: string;
|
|
246
|
+
submitting: boolean;
|
|
247
|
+
submitted: boolean;
|
|
248
|
+
error: string | null;
|
|
249
|
+
setRating: (r: 'like' | 'dislike') => void;
|
|
250
|
+
toggleTag: (tag: string) => void;
|
|
251
|
+
setComment: (c: string) => void;
|
|
252
|
+
submit: () => Promise<void>;
|
|
253
|
+
clearError: () => void;
|
|
254
|
+
isEnabled: boolean;
|
|
255
|
+
config: NormalizedFeedbackConfig | null;
|
|
256
|
+
sideConfig: NormalizedFeedbackFormConfig | null;
|
|
257
|
+
};
|
|
258
|
+
type UseFeedbackMessageOptions = {
|
|
259
|
+
conversationId: string;
|
|
260
|
+
messageId: string;
|
|
261
|
+
messagePreview: string;
|
|
262
|
+
metadata?: Record<string, unknown>;
|
|
263
|
+
};
|
|
264
|
+
/**
|
|
265
|
+
* **Module mode** — `useFeedback()`
|
|
266
|
+
* Returns `firstflow.feedback`: programmatic `submit(payload)`, `getConfig()`, `isEnabled()` (e.g. Thread slot, one-off submits).
|
|
267
|
+
*
|
|
268
|
+
* **Message mode** — `useFeedback({ conversationId, messageId, messagePreview, metadata? })`
|
|
269
|
+
* Headless per-message state: rating, tags, comment, `submit()`, localStorage.
|
|
270
|
+
*/
|
|
271
|
+
declare function useFeedback(): FeedbackModulePublic;
|
|
272
|
+
declare function useFeedback(options: UseFeedbackMessageOptions): UseFeedbackMessageResult;
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Runtime types for experience "Message" flow nodes (aligned with dashboard CardData.config).
|
|
276
|
+
* @see blocksVersion — increment when block union or order semantics change.
|
|
277
|
+
*/
|
|
278
|
+
type FlowMessageStyle = 'message'
|
|
279
|
+
/** @deprecated Dashboard now saves `message`; kept for older flows */
|
|
280
|
+
| 'inline' | 'card' | 'carousel' | 'quick_replies' | 'rich_card';
|
|
281
|
+
/** Canonical style for analytics / UI (`inline` → `message`). */
|
|
282
|
+
declare function normalizeFlowMessageStyle(style: FlowMessageStyle | undefined): FlowMessageStyle | undefined;
|
|
283
|
+
type FlowMessageCtaType = 'none' | 'button' | 'link' | 'dismiss' | 'button_dismiss';
|
|
284
|
+
type FlowCarouselCardButtonAction = 'prompt' | 'link';
|
|
285
|
+
type FlowQuickReplyItem = {
|
|
286
|
+
label: string;
|
|
287
|
+
prompt?: string;
|
|
288
|
+
};
|
|
289
|
+
declare function normalizeFlowQuickReplyItem(entry: unknown): FlowQuickReplyItem;
|
|
290
|
+
declare function normalizeFlowQuickReplyList(raw: unknown): FlowQuickReplyItem[];
|
|
291
|
+
type FlowCarouselCard = {
|
|
292
|
+
id: string;
|
|
293
|
+
title: string;
|
|
294
|
+
description: string;
|
|
295
|
+
buttonText?: string;
|
|
296
|
+
buttonAction?: FlowCarouselCardButtonAction;
|
|
297
|
+
buttonUrl?: string;
|
|
298
|
+
buttonPrompt?: string;
|
|
299
|
+
showCardCta?: boolean;
|
|
300
|
+
secondaryButtonText?: string;
|
|
301
|
+
secondaryButtonAction?: FlowCarouselCardButtonAction;
|
|
302
|
+
secondaryButtonUrl?: string;
|
|
303
|
+
secondaryButtonPrompt?: string;
|
|
304
|
+
emoji?: string;
|
|
305
|
+
mediaType?: 'emoji' | 'image' | 'video';
|
|
306
|
+
imageUrl?: string;
|
|
307
|
+
videoUrl?: string;
|
|
308
|
+
};
|
|
309
|
+
type FlowMessageNodeConfig = {
|
|
310
|
+
messageContent?: string;
|
|
311
|
+
messageStyle?: FlowMessageStyle;
|
|
312
|
+
ctaType?: FlowMessageCtaType;
|
|
313
|
+
ctaText?: string;
|
|
314
|
+
/** Link CTA destination */
|
|
315
|
+
ctaUrl?: string;
|
|
316
|
+
/** Button / button_dismiss: user message sent when primary CTA is activated (falls back to label in host apps if empty). */
|
|
317
|
+
ctaPrompt?: string;
|
|
318
|
+
dismissText?: string;
|
|
319
|
+
/** Legacy flows may use `string[]`; normalize with `normalizeFlowQuickReplyList`. */
|
|
320
|
+
quickReplies?: Array<string | FlowQuickReplyItem>;
|
|
321
|
+
carouselCards?: FlowCarouselCard[];
|
|
322
|
+
};
|
|
323
|
+
type ExperienceMessageBlock = {
|
|
324
|
+
type: 'text';
|
|
325
|
+
body: string;
|
|
326
|
+
} | {
|
|
327
|
+
type: 'carousel';
|
|
328
|
+
cards: FlowCarouselCard[];
|
|
329
|
+
} | {
|
|
330
|
+
type: 'quick_replies';
|
|
331
|
+
options: FlowQuickReplyItem[];
|
|
332
|
+
} | {
|
|
333
|
+
type: 'cta_primary';
|
|
334
|
+
label: string;
|
|
335
|
+
ctaType: FlowMessageCtaType;
|
|
336
|
+
url?: string;
|
|
337
|
+
/** Present for button / button_dismiss when dashboard set ctaPrompt */
|
|
338
|
+
promptText?: string;
|
|
339
|
+
} | {
|
|
340
|
+
type: 'cta_dismiss';
|
|
341
|
+
label: string;
|
|
342
|
+
};
|
|
343
|
+
type ExperienceMessageAction = {
|
|
344
|
+
kind: 'cta_primary';
|
|
345
|
+
ctaType: FlowMessageCtaType;
|
|
346
|
+
label: string;
|
|
347
|
+
url?: string;
|
|
348
|
+
promptText?: string;
|
|
349
|
+
} | {
|
|
350
|
+
kind: 'cta_dismiss';
|
|
351
|
+
label: string;
|
|
352
|
+
} | {
|
|
353
|
+
kind: 'quick_reply';
|
|
354
|
+
label: string;
|
|
355
|
+
index: number;
|
|
356
|
+
promptText?: string;
|
|
357
|
+
} | {
|
|
358
|
+
kind: 'carousel_cta';
|
|
359
|
+
cardId: string;
|
|
360
|
+
actionId?: string;
|
|
361
|
+
/** Resolved from card config; omitted if card not found */
|
|
362
|
+
buttonAction?: FlowCarouselCardButtonAction;
|
|
363
|
+
/** Primary or secondary button label */
|
|
364
|
+
label?: string;
|
|
365
|
+
linkUrl?: string;
|
|
366
|
+
promptText?: string;
|
|
367
|
+
};
|
|
368
|
+
/** Maps action kind → analytics `action` property (single source of truth). */
|
|
369
|
+
declare const EXPERIENCE_MESSAGE_ANALYTICS_ACTION: Record<ExperienceMessageAction['kind'], string>;
|
|
370
|
+
/**
|
|
371
|
+
* v4: Quick replies are `{ label, prompt? }[]` (normalized); `quick_replies` block options carry prompts; `quick_reply` actions include optional `promptText`.
|
|
372
|
+
* v3: `cta_primary` blocks carry optional `promptText` (dashboard `ctaPrompt`); `FlowMessageStyle` adds `message` (alias of legacy `inline`).
|
|
373
|
+
* v2: `FlowCarouselCard` supports optional per-card CTAs (`showCardCta`, `secondaryButtonText`, optional `buttonText`).
|
|
374
|
+
* v1: carousel cards required `buttonText`; consumers should ignore unknown keys on card objects.
|
|
375
|
+
*/
|
|
376
|
+
declare const EXPERIENCE_MESSAGE_BLOCKS_VERSION: 4;
|
|
377
|
+
type ExperienceMessageUi = {
|
|
378
|
+
hasText: boolean;
|
|
379
|
+
hasPrimaryCta: boolean;
|
|
380
|
+
hasDismissCta: boolean;
|
|
381
|
+
hasQuickReplies: boolean;
|
|
382
|
+
hasCarousel: boolean;
|
|
383
|
+
messageStyle: FlowMessageStyle | undefined;
|
|
384
|
+
};
|
|
385
|
+
/**
|
|
386
|
+
* Canonical block order: text → carousel → quick_replies → cta_primary → cta_dismiss.
|
|
387
|
+
* Carousel card objects follow `FlowCarouselCard` (v2 fields optional for per-card CTAs).
|
|
388
|
+
*/
|
|
389
|
+
declare function buildExperienceMessageBlocks(config: FlowMessageNodeConfig): ExperienceMessageBlock[];
|
|
390
|
+
declare function buildExperienceMessageUi(blocks: ExperienceMessageBlock[], messageStyle: FlowMessageStyle | undefined): ExperienceMessageUi;
|
|
391
|
+
/**
|
|
392
|
+
* Builds the `carousel_cta` action payload from node config (prompt vs link per button).
|
|
393
|
+
* Host apps should open `linkUrl` or send `promptText` / `label` as the user message — same rules as the dashboard preview.
|
|
394
|
+
*/
|
|
395
|
+
declare function buildExperienceCarouselCtaAction(config: FlowMessageNodeConfig, cardId: string, actionId?: string): Extract<ExperienceMessageAction, {
|
|
396
|
+
kind: 'carousel_cta';
|
|
397
|
+
}>;
|
|
398
|
+
|
|
399
|
+
type UseExperienceMessageNodeOptions = {
|
|
400
|
+
config: FlowMessageNodeConfig;
|
|
401
|
+
nodeId: string;
|
|
402
|
+
experienceId: string;
|
|
403
|
+
conversationId?: string;
|
|
404
|
+
/** Merged into analytics props (non-reserved keys only if colliding — core ids always win). */
|
|
405
|
+
metadata?: Record<string, unknown>;
|
|
406
|
+
/**
|
|
407
|
+
* When true (default), fires first impression on mount via internal `reportShown()`.
|
|
408
|
+
* Set false for virtualized lists; call `reportShown()` when the row is visible (e.g. IntersectionObserver).
|
|
409
|
+
*/
|
|
410
|
+
trackShownOnMount?: boolean;
|
|
411
|
+
/**
|
|
412
|
+
* Overrides the dedupe key. Include a per-flow UUID (e.g. `flowInstanceId`) if the same node may
|
|
413
|
+
* legitimately be shown twice in one session — otherwise dedupe drops the second impression.
|
|
414
|
+
*/
|
|
415
|
+
impressionKey?: string;
|
|
416
|
+
/**
|
|
417
|
+
* When true (default), only one `EXPERIENCE_SHOWN` per impression key per page session.
|
|
418
|
+
* Set false to count every mount / every `reportShown()` call.
|
|
419
|
+
*/
|
|
420
|
+
dedupeShown?: boolean;
|
|
421
|
+
onAction?: (e: ExperienceMessageAction) => void;
|
|
422
|
+
/**
|
|
423
|
+
* Transform props before `analytics.track`. Do not rename event names unless intentional.
|
|
424
|
+
* If this throws, base props are used and a warning is logged.
|
|
425
|
+
*/
|
|
426
|
+
mapAnalytics?: (eventName: string, props: Record<string, unknown>) => Record<string, unknown>;
|
|
427
|
+
};
|
|
428
|
+
type UseExperienceMessageNodeHandlers = {
|
|
429
|
+
onPrimaryCta: () => void;
|
|
430
|
+
onDismissCta: () => void;
|
|
431
|
+
onQuickReply: (label: string, index: number) => void;
|
|
432
|
+
/**
|
|
433
|
+
* `actionId` is `primary` | `secondary`; defaults to `primary`.
|
|
434
|
+
* Fires `carousel_cta` with `buttonAction`, `label`, `linkUrl`, and `promptText` filled from `config.carouselCards` when the card exists.
|
|
435
|
+
*/
|
|
436
|
+
onCarouselCta: (cardId: string, actionId?: string) => void;
|
|
437
|
+
};
|
|
438
|
+
type UseExperienceMessageNodeResult = {
|
|
439
|
+
config: FlowMessageNodeConfig;
|
|
440
|
+
blocks: ExperienceMessageBlock[];
|
|
441
|
+
blocksVersion: typeof EXPERIENCE_MESSAGE_BLOCKS_VERSION;
|
|
442
|
+
ui: ExperienceMessageUi;
|
|
443
|
+
handlers: UseExperienceMessageNodeHandlers;
|
|
444
|
+
/**
|
|
445
|
+
* Record `EXPERIENCE_SHOWN`. With `dedupeShown`, same `impressionKey` as an earlier successful
|
|
446
|
+
* track is a no-op. When `trackShownOnMount` is true, the mount effect counts as the first call.
|
|
447
|
+
*/
|
|
448
|
+
reportShown: () => void;
|
|
449
|
+
};
|
|
450
|
+
/**
|
|
451
|
+
* Headless runtime for experience **Message** flow nodes: canonical `blocks` + `ui`, structured
|
|
452
|
+
* `onAction`, and `EXPERIENCE_SHOWN` / `EXPERIENCE_CLICKED` analytics (with optional dedupe and
|
|
453
|
+
* `mapAnalytics`). Requires `FirstflowProvider`.
|
|
454
|
+
*
|
|
455
|
+
* **Dedupe footgun:** Default impression key is stable per node + conversation. Re-visiting the same
|
|
456
|
+
* node in a new flow run without changing the key will not fire a second shown. Pass a unique
|
|
457
|
+
* `impressionKey` (e.g. including `flowInstanceId`) or set `dedupeShown: false`.
|
|
458
|
+
*
|
|
459
|
+
* **Block order:** text → carousel → quick_replies → cta_primary → cta_dismiss. v4 normalizes quick replies to `{ label, prompt? }` and adds `promptText` on `quick_reply` actions. v3 adds `promptText` on primary CTA blocks. v2 added per-card carousel CTA fields.
|
|
460
|
+
* **`onCarouselCta`:** emits `carousel_cta` with `buttonAction` / `label` / `linkUrl` / `promptText` resolved from `config.carouselCards` (dashboard prompt vs link per button).
|
|
461
|
+
*
|
|
462
|
+
* **Errors:** `onAction` and `mapAnalytics` are wrapped in try/catch; analytics still runs after
|
|
463
|
+
* `onAction` throws; if `mapAnalytics` throws, base props are tracked.
|
|
464
|
+
*/
|
|
465
|
+
declare function useExperienceMessageNode(options: UseExperienceMessageNodeOptions): UseExperienceMessageNodeResult;
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Runtime types for experience "Announcement" flow nodes (aligned with dashboard CardData.config).
|
|
469
|
+
* @see blocksVersion — increment when content/ui semantics change.
|
|
470
|
+
*/
|
|
471
|
+
type FlowAnnouncementStyle = 'chat_bubble' | 'card' | 'banner' | 'tooltip' | 'spotlight';
|
|
472
|
+
type FlowAnnouncementTheme = 'info' | 'success' | 'warning' | 'promo' | 'neutral';
|
|
473
|
+
type FlowAnnouncementPosition = 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'center';
|
|
474
|
+
type FlowAnnouncementNodeConfig = {
|
|
475
|
+
announcementStyle?: FlowAnnouncementStyle;
|
|
476
|
+
announcementTheme?: FlowAnnouncementTheme;
|
|
477
|
+
announcementTitle?: string;
|
|
478
|
+
announcementBody?: string;
|
|
479
|
+
announcementEmoji?: string;
|
|
480
|
+
ctaText?: string;
|
|
481
|
+
ctaUrl?: string;
|
|
482
|
+
announcementDismissible?: boolean;
|
|
483
|
+
announcementAutoHide?: boolean;
|
|
484
|
+
announcementAutoHideDelay?: number;
|
|
485
|
+
announcementPosition?: FlowAnnouncementPosition;
|
|
486
|
+
};
|
|
487
|
+
type ExperienceAnnouncementAction = {
|
|
488
|
+
kind: 'cta_click';
|
|
489
|
+
label: string;
|
|
490
|
+
url?: string;
|
|
491
|
+
} | {
|
|
492
|
+
kind: 'dismiss';
|
|
493
|
+
} | {
|
|
494
|
+
kind: 'auto_hidden';
|
|
495
|
+
};
|
|
496
|
+
/** Maps action kind → analytics `action` property (single source of truth). */
|
|
497
|
+
declare const EXPERIENCE_ANNOUNCEMENT_ANALYTICS_ACTION: Record<ExperienceAnnouncementAction['kind'], string>;
|
|
498
|
+
declare const EXPERIENCE_ANNOUNCEMENT_BLOCKS_VERSION: 1;
|
|
499
|
+
/** Trimmed display fields; omit keys when empty. */
|
|
500
|
+
type ExperienceAnnouncementContent = {
|
|
501
|
+
title?: string;
|
|
502
|
+
body?: string;
|
|
503
|
+
emoji?: string;
|
|
504
|
+
ctaLabel?: string;
|
|
505
|
+
ctaUrl?: string;
|
|
506
|
+
};
|
|
507
|
+
type ExperienceAnnouncementUi = {
|
|
508
|
+
hasTitle: boolean;
|
|
509
|
+
hasBody: boolean;
|
|
510
|
+
hasEmoji: boolean;
|
|
511
|
+
hasCta: boolean;
|
|
512
|
+
isDismissible: boolean;
|
|
513
|
+
autoHide: boolean;
|
|
514
|
+
autoHideDelay: number;
|
|
515
|
+
position: FlowAnnouncementPosition | undefined;
|
|
516
|
+
style: FlowAnnouncementStyle | undefined;
|
|
517
|
+
theme: FlowAnnouncementTheme | undefined;
|
|
518
|
+
};
|
|
519
|
+
/**
|
|
520
|
+
* Maps raw dashboard/API config to a safe `FlowAnnouncementNodeConfig`.
|
|
521
|
+
*/
|
|
522
|
+
declare function normalizeFlowAnnouncementNodeConfig(raw: Record<string, unknown> | FlowAnnouncementNodeConfig | undefined | null): FlowAnnouncementNodeConfig;
|
|
523
|
+
declare function buildExperienceAnnouncementContent(config: FlowAnnouncementNodeConfig): ExperienceAnnouncementContent;
|
|
524
|
+
declare function buildExperienceAnnouncementUi(config: FlowAnnouncementNodeConfig, content: ExperienceAnnouncementContent): ExperienceAnnouncementUi;
|
|
525
|
+
|
|
526
|
+
type UseExperienceAnnouncementNodeOptions = {
|
|
527
|
+
config: FlowAnnouncementNodeConfig | Record<string, unknown>;
|
|
528
|
+
nodeId: string;
|
|
529
|
+
experienceId: string;
|
|
530
|
+
conversationId?: string;
|
|
531
|
+
metadata?: Record<string, unknown>;
|
|
532
|
+
trackShownOnMount?: boolean;
|
|
533
|
+
impressionKey?: string;
|
|
534
|
+
dedupeShown?: boolean;
|
|
535
|
+
onAction?: (e: ExperienceAnnouncementAction) => void;
|
|
536
|
+
mapAnalytics?: (eventName: string, props: Record<string, unknown>) => Record<string, unknown>;
|
|
537
|
+
};
|
|
538
|
+
type UseExperienceAnnouncementNodeHandlers = {
|
|
539
|
+
dismiss: () => void;
|
|
540
|
+
ctaClick: () => void;
|
|
541
|
+
cancelAutoHide: () => void;
|
|
542
|
+
reportShown: () => void;
|
|
543
|
+
};
|
|
544
|
+
type UseExperienceAnnouncementNodeResult = {
|
|
545
|
+
config: FlowAnnouncementNodeConfig;
|
|
546
|
+
content: ExperienceAnnouncementContent;
|
|
547
|
+
ui: ExperienceAnnouncementUi;
|
|
548
|
+
blocksVersion: typeof EXPERIENCE_ANNOUNCEMENT_BLOCKS_VERSION;
|
|
549
|
+
handlers: UseExperienceAnnouncementNodeHandlers;
|
|
550
|
+
};
|
|
551
|
+
/**
|
|
552
|
+
* Headless runtime for experience **Announcement** flow nodes: `content` + `ui`, structured
|
|
553
|
+
* `onAction` (cta_click, dismiss, auto_hidden), auto-hide timer, and EXPERIENCE_SHOWN /
|
|
554
|
+
* EXPERIENCE_CLICKED analytics. Requires `FirstflowProvider`.
|
|
555
|
+
*/
|
|
556
|
+
declare function useExperienceAnnouncementNode(options: UseExperienceAnnouncementNodeOptions): UseExperienceAnnouncementNodeResult;
|
|
557
|
+
|
|
558
|
+
type UseIssueFormResult = {
|
|
559
|
+
/** Current field values (ids from config). */
|
|
560
|
+
values: IssueFormValues;
|
|
561
|
+
setValue: (fieldId: string, value: string) => void;
|
|
562
|
+
setValues: (next: IssueFormValues) => void;
|
|
563
|
+
errors: Record<string, string>;
|
|
564
|
+
submitting: boolean;
|
|
565
|
+
submitted: boolean;
|
|
566
|
+
submitError: string | null;
|
|
567
|
+
/** Validate only; sets `errors`. Returns whether valid. */
|
|
568
|
+
validate: () => boolean;
|
|
569
|
+
/** Validate, then `reportIssue` with merged `open()` context (messageId, etc.). */
|
|
570
|
+
submit: () => Promise<void>;
|
|
571
|
+
/** Clear values to empty, errors, submit state. */
|
|
572
|
+
reset: () => void;
|
|
573
|
+
clearSubmitError: () => void;
|
|
574
|
+
isEnabled: boolean;
|
|
575
|
+
config: NormalizedConfig;
|
|
576
|
+
fields: NormalizedFieldConfig[];
|
|
577
|
+
promptText: string;
|
|
578
|
+
};
|
|
579
|
+
/**
|
|
580
|
+
* Headless issue form: same validation + submit as {@link FormEngine} / {@link InlineIssueForm}.
|
|
581
|
+
* Build any UI; merge context from `open({ messageId, conversationId, … })` on submit.
|
|
582
|
+
*/
|
|
583
|
+
declare function useIssueForm(): UseIssueFormResult;
|
|
584
|
+
|
|
585
|
+
type MessageFeedbackProps = {
|
|
586
|
+
conversationId: string;
|
|
587
|
+
messageId: string;
|
|
588
|
+
messagePreview: string;
|
|
589
|
+
className?: string;
|
|
590
|
+
/** Merged into each Jitsu `feedback_submitted` event as `metadata` (JSON-serializable). */
|
|
591
|
+
metadata?: Record<string, unknown>;
|
|
592
|
+
/**
|
|
593
|
+
* `inline` — thumbs beside the message; tag/comment form full width below when a rating is chosen.
|
|
594
|
+
* `default` — full card with preview + thumbs.
|
|
595
|
+
*/
|
|
596
|
+
variant?: 'default' | 'inline';
|
|
597
|
+
/** Styling for the expanded form when `variant="inline"` (thumbs stay unchanged). */
|
|
598
|
+
inlineFormSurface?: 'light' | 'dark';
|
|
599
|
+
};
|
|
600
|
+
declare function MessageFeedback({ conversationId, messageId, messagePreview, className, metadata, variant, inlineFormSurface, }: MessageFeedbackProps): react_jsx_runtime.JSX.Element | null;
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* DOM adapter only: renders the React tree into target. No business logic.
|
|
604
|
+
* Renders FirstflowProvider + InlineIssueForm so firstflow.issue.open() works after mount.
|
|
605
|
+
*/
|
|
606
|
+
declare function mount(firstflow: FirstflowInstance, target: HTMLElement): () => void;
|
|
607
|
+
|
|
608
|
+
declare function useIssueReporter(): {
|
|
609
|
+
reporter: IssueReporterInstance;
|
|
610
|
+
open: (options?: OpenOptions) => void;
|
|
611
|
+
reportIssue: (data: IssueReportData) => Promise<void>;
|
|
612
|
+
submit: (data: IssueReportData) => Promise<void>;
|
|
613
|
+
config: NormalizedConfig;
|
|
614
|
+
isModalOpen: boolean;
|
|
615
|
+
closeModal: () => void;
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
declare function InlineIssueForm(): react_jsx_runtime.JSX.Element | null;
|
|
619
|
+
|
|
620
|
+
declare function IssueModal(): React.ReactPortal | null;
|
|
621
|
+
|
|
622
|
+
type FormEngineProps = {
|
|
623
|
+
onSubmitSuccess?: () => void;
|
|
624
|
+
onCancel?: () => void;
|
|
625
|
+
submitLabel?: string;
|
|
626
|
+
cancelLabel?: string;
|
|
627
|
+
};
|
|
628
|
+
declare function FormEngine({ onSubmitSuccess, onCancel, submitLabel, cancelLabel, }: FormEngineProps): react_jsx_runtime.JSX.Element | null;
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Issue module types. Use the Issue namespace so the root package stays platform-first.
|
|
632
|
+
*/
|
|
633
|
+
|
|
634
|
+
type issue_IssueContextMetadata = IssueContextMetadata;
|
|
635
|
+
type issue_NormalizedConfig = NormalizedConfig;
|
|
636
|
+
type issue_NormalizedFieldConfig = NormalizedFieldConfig;
|
|
637
|
+
type issue_OpenOptions = OpenOptions;
|
|
638
|
+
type issue_RawIssueFieldConfig = RawIssueFieldConfig;
|
|
639
|
+
type issue_RawIssuesConfig = RawIssuesConfig;
|
|
640
|
+
type issue_ValidationResult = ValidationResult;
|
|
641
|
+
declare namespace issue {
|
|
642
|
+
export type { IssueFormValues as FormValues, issue_IssueContextMetadata as IssueContextMetadata, issue_NormalizedConfig as NormalizedConfig, issue_NormalizedFieldConfig as NormalizedFieldConfig, issue_OpenOptions as OpenOptions, IssuePayload as Payload, issue_RawIssueFieldConfig as RawIssueFieldConfig, issue_RawIssuesConfig as RawIssuesConfig, issue_ValidationResult as ValidationResult };
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
type IssueReporterContextValue = {
|
|
646
|
+
reporter: IssueReporterInstance;
|
|
647
|
+
isModalOpen: boolean;
|
|
648
|
+
openModal: (options?: OpenOptions) => void;
|
|
649
|
+
closeModal: () => void;
|
|
650
|
+
openOptionsRef: React.MutableRefObject<OpenOptions | undefined>;
|
|
651
|
+
};
|
|
652
|
+
type IssueReporterProviderProps = {
|
|
653
|
+
reporter: IssueReporterInstance;
|
|
654
|
+
children: ReactNode;
|
|
655
|
+
};
|
|
656
|
+
/**
|
|
657
|
+
* Provides React bindings and modal state only. Config lifecycle and submission stay in the reporter instance.
|
|
658
|
+
*/
|
|
659
|
+
declare function IssueReporterProvider({ reporter, children, }: IssueReporterProviderProps): react_jsx_runtime.JSX.Element;
|
|
660
|
+
declare function useIssueReporterContext(): IssueReporterContextValue;
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Factory: returns an instance. No global state; callback ref from Provider for open().
|
|
664
|
+
* Issue events are sent via the platform analytics layer only (no direct Jitsu/backend calls).
|
|
665
|
+
*/
|
|
666
|
+
declare function createIssueReporter(options: CreateIssueReporterOptions): IssueReporterInstance;
|
|
667
|
+
|
|
668
|
+
export { type AnalyticsModulePublic, CHAT_MESSAGE_SENT, type CreateFirstflowOptions, type CreateIssueReporterOptions, EXPERIENCE_ANNOUNCEMENT_ANALYTICS_ACTION, EXPERIENCE_ANNOUNCEMENT_BLOCKS_VERSION, EXPERIENCE_CLICKED, EXPERIENCE_MESSAGE_ANALYTICS_ACTION, EXPERIENCE_MESSAGE_BLOCKS_VERSION, EXPERIENCE_SHOWN, type ExperienceAnnouncementAction, type ExperienceAnnouncementContent, type ExperienceAnnouncementUi, type ExperienceMessageAction, type ExperienceMessageBlock, type ExperienceMessageUi, FEEDBACK_SUBMITTED, type FeedbackModulePublic, type FirstflowInstance, FirstflowProvider, type FlowAnnouncementNodeConfig, type FlowAnnouncementPosition, type FlowAnnouncementStyle, type FlowAnnouncementTheme, type FlowCarouselCard, type FlowCarouselCardButtonAction, type FlowMessageCtaType, type FlowMessageNodeConfig, type FlowMessageStyle, type FlowQuickReplyItem, FormEngine, type FormEngineProps, ISSUE_SUBMITTED, InlineIssueForm, issue as Issue, type IssueContextMetadata, type IssueFormValues, IssueModal, type IssueModulePublic, type IssuePayload, type IssueReporterInstance, IssueReporterProvider, MessageFeedback, type MessageFeedbackProps, type MessageFeedbackSubmitPayload, type NormalizedConfig, type NormalizedFeedbackConfig, type NormalizedFieldConfig, type OpenOptions, type RawFeedbackConfig, type RawIssueFieldConfig, type RawIssuesConfig, SURVEY_COMPLETED, type SdkAgentConfigExperience, type SdkAgentConfigPayload, type UseCreateFirstflowOptions, type UseCreateFirstflowResult, type UseExperienceAnnouncementNodeHandlers, type UseExperienceAnnouncementNodeOptions, type UseExperienceAnnouncementNodeResult, type UseExperienceMessageNodeHandlers, type UseExperienceMessageNodeOptions, type UseExperienceMessageNodeResult, type UseFeedbackMessageOptions, type UseFeedbackMessageResult, type UseIssueFormResult, type ValidationResult, buildExperienceAnnouncementContent, buildExperienceAnnouncementUi, buildExperienceCarouselCtaAction, buildExperienceMessageBlocks, buildExperienceMessageUi, createFirstflow, createIssueReporter, fetchSdkAgentConfig, mount, normalizeFlowAnnouncementNodeConfig, normalizeFlowMessageStyle, normalizeFlowQuickReplyItem, normalizeFlowQuickReplyList, useCreateFirstflow, useExperienceAnnouncementNode, useExperienceMessageNode, useFeedback, useFirstflow, useFirstflowConfig, useIssueForm, useIssueReporter, useIssueReporterContext };
|