@getforty/widget 0.1.0

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.

Potentially problematic release.


This version of @getforty/widget might be problematic. Click here for more details.

@@ -0,0 +1,359 @@
1
+ /**
2
+ * Widget Configuration Types
3
+ * These types are exported publicly for developers using the widget
4
+ */
5
+ /**
6
+ * Primary configuration object passed to widget initialization
7
+ */
8
+ interface WidgetConfig {
9
+ /** Workspace tracking ID (required) - format: gf_xxxxxxxxxxxx */
10
+ trackingId: string;
11
+ /** Display language (default: auto-detect from browser) */
12
+ locale?: "en" | "pt-BR" | string;
13
+ /** Custom translations to override built-in strings */
14
+ translations?: Partial<TranslationStrings>;
15
+ /** Visual customization options for forms */
16
+ theme?: WidgetTheme;
17
+ /** Rendering mode for forms */
18
+ mode?: "inline" | "modal";
19
+ /** Target element for inline mode (CSS selector or HTMLElement) */
20
+ container?: string | HTMLElement;
21
+ /** Show/hide GetForty branding */
22
+ showBranding?: boolean;
23
+ /** Automatically track page views */
24
+ autoTrackPageViews?: boolean;
25
+ /** Automatically display forms based on server-side conditions (default: true) */
26
+ autoDisplay?: boolean;
27
+ /** API base URL (default: https://getforty.club) */
28
+ apiBaseUrl?: string;
29
+ /** Enable debug logging */
30
+ debug?: boolean;
31
+ /**
32
+ * Observe parent window's dataLayer (Google Tag Manager) and automatically
33
+ * send events through GetForty tracking pipeline (opt-in)
34
+ *
35
+ * When enabled, watches for events pushed to window.dataLayer and forwards
36
+ * them to GetForty's backend, allowing you to leverage existing GTM integrations.
37
+ *
38
+ * Note: Only works in same-origin scenarios (cross-origin iframes not supported)
39
+ */
40
+ observeDataLayer?: boolean;
41
+ /**
42
+ * Prefix added to dataLayer event names when sent to GetForty
43
+ * (default: "gtm_")
44
+ *
45
+ * Example: dataLayer event "purchase" becomes "gtm_purchase" in GetForty
46
+ */
47
+ dataLayerEventPrefix?: string;
48
+ /**
49
+ * Filter which dataLayer events to send (optional)
50
+ * Can be a RegExp to test event names or a function that returns boolean
51
+ *
52
+ * Examples:
53
+ * - /^custom_/ (only events starting with "custom_")
54
+ * - (name) => name !== "gtm.js" (exclude GTM internal events)
55
+ */
56
+ dataLayerEventFilter?: RegExp | ((eventName: string) => boolean);
57
+ }
58
+ /**
59
+ * Visual customization options for form UI
60
+ */
61
+ interface WidgetTheme {
62
+ /** Primary color for buttons and accents (CSS color) */
63
+ primaryColor?: string;
64
+ /** Background color for widget container (CSS color) */
65
+ backgroundColor?: string;
66
+ /** Text color (CSS color) */
67
+ textColor?: string;
68
+ /** Font family (CSS font-family) */
69
+ fontFamily?: string;
70
+ /** Border radius for containers and inputs (CSS value) */
71
+ borderRadius?: string;
72
+ }
73
+ /**
74
+ * Options for tracking a custom event
75
+ */
76
+ interface TrackEventOptions {
77
+ /** Custom properties to attach to the event */
78
+ properties?: Record<string, string | number | boolean | null>;
79
+ /** Override the auto-generated session ID */
80
+ sessionId?: string;
81
+ /** Override the identified user ID */
82
+ userId?: string;
83
+ /** Timestamp override (default: now) */
84
+ timestamp?: Date;
85
+ }
86
+ /**
87
+ * Options for identifying a user
88
+ */
89
+ interface IdentifyOptions {
90
+ /** User traits/properties */
91
+ traits?: Record<string, string | number | boolean | null>;
92
+ }
93
+ /**
94
+ * Internal representation of a tracked event
95
+ */
96
+ interface TrackedEvent {
97
+ /** Event name (e.g., 'page_view', 'purchase', 'signup') */
98
+ eventName: string;
99
+ /** Custom event properties */
100
+ properties?: Record<string, unknown>;
101
+ /** Session identifier (auto-generated or provided) */
102
+ sessionId: string;
103
+ /** User identifier (from identify() call) */
104
+ userId?: string;
105
+ /** Event timestamp */
106
+ timestamp: string;
107
+ /** Retry count for failed sends */
108
+ _retryCount?: number;
109
+ }
110
+ /**
111
+ * Localizable UI strings
112
+ */
113
+ interface TranslationStrings {
114
+ submit: string;
115
+ submitting: string;
116
+ next: string;
117
+ previous: string;
118
+ skip: string;
119
+ required: string;
120
+ invalidEmail: string;
121
+ invalidNumber: string;
122
+ minLength: string;
123
+ maxLength: string;
124
+ loading: string;
125
+ success: string;
126
+ successMessage: string;
127
+ error: string;
128
+ networkError: string;
129
+ rateLimited: string;
130
+ tryAgain: string;
131
+ npsNotLikely: string;
132
+ npsVeryLikely: string;
133
+ closeModal: string;
134
+ formLabel: string;
135
+ questionOf: string;
136
+ }
137
+ /**
138
+ * Form configuration received from API
139
+ */
140
+ interface FormConfig {
141
+ id: string;
142
+ title: string;
143
+ type: "NPS" | "CSAT" | "PMF" | "CUSTOM";
144
+ questions: Question[];
145
+ branding?: {
146
+ logoUrl?: string;
147
+ thankYouMessage?: string;
148
+ colors?: {
149
+ primary?: string;
150
+ background?: string;
151
+ };
152
+ };
153
+ }
154
+ /**
155
+ * Question definition within a form
156
+ */
157
+ interface Question {
158
+ id: string;
159
+ type: "rating" | "nps" | "text" | "textarea" | "select" | "multiselect" | "scale";
160
+ label: string;
161
+ description?: string;
162
+ required: boolean;
163
+ options?: QuestionOption[];
164
+ validation?: {
165
+ minLength?: number;
166
+ maxLength?: number;
167
+ pattern?: string;
168
+ };
169
+ }
170
+ /**
171
+ * Option for select/multiselect questions
172
+ */
173
+ interface QuestionOption {
174
+ value: string;
175
+ label: string;
176
+ }
177
+ /**
178
+ * Answer submitted for a question
179
+ */
180
+ interface Answer {
181
+ questionId: string;
182
+ value: string | string[] | number;
183
+ }
184
+ /**
185
+ * Events emitted by widget for developer integration
186
+ */
187
+ interface WidgetEventMap {
188
+ /** Widget started loading form configuration */
189
+ "load:start": {
190
+ formId: string;
191
+ };
192
+ /** Form configuration loaded successfully */
193
+ "load:success": {
194
+ form: FormConfig;
195
+ };
196
+ /** Form loading failed */
197
+ "load:error": {
198
+ error: string;
199
+ retryable: boolean;
200
+ };
201
+ /** Widget became visible (modal opened or inline rendered) */
202
+ open: {
203
+ mode: "inline" | "modal";
204
+ };
205
+ /** Widget hidden (modal closed) */
206
+ close: {
207
+ reason: "user" | "submitted" | "programmatic";
208
+ };
209
+ /** Form submission started */
210
+ "submit:start": {
211
+ answers: Answer[];
212
+ };
213
+ /** Form submission successful */
214
+ "submit:success": {
215
+ responseId: string;
216
+ };
217
+ /** Form submission failed */
218
+ "submit:error": {
219
+ error: string;
220
+ retryable: boolean;
221
+ };
222
+ /** Any error occurred */
223
+ error: {
224
+ type: "load" | "submit" | "network";
225
+ message: string;
226
+ };
227
+ /** Field received focus */
228
+ "field:focus": {
229
+ questionId: string;
230
+ questionLabel: string;
231
+ };
232
+ /** Field lost focus */
233
+ "field:blur": {
234
+ questionId: string;
235
+ questionLabel: string;
236
+ };
237
+ /** Field value changed */
238
+ "field:change": {
239
+ questionId: string;
240
+ questionLabel: string;
241
+ };
242
+ /** Field validation error */
243
+ "field:validation": {
244
+ questionId: string;
245
+ questionLabel: string;
246
+ error: string;
247
+ };
248
+ }
249
+ /**
250
+ * Public interface for the GetForty widget instance
251
+ */
252
+ interface GetFortyWidgetInstance {
253
+ /**
254
+ * Track a custom event
255
+ * @param eventName - Name of the event (e.g., 'page_view', 'purchase')
256
+ * @param properties - Optional custom properties
257
+ */
258
+ track(eventName: string, properties?: Record<string, unknown>): void;
259
+ /**
260
+ * Identify the current user
261
+ * Sends user data to backend and links events/respondents
262
+ * @param userId - Unique user identifier
263
+ * @param traits - Optional user traits (email, name, plan, etc.)
264
+ */
265
+ identify(userId: string, traits?: Record<string, unknown>): Promise<void>;
266
+ /**
267
+ * Show a feedback form
268
+ * @param formId - The form ID to display
269
+ */
270
+ showForm(formId: string): void;
271
+ /**
272
+ * Hide the currently displayed form
273
+ */
274
+ hideForm(): void;
275
+ /**
276
+ * Subscribe to widget lifecycle events
277
+ * @param event - Event name
278
+ * @param callback - Event handler
279
+ */
280
+ on<K extends keyof WidgetEventMap>(event: K, callback: (data: WidgetEventMap[K]) => void): void;
281
+ /**
282
+ * Unsubscribe from widget lifecycle events
283
+ */
284
+ off<K extends keyof WidgetEventMap>(event: K, callback: (data: WidgetEventMap[K]) => void): void;
285
+ /**
286
+ * Flush any queued events immediately
287
+ */
288
+ flush(): Promise<void>;
289
+ /**
290
+ * Get the current session ID
291
+ */
292
+ getSessionId(): string;
293
+ /**
294
+ * Destroy the widget and clean up resources
295
+ * Stops polling, clears timers, and removes DOM elements
296
+ */
297
+ destroy(): void;
298
+ }
299
+
300
+ /**
301
+ * Widget constants
302
+ */
303
+ declare const VERSION = "0.1.0";
304
+
305
+ /**
306
+ * @getforty/widget
307
+ * Embeddable feedback widget and event tracking SDK for GetForty
308
+ *
309
+ * Usage:
310
+ * ```typescript
311
+ * import { GetForty } from '@getforty/widget'
312
+ *
313
+ * const widget = await GetForty.init({
314
+ * trackingId: 'gf_xxxxxxxxxxxx',
315
+ * })
316
+ *
317
+ * // Track events
318
+ * widget.track('page_view', { page: '/pricing' })
319
+ *
320
+ * // Identify users
321
+ * widget.identify('user_123', { email: 'user@example.com' })
322
+ *
323
+ * // Show forms programmatically
324
+ * widget.showForm('form-id')
325
+ *
326
+ * // Listen to events
327
+ * widget.on('submit:success', (data) => {
328
+ * console.log('Feedback submitted!', data.responseId)
329
+ * })
330
+ * ```
331
+ */
332
+
333
+ /**
334
+ * GetForty namespace
335
+ * Main entry point for the widget SDK
336
+ */
337
+ declare const GetForty: {
338
+ /**
339
+ * Initialize the GetForty widget
340
+ * @param config - Widget configuration
341
+ * @returns Promise that resolves to a widget instance
342
+ * @throws Error if trackingId is missing or invalid
343
+ *
344
+ * @example
345
+ * ```typescript
346
+ * const widget = await GetForty.init({
347
+ * trackingId: 'gf_xxxxxxxxxxxx',
348
+ * debug: true, // Enable debug logging
349
+ * })
350
+ * ```
351
+ */
352
+ init(config: WidgetConfig): Promise<GetFortyWidgetInstance>;
353
+ /**
354
+ * Current SDK version
355
+ */
356
+ version: string;
357
+ };
358
+
359
+ export { type Answer, type FormConfig, GetForty, type GetFortyWidgetInstance, type IdentifyOptions, type Question, type TrackEventOptions, type TrackedEvent, type TranslationStrings, VERSION, type WidgetConfig, type WidgetEventMap, type WidgetTheme, GetForty as default };
@@ -0,0 +1,359 @@
1
+ /**
2
+ * Widget Configuration Types
3
+ * These types are exported publicly for developers using the widget
4
+ */
5
+ /**
6
+ * Primary configuration object passed to widget initialization
7
+ */
8
+ interface WidgetConfig {
9
+ /** Workspace tracking ID (required) - format: gf_xxxxxxxxxxxx */
10
+ trackingId: string;
11
+ /** Display language (default: auto-detect from browser) */
12
+ locale?: "en" | "pt-BR" | string;
13
+ /** Custom translations to override built-in strings */
14
+ translations?: Partial<TranslationStrings>;
15
+ /** Visual customization options for forms */
16
+ theme?: WidgetTheme;
17
+ /** Rendering mode for forms */
18
+ mode?: "inline" | "modal";
19
+ /** Target element for inline mode (CSS selector or HTMLElement) */
20
+ container?: string | HTMLElement;
21
+ /** Show/hide GetForty branding */
22
+ showBranding?: boolean;
23
+ /** Automatically track page views */
24
+ autoTrackPageViews?: boolean;
25
+ /** Automatically display forms based on server-side conditions (default: true) */
26
+ autoDisplay?: boolean;
27
+ /** API base URL (default: https://getforty.club) */
28
+ apiBaseUrl?: string;
29
+ /** Enable debug logging */
30
+ debug?: boolean;
31
+ /**
32
+ * Observe parent window's dataLayer (Google Tag Manager) and automatically
33
+ * send events through GetForty tracking pipeline (opt-in)
34
+ *
35
+ * When enabled, watches for events pushed to window.dataLayer and forwards
36
+ * them to GetForty's backend, allowing you to leverage existing GTM integrations.
37
+ *
38
+ * Note: Only works in same-origin scenarios (cross-origin iframes not supported)
39
+ */
40
+ observeDataLayer?: boolean;
41
+ /**
42
+ * Prefix added to dataLayer event names when sent to GetForty
43
+ * (default: "gtm_")
44
+ *
45
+ * Example: dataLayer event "purchase" becomes "gtm_purchase" in GetForty
46
+ */
47
+ dataLayerEventPrefix?: string;
48
+ /**
49
+ * Filter which dataLayer events to send (optional)
50
+ * Can be a RegExp to test event names or a function that returns boolean
51
+ *
52
+ * Examples:
53
+ * - /^custom_/ (only events starting with "custom_")
54
+ * - (name) => name !== "gtm.js" (exclude GTM internal events)
55
+ */
56
+ dataLayerEventFilter?: RegExp | ((eventName: string) => boolean);
57
+ }
58
+ /**
59
+ * Visual customization options for form UI
60
+ */
61
+ interface WidgetTheme {
62
+ /** Primary color for buttons and accents (CSS color) */
63
+ primaryColor?: string;
64
+ /** Background color for widget container (CSS color) */
65
+ backgroundColor?: string;
66
+ /** Text color (CSS color) */
67
+ textColor?: string;
68
+ /** Font family (CSS font-family) */
69
+ fontFamily?: string;
70
+ /** Border radius for containers and inputs (CSS value) */
71
+ borderRadius?: string;
72
+ }
73
+ /**
74
+ * Options for tracking a custom event
75
+ */
76
+ interface TrackEventOptions {
77
+ /** Custom properties to attach to the event */
78
+ properties?: Record<string, string | number | boolean | null>;
79
+ /** Override the auto-generated session ID */
80
+ sessionId?: string;
81
+ /** Override the identified user ID */
82
+ userId?: string;
83
+ /** Timestamp override (default: now) */
84
+ timestamp?: Date;
85
+ }
86
+ /**
87
+ * Options for identifying a user
88
+ */
89
+ interface IdentifyOptions {
90
+ /** User traits/properties */
91
+ traits?: Record<string, string | number | boolean | null>;
92
+ }
93
+ /**
94
+ * Internal representation of a tracked event
95
+ */
96
+ interface TrackedEvent {
97
+ /** Event name (e.g., 'page_view', 'purchase', 'signup') */
98
+ eventName: string;
99
+ /** Custom event properties */
100
+ properties?: Record<string, unknown>;
101
+ /** Session identifier (auto-generated or provided) */
102
+ sessionId: string;
103
+ /** User identifier (from identify() call) */
104
+ userId?: string;
105
+ /** Event timestamp */
106
+ timestamp: string;
107
+ /** Retry count for failed sends */
108
+ _retryCount?: number;
109
+ }
110
+ /**
111
+ * Localizable UI strings
112
+ */
113
+ interface TranslationStrings {
114
+ submit: string;
115
+ submitting: string;
116
+ next: string;
117
+ previous: string;
118
+ skip: string;
119
+ required: string;
120
+ invalidEmail: string;
121
+ invalidNumber: string;
122
+ minLength: string;
123
+ maxLength: string;
124
+ loading: string;
125
+ success: string;
126
+ successMessage: string;
127
+ error: string;
128
+ networkError: string;
129
+ rateLimited: string;
130
+ tryAgain: string;
131
+ npsNotLikely: string;
132
+ npsVeryLikely: string;
133
+ closeModal: string;
134
+ formLabel: string;
135
+ questionOf: string;
136
+ }
137
+ /**
138
+ * Form configuration received from API
139
+ */
140
+ interface FormConfig {
141
+ id: string;
142
+ title: string;
143
+ type: "NPS" | "CSAT" | "PMF" | "CUSTOM";
144
+ questions: Question[];
145
+ branding?: {
146
+ logoUrl?: string;
147
+ thankYouMessage?: string;
148
+ colors?: {
149
+ primary?: string;
150
+ background?: string;
151
+ };
152
+ };
153
+ }
154
+ /**
155
+ * Question definition within a form
156
+ */
157
+ interface Question {
158
+ id: string;
159
+ type: "rating" | "nps" | "text" | "textarea" | "select" | "multiselect" | "scale";
160
+ label: string;
161
+ description?: string;
162
+ required: boolean;
163
+ options?: QuestionOption[];
164
+ validation?: {
165
+ minLength?: number;
166
+ maxLength?: number;
167
+ pattern?: string;
168
+ };
169
+ }
170
+ /**
171
+ * Option for select/multiselect questions
172
+ */
173
+ interface QuestionOption {
174
+ value: string;
175
+ label: string;
176
+ }
177
+ /**
178
+ * Answer submitted for a question
179
+ */
180
+ interface Answer {
181
+ questionId: string;
182
+ value: string | string[] | number;
183
+ }
184
+ /**
185
+ * Events emitted by widget for developer integration
186
+ */
187
+ interface WidgetEventMap {
188
+ /** Widget started loading form configuration */
189
+ "load:start": {
190
+ formId: string;
191
+ };
192
+ /** Form configuration loaded successfully */
193
+ "load:success": {
194
+ form: FormConfig;
195
+ };
196
+ /** Form loading failed */
197
+ "load:error": {
198
+ error: string;
199
+ retryable: boolean;
200
+ };
201
+ /** Widget became visible (modal opened or inline rendered) */
202
+ open: {
203
+ mode: "inline" | "modal";
204
+ };
205
+ /** Widget hidden (modal closed) */
206
+ close: {
207
+ reason: "user" | "submitted" | "programmatic";
208
+ };
209
+ /** Form submission started */
210
+ "submit:start": {
211
+ answers: Answer[];
212
+ };
213
+ /** Form submission successful */
214
+ "submit:success": {
215
+ responseId: string;
216
+ };
217
+ /** Form submission failed */
218
+ "submit:error": {
219
+ error: string;
220
+ retryable: boolean;
221
+ };
222
+ /** Any error occurred */
223
+ error: {
224
+ type: "load" | "submit" | "network";
225
+ message: string;
226
+ };
227
+ /** Field received focus */
228
+ "field:focus": {
229
+ questionId: string;
230
+ questionLabel: string;
231
+ };
232
+ /** Field lost focus */
233
+ "field:blur": {
234
+ questionId: string;
235
+ questionLabel: string;
236
+ };
237
+ /** Field value changed */
238
+ "field:change": {
239
+ questionId: string;
240
+ questionLabel: string;
241
+ };
242
+ /** Field validation error */
243
+ "field:validation": {
244
+ questionId: string;
245
+ questionLabel: string;
246
+ error: string;
247
+ };
248
+ }
249
+ /**
250
+ * Public interface for the GetForty widget instance
251
+ */
252
+ interface GetFortyWidgetInstance {
253
+ /**
254
+ * Track a custom event
255
+ * @param eventName - Name of the event (e.g., 'page_view', 'purchase')
256
+ * @param properties - Optional custom properties
257
+ */
258
+ track(eventName: string, properties?: Record<string, unknown>): void;
259
+ /**
260
+ * Identify the current user
261
+ * Sends user data to backend and links events/respondents
262
+ * @param userId - Unique user identifier
263
+ * @param traits - Optional user traits (email, name, plan, etc.)
264
+ */
265
+ identify(userId: string, traits?: Record<string, unknown>): Promise<void>;
266
+ /**
267
+ * Show a feedback form
268
+ * @param formId - The form ID to display
269
+ */
270
+ showForm(formId: string): void;
271
+ /**
272
+ * Hide the currently displayed form
273
+ */
274
+ hideForm(): void;
275
+ /**
276
+ * Subscribe to widget lifecycle events
277
+ * @param event - Event name
278
+ * @param callback - Event handler
279
+ */
280
+ on<K extends keyof WidgetEventMap>(event: K, callback: (data: WidgetEventMap[K]) => void): void;
281
+ /**
282
+ * Unsubscribe from widget lifecycle events
283
+ */
284
+ off<K extends keyof WidgetEventMap>(event: K, callback: (data: WidgetEventMap[K]) => void): void;
285
+ /**
286
+ * Flush any queued events immediately
287
+ */
288
+ flush(): Promise<void>;
289
+ /**
290
+ * Get the current session ID
291
+ */
292
+ getSessionId(): string;
293
+ /**
294
+ * Destroy the widget and clean up resources
295
+ * Stops polling, clears timers, and removes DOM elements
296
+ */
297
+ destroy(): void;
298
+ }
299
+
300
+ /**
301
+ * Widget constants
302
+ */
303
+ declare const VERSION = "0.1.0";
304
+
305
+ /**
306
+ * @getforty/widget
307
+ * Embeddable feedback widget and event tracking SDK for GetForty
308
+ *
309
+ * Usage:
310
+ * ```typescript
311
+ * import { GetForty } from '@getforty/widget'
312
+ *
313
+ * const widget = await GetForty.init({
314
+ * trackingId: 'gf_xxxxxxxxxxxx',
315
+ * })
316
+ *
317
+ * // Track events
318
+ * widget.track('page_view', { page: '/pricing' })
319
+ *
320
+ * // Identify users
321
+ * widget.identify('user_123', { email: 'user@example.com' })
322
+ *
323
+ * // Show forms programmatically
324
+ * widget.showForm('form-id')
325
+ *
326
+ * // Listen to events
327
+ * widget.on('submit:success', (data) => {
328
+ * console.log('Feedback submitted!', data.responseId)
329
+ * })
330
+ * ```
331
+ */
332
+
333
+ /**
334
+ * GetForty namespace
335
+ * Main entry point for the widget SDK
336
+ */
337
+ declare const GetForty: {
338
+ /**
339
+ * Initialize the GetForty widget
340
+ * @param config - Widget configuration
341
+ * @returns Promise that resolves to a widget instance
342
+ * @throws Error if trackingId is missing or invalid
343
+ *
344
+ * @example
345
+ * ```typescript
346
+ * const widget = await GetForty.init({
347
+ * trackingId: 'gf_xxxxxxxxxxxx',
348
+ * debug: true, // Enable debug logging
349
+ * })
350
+ * ```
351
+ */
352
+ init(config: WidgetConfig): Promise<GetFortyWidgetInstance>;
353
+ /**
354
+ * Current SDK version
355
+ */
356
+ version: string;
357
+ };
358
+
359
+ export { type Answer, type FormConfig, GetForty, type GetFortyWidgetInstance, type IdentifyOptions, type Question, type TrackEventOptions, type TrackedEvent, type TranslationStrings, VERSION, type WidgetConfig, type WidgetEventMap, type WidgetTheme, GetForty as default };