@clipform/mcp-server 4.5.0 → 4.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.
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  FULL_CAPS,
3
3
  getSessionContext
4
- } from "./chunk-RN5ORN7O.js";
4
+ } from "./chunk-EFPJA3JE.js";
5
5
  import {
6
6
  ALL_VARIANTS,
7
7
  FORM_TYPES,
8
8
  FORM_TYPE_KEYS,
9
9
  callApi
10
- } from "./chunk-Q6OG6RXP.js";
10
+ } from "./chunk-XC3YMWCN.js";
11
11
  import {
12
12
  getMcpAuth
13
- } from "./chunk-BV3KA6HC.js";
13
+ } from "./chunk-ENVV65JX.js";
14
14
 
15
15
  // src/lib/guides.ts
16
16
  var guidesPromise = null;
@@ -155,4 +155,4 @@ export {
155
155
  getGuideUri,
156
156
  registerResources
157
157
  };
158
- //# sourceMappingURL=chunk-WTYIKGXQ.js.map
158
+ //# sourceMappingURL=chunk-VSSV3IOU.js.map
@@ -5,7 +5,7 @@ import {
5
5
  MCP_SESSION_ID_HEADER,
6
6
  MCP_SESSION_PROOF_HEADER,
7
7
  getMcpAuth
8
- } from "./chunk-BV3KA6HC.js";
8
+ } from "./chunk-ENVV65JX.js";
9
9
  import {
10
10
  isAuthFault,
11
11
  isServerFault,
@@ -239,13 +239,13 @@ var FEATURES = {
239
239
  node_draw: {
240
240
  name: "Drawing",
241
241
  description: "Drawing canvas; respondents draw and it is saved as a PNG image",
242
- // Went GA 2026-06-27 (#1012), pulled back behind the allowlist 2026-07-20
243
- // (#2289) while pen options / match-to-shape mature. Prod usage at
244
- // pull-back verified = Clipform Public only, zero external customers.
245
- // Existing nodes still render (creation-gated only, camera precedent).
246
- enabled: false,
247
- status: "beta",
248
- wentLiveAt: "2026-06-27",
242
+ // First GA 2026-06-27 (#1012), pulled back behind the allowlist 2026-07-20
243
+ // (#2289), back to GA 2026-10-26 (#5052). The NODE_COMPANY_ALLOWLIST.node_draw
244
+ // entry below stays as a safety valve: flip enabled back to false to pull it
245
+ // behind the allowlist again (creation-gated only - existing nodes render).
246
+ enabled: true,
247
+ status: "live",
248
+ wentLiveAt: "2026-10-26",
249
249
  category: "node-types"
250
250
  },
251
251
  node_camera: {
@@ -838,6 +838,7 @@ var HELP_TOPICS = {
838
838
  node_choice: { path: "/help/node-types", anchor: "choice" },
839
839
  node_open: { path: "/help/node-types", anchor: "open-ended" },
840
840
  node_camera: { path: "/help/node-types", anchor: "camera" },
841
+ node_draw: { path: "/help/node-types", anchor: "drawing" },
841
842
  node_details: { path: "/help/node-types", anchor: "details" },
842
843
  node_button: { path: "/help/node-types", anchor: "button" },
843
844
  node_end_screen: { path: "/help/node-types", anchor: "end-screen" },
@@ -853,6 +854,19 @@ function buildHelpLinks(docsBaseUrl) {
853
854
  return links;
854
855
  }
855
856
 
857
+ // ../config/draw-presets.js
858
+ var DRAW_PRESETS = [
859
+ { id: "body-front", label: "Body diagram - front", shortLabel: "Front", file: "body-front.png", group: "body" },
860
+ { id: "body-back", label: "Body diagram - back", shortLabel: "Back", file: "body-back.png", group: "body" },
861
+ { id: "hands-palms", label: "Hands diagram - palms", shortLabel: "Palms", file: "hands-palms.png", group: "body" },
862
+ { id: "hands-backs", label: "Hands diagram - backs", shortLabel: "Backs of hands", file: "hands-backs.png", group: "body" },
863
+ { id: "feet-soles", label: "Feet diagram - soles", shortLabel: "Soles", file: "feet-soles.png", group: "body" },
864
+ { id: "face-profile", label: "Face diagram - profile", shortLabel: "Face", file: "face-profile.png", group: "body" },
865
+ { id: "vehicle-sides", label: "Vehicle diagram - sides", shortLabel: "Sides", file: "vehicle-sides.png", group: "vehicle" },
866
+ { id: "vehicle-top", label: "Vehicle diagram - top and ends", shortLabel: "Top and ends", file: "vehicle-top.png", group: "vehicle" }
867
+ ];
868
+ var DRAW_PRESET_IDS = DRAW_PRESETS.map((p) => p.id);
869
+
856
870
  // ../config/node-types.js
857
871
  var RESPONSE_FORMATS = ["text", "audio", "video"];
858
872
  var CONSENT_TYPES = ["consent", "opt_in"];
@@ -1349,8 +1363,11 @@ var NODE_TYPES = {
1349
1363
  type: { type: "string", enum: CONSENT_TYPES },
1350
1364
  // Optional attached agreement document (PDF only in v1, #2760). Served
1351
1365
  // from the public node-media bucket; `version` bumps on file replace.
1366
+ // anon_locked_file: an outside file on a guest live form (#4847), stripped from the
1367
+ // payload so the item renders as a plain consent checkbox.
1352
1368
  document: {
1353
1369
  type: "object",
1370
+ anon_locked_file: true,
1354
1371
  properties: {
1355
1372
  storage_path: { type: "string" },
1356
1373
  filename: { type: "string" },
@@ -1629,7 +1646,8 @@ var NODE_TYPES = {
1629
1646
  default: [3, 6, 12],
1630
1647
  description: "Stroke widths (px) the respondent can choose. The middle entry is the default selection; a single entry locks the pen to that width and hides the picker."
1631
1648
  },
1632
- // The reference image itself is the node's attached media (media_id,
1649
+ // The reference image is EITHER a built-in outline (`preset`, below: a static image
1650
+ // referenced by name, #5263) OR the node's attached media (media_id,
1633
1651
  // via the same media_asset/create-media.ts pipeline every other
1634
1652
  // supports_media node uses) - not a config field, to avoid a
1635
1653
  // duplicated asset ref. This only tunes its display/bake.
@@ -1638,9 +1656,11 @@ var NODE_TYPES = {
1638
1656
  label: "Diagram",
1639
1657
  description: "Display settings for the optional diagram the respondent draws on (a body, vehicle or your own image)",
1640
1658
  properties: {
1641
- // Fit + position live on the node_media placement (fit_media / position_x), shared with every media node.
1659
+ // Fit + position (uploaded image only) live on the node_media placement (fit_media / position_x), shared with every media node.
1642
1660
  opacity: { type: "number", minimum: 0, maximum: 1, default: 1, label: "Opacity", description: "Diagram opacity, from 0 (invisible) to 1 (fully opaque)" },
1643
- scale: { type: "number", minimum: 0.5, maximum: 1, default: 1, label: "Size", description: "Diagram size as a fraction of its fitted size. Applies only when the diagram is fitted (fit_media true)." }
1661
+ scale: { type: "number", minimum: 0.5, maximum: 1, default: 1, label: "Size", description: "Diagram size as a fraction of its fitted size. Applies only when the diagram is fitted (fit_media true)." },
1662
+ // A built-in outline (#5263): a static image served by the viewer, referenced by name. Not a media asset - no placement. Wins over an attached image; always shown whole and centred.
1663
+ preset: { type: "string", enum: DRAW_PRESETS.map((p) => p.id), label: "Built-in diagram", description: "Use a ready-made outline instead of an uploaded image: " + DRAW_PRESETS.map((p) => `${p.id} (${p.label})`).join(", ") + ". Shown whole and centred, so fit/position do not apply. Shown instead of any attached image while set; unset it to use the attached image of the node." }
1644
1664
  }
1645
1665
  },
1646
1666
  // Optional match-to-shape game (#2148). Absent entirely by default
@@ -1893,7 +1913,25 @@ var NODE_TYPES = {
1893
1913
  storage_path: { type: "string", description: "Bucket-prefixed storage path: respondent-captures/workspace_id/form_id/session_id/uuid.ext" },
1894
1914
  width: { type: "number", description: "Displayed pixel width, when the browser could read it (#5125)" },
1895
1915
  height: { type: "number", description: "Displayed pixel height, when the browser could read it (#5125)" },
1896
- duration: { type: "number", description: "Video duration in seconds, when readable (#5125)" }
1916
+ duration: { type: "number", description: "Video duration in seconds, when readable (#5125)" },
1917
+ // Viewer-written for a video recorded without the on-device 9:16 crop (#5253); the camera
1918
+ // video processor validates it and crops the playback copy server-side.
1919
+ preview_crop: {
1920
+ type: "object",
1921
+ description: "What the viewfinder showed (stream and preview box sizes); untrusted, validated server-side",
1922
+ properties: {
1923
+ stream_width: { type: "number" },
1924
+ stream_height: { type: "number" },
1925
+ preview_width: { type: "number" },
1926
+ preview_height: { type: "number" }
1927
+ }
1928
+ },
1929
+ // Server-written by the camera video processor (#5114); stripped from client input.
1930
+ thumbnail_storage_path: { type: "string", description: "Poster frame (webp) of a video, bucket-prefixed" },
1931
+ playback_storage_path: { type: "string", description: "Browser-safe H.264/AAC mp4 copy of a video, when the original is not one" },
1932
+ processed_at: { type: "string", description: "When the video was processed" },
1933
+ processing_attempts: { type: "integer", description: "Failed processing attempts so far" },
1934
+ processing_failed_at: { type: "string", description: "Set once processing gave up" }
1897
1935
  }
1898
1936
  },
1899
1937
  minItems: 1,
@@ -2006,8 +2044,8 @@ var NODE_TYPES = {
2006
2044
  currency: { enum: ["usd", "eur", "gbp", "cad", "aud"], type: "string", label: "Currency", default: "usd", required: true, description: "Three-letter ISO currency code" },
2007
2045
  provider: { enum: ["stripe", "paddle"], type: "string", label: "Payment Provider", default: "stripe", required: true, description: "Payment provider to use" },
2008
2046
  workspace_integration_id: { type: "string", label: "Workspace Integration ID", description: "UUID of the workspace_integrations record for the connected payment account" },
2009
- title: { type: "string", label: "Heading", description: "Heading shown above the order summary" },
2010
- description: { type: "string", label: "Description", description: "Body text shown below the heading in the order summary" }
2047
+ title: { type: "string", label: "Heading", description: "Heading shown above the order summary", anon_locked_keep: true },
2048
+ description: { type: "string", label: "Description", description: "Body text shown below the heading in the order summary", anon_locked_keep: true }
2011
2049
  },
2012
2050
  description: "Payment configuration with provider-agnostic flat structure"
2013
2051
  },
@@ -2257,7 +2295,7 @@ var NODE_TYPES = {
2257
2295
  config_schema: {
2258
2296
  type: "object",
2259
2297
  properties: {
2260
- url: { type: "string", label: "Redirect URL", placeholder: "https://example.com" },
2298
+ url: { type: "string", label: "Redirect URL", placeholder: "https://example.com", outbound_link: true },
2261
2299
  auto_redirect: { type: "boolean", label: "Auto-redirect", default: true, description: "Automatically redirect to the URL instead of showing a button" }
2262
2300
  }
2263
2301
  },
@@ -2300,7 +2338,7 @@ var NODE_TYPES = {
2300
2338
  required: ["id", "url"],
2301
2339
  properties: {
2302
2340
  id: { type: "string" },
2303
- url: { type: "string", label: "URL", placeholder: "https://example.com" },
2341
+ url: { type: "string", label: "URL", placeholder: "https://example.com", outbound_link: true },
2304
2342
  title: { type: "string", label: "Heading" },
2305
2343
  description: { type: "string", label: "Description" },
2306
2344
  order: { type: "number", label: "Sort order" }
@@ -2361,7 +2399,7 @@ var NODE_TYPES = {
2361
2399
  label: "Downloadable files"
2362
2400
  },
2363
2401
  button_text: { type: "string", label: "Continue button text", default: "Continue" },
2364
- description: { type: "string", label: "Description text" }
2402
+ description: { type: "string", label: "Description text", anon_locked_keep: true }
2365
2403
  }
2366
2404
  },
2367
2405
  response_schema: {
@@ -2630,6 +2668,52 @@ var ANON_MCP_OUTBOUND_LINK_RULES = (() => {
2630
2668
  for (const [type, def] of Object.entries(NODE_TYPES)) walk(type, def.config_schema, []);
2631
2669
  return rules;
2632
2670
  })();
2671
+ var ANON_MCP_STRIPPED_FIELD_RULES = (() => {
2672
+ const rules = ANON_MCP_OUTBOUND_LINK_RULES.filter((r) => r.kind === "non_empty" && !ANON_MCP_BLOCKED_NODE_TYPES.includes(r.type)).map(({ type, path }) => ({ type, path }));
2673
+ const walk = (type, schema, path) => {
2674
+ if (!schema || typeof schema !== "object") return;
2675
+ for (const [key, prop] of Object.entries(schema.properties ?? {})) {
2676
+ const next = [...path, key];
2677
+ if (prop.anon_locked_file === true) rules.push({ type, path: next });
2678
+ walk(type, prop, next);
2679
+ if (prop.items) walk(type, prop.items, [...next, "[]"]);
2680
+ }
2681
+ for (const branch of [...schema.oneOf ?? [], ...schema.anyOf ?? []]) walk(type, branch, path);
2682
+ };
2683
+ for (const [type, def] of Object.entries(NODE_TYPES)) {
2684
+ if (!ANON_MCP_BLOCKED_NODE_TYPES.includes(type)) walk(type, def.config_schema, []);
2685
+ }
2686
+ return rules;
2687
+ })();
2688
+ var ANON_MCP_KEPT_TEXT_KEYS = (() => {
2689
+ const out = {};
2690
+ for (const type of ANON_MCP_BLOCKED_NODE_TYPES) {
2691
+ const props = NODE_TYPES[type]?.config_schema?.properties ?? {};
2692
+ const keys = Object.entries(props).filter(([, p]) => p && p.anon_locked_keep === true && p.type === "string").map(([k]) => k);
2693
+ if (keys.length > 0) out[type] = keys;
2694
+ }
2695
+ return out;
2696
+ })();
2697
+ function anonValuesAtPath(value, path) {
2698
+ if (path.length === 0) return [value];
2699
+ const [head, ...rest] = path;
2700
+ if (head === "[]") return Array.isArray(value) ? value.flatMap((v) => anonValuesAtPath(v, rest)) : [];
2701
+ if (value && typeof value === "object") return anonValuesAtPath(value[head], rest);
2702
+ return [];
2703
+ }
2704
+ function isAnonMcpLockedNode(node) {
2705
+ if (!node || typeof node.type !== "string") return false;
2706
+ if (ANON_MCP_BLOCKED_NODE_TYPES.includes(node.type)) return true;
2707
+ const isSet = (v) => typeof v === "string" ? v.trim() !== "" : v != null && v !== false;
2708
+ const outbound = ANON_MCP_OUTBOUND_LINK_RULES.some((rule) => {
2709
+ if (rule.type !== node.type) return false;
2710
+ return anonValuesAtPath(node.config, rule.path).some((v) => rule.kind === "equals" ? v === rule.value : isSet(v));
2711
+ });
2712
+ if (outbound) return true;
2713
+ return ANON_MCP_STRIPPED_FIELD_RULES.some(
2714
+ (rule) => rule.type === node.type && anonValuesAtPath(node.config, rule.path).some(isSet)
2715
+ );
2716
+ }
2633
2717
 
2634
2718
  // ../config/form-types.js
2635
2719
  var FORM_TYPES = {
@@ -2893,6 +2977,12 @@ function isInactiveOptionEdge(node, action) {
2893
2977
  return isOptionEdge(action) && !isBranchingActive(node);
2894
2978
  }
2895
2979
 
2980
+ // ../config/anon-mcp-limits.js
2981
+ var ANON_MCP_RESPONSE_CAP = 3;
2982
+ var ANON_MCP_STARTED_SESSION_MULTIPLE = 5;
2983
+ var ANON_MCP_STARTED_SESSION_CAP = ANON_MCP_RESPONSE_CAP * ANON_MCP_STARTED_SESSION_MULTIPLE;
2984
+ var ANON_MCP_LIVE_TTL_DAYS = 7;
2985
+
2896
2986
  // ../config/logic-chain.js
2897
2987
  function outgoingTargets(actions, node) {
2898
2988
  const out = [];
@@ -3015,6 +3105,7 @@ var BUSINESS = {
3015
3105
  };
3016
3106
  var MEDIA_DIRECT_MAX_BYTES = 20 * 1024 * 1024;
3017
3107
  var MEDIA_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
3108
+ var DRAW_DIAGRAM_SPEC = `PNG with simple dark outlines on a light or transparent background (no shading or text), portrait, at least 1000px wide. Up to ${Math.round(MEDIA_IMAGE_MAX_BYTES / (1024 * 1024))}MB.`;
3018
3109
  var MEDIA_DOCUMENT_MAX_BYTES = 20 * 1024 * 1024;
3019
3110
  var SUPABASE_STORAGE_MAX_BYTES = 200 * 1024 * 1024;
3020
3111
  var VIDEO_COMPRESS_FLOOR_BYTES = 1 * 1024 * 1024;
@@ -3335,10 +3426,6 @@ var MCP_TOOL_SECURITY = Object.freeze(
3335
3426
  ])
3336
3427
  )
3337
3428
  );
3338
- var MCP_ANON_PUBLISH_GATE = Object.freeze({
3339
- tool: "clipform_update_form",
3340
- argument: "is_live"
3341
- });
3342
3429
 
3343
3430
  // src/lib/api-client.ts
3344
3431
  function getApiBaseUrl() {
@@ -3518,6 +3605,8 @@ export {
3518
3605
  stripGatedConfigKeys,
3519
3606
  ACTIVE_NODE_TYPES,
3520
3607
  NON_COUNTABLE_TYPES,
3608
+ ANON_MCP_BLOCKED_NODE_TYPES,
3609
+ isAnonMcpLockedNode,
3521
3610
  FORM_TYPES,
3522
3611
  FORM_TYPES_LIST,
3523
3612
  FORM_TYPE_KEYS,
@@ -3526,6 +3615,8 @@ export {
3526
3615
  ALL_VARIANTS,
3527
3616
  resolveFormType,
3528
3617
  getDiscoveryParams,
3618
+ ANON_MCP_RESPONSE_CAP,
3619
+ ANON_MCP_LIVE_TTL_DAYS,
3529
3620
  defaultTarget,
3530
3621
  bfsOrder,
3531
3622
  PLAN_LIMITS,
@@ -3535,7 +3626,6 @@ export {
3535
3626
  MCP_TOOL_TIERS,
3536
3627
  MCP_TOOL_TOOLSETS,
3537
3628
  MCP_TOOL_SECURITY,
3538
- MCP_ANON_PUBLISH_GATE,
3539
3629
  callApi,
3540
3630
  recoveryHint,
3541
3631
  errorResult,
@@ -3544,4 +3634,4 @@ export {
3544
3634
  textResult,
3545
3635
  structuredResult
3546
3636
  };
3547
- //# sourceMappingURL=chunk-Q6OG6RXP.js.map
3637
+ //# sourceMappingURL=chunk-XC3YMWCN.js.map