@wootsup/mcp 0.1.0-rc.9 → 0.3.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/CHANGELOG.md +148 -83
- package/README.md +36 -32
- package/SECURITY.md +15 -6
- package/dist/auth/keychain.d.ts +27 -1
- package/dist/auth/keychain.js +48 -2
- package/dist/auth/keychain.js.map +1 -1
- package/dist/cli-hint.d.ts +22 -0
- package/dist/cli-hint.js +55 -0
- package/dist/cli-hint.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +163 -22
- package/dist/index.js.map +1 -1
- package/dist/install-skill.js +1 -1
- package/dist/modules/apimapper/cache.d.ts +2 -2
- package/dist/modules/apimapper/cache.js +119 -29
- package/dist/modules/apimapper/cache.js.map +1 -1
- package/dist/modules/apimapper/client.d.ts +102 -1
- package/dist/modules/apimapper/client.js +631 -297
- package/dist/modules/apimapper/client.js.map +1 -1
- package/dist/modules/apimapper/connections-format.d.ts +51 -0
- package/dist/modules/apimapper/connections-format.js +261 -0
- package/dist/modules/apimapper/connections-format.js.map +1 -0
- package/dist/modules/apimapper/connections-trim.d.ts +82 -0
- package/dist/modules/apimapper/connections-trim.js +224 -0
- package/dist/modules/apimapper/connections-trim.js.map +1 -0
- package/dist/modules/apimapper/connections.d.ts +14 -2
- package/dist/modules/apimapper/connections.js +612 -153
- package/dist/modules/apimapper/connections.js.map +1 -1
- package/dist/modules/apimapper/credential-sanitizer.d.ts +5 -0
- package/dist/modules/apimapper/credential-sanitizer.js +60 -1
- package/dist/modules/apimapper/credential-sanitizer.js.map +1 -1
- package/dist/modules/apimapper/credentials-format.d.ts +21 -0
- package/dist/modules/apimapper/credentials-format.js +145 -0
- package/dist/modules/apimapper/credentials-format.js.map +1 -0
- package/dist/modules/apimapper/credentials.d.ts +12 -2
- package/dist/modules/apimapper/credentials.js +226 -73
- package/dist/modules/apimapper/credentials.js.map +1 -1
- package/dist/modules/apimapper/diagnose.d.ts +54 -2
- package/dist/modules/apimapper/diagnose.js +213 -12
- package/dist/modules/apimapper/diagnose.js.map +1 -1
- package/dist/modules/apimapper/elicitation.d.ts +54 -0
- package/dist/modules/apimapper/elicitation.js +90 -0
- package/dist/modules/apimapper/elicitation.js.map +1 -0
- package/dist/modules/apimapper/flows-format.d.ts +50 -0
- package/dist/modules/apimapper/flows-format.js +318 -0
- package/dist/modules/apimapper/flows-format.js.map +1 -0
- package/dist/modules/apimapper/flows.d.ts +13 -2
- package/dist/modules/apimapper/flows.js +312 -122
- package/dist/modules/apimapper/flows.js.map +1 -1
- package/dist/modules/apimapper/gateway/advanced-tool.d.ts +9 -0
- package/dist/modules/apimapper/gateway/advanced-tool.js +265 -0
- package/dist/modules/apimapper/gateway/advanced-tool.js.map +1 -0
- package/dist/modules/apimapper/gateway/capturing-server.d.ts +81 -0
- package/dist/modules/apimapper/gateway/capturing-server.js +87 -0
- package/dist/modules/apimapper/gateway/capturing-server.js.map +1 -0
- package/dist/modules/apimapper/gateway/essentials.d.ts +4 -0
- package/dist/modules/apimapper/gateway/essentials.js +35 -0
- package/dist/modules/apimapper/gateway/essentials.js.map +1 -0
- package/dist/modules/apimapper/gateway/test-support.d.ts +17 -0
- package/dist/modules/apimapper/gateway/test-support.js +43 -0
- package/dist/modules/apimapper/gateway/test-support.js.map +1 -0
- package/dist/modules/apimapper/get-skill.d.ts +3 -3
- package/dist/modules/apimapper/get-skill.js +47 -7
- package/dist/modules/apimapper/get-skill.js.map +1 -1
- package/dist/modules/apimapper/graph-builder.js +1 -1
- package/dist/modules/apimapper/graph-builder.js.map +1 -1
- package/dist/modules/apimapper/graph.d.ts +2 -2
- package/dist/modules/apimapper/graph.js +170 -35
- package/dist/modules/apimapper/graph.js.map +1 -1
- package/dist/modules/apimapper/index.d.ts +17 -1
- package/dist/modules/apimapper/index.js +68 -17
- package/dist/modules/apimapper/index.js.map +1 -1
- package/dist/modules/apimapper/inspect.d.ts +3 -2
- package/dist/modules/apimapper/inspect.js +97 -13
- package/dist/modules/apimapper/inspect.js.map +1 -1
- package/dist/modules/apimapper/library.d.ts +2 -2
- package/dist/modules/apimapper/library.js +665 -80
- package/dist/modules/apimapper/library.js.map +1 -1
- package/dist/modules/apimapper/license-format.d.ts +22 -0
- package/dist/modules/apimapper/license-format.js +149 -0
- package/dist/modules/apimapper/license-format.js.map +1 -0
- package/dist/modules/apimapper/license.d.ts +16 -2
- package/dist/modules/apimapper/license.js +62 -38
- package/dist/modules/apimapper/license.js.map +1 -1
- package/dist/modules/apimapper/local-sources.d.ts +2 -2
- package/dist/modules/apimapper/local-sources.js +44 -30
- package/dist/modules/apimapper/local-sources.js.map +1 -1
- package/dist/modules/apimapper/misc.d.ts +30 -2
- package/dist/modules/apimapper/misc.js +114 -49
- package/dist/modules/apimapper/misc.js.map +1 -1
- package/dist/modules/apimapper/node-schema.d.ts +52 -0
- package/dist/modules/apimapper/node-schema.js +70 -2
- package/dist/modules/apimapper/node-schema.js.map +1 -1
- package/dist/modules/apimapper/normalizers.d.ts +1 -0
- package/dist/modules/apimapper/normalizers.js +51 -0
- package/dist/modules/apimapper/normalizers.js.map +1 -1
- package/dist/modules/apimapper/onboarding.d.ts +78 -3
- package/dist/modules/apimapper/onboarding.js +428 -26
- package/dist/modules/apimapper/onboarding.js.map +1 -1
- package/dist/modules/apimapper/read-cache.d.ts +31 -2
- package/dist/modules/apimapper/read-cache.js +20 -6
- package/dist/modules/apimapper/read-cache.js.map +1 -1
- package/dist/modules/apimapper/render/_shared.d.ts +24 -0
- package/dist/modules/apimapper/render/_shared.js +84 -0
- package/dist/modules/apimapper/render/_shared.js.map +1 -0
- package/dist/modules/apimapper/render/dag.d.ts +18 -0
- package/dist/modules/apimapper/render/dag.js +70 -0
- package/dist/modules/apimapper/render/dag.js.map +1 -0
- package/dist/modules/apimapper/render/index.d.ts +2 -0
- package/dist/modules/apimapper/render/index.js +112 -0
- package/dist/modules/apimapper/render/index.js.map +1 -0
- package/dist/modules/apimapper/render/renderers/chart-bar.d.ts +2 -0
- package/dist/modules/apimapper/render/renderers/chart-bar.js +70 -0
- package/dist/modules/apimapper/render/renderers/chart-bar.js.map +1 -0
- package/dist/modules/apimapper/render/renderers/chart-line.d.ts +2 -0
- package/dist/modules/apimapper/render/renderers/chart-line.js +71 -0
- package/dist/modules/apimapper/render/renderers/chart-line.js.map +1 -0
- package/dist/modules/apimapper/render/renderers/diff.d.ts +2 -0
- package/dist/modules/apimapper/render/renderers/diff.js +154 -0
- package/dist/modules/apimapper/render/renderers/diff.js.map +1 -0
- package/dist/modules/apimapper/render/renderers/flow-diagram.d.ts +1 -0
- package/dist/modules/apimapper/render/renderers/flow-diagram.js +180 -0
- package/dist/modules/apimapper/render/renderers/flow-diagram.js.map +1 -0
- package/dist/modules/apimapper/render/renderers/json-tree.d.ts +2 -0
- package/dist/modules/apimapper/render/renderers/json-tree.js +87 -0
- package/dist/modules/apimapper/render/renderers/json-tree.js.map +1 -0
- package/dist/modules/apimapper/render/renderers/schema-diagram.d.ts +2 -0
- package/dist/modules/apimapper/render/renderers/schema-diagram.js +83 -0
- package/dist/modules/apimapper/render/renderers/schema-diagram.js.map +1 -0
- package/dist/modules/apimapper/render/renderers/table.d.ts +2 -0
- package/dist/modules/apimapper/render/renderers/table.js +75 -0
- package/dist/modules/apimapper/render/renderers/table.js.map +1 -0
- package/dist/modules/apimapper/render/schemas.d.ts +23 -0
- package/dist/modules/apimapper/render/schemas.js +56 -0
- package/dist/modules/apimapper/render/schemas.js.map +1 -0
- package/dist/modules/apimapper/render/secret-masking.d.ts +5 -0
- package/dist/modules/apimapper/render/secret-masking.js +51 -0
- package/dist/modules/apimapper/render/secret-masking.js.map +1 -0
- package/dist/modules/apimapper/render/sidecar.d.ts +21 -0
- package/dist/modules/apimapper/render/sidecar.js +66 -0
- package/dist/modules/apimapper/render/sidecar.js.map +1 -0
- package/dist/modules/apimapper/render/token-cap.d.ts +21 -0
- package/dist/modules/apimapper/render/token-cap.js +57 -0
- package/dist/modules/apimapper/render/token-cap.js.map +1 -0
- package/dist/modules/apimapper/schema.d.ts +2 -2
- package/dist/modules/apimapper/schema.js +92 -33
- package/dist/modules/apimapper/schema.js.map +1 -1
- package/dist/modules/apimapper/settings-format.d.ts +23 -0
- package/dist/modules/apimapper/settings-format.js +135 -0
- package/dist/modules/apimapper/settings-format.js.map +1 -0
- package/dist/modules/apimapper/settings.d.ts +2 -2
- package/dist/modules/apimapper/settings.js +100 -42
- package/dist/modules/apimapper/settings.js.map +1 -1
- package/dist/modules/apimapper/sites-tools.d.ts +29 -0
- package/dist/modules/apimapper/sites-tools.js +165 -0
- package/dist/modules/apimapper/sites-tools.js.map +1 -0
- package/dist/modules/apimapper/skill-resources.d.ts +2 -2
- package/dist/modules/apimapper/skill-resources.js.map +1 -1
- package/dist/modules/apimapper/token-baseline.harness.d.ts +91 -0
- package/dist/modules/apimapper/token-baseline.harness.js +291 -0
- package/dist/modules/apimapper/token-baseline.harness.js.map +1 -0
- package/dist/modules/apimapper/tool-result.d.ts +46 -0
- package/dist/modules/apimapper/tool-result.js +63 -0
- package/dist/modules/apimapper/tool-result.js.map +1 -0
- package/dist/modules/apimapper/toolslist-size.d.ts +56 -0
- package/dist/modules/apimapper/toolslist-size.js +192 -0
- package/dist/modules/apimapper/toolslist-size.js.map +1 -0
- package/dist/modules/apimapper/types.d.ts +44 -8
- package/dist/modules/apimapper/types.js +26 -1
- package/dist/modules/apimapper/types.js.map +1 -1
- package/dist/modules/apimapper/use-profile.d.ts +21 -0
- package/dist/modules/apimapper/use-profile.js +56 -2
- package/dist/modules/apimapper/use-profile.js.map +1 -1
- package/dist/modules/apimapper/whitelist-drift.d.ts +85 -0
- package/dist/modules/apimapper/whitelist-drift.js +360 -0
- package/dist/modules/apimapper/whitelist-drift.js.map +1 -0
- package/dist/modules/apimapper/workflows.d.ts +2 -2
- package/dist/modules/apimapper/workflows.js +202 -20
- package/dist/modules/apimapper/workflows.js.map +1 -1
- package/dist/modules/apimapper/yootheme-binding.d.ts +35 -0
- package/dist/modules/apimapper/yootheme-binding.js +186 -0
- package/dist/modules/apimapper/yootheme-binding.js.map +1 -0
- package/dist/platform/index.d.ts +56 -0
- package/dist/platform/index.js +195 -7
- package/dist/platform/index.js.map +1 -1
- package/dist/setup/detect-clients.d.ts +40 -1
- package/dist/setup/detect-clients.js +148 -1
- package/dist/setup/detect-clients.js.map +1 -1
- package/dist/setup/probe-handshake.js +40 -7
- package/dist/setup/probe-handshake.js.map +1 -1
- package/dist/setup/remove-config.d.ts +8 -0
- package/dist/setup/remove-config.js +145 -0
- package/dist/setup/remove-config.js.map +1 -0
- package/dist/setup/uninstall.d.ts +34 -0
- package/dist/setup/uninstall.js +147 -0
- package/dist/setup/uninstall.js.map +1 -0
- package/dist/setup-cli.d.ts +60 -0
- package/dist/setup-cli.js +155 -5
- package/dist/setup-cli.js.map +1 -1
- package/dist/sites/loader.d.ts +41 -0
- package/dist/sites/loader.js +119 -0
- package/dist/sites/loader.js.map +1 -0
- package/dist/sites/schema.d.ts +69 -0
- package/dist/sites/schema.js +71 -0
- package/dist/sites/schema.js.map +1 -0
- package/dist/sites/secret-resolver.d.ts +47 -0
- package/dist/sites/secret-resolver.js +150 -0
- package/dist/sites/secret-resolver.js.map +1 -0
- package/dist/skill-instructions.d.ts +1 -1
- package/dist/skill-instructions.js +5 -0
- package/dist/skill-instructions.js.map +1 -1
- package/dist/transports/stdio.js +4 -4
- package/dist/transports/stdio.js.map +1 -1
- package/dist/uninstall-skill.d.ts +27 -0
- package/dist/uninstall-skill.js +89 -0
- package/dist/uninstall-skill.js.map +1 -0
- package/docs/architecture.md +22 -22
- package/docs/customgraph-internal-migration.md +4 -4
- package/docs/security.md +2 -21
- package/docs/tools.md +40 -12
- package/manifest.json +77 -70
- package/package.json +68 -60
- package/skills/apimapper/SKILL.md +53 -7
- package/skills/apimapper/reference/conditional-style-multi-items.md +114 -0
- package/skills/apimapper/reference/jmespath-pitfalls.md +108 -0
- package/skills/apimapper/reference/joomla.md +1 -1
- package/skills/apimapper/reference/library-template-discovery.md +65 -0
- package/skills/apimapper/reference/merge-two-sources-on-key.md +99 -0
- package/skills/apimapper/reference/render.md +132 -0
- package/skills/apimapper/reference/troubleshooting.md +21 -1
- package/skills/apimapper/reference/yootheme.md +1 -1
- package/dist/auth/oauth-provider.d.ts +0 -68
- package/dist/auth/oauth-provider.js +0 -232
- package/dist/auth/oauth-provider.js.map +0 -1
- package/dist/server-http.d.ts +0 -22
- package/dist/server-http.js +0 -159
- package/dist/server-http.js.map +0 -1
- package/dist/transports/http.d.ts +0 -29
- package/dist/transports/http.js +0 -267
- package/dist/transports/http.js.map +0 -1
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { formatResult, readOnly } from "@getimo/mcp-toolkit";
|
|
3
|
-
import { request
|
|
3
|
+
import { request } from "./client.js";
|
|
4
|
+
import { restErrorResult } from "./tool-result.js";
|
|
4
5
|
import { encodePathPreservingSlashes } from "./normalizers.js";
|
|
6
|
+
// rc.13 Welle 3 (2026-05-20) — error branches upgraded to the toolkit's
|
|
7
|
+
// errorResult builder. Object-passthrough judgment (W3.1 note 2): every
|
|
8
|
+
// local-source SUCCESS payload is arbitrary-shape data with NO stable column
|
|
9
|
+
// or field schema — local_source_types returns provider-defined type
|
|
10
|
+
// descriptors, local_source_query returns WP posts / Joomla articles with
|
|
11
|
+
// per-content-type field sets, local_source_schema / local_source_filter_options
|
|
12
|
+
// return free-form schema/option objects. Forcing any onto tableResult /
|
|
13
|
+
// detailResult would mean inventing a column/field map that drifts the moment
|
|
14
|
+
// a content type adds a field. So all four KEEP formatResult on success; only
|
|
15
|
+
// the ERROR branch upgrades to errorResult (display="error", isError:true).
|
|
5
16
|
export function registerLocalSourceTools(server) {
|
|
6
17
|
// ── apimapper_local_source_types ───────────────────────────────────
|
|
7
18
|
server.registerTool("apimapper_local_source_types", {
|
|
@@ -10,11 +21,11 @@ export function registerLocalSourceTools(server) {
|
|
|
10
21
|
"Local sources don't need a connection — they query WP/Joomla internal data." +
|
|
11
22
|
"\n\nExample:\n apimapper_local_source_types({})",
|
|
12
23
|
inputSchema: {},
|
|
13
|
-
annotations: readOnly(),
|
|
24
|
+
annotations: readOnly({ title: "List Local Source Types", openWorld: true }),
|
|
14
25
|
}, async () => {
|
|
15
26
|
const r = await request("/local-sources/types");
|
|
16
27
|
if (!r.success) {
|
|
17
|
-
return
|
|
28
|
+
return restErrorResult(r, {}, { message: "local source types failed" });
|
|
18
29
|
}
|
|
19
30
|
const types = Array.isArray(r.data?.types) ? r.data.types : [];
|
|
20
31
|
return formatResult({ count: types.length, types }, false, { maxChars: 4000 });
|
|
@@ -34,11 +45,11 @@ export function registerLocalSourceTools(server) {
|
|
|
34
45
|
.regex(/^[a-z]+\/[a-z0-9_-]+$/, "Must be in the form 'platform/type', e.g., 'wordpress/posts'")
|
|
35
46
|
.describe('Local source type id in "platform/type" form (e.g., "wordpress/posts", "joomla/articles"). Use apimapper_local_source_types.'),
|
|
36
47
|
},
|
|
37
|
-
annotations: readOnly(),
|
|
48
|
+
annotations: readOnly({ title: "Get Local Source Schema", openWorld: true }),
|
|
38
49
|
}, async ({ type_id }) => {
|
|
39
50
|
const r = await request(`/local-sources/schema/${encodePathPreservingSlashes(type_id)}`);
|
|
40
51
|
if (!r.success) {
|
|
41
|
-
return
|
|
52
|
+
return restErrorResult(r, { type_id }, { message: "local source schema failed" });
|
|
42
53
|
}
|
|
43
54
|
return formatResult(r.data ?? {}, false, { maxChars: 4000 });
|
|
44
55
|
});
|
|
@@ -57,26 +68,25 @@ export function registerLocalSourceTools(server) {
|
|
|
57
68
|
.regex(/^[a-z_]+$/, "Must be lowercase with underscores")
|
|
58
69
|
.describe('Filter field name (e.g., "category", "tag", "author")'),
|
|
59
70
|
},
|
|
60
|
-
annotations: readOnly(),
|
|
71
|
+
annotations: readOnly({ title: "Get Local Source Filter Options", openWorld: true }),
|
|
61
72
|
}, async ({ type_id, filter_name }) => {
|
|
62
73
|
const r = await request(`/local-sources/filter-options/${encodePathPreservingSlashes(type_id)}/${encodeURIComponent(filter_name)}`);
|
|
63
74
|
if (!r.success) {
|
|
64
|
-
return
|
|
65
|
-
error: r.error,
|
|
66
|
-
status: r.status,
|
|
67
|
-
errorCode: r.errorCode,
|
|
68
|
-
context: { type_id, filter_name },
|
|
69
|
-
hint: hintFor(r.errorCode),
|
|
70
|
-
}, true);
|
|
75
|
+
return restErrorResult(r, { type_id, filter_name }, { message: "local source filter options failed" });
|
|
71
76
|
}
|
|
72
77
|
return formatResult(r.data ?? {}, false, { maxChars: 4000 });
|
|
73
78
|
});
|
|
74
79
|
// ── apimapper_local_source_query ───────────────────────────────────
|
|
75
80
|
server.registerTool("apimapper_local_source_query", {
|
|
76
81
|
title: "Query Local Source Data",
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
82
|
+
// rc.10 A7 (2026-05-19) — anti-thrash for AI agents: the `offset`
|
|
83
|
+
// parameter exists for UI pagers; AI agents should prefer a larger
|
|
84
|
+
// `limit` over offset-loops because most installs fit in one page.
|
|
85
|
+
description: "Execute a query against a local source (WP posts/pages, Joomla articles, etc.) and return " +
|
|
86
|
+
"the matching items in one call. Body uses camelCase `contentType` (FlowExecutor node-data " +
|
|
87
|
+
"convention). For AI agents: prefer a higher `limit` (up to 500) over iterating with " +
|
|
88
|
+
"`offset` — most installs fit comfortably in a single page." +
|
|
89
|
+
"\n\nExample:\n apimapper_local_source_query({ contentType: 'wordpress/posts', limit: 100 })",
|
|
80
90
|
inputSchema: {
|
|
81
91
|
content_type: z
|
|
82
92
|
.string()
|
|
@@ -86,40 +96,44 @@ export function registerLocalSourceTools(server) {
|
|
|
86
96
|
.record(z.string(), z.unknown())
|
|
87
97
|
.optional()
|
|
88
98
|
.describe('Filter values (e.g., {"category":"news","status":"publish"})'),
|
|
89
|
-
limit: z.number().min(1).max(500).default(50).describe("Max items (1-500)"),
|
|
90
|
-
offset: z.number().min(0).default(0).describe("Offset for pagination"),
|
|
99
|
+
limit: z.number().min(1).max(500).default(50).describe("Max items (1-500). Prefer a single larger limit over offset-iteration — most installs fit in one page."),
|
|
100
|
+
offset: z.number().min(0).default(0).describe("Offset for pagination. Intended for UI pagers; AI agents should prefer a larger `limit` instead of offset-loops because the data set is bounded and a single call returns the result."),
|
|
91
101
|
orderby: z.string().optional().describe('Order field (e.g., "date","title")'),
|
|
92
102
|
order: z.enum(["asc", "desc"]).default("desc").describe("Order direction"),
|
|
93
103
|
},
|
|
94
|
-
annotations: readOnly(),
|
|
104
|
+
annotations: readOnly({ title: "Query Local Source", openWorld: true }),
|
|
95
105
|
}, async ({ content_type, filters, limit, offset, orderby, order }) => {
|
|
106
|
+
// Wave-16 #88 — wire-key alignment with ContentQuery::fromNodeData, which
|
|
107
|
+
// reads `sort` (the field) + `sortDirection` (asc/desc). The tool
|
|
108
|
+
// previously sent `orderby`/`order`, which PHP silently ignored — so the
|
|
109
|
+
// advertised ordering never took effect. Map the zod inputs to the wire
|
|
110
|
+
// keys PHP actually consumes so sorting works.
|
|
96
111
|
const body = {
|
|
97
112
|
contentType: content_type, // camelCase wire-format key
|
|
98
113
|
limit,
|
|
99
114
|
offset,
|
|
100
|
-
order,
|
|
115
|
+
sortDirection: order,
|
|
101
116
|
};
|
|
102
117
|
if (filters)
|
|
103
118
|
body.filters = filters;
|
|
104
119
|
if (orderby)
|
|
105
|
-
body.
|
|
120
|
+
body.sort = orderby;
|
|
106
121
|
const r = await request("/local-sources/query", { method: "POST", body: JSON.stringify(body) });
|
|
107
122
|
if (!r.success) {
|
|
108
123
|
// F-A5-02: on 403 feature-gate response the PHP body carries
|
|
109
|
-
// `error_code` + `upgrade` hints — surface them to the agent
|
|
110
|
-
// can route the user to the upgrade flow
|
|
124
|
+
// `error_code` + `upgrade` hints — surface them to the agent (in the
|
|
125
|
+
// errorResult details) so it can route the user to the upgrade flow
|
|
126
|
+
// instead of a generic error.
|
|
111
127
|
const dataObj = r.data && typeof r.data === "object"
|
|
112
128
|
? r.data
|
|
113
129
|
: {};
|
|
114
|
-
return
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
130
|
+
return restErrorResult(r, {
|
|
131
|
+
content_type,
|
|
132
|
+
limit,
|
|
133
|
+
offset,
|
|
118
134
|
error_code: typeof dataObj.error_code === "string" ? dataObj.error_code : undefined,
|
|
119
135
|
upgrade: dataObj.upgrade,
|
|
120
|
-
|
|
121
|
-
hint: hintFor(r.errorCode),
|
|
122
|
-
}, true);
|
|
136
|
+
}, { message: "local source query failed" });
|
|
123
137
|
}
|
|
124
138
|
const items = Array.isArray(r.data?.items) ? r.data.items : [];
|
|
125
139
|
return formatResult({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-sources.js","sourceRoot":"","sources":["../../../src/modules/apimapper/local-sources.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"local-sources.js","sourceRoot":"","sources":["../../../src/modules/apimapper/local-sources.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,30 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare
|
|
1
|
+
import type { ToolRegistrar } from "./gateway/capturing-server.js";
|
|
2
|
+
export declare const UUID4_REGEX: RegExp;
|
|
3
|
+
/**
|
|
4
|
+
* A1-P3-2: Wire-shape for the `POST /feedback` REST response.
|
|
5
|
+
*
|
|
6
|
+
* Mirror of the PHP `@phpstan-type FeedbackResponse` aliases declared in:
|
|
7
|
+
* - WP: src/modules/admin-wordpress/.../FeedbackController.php
|
|
8
|
+
* - Joomla: src/modules/admin-joomla/.../FeedbackAjaxHandler.php
|
|
9
|
+
*
|
|
10
|
+
* All fields except `success` are optional because the PHP layer emits
|
|
11
|
+
* different subsets depending on the path:
|
|
12
|
+
* - 500 webhook-not-configured → `{ success: false, error }`
|
|
13
|
+
* - 400 missing-required-field → `{ success: false, error }`
|
|
14
|
+
* - 200 idempotency-duplicate → `{ success: true, queued, ticket_id, duplicate, idempotency_key }`
|
|
15
|
+
* - 200 fresh-submission → `{ success: true, queued?, ticket_id?, idempotency_key? }`
|
|
16
|
+
*
|
|
17
|
+
* Hoisted out of the inline `request<{...}>(...)` call-site (was at
|
|
18
|
+
* misc.ts:245-249) so the named interface is the single TS counterpart
|
|
19
|
+
* to the PHP @phpstan-type — touching one side without the other now
|
|
20
|
+
* shows up immediately as a cross-stack drift.
|
|
21
|
+
*/
|
|
22
|
+
export interface FeedbackSubmitResponse {
|
|
23
|
+
success: boolean;
|
|
24
|
+
queued?: boolean;
|
|
25
|
+
ticket_id?: string | null;
|
|
26
|
+
duplicate?: boolean;
|
|
27
|
+
idempotency_key?: string;
|
|
28
|
+
error?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function registerMiscTools(server: ToolRegistrar): void;
|
|
@@ -1,6 +1,37 @@
|
|
|
1
|
+
// src/modules/apimapper/misc.ts — Releases + Brandfetch + Feedback
|
|
2
|
+
//
|
|
3
|
+
// REST surface: GET /releases, POST /releases/download, GET /brandfetch/{domain},
|
|
4
|
+
// POST /feedback.
|
|
5
|
+
// Domain: tail-end of the plugin surface — release listing + download URL,
|
|
6
|
+
// brand SVG proxy, and customer-feedback submission (proxied to Discord webhook).
|
|
7
|
+
// `feedback_submit` uses `unwrapInnerSuccess` because the queue can refuse
|
|
8
|
+
// (rate limit, mis-config) with 200+{success:false}.
|
|
9
|
+
import { randomUUID } from "node:crypto";
|
|
1
10
|
import { z } from "zod";
|
|
2
|
-
import { formatResult,
|
|
11
|
+
import { formatResult, tableResult, detailResult, errorResult, readOnly, mutating, } from "@getimo/mcp-toolkit";
|
|
3
12
|
import { request, hintFor } from "./client.js";
|
|
13
|
+
import { restErrorResult } from "./tool-result.js";
|
|
14
|
+
// rc.13 Welle 3 (2026-05-20) — heavy read tools migrated to the toolkit's
|
|
15
|
+
// structuredContent builders. Migration is purely additive (text `content`
|
|
16
|
+
// block preserved, `_meta.ui` added).
|
|
17
|
+
// - release_list → tableResult (display="data-table").
|
|
18
|
+
// - brandfetch → detailResult (display="detail") — the flat {domain,
|
|
19
|
+
// has_svg, svg_size, hash} object renders as a grouped key-value detail.
|
|
20
|
+
// - release_download / feedback_submit keep their formatResult success
|
|
21
|
+
// payloads (a signed URL / a small confirmation); error branches →
|
|
22
|
+
// errorResult.
|
|
23
|
+
// - all error returns → errorResult (display="error", isError:true).
|
|
24
|
+
// ── release_list table shape ──────────────────────────────────────────
|
|
25
|
+
const RELEASE_COLUMNS = [
|
|
26
|
+
{ key: "version", label: "VERSION", width: 12 },
|
|
27
|
+
{ key: "date", label: "DATE", width: 22 },
|
|
28
|
+
{ key: "breaking", label: "BREAKING", width: 8 },
|
|
29
|
+
{ key: "is_current", label: "CURRENT", width: 7 },
|
|
30
|
+
];
|
|
31
|
+
// RFC 4122 UUID v4 regex (lowercase + uppercase tolerated).
|
|
32
|
+
// Exported so tests can pin both request-body and response-payload formats
|
|
33
|
+
// against the same canonical pattern (single source of truth).
|
|
34
|
+
export const UUID4_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
4
35
|
export function registerMiscTools(server) {
|
|
5
36
|
// ── apimapper_release_list ─────────────────────────────────────────
|
|
6
37
|
// F-A6-03: PHP ReleaseHandler returns `{success, current_version, releases}`.
|
|
@@ -14,33 +45,24 @@ export function registerMiscTools(server) {
|
|
|
14
45
|
inputSchema: {
|
|
15
46
|
limit: z.number().min(1).max(50).default(10).describe("Max items (1-50)"),
|
|
16
47
|
},
|
|
17
|
-
annotations: readOnly(),
|
|
48
|
+
annotations: readOnly({ title: "List Releases", openWorld: true }),
|
|
18
49
|
}, async ({ limit }) => {
|
|
19
50
|
const r = await request("/releases");
|
|
20
51
|
if (!r.success) {
|
|
21
|
-
return
|
|
22
|
-
error: r.error,
|
|
23
|
-
status: r.status,
|
|
24
|
-
errorCode: r.errorCode,
|
|
25
|
-
context: { limit },
|
|
26
|
-
hint: hintFor(r.errorCode),
|
|
27
|
-
}, true);
|
|
52
|
+
return restErrorResult(r, { limit }, { message: "release list failed" });
|
|
28
53
|
}
|
|
29
54
|
const allReleases = Array.isArray(r.data?.releases) ? r.data.releases : [];
|
|
30
55
|
const releases = allReleases.slice(0, limit);
|
|
31
56
|
const currentVersion = r.data?.current_version ?? "?";
|
|
32
|
-
|
|
57
|
+
// W3.1 — tableResult: ASCII table for the LLM + typed DataTable payload
|
|
58
|
+
// for the Rich Card. IA-10: the footer carries the next-step guidance.
|
|
59
|
+
return tableResult(releases.map((rel) => ({
|
|
33
60
|
version: rel.version ?? "?",
|
|
34
61
|
date: rel.date ?? "—",
|
|
35
62
|
breaking: rel.has_breaking_changes ? "✓" : "✗",
|
|
36
63
|
is_current: rel.version === currentVersion ? "✓" : "",
|
|
37
64
|
})), {
|
|
38
|
-
columns:
|
|
39
|
-
{ key: "version", label: "VERSION", width: 12 },
|
|
40
|
-
{ key: "date", label: "DATE", width: 22 },
|
|
41
|
-
{ key: "breaking", label: "BREAKING", width: 8 },
|
|
42
|
-
{ key: "is_current", label: "CURRENT", width: 7 },
|
|
43
|
-
],
|
|
65
|
+
columns: RELEASE_COLUMNS,
|
|
44
66
|
header: (n) => `${n} releases (current=${currentVersion})`,
|
|
45
67
|
footer: "Use apimapper_release_download to fetch a download URL.",
|
|
46
68
|
});
|
|
@@ -60,32 +82,28 @@ export function registerMiscTools(server) {
|
|
|
60
82
|
.describe('Release version (e.g., "2.0.7")'),
|
|
61
83
|
product: z.enum(["wordpress", "joomla"]).describe("Product variant"),
|
|
62
84
|
},
|
|
63
|
-
|
|
85
|
+
// W1.26 (IA-1): the description already states this is read-only server-side
|
|
86
|
+
// (no state change — generates a signed URL). The annotation now matches.
|
|
87
|
+
annotations: readOnly({ title: "Get Release Download URL", openWorld: true }),
|
|
64
88
|
}, async ({ version, product }) => {
|
|
65
89
|
const r = await request("/releases/download", {
|
|
66
90
|
method: "POST",
|
|
67
91
|
body: JSON.stringify({ version, product }),
|
|
68
92
|
});
|
|
69
93
|
if (!r.success) {
|
|
70
|
-
return
|
|
71
|
-
error: r.error,
|
|
72
|
-
status: r.status,
|
|
73
|
-
errorCode: r.errorCode,
|
|
74
|
-
context: { version, product },
|
|
75
|
-
hint: hintFor(r.errorCode),
|
|
76
|
-
}, true);
|
|
94
|
+
return restErrorResult(r, { version, product }, { message: "release download failed" });
|
|
77
95
|
}
|
|
78
96
|
// Defensive read: PHP currently returns flat `{success, download_url}`
|
|
79
97
|
// (post Wave 1B), but older shape wrapped under `data.download_url`.
|
|
80
98
|
// Tolerate either.
|
|
81
99
|
const downloadUrl = r.data?.data?.download_url ?? r.data?.download_url;
|
|
82
100
|
if (!downloadUrl) {
|
|
83
|
-
return
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
101
|
+
return errorResult({
|
|
102
|
+
message: "no download URL returned",
|
|
103
|
+
code: r.status ? String(r.status) : undefined,
|
|
104
|
+
suggestion: "Server returned 200 but no download_url field. Verify version+product combination.",
|
|
105
|
+
details: { version, product },
|
|
106
|
+
});
|
|
89
107
|
}
|
|
90
108
|
return formatResult({
|
|
91
109
|
download_url: downloadUrl,
|
|
@@ -106,22 +124,39 @@ export function registerMiscTools(server) {
|
|
|
106
124
|
inputSchema: {
|
|
107
125
|
domain: z.string().describe('Domain (e.g., "calendly.com", "google.com")'),
|
|
108
126
|
},
|
|
109
|
-
annotations: readOnly(),
|
|
127
|
+
annotations: readOnly({ title: "Brand Fetch", openWorld: true }),
|
|
110
128
|
}, async ({ domain }) => {
|
|
111
129
|
const r = await request(`/brandfetch/${encodeURIComponent(domain)}`);
|
|
112
130
|
if (!r.success) {
|
|
113
|
-
return
|
|
131
|
+
return restErrorResult(r, { domain }, { message: "brandfetch failed" });
|
|
114
132
|
}
|
|
115
133
|
// Defensive read: tolerate both flat (Wave 1B) and wrapped (legacy) shapes.
|
|
116
134
|
const svg = r.data?.data?.svg ?? r.data?.svg;
|
|
117
135
|
const hash = r.data?.data?.hash ?? r.data?.hash;
|
|
118
136
|
const normalisedDomain = r.data?.data?.domain ?? r.data?.domain ?? domain;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
137
|
+
const hasSvg = Boolean(svg);
|
|
138
|
+
// W3.1 — detailResult: the flat {domain, has_svg, svg_size, hash} object
|
|
139
|
+
// renders as a grouped key-value detail for the Rich Card.
|
|
140
|
+
const entries = [
|
|
141
|
+
{ key: "domain", label: "Domain", value: normalisedDomain, format: "text" },
|
|
142
|
+
{ key: "has_svg", label: "Has SVG", value: hasSvg, format: "boolean" },
|
|
143
|
+
{
|
|
144
|
+
key: "svg_size",
|
|
145
|
+
label: "SVG size (bytes)",
|
|
146
|
+
value: svg ? svg.length : 0,
|
|
147
|
+
},
|
|
148
|
+
];
|
|
149
|
+
if (hash) {
|
|
150
|
+
entries.push({ key: "hash", label: "SRI hash", value: hash, format: "code" });
|
|
151
|
+
}
|
|
152
|
+
return detailResult({
|
|
153
|
+
title: `Brand: ${normalisedDomain}`,
|
|
154
|
+
subtitle: hasSvg ? "SVG logo available" : "no SVG logo",
|
|
155
|
+
badge: hasSvg
|
|
156
|
+
? { text: "svg", variant: "success" }
|
|
157
|
+
: { text: "no svg", variant: "secondary" },
|
|
158
|
+
groups: [{ label: "Logo", entries }],
|
|
159
|
+
});
|
|
125
160
|
});
|
|
126
161
|
// ── apimapper_feedback_submit ──────────────────────────────────────
|
|
127
162
|
// F-A6-13: PHP FeedbackController accepts `type`, `message`, and forwards
|
|
@@ -140,27 +175,57 @@ export function registerMiscTools(server) {
|
|
|
140
175
|
email: z.string().email().optional().describe("Reply email (optional)"),
|
|
141
176
|
attachments: z
|
|
142
177
|
.array(z.string().url())
|
|
178
|
+
.max(5)
|
|
143
179
|
.optional()
|
|
144
|
-
.describe("Optional attachment URLs (e.g., screenshots already uploaded elsewhere)"),
|
|
180
|
+
.describe("Optional attachment URLs (e.g., screenshots already uploaded elsewhere). Max 5."),
|
|
181
|
+
idempotency_key: z
|
|
182
|
+
.string()
|
|
183
|
+
.regex(UUID4_REGEX, "idempotency_key must be a UUID v4")
|
|
184
|
+
.optional()
|
|
185
|
+
.describe("Optional UUID4 idempotency key to prevent duplicate submissions on retry. " +
|
|
186
|
+
"If omitted, the MCP auto-generates one. Server dedupes within 15 minutes."),
|
|
145
187
|
},
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
188
|
+
// W1.26 (IA-1): feedback_submit is idempotent — W1.20 added UUID4 dedupe on
|
|
189
|
+
// the server side (15-min window). Re-submitting the same idempotency_key
|
|
190
|
+
// returns the existing record. mutating() captures "writes + idempotent";
|
|
191
|
+
// creating() implied a new row per call which is no longer true.
|
|
192
|
+
annotations: mutating({ title: "Submit Feedback", openWorld: true }),
|
|
193
|
+
}, async ({ type, subject, message, email, attachments, idempotency_key }) => {
|
|
194
|
+
const key = idempotency_key ?? randomUUID();
|
|
195
|
+
// A1-P3-2: named `FeedbackSubmitResponse` interface — hoisted so it
|
|
196
|
+
// mirrors the PHP @phpstan-type FeedbackResponse alias on both
|
|
197
|
+
// FeedbackController (WP) and FeedbackAjaxHandler (Joomla).
|
|
198
|
+
const r = await request("/feedback", {
|
|
199
|
+
method: "POST",
|
|
200
|
+
body: JSON.stringify({
|
|
201
|
+
type,
|
|
202
|
+
subject,
|
|
203
|
+
message,
|
|
204
|
+
email,
|
|
205
|
+
attachments,
|
|
206
|
+
idempotency_key: key,
|
|
207
|
+
}),
|
|
208
|
+
}, { unwrapInnerSuccess: true });
|
|
149
209
|
if (!r.success) {
|
|
150
|
-
return
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
210
|
+
return restErrorResult(r, {
|
|
211
|
+
type,
|
|
212
|
+
subject_len: subject.length,
|
|
213
|
+
idempotency_key: key,
|
|
154
214
|
payloadFailed: r.payloadFailed,
|
|
155
|
-
|
|
156
|
-
|
|
215
|
+
}, {
|
|
216
|
+
message: "feedback submission failed",
|
|
217
|
+
// Per-site nuance: 200 + success:false (payloadFailed) → proxy
|
|
218
|
+
// delivery hint; otherwise fall back to the error-code hint.
|
|
219
|
+
suggestion: r.payloadFailed
|
|
157
220
|
? "Server accepted the request but the proxy did not deliver it. Reason in error field."
|
|
158
221
|
: hintFor(r.errorCode),
|
|
159
|
-
}
|
|
222
|
+
});
|
|
160
223
|
}
|
|
161
224
|
// unwrapInnerSuccess already caught success:false, so here success is true.
|
|
162
225
|
return formatResult({
|
|
163
226
|
submitted: true,
|
|
227
|
+
idempotency_key: r.data?.idempotency_key ?? key,
|
|
228
|
+
duplicate: r.data?.duplicate ?? false,
|
|
164
229
|
}, false, { maxChars: 2000 });
|
|
165
230
|
});
|
|
166
231
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"misc.js","sourceRoot":"","sources":["../../../src/modules/apimapper/misc.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"misc.js","sourceRoot":"","sources":["../../../src/modules/apimapper/misc.ts"],"names":[],"mappings":"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"}
|
|
@@ -215,3 +215,55 @@ export declare const nodeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
215
215
|
}, z.core.$loose>;
|
|
216
216
|
}, z.core.$strip>], "type">;
|
|
217
217
|
export type FlowNode = z.infer<typeof nodeSchema>;
|
|
218
|
+
/**
|
|
219
|
+
* Strict edge schema shared by flow_create, graph_preview, and graph_validate.
|
|
220
|
+
*
|
|
221
|
+
* Centralized so the 3 tool registrations have identical shape contracts —
|
|
222
|
+
* preventing silent drift where one site accepts a shape the others reject.
|
|
223
|
+
*
|
|
224
|
+
* Before W1.6 each site used `z.array(z.record(z.string(), z.unknown()))` —
|
|
225
|
+
* arbitrary structures (e.g. `{source: 1, target: null}`) passed validation
|
|
226
|
+
* and then failed at graph-execution with confusing errors.
|
|
227
|
+
*
|
|
228
|
+
* Defense-in-depth: source + target are required non-empty strings;
|
|
229
|
+
* non-string types and empty strings are rejected at the Zod boundary.
|
|
230
|
+
*
|
|
231
|
+
* For merge nodes, targetHandle uses "input-0" / "input-1" convention
|
|
232
|
+
* (zero-indexed by input slot — matches frontend BaseNode.tsx Handle id rendering
|
|
233
|
+
* and the backend DagExecutor tolerant input-slot resolution).
|
|
234
|
+
*/
|
|
235
|
+
export declare const edgeSchema: z.ZodObject<{
|
|
236
|
+
id: z.ZodOptional<z.ZodString>;
|
|
237
|
+
source: z.ZodString;
|
|
238
|
+
target: z.ZodString;
|
|
239
|
+
sourceHandle: z.ZodOptional<z.ZodString>;
|
|
240
|
+
targetHandle: z.ZodOptional<z.ZodString>;
|
|
241
|
+
}, z.core.$strip>;
|
|
242
|
+
export type FlowEdge = z.infer<typeof edgeSchema>;
|
|
243
|
+
/**
|
|
244
|
+
* W1.18 (F-32): case-insensitive substring filter applied in-memory after
|
|
245
|
+
* the upstream list fetch.
|
|
246
|
+
*
|
|
247
|
+
* Shared between `apimapper_flow_list` and `apimapper_connection_list` so
|
|
248
|
+
* the two tools cannot drift on semantics (case-folding, undefined-skip,
|
|
249
|
+
* empty-string behaviour). The min-2-char guard lives on each tool's Zod
|
|
250
|
+
* schema (`z.string().min(2).optional()`) — this helper deliberately does
|
|
251
|
+
* NOT enforce the length here so that direct programmatic callers (e.g.
|
|
252
|
+
* unit tests, internal composers) can still pass a 1-char needle when
|
|
253
|
+
* they really mean it. The wire boundary is the gate; this helper is the
|
|
254
|
+
* pure transform.
|
|
255
|
+
*
|
|
256
|
+
* Contract:
|
|
257
|
+
* - `needle === undefined` → returns the input array unchanged (no filter)
|
|
258
|
+
* - `needle === ""` → returns the input array unchanged (empty
|
|
259
|
+
* haystack-match is meaningless; treat as
|
|
260
|
+
* "no filter applied")
|
|
261
|
+
* - otherwise → returns items whose `name` (lowercased)
|
|
262
|
+
* contains the lowercased needle
|
|
263
|
+
*
|
|
264
|
+
* Generic over `T extends { name?: string }` — accepts both `Flow` and
|
|
265
|
+
* `Connection` shapes without adapter wrappers at the call site.
|
|
266
|
+
*/
|
|
267
|
+
export declare function filterByNameQuery<T extends {
|
|
268
|
+
name?: string;
|
|
269
|
+
}>(items: T[], needle: string | undefined): T[];
|
|
@@ -138,11 +138,11 @@ export const mergeNodeSchema = z
|
|
|
138
138
|
.enum(["concat", "join"])
|
|
139
139
|
.describe("'concat' = stack items from both inputs; 'join' = relational join on key. " +
|
|
140
140
|
"Strategies 'append', 'chronological', etc. are NOT valid here."),
|
|
141
|
-
joinKey: z.string().optional().describe("Field on input-
|
|
141
|
+
joinKey: z.string().optional().describe("Field on input-0 (required if strategy='join')"),
|
|
142
142
|
joinKeyRight: z
|
|
143
143
|
.string()
|
|
144
144
|
.optional()
|
|
145
|
-
.describe("Field on input-
|
|
145
|
+
.describe("Field on input-1 (defaults to joinKey when omitted)"),
|
|
146
146
|
joinType: z
|
|
147
147
|
.enum(["left", "right", "inner", "outer"])
|
|
148
148
|
.optional()
|
|
@@ -215,4 +215,72 @@ export const nodeSchema = z
|
|
|
215
215
|
}),
|
|
216
216
|
])
|
|
217
217
|
.describe("Flow node. Discriminator: `type` ∈ source | local-source | filter | transform | merge | output | output-yootheme | output-shortcode");
|
|
218
|
+
// ── edge ─────────────────────────────────────────────────────────────────
|
|
219
|
+
/**
|
|
220
|
+
* Strict edge schema shared by flow_create, graph_preview, and graph_validate.
|
|
221
|
+
*
|
|
222
|
+
* Centralized so the 3 tool registrations have identical shape contracts —
|
|
223
|
+
* preventing silent drift where one site accepts a shape the others reject.
|
|
224
|
+
*
|
|
225
|
+
* Before W1.6 each site used `z.array(z.record(z.string(), z.unknown()))` —
|
|
226
|
+
* arbitrary structures (e.g. `{source: 1, target: null}`) passed validation
|
|
227
|
+
* and then failed at graph-execution with confusing errors.
|
|
228
|
+
*
|
|
229
|
+
* Defense-in-depth: source + target are required non-empty strings;
|
|
230
|
+
* non-string types and empty strings are rejected at the Zod boundary.
|
|
231
|
+
*
|
|
232
|
+
* For merge nodes, targetHandle uses "input-0" / "input-1" convention
|
|
233
|
+
* (zero-indexed by input slot — matches frontend BaseNode.tsx Handle id rendering
|
|
234
|
+
* and the backend DagExecutor tolerant input-slot resolution).
|
|
235
|
+
*/
|
|
236
|
+
export const edgeSchema = z
|
|
237
|
+
.object({
|
|
238
|
+
id: z.string().min(1).optional().describe("Stable edge identifier (optional)"),
|
|
239
|
+
source: z.string().min(1).describe("Source node id (required, non-empty)"),
|
|
240
|
+
target: z.string().min(1).describe("Target node id (required, non-empty)"),
|
|
241
|
+
sourceHandle: z
|
|
242
|
+
.string()
|
|
243
|
+
.min(1)
|
|
244
|
+
.optional()
|
|
245
|
+
.describe("Source-side handle (e.g., 'out')"),
|
|
246
|
+
targetHandle: z
|
|
247
|
+
.string()
|
|
248
|
+
.min(1)
|
|
249
|
+
.optional()
|
|
250
|
+
.describe('Target-side handle (e.g., "input-0" or "input-1" for merge nodes). ' +
|
|
251
|
+
'Legacy "input-A"/"input-B" still accepted for backward-compat but new ' +
|
|
252
|
+
'flows should use the canonical zero-indexed form.'),
|
|
253
|
+
})
|
|
254
|
+
.describe("Flow edge connecting two nodes. Shape: {id?, source, target, sourceHandle?, targetHandle?}");
|
|
255
|
+
// ── name_query filter helper ─────────────────────────────────────────────
|
|
256
|
+
/**
|
|
257
|
+
* W1.18 (F-32): case-insensitive substring filter applied in-memory after
|
|
258
|
+
* the upstream list fetch.
|
|
259
|
+
*
|
|
260
|
+
* Shared between `apimapper_flow_list` and `apimapper_connection_list` so
|
|
261
|
+
* the two tools cannot drift on semantics (case-folding, undefined-skip,
|
|
262
|
+
* empty-string behaviour). The min-2-char guard lives on each tool's Zod
|
|
263
|
+
* schema (`z.string().min(2).optional()`) — this helper deliberately does
|
|
264
|
+
* NOT enforce the length here so that direct programmatic callers (e.g.
|
|
265
|
+
* unit tests, internal composers) can still pass a 1-char needle when
|
|
266
|
+
* they really mean it. The wire boundary is the gate; this helper is the
|
|
267
|
+
* pure transform.
|
|
268
|
+
*
|
|
269
|
+
* Contract:
|
|
270
|
+
* - `needle === undefined` → returns the input array unchanged (no filter)
|
|
271
|
+
* - `needle === ""` → returns the input array unchanged (empty
|
|
272
|
+
* haystack-match is meaningless; treat as
|
|
273
|
+
* "no filter applied")
|
|
274
|
+
* - otherwise → returns items whose `name` (lowercased)
|
|
275
|
+
* contains the lowercased needle
|
|
276
|
+
*
|
|
277
|
+
* Generic over `T extends { name?: string }` — accepts both `Flow` and
|
|
278
|
+
* `Connection` shapes without adapter wrappers at the call site.
|
|
279
|
+
*/
|
|
280
|
+
export function filterByNameQuery(items, needle) {
|
|
281
|
+
if (!needle)
|
|
282
|
+
return items;
|
|
283
|
+
const lowered = needle.toLowerCase();
|
|
284
|
+
return items.filter((item) => (item.name ?? "").toLowerCase().includes(lowered));
|
|
285
|
+
}
|
|
218
286
|
//# sourceMappingURL=node-schema.js.map
|