@wootsup/mcp 0.1.0 → 0.4.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.
Files changed (208) hide show
  1. package/CHANGELOG.md +157 -83
  2. package/README.md +31 -27
  3. package/SECURITY.md +15 -6
  4. package/dist/auth/keychain.d.ts +27 -1
  5. package/dist/auth/keychain.js +48 -2
  6. package/dist/auth/keychain.js.map +1 -1
  7. package/dist/catalog/build-catalog.d.ts +31 -0
  8. package/dist/catalog/build-catalog.js +68 -0
  9. package/dist/catalog/build-catalog.js.map +1 -0
  10. package/dist/cli-hint.d.ts +22 -0
  11. package/dist/cli-hint.js +55 -0
  12. package/dist/cli-hint.js.map +1 -0
  13. package/dist/index.js +129 -22
  14. package/dist/index.js.map +1 -1
  15. package/dist/install-skill.js +1 -1
  16. package/dist/modules/apimapper/auto-layout.d.ts +21 -0
  17. package/dist/modules/apimapper/auto-layout.js +54 -0
  18. package/dist/modules/apimapper/auto-layout.js.map +1 -0
  19. package/dist/modules/apimapper/cache.js +25 -17
  20. package/dist/modules/apimapper/cache.js.map +1 -1
  21. package/dist/modules/apimapper/client.d.ts +115 -4
  22. package/dist/modules/apimapper/client.js +699 -304
  23. package/dist/modules/apimapper/client.js.map +1 -1
  24. package/dist/modules/apimapper/connections-format.d.ts +31 -1
  25. package/dist/modules/apimapper/connections-format.js +97 -5
  26. package/dist/modules/apimapper/connections-format.js.map +1 -1
  27. package/dist/modules/apimapper/connections.d.ts +9 -7
  28. package/dist/modules/apimapper/connections.js +449 -127
  29. package/dist/modules/apimapper/connections.js.map +1 -1
  30. package/dist/modules/apimapper/credential-sanitizer.d.ts +5 -0
  31. package/dist/modules/apimapper/credential-sanitizer.js +60 -1
  32. package/dist/modules/apimapper/credential-sanitizer.js.map +1 -1
  33. package/dist/modules/apimapper/credentials.js +105 -61
  34. package/dist/modules/apimapper/credentials.js.map +1 -1
  35. package/dist/modules/apimapper/diagnose.js +21 -2
  36. package/dist/modules/apimapper/diagnose.js.map +1 -1
  37. package/dist/modules/apimapper/elicitation.d.ts +29 -0
  38. package/dist/modules/apimapper/elicitation.js +62 -0
  39. package/dist/modules/apimapper/elicitation.js.map +1 -1
  40. package/dist/modules/apimapper/example-extract.d.ts +13 -0
  41. package/dist/modules/apimapper/example-extract.js +111 -0
  42. package/dist/modules/apimapper/example-extract.js.map +1 -0
  43. package/dist/modules/apimapper/filter-operators.d.ts +24 -0
  44. package/dist/modules/apimapper/filter-operators.js +103 -0
  45. package/dist/modules/apimapper/filter-operators.js.map +1 -0
  46. package/dist/modules/apimapper/flows-format.js +92 -22
  47. package/dist/modules/apimapper/flows-format.js.map +1 -1
  48. package/dist/modules/apimapper/flows.d.ts +8 -7
  49. package/dist/modules/apimapper/flows.js +275 -120
  50. package/dist/modules/apimapper/flows.js.map +1 -1
  51. package/dist/modules/apimapper/gateway/advanced-read-tool.d.ts +9 -0
  52. package/dist/modules/apimapper/gateway/advanced-read-tool.js +172 -0
  53. package/dist/modules/apimapper/gateway/advanced-read-tool.js.map +1 -0
  54. package/dist/modules/apimapper/gateway/advanced-tool.js +66 -106
  55. package/dist/modules/apimapper/gateway/advanced-tool.js.map +1 -1
  56. package/dist/modules/apimapper/gateway/collect-module-tools.d.ts +17 -0
  57. package/dist/modules/apimapper/gateway/collect-module-tools.js +44 -0
  58. package/dist/modules/apimapper/gateway/collect-module-tools.js.map +1 -0
  59. package/dist/modules/apimapper/gateway/essentials.d.ts +1 -1
  60. package/dist/modules/apimapper/gateway/essentials.js +21 -2
  61. package/dist/modules/apimapper/gateway/essentials.js.map +1 -1
  62. package/dist/modules/apimapper/gateway/gateway-shared.d.ts +21 -0
  63. package/dist/modules/apimapper/gateway/gateway-shared.js +124 -0
  64. package/dist/modules/apimapper/gateway/gateway-shared.js.map +1 -0
  65. package/dist/modules/apimapper/gateway/test-support.d.ts +1 -17
  66. package/dist/modules/apimapper/gateway/test-support.js +4 -33
  67. package/dist/modules/apimapper/gateway/test-support.js.map +1 -1
  68. package/dist/modules/apimapper/get-skill-cores.d.ts +4 -0
  69. package/dist/modules/apimapper/get-skill-cores.js +220 -0
  70. package/dist/modules/apimapper/get-skill-cores.js.map +1 -0
  71. package/dist/modules/apimapper/get-skill.d.ts +1 -1
  72. package/dist/modules/apimapper/get-skill.js +74 -9
  73. package/dist/modules/apimapper/get-skill.js.map +1 -1
  74. package/dist/modules/apimapper/graph-builder.d.ts +85 -2
  75. package/dist/modules/apimapper/graph-builder.js +151 -15
  76. package/dist/modules/apimapper/graph-builder.js.map +1 -1
  77. package/dist/modules/apimapper/graph.js +152 -48
  78. package/dist/modules/apimapper/graph.js.map +1 -1
  79. package/dist/modules/apimapper/index.js +27 -13
  80. package/dist/modules/apimapper/index.js.map +1 -1
  81. package/dist/modules/apimapper/jmespath-test.d.ts +4 -0
  82. package/dist/modules/apimapper/jmespath-test.js +152 -0
  83. package/dist/modules/apimapper/jmespath-test.js.map +1 -0
  84. package/dist/modules/apimapper/library.js +553 -88
  85. package/dist/modules/apimapper/library.js.map +1 -1
  86. package/dist/modules/apimapper/license.js +12 -36
  87. package/dist/modules/apimapper/license.js.map +1 -1
  88. package/dist/modules/apimapper/list-footer.d.ts +27 -0
  89. package/dist/modules/apimapper/list-footer.js +57 -0
  90. package/dist/modules/apimapper/list-footer.js.map +1 -0
  91. package/dist/modules/apimapper/local-sources.js +100 -57
  92. package/dist/modules/apimapper/local-sources.js.map +1 -1
  93. package/dist/modules/apimapper/mcp-client-identity.d.ts +32 -0
  94. package/dist/modules/apimapper/mcp-client-identity.js +70 -0
  95. package/dist/modules/apimapper/mcp-client-identity.js.map +1 -0
  96. package/dist/modules/apimapper/merge-constants.d.ts +6 -0
  97. package/dist/modules/apimapper/merge-constants.js +26 -0
  98. package/dist/modules/apimapper/merge-constants.js.map +1 -0
  99. package/dist/modules/apimapper/misc.js +13 -27
  100. package/dist/modules/apimapper/misc.js.map +1 -1
  101. package/dist/modules/apimapper/node-schema.d.ts +52 -2
  102. package/dist/modules/apimapper/node-schema.js +95 -4
  103. package/dist/modules/apimapper/node-schema.js.map +1 -1
  104. package/dist/modules/apimapper/onboarding.d.ts +59 -1
  105. package/dist/modules/apimapper/onboarding.js +231 -28
  106. package/dist/modules/apimapper/onboarding.js.map +1 -1
  107. package/dist/modules/apimapper/read-cache.d.ts +16 -3
  108. package/dist/modules/apimapper/read-cache.js +59 -4
  109. package/dist/modules/apimapper/read-cache.js.map +1 -1
  110. package/dist/modules/apimapper/render/index.js +26 -5
  111. package/dist/modules/apimapper/render/index.js.map +1 -1
  112. package/dist/modules/apimapper/resource-id.d.ts +13 -0
  113. package/dist/modules/apimapper/resource-id.js +69 -0
  114. package/dist/modules/apimapper/resource-id.js.map +1 -0
  115. package/dist/modules/apimapper/schema.js +9 -18
  116. package/dist/modules/apimapper/schema.js.map +1 -1
  117. package/dist/modules/apimapper/settings.js +49 -52
  118. package/dist/modules/apimapper/settings.js.map +1 -1
  119. package/dist/modules/apimapper/sites-tools.d.ts +29 -0
  120. package/dist/modules/apimapper/sites-tools.js +165 -0
  121. package/dist/modules/apimapper/sites-tools.js.map +1 -0
  122. package/dist/modules/apimapper/tool-result.d.ts +66 -0
  123. package/dist/modules/apimapper/tool-result.js +125 -0
  124. package/dist/modules/apimapper/tool-result.js.map +1 -0
  125. package/dist/modules/apimapper/toolslist-size.d.ts +12 -11
  126. package/dist/modules/apimapper/toolslist-size.js +34 -21
  127. package/dist/modules/apimapper/toolslist-size.js.map +1 -1
  128. package/dist/modules/apimapper/types.d.ts +34 -0
  129. package/dist/modules/apimapper/types.js +1 -1
  130. package/dist/modules/apimapper/types.js.map +1 -1
  131. package/dist/modules/apimapper/whitelist-drift.d.ts +85 -0
  132. package/dist/modules/apimapper/whitelist-drift.js +375 -0
  133. package/dist/modules/apimapper/whitelist-drift.js.map +1 -0
  134. package/dist/modules/apimapper/workflows.js +302 -58
  135. package/dist/modules/apimapper/workflows.js.map +1 -1
  136. package/dist/modules/apimapper/yootheme-binding.d.ts +35 -0
  137. package/dist/modules/apimapper/yootheme-binding.js +267 -0
  138. package/dist/modules/apimapper/yootheme-binding.js.map +1 -0
  139. package/dist/platform/index.d.ts +56 -0
  140. package/dist/platform/index.js +158 -2
  141. package/dist/platform/index.js.map +1 -1
  142. package/dist/proxy/bridge.d.ts +35 -0
  143. package/dist/proxy/bridge.js +129 -0
  144. package/dist/proxy/bridge.js.map +1 -0
  145. package/dist/proxy/mode.d.ts +9 -0
  146. package/dist/proxy/mode.js +20 -0
  147. package/dist/proxy/mode.js.map +1 -0
  148. package/dist/setup/detect-clients.d.ts +40 -1
  149. package/dist/setup/detect-clients.js +148 -1
  150. package/dist/setup/detect-clients.js.map +1 -1
  151. package/dist/setup/probe-auth.d.ts +51 -0
  152. package/dist/setup/probe-auth.js +141 -0
  153. package/dist/setup/probe-auth.js.map +1 -0
  154. package/dist/setup/probe-handshake.js +40 -7
  155. package/dist/setup/probe-handshake.js.map +1 -1
  156. package/dist/setup/remove-config.d.ts +8 -0
  157. package/dist/setup/remove-config.js +145 -0
  158. package/dist/setup/remove-config.js.map +1 -0
  159. package/dist/setup/uninstall.d.ts +34 -0
  160. package/dist/setup/uninstall.js +147 -0
  161. package/dist/setup/uninstall.js.map +1 -0
  162. package/dist/setup-cli.d.ts +16 -0
  163. package/dist/setup-cli.js +63 -1
  164. package/dist/setup-cli.js.map +1 -1
  165. package/dist/sites/loader.d.ts +48 -0
  166. package/dist/sites/loader.js +134 -0
  167. package/dist/sites/loader.js.map +1 -0
  168. package/dist/sites/schema.d.ts +69 -0
  169. package/dist/sites/schema.js +71 -0
  170. package/dist/sites/schema.js.map +1 -0
  171. package/dist/sites/secret-resolver.d.ts +47 -0
  172. package/dist/sites/secret-resolver.js +150 -0
  173. package/dist/sites/secret-resolver.js.map +1 -0
  174. package/dist/skill-instructions.d.ts +14 -1
  175. package/dist/skill-instructions.js +35 -6
  176. package/dist/skill-instructions.js.map +1 -1
  177. package/dist/transports/stdio.js +4 -4
  178. package/dist/transports/stdio.js.map +1 -1
  179. package/dist/uninstall-skill.d.ts +27 -0
  180. package/dist/uninstall-skill.js +89 -0
  181. package/dist/uninstall-skill.js.map +1 -0
  182. package/docs/architecture.md +21 -21
  183. package/docs/customgraph-internal-migration.md +4 -4
  184. package/docs/security.md +2 -21
  185. package/docs/tools.md +40 -12
  186. package/manifest.json +77 -79
  187. package/package.json +69 -65
  188. package/skills/apimapper/SKILL.md +128 -7
  189. package/skills/apimapper/reference/conditional-style-multi-items.md +114 -0
  190. package/skills/apimapper/reference/dynamize-existing-layout.md +158 -0
  191. package/skills/apimapper/reference/jmespath-cookbook.md +241 -0
  192. package/skills/apimapper/reference/jmespath-pitfalls.md +189 -0
  193. package/skills/apimapper/reference/joomla.md +1 -1
  194. package/skills/apimapper/reference/library-template-discovery.md +65 -0
  195. package/skills/apimapper/reference/merge-two-sources-on-key.md +204 -0
  196. package/skills/apimapper/reference/oauth.md +143 -52
  197. package/skills/apimapper/reference/troubleshooting.md +22 -2
  198. package/skills/apimapper/reference/yootheme-source-to-builder-handoff.md +348 -0
  199. package/skills/apimapper/reference/yootheme.md +75 -44
  200. package/dist/auth/oauth-provider.d.ts +0 -68
  201. package/dist/auth/oauth-provider.js +0 -232
  202. package/dist/auth/oauth-provider.js.map +0 -1
  203. package/dist/server-http.d.ts +0 -22
  204. package/dist/server-http.js +0 -159
  205. package/dist/server-http.js.map +0 -1
  206. package/dist/transports/http.d.ts +0 -29
  207. package/dist/transports/http.js +0 -267
  208. package/dist/transports/http.js.map +0 -1
@@ -0,0 +1,85 @@
1
+ /** How a tool's request body relates to the PHP route. */
2
+ export type ToolBodyKind = "structured" | "envelope";
3
+ /** One body-sending tool's route binding. */
4
+ export interface ToolWireBinding {
5
+ /** HTTP method + normalised path, e.g. "POST /connections". Joins the manifest. */
6
+ route: string;
7
+ /** The literal wire body keys the tool sends (envelope tools list their wrapper key). */
8
+ bodyKeys: readonly string[];
9
+ kind: ToolBodyKind;
10
+ }
11
+ /**
12
+ * Curated bridge: body-sending tool → route + wire body keys.
13
+ *
14
+ * ONLY tools that send a request body appear here. Read-only (GET) tools and
15
+ * path/query-only tools carry no body-drift surface and are listed in the
16
+ * manifest's `_local_tools` (when they hit no route at all) or are simply
17
+ * absent (when they hit a GET route — GET routes never drift on body keys).
18
+ *
19
+ * `envelope` tools forward a free-form record (`patch` / `pipeline` / a settings
20
+ * map) whose individual keys are validated on the PHP side (e.g.
21
+ * ConnectionAdminController::ALLOWED_PATCH_KEYS). Their wrapper key is recorded
22
+ * so the test confirms the tool is accounted for; per-key validation lives in
23
+ * the PHP layer and is covered by PHP-side tests.
24
+ */
25
+ export declare const TOOL_WIRE_MAP: Readonly<Record<string, ToolWireBinding>>;
26
+ /** The PHP-accepted-params manifest fixture shape. */
27
+ export interface PhpAcceptedManifest {
28
+ /** "<METHOD> <path>" → accepted request-body keys. */
29
+ routes: Record<string, string[]>;
30
+ /** tool → { wire-key → justification } for keys the PHP route does not read. */
31
+ _allowed_drift: Record<string, Record<string, string>>;
32
+ /** tool → reason: tools with no REST route (purely client-side / aggregate). */
33
+ _local_tools: Record<string, string>;
34
+ /** route → { php-key → reason } for keys PHP accepts that no tool sends. */
35
+ _inverse_ignore?: Record<string, Record<string, string>>;
36
+ _meta?: Record<string, unknown>;
37
+ }
38
+ /** A single forward-direction drift: a wire key the PHP route does not accept. */
39
+ export interface DriftFinding {
40
+ tool: string;
41
+ route: string;
42
+ key: string;
43
+ }
44
+ /** A single inverse-direction advisory: a PHP-accepted key no tool sends. */
45
+ export interface InverseFinding {
46
+ route: string;
47
+ key: string;
48
+ }
49
+ export interface DriftReport {
50
+ /** Dangerous direction: tool sends a key PHP neither accepts nor allow-lists. */
51
+ drift: DriftFinding[];
52
+ /** Advisory: PHP accepts a key no tool sends (minus `_inverse_ignore`). */
53
+ inverse: InverseFinding[];
54
+ /** Live tools missing from BOTH TOOL_WIRE_MAP and `_local_tools` (coverage gap). */
55
+ uncovered: string[];
56
+ /** Entries in TOOL_WIRE_MAP / `_local_tools` no longer present in the live surface. */
57
+ stale: string[];
58
+ }
59
+ /**
60
+ * Resolve the committed fixture path. From this module
61
+ * (`<pkg>/{src,dist}/modules/apimapper/whitelist-drift.{ts,js}`) the package
62
+ * root is three directories up; the fixture is `tests/fixtures/...` under it.
63
+ * The depth is identical for the source layout (vitest/tsx) and the built
64
+ * `dist/` layout, so the same relative offset works in both.
65
+ */
66
+ export declare function manifestPath(): string;
67
+ /** Load + validate the committed PHP-accepted-params manifest. */
68
+ export declare function loadManifest(path?: string): PhpAcceptedManifest;
69
+ /**
70
+ * Enumerate every registered MCP tool name. Mirrors the runtime tool surface:
71
+ * - module essentials forwarded to a real McpServer,
72
+ * - the gateway-captured advanced tools,
73
+ * - the profile / status tools registered in src/index.ts AFTER module load.
74
+ *
75
+ * The src/index.ts trio is appended explicitly: they are registered on the real
76
+ * server outside the module's register(), so a module-only enumeration would
77
+ * miss them. They are pure local/profile tools (no REST body) and live in
78
+ * `_local_tools`; listing them here keeps the coverage check honest.
79
+ */
80
+ export declare function collectLiveTools(): string[];
81
+ /**
82
+ * Compute the drift report from the live tool surface + the curated wire map +
83
+ * the PHP-accepted manifest. Pure — no I/O.
84
+ */
85
+ export declare function computeDrift(liveTools: readonly string[], manifest: PhpAcceptedManifest): DriftReport;
@@ -0,0 +1,375 @@
1
+ // src/modules/apimapper/whitelist-drift.ts — Wave-16 #88
2
+ //
3
+ // MCP↔PHP whitelist drift detector — shared harness.
4
+ //
5
+ // PURPOSE
6
+ // -------
7
+ // Every API Mapper MCP tool that mutates state POSTs/PUTs a JSON body to a
8
+ // WordPress REST route under /wp-json/api-mapper/v1/. If a tool puts a key in
9
+ // that body which the PHP handler does NOT read, one of two bad things happens:
10
+ //
11
+ // * the PHP layer silently DROPS the key (the tool advertises behaviour that
12
+ // never takes effect — e.g. an ordering option that does nothing), or
13
+ // * the PHP layer REJECTS the request (e.g. ConnectionAdminController's
14
+ // ALLOWED_PATCH_KEYS 422s an unknown patch key).
15
+ //
16
+ // Both are real defects, and both are invisible to the type system because the
17
+ // MCP and PHP sides live in different languages. This harness reconciles the
18
+ // two surfaces so a CI test fails the moment they drift.
19
+ //
20
+ // THE THREE INPUTS
21
+ // ----------------
22
+ // 1. The LIVE MCP tool surface — enumerated at runtime from the registered
23
+ // module (essentials forwarded to a real McpServer + advanced registry +
24
+ // the externally-registered profile/status tools). See collectLiveTools().
25
+ // 2. TOOL_WIRE_MAP — the hand-maintained bridge from each body-sending tool to
26
+ // the REST route it calls and the EXACT wire body keys it sends. The wire
27
+ // keys are NOT always the zod keys: several tools remap (e.g.
28
+ // local_source_query's zod `content_type` → wire `contentType`). A PHP scan
29
+ // cannot see this remap and the zod schema does not encode the route, so
30
+ // this bridge is curated. It is anti-rot-guarded: the test asserts it
31
+ // covers EXACTLY the live tool set (minus declared local tools), so a new
32
+ // or removed tool fails CI until the map is updated.
33
+ // 3. The PHP-accepted-params manifest (tests/fixtures/php-accepted-params.json)
34
+ // — route → accepted body keys, generated by scripts/dump-rest-whitelist.php
35
+ // from the real controllers and hand-reconciled. Plus `_allowed_drift`
36
+ // (per-tool justified exceptions) and `_local_tools` (tools with no REST
37
+ // route).
38
+ //
39
+ // The harness is pure + import-safe (no network, no env requirement) so it can
40
+ // be imported by both the vitest pin test and the standalone gate script.
41
+ import { readFileSync } from "node:fs";
42
+ import { fileURLToPath } from "node:url";
43
+ import { dirname, resolve } from "node:path";
44
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
45
+ import { apimapperRestModule } from "./index.js";
46
+ /**
47
+ * Curated bridge: body-sending tool → route + wire body keys.
48
+ *
49
+ * ONLY tools that send a request body appear here. Read-only (GET) tools and
50
+ * path/query-only tools carry no body-drift surface and are listed in the
51
+ * manifest's `_local_tools` (when they hit no route at all) or are simply
52
+ * absent (when they hit a GET route — GET routes never drift on body keys).
53
+ *
54
+ * `envelope` tools forward a free-form record (`patch` / `pipeline` / a settings
55
+ * map) whose individual keys are validated on the PHP side (e.g.
56
+ * ConnectionAdminController::ALLOWED_PATCH_KEYS). Their wrapper key is recorded
57
+ * so the test confirms the tool is accounted for; per-key validation lives in
58
+ * the PHP layer and is covered by PHP-side tests.
59
+ */
60
+ export const TOOL_WIRE_MAP = {
61
+ // ── Connections ────────────────────────────────────────────────────
62
+ apimapper_connection_create: {
63
+ route: "POST /connections",
64
+ bodyKeys: [
65
+ "name",
66
+ "endpoint",
67
+ "method",
68
+ "auth_type",
69
+ "credential_id",
70
+ "items_path",
71
+ "cache_ttl",
72
+ "description",
73
+ ],
74
+ kind: "structured",
75
+ },
76
+ apimapper_connection_update: {
77
+ route: "PUT /connections/{id}",
78
+ bodyKeys: ["patch"],
79
+ kind: "envelope",
80
+ },
81
+ apimapper_connection_recover: {
82
+ route: "PUT /connections/{id}",
83
+ bodyKeys: ["patch"],
84
+ kind: "envelope",
85
+ },
86
+ apimapper_connection_test: {
87
+ route: "POST /connections/test",
88
+ bodyKeys: ["connection_id"],
89
+ kind: "structured",
90
+ },
91
+ apimapper_connection_health_check: {
92
+ route: "POST /connections/health-check",
93
+ bodyKeys: ["connection_ids"],
94
+ kind: "structured",
95
+ },
96
+ apimapper_connection_pipeline_update: {
97
+ route: "PUT /connections/{id}/pipeline",
98
+ bodyKeys: ["pipeline"],
99
+ kind: "envelope",
100
+ },
101
+ // ── Credentials ────────────────────────────────────────────────────
102
+ apimapper_credential_create: {
103
+ route: "POST /credentials",
104
+ bodyKeys: [
105
+ "name",
106
+ "auth_type",
107
+ "auth_data",
108
+ "oauth_provider",
109
+ "provider",
110
+ "oauth_token_expires_at",
111
+ ],
112
+ kind: "structured",
113
+ },
114
+ apimapper_credential_update: {
115
+ route: "PUT /credentials/{id}",
116
+ bodyKeys: ["patch"],
117
+ kind: "envelope",
118
+ },
119
+ apimapper_credential_link: {
120
+ route: "POST /oauth/authorize",
121
+ bodyKeys: ["existing_credential_id", "scopes"],
122
+ kind: "structured",
123
+ },
124
+ apimapper_oauth_authorize_begin: {
125
+ route: "POST /oauth/authorize",
126
+ bodyKeys: [
127
+ "existing_credential_id",
128
+ "scopes",
129
+ "oauth_config",
130
+ "client_id",
131
+ "client_secret",
132
+ "credential_name",
133
+ ],
134
+ kind: "structured",
135
+ },
136
+ // ── Flows ──────────────────────────────────────────────────────────
137
+ apimapper_flow_create: {
138
+ route: "POST /flows",
139
+ bodyKeys: ["name", "description", "nodes", "edges", "viewport"],
140
+ kind: "structured",
141
+ },
142
+ apimapper_flow_update: {
143
+ route: "PUT /flows/{id}",
144
+ bodyKeys: ["patch"],
145
+ kind: "envelope",
146
+ },
147
+ apimapper_flow_import_validate: {
148
+ route: "POST /flows/import/validate",
149
+ bodyKeys: ["bundle"],
150
+ kind: "envelope",
151
+ },
152
+ apimapper_flow_import: {
153
+ route: "POST /flows/import",
154
+ bodyKeys: ["bundle"],
155
+ kind: "envelope",
156
+ },
157
+ // ── Graph / Schema ─────────────────────────────────────────────────
158
+ apimapper_graph_preview: {
159
+ route: "POST /graph/preview",
160
+ bodyKeys: ["nodes", "edges", "targetNodeId", "forceRefresh"],
161
+ kind: "structured",
162
+ },
163
+ apimapper_graph_validate: {
164
+ route: "POST /graph/validate",
165
+ bodyKeys: ["nodes", "edges"],
166
+ kind: "structured",
167
+ },
168
+ apimapper_schema_profile: {
169
+ route: "POST /schema-profile",
170
+ bodyKeys: ["nodes", "edges", "target_node_id", "flow_id"],
171
+ kind: "structured",
172
+ },
173
+ // ── Local sources ──────────────────────────────────────────────────
174
+ apimapper_local_source_query: {
175
+ route: "POST /local-sources/query",
176
+ // Wire keys after the handler's zod→wire remap: content_type→contentType,
177
+ // orderby→sort, order→sortDirection (see #88 reconciliation).
178
+ bodyKeys: ["contentType", "filters", "limit", "offset", "sort", "sortDirection"],
179
+ kind: "structured",
180
+ },
181
+ // ── Cache / Settings ───────────────────────────────────────────────
182
+ apimapper_cache_invalidate: {
183
+ route: "POST /cache/admin/invalidate",
184
+ bodyKeys: ["scope", "payload"],
185
+ kind: "structured",
186
+ },
187
+ apimapper_settings_update: {
188
+ route: "POST /settings",
189
+ bodyKeys: ["patch"],
190
+ kind: "envelope",
191
+ },
192
+ // ── License ────────────────────────────────────────────────────────
193
+ apimapper_license_activate: {
194
+ route: "POST /license/activate",
195
+ bodyKeys: ["license_key", "email"],
196
+ kind: "structured",
197
+ },
198
+ apimapper_license_beta_channel: {
199
+ route: "POST /license/beta-channel",
200
+ bodyKeys: ["enabled"],
201
+ kind: "structured",
202
+ },
203
+ // ── Misc ───────────────────────────────────────────────────────────
204
+ apimapper_health_warnings_dismiss: {
205
+ route: "POST /admin/health-warnings/dismiss",
206
+ bodyKeys: ["id"],
207
+ kind: "structured",
208
+ },
209
+ apimapper_feedback_submit: {
210
+ route: "POST /feedback",
211
+ bodyKeys: ["type", "subject", "message", "email", "attachments", "idempotency_key"],
212
+ kind: "structured",
213
+ },
214
+ apimapper_release_download: {
215
+ route: "POST /releases/download",
216
+ bodyKeys: ["version", "product"],
217
+ kind: "structured",
218
+ },
219
+ // P-B (JMESPath superpowers) — POST /jmespath/test sends the expression +
220
+ // the sample rows to evaluate against. Both are accepted by the WP
221
+ // JmespathTestController / Joomla JmespathTestAjaxHandler.
222
+ apimapper_jmespath_test: {
223
+ route: "POST /jmespath/test",
224
+ bodyKeys: ["expression", "sample_rows"],
225
+ kind: "structured",
226
+ },
227
+ };
228
+ /**
229
+ * Resolve the committed fixture path. From this module
230
+ * (`<pkg>/{src,dist}/modules/apimapper/whitelist-drift.{ts,js}`) the package
231
+ * root is three directories up; the fixture is `tests/fixtures/...` under it.
232
+ * The depth is identical for the source layout (vitest/tsx) and the built
233
+ * `dist/` layout, so the same relative offset works in both.
234
+ */
235
+ export function manifestPath() {
236
+ const here = dirname(fileURLToPath(import.meta.url));
237
+ return resolve(here, "..", "..", "..", "tests", "fixtures", "php-accepted-params.json");
238
+ }
239
+ /** Narrowing guard for the parsed manifest JSON. */
240
+ function isManifest(value) {
241
+ if (typeof value !== "object" || value === null)
242
+ return false;
243
+ const v = value;
244
+ return (typeof v.routes === "object" &&
245
+ v.routes !== null &&
246
+ typeof v._allowed_drift === "object" &&
247
+ v._allowed_drift !== null &&
248
+ typeof v._local_tools === "object" &&
249
+ v._local_tools !== null);
250
+ }
251
+ /** Load + validate the committed PHP-accepted-params manifest. */
252
+ export function loadManifest(path = manifestPath()) {
253
+ const raw = JSON.parse(readFileSync(path, "utf8"));
254
+ if (!isManifest(raw)) {
255
+ throw new Error(`Invalid php-accepted-params manifest at ${path}`);
256
+ }
257
+ return raw;
258
+ }
259
+ /**
260
+ * Enumerate every registered MCP tool name. Mirrors the runtime tool surface:
261
+ * - module essentials forwarded to a real McpServer,
262
+ * - the gateway-captured advanced tools,
263
+ * - the profile / status tools registered in src/index.ts AFTER module load.
264
+ *
265
+ * The src/index.ts trio is appended explicitly: they are registered on the real
266
+ * server outside the module's register(), so a module-only enumeration would
267
+ * miss them. They are pure local/profile tools (no REST body) and live in
268
+ * `_local_tools`; listing them here keeps the coverage check honest.
269
+ */
270
+ export function collectLiveTools() {
271
+ const server = new McpServer({ name: "drift-probe", version: "0.0.0" });
272
+ const names = new Set();
273
+ // Intercept registerTool so essentials forwarded to the real server are seen.
274
+ const realRegister = server.registerTool.bind(server);
275
+ const patched = server;
276
+ patched.registerTool = (name, config, cb) => {
277
+ names.add(name);
278
+ return realRegister(name, config, cb);
279
+ };
280
+ apimapperRestModule.register(server);
281
+ const advanced = apimapperRestModule.getAdvancedRegistry();
282
+ if (advanced) {
283
+ for (const name of advanced.keys())
284
+ names.add(name);
285
+ }
286
+ // Externally-registered (src/index.ts) — no REST body; covered by _local_tools.
287
+ for (const n of ["apimapper_use_profile", "apimapper_list_profiles", "apimapper_rest_modules_status"]) {
288
+ names.add(n);
289
+ }
290
+ return [...names].sort();
291
+ }
292
+ /**
293
+ * Compute the drift report from the live tool surface + the curated wire map +
294
+ * the PHP-accepted manifest. Pure — no I/O.
295
+ */
296
+ export function computeDrift(liveTools, manifest) {
297
+ const drift = [];
298
+ const inverse = [];
299
+ const uncovered = [];
300
+ const live = new Set(liveTools);
301
+ // Coverage: every live tool must be in the wire map OR declared local.
302
+ for (const tool of liveTools) {
303
+ const inWireMap = Object.prototype.hasOwnProperty.call(TOOL_WIRE_MAP, tool);
304
+ const isLocal = Object.prototype.hasOwnProperty.call(manifest._local_tools, tool);
305
+ if (!inWireMap && !isLocal)
306
+ uncovered.push(tool);
307
+ }
308
+ // Anti-rot: nothing in the wire map / local map may reference a vanished tool.
309
+ const stale = [];
310
+ for (const tool of Object.keys(TOOL_WIRE_MAP)) {
311
+ if (!live.has(tool))
312
+ stale.push(tool);
313
+ }
314
+ for (const tool of Object.keys(manifest._local_tools)) {
315
+ if (!live.has(tool))
316
+ stale.push(tool);
317
+ }
318
+ // Forward direction: each wire body key must be accepted or allow-listed.
319
+ for (const [tool, binding] of Object.entries(TOOL_WIRE_MAP)) {
320
+ if (!live.has(tool))
321
+ continue; // reported as stale above
322
+ const accepted = new Set(manifest.routes[binding.route] ?? []);
323
+ const allowed = manifest._allowed_drift[tool] ?? {};
324
+ for (const key of binding.bodyKeys) {
325
+ if (accepted.has(key))
326
+ continue;
327
+ if (Object.prototype.hasOwnProperty.call(allowed, key))
328
+ continue;
329
+ drift.push({ tool, route: binding.route, key });
330
+ }
331
+ }
332
+ // Inverse direction (advisory): PHP-accepted keys no tool sends.
333
+ //
334
+ // Built per route from the union of the STRUCTURED bindings' literal body
335
+ // keys. Routes that ANY envelope binding targets are skipped entirely: an
336
+ // envelope tool forwards a free-form record that can legitimately carry any
337
+ // of the route's accepted keys, so "no tool sends key X" is meaningless there
338
+ // (per-key validity for envelope routes is a PHP-side concern). The inverse
339
+ // check therefore only fires for routes whose tools send a fixed, literal key
340
+ // set — exactly where a PHP-only key really is unreachable from the MCP.
341
+ const sentByRoute = new Map();
342
+ const envelopeRoutes = new Set();
343
+ for (const binding of Object.values(TOOL_WIRE_MAP)) {
344
+ if (binding.kind === "envelope") {
345
+ envelopeRoutes.add(binding.route);
346
+ continue;
347
+ }
348
+ if (!sentByRoute.has(binding.route))
349
+ sentByRoute.set(binding.route, new Set());
350
+ const set = sentByRoute.get(binding.route);
351
+ for (const k of binding.bodyKeys)
352
+ set.add(k);
353
+ }
354
+ for (const [route, accepted] of Object.entries(manifest.routes)) {
355
+ if (envelopeRoutes.has(route))
356
+ continue; // free-form record carries any key
357
+ const sent = sentByRoute.get(route);
358
+ if (!sent)
359
+ continue; // no structured tool targets this route with a body
360
+ const ignore = manifest._inverse_ignore?.[route] ?? {};
361
+ for (const key of accepted) {
362
+ if (sent.has(key))
363
+ continue;
364
+ if (Object.prototype.hasOwnProperty.call(ignore, key))
365
+ continue;
366
+ inverse.push({ route, key });
367
+ }
368
+ }
369
+ drift.sort((a, b) => a.tool.localeCompare(b.tool) || a.key.localeCompare(b.key));
370
+ inverse.sort((a, b) => a.route.localeCompare(b.route) || a.key.localeCompare(b.key));
371
+ uncovered.sort();
372
+ stale.sort();
373
+ return { drift, inverse, uncovered, stale };
374
+ }
375
+ //# sourceMappingURL=whitelist-drift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whitelist-drift.js","sourceRoot":"","sources":["../../../src/modules/apimapper/whitelist-drift.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,EAAE;AACF,qDAAqD;AACrD,EAAE;AACF,UAAU;AACV,UAAU;AACV,2EAA2E;AAC3E,8EAA8E;AAC9E,gFAAgF;AAChF,EAAE;AACF,+EAA+E;AAC/E,0EAA0E;AAC1E,0EAA0E;AAC1E,qDAAqD;AACrD,EAAE;AACF,+EAA+E;AAC/E,6EAA6E;AAC7E,yDAAyD;AACzD,EAAE;AACF,mBAAmB;AACnB,mBAAmB;AACnB,4EAA4E;AAC5E,6EAA6E;AAC7E,+EAA+E;AAC/E,gFAAgF;AAChF,8EAA8E;AAC9E,kEAAkE;AAClE,gFAAgF;AAChF,6EAA6E;AAC7E,0EAA0E;AAC1E,8EAA8E;AAC9E,yDAAyD;AACzD,iFAAiF;AACjF,iFAAiF;AACjF,2EAA2E;AAC3E,6EAA6E;AAC7E,cAAc;AACd,EAAE;AACF,+EAA+E;AAC/E,0EAA0E;AAE1E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAgBjD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,aAAa,GAA8C;IACtE,sEAAsE;IACtE,2BAA2B,EAAE;QAC3B,KAAK,EAAE,mBAAmB;QAC1B,QAAQ,EAAE;YACR,MAAM;YACN,UAAU;YACV,QAAQ;YACR,WAAW;YACX,eAAe;YACf,YAAY;YACZ,WAAW;YACX,aAAa;SACd;QACD,IAAI,EAAE,YAAY;KACnB;IACD,2BAA2B,EAAE;QAC3B,KAAK,EAAE,uBAAuB;QAC9B,QAAQ,EAAE,CAAC,OAAO,CAAC;QACnB,IAAI,EAAE,UAAU;KACjB;IACD,4BAA4B,EAAE;QAC5B,KAAK,EAAE,uBAAuB;QAC9B,QAAQ,EAAE,CAAC,OAAO,CAAC;QACnB,IAAI,EAAE,UAAU;KACjB;IACD,yBAAyB,EAAE;QACzB,KAAK,EAAE,wBAAwB;QAC/B,QAAQ,EAAE,CAAC,eAAe,CAAC;QAC3B,IAAI,EAAE,YAAY;KACnB;IACD,iCAAiC,EAAE;QACjC,KAAK,EAAE,gCAAgC;QACvC,QAAQ,EAAE,CAAC,gBAAgB,CAAC;QAC5B,IAAI,EAAE,YAAY;KACnB;IACD,oCAAoC,EAAE;QACpC,KAAK,EAAE,gCAAgC;QACvC,QAAQ,EAAE,CAAC,UAAU,CAAC;QACtB,IAAI,EAAE,UAAU;KACjB;IAED,sEAAsE;IACtE,2BAA2B,EAAE;QAC3B,KAAK,EAAE,mBAAmB;QAC1B,QAAQ,EAAE;YACR,MAAM;YACN,WAAW;YACX,WAAW;YACX,gBAAgB;YAChB,UAAU;YACV,wBAAwB;SACzB;QACD,IAAI,EAAE,YAAY;KACnB;IACD,2BAA2B,EAAE;QAC3B,KAAK,EAAE,uBAAuB;QAC9B,QAAQ,EAAE,CAAC,OAAO,CAAC;QACnB,IAAI,EAAE,UAAU;KACjB;IACD,yBAAyB,EAAE;QACzB,KAAK,EAAE,uBAAuB;QAC9B,QAAQ,EAAE,CAAC,wBAAwB,EAAE,QAAQ,CAAC;QAC9C,IAAI,EAAE,YAAY;KACnB;IACD,+BAA+B,EAAE;QAC/B,KAAK,EAAE,uBAAuB;QAC9B,QAAQ,EAAE;YACR,wBAAwB;YACxB,QAAQ;YACR,cAAc;YACd,WAAW;YACX,eAAe;YACf,iBAAiB;SAClB;QACD,IAAI,EAAE,YAAY;KACnB;IAED,sEAAsE;IACtE,qBAAqB,EAAE;QACrB,KAAK,EAAE,aAAa;QACpB,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC;QAC/D,IAAI,EAAE,YAAY;KACnB;IACD,qBAAqB,EAAE;QACrB,KAAK,EAAE,iBAAiB;QACxB,QAAQ,EAAE,CAAC,OAAO,CAAC;QACnB,IAAI,EAAE,UAAU;KACjB;IACD,8BAA8B,EAAE;QAC9B,KAAK,EAAE,6BAA6B;QACpC,QAAQ,EAAE,CAAC,QAAQ,CAAC;QACpB,IAAI,EAAE,UAAU;KACjB;IACD,qBAAqB,EAAE;QACrB,KAAK,EAAE,oBAAoB;QAC3B,QAAQ,EAAE,CAAC,QAAQ,CAAC;QACpB,IAAI,EAAE,UAAU;KACjB;IAED,sEAAsE;IACtE,uBAAuB,EAAE;QACvB,KAAK,EAAE,qBAAqB;QAC5B,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,CAAC;QAC5D,IAAI,EAAE,YAAY;KACnB;IACD,wBAAwB,EAAE;QACxB,KAAK,EAAE,sBAAsB;QAC7B,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC;QAC5B,IAAI,EAAE,YAAY;KACnB;IACD,wBAAwB,EAAE;QACxB,KAAK,EAAE,sBAAsB;QAC7B,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,SAAS,CAAC;QACzD,IAAI,EAAE,YAAY;KACnB;IAED,sEAAsE;IACtE,4BAA4B,EAAE;QAC5B,KAAK,EAAE,2BAA2B;QAClC,0EAA0E;QAC1E,8DAA8D;QAC9D,QAAQ,EAAE,CAAC,aAAa,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC;QAChF,IAAI,EAAE,YAAY;KACnB;IAED,sEAAsE;IACtE,0BAA0B,EAAE;QAC1B,KAAK,EAAE,8BAA8B;QACrC,QAAQ,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC;QAC9B,IAAI,EAAE,YAAY;KACnB;IACD,yBAAyB,EAAE;QACzB,KAAK,EAAE,gBAAgB;QACvB,QAAQ,EAAE,CAAC,OAAO,CAAC;QACnB,IAAI,EAAE,UAAU;KACjB;IAED,sEAAsE;IACtE,0BAA0B,EAAE;QAC1B,KAAK,EAAE,wBAAwB;QAC/B,QAAQ,EAAE,CAAC,aAAa,EAAE,OAAO,CAAC;QAClC,IAAI,EAAE,YAAY;KACnB;IACD,8BAA8B,EAAE;QAC9B,KAAK,EAAE,4BAA4B;QACnC,QAAQ,EAAE,CAAC,SAAS,CAAC;QACrB,IAAI,EAAE,YAAY;KACnB;IAED,sEAAsE;IACtE,iCAAiC,EAAE;QACjC,KAAK,EAAE,qCAAqC;QAC5C,QAAQ,EAAE,CAAC,IAAI,CAAC;QAChB,IAAI,EAAE,YAAY;KACnB;IACD,yBAAyB,EAAE;QACzB,KAAK,EAAE,gBAAgB;QACvB,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,iBAAiB,CAAC;QACnF,IAAI,EAAE,YAAY;KACnB;IACD,0BAA0B,EAAE;QAC1B,KAAK,EAAE,yBAAyB;QAChC,QAAQ,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC;QAChC,IAAI,EAAE,YAAY;KACnB;IACD,0EAA0E;IAC1E,mEAAmE;IACnE,2DAA2D;IAC3D,uBAAuB,EAAE;QACvB,KAAK,EAAE,qBAAqB;QAC5B,QAAQ,EAAE,CAAC,YAAY,EAAE,aAAa,CAAC;QACvC,IAAI,EAAE,YAAY;KACnB;CACF,CAAC;AAuCF;;;;;;GAMG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,OAAO,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,0BAA0B,CAAC,CAAC;AAC1F,CAAC;AAED,oDAAoD;AACpD,SAAS,UAAU,CAAC,KAAc;IAChC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,CAAC,GAAG,KAAgC,CAAC;IAC3C,OAAO,CACL,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;QAC5B,CAAC,CAAC,MAAM,KAAK,IAAI;QACjB,OAAO,CAAC,CAAC,cAAc,KAAK,QAAQ;QACpC,CAAC,CAAC,cAAc,KAAK,IAAI;QACzB,OAAO,CAAC,CAAC,YAAY,KAAK,QAAQ;QAClC,CAAC,CAAC,YAAY,KAAK,IAAI,CACxB,CAAC;AACJ,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,YAAY,CAAC,OAAe,YAAY,EAAE;IACxD,MAAM,GAAG,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5D,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,2CAA2C,IAAI,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACxE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAEhC,8EAA8E;IAC9E,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,MAEf,CAAC;IACF,OAAO,CAAC,YAAY,GAAG,CAAC,IAAY,EAAE,MAAe,EAAE,EAAW,EAAE,EAAE;QACpE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChB,OAAQ,YAA2E,CACjF,IAAI,EACJ,MAAM,EACN,EAAE,CACH,CAAC;IACJ,CAAC,CAAC;IAEF,mBAAmB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAErC,MAAM,QAAQ,GAAG,mBAAmB,CAAC,mBAAmB,EAAE,CAAC;IAC3D,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,IAAI,EAAE;YAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC;IAED,gFAAgF;IAChF,KAAK,MAAM,CAAC,IAAI,CAAC,uBAAuB,EAAE,yBAAyB,EAAE,+BAA+B,CAAC,EAAE,CAAC;QACtG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACf,CAAC;IAED,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AAC3B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,SAA4B,EAC5B,QAA6B;IAE7B,MAAM,KAAK,GAAmB,EAAE,CAAC;IACjC,MAAM,OAAO,GAAqB,EAAE,CAAC;IACrC,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IAEhC,uEAAuE;IACvE,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;QAC5E,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAClF,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO;YAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,+EAA+E;IAC/E,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,0EAA0E;IAC1E,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;QAC5D,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS,CAAC,0BAA0B;QACzD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/D,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACpD,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACnC,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,SAAS;YAChC,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC;gBAAE,SAAS;YACjE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,iEAAiE;IACjE,EAAE;IACF,0EAA0E;IAC1E,0EAA0E;IAC1E,4EAA4E;IAC5E,8EAA8E;IAC9E,4EAA4E;IAC5E,8EAA8E;IAC9E,yEAAyE;IACzE,MAAM,WAAW,GAAG,IAAI,GAAG,EAAuB,CAAC;IACnD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;IACzC,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;QACnD,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAChC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAClC,SAAS;QACX,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QAC/E,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAE,CAAC;QAC5C,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,QAAQ;YAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,KAAK,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAChE,IAAI,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS,CAAC,mCAAmC;QAC5E,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI;YAAE,SAAS,CAAC,oDAAoD;QACzE,MAAM,MAAM,GAAG,QAAQ,CAAC,eAAe,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACvD,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,SAAS;YAC5B,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC;gBAAE,SAAS;YAChE,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACrF,SAAS,CAAC,IAAI,EAAE,CAAC;IACjB,KAAK,CAAC,IAAI,EAAE,CAAC;IAEb,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAC9C,CAAC"}