@clipform/mcp-server 1.22.1 → 1.22.2
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/dist/{chunk-DDSNGWKB.js → chunk-G727XWN4.js} +6 -4
- package/dist/chunk-G727XWN4.js.map +1 -0
- package/dist/{chunk-CN4LJK36.js → chunk-H3DV5X53.js} +157 -1460
- package/dist/{chunk-CN4LJK36.js.map → chunk-H3DV5X53.js.map} +1 -1
- package/dist/{chunk-DWFACCUE.js → chunk-LMGXTF23.js} +67 -94
- package/dist/{chunk-DWFACCUE.js.map → chunk-LMGXTF23.js.map} +1 -1
- package/dist/chunk-ZDSVE6D3.js +2023 -0
- package/dist/chunk-ZDSVE6D3.js.map +1 -0
- package/dist/index.js +4 -4
- package/dist/prompts.d.ts +8 -17
- package/dist/prompts.js +2 -18
- package/dist/resources.d.ts +5 -4
- package/dist/resources.js +2 -2
- package/dist/server.js +4 -4
- package/package.json +1 -1
- package/dist/chunk-DDSNGWKB.js.map +0 -1
- package/dist/chunk-Z7CP5LVY.js +0 -188
- package/dist/chunk-Z7CP5LVY.js.map +0 -1
|
@@ -0,0 +1,2023 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getMcpAuth
|
|
3
|
+
} from "./chunk-HCZI2UJ5.js";
|
|
4
|
+
|
|
5
|
+
// ../config/form-types.js
|
|
6
|
+
var FORM_TYPES = {
|
|
7
|
+
quiz: {
|
|
8
|
+
label: "Quiz",
|
|
9
|
+
description: "Scored knowledge quiz with narrated video questions",
|
|
10
|
+
is_active: true,
|
|
11
|
+
sort_order: 1,
|
|
12
|
+
category: "assessment",
|
|
13
|
+
aliases: ["trivia", "test", "exam"],
|
|
14
|
+
variants: ["personality", "comprehension"],
|
|
15
|
+
required_features: [],
|
|
16
|
+
required_node_types: ["choice", "end_screen"],
|
|
17
|
+
default_media_style: "video",
|
|
18
|
+
guide_uri: "clipform://guides/quiz",
|
|
19
|
+
guide_description: "Craft knowledge for writing engaging quizzes - difficulty curves, question psychology, narration style, scoring",
|
|
20
|
+
discovery: [
|
|
21
|
+
{ key: "topic", question: "What topic or subject area?", fallback: "General trivia", mode: "all" },
|
|
22
|
+
{ key: "question_count", question: "How many questions?", fallback: "8", mode: "all" },
|
|
23
|
+
{ key: "media_style", question: "Video with narration (recommended), images, or text only?", fallback: "Video with narration", mode: "full" }
|
|
24
|
+
],
|
|
25
|
+
variant_discovery: {
|
|
26
|
+
personality: [
|
|
27
|
+
{ key: "topic", question: "What's the theme? (Which X are you?)", fallback: "General personality", mode: "all" },
|
|
28
|
+
{ key: "categories", question: "What outcome categories? (3-5 results)", fallback: "Infer 4 categories from the theme", mode: "full" },
|
|
29
|
+
{ key: "question_count", question: "How many questions?", fallback: "8", mode: "all" }
|
|
30
|
+
],
|
|
31
|
+
comprehension: [
|
|
32
|
+
{ key: "youtube_url", question: "What's the YouTube URL?", fallback: "REQUIRED - cannot proceed without it", mode: "all" },
|
|
33
|
+
{ key: "question_count", question: "How many questions?", fallback: "8", mode: "all" },
|
|
34
|
+
{ key: "audience", question: "Who's the audience? (kids, teens, adults)", fallback: "General adults", mode: "full" }
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
variant_guide_uris: {
|
|
38
|
+
personality: "clipform://guides/quiz/personality",
|
|
39
|
+
comprehension: "clipform://guides/quiz/comprehension"
|
|
40
|
+
},
|
|
41
|
+
variant_descriptions: {
|
|
42
|
+
personality: "Addendum for personality quizzes - category design, option weighting, outcome writing, no right/wrong answers",
|
|
43
|
+
comprehension: "Addendum for YouTube comprehension quizzes - extracting questions from transcripts, distractor design, audience adaptation"
|
|
44
|
+
},
|
|
45
|
+
prompt: { name: "create-quiz", title: "Create a Quiz", description: "Build a scored knowledge quiz with narrated video questions" }
|
|
46
|
+
},
|
|
47
|
+
survey: {
|
|
48
|
+
label: "Survey",
|
|
49
|
+
description: "Feedback survey, NPS form, or research questionnaire",
|
|
50
|
+
is_active: true,
|
|
51
|
+
sort_order: 2,
|
|
52
|
+
category: "feedback",
|
|
53
|
+
aliases: ["feedback", "poll", "nps", "questionnaire"],
|
|
54
|
+
variants: [],
|
|
55
|
+
required_features: [],
|
|
56
|
+
required_node_types: ["choice", "open", "end_screen"],
|
|
57
|
+
default_media_style: "text",
|
|
58
|
+
guide_uri: "clipform://guides/survey",
|
|
59
|
+
guide_description: "Craft knowledge for feedback surveys, NPS, and research forms - brevity, rating scales, respondent fatigue",
|
|
60
|
+
discovery: [
|
|
61
|
+
{ key: "topic", question: "What are you measuring? (satisfaction, NPS, feedback on what?)", fallback: "General satisfaction", mode: "all" },
|
|
62
|
+
{ key: "anonymous", question: "Anonymous or identified responses?", fallback: "Anonymous", mode: "full" }
|
|
63
|
+
],
|
|
64
|
+
variant_discovery: {},
|
|
65
|
+
variant_guide_uris: {},
|
|
66
|
+
variant_descriptions: {},
|
|
67
|
+
prompt: { name: "create-survey", title: "Create a Survey", description: "Build a feedback survey, NPS form, or research questionnaire" }
|
|
68
|
+
},
|
|
69
|
+
interview: {
|
|
70
|
+
label: "Interview",
|
|
71
|
+
description: "Async video interview, case study, or expert input collection",
|
|
72
|
+
is_active: true,
|
|
73
|
+
sort_order: 3,
|
|
74
|
+
category: "collection",
|
|
75
|
+
aliases: ["case-study", "callout"],
|
|
76
|
+
variants: [],
|
|
77
|
+
required_features: [],
|
|
78
|
+
required_node_types: ["open", "contact", "end_screen"],
|
|
79
|
+
default_media_style: "video",
|
|
80
|
+
guide_uri: "clipform://guides/interview",
|
|
81
|
+
guide_description: "Craft knowledge for building interview forms - warm-up pacing, open questions, consent, video responses",
|
|
82
|
+
discovery: [
|
|
83
|
+
{ key: "purpose", question: "What are you collecting? (case studies, feedback, expert input)", fallback: "General responses", mode: "all" },
|
|
84
|
+
{ key: "response_format", question: "How should people respond? (video, audio, text, all)", fallback: "All formats", mode: "full" },
|
|
85
|
+
{ key: "needs_consent", question: "Need a consent statement?", fallback: "Yes", mode: "full" }
|
|
86
|
+
],
|
|
87
|
+
variant_discovery: {},
|
|
88
|
+
variant_guide_uris: {},
|
|
89
|
+
variant_descriptions: {},
|
|
90
|
+
prompt: { name: "create-interview", title: "Create an Interview", description: "Build an async video interview for collecting case studies, feedback, or expert input" }
|
|
91
|
+
},
|
|
92
|
+
funnel: {
|
|
93
|
+
label: "Funnel",
|
|
94
|
+
description: "Lead qualification funnel with conditional routing",
|
|
95
|
+
is_active: false,
|
|
96
|
+
sort_order: 4,
|
|
97
|
+
category: "qualification",
|
|
98
|
+
aliases: ["lead-gen", "qualification", "lead-magnet"],
|
|
99
|
+
variants: [],
|
|
100
|
+
required_features: ["branching"],
|
|
101
|
+
required_node_types: ["choice", "contact", "end_screen"],
|
|
102
|
+
default_media_style: "text",
|
|
103
|
+
guide_uri: "clipform://guides/funnel",
|
|
104
|
+
guide_description: "Craft knowledge for lead qualification funnels - planned feature, conditional routing coming soon",
|
|
105
|
+
discovery: [],
|
|
106
|
+
variant_discovery: {},
|
|
107
|
+
variant_guide_uris: {},
|
|
108
|
+
variant_descriptions: {},
|
|
109
|
+
prompt: { name: "create-funnel", title: "Create a Funnel", description: "Lead qualification funnels with branching logic are planned but not yet available" }
|
|
110
|
+
},
|
|
111
|
+
testimonial: {
|
|
112
|
+
label: "Testimonial",
|
|
113
|
+
description: "Video testimonial and story collection form",
|
|
114
|
+
is_active: true,
|
|
115
|
+
sort_order: 5,
|
|
116
|
+
category: "collection",
|
|
117
|
+
aliases: ["story", "review"],
|
|
118
|
+
variants: [],
|
|
119
|
+
required_features: [],
|
|
120
|
+
required_node_types: ["open", "contact", "end_screen"],
|
|
121
|
+
default_media_style: "video",
|
|
122
|
+
guide_uri: "clipform://guides/testimonial",
|
|
123
|
+
guide_description: "Craft knowledge for collecting testimonials and customer stories on video - storytelling prompts, comfort techniques, consent",
|
|
124
|
+
discovery: [
|
|
125
|
+
{ key: "use_case", question: "What stories are you collecting? (customer success, employee, partner)", fallback: "Customer success stories", mode: "all" },
|
|
126
|
+
{ key: "media_style", question: "Video responses (recommended), audio, or text?", fallback: "Video", mode: "full" }
|
|
127
|
+
],
|
|
128
|
+
variant_discovery: {},
|
|
129
|
+
variant_guide_uris: {},
|
|
130
|
+
variant_descriptions: {},
|
|
131
|
+
prompt: { name: "create-testimonial", title: "Collect Testimonials", description: "Build a video testimonial collection form - capture authentic customer stories on camera" }
|
|
132
|
+
},
|
|
133
|
+
application: {
|
|
134
|
+
label: "Application",
|
|
135
|
+
description: "Structured application form for jobs, programmes, or grants",
|
|
136
|
+
is_active: true,
|
|
137
|
+
sort_order: 6,
|
|
138
|
+
category: "collection",
|
|
139
|
+
aliases: ["job-application", "admission", "enrollment", "grant"],
|
|
140
|
+
variants: [],
|
|
141
|
+
required_features: [],
|
|
142
|
+
required_node_types: ["open", "choice", "contact", "end_screen"],
|
|
143
|
+
default_media_style: "video",
|
|
144
|
+
guide_uri: "clipform://guides/application",
|
|
145
|
+
guide_description: "Craft knowledge for application and evaluation forms - multi-section structure, video responses for behavioural questions, screening",
|
|
146
|
+
discovery: [
|
|
147
|
+
{ key: "role", question: "What role or position?", fallback: "General application", mode: "all" }
|
|
148
|
+
],
|
|
149
|
+
variant_discovery: {},
|
|
150
|
+
variant_guide_uris: {},
|
|
151
|
+
variant_descriptions: {},
|
|
152
|
+
prompt: { name: "create-application", title: "Create an Application Form", description: "Build a structured application form with video responses for behavioural questions" }
|
|
153
|
+
},
|
|
154
|
+
booking: {
|
|
155
|
+
label: "Booking",
|
|
156
|
+
description: "Event registration, course signup, or booking form",
|
|
157
|
+
is_active: true,
|
|
158
|
+
sort_order: 7,
|
|
159
|
+
category: "registration",
|
|
160
|
+
aliases: ["registration", "signup", "event", "rsvp", "workshop"],
|
|
161
|
+
variants: [],
|
|
162
|
+
required_features: [],
|
|
163
|
+
required_node_types: ["contact", "choice", "end_screen"],
|
|
164
|
+
default_media_style: "text",
|
|
165
|
+
guide_uri: "clipform://guides/booking",
|
|
166
|
+
guide_description: "Craft knowledge for event registration and booking forms - minimal friction, video welcome, confirmation flow",
|
|
167
|
+
discovery: [
|
|
168
|
+
{ key: "event_name", question: "What's the event name?", fallback: "Event registration", mode: "all" },
|
|
169
|
+
{ key: "event_type", question: "What type? (workshop, webinar, meetup, conference)", fallback: "Event", mode: "full" }
|
|
170
|
+
],
|
|
171
|
+
variant_discovery: {},
|
|
172
|
+
variant_guide_uris: {},
|
|
173
|
+
variant_descriptions: {},
|
|
174
|
+
prompt: { name: "create-booking", title: "Create a Booking Form", description: "Build an event registration or booking form with a personal video welcome" }
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
var FORM_TYPES_LIST = Object.entries(FORM_TYPES).map(([key, def]) => ({ key, ...def })).sort((a, b) => a.sort_order - b.sort_order);
|
|
178
|
+
var FORM_TYPE_KEYS = Object.keys(FORM_TYPES);
|
|
179
|
+
var WORKFLOW_TYPES = FORM_TYPE_KEYS.filter(
|
|
180
|
+
(key) => FORM_TYPES[key].is_active
|
|
181
|
+
);
|
|
182
|
+
var FORM_TYPE_ALIASES = Object.fromEntries(
|
|
183
|
+
Object.entries(FORM_TYPES).flatMap(
|
|
184
|
+
([key, def]) => def.aliases.map((alias) => [alias, key])
|
|
185
|
+
)
|
|
186
|
+
);
|
|
187
|
+
var ALL_VARIANTS = Object.entries(FORM_TYPES).flatMap(
|
|
188
|
+
([, def]) => def.variants
|
|
189
|
+
);
|
|
190
|
+
function resolveFormType(input) {
|
|
191
|
+
const normalised = input.toLowerCase().trim();
|
|
192
|
+
if (FORM_TYPES[normalised]) return normalised;
|
|
193
|
+
return FORM_TYPE_ALIASES[normalised] ?? null;
|
|
194
|
+
}
|
|
195
|
+
function getDiscoveryParams(formType, variant, mode = "full") {
|
|
196
|
+
const def = FORM_TYPES[formType];
|
|
197
|
+
if (!def) return [];
|
|
198
|
+
let params;
|
|
199
|
+
if (variant && def.variant_discovery?.[variant]) {
|
|
200
|
+
params = def.variant_discovery[variant];
|
|
201
|
+
} else {
|
|
202
|
+
params = def.discovery;
|
|
203
|
+
}
|
|
204
|
+
if (mode === "demo") {
|
|
205
|
+
return params.filter((p) => p.mode === "all");
|
|
206
|
+
}
|
|
207
|
+
return params;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ../config/features.js
|
|
211
|
+
var FEATURES = {
|
|
212
|
+
// -- Builder --
|
|
213
|
+
visual_form_builder: {
|
|
214
|
+
name: "Visual form builder",
|
|
215
|
+
description: "Drag-and-drop node-based form builder powered by React Flow",
|
|
216
|
+
enabled: true,
|
|
217
|
+
status: "live",
|
|
218
|
+
category: "builder"
|
|
219
|
+
},
|
|
220
|
+
form_themes: {
|
|
221
|
+
name: "Form themes",
|
|
222
|
+
description: "Customise primary colour, background colour, and font",
|
|
223
|
+
enabled: true,
|
|
224
|
+
status: "live",
|
|
225
|
+
category: "builder"
|
|
226
|
+
},
|
|
227
|
+
media_prompts: {
|
|
228
|
+
name: "Media prompts",
|
|
229
|
+
description: "Attach video, audio, or images to any question node",
|
|
230
|
+
enabled: true,
|
|
231
|
+
status: "live",
|
|
232
|
+
category: "builder"
|
|
233
|
+
},
|
|
234
|
+
node_logic: {
|
|
235
|
+
name: "Node routing logic",
|
|
236
|
+
description: "Define the order nodes appear in - currently supports linear paths (A to B to C)",
|
|
237
|
+
enabled: true,
|
|
238
|
+
status: "live",
|
|
239
|
+
category: "builder"
|
|
240
|
+
},
|
|
241
|
+
branching: {
|
|
242
|
+
name: "Conditional branching",
|
|
243
|
+
description: "Choice nodes route to different destinations based on which option is picked",
|
|
244
|
+
enabled: false,
|
|
245
|
+
status: "planned",
|
|
246
|
+
category: "builder"
|
|
247
|
+
},
|
|
248
|
+
custom_scores: {
|
|
249
|
+
name: "Custom scoring",
|
|
250
|
+
description: "Assign scores to choice options for quizzes and assessments",
|
|
251
|
+
enabled: false,
|
|
252
|
+
status: "planned",
|
|
253
|
+
category: "builder"
|
|
254
|
+
},
|
|
255
|
+
text_response: {
|
|
256
|
+
name: "Text response option",
|
|
257
|
+
description: "Allow free-text input alongside choice options",
|
|
258
|
+
enabled: false,
|
|
259
|
+
status: "planned",
|
|
260
|
+
category: "builder"
|
|
261
|
+
},
|
|
262
|
+
custom_fonts: {
|
|
263
|
+
name: "Custom fonts",
|
|
264
|
+
description: "Upload and use custom fonts in forms",
|
|
265
|
+
enabled: false,
|
|
266
|
+
status: "planned",
|
|
267
|
+
category: "builder"
|
|
268
|
+
},
|
|
269
|
+
brand_name: {
|
|
270
|
+
name: "Custom brand name",
|
|
271
|
+
description: "Replace Clipform branding with your own brand name",
|
|
272
|
+
enabled: false,
|
|
273
|
+
status: "planned",
|
|
274
|
+
category: "builder"
|
|
275
|
+
},
|
|
276
|
+
allow_resume: {
|
|
277
|
+
name: "Session resume",
|
|
278
|
+
description: "Respondents can continue a form where they left off",
|
|
279
|
+
enabled: true,
|
|
280
|
+
status: "live",
|
|
281
|
+
category: "builder"
|
|
282
|
+
},
|
|
283
|
+
// -- Node types --
|
|
284
|
+
node_start: {
|
|
285
|
+
name: "Start node",
|
|
286
|
+
description: "Entry point for every form",
|
|
287
|
+
enabled: true,
|
|
288
|
+
status: "live",
|
|
289
|
+
category: "node-types"
|
|
290
|
+
},
|
|
291
|
+
node_choice: {
|
|
292
|
+
name: "Multiple choice",
|
|
293
|
+
description: "Single or multi-select questions with configurable options",
|
|
294
|
+
enabled: true,
|
|
295
|
+
status: "live",
|
|
296
|
+
category: "node-types"
|
|
297
|
+
},
|
|
298
|
+
node_open: {
|
|
299
|
+
name: "Open-ended questions",
|
|
300
|
+
description: "Free-form responses via text, audio, or video",
|
|
301
|
+
enabled: true,
|
|
302
|
+
status: "live",
|
|
303
|
+
category: "node-types"
|
|
304
|
+
},
|
|
305
|
+
node_contact: {
|
|
306
|
+
name: "Contact form",
|
|
307
|
+
description: "Structured fields (name, email, phone, company) with consent checkboxes",
|
|
308
|
+
enabled: true,
|
|
309
|
+
status: "live",
|
|
310
|
+
category: "node-types"
|
|
311
|
+
},
|
|
312
|
+
node_button: {
|
|
313
|
+
name: "Button",
|
|
314
|
+
description: "Simple navigation or statement node",
|
|
315
|
+
enabled: true,
|
|
316
|
+
status: "live",
|
|
317
|
+
category: "node-types"
|
|
318
|
+
},
|
|
319
|
+
node_redirect: {
|
|
320
|
+
name: "Redirect",
|
|
321
|
+
description: "Terminal node that sends respondents to an external URL",
|
|
322
|
+
enabled: true,
|
|
323
|
+
status: "live",
|
|
324
|
+
category: "node-types"
|
|
325
|
+
},
|
|
326
|
+
node_end_screen: {
|
|
327
|
+
name: "End screen",
|
|
328
|
+
description: "Configurable thank-you screen with messaging, CTAs, and share button",
|
|
329
|
+
enabled: true,
|
|
330
|
+
status: "live",
|
|
331
|
+
category: "node-types"
|
|
332
|
+
},
|
|
333
|
+
node_scale: {
|
|
334
|
+
name: "Scale / rating",
|
|
335
|
+
description: "Numerical rating questions (1-10, stars, etc.)",
|
|
336
|
+
enabled: false,
|
|
337
|
+
status: "planned",
|
|
338
|
+
category: "node-types"
|
|
339
|
+
},
|
|
340
|
+
node_file_upload: {
|
|
341
|
+
name: "File upload",
|
|
342
|
+
description: "Collect files from respondents",
|
|
343
|
+
enabled: false,
|
|
344
|
+
status: "planned",
|
|
345
|
+
category: "node-types"
|
|
346
|
+
},
|
|
347
|
+
node_booking: {
|
|
348
|
+
name: "Booking",
|
|
349
|
+
description: "Calendly or Google Meet scheduling embedded in the form",
|
|
350
|
+
enabled: false,
|
|
351
|
+
status: "planned",
|
|
352
|
+
category: "node-types"
|
|
353
|
+
},
|
|
354
|
+
node_payment: {
|
|
355
|
+
name: "Payment",
|
|
356
|
+
description: "Collect payments via Stripe or Paddle inline",
|
|
357
|
+
enabled: false,
|
|
358
|
+
status: "planned",
|
|
359
|
+
category: "node-types"
|
|
360
|
+
},
|
|
361
|
+
// -- Response formats --
|
|
362
|
+
text_responses: {
|
|
363
|
+
name: "Text responses",
|
|
364
|
+
description: "Respondents type free-form text answers",
|
|
365
|
+
enabled: true,
|
|
366
|
+
status: "live",
|
|
367
|
+
category: "responses"
|
|
368
|
+
},
|
|
369
|
+
audio_responses: {
|
|
370
|
+
name: "Audio responses",
|
|
371
|
+
description: "Respondents record audio directly in the browser",
|
|
372
|
+
enabled: true,
|
|
373
|
+
status: "live",
|
|
374
|
+
category: "responses"
|
|
375
|
+
},
|
|
376
|
+
video_responses: {
|
|
377
|
+
name: "Video responses",
|
|
378
|
+
description: "Respondents record video directly in the browser",
|
|
379
|
+
enabled: true,
|
|
380
|
+
status: "live",
|
|
381
|
+
category: "responses"
|
|
382
|
+
},
|
|
383
|
+
audio_attachments: {
|
|
384
|
+
name: "Audio attachments",
|
|
385
|
+
description: "Attach audio files to form nodes",
|
|
386
|
+
enabled: false,
|
|
387
|
+
status: "planned",
|
|
388
|
+
category: "responses"
|
|
389
|
+
},
|
|
390
|
+
transcription: {
|
|
391
|
+
name: "Auto-transcription",
|
|
392
|
+
description: "Whisper-powered transcription for audio and video responses",
|
|
393
|
+
enabled: true,
|
|
394
|
+
status: "live",
|
|
395
|
+
category: "responses"
|
|
396
|
+
},
|
|
397
|
+
// -- Analytics --
|
|
398
|
+
analytics_overview: {
|
|
399
|
+
name: "Analytics dashboard",
|
|
400
|
+
description: "Views, starts, completions with daily time series",
|
|
401
|
+
enabled: true,
|
|
402
|
+
status: "live",
|
|
403
|
+
category: "analytics"
|
|
404
|
+
},
|
|
405
|
+
analytics_demographics: {
|
|
406
|
+
name: "Demographic breakdown",
|
|
407
|
+
description: "Country, browser, device, and referrer source analytics",
|
|
408
|
+
enabled: true,
|
|
409
|
+
status: "live",
|
|
410
|
+
category: "analytics"
|
|
411
|
+
},
|
|
412
|
+
utm_tracking: {
|
|
413
|
+
name: "UTM parameter tracking",
|
|
414
|
+
description: "Track utm_source, utm_medium, utm_campaign on form views",
|
|
415
|
+
enabled: false,
|
|
416
|
+
status: "planned",
|
|
417
|
+
category: "analytics"
|
|
418
|
+
},
|
|
419
|
+
csv_export: {
|
|
420
|
+
name: "CSV export",
|
|
421
|
+
description: "Export analytics and response data to CSV",
|
|
422
|
+
enabled: false,
|
|
423
|
+
status: "planned",
|
|
424
|
+
category: "analytics"
|
|
425
|
+
},
|
|
426
|
+
tracked_links: {
|
|
427
|
+
name: "Tracked links",
|
|
428
|
+
description: "URL tracking and click-through analytics for shared form links",
|
|
429
|
+
enabled: false,
|
|
430
|
+
status: "planned",
|
|
431
|
+
category: "analytics"
|
|
432
|
+
},
|
|
433
|
+
// -- Sharing & embedding --
|
|
434
|
+
public_share_links: {
|
|
435
|
+
name: "Public share links",
|
|
436
|
+
description: "Share forms via a public URL",
|
|
437
|
+
enabled: true,
|
|
438
|
+
status: "live",
|
|
439
|
+
category: "sharing"
|
|
440
|
+
},
|
|
441
|
+
share_node: {
|
|
442
|
+
name: "Share individual nodes",
|
|
443
|
+
description: "Share a direct link to a specific node within a form",
|
|
444
|
+
enabled: false,
|
|
445
|
+
status: "planned",
|
|
446
|
+
category: "sharing"
|
|
447
|
+
},
|
|
448
|
+
embed_widget: {
|
|
449
|
+
name: "Embed widget",
|
|
450
|
+
description: "Embed forms on external websites via JavaScript widget",
|
|
451
|
+
enabled: false,
|
|
452
|
+
status: "planned",
|
|
453
|
+
category: "sharing"
|
|
454
|
+
},
|
|
455
|
+
embed_autoplay: {
|
|
456
|
+
name: "Embed autoplay",
|
|
457
|
+
description: "Auto-play media when forms are embedded on external sites",
|
|
458
|
+
enabled: false,
|
|
459
|
+
status: "planned",
|
|
460
|
+
category: "sharing"
|
|
461
|
+
},
|
|
462
|
+
remove_branding: {
|
|
463
|
+
name: "Remove branding",
|
|
464
|
+
description: "Hide Clipform watermark (Pro plan)",
|
|
465
|
+
enabled: true,
|
|
466
|
+
status: "live",
|
|
467
|
+
category: "sharing"
|
|
468
|
+
},
|
|
469
|
+
// -- AI --
|
|
470
|
+
ai_form_generation: {
|
|
471
|
+
name: "AI form generation",
|
|
472
|
+
description: "Generate complete forms from a text prompt via MCP or dashboard",
|
|
473
|
+
enabled: true,
|
|
474
|
+
status: "live",
|
|
475
|
+
category: "ai"
|
|
476
|
+
},
|
|
477
|
+
ai_tts: {
|
|
478
|
+
name: "AI text-to-speech",
|
|
479
|
+
description: "Generate voiceover audio for form prompts",
|
|
480
|
+
enabled: true,
|
|
481
|
+
status: "live",
|
|
482
|
+
category: "ai"
|
|
483
|
+
},
|
|
484
|
+
// -- API --
|
|
485
|
+
public_api: {
|
|
486
|
+
name: "Public API",
|
|
487
|
+
description: "REST API for form creation, node management, and response collection",
|
|
488
|
+
enabled: true,
|
|
489
|
+
status: "live",
|
|
490
|
+
category: "api"
|
|
491
|
+
},
|
|
492
|
+
api_keys: {
|
|
493
|
+
name: "API key management",
|
|
494
|
+
description: "Self-service API key creation in the dashboard",
|
|
495
|
+
enabled: false,
|
|
496
|
+
status: "planned",
|
|
497
|
+
category: "api"
|
|
498
|
+
},
|
|
499
|
+
// -- Integrations --
|
|
500
|
+
webhooks: {
|
|
501
|
+
name: "Webhooks",
|
|
502
|
+
description: "Send response data to external URLs on form completion",
|
|
503
|
+
enabled: false,
|
|
504
|
+
status: "planned",
|
|
505
|
+
category: "integrations"
|
|
506
|
+
},
|
|
507
|
+
integrations: {
|
|
508
|
+
name: "Third-party integrations",
|
|
509
|
+
description: "Connect forms to external services (Zapier, HubSpot, Slack, etc.)",
|
|
510
|
+
enabled: false,
|
|
511
|
+
status: "planned",
|
|
512
|
+
category: "integrations"
|
|
513
|
+
},
|
|
514
|
+
notifications: {
|
|
515
|
+
name: "Response notifications",
|
|
516
|
+
description: "Email or webhook alerts when new responses arrive",
|
|
517
|
+
enabled: false,
|
|
518
|
+
status: "planned",
|
|
519
|
+
category: "integrations"
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
// ../config/node-types.js
|
|
524
|
+
var NODE_TYPES = {
|
|
525
|
+
start: {
|
|
526
|
+
label: "Start",
|
|
527
|
+
shorthand: "Start",
|
|
528
|
+
icon: "ArrowRight",
|
|
529
|
+
color: "#D1FAE5",
|
|
530
|
+
description: "Entry point for the form - connects to the first node",
|
|
531
|
+
category: "start",
|
|
532
|
+
sort_order: 0,
|
|
533
|
+
has_options: false,
|
|
534
|
+
is_terminal: false,
|
|
535
|
+
show_nav_bar: false,
|
|
536
|
+
loading: "eager",
|
|
537
|
+
supports_prompt: false,
|
|
538
|
+
supports_media: false,
|
|
539
|
+
is_system: true,
|
|
540
|
+
is_active: true,
|
|
541
|
+
show_in_results: false,
|
|
542
|
+
default_config: null,
|
|
543
|
+
config_schema: null,
|
|
544
|
+
response_schema: null,
|
|
545
|
+
output_schema: null
|
|
546
|
+
},
|
|
547
|
+
choice: {
|
|
548
|
+
label: "Multiple Choice",
|
|
549
|
+
shorthand: "Multi",
|
|
550
|
+
icon: "CheckSquare",
|
|
551
|
+
color: "#DBEAFE",
|
|
552
|
+
description: "Single or multiple choice node with predefined options",
|
|
553
|
+
category: "input",
|
|
554
|
+
sort_order: 1,
|
|
555
|
+
has_options: true,
|
|
556
|
+
min_options: 1,
|
|
557
|
+
max_options: 6,
|
|
558
|
+
max_option_length: 36,
|
|
559
|
+
is_terminal: false,
|
|
560
|
+
show_nav_bar: true,
|
|
561
|
+
loading: "eager",
|
|
562
|
+
supports_prompt: true,
|
|
563
|
+
supports_media: true,
|
|
564
|
+
is_system: false,
|
|
565
|
+
is_active: true,
|
|
566
|
+
show_in_results: true,
|
|
567
|
+
default_config: {
|
|
568
|
+
selection_mode: "single",
|
|
569
|
+
choice: { enable_branching: true, record_scores: false },
|
|
570
|
+
randomise_options: false,
|
|
571
|
+
show_option_count: false,
|
|
572
|
+
options: [
|
|
573
|
+
{ content: "Option 1" },
|
|
574
|
+
{ content: "Option 2" }
|
|
575
|
+
]
|
|
576
|
+
},
|
|
577
|
+
config_schema: {
|
|
578
|
+
type: "object",
|
|
579
|
+
properties: {
|
|
580
|
+
choice: {
|
|
581
|
+
type: "object",
|
|
582
|
+
properties: {
|
|
583
|
+
enable_branching: {
|
|
584
|
+
type: "boolean",
|
|
585
|
+
label: "Enable branching logic",
|
|
586
|
+
default: true,
|
|
587
|
+
description: "Allow each option to have its own logic path. When disabled, all options share a single jump action."
|
|
588
|
+
},
|
|
589
|
+
show_answer_feedback: {
|
|
590
|
+
type: "boolean",
|
|
591
|
+
label: "Show answer feedback",
|
|
592
|
+
default: false,
|
|
593
|
+
description: "Show correct/incorrect feedback after selection (requires scored options)."
|
|
594
|
+
},
|
|
595
|
+
record_scores: {
|
|
596
|
+
type: "boolean",
|
|
597
|
+
label: "Mark correct answer",
|
|
598
|
+
default: false,
|
|
599
|
+
description: "Select which option is the correct answer."
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
},
|
|
603
|
+
selection_mode: {
|
|
604
|
+
enum: ["single", "multiple"],
|
|
605
|
+
type: "string",
|
|
606
|
+
label: "Selection mode",
|
|
607
|
+
default: "single",
|
|
608
|
+
description: "Allow single or multiple selections"
|
|
609
|
+
},
|
|
610
|
+
allow_text_response: {
|
|
611
|
+
type: "boolean",
|
|
612
|
+
label: "Allow text response",
|
|
613
|
+
default: false,
|
|
614
|
+
description: "Allow free-text response in addition to options (single choice only)"
|
|
615
|
+
},
|
|
616
|
+
randomise_options: {
|
|
617
|
+
type: "boolean",
|
|
618
|
+
label: "Randomise options",
|
|
619
|
+
default: false,
|
|
620
|
+
description: "Show options in random order"
|
|
621
|
+
},
|
|
622
|
+
show_option_count: {
|
|
623
|
+
type: "boolean",
|
|
624
|
+
label: "Show option count",
|
|
625
|
+
default: false,
|
|
626
|
+
description: "Display number of options"
|
|
627
|
+
},
|
|
628
|
+
content_media_type: {
|
|
629
|
+
enum: ["upload", "recorded"],
|
|
630
|
+
type: "string",
|
|
631
|
+
label: "Content media type",
|
|
632
|
+
description: "How the node media was provided"
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
},
|
|
636
|
+
response_schema: {
|
|
637
|
+
type: "string",
|
|
638
|
+
description: "Selected option ID"
|
|
639
|
+
},
|
|
640
|
+
output_schema: {
|
|
641
|
+
type: "object",
|
|
642
|
+
required: ["type", "label", "option_id"],
|
|
643
|
+
properties: {
|
|
644
|
+
type: { type: "string", const: "choice" },
|
|
645
|
+
label: { type: "string", description: "Human-readable option label" },
|
|
646
|
+
option_id: { type: "string", format: "uuid", description: "Selected option UUID" }
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
},
|
|
650
|
+
open: {
|
|
651
|
+
label: "Open Ended",
|
|
652
|
+
shorthand: "Open",
|
|
653
|
+
icon: "Type",
|
|
654
|
+
color: "#DBEAFE",
|
|
655
|
+
description: "Free-form text responses from users",
|
|
656
|
+
category: "input",
|
|
657
|
+
sort_order: 2,
|
|
658
|
+
has_options: false,
|
|
659
|
+
is_terminal: false,
|
|
660
|
+
show_nav_bar: true,
|
|
661
|
+
loading: "eager",
|
|
662
|
+
supports_prompt: true,
|
|
663
|
+
supports_media: true,
|
|
664
|
+
is_system: false,
|
|
665
|
+
is_active: true,
|
|
666
|
+
show_in_results: true,
|
|
667
|
+
default_config: {
|
|
668
|
+
formats: [
|
|
669
|
+
{ order: 0, format: "text" },
|
|
670
|
+
{ order: 1, format: "audio" },
|
|
671
|
+
{ order: 2, format: "video" }
|
|
672
|
+
]
|
|
673
|
+
},
|
|
674
|
+
config_schema: {
|
|
675
|
+
type: "object",
|
|
676
|
+
properties: {
|
|
677
|
+
formats: {
|
|
678
|
+
type: "array",
|
|
679
|
+
items: {
|
|
680
|
+
type: "object",
|
|
681
|
+
properties: {
|
|
682
|
+
format: { enum: ["text", "audio", "video"], type: "string" },
|
|
683
|
+
order: { type: "number" }
|
|
684
|
+
}
|
|
685
|
+
},
|
|
686
|
+
label: "Allowed response formats",
|
|
687
|
+
description: "Which formats the user can respond with, in display order"
|
|
688
|
+
},
|
|
689
|
+
content_media_type: {
|
|
690
|
+
enum: ["upload", "recorded"],
|
|
691
|
+
type: "string",
|
|
692
|
+
label: "Content media type",
|
|
693
|
+
description: "How the node media was provided"
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
},
|
|
697
|
+
response_schema: {
|
|
698
|
+
type: "object",
|
|
699
|
+
required: ["response_type"],
|
|
700
|
+
properties: {
|
|
701
|
+
text: {
|
|
702
|
+
type: "string",
|
|
703
|
+
description: "Text response (when response_type is text) or transcribed text from audio/video"
|
|
704
|
+
},
|
|
705
|
+
media: {
|
|
706
|
+
type: "object",
|
|
707
|
+
properties: {
|
|
708
|
+
type: { enum: ["audio", "video"], type: "string" },
|
|
709
|
+
storage_path: { type: "string" },
|
|
710
|
+
facing_mode: { enum: ["user", "environment"], type: "string" },
|
|
711
|
+
preview_crop: {
|
|
712
|
+
type: "object",
|
|
713
|
+
properties: {
|
|
714
|
+
stream_width: { type: "number" },
|
|
715
|
+
stream_height: { type: "number" },
|
|
716
|
+
preview_width: { type: "number" },
|
|
717
|
+
preview_height: { type: "number" }
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
},
|
|
721
|
+
description: "Media response (when response_type is audio or video)"
|
|
722
|
+
},
|
|
723
|
+
response_type: {
|
|
724
|
+
enum: ["text", "audio", "video"],
|
|
725
|
+
type: "string"
|
|
726
|
+
},
|
|
727
|
+
transcription: {
|
|
728
|
+
type: "object",
|
|
729
|
+
properties: {
|
|
730
|
+
text: { type: "string" },
|
|
731
|
+
language: { type: "string" },
|
|
732
|
+
duration: { type: "number" },
|
|
733
|
+
words: { type: "array" }
|
|
734
|
+
},
|
|
735
|
+
description: "Whisper transcription data for audio/video responses"
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
},
|
|
739
|
+
output_schema: {
|
|
740
|
+
type: "object",
|
|
741
|
+
required: ["type"],
|
|
742
|
+
properties: {
|
|
743
|
+
type: { type: "string", const: "text" },
|
|
744
|
+
text: { type: "string", description: "Text response or transcription" },
|
|
745
|
+
media: {
|
|
746
|
+
type: "object",
|
|
747
|
+
properties: {
|
|
748
|
+
type: { enum: ["audio", "video"], type: "string" },
|
|
749
|
+
storage_path: { type: "string" },
|
|
750
|
+
facing_mode: { enum: ["user", "environment"], type: "string" },
|
|
751
|
+
preview_crop: {
|
|
752
|
+
type: "object",
|
|
753
|
+
properties: {
|
|
754
|
+
stream_width: { type: "number" },
|
|
755
|
+
stream_height: { type: "number" },
|
|
756
|
+
preview_width: { type: "number" },
|
|
757
|
+
preview_height: { type: "number" }
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
},
|
|
762
|
+
transcription: {
|
|
763
|
+
type: "object",
|
|
764
|
+
properties: {
|
|
765
|
+
text: { type: "string" },
|
|
766
|
+
language: { type: "string" }
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
},
|
|
772
|
+
scale: {
|
|
773
|
+
label: "Scale",
|
|
774
|
+
shorthand: "Scale",
|
|
775
|
+
icon: "BarChart3",
|
|
776
|
+
color: "#DBEAFE",
|
|
777
|
+
description: "Numerical rating or scale node (1-10, etc.)",
|
|
778
|
+
category: "input",
|
|
779
|
+
sort_order: 3,
|
|
780
|
+
has_options: false,
|
|
781
|
+
is_terminal: false,
|
|
782
|
+
show_nav_bar: true,
|
|
783
|
+
loading: "eager",
|
|
784
|
+
supports_prompt: true,
|
|
785
|
+
supports_media: true,
|
|
786
|
+
is_system: false,
|
|
787
|
+
is_active: false,
|
|
788
|
+
show_in_results: true,
|
|
789
|
+
default_config: null,
|
|
790
|
+
config_schema: {
|
|
791
|
+
type: "object",
|
|
792
|
+
properties: {
|
|
793
|
+
max: { type: "number", label: "Maximum value", default: 10, required: true },
|
|
794
|
+
min: { type: "number", label: "Minimum value", default: 1, required: true },
|
|
795
|
+
step: { min: 0.1, type: "number", label: "Step increment", default: 1 },
|
|
796
|
+
left_label: { type: "string", label: "Left label", placeholder: "Not likely" },
|
|
797
|
+
right_label: { type: "string", label: "Right label", placeholder: "Very likely" },
|
|
798
|
+
show_numbers: { type: "boolean", label: "Show numbers", default: true }
|
|
799
|
+
}
|
|
800
|
+
},
|
|
801
|
+
response_schema: {
|
|
802
|
+
type: "number",
|
|
803
|
+
description: "Selected scale value"
|
|
804
|
+
},
|
|
805
|
+
output_schema: null
|
|
806
|
+
},
|
|
807
|
+
booking: {
|
|
808
|
+
label: "Booking",
|
|
809
|
+
shorthand: "Booking",
|
|
810
|
+
icon: "Calendar",
|
|
811
|
+
color: "#E9D5FF",
|
|
812
|
+
description: null,
|
|
813
|
+
category: "action",
|
|
814
|
+
sort_order: 4,
|
|
815
|
+
has_options: false,
|
|
816
|
+
is_terminal: false,
|
|
817
|
+
show_nav_bar: true,
|
|
818
|
+
loading: "lazy",
|
|
819
|
+
supports_prompt: false,
|
|
820
|
+
supports_media: false,
|
|
821
|
+
is_system: false,
|
|
822
|
+
is_active: false,
|
|
823
|
+
show_in_results: true,
|
|
824
|
+
default_config: null,
|
|
825
|
+
config_schema: {
|
|
826
|
+
type: "object",
|
|
827
|
+
oneOf: [
|
|
828
|
+
{
|
|
829
|
+
required: ["calendly"],
|
|
830
|
+
properties: {
|
|
831
|
+
calendly: {
|
|
832
|
+
type: "object",
|
|
833
|
+
properties: {
|
|
834
|
+
event_name: { type: "string", label: "Event name", description: "Display name for the event" },
|
|
835
|
+
event_type_uri: { type: "string", label: "Event type URI", format: "uri", description: "Your Calendly event type URI", placeholder: "https://calendly.com/your-link" }
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
required: ["google_meet"],
|
|
842
|
+
properties: {
|
|
843
|
+
google_meet: {
|
|
844
|
+
type: "object",
|
|
845
|
+
properties: {
|
|
846
|
+
duration: { type: "number", label: "Duration (minutes)", default: 30, description: "Meeting duration in minutes" },
|
|
847
|
+
calendar_id: { type: "string", label: "Calendar", description: "Google Calendar to use for bookings" },
|
|
848
|
+
event_title: { type: "string", label: "Event title", default: "Meeting", description: "Default title for scheduled meetings" },
|
|
849
|
+
calendar_name: { type: "string", label: "Calendar name", description: "Display name for the selected calendar" }
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
],
|
|
855
|
+
description: "Booking provider configuration (one provider per node)"
|
|
856
|
+
},
|
|
857
|
+
response_schema: {
|
|
858
|
+
type: "object",
|
|
859
|
+
oneOf: [
|
|
860
|
+
{
|
|
861
|
+
required: ["calendly"],
|
|
862
|
+
properties: {
|
|
863
|
+
calendly: {
|
|
864
|
+
type: "object",
|
|
865
|
+
required: ["event_uri", "scheduled_time"],
|
|
866
|
+
properties: {
|
|
867
|
+
event_uri: { type: "string", format: "uri" },
|
|
868
|
+
event_type: { type: "string" },
|
|
869
|
+
invitee_uri: { type: "string", format: "uri" },
|
|
870
|
+
reschedule_url: { type: "string", format: "uri" },
|
|
871
|
+
scheduled_time: { type: "string", format: "date-time" },
|
|
872
|
+
cancellation_url: { type: "string", format: "uri" }
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
],
|
|
878
|
+
description: "Booking response with provider-specific data"
|
|
879
|
+
},
|
|
880
|
+
output_schema: null
|
|
881
|
+
},
|
|
882
|
+
contact: {
|
|
883
|
+
label: "Contact Form",
|
|
884
|
+
shorthand: "Contact",
|
|
885
|
+
icon: "User",
|
|
886
|
+
color: "#FEF9C3",
|
|
887
|
+
description: "Collect standardized contact information (name, email, phone, company)",
|
|
888
|
+
category: "input",
|
|
889
|
+
sort_order: 5,
|
|
890
|
+
has_options: false,
|
|
891
|
+
is_terminal: false,
|
|
892
|
+
show_nav_bar: true,
|
|
893
|
+
loading: "lazy",
|
|
894
|
+
supports_prompt: false,
|
|
895
|
+
supports_media: false,
|
|
896
|
+
is_system: false,
|
|
897
|
+
is_active: true,
|
|
898
|
+
show_in_results: false,
|
|
899
|
+
default_config: {
|
|
900
|
+
fields: [
|
|
901
|
+
{ id: "first_name", type: "first_name", label: "First Name", enabled: true, required: true },
|
|
902
|
+
{ id: "email", type: "email", label: "Email", enabled: true, required: true }
|
|
903
|
+
],
|
|
904
|
+
consent_items: [
|
|
905
|
+
{ id: "default-consent", name: "Privacy policy", label: "I agree to the privacy policy and terms of service", order: 0, type: "consent" }
|
|
906
|
+
]
|
|
907
|
+
},
|
|
908
|
+
config_schema: {
|
|
909
|
+
type: "object",
|
|
910
|
+
required: ["fields"],
|
|
911
|
+
properties: {
|
|
912
|
+
title: { type: "string" },
|
|
913
|
+
fields: {
|
|
914
|
+
type: "array",
|
|
915
|
+
minItems: 1,
|
|
916
|
+
items: {
|
|
917
|
+
type: "object",
|
|
918
|
+
required: ["id", "required"],
|
|
919
|
+
properties: {
|
|
920
|
+
id: { type: "string" },
|
|
921
|
+
type: { enum: ["text", "textarea", "email", "tel", "url"], type: "string" },
|
|
922
|
+
label: { type: "string" },
|
|
923
|
+
order: { type: "number" },
|
|
924
|
+
required: { type: "boolean", default: true },
|
|
925
|
+
is_custom: { type: "boolean", default: false }
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
},
|
|
929
|
+
description: { type: "string" },
|
|
930
|
+
consent_items: {
|
|
931
|
+
type: "array",
|
|
932
|
+
items: {
|
|
933
|
+
type: "object",
|
|
934
|
+
properties: {
|
|
935
|
+
id: { type: "string" },
|
|
936
|
+
name: { type: "string" },
|
|
937
|
+
label: { type: "string" },
|
|
938
|
+
order: { type: "number" },
|
|
939
|
+
type: { type: "string", enum: ["consent", "opt_in"] }
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
},
|
|
945
|
+
response_schema: {
|
|
946
|
+
type: "object",
|
|
947
|
+
required: ["fields"],
|
|
948
|
+
properties: {
|
|
949
|
+
fields: {
|
|
950
|
+
type: "array",
|
|
951
|
+
items: {
|
|
952
|
+
type: "object",
|
|
953
|
+
required: ["id", "type", "label", "value"],
|
|
954
|
+
properties: {
|
|
955
|
+
id: { type: "string" },
|
|
956
|
+
type: { type: "string" },
|
|
957
|
+
label: { type: "string" },
|
|
958
|
+
value: { type: "string" }
|
|
959
|
+
}
|
|
960
|
+
},
|
|
961
|
+
description: "Contact form field entries with metadata"
|
|
962
|
+
},
|
|
963
|
+
consent: {
|
|
964
|
+
type: "array",
|
|
965
|
+
items: {
|
|
966
|
+
type: "object",
|
|
967
|
+
required: ["id", "name", "label", "accepted", "type"],
|
|
968
|
+
properties: {
|
|
969
|
+
id: { type: "string" },
|
|
970
|
+
name: { type: "string" },
|
|
971
|
+
label: { type: "string" },
|
|
972
|
+
accepted: { type: "boolean" },
|
|
973
|
+
type: { type: "string", enum: ["consent", "opt_in"] }
|
|
974
|
+
}
|
|
975
|
+
},
|
|
976
|
+
description: "Consent checkbox entries"
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
},
|
|
980
|
+
output_schema: {
|
|
981
|
+
type: "object",
|
|
982
|
+
required: ["type", "fields"],
|
|
983
|
+
properties: {
|
|
984
|
+
type: { type: "string", const: "contact" },
|
|
985
|
+
fields: {
|
|
986
|
+
type: "array",
|
|
987
|
+
items: {
|
|
988
|
+
type: "object",
|
|
989
|
+
required: ["type", "value"],
|
|
990
|
+
properties: {
|
|
991
|
+
type: { type: "string" },
|
|
992
|
+
value: { type: "string" }
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
},
|
|
999
|
+
file_upload: {
|
|
1000
|
+
label: "File Upload",
|
|
1001
|
+
shorthand: "Upload",
|
|
1002
|
+
icon: "Upload",
|
|
1003
|
+
color: "#FEF9C3",
|
|
1004
|
+
description: "Collect file uploads from respondents",
|
|
1005
|
+
category: "input",
|
|
1006
|
+
sort_order: 6,
|
|
1007
|
+
has_options: false,
|
|
1008
|
+
is_terminal: false,
|
|
1009
|
+
show_nav_bar: true,
|
|
1010
|
+
loading: "lazy",
|
|
1011
|
+
supports_prompt: false,
|
|
1012
|
+
supports_media: false,
|
|
1013
|
+
is_system: false,
|
|
1014
|
+
is_active: false,
|
|
1015
|
+
show_in_results: true,
|
|
1016
|
+
default_config: null,
|
|
1017
|
+
config_schema: {
|
|
1018
|
+
type: "object",
|
|
1019
|
+
properties: {
|
|
1020
|
+
max_files: { max: 20, min: 1, type: "number", label: "Max files", default: 5, description: "Maximum number of files respondents can upload" },
|
|
1021
|
+
max_file_size_mb: { max: 500, min: 1, type: "number", label: "Max file size (MB)", default: 50, description: "Maximum size per file (1-500 MB)" },
|
|
1022
|
+
allowed_media_types: {
|
|
1023
|
+
type: "array",
|
|
1024
|
+
items: { enum: ["images", "videos", "documents", "all"], type: "string" },
|
|
1025
|
+
label: "Allowed media types",
|
|
1026
|
+
default: ["images", "documents"],
|
|
1027
|
+
enumLabels: {
|
|
1028
|
+
all: "All file types",
|
|
1029
|
+
images: "Images (JPEG, PNG, GIF, WebP, HEIC)",
|
|
1030
|
+
videos: "Videos (MP4, MOV, WebM, AVI)",
|
|
1031
|
+
documents: "Documents (PDF, DOC, DOCX, XLS, XLSX, TXT, CSV)"
|
|
1032
|
+
},
|
|
1033
|
+
description: "Select which types of files respondents can upload"
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
},
|
|
1037
|
+
response_schema: {
|
|
1038
|
+
type: "object",
|
|
1039
|
+
required: ["files"],
|
|
1040
|
+
properties: {
|
|
1041
|
+
files: {
|
|
1042
|
+
type: "array",
|
|
1043
|
+
items: {
|
|
1044
|
+
type: "object",
|
|
1045
|
+
required: ["id", "name", "storage_path", "url", "mime_type", "size", "uploaded_at"],
|
|
1046
|
+
properties: {
|
|
1047
|
+
id: { type: "string", format: "uuid", description: "Unique file identifier" },
|
|
1048
|
+
url: { type: "string", format: "uri", description: "Signed Supabase Storage URL for download" },
|
|
1049
|
+
name: { type: "string", description: "Original filename" },
|
|
1050
|
+
size: { type: "integer", minimum: 1, description: "File size in bytes" },
|
|
1051
|
+
mime_type: { type: "string", description: "File MIME type" },
|
|
1052
|
+
uploaded_at: { type: "string", format: "date-time", description: "ISO timestamp of upload completion" },
|
|
1053
|
+
storage_path: { type: "string", description: "Full storage path: workspace_id/form_id/node_id/uuid.ext" }
|
|
1054
|
+
}
|
|
1055
|
+
},
|
|
1056
|
+
minItems: 1,
|
|
1057
|
+
description: "Array of uploaded file metadata"
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
},
|
|
1061
|
+
output_schema: null
|
|
1062
|
+
},
|
|
1063
|
+
payment: {
|
|
1064
|
+
label: "Payment",
|
|
1065
|
+
shorthand: "Payment",
|
|
1066
|
+
icon: "DollarSign",
|
|
1067
|
+
color: "#E9D5FF",
|
|
1068
|
+
description: null,
|
|
1069
|
+
category: "action",
|
|
1070
|
+
sort_order: 7,
|
|
1071
|
+
has_options: false,
|
|
1072
|
+
is_terminal: false,
|
|
1073
|
+
show_nav_bar: true,
|
|
1074
|
+
loading: "lazy",
|
|
1075
|
+
supports_prompt: false,
|
|
1076
|
+
supports_media: false,
|
|
1077
|
+
is_system: false,
|
|
1078
|
+
is_active: false,
|
|
1079
|
+
show_in_results: true,
|
|
1080
|
+
default_config: { amount: null, currency: "usd", provider: "stripe" },
|
|
1081
|
+
config_schema: {
|
|
1082
|
+
type: "object",
|
|
1083
|
+
required: ["amount", "currency", "provider"],
|
|
1084
|
+
properties: {
|
|
1085
|
+
amount: { type: "number", label: "Amount (in cents)", minimum: 50, required: true, description: "Payment amount in cents (e.g., 5000 = $50.00)" },
|
|
1086
|
+
currency: { enum: ["usd", "eur", "gbp", "cad", "aud"], type: "string", label: "Currency", default: "usd", required: true, description: "Three-letter ISO currency code" },
|
|
1087
|
+
provider: { enum: ["stripe", "paddle"], type: "string", label: "Payment Provider", default: "stripe", required: true, description: "Payment provider to use" },
|
|
1088
|
+
workspace_integration_id: { type: "string", label: "Workspace Integration ID", description: "UUID of the workspace_integrations record for the connected payment account" }
|
|
1089
|
+
},
|
|
1090
|
+
description: "Payment configuration with provider-agnostic flat structure"
|
|
1091
|
+
},
|
|
1092
|
+
response_schema: {
|
|
1093
|
+
type: "object",
|
|
1094
|
+
oneOf: [
|
|
1095
|
+
{
|
|
1096
|
+
required: ["stripe"],
|
|
1097
|
+
properties: {
|
|
1098
|
+
stripe: {
|
|
1099
|
+
type: "object",
|
|
1100
|
+
required: ["payment_intent_id", "status", "amount", "currency"],
|
|
1101
|
+
properties: {
|
|
1102
|
+
name: { type: "string", description: "Customer name from Stripe billing details" },
|
|
1103
|
+
email: { type: "string", format: "email", description: "Customer email from Stripe billing details" },
|
|
1104
|
+
amount: { type: "number", description: "Payment amount in cents" },
|
|
1105
|
+
status: { enum: ["pending", "succeeded", "failed"], type: "string", description: "Payment status" },
|
|
1106
|
+
currency: { type: "string", description: "Three-letter ISO currency code (e.g., usd, eur)" },
|
|
1107
|
+
payment_intent_id: { type: "string", description: "Stripe payment intent ID" }
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
required: ["square"],
|
|
1114
|
+
properties: {
|
|
1115
|
+
square: {
|
|
1116
|
+
type: "object",
|
|
1117
|
+
properties: {
|
|
1118
|
+
amount: { type: "number" },
|
|
1119
|
+
status: { type: "string" },
|
|
1120
|
+
order_id: { type: "string" },
|
|
1121
|
+
payment_id: { type: "string" }
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
},
|
|
1126
|
+
{
|
|
1127
|
+
required: ["paddle"],
|
|
1128
|
+
properties: {
|
|
1129
|
+
paddle: {
|
|
1130
|
+
type: "object",
|
|
1131
|
+
properties: {
|
|
1132
|
+
amount: { type: "number" },
|
|
1133
|
+
status: { type: "string" },
|
|
1134
|
+
order_id: { type: "string" },
|
|
1135
|
+
checkout_id: { type: "string" }
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
],
|
|
1141
|
+
description: "Payment response with provider-specific data"
|
|
1142
|
+
},
|
|
1143
|
+
output_schema: null
|
|
1144
|
+
},
|
|
1145
|
+
binary: {
|
|
1146
|
+
label: "Binary",
|
|
1147
|
+
shorthand: "A/B",
|
|
1148
|
+
icon: "CircleCheck",
|
|
1149
|
+
color: "#D1FAE5",
|
|
1150
|
+
description: "Two-option choice - yes/no, true/false, or this vs that",
|
|
1151
|
+
category: "input",
|
|
1152
|
+
sort_order: 1.5,
|
|
1153
|
+
has_options: true,
|
|
1154
|
+
min_options: 2,
|
|
1155
|
+
max_options: 2,
|
|
1156
|
+
max_option_length: 12,
|
|
1157
|
+
is_terminal: false,
|
|
1158
|
+
show_nav_bar: true,
|
|
1159
|
+
loading: "eager",
|
|
1160
|
+
supports_prompt: true,
|
|
1161
|
+
supports_media: true,
|
|
1162
|
+
is_system: false,
|
|
1163
|
+
is_active: false,
|
|
1164
|
+
show_in_results: true,
|
|
1165
|
+
default_config: {
|
|
1166
|
+
choice: { enable_branching: true },
|
|
1167
|
+
options: [
|
|
1168
|
+
{ content: "Yes" },
|
|
1169
|
+
{ content: "No" }
|
|
1170
|
+
]
|
|
1171
|
+
},
|
|
1172
|
+
config_schema: {
|
|
1173
|
+
type: "object",
|
|
1174
|
+
properties: {
|
|
1175
|
+
choice: {
|
|
1176
|
+
type: "object",
|
|
1177
|
+
properties: {
|
|
1178
|
+
enable_branching: {
|
|
1179
|
+
type: "boolean",
|
|
1180
|
+
label: "Enable branching logic",
|
|
1181
|
+
default: true,
|
|
1182
|
+
description: "Allow each option to have its own logic path."
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
},
|
|
1186
|
+
content_media_type: {
|
|
1187
|
+
enum: ["upload", "recorded"],
|
|
1188
|
+
type: "string",
|
|
1189
|
+
label: "Content media type",
|
|
1190
|
+
description: "How the node media was provided"
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
},
|
|
1194
|
+
response_schema: {
|
|
1195
|
+
type: "string",
|
|
1196
|
+
description: "Selected option ID"
|
|
1197
|
+
},
|
|
1198
|
+
output_schema: {
|
|
1199
|
+
type: "object",
|
|
1200
|
+
required: ["type", "label", "option_id"],
|
|
1201
|
+
properties: {
|
|
1202
|
+
type: { type: "string", const: "binary" },
|
|
1203
|
+
label: { type: "string", description: "Human-readable option label" },
|
|
1204
|
+
option_id: { type: "string", format: "uuid", description: "Selected option UUID" }
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
},
|
|
1208
|
+
button: {
|
|
1209
|
+
label: "Button",
|
|
1210
|
+
shorthand: "Button",
|
|
1211
|
+
icon: "RectangleHorizontal",
|
|
1212
|
+
color: "#DBEAFE",
|
|
1213
|
+
description: "Simple button for acknowledgment or navigation",
|
|
1214
|
+
category: "input",
|
|
1215
|
+
sort_order: 3,
|
|
1216
|
+
has_options: true,
|
|
1217
|
+
min_options: 1,
|
|
1218
|
+
max_options: 1,
|
|
1219
|
+
max_option_length: 28,
|
|
1220
|
+
is_terminal: false,
|
|
1221
|
+
show_nav_bar: true,
|
|
1222
|
+
loading: "eager",
|
|
1223
|
+
supports_prompt: true,
|
|
1224
|
+
supports_media: true,
|
|
1225
|
+
is_system: false,
|
|
1226
|
+
is_active: true,
|
|
1227
|
+
show_in_results: false,
|
|
1228
|
+
default_config: { options: [{ content: "Continue" }] },
|
|
1229
|
+
config_schema: {
|
|
1230
|
+
type: "object",
|
|
1231
|
+
properties: {
|
|
1232
|
+
button_text: { type: "string", label: "Button text", default: "Continue" },
|
|
1233
|
+
button_style: { enum: ["primary", "secondary", "outline"], type: "string", label: "Button style", default: "primary" }
|
|
1234
|
+
}
|
|
1235
|
+
},
|
|
1236
|
+
response_schema: {
|
|
1237
|
+
type: "string",
|
|
1238
|
+
description: "Selected option ID"
|
|
1239
|
+
},
|
|
1240
|
+
output_schema: {
|
|
1241
|
+
type: "object",
|
|
1242
|
+
required: ["type", "label", "option_id"],
|
|
1243
|
+
properties: {
|
|
1244
|
+
type: { type: "string", const: "button" },
|
|
1245
|
+
label: { type: "string", description: "Human-readable option label" },
|
|
1246
|
+
option_id: { type: "string", format: "uuid", description: "Selected option UUID" }
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
},
|
|
1250
|
+
redirect: {
|
|
1251
|
+
label: "Redirect",
|
|
1252
|
+
shorthand: "Redirect",
|
|
1253
|
+
icon: "ExternalLink",
|
|
1254
|
+
color: "#FEE2E2",
|
|
1255
|
+
description: "Redirect users to an external URL",
|
|
1256
|
+
category: "end",
|
|
1257
|
+
sort_order: 101,
|
|
1258
|
+
has_options: false,
|
|
1259
|
+
is_terminal: true,
|
|
1260
|
+
show_nav_bar: false,
|
|
1261
|
+
loading: "lazy",
|
|
1262
|
+
supports_prompt: false,
|
|
1263
|
+
supports_media: false,
|
|
1264
|
+
is_system: false,
|
|
1265
|
+
is_active: true,
|
|
1266
|
+
show_in_results: false,
|
|
1267
|
+
default_config: { url: "", auto_redirect: true },
|
|
1268
|
+
config_schema: {
|
|
1269
|
+
type: "object",
|
|
1270
|
+
properties: {
|
|
1271
|
+
url: { type: "string", label: "Redirect URL", placeholder: "https://example.com" },
|
|
1272
|
+
auto_redirect: { type: "boolean", label: "Auto-redirect", default: true, description: "Automatically redirect to the URL instead of showing a button" }
|
|
1273
|
+
}
|
|
1274
|
+
},
|
|
1275
|
+
response_schema: {
|
|
1276
|
+
type: "string",
|
|
1277
|
+
description: "URL the user was redirected to"
|
|
1278
|
+
},
|
|
1279
|
+
output_schema: null
|
|
1280
|
+
},
|
|
1281
|
+
link_list: {
|
|
1282
|
+
label: "Link List",
|
|
1283
|
+
shorthand: "Links",
|
|
1284
|
+
icon: "ExternalLink",
|
|
1285
|
+
color: "#FEE2E2",
|
|
1286
|
+
description: "Display a list of links for users to choose from",
|
|
1287
|
+
category: "end",
|
|
1288
|
+
sort_order: 102,
|
|
1289
|
+
has_options: false,
|
|
1290
|
+
is_terminal: true,
|
|
1291
|
+
show_nav_bar: false,
|
|
1292
|
+
loading: "lazy",
|
|
1293
|
+
supports_prompt: false,
|
|
1294
|
+
supports_media: false,
|
|
1295
|
+
is_system: false,
|
|
1296
|
+
is_active: false,
|
|
1297
|
+
show_in_results: false,
|
|
1298
|
+
default_config: { links: [{ id: "default", url: "", title: "", description: "", order: 0 }], auto_redirect: false },
|
|
1299
|
+
config_schema: {
|
|
1300
|
+
type: "object",
|
|
1301
|
+
properties: {
|
|
1302
|
+
links: {
|
|
1303
|
+
type: "array",
|
|
1304
|
+
items: {
|
|
1305
|
+
type: "object",
|
|
1306
|
+
required: ["id", "url"],
|
|
1307
|
+
properties: {
|
|
1308
|
+
id: { type: "string" },
|
|
1309
|
+
url: { type: "string", label: "URL", placeholder: "https://example.com" },
|
|
1310
|
+
title: { type: "string", label: "Heading" },
|
|
1311
|
+
description: { type: "string", label: "Description" },
|
|
1312
|
+
order: { type: "number", label: "Sort order" }
|
|
1313
|
+
}
|
|
1314
|
+
},
|
|
1315
|
+
label: "Links",
|
|
1316
|
+
minItems: 1
|
|
1317
|
+
},
|
|
1318
|
+
auto_redirect: { type: "boolean", label: "Auto-redirect", default: false, description: "Automatically redirect to the URL instead of showing a button" }
|
|
1319
|
+
}
|
|
1320
|
+
},
|
|
1321
|
+
response_schema: {
|
|
1322
|
+
type: "string",
|
|
1323
|
+
description: "URL of the link that was clicked"
|
|
1324
|
+
},
|
|
1325
|
+
output_schema: null
|
|
1326
|
+
},
|
|
1327
|
+
file_download: {
|
|
1328
|
+
label: "File Download",
|
|
1329
|
+
shorthand: "Download",
|
|
1330
|
+
icon: "Download",
|
|
1331
|
+
color: "#E9D5FF",
|
|
1332
|
+
description: "Provide a file for respondents to download",
|
|
1333
|
+
category: "action",
|
|
1334
|
+
sort_order: 103,
|
|
1335
|
+
has_options: false,
|
|
1336
|
+
is_terminal: false,
|
|
1337
|
+
show_nav_bar: true,
|
|
1338
|
+
loading: "lazy",
|
|
1339
|
+
supports_prompt: false,
|
|
1340
|
+
supports_media: false,
|
|
1341
|
+
is_system: false,
|
|
1342
|
+
is_active: false,
|
|
1343
|
+
show_in_results: true,
|
|
1344
|
+
default_config: null,
|
|
1345
|
+
config_schema: {
|
|
1346
|
+
type: "object",
|
|
1347
|
+
properties: {
|
|
1348
|
+
files: {
|
|
1349
|
+
type: "array",
|
|
1350
|
+
items: {
|
|
1351
|
+
type: "object",
|
|
1352
|
+
properties: {
|
|
1353
|
+
file_name: { type: "string", label: "Display file name", required: true },
|
|
1354
|
+
file_path: { type: "string", label: "File path in storage", required: true },
|
|
1355
|
+
file_size: { type: "number", label: "File size in bytes" },
|
|
1356
|
+
mime_type: { type: "string", label: "MIME type" }
|
|
1357
|
+
}
|
|
1358
|
+
},
|
|
1359
|
+
label: "Downloadable files"
|
|
1360
|
+
},
|
|
1361
|
+
button_text: { type: "string", label: "Button text", default: "Download Files" },
|
|
1362
|
+
description: { type: "string", label: "Description text" }
|
|
1363
|
+
}
|
|
1364
|
+
},
|
|
1365
|
+
response_schema: {
|
|
1366
|
+
type: "object",
|
|
1367
|
+
required: ["files"],
|
|
1368
|
+
properties: {
|
|
1369
|
+
files: {
|
|
1370
|
+
type: "array",
|
|
1371
|
+
items: {
|
|
1372
|
+
type: "object",
|
|
1373
|
+
required: ["file_path", "file_name", "downloaded_at"],
|
|
1374
|
+
properties: {
|
|
1375
|
+
file_name: { type: "string", description: "Display name of the file" },
|
|
1376
|
+
file_path: { type: "string", description: "Storage path of the downloaded file" },
|
|
1377
|
+
downloaded_at: { type: "string", format: "date-time", description: "Timestamp when download was initiated" }
|
|
1378
|
+
}
|
|
1379
|
+
},
|
|
1380
|
+
description: "List of files downloaded by respondent"
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
},
|
|
1384
|
+
output_schema: null
|
|
1385
|
+
},
|
|
1386
|
+
shopping: {
|
|
1387
|
+
label: "Shopping",
|
|
1388
|
+
shorthand: "Shop",
|
|
1389
|
+
icon: "ShoppingBag",
|
|
1390
|
+
color: "#D1FAE5",
|
|
1391
|
+
description: "Product recommendations with direct checkout",
|
|
1392
|
+
category: "action",
|
|
1393
|
+
sort_order: 8,
|
|
1394
|
+
has_options: false,
|
|
1395
|
+
is_terminal: true,
|
|
1396
|
+
show_nav_bar: true,
|
|
1397
|
+
loading: "lazy",
|
|
1398
|
+
supports_prompt: false,
|
|
1399
|
+
supports_media: false,
|
|
1400
|
+
is_system: false,
|
|
1401
|
+
is_active: false,
|
|
1402
|
+
show_in_results: false,
|
|
1403
|
+
default_config: { provider: "shopify", cta_mode: "checkout", source_mode: "manual" },
|
|
1404
|
+
config_schema: {
|
|
1405
|
+
type: "object",
|
|
1406
|
+
required: ["provider", "cta_mode"],
|
|
1407
|
+
properties: {
|
|
1408
|
+
title: { type: "string", label: "Heading", description: "Heading shown above the product list" },
|
|
1409
|
+
description: { type: "string", label: "Description", description: "Body text shown below the heading" },
|
|
1410
|
+
provider: { enum: ["shopify"], type: "string", label: "Provider", default: "shopify", description: "Ecommerce provider" },
|
|
1411
|
+
workspace_integration_id: { type: "string", label: "Workspace Integration ID", description: "UUID of the workspace_integrations record for the connected store" },
|
|
1412
|
+
cta_mode: { enum: ["checkout", "add_to_cart"], type: "string", label: "CTA Mode", default: "checkout", description: "Whether to go to checkout or add to cart" },
|
|
1413
|
+
source_mode: { enum: ["manual", "collection"], type: "string", label: "Product source", default: "manual", description: "How products are selected: manually picked or from a collection" },
|
|
1414
|
+
collection_id: { type: "string", label: "Collection ID", description: "Shopify collection GID (when source_mode is collection)" },
|
|
1415
|
+
collection_title: { type: "string", label: "Collection title", description: "Display name of the selected collection" },
|
|
1416
|
+
products: {
|
|
1417
|
+
type: "array",
|
|
1418
|
+
label: "Selected Products",
|
|
1419
|
+
description: "Products to show (static mode)",
|
|
1420
|
+
items: {
|
|
1421
|
+
type: "object",
|
|
1422
|
+
properties: {
|
|
1423
|
+
product_id: { type: "string", description: "Shopify product GID" },
|
|
1424
|
+
variant_id: { type: "string", description: "Shopify variant GID" },
|
|
1425
|
+
title: { type: "string" },
|
|
1426
|
+
handle: { type: "string" },
|
|
1427
|
+
image_url: { type: "string" },
|
|
1428
|
+
price: { type: "string" },
|
|
1429
|
+
currency: { type: "string" },
|
|
1430
|
+
recommended: { type: "boolean", default: true, description: "Pre-ticked in viewer" }
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
},
|
|
1434
|
+
product_mappings: {
|
|
1435
|
+
type: "array",
|
|
1436
|
+
label: "Score-based product mappings",
|
|
1437
|
+
description: "Map score ranges to different product sets. First matching range wins.",
|
|
1438
|
+
items: {
|
|
1439
|
+
type: "object",
|
|
1440
|
+
required: ["min", "max"],
|
|
1441
|
+
properties: {
|
|
1442
|
+
min: { type: "integer", label: "Minimum score (inclusive)" },
|
|
1443
|
+
max: { type: "integer", label: "Maximum score (inclusive)" },
|
|
1444
|
+
message: { type: "string", label: "Message" },
|
|
1445
|
+
products: { type: "array", description: "Products for this score range" }
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
},
|
|
1450
|
+
description: "Shopping configuration with provider-agnostic structure"
|
|
1451
|
+
},
|
|
1452
|
+
response_schema: null,
|
|
1453
|
+
output_schema: null
|
|
1454
|
+
},
|
|
1455
|
+
end_screen: {
|
|
1456
|
+
label: "Ending",
|
|
1457
|
+
shorthand: "End",
|
|
1458
|
+
icon: "Flag",
|
|
1459
|
+
color: "#FEE2E2",
|
|
1460
|
+
description: "Final screen shown when form is completed",
|
|
1461
|
+
category: "end",
|
|
1462
|
+
sort_order: 999,
|
|
1463
|
+
has_options: false,
|
|
1464
|
+
is_terminal: true,
|
|
1465
|
+
show_nav_bar: false,
|
|
1466
|
+
loading: "eager",
|
|
1467
|
+
supports_prompt: false,
|
|
1468
|
+
supports_media: false,
|
|
1469
|
+
is_system: false,
|
|
1470
|
+
is_active: true,
|
|
1471
|
+
show_in_results: false,
|
|
1472
|
+
default_config: null,
|
|
1473
|
+
config_schema: {
|
|
1474
|
+
type: "object",
|
|
1475
|
+
properties: {
|
|
1476
|
+
title: { type: "string", label: "Title", default: "Thank you!", description: "Heading shown on completion" },
|
|
1477
|
+
message: { type: "string", label: "Message", default: "Your response has been submitted.", description: "Message shown on completion" },
|
|
1478
|
+
show_score: { type: "boolean", label: "Show score", default: false, description: 'Display score on the end screen (e.g. "You scored 4 out of 5")' },
|
|
1479
|
+
icon: { type: "string", label: "Icon", enum: ["tick", "trophy", "star", "crown", "party", "none"], default: "tick", description: "Icon shown above the title" },
|
|
1480
|
+
show_share_button: { type: "boolean", label: "Show share button", default: false, description: "Show a share button above the CTA" },
|
|
1481
|
+
cta_type: { type: "string", label: "CTA type", enum: ["none", "restart", "external_link"], default: "none", description: "Primary call-to-action button type" },
|
|
1482
|
+
cta_text: { type: "string", label: "CTA button text", default: "Continue", description: "Button label for the CTA" },
|
|
1483
|
+
cta_url: { type: "string", label: "CTA URL", format: "uri", description: "URL to open (only for external_link CTA type)", placeholder: "https://example.com" },
|
|
1484
|
+
score_ranges: {
|
|
1485
|
+
type: "array",
|
|
1486
|
+
label: "Score-based content",
|
|
1487
|
+
description: "Show different content based on cumulative score. First matching range wins.",
|
|
1488
|
+
items: {
|
|
1489
|
+
type: "object",
|
|
1490
|
+
required: ["min", "max", "title"],
|
|
1491
|
+
properties: {
|
|
1492
|
+
min: { type: "integer", label: "Minimum score (inclusive)" },
|
|
1493
|
+
max: { type: "integer", label: "Maximum score (inclusive)" },
|
|
1494
|
+
title: { type: "string", label: "Title" },
|
|
1495
|
+
message: { type: "string", label: "Message" }
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
},
|
|
1499
|
+
scoring_results: {
|
|
1500
|
+
type: "array",
|
|
1501
|
+
label: "Category-based results",
|
|
1502
|
+
description: "Results keyed by scoring category. The winning category (highest non-knocked-out score) determines which result is shown.",
|
|
1503
|
+
items: {
|
|
1504
|
+
type: "object",
|
|
1505
|
+
required: ["category", "title"],
|
|
1506
|
+
properties: {
|
|
1507
|
+
category: { type: "string", label: "Category key (must match keys used in option scores)" },
|
|
1508
|
+
title: { type: "string", label: "Title" },
|
|
1509
|
+
message: { type: "string", label: "Message" },
|
|
1510
|
+
cta_url: { type: "string", label: "CTA URL", format: "uri" },
|
|
1511
|
+
cta_text: { type: "string", label: "CTA button text" }
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
},
|
|
1517
|
+
response_schema: null,
|
|
1518
|
+
output_schema: null
|
|
1519
|
+
}
|
|
1520
|
+
};
|
|
1521
|
+
var NODE_TYPES_LIST = Object.entries(NODE_TYPES).map(([type, def]) => ({ type, ...def })).sort((a, b) => a.sort_order - b.sort_order);
|
|
1522
|
+
var NODE_TYPE_KEYS = Object.keys(NODE_TYPES);
|
|
1523
|
+
var RESPONSE_SCHEMAS = Object.fromEntries(
|
|
1524
|
+
Object.entries(NODE_TYPES).map(([k, v]) => [k, v.response_schema])
|
|
1525
|
+
);
|
|
1526
|
+
var CONFIG_SCHEMAS = Object.fromEntries(
|
|
1527
|
+
Object.entries(NODE_TYPES).map(([k, v]) => [k, v.config_schema])
|
|
1528
|
+
);
|
|
1529
|
+
var OUTPUT_SCHEMAS = Object.fromEntries(
|
|
1530
|
+
Object.entries(NODE_TYPES).map(([k, v]) => [k, v.output_schema])
|
|
1531
|
+
);
|
|
1532
|
+
var NODE_TYPE_METADATA = Object.fromEntries(
|
|
1533
|
+
Object.entries(NODE_TYPES).map(([k, v]) => [k, {
|
|
1534
|
+
supports_prompt: v.supports_prompt,
|
|
1535
|
+
supports_media: v.supports_media,
|
|
1536
|
+
is_terminal: v.is_terminal,
|
|
1537
|
+
show_nav_bar: v.show_nav_bar,
|
|
1538
|
+
category: v.category,
|
|
1539
|
+
loading: v.loading
|
|
1540
|
+
}])
|
|
1541
|
+
);
|
|
1542
|
+
var TERMINAL_TYPES = Object.entries(NODE_TYPES).filter(([, v]) => v.is_terminal).map(([k]) => k);
|
|
1543
|
+
var NON_COUNTABLE_TYPES = Object.entries(NODE_TYPES).filter(([, v]) => v.is_system || v.is_terminal).map(([k]) => k);
|
|
1544
|
+
var NON_COUNTABLE_FILTER = `(${NON_COUNTABLE_TYPES.map((t) => `"${t}"`).join(",")})`;
|
|
1545
|
+
var RESULTS_EXCLUDED_TYPES = Object.entries(NODE_TYPES).filter(([, v]) => !v.show_in_results).map(([k]) => k);
|
|
1546
|
+
|
|
1547
|
+
// ../config/integration-catalog.js
|
|
1548
|
+
var INTEGRATION_CATALOG = {
|
|
1549
|
+
stripe: {
|
|
1550
|
+
name: "Stripe",
|
|
1551
|
+
category: "form_action",
|
|
1552
|
+
description: "Accept payments directly in your forms",
|
|
1553
|
+
logo_url: "https://cdn.brandfetch.io/stripe.com/w/400/h/400",
|
|
1554
|
+
color: "#635BFF",
|
|
1555
|
+
sort_order: 1,
|
|
1556
|
+
tags: ["payment"],
|
|
1557
|
+
external_account_id_field: "account_id",
|
|
1558
|
+
display_name_field: "account_name",
|
|
1559
|
+
is_active: true
|
|
1560
|
+
},
|
|
1561
|
+
paddle: {
|
|
1562
|
+
name: "Paddle",
|
|
1563
|
+
category: "form_action",
|
|
1564
|
+
description: "Accept payments with Paddle",
|
|
1565
|
+
logo_url: "https://cdn.brandfetch.io/paddle.com/w/400/h/400",
|
|
1566
|
+
color: "#6837FC",
|
|
1567
|
+
sort_order: 2,
|
|
1568
|
+
tags: ["payment"],
|
|
1569
|
+
external_account_id_field: null,
|
|
1570
|
+
display_name_field: null,
|
|
1571
|
+
is_active: true
|
|
1572
|
+
},
|
|
1573
|
+
square: {
|
|
1574
|
+
name: "Square",
|
|
1575
|
+
category: "form_action",
|
|
1576
|
+
description: "Accept payments with Square",
|
|
1577
|
+
logo_url: "https://cdn.brandfetch.io/square.com/w/400/h/400",
|
|
1578
|
+
color: "#000000",
|
|
1579
|
+
sort_order: 3,
|
|
1580
|
+
tags: ["payment"],
|
|
1581
|
+
external_account_id_field: null,
|
|
1582
|
+
display_name_field: null,
|
|
1583
|
+
is_active: true
|
|
1584
|
+
},
|
|
1585
|
+
calendly: {
|
|
1586
|
+
name: "Calendly",
|
|
1587
|
+
category: "form_action",
|
|
1588
|
+
description: "Schedule meetings directly in your forms",
|
|
1589
|
+
logo_url: "https://cdn.brandfetch.io/calendly.com/w/400/h/400",
|
|
1590
|
+
color: "#006BFF",
|
|
1591
|
+
sort_order: 4,
|
|
1592
|
+
tags: ["booking"],
|
|
1593
|
+
external_account_id_field: "user_uri",
|
|
1594
|
+
display_name_field: "user_name",
|
|
1595
|
+
is_active: true
|
|
1596
|
+
},
|
|
1597
|
+
calcom: {
|
|
1598
|
+
name: "Cal.com",
|
|
1599
|
+
category: "form_action",
|
|
1600
|
+
description: "Open-source scheduling platform for booking meetings",
|
|
1601
|
+
logo_url: null,
|
|
1602
|
+
color: "#292929",
|
|
1603
|
+
sort_order: 4,
|
|
1604
|
+
tags: ["booking"],
|
|
1605
|
+
external_account_id_field: "id",
|
|
1606
|
+
display_name_field: "name",
|
|
1607
|
+
is_active: true
|
|
1608
|
+
},
|
|
1609
|
+
docusign: {
|
|
1610
|
+
name: "DocuSign",
|
|
1611
|
+
category: "form_action",
|
|
1612
|
+
description: "Collect signatures in your forms",
|
|
1613
|
+
logo_url: "https://cdn.brandfetch.io/docusign.com/w/400/h/400",
|
|
1614
|
+
color: "#FF0037",
|
|
1615
|
+
sort_order: 5,
|
|
1616
|
+
tags: ["document", "e-signature", "contract"],
|
|
1617
|
+
external_account_id_field: null,
|
|
1618
|
+
display_name_field: null,
|
|
1619
|
+
is_active: true
|
|
1620
|
+
},
|
|
1621
|
+
webhook: {
|
|
1622
|
+
name: "Webhook",
|
|
1623
|
+
category: "automation",
|
|
1624
|
+
description: "Send responses to custom webhooks",
|
|
1625
|
+
logo_url: null,
|
|
1626
|
+
color: "#6B7280",
|
|
1627
|
+
sort_order: 100,
|
|
1628
|
+
tags: ["webhook", "automation", "developer"],
|
|
1629
|
+
external_account_id_field: null,
|
|
1630
|
+
display_name_field: null,
|
|
1631
|
+
is_active: true
|
|
1632
|
+
},
|
|
1633
|
+
zapier: {
|
|
1634
|
+
name: "Zapier",
|
|
1635
|
+
category: "automation",
|
|
1636
|
+
description: "Connect to 5,000+ apps and automate workflows",
|
|
1637
|
+
logo_url: "https://cdn.brandfetch.io/zapier.com/w/400/h/400",
|
|
1638
|
+
color: "#FF4A00",
|
|
1639
|
+
sort_order: 101,
|
|
1640
|
+
tags: ["automation", "workflow", "no-code"],
|
|
1641
|
+
external_account_id_field: null,
|
|
1642
|
+
display_name_field: null,
|
|
1643
|
+
is_active: true
|
|
1644
|
+
},
|
|
1645
|
+
make: {
|
|
1646
|
+
name: "Make",
|
|
1647
|
+
category: "automation",
|
|
1648
|
+
description: "Advanced automation and integrations",
|
|
1649
|
+
logo_url: "https://cdn.brandfetch.io/make.com/w/400/h/400",
|
|
1650
|
+
color: "#6B4AFF",
|
|
1651
|
+
sort_order: 102,
|
|
1652
|
+
tags: ["automation", "workflow", "integration"],
|
|
1653
|
+
external_account_id_field: null,
|
|
1654
|
+
display_name_field: null,
|
|
1655
|
+
is_active: true
|
|
1656
|
+
},
|
|
1657
|
+
hubspot: {
|
|
1658
|
+
name: "HubSpot",
|
|
1659
|
+
category: "automation",
|
|
1660
|
+
description: "Sync responses to HubSpot CRM",
|
|
1661
|
+
logo_url: "https://cdn.brandfetch.io/hubspot.com/w/400/h/400",
|
|
1662
|
+
color: "#FF7A59",
|
|
1663
|
+
sort_order: 103,
|
|
1664
|
+
tags: ["automation", "crm", "marketing"],
|
|
1665
|
+
external_account_id_field: "portal_id",
|
|
1666
|
+
display_name_field: "portal_name",
|
|
1667
|
+
is_active: true
|
|
1668
|
+
},
|
|
1669
|
+
salesforce: {
|
|
1670
|
+
name: "Salesforce",
|
|
1671
|
+
category: "automation",
|
|
1672
|
+
description: "Sync responses to Salesforce CRM",
|
|
1673
|
+
logo_url: "https://cdn.brandfetch.io/salesforce.com/w/400/h/400",
|
|
1674
|
+
color: "#00A1E0",
|
|
1675
|
+
sort_order: 104,
|
|
1676
|
+
tags: ["automation", "crm", "sales"],
|
|
1677
|
+
external_account_id_field: null,
|
|
1678
|
+
display_name_field: null,
|
|
1679
|
+
is_active: true
|
|
1680
|
+
},
|
|
1681
|
+
slack: {
|
|
1682
|
+
name: "Slack",
|
|
1683
|
+
category: "automation",
|
|
1684
|
+
description: "Send notifications to Slack channels",
|
|
1685
|
+
logo_url: "https://cdn.brandfetch.io/slack.com/w/400/h/400",
|
|
1686
|
+
color: "#4A154B",
|
|
1687
|
+
sort_order: 105,
|
|
1688
|
+
tags: ["automation", "communication", "notifications"],
|
|
1689
|
+
external_account_id_field: null,
|
|
1690
|
+
display_name_field: null,
|
|
1691
|
+
is_active: true
|
|
1692
|
+
},
|
|
1693
|
+
shopify: {
|
|
1694
|
+
name: "Shopify",
|
|
1695
|
+
category: "ecommerce",
|
|
1696
|
+
description: "Product recommendations from quiz results with direct checkout",
|
|
1697
|
+
logo_url: "https://cdn.brandfetch.io/shopify.com/w/400/h/400",
|
|
1698
|
+
color: "#95BF47",
|
|
1699
|
+
sort_order: 200,
|
|
1700
|
+
tags: ["ecommerce", "product", "checkout", "quiz"],
|
|
1701
|
+
external_account_id_field: "shop_domain",
|
|
1702
|
+
display_name_field: "shop_name",
|
|
1703
|
+
is_active: true
|
|
1704
|
+
}
|
|
1705
|
+
};
|
|
1706
|
+
var INTEGRATION_CATALOG_LIST = Object.entries(INTEGRATION_CATALOG).map(([slug, def]) => ({ slug, ...def })).sort((a, b) => a.sort_order - b.sort_order);
|
|
1707
|
+
var INTEGRATION_SLUGS = Object.keys(INTEGRATION_CATALOG);
|
|
1708
|
+
|
|
1709
|
+
// ../config/index.js
|
|
1710
|
+
var isServer = typeof window === "undefined";
|
|
1711
|
+
var isBrowser = typeof window !== "undefined";
|
|
1712
|
+
var isLocalhost = isBrowser && (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1" || window.location.hostname.includes("local"));
|
|
1713
|
+
var isDevelopment = isServer ? process.env.NODE_ENV !== "production" : isLocalhost;
|
|
1714
|
+
var ENV = {
|
|
1715
|
+
isDevelopment,
|
|
1716
|
+
isProduction: !isDevelopment,
|
|
1717
|
+
isLocalhost: isDevelopment
|
|
1718
|
+
// alias for clarity
|
|
1719
|
+
};
|
|
1720
|
+
var COOKIE_DOMAIN = ENV.isDevelopment ? void 0 : ".clipform.io";
|
|
1721
|
+
var isTunnelBrowser = isBrowser && window.location.hostname.endsWith(".smith-forge.com");
|
|
1722
|
+
function getUrls() {
|
|
1723
|
+
if (isTunnelBrowser) {
|
|
1724
|
+
return {
|
|
1725
|
+
marketing: "https://marketing-dev.smith-forge.com",
|
|
1726
|
+
dashboard: "https://dashboard-dev.smith-forge.com",
|
|
1727
|
+
viewer: "https://viewer-dev.smith-forge.com",
|
|
1728
|
+
api: "https://api-dev.smith-forge.com",
|
|
1729
|
+
mcp: "https://api-dev.smith-forge.com/mcp",
|
|
1730
|
+
docs: "https://docs.clipform.io"
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1733
|
+
if (ENV.isDevelopment) {
|
|
1734
|
+
return {
|
|
1735
|
+
marketing: "http://localhost:3002",
|
|
1736
|
+
dashboard: "http://localhost:3000",
|
|
1737
|
+
viewer: "http://localhost:3001",
|
|
1738
|
+
api: "http://localhost:3003",
|
|
1739
|
+
// No separate MCP host in dev - tools live on the api subpath.
|
|
1740
|
+
mcp: "http://localhost:3003/mcp",
|
|
1741
|
+
docs: "http://localhost:3004"
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
return {
|
|
1745
|
+
marketing: "https://www.clipform.io",
|
|
1746
|
+
dashboard: "https://app.clipform.io",
|
|
1747
|
+
viewer: "https://clipform.io",
|
|
1748
|
+
api: "https://api.clipform.io",
|
|
1749
|
+
// Dedicated subdomain for the remote MCP server. Same Render service
|
|
1750
|
+
// as `api`, just routed by Host header. Token audience is bound here.
|
|
1751
|
+
mcp: "https://mcp.clipform.io",
|
|
1752
|
+
docs: "https://docs.clipform.io"
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
var BUSINESS = {
|
|
1756
|
+
name: "Clipform",
|
|
1757
|
+
tagline: "Video-Driven Form Builder",
|
|
1758
|
+
description: "Create engaging forms that combine video content with interactive questions. Capture authentic responses with text, audio, or video recordings.",
|
|
1759
|
+
shortDescription: "Interactive video forms that capture authentic responses. Build engaging forms in minutes.",
|
|
1760
|
+
domain: "clipform.io",
|
|
1761
|
+
email: {
|
|
1762
|
+
support: "support@clipform.io",
|
|
1763
|
+
sales: "sales@clipform.io",
|
|
1764
|
+
hello: "hello@clipform.io"
|
|
1765
|
+
},
|
|
1766
|
+
phone: "+1 (555) 123-4567",
|
|
1767
|
+
urls: getUrls()
|
|
1768
|
+
};
|
|
1769
|
+
var CONTACT_FIELDS = [
|
|
1770
|
+
{ id: "first_name", label: "First Name", type: "text", placeholder: "Enter first name", order: 1 },
|
|
1771
|
+
{ id: "last_name", label: "Last Name", type: "text", placeholder: "Enter last name", order: 2 },
|
|
1772
|
+
{ id: "email", label: "Email Address", type: "email", placeholder: "you@example.com", order: 3 },
|
|
1773
|
+
{ id: "phone", label: "Phone Number", type: "tel", placeholder: "(555) 123-4567", order: 4 }
|
|
1774
|
+
];
|
|
1775
|
+
var CONTACT_FIELDS_MAP = Object.fromEntries(
|
|
1776
|
+
CONTACT_FIELDS.map((f) => [f.id, f])
|
|
1777
|
+
);
|
|
1778
|
+
var KEN_BURNS_EFFECTS = [
|
|
1779
|
+
"pan-left",
|
|
1780
|
+
"pan-right",
|
|
1781
|
+
"pan-up",
|
|
1782
|
+
"pan-down",
|
|
1783
|
+
"zoom-in-pan-left",
|
|
1784
|
+
"zoom-in-pan-right",
|
|
1785
|
+
"zoom-in",
|
|
1786
|
+
"zoom-out",
|
|
1787
|
+
"static"
|
|
1788
|
+
];
|
|
1789
|
+
var KEN_BURNS_PRESETS = [
|
|
1790
|
+
"cinematic",
|
|
1791
|
+
"dramatic",
|
|
1792
|
+
"calm",
|
|
1793
|
+
"documentary",
|
|
1794
|
+
"dreamy",
|
|
1795
|
+
"moody"
|
|
1796
|
+
];
|
|
1797
|
+
var KEN_BURNS_FIT_MODES = ["cover", "blur-pad", "auto"];
|
|
1798
|
+
var SLIDESHOW_TRANSITIONS = [
|
|
1799
|
+
"fade",
|
|
1800
|
+
"fadeblack",
|
|
1801
|
+
"fadewhite",
|
|
1802
|
+
"slideleft",
|
|
1803
|
+
"slideright",
|
|
1804
|
+
"circlecrop",
|
|
1805
|
+
"circleopen",
|
|
1806
|
+
"circleclose",
|
|
1807
|
+
"dissolve",
|
|
1808
|
+
"pixelize",
|
|
1809
|
+
"radial",
|
|
1810
|
+
"smoothleft",
|
|
1811
|
+
"smoothright",
|
|
1812
|
+
"wipeleft",
|
|
1813
|
+
"wiperight",
|
|
1814
|
+
"diagtl",
|
|
1815
|
+
"diagbr",
|
|
1816
|
+
"hblur"
|
|
1817
|
+
];
|
|
1818
|
+
|
|
1819
|
+
// src/lib/telemetry.ts
|
|
1820
|
+
var telemetryEnabled = process.env.DO_NOT_TRACK !== "1" && process.env.CLIPFORM_TELEMETRY !== "off";
|
|
1821
|
+
var mcpVersion = "unknown";
|
|
1822
|
+
function setMcpVersion(version) {
|
|
1823
|
+
mcpVersion = version;
|
|
1824
|
+
}
|
|
1825
|
+
function getApiBaseUrl() {
|
|
1826
|
+
return process.env.API_URL || null;
|
|
1827
|
+
}
|
|
1828
|
+
function reportError(report) {
|
|
1829
|
+
if (!telemetryEnabled) return;
|
|
1830
|
+
const base = getApiBaseUrl();
|
|
1831
|
+
if (!base) return;
|
|
1832
|
+
const payload = {
|
|
1833
|
+
...report,
|
|
1834
|
+
error_message: report.error_message.slice(0, 500),
|
|
1835
|
+
mcp_version: mcpVersion,
|
|
1836
|
+
runtime: detectRuntime(),
|
|
1837
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1838
|
+
};
|
|
1839
|
+
fetch(`${base}/v1/telemetry/errors`, {
|
|
1840
|
+
method: "POST",
|
|
1841
|
+
headers: { "Content-Type": "application/json" },
|
|
1842
|
+
body: JSON.stringify(payload),
|
|
1843
|
+
signal: AbortSignal.timeout(2e3)
|
|
1844
|
+
}).catch(() => {
|
|
1845
|
+
});
|
|
1846
|
+
}
|
|
1847
|
+
function isServerFault(status) {
|
|
1848
|
+
return status >= 500;
|
|
1849
|
+
}
|
|
1850
|
+
function detectRuntime() {
|
|
1851
|
+
if (process.env.CLAUDE_CODE) return "claude-code";
|
|
1852
|
+
if (process.env.CURSOR_SESSION_ID) return "cursor";
|
|
1853
|
+
return "stdio";
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
// src/lib/api-client.ts
|
|
1857
|
+
function getApiBaseUrl2() {
|
|
1858
|
+
const url = process.env.API_URL;
|
|
1859
|
+
if (!url) {
|
|
1860
|
+
throw new Error(
|
|
1861
|
+
"API_URL must be set (e.g. http://localhost:3003 or https://api.clipform.io)"
|
|
1862
|
+
);
|
|
1863
|
+
}
|
|
1864
|
+
return url;
|
|
1865
|
+
}
|
|
1866
|
+
function getAuthHeaders() {
|
|
1867
|
+
const authCtx = getMcpAuth();
|
|
1868
|
+
const apiKey = authCtx?.api_key || process.env.CLIPFORM_API_KEY;
|
|
1869
|
+
if (!apiKey) {
|
|
1870
|
+
throw new Error("CLIPFORM_API_KEY must be set.");
|
|
1871
|
+
}
|
|
1872
|
+
return { "Authorization": `Bearer ${apiKey}` };
|
|
1873
|
+
}
|
|
1874
|
+
async function callApi(path, options = {}) {
|
|
1875
|
+
const { body, params, timeoutMs = 3e4 } = options;
|
|
1876
|
+
const method = options.method || (body ? "POST" : "GET");
|
|
1877
|
+
const base = getApiBaseUrl2();
|
|
1878
|
+
const prefix = path.startsWith("/internal/") ? "" : "/v1";
|
|
1879
|
+
let url = `${base}${prefix}${path}`;
|
|
1880
|
+
if (params) {
|
|
1881
|
+
const searchParams = new URLSearchParams(params);
|
|
1882
|
+
url += `?${searchParams.toString()}`;
|
|
1883
|
+
}
|
|
1884
|
+
const headers = {
|
|
1885
|
+
"Content-Type": "application/json",
|
|
1886
|
+
...getAuthHeaders()
|
|
1887
|
+
};
|
|
1888
|
+
const fetchOptions = {
|
|
1889
|
+
method,
|
|
1890
|
+
headers,
|
|
1891
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
1892
|
+
};
|
|
1893
|
+
if (body && method !== "GET") {
|
|
1894
|
+
fetchOptions.body = JSON.stringify(body);
|
|
1895
|
+
}
|
|
1896
|
+
let response;
|
|
1897
|
+
try {
|
|
1898
|
+
response = await fetch(url, fetchOptions);
|
|
1899
|
+
} catch (err) {
|
|
1900
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1901
|
+
reportError({
|
|
1902
|
+
error_type: "connection_error",
|
|
1903
|
+
error_message: message,
|
|
1904
|
+
tool_name: getMcpAuth()?.tool_name,
|
|
1905
|
+
api_path: `${prefix}${path}`
|
|
1906
|
+
});
|
|
1907
|
+
return {
|
|
1908
|
+
ok: false,
|
|
1909
|
+
status: 0,
|
|
1910
|
+
error: `Failed to connect to API at ${url}.
|
|
1911
|
+
|
|
1912
|
+
Error: ${message}`
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
if (response.status === 204) {
|
|
1916
|
+
return { ok: true, data: {} };
|
|
1917
|
+
}
|
|
1918
|
+
const data = await response.json();
|
|
1919
|
+
if (!response.ok) {
|
|
1920
|
+
const errorMsg = data.error || `API error (${response.status})`;
|
|
1921
|
+
if (isServerFault(response.status)) {
|
|
1922
|
+
reportError({
|
|
1923
|
+
error_type: `http_${response.status}`,
|
|
1924
|
+
error_message: errorMsg,
|
|
1925
|
+
tool_name: getMcpAuth()?.tool_name,
|
|
1926
|
+
status_code: response.status,
|
|
1927
|
+
api_path: `${prefix}${path}`
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
return {
|
|
1931
|
+
ok: false,
|
|
1932
|
+
status: response.status,
|
|
1933
|
+
error: errorMsg
|
|
1934
|
+
};
|
|
1935
|
+
}
|
|
1936
|
+
return { ok: true, data };
|
|
1937
|
+
}
|
|
1938
|
+
function errorResult(message) {
|
|
1939
|
+
return {
|
|
1940
|
+
content: [{ type: "text", text: message }],
|
|
1941
|
+
isError: true
|
|
1942
|
+
};
|
|
1943
|
+
}
|
|
1944
|
+
function textResult(text) {
|
|
1945
|
+
return {
|
|
1946
|
+
content: [{ type: "text", text }]
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
// src/lib/session-context.ts
|
|
1951
|
+
async function getSessionContextWithAuth() {
|
|
1952
|
+
let result;
|
|
1953
|
+
try {
|
|
1954
|
+
result = await callApi("/me", { method: "GET" });
|
|
1955
|
+
} catch {
|
|
1956
|
+
return { text: "", authMode: "anonymous" };
|
|
1957
|
+
}
|
|
1958
|
+
if (!result.ok) return { text: "", authMode: "anonymous" };
|
|
1959
|
+
const me = result.data;
|
|
1960
|
+
const authMode = me.auth_mode === "oauth" ? "oauth" : "anonymous";
|
|
1961
|
+
const plan = me.plan;
|
|
1962
|
+
const lines = [];
|
|
1963
|
+
lines.push("## Your Session");
|
|
1964
|
+
if (authMode === "oauth") {
|
|
1965
|
+
lines.push(`Auth: OAuth (connected)`);
|
|
1966
|
+
lines.push(`Workspace: ${me.workspace?.name ?? "Unknown"} (${me.workspace?.id ?? "?"})`);
|
|
1967
|
+
lines.push(`User: ${me.user_id ?? "?"}`);
|
|
1968
|
+
lines.push(`Company: ${me.company_id ?? "none"}`);
|
|
1969
|
+
} else {
|
|
1970
|
+
lines.push("Auth: anonymous (not connected to a Clipform account)");
|
|
1971
|
+
if (me.workspace) {
|
|
1972
|
+
lines.push(`Workspace: ${me.workspace.name} (${me.workspace.id})`);
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
lines.push(`Plan: ${plan.name} (tier ${plan.tier})`);
|
|
1976
|
+
if (plan.node_limit !== null) {
|
|
1977
|
+
lines.push(`Question limit: ${plan.node_limit} per form`);
|
|
1978
|
+
} else {
|
|
1979
|
+
lines.push("Questions: unlimited");
|
|
1980
|
+
}
|
|
1981
|
+
if (plan.form_limit !== null) {
|
|
1982
|
+
lines.push(`Form limit: ${plan.form_limit} forms`);
|
|
1983
|
+
} else {
|
|
1984
|
+
lines.push("Forms: unlimited");
|
|
1985
|
+
}
|
|
1986
|
+
if (plan.custom_theme === false) {
|
|
1987
|
+
lines.push("Custom themes: not available on this plan");
|
|
1988
|
+
}
|
|
1989
|
+
if (authMode !== "oauth") {
|
|
1990
|
+
lines.push(`
|
|
1991
|
+
To unlock your full plan: sign in to your Clipform account.`);
|
|
1992
|
+
}
|
|
1993
|
+
return { text: lines.join("\n"), authMode };
|
|
1994
|
+
}
|
|
1995
|
+
async function getSessionContext() {
|
|
1996
|
+
const { text } = await getSessionContextWithAuth();
|
|
1997
|
+
return text;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
export {
|
|
2001
|
+
FEATURES,
|
|
2002
|
+
NODE_TYPES,
|
|
2003
|
+
NON_COUNTABLE_TYPES,
|
|
2004
|
+
FORM_TYPE_KEYS,
|
|
2005
|
+
WORKFLOW_TYPES,
|
|
2006
|
+
FORM_TYPE_ALIASES,
|
|
2007
|
+
ALL_VARIANTS,
|
|
2008
|
+
resolveFormType,
|
|
2009
|
+
getDiscoveryParams,
|
|
2010
|
+
BUSINESS,
|
|
2011
|
+
CONTACT_FIELDS,
|
|
2012
|
+
KEN_BURNS_EFFECTS,
|
|
2013
|
+
KEN_BURNS_PRESETS,
|
|
2014
|
+
KEN_BURNS_FIT_MODES,
|
|
2015
|
+
SLIDESHOW_TRANSITIONS,
|
|
2016
|
+
setMcpVersion,
|
|
2017
|
+
callApi,
|
|
2018
|
+
errorResult,
|
|
2019
|
+
textResult,
|
|
2020
|
+
getSessionContextWithAuth,
|
|
2021
|
+
getSessionContext
|
|
2022
|
+
};
|
|
2023
|
+
//# sourceMappingURL=chunk-ZDSVE6D3.js.map
|