@clipform/mcp-server 1.5.0 → 1.7.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.
- package/README.md +21 -9
- package/dist/__tests__/config-sync.test.js +8 -27
- package/dist/__tests__/config-sync.test.js.map +1 -1
- package/dist/lib/api-client.d.ts +1 -1
- package/dist/lib/api-client.js +21 -5
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/auth-context.d.ts +17 -0
- package/dist/lib/auth-context.js +9 -0
- package/dist/lib/auth-context.js.map +1 -0
- package/dist/lib/config.d.ts +9 -11
- package/dist/lib/config.js +3 -336
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/schemas.d.ts +3 -3
- package/dist/lib/schemas.js +24 -6
- package/dist/lib/schemas.js.map +1 -1
- package/dist/lib/session-context.d.ts +1 -0
- package/dist/lib/session-context.js +32 -0
- package/dist/lib/session-context.js.map +1 -0
- package/dist/prompts.js +241 -125
- package/dist/prompts.js.map +1 -1
- package/dist/resources.d.ts +2 -0
- package/dist/resources.js +336 -0
- package/dist/resources.js.map +1 -0
- package/dist/server.js +7 -3
- package/dist/server.js.map +1 -1
- package/dist/tools/add-question.js +2 -2
- package/dist/tools/add-question.js.map +1 -1
- package/dist/tools/attach-question-audio.js +2 -2
- package/dist/tools/attach-question-audio.js.map +1 -1
- package/dist/tools/create-form.js +65 -12
- package/dist/tools/create-form.js.map +1 -1
- package/dist/tools/delete-form.js +2 -2
- package/dist/tools/delete-form.js.map +1 -1
- package/dist/tools/delete-question-media.js +2 -2
- package/dist/tools/delete-question-media.js.map +1 -1
- package/dist/tools/delete-question.js +2 -2
- package/dist/tools/delete-question.js.map +1 -1
- package/dist/tools/generate-slideshow.js +114 -17
- package/dist/tools/generate-slideshow.js.map +1 -1
- package/dist/tools/generate-tts.js +3 -2
- package/dist/tools/generate-tts.js.map +1 -1
- package/dist/tools/generate-video.d.ts +2 -0
- package/dist/tools/generate-video.js +113 -0
- package/dist/tools/generate-video.js.map +1 -0
- package/dist/tools/get-form.js +1 -1
- package/dist/tools/get-form.js.map +1 -1
- package/dist/tools/get-question-media.js +2 -2
- package/dist/tools/get-question-media.js.map +1 -1
- package/dist/tools/list-assets.js +1 -1
- package/dist/tools/list-assets.js.map +1 -1
- package/dist/tools/list-compositions.js +3 -3
- package/dist/tools/list-compositions.js.map +1 -1
- package/dist/tools/log-generation.js +3 -3
- package/dist/tools/log-generation.js.map +1 -1
- package/dist/tools/render-composition.js +6 -4
- package/dist/tools/render-composition.js.map +1 -1
- package/dist/tools/search-media.js +1 -1
- package/dist/tools/search-media.js.map +1 -1
- package/dist/tools/search-music.js +1 -1
- package/dist/tools/search-music.js.map +1 -1
- package/dist/tools/search-news.js +1 -1
- package/dist/tools/search-news.js.map +1 -1
- package/dist/tools/set-question-logic.js +2 -2
- package/dist/tools/set-question-logic.js.map +1 -1
- package/dist/tools/update-form.js +39 -3
- package/dist/tools/update-form.js.map +1 -1
- package/dist/tools/update-question.js +2 -2
- package/dist/tools/update-question.js.map +1 -1
- package/dist/tools/upload-question-media.js +14 -6
- package/dist/tools/upload-question-media.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -4,19 +4,29 @@ MCP server for [Clipform](https://clipform.io) - build and manage video-style fo
|
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
There are two ways to connect: **remote** (recommended, uses your Clipform account) and **local** (anonymous, free-tier limits).
|
|
8
|
+
|
|
9
|
+
### Remote - claude.ai (recommended)
|
|
10
|
+
|
|
11
|
+
Use this if you have a Clipform account. Forms are created directly in your workspace and your plan tier applies (no 3-question cap on Pro).
|
|
12
|
+
|
|
13
|
+
1. In claude.ai, open **Settings → Connectors → Add custom connector**.
|
|
14
|
+
2. Enter the MCP URL: `https://mcp.clipform.io`
|
|
15
|
+
3. Follow the OAuth prompts. You'll be redirected to Clipform to sign in and pick a workspace.
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
No install or config file needed - claude.ai handles discovery and registration automatically via OAuth 2.1 + Dynamic Client Registration (RFC 7591).
|
|
18
|
+
|
|
19
|
+
### Local - Claude Code / Claude Desktop
|
|
20
|
+
|
|
21
|
+
Use this for local development or if you don't have a Clipform account. Forms go into a shared anonymous workspace with the free-tier 3-question limit, and you claim them afterwards via the claim URL.
|
|
22
|
+
|
|
23
|
+
**Claude Code:**
|
|
12
24
|
|
|
13
25
|
```bash
|
|
14
26
|
claude mcp add clipform -- npx -y @clipform/mcp-server
|
|
15
27
|
```
|
|
16
28
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Add to your `claude_desktop_config.json`:
|
|
29
|
+
**Claude Desktop** - add to `claude_desktop_config.json`:
|
|
20
30
|
|
|
21
31
|
```json
|
|
22
32
|
{
|
|
@@ -59,7 +69,7 @@ Add to your `claude_desktop_config.json`:
|
|
|
59
69
|
|------|-------------|
|
|
60
70
|
| `clipform_render_composition` | Render a Remotion composition to MP4, PNG, or GIF |
|
|
61
71
|
| `clipform_generate_tts` | Generate narration audio with word-level captions |
|
|
62
|
-
| `clipform_generate_slideshow` | Create
|
|
72
|
+
| `clipform_generate_slideshow` | Create slideshow videos from images + audio (director props: zoom, pan, easing, blur-pad, vignette, per-image style) |
|
|
63
73
|
| `clipform_search_media` | Search royalty-free images and videos |
|
|
64
74
|
| `clipform_search_music` | Search royalty-free music and ambient sounds |
|
|
65
75
|
| `clipform_list_compositions` | List available Remotion compositions and prop schemas |
|
|
@@ -71,7 +81,9 @@ Add to your `claude_desktop_config.json`:
|
|
|
71
81
|
|
|
72
82
|
## How it works
|
|
73
83
|
|
|
74
|
-
|
|
84
|
+
**Remote (claude.ai):** OAuth Bearer tokens are audience-bound to `https://mcp.clipform.io` (RFC 8707) and scoped to `mcp` only. Forms land directly in the workspace you approved during consent, and plan-tier limits come from that workspace's company.
|
|
85
|
+
|
|
86
|
+
**Local (npx):** When you create a form, you get back an `edit_token` that authorizes all subsequent changes. The token works until the form is claimed by a user via the claim URL.
|
|
75
87
|
|
|
76
88
|
Forms are created with a start node and end screen automatically - you just add the questions in between.
|
|
77
89
|
|
|
@@ -1,35 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Verifies that the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* This test runs in CI and will fail if the config package changes
|
|
6
|
-
* without the MCP server's inlined copy being updated.
|
|
2
|
+
* Verifies that the MCP server's config re-exports match @vid-master/config.
|
|
3
|
+
* This ensures the re-export path is working correctly.
|
|
7
4
|
*/
|
|
8
5
|
import { describe, it, expect } from "vitest";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
6
|
+
import { NODE_TYPES as SOURCE_NODE_TYPES, CONTACT_FIELDS as SOURCE_CONTACT_FIELDS, } from "@vid-master/config";
|
|
7
|
+
import { NODE_TYPES as MCP_NODE_TYPES, CONTACT_FIELDS as MCP_CONTACT_FIELDS, } from "../lib/config.js";
|
|
11
8
|
describe("config-sync", () => {
|
|
12
|
-
it("
|
|
13
|
-
|
|
14
|
-
.filter(([, def]) => def.is_active && !def.is_system)
|
|
15
|
-
.map(([type]) => type);
|
|
16
|
-
const inlinedTypes = Object.keys(INLINED_ANSWER_TYPES);
|
|
17
|
-
// Same set of type keys
|
|
18
|
-
expect(inlinedTypes.sort()).toEqual(sourceActiveTypes.sort());
|
|
19
|
-
// Each inlined type matches the source on the fields the MCP server uses
|
|
20
|
-
for (const type of inlinedTypes) {
|
|
21
|
-
const source = SOURCE_ANSWER_TYPES[type];
|
|
22
|
-
const inlined = INLINED_ANSWER_TYPES[type];
|
|
23
|
-
expect(inlined.label).toBe(source.label);
|
|
24
|
-
expect(inlined.description).toBe(source.description);
|
|
25
|
-
expect(inlined.is_active).toBe(source.is_active);
|
|
26
|
-
expect(inlined.is_system).toBe(source.is_system);
|
|
27
|
-
expect(inlined.has_options).toBe(source.has_options);
|
|
28
|
-
expect(inlined.config_schema).toEqual(source.config_schema);
|
|
29
|
-
}
|
|
9
|
+
it("NODE_TYPES re-export matches @vid-master/config", () => {
|
|
10
|
+
expect(MCP_NODE_TYPES).toBe(SOURCE_NODE_TYPES);
|
|
30
11
|
});
|
|
31
|
-
it("
|
|
32
|
-
expect(
|
|
12
|
+
it("CONTACT_FIELDS re-export matches @vid-master/config", () => {
|
|
13
|
+
expect(MCP_CONTACT_FIELDS).toBe(SOURCE_CONTACT_FIELDS);
|
|
33
14
|
});
|
|
34
15
|
});
|
|
35
16
|
//# sourceMappingURL=config-sync.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-sync.test.js","sourceRoot":"","sources":["../../src/__tests__/config-sync.test.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"config-sync.test.js","sourceRoot":"","sources":["../../src/__tests__/config-sync.test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,UAAU,IAAI,iBAAiB,EAC/B,cAAc,IAAI,qBAAqB,GACxC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,UAAU,IAAI,cAAc,EAC5B,cAAc,IAAI,kBAAkB,GACrC,MAAM,kBAAkB,CAAC;AAE1B,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/lib/api-client.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ type ApiResult = {
|
|
|
15
15
|
export declare function callApi(path: string, options?: ApiOptions): Promise<ApiResult>;
|
|
16
16
|
/**
|
|
17
17
|
* Call an internal API endpoint (formgen, media, etc.)
|
|
18
|
-
* Uses
|
|
18
|
+
* Uses INTERNAL_SECRET for auth and INTERNAL_API_URL as base.
|
|
19
19
|
*/
|
|
20
20
|
export declare function callInternalApi(path: string, options?: Omit<ApiOptions, "token">): Promise<ApiResult>;
|
|
21
21
|
export declare function errorResult(message: string): {
|
package/dist/lib/api-client.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { getMcpAuth } from "./auth-context.js";
|
|
1
2
|
const DASHBOARD_URL = process.env.SERVER_URL || process.env.DASHBOARD_URL || "https://api.clipform.io";
|
|
2
3
|
const API_VERSION = "v1";
|
|
3
4
|
const INTERNAL_API_URL = process.env.INTERNAL_API_URL || DASHBOARD_URL;
|
|
4
|
-
const
|
|
5
|
+
const INTERNAL_SECRET = process.env.INTERNAL_SERVICE_SECRET || "";
|
|
5
6
|
export async function callApi(path, options = {}) {
|
|
6
7
|
const { method = "GET", body, params, token } = options;
|
|
7
8
|
let url = `${DASHBOARD_URL}/${API_VERSION}${path}`;
|
|
@@ -12,7 +13,22 @@ export async function callApi(path, options = {}) {
|
|
|
12
13
|
const headers = {
|
|
13
14
|
"Content-Type": "application/json",
|
|
14
15
|
};
|
|
15
|
-
|
|
16
|
+
// If the MCP server is running in-process inside the API host AND the
|
|
17
|
+
// request has been OAuth-authenticated, forward the end-user identity
|
|
18
|
+
// via internal headers instead of propagating the caller's Bearer.
|
|
19
|
+
//
|
|
20
|
+
// Token passthrough is forbidden by the MCP Authorization spec: the
|
|
21
|
+
// token that claude.ai presented was issued for audience `${api}/mcp`
|
|
22
|
+
// and must not be replayed against downstream routes like /v1/forms/*.
|
|
23
|
+
// Those routes instead trust the INTERNAL_SECRET + X-Mcp-User /
|
|
24
|
+
// X-Mcp-Workspace headers set below.
|
|
25
|
+
const mcpAuth = getMcpAuth();
|
|
26
|
+
if (mcpAuth && INTERNAL_SECRET) {
|
|
27
|
+
headers["Authorization"] = `Bearer ${INTERNAL_SECRET}`;
|
|
28
|
+
headers["X-Mcp-User"] = mcpAuth.user_id;
|
|
29
|
+
headers["X-Mcp-Workspace"] = mcpAuth.workspace_id;
|
|
30
|
+
}
|
|
31
|
+
else if (token) {
|
|
16
32
|
headers["Authorization"] = `Bearer ${token}`;
|
|
17
33
|
}
|
|
18
34
|
const fetchOptions = { method, headers };
|
|
@@ -46,7 +62,7 @@ export async function callApi(path, options = {}) {
|
|
|
46
62
|
}
|
|
47
63
|
/**
|
|
48
64
|
* Call an internal API endpoint (formgen, media, etc.)
|
|
49
|
-
* Uses
|
|
65
|
+
* Uses INTERNAL_SECRET for auth and INTERNAL_API_URL as base.
|
|
50
66
|
*/
|
|
51
67
|
export async function callInternalApi(path, options = {}) {
|
|
52
68
|
const { method = "POST", body, params } = options;
|
|
@@ -58,8 +74,8 @@ export async function callInternalApi(path, options = {}) {
|
|
|
58
74
|
const headers = {
|
|
59
75
|
"Content-Type": "application/json",
|
|
60
76
|
};
|
|
61
|
-
if (
|
|
62
|
-
headers["Authorization"] = `Bearer ${
|
|
77
|
+
if (INTERNAL_SECRET) {
|
|
78
|
+
headers["Authorization"] = `Bearer ${INTERNAL_SECRET}`;
|
|
63
79
|
}
|
|
64
80
|
const fetchOptions = { method, headers };
|
|
65
81
|
if (body && method !== "GET") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity of the end-user a given MCP request is acting on behalf of.
|
|
3
|
+
*
|
|
4
|
+
* Populated by the in-process host (apps/api) after validating an OAuth
|
|
5
|
+
* Bearer on /mcp. The MCP tool layer reads it to decide which workspace
|
|
6
|
+
* forms should land in and which plan tier gates apply.
|
|
7
|
+
*
|
|
8
|
+
* NOT populated when the server runs as a local stdio process (npx) - in
|
|
9
|
+
* that mode tools fall back to edit-token based auth.
|
|
10
|
+
*/
|
|
11
|
+
export interface McpAuthContext {
|
|
12
|
+
user_id: string;
|
|
13
|
+
workspace_id: string;
|
|
14
|
+
scopes: string[];
|
|
15
|
+
}
|
|
16
|
+
export declare function runWithMcpAuth<T>(ctx: McpAuthContext, fn: () => Promise<T> | T): Promise<T> | T;
|
|
17
|
+
export declare function getMcpAuth(): McpAuthContext | undefined;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
const storage = new AsyncLocalStorage();
|
|
3
|
+
export function runWithMcpAuth(ctx, fn) {
|
|
4
|
+
return storage.run(ctx, fn);
|
|
5
|
+
}
|
|
6
|
+
export function getMcpAuth() {
|
|
7
|
+
return storage.getStore();
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=auth-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-context.js","sourceRoot":"","sources":["../../src/lib/auth-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAkBrD,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAkB,CAAC;AAExD,MAAM,UAAU,cAAc,CAAI,GAAmB,EAAE,EAAwB;IAC7E,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC;AAC5B,CAAC"}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* the MCP server actually references.
|
|
5
|
-
*
|
|
6
|
-
* Keep in sync with packages/config/ — verified by config-sync.test.ts.
|
|
2
|
+
* Re-export from @vid-master/config — single source of truth.
|
|
3
|
+
* The MCP server uses NODE_TYPES and CONTACT_FIELDS directly.
|
|
7
4
|
*/
|
|
8
|
-
export
|
|
5
|
+
export { NODE_TYPES, CONTACT_FIELDS } from "@vid-master/config";
|
|
6
|
+
export type NodeTypeDefinition = {
|
|
9
7
|
label: string;
|
|
10
8
|
description: string;
|
|
11
9
|
is_active: boolean;
|
|
12
10
|
is_system: boolean;
|
|
13
11
|
has_options: boolean;
|
|
12
|
+
min_options?: number;
|
|
13
|
+
max_options?: number;
|
|
14
14
|
max_option_length?: number;
|
|
15
15
|
config_schema: Record<string, unknown> | null;
|
|
16
|
-
}
|
|
17
|
-
export
|
|
16
|
+
};
|
|
17
|
+
export type ContactFieldDefinition = {
|
|
18
18
|
id: string;
|
|
19
19
|
label: string;
|
|
20
20
|
type: string;
|
|
21
21
|
placeholder: string;
|
|
22
22
|
order: number;
|
|
23
|
-
}
|
|
24
|
-
export declare const ANSWER_TYPES: Record<string, AnswerTypeDefinition>;
|
|
25
|
-
export declare const CONTACT_FIELDS: ContactFieldDefinition[];
|
|
23
|
+
};
|
package/dist/lib/config.js
CHANGED
|
@@ -1,339 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* the MCP server actually references.
|
|
5
|
-
*
|
|
6
|
-
* Keep in sync with packages/config/ — verified by config-sync.test.ts.
|
|
2
|
+
* Re-export from @vid-master/config — single source of truth.
|
|
3
|
+
* The MCP server uses NODE_TYPES and CONTACT_FIELDS directly.
|
|
7
4
|
*/
|
|
8
|
-
export
|
|
9
|
-
choice: {
|
|
10
|
-
label: "Multiple Choice",
|
|
11
|
-
description: "Single or multiple choice questions with predefined options",
|
|
12
|
-
is_active: true,
|
|
13
|
-
is_system: false,
|
|
14
|
-
has_options: true,
|
|
15
|
-
max_option_length: 36,
|
|
16
|
-
config_schema: {
|
|
17
|
-
type: "object",
|
|
18
|
-
properties: {
|
|
19
|
-
choice: {
|
|
20
|
-
type: "object",
|
|
21
|
-
properties: {
|
|
22
|
-
enable_branching: {
|
|
23
|
-
type: "boolean",
|
|
24
|
-
label: "Enable branching logic",
|
|
25
|
-
default: true,
|
|
26
|
-
description: "Allow each option to have its own logic path. When disabled, all options share a single jump action.",
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
selection_mode: {
|
|
31
|
-
enum: ["single", "multiple"],
|
|
32
|
-
type: "string",
|
|
33
|
-
label: "Selection mode",
|
|
34
|
-
default: "single",
|
|
35
|
-
description: "Allow single or multiple selections",
|
|
36
|
-
},
|
|
37
|
-
allow_text_response: {
|
|
38
|
-
type: "boolean",
|
|
39
|
-
label: "Allow text response",
|
|
40
|
-
default: false,
|
|
41
|
-
description: "Allow free-text response in addition to options (single choice only)",
|
|
42
|
-
},
|
|
43
|
-
randomise_options: {
|
|
44
|
-
type: "boolean",
|
|
45
|
-
label: "Randomise options",
|
|
46
|
-
default: false,
|
|
47
|
-
description: "Show options in random order",
|
|
48
|
-
},
|
|
49
|
-
show_option_count: {
|
|
50
|
-
type: "boolean",
|
|
51
|
-
label: "Show option count",
|
|
52
|
-
default: false,
|
|
53
|
-
description: "Display number of options",
|
|
54
|
-
},
|
|
55
|
-
content_media_type: {
|
|
56
|
-
enum: ["upload", "recorded"],
|
|
57
|
-
type: "string",
|
|
58
|
-
label: "Content media type",
|
|
59
|
-
description: "How the question media was provided",
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
open: {
|
|
65
|
-
label: "Open Ended",
|
|
66
|
-
description: "Free-form text responses from users",
|
|
67
|
-
is_active: true,
|
|
68
|
-
is_system: false,
|
|
69
|
-
has_options: false,
|
|
70
|
-
config_schema: {
|
|
71
|
-
type: "object",
|
|
72
|
-
properties: {
|
|
73
|
-
formats: {
|
|
74
|
-
type: "array",
|
|
75
|
-
items: {
|
|
76
|
-
type: "object",
|
|
77
|
-
properties: {
|
|
78
|
-
format: {
|
|
79
|
-
enum: ["text", "audio", "video"],
|
|
80
|
-
type: "string",
|
|
81
|
-
},
|
|
82
|
-
order: { type: "number" },
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
label: "Allowed response formats",
|
|
86
|
-
description: "Which formats the user can respond with, in display order",
|
|
87
|
-
},
|
|
88
|
-
content_media_type: {
|
|
89
|
-
enum: ["upload", "recorded"],
|
|
90
|
-
type: "string",
|
|
91
|
-
label: "Content media type",
|
|
92
|
-
description: "How the question media was provided",
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
},
|
|
97
|
-
contact: {
|
|
98
|
-
label: "Contact Form",
|
|
99
|
-
description: "Collect standardized contact information (name, email, phone, company)",
|
|
100
|
-
is_active: true,
|
|
101
|
-
is_system: false,
|
|
102
|
-
has_options: false,
|
|
103
|
-
config_schema: {
|
|
104
|
-
type: "object",
|
|
105
|
-
properties: {
|
|
106
|
-
title: { type: "string" },
|
|
107
|
-
fields: {
|
|
108
|
-
type: "array",
|
|
109
|
-
items: {
|
|
110
|
-
type: "object",
|
|
111
|
-
required: ["id", "required"],
|
|
112
|
-
properties: {
|
|
113
|
-
id: { type: "string" },
|
|
114
|
-
type: {
|
|
115
|
-
enum: ["text", "textarea", "email", "tel", "url"],
|
|
116
|
-
type: "string",
|
|
117
|
-
},
|
|
118
|
-
label: { type: "string" },
|
|
119
|
-
order: { type: "number" },
|
|
120
|
-
required: { type: "boolean", default: true },
|
|
121
|
-
is_custom: { type: "boolean", default: false },
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
description: { type: "string" },
|
|
126
|
-
consent_items: {
|
|
127
|
-
type: "array",
|
|
128
|
-
items: {
|
|
129
|
-
type: "object",
|
|
130
|
-
properties: {
|
|
131
|
-
id: { type: "string" },
|
|
132
|
-
label: { type: "string" },
|
|
133
|
-
order: { type: "number" },
|
|
134
|
-
required: { type: "boolean" },
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
},
|
|
141
|
-
binary: {
|
|
142
|
-
label: "Binary",
|
|
143
|
-
description: "Two-option choice - yes/no, true/false, or this vs that",
|
|
144
|
-
is_active: true,
|
|
145
|
-
is_system: false,
|
|
146
|
-
has_options: true,
|
|
147
|
-
max_option_length: 12,
|
|
148
|
-
config_schema: {
|
|
149
|
-
type: "object",
|
|
150
|
-
properties: {
|
|
151
|
-
choice: {
|
|
152
|
-
type: "object",
|
|
153
|
-
properties: {
|
|
154
|
-
enable_branching: {
|
|
155
|
-
type: "boolean",
|
|
156
|
-
label: "Enable branching logic",
|
|
157
|
-
default: true,
|
|
158
|
-
description: "Allow each option to have its own logic path.",
|
|
159
|
-
},
|
|
160
|
-
},
|
|
161
|
-
},
|
|
162
|
-
content_media_type: {
|
|
163
|
-
enum: ["upload", "recorded"],
|
|
164
|
-
type: "string",
|
|
165
|
-
label: "Content media type",
|
|
166
|
-
description: "How the question media was provided",
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
},
|
|
171
|
-
button: {
|
|
172
|
-
label: "Button",
|
|
173
|
-
description: "Simple button for acknowledgment or navigation",
|
|
174
|
-
is_active: true,
|
|
175
|
-
is_system: false,
|
|
176
|
-
has_options: true,
|
|
177
|
-
max_option_length: 28,
|
|
178
|
-
config_schema: {
|
|
179
|
-
type: "object",
|
|
180
|
-
properties: {
|
|
181
|
-
button_text: {
|
|
182
|
-
type: "string",
|
|
183
|
-
label: "Button text",
|
|
184
|
-
default: "Continue",
|
|
185
|
-
},
|
|
186
|
-
button_style: {
|
|
187
|
-
enum: ["primary", "secondary", "outline"],
|
|
188
|
-
type: "string",
|
|
189
|
-
label: "Button style",
|
|
190
|
-
default: "primary",
|
|
191
|
-
},
|
|
192
|
-
},
|
|
193
|
-
},
|
|
194
|
-
},
|
|
195
|
-
external_link: {
|
|
196
|
-
label: "External Link",
|
|
197
|
-
description: "Redirect users to an external URL",
|
|
198
|
-
is_active: true,
|
|
199
|
-
is_system: false,
|
|
200
|
-
has_options: false,
|
|
201
|
-
config_schema: {
|
|
202
|
-
type: "object",
|
|
203
|
-
properties: {
|
|
204
|
-
links: {
|
|
205
|
-
type: "array",
|
|
206
|
-
items: {
|
|
207
|
-
type: "object",
|
|
208
|
-
required: ["id", "url"],
|
|
209
|
-
properties: {
|
|
210
|
-
id: { type: "string" },
|
|
211
|
-
url: {
|
|
212
|
-
type: "string",
|
|
213
|
-
label: "URL",
|
|
214
|
-
placeholder: "https://example.com",
|
|
215
|
-
},
|
|
216
|
-
title: { type: "string", label: "Heading" },
|
|
217
|
-
description: { type: "string", label: "Description" },
|
|
218
|
-
order: { type: "number", label: "Sort order" },
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
|
-
label: "Links",
|
|
222
|
-
minItems: 1,
|
|
223
|
-
},
|
|
224
|
-
auto_redirect: {
|
|
225
|
-
type: "boolean",
|
|
226
|
-
label: "Auto-redirect",
|
|
227
|
-
default: false,
|
|
228
|
-
description: "Automatically redirect to the URL instead of showing a button",
|
|
229
|
-
},
|
|
230
|
-
},
|
|
231
|
-
},
|
|
232
|
-
},
|
|
233
|
-
end_screen: {
|
|
234
|
-
label: "End Screen",
|
|
235
|
-
description: "Final screen shown when form is completed",
|
|
236
|
-
is_active: true,
|
|
237
|
-
is_system: false,
|
|
238
|
-
has_options: false,
|
|
239
|
-
config_schema: {
|
|
240
|
-
type: "object",
|
|
241
|
-
properties: {
|
|
242
|
-
title: {
|
|
243
|
-
type: "string",
|
|
244
|
-
label: "Title",
|
|
245
|
-
default: "Thank you!",
|
|
246
|
-
description: "Heading shown on completion",
|
|
247
|
-
},
|
|
248
|
-
message: {
|
|
249
|
-
type: "string",
|
|
250
|
-
label: "Message",
|
|
251
|
-
default: "Your response has been submitted.",
|
|
252
|
-
description: "Message shown on completion",
|
|
253
|
-
},
|
|
254
|
-
show_score: {
|
|
255
|
-
type: "boolean",
|
|
256
|
-
label: "Show score",
|
|
257
|
-
default: false,
|
|
258
|
-
description: "Display score on the end screen (e.g. \"You scored 4 out of 5\")",
|
|
259
|
-
},
|
|
260
|
-
icon: {
|
|
261
|
-
type: "string",
|
|
262
|
-
label: "Icon",
|
|
263
|
-
enum: ["tick", "trophy", "star", "crown", "party", "none"],
|
|
264
|
-
default: "tick",
|
|
265
|
-
description: "Icon shown above the title",
|
|
266
|
-
},
|
|
267
|
-
show_share_button: {
|
|
268
|
-
type: "boolean",
|
|
269
|
-
label: "Show share button",
|
|
270
|
-
default: false,
|
|
271
|
-
description: "Show a share button above the CTA",
|
|
272
|
-
},
|
|
273
|
-
cta_type: {
|
|
274
|
-
type: "string",
|
|
275
|
-
label: "CTA type",
|
|
276
|
-
enum: ["none", "restart", "external_link"],
|
|
277
|
-
default: "none",
|
|
278
|
-
description: "Primary call-to-action button type",
|
|
279
|
-
},
|
|
280
|
-
cta_text: {
|
|
281
|
-
type: "string",
|
|
282
|
-
label: "CTA button text",
|
|
283
|
-
default: "Continue",
|
|
284
|
-
description: "Button label for the CTA",
|
|
285
|
-
},
|
|
286
|
-
cta_url: {
|
|
287
|
-
type: "string",
|
|
288
|
-
label: "CTA URL",
|
|
289
|
-
format: "uri",
|
|
290
|
-
description: "URL to open (only for external_link CTA type)",
|
|
291
|
-
placeholder: "https://example.com",
|
|
292
|
-
},
|
|
293
|
-
score_ranges: {
|
|
294
|
-
type: "array",
|
|
295
|
-
label: "Score-based content",
|
|
296
|
-
description: "Show different content based on cumulative score. First matching range wins.",
|
|
297
|
-
items: {
|
|
298
|
-
type: "object",
|
|
299
|
-
required: ["min", "max", "title"],
|
|
300
|
-
properties: {
|
|
301
|
-
min: { type: "integer", label: "Minimum score (inclusive)" },
|
|
302
|
-
max: { type: "integer", label: "Maximum score (inclusive)" },
|
|
303
|
-
title: { type: "string", label: "Title" },
|
|
304
|
-
message: { type: "string", label: "Message" },
|
|
305
|
-
},
|
|
306
|
-
},
|
|
307
|
-
},
|
|
308
|
-
scoring_results: {
|
|
309
|
-
type: "array",
|
|
310
|
-
label: "Category-based results",
|
|
311
|
-
description: "Results keyed by scoring category. The winning category (highest non-knocked-out score) determines which result is shown.",
|
|
312
|
-
items: {
|
|
313
|
-
type: "object",
|
|
314
|
-
required: ["category", "title"],
|
|
315
|
-
properties: {
|
|
316
|
-
category: { type: "string", label: "Category key (must match keys used in option scores)" },
|
|
317
|
-
title: { type: "string", label: "Title" },
|
|
318
|
-
message: { type: "string", label: "Message" },
|
|
319
|
-
cta_url: { type: "string", label: "CTA URL", format: "uri" },
|
|
320
|
-
cta_text: { type: "string", label: "CTA button text" },
|
|
321
|
-
},
|
|
322
|
-
},
|
|
323
|
-
},
|
|
324
|
-
},
|
|
325
|
-
},
|
|
326
|
-
},
|
|
327
|
-
};
|
|
328
|
-
export const CONTACT_FIELDS = [
|
|
329
|
-
{ id: "first_name", label: "First Name", type: "text", placeholder: "Enter first name", order: 1 },
|
|
330
|
-
{ id: "last_name", label: "Last Name", type: "text", placeholder: "Enter last name", order: 2 },
|
|
331
|
-
{ id: "email", label: "Email Address", type: "email", placeholder: "you@example.com", order: 3 },
|
|
332
|
-
{ id: "phone", label: "Phone Number", type: "tel", placeholder: "(555) 123-4567", order: 4 },
|
|
333
|
-
{ id: "company", label: "Company", type: "text", placeholder: "Company name", order: 5 },
|
|
334
|
-
{ id: "job_title", label: "Job Title", type: "text", placeholder: "Your role", order: 6 },
|
|
335
|
-
{ id: "website", label: "Website", type: "url", placeholder: "https://example.com", order: 7 },
|
|
336
|
-
{ id: "linkedin", label: "LinkedIn Profile", type: "url", placeholder: "https://linkedin.com/in/username", order: 8 },
|
|
337
|
-
{ id: "message", label: "Message", type: "textarea", placeholder: "Your message...", order: 9 },
|
|
338
|
-
];
|
|
5
|
+
export { NODE_TYPES, CONTACT_FIELDS } from "@vid-master/config";
|
|
339
6
|
//# sourceMappingURL=config.js.map
|
package/dist/lib/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC"}
|