@aexol/spectral 0.9.254 → 0.9.255

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 (49) hide show
  1. package/dist/extensions/dataset-uploader/analyzer.d.ts +103 -0
  2. package/dist/extensions/dataset-uploader/analyzer.d.ts.map +1 -0
  3. package/dist/extensions/dataset-uploader/analyzer.js +266 -0
  4. package/dist/extensions/dataset-uploader/cleaner.d.ts +59 -0
  5. package/dist/extensions/dataset-uploader/cleaner.d.ts.map +1 -0
  6. package/dist/extensions/dataset-uploader/cleaner.js +118 -0
  7. package/dist/extensions/dataset-uploader/exporter.d.ts +147 -0
  8. package/dist/extensions/dataset-uploader/exporter.d.ts.map +1 -0
  9. package/dist/extensions/dataset-uploader/exporter.js +313 -0
  10. package/dist/extensions/dataset-uploader/extra-values.d.ts +17 -0
  11. package/dist/extensions/dataset-uploader/extra-values.d.ts.map +1 -0
  12. package/dist/extensions/dataset-uploader/extra-values.js +51 -0
  13. package/dist/extensions/dataset-uploader/index.d.ts +22 -0
  14. package/dist/extensions/dataset-uploader/index.d.ts.map +1 -0
  15. package/dist/extensions/dataset-uploader/index.js +247 -0
  16. package/dist/extensions/dataset-uploader/scrubber.d.ts +34 -0
  17. package/dist/extensions/dataset-uploader/scrubber.d.ts.map +1 -0
  18. package/dist/extensions/dataset-uploader/scrubber.js +91 -0
  19. package/dist/extensions/dataset-uploader/upload.d.ts +105 -0
  20. package/dist/extensions/dataset-uploader/upload.d.ts.map +1 -0
  21. package/dist/extensions/dataset-uploader/upload.js +274 -0
  22. package/dist/generated/zeus/const.d.ts.map +1 -1
  23. package/dist/generated/zeus/const.js +32 -0
  24. package/dist/generated/zeus/index.d.ts +166 -0
  25. package/dist/generated/zeus/index.d.ts.map +1 -1
  26. package/dist/mcp/commands.d.ts.map +1 -1
  27. package/dist/mcp/commands.js +3 -0
  28. package/dist/mcp/direct-tools.d.ts.map +1 -1
  29. package/dist/mcp/direct-tools.js +4 -3
  30. package/dist/mcp/index.d.ts.map +1 -1
  31. package/dist/mcp/index.js +5 -1
  32. package/dist/mcp/mcp-auth-flow.d.ts +1 -1
  33. package/dist/mcp/mcp-auth-flow.d.ts.map +1 -1
  34. package/dist/mcp/mcp-auth-flow.js +13 -0
  35. package/dist/mcp/mcp-auth-start.d.ts +64 -0
  36. package/dist/mcp/mcp-auth-start.d.ts.map +1 -0
  37. package/dist/mcp/mcp-auth-start.js +136 -0
  38. package/dist/mcp/proxy-modes.d.ts +7 -0
  39. package/dist/mcp/proxy-modes.d.ts.map +1 -1
  40. package/dist/mcp/proxy-modes.js +71 -11
  41. package/dist/mcp/server-manager.d.ts +2 -1
  42. package/dist/mcp/server-manager.d.ts.map +1 -1
  43. package/dist/mcp/server-manager.js +8 -4
  44. package/dist/sdk/coding-agent/core/extensions/native-extensions.d.ts.map +1 -1
  45. package/dist/sdk/coding-agent/core/extensions/native-extensions.js +10 -0
  46. package/dist/server/handlers/mcp-auth.d.ts +7 -4
  47. package/dist/server/handlers/mcp-auth.d.ts.map +1 -1
  48. package/dist/server/handlers/mcp-auth.js +15 -80
  49. package/package.json +1 -1
@@ -2,46 +2,19 @@
2
2
  * Handler for `POST /api/mcp-auth`.
3
3
  *
4
4
  * Starts the OAuth flow for a locally configured MCP server managed by
5
- * `spectral serve`. Runs headless: `startAuth` captures the authorization
6
- * URL through the provider's `onRedirect` hook (no browser is opened
7
- * here — the caller renders `authUrl`), and the flow is completed in the
8
- * background once the local callback server receives the code.
5
+ * `spectral serve`. Delegates to the shared non-blocking helper
6
+ * (`startMcpAuthFlow`) used by the agent `mcp` tool: `startAuth` captures
7
+ * the authorization URL through the provider's `onRedirect` hook, and the
8
+ * flow is completed in the background once the local callback server
9
+ * receives the code. `openBrowser: true` in the body launches the system
10
+ * browser (default: headless — the caller renders `authUrl`).
9
11
  *
10
12
  * Pure handler pattern — no framework, no side effects on the wire. The
11
13
  * caller (the relay dispatcher) injects `McpExtensionState`; validation
12
14
  * failures throw `BadRequestError` which `relay/rest.ts` maps to 400.
13
15
  */
14
- import { waitForCallback } from "../../mcp/mcp-callback-server.js";
15
- import { completeAuth, startAuth, supportsOAuth, } from "../../mcp/mcp-auth-flow.js";
16
- import { clearOAuthState } from "../../mcp/mcp-auth.js";
17
- import { reloadMcpConfig } from "../../mcp/init.js";
16
+ import { McpAuthStartError, startMcpAuthFlow, } from "../../mcp/mcp-auth-start.js";
18
17
  import { BadRequestError } from "./errors.js";
19
- /**
20
- * Per-server in-flight guard. `startAuth` keys its pending transports and
21
- * persisted OAuth state by server name, so two concurrent flows for the same
22
- * server would clobber each other (the headless handler bypasses the
23
- * `authenticate()` dedupe). Reject the second POST until the first
24
- * flow's background chain finishes.
25
- */
26
- const inFlightMcpAuths = new Set();
27
- /**
28
- * An authorization URL is about to be opened in the user's browser, so it
29
- * must never be a `javascript:` / `data:` / malformed URL coming from a
30
- * malicious MCP server's OAuth metadata. Defense in depth: the landing UI
31
- * applies the same check before `window.open`.
32
- */
33
- function assertSafeAuthorizationUrl(authUrl) {
34
- let parsed;
35
- try {
36
- parsed = new URL(authUrl);
37
- }
38
- catch {
39
- throw new BadRequestError("Invalid authorization URL");
40
- }
41
- if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
42
- throw new BadRequestError("Invalid authorization URL");
43
- }
44
- }
45
18
  export async function handleStartMcpAuth(state, body) {
46
19
  if (!state) {
47
20
  throw new BadRequestError("MCP adapter not loaded");
@@ -50,57 +23,19 @@ export async function handleStartMcpAuth(state, body) {
50
23
  if (typeof name !== "string" || name.length === 0) {
51
24
  throw new BadRequestError("name is required");
52
25
  }
53
- const definition = state.config.mcpServers[name];
54
- if (!definition) {
55
- throw new BadRequestError(`Unknown MCP server: ${name}`);
56
- }
57
- if (!definition.url || !supportsOAuth(definition)) {
58
- throw new BadRequestError(`MCP server "${name}" does not support OAuth`);
59
- }
60
- if (inFlightMcpAuths.has(name)) {
61
- throw new BadRequestError("OAuth authentication already in progress for this server");
62
- }
63
- inFlightMcpAuths.add(name);
64
- let authorizationUrl;
65
- let oauthState;
66
26
  try {
67
- ({ authorizationUrl, oauthState } = await startAuth(name, definition.url, definition));
68
- if (authorizationUrl === "") {
69
- inFlightMcpAuths.delete(name);
27
+ const result = await startMcpAuthFlow(state, name, {
28
+ openBrowser: body?.openBrowser === true,
29
+ });
30
+ if (result.status === "already-authenticated") {
70
31
  return { status: "already-authenticated" };
71
32
  }
72
- // Fail loudly instead of skipping background completion — a flow without
73
- // its persisted state could never be completed nor cleanly aborted.
74
- if (!oauthState) {
75
- throw new BadRequestError("OAuth state missing after authorization start");
76
- }
77
- assertSafeAuthorizationUrl(authorizationUrl);
33
+ return { status: "auth_url_ready", authUrl: result.authUrl };
78
34
  }
79
35
  catch (error) {
80
- // Release the guard so a failed start does not wedge the server.
81
- inFlightMcpAuths.delete(name);
36
+ if (error instanceof McpAuthStartError) {
37
+ throw new BadRequestError(error.message);
38
+ }
82
39
  throw error;
83
40
  }
84
- // Complete the flow in the background from the local callback server:
85
- // waitForCallback resolves with the authorization code, completeAuth
86
- // exchanges it for tokens, and the MCP config is reloaded so the server
87
- // comes up authenticated. Fire-and-forget — the response already carries
88
- // the authUrl and auth progress is observable via GET /api/mcp-status,
89
- // so failures are swallowed. The finally block releases the per-server
90
- // in-flight guard and clears the now-stale OAuth state (idempotent) on
91
- // every path.
92
- waitForCallback(oauthState)
93
- .then((code) => completeAuth(name, code))
94
- .then(() => reloadMcpConfig(state))
95
- .catch(() => { })
96
- .finally(() => {
97
- inFlightMcpAuths.delete(name);
98
- try {
99
- clearOAuthState(name);
100
- }
101
- catch {
102
- // Storage errors must not surface as unhandled rejections.
103
- }
104
- });
105
- return { status: "auth_url_ready", authUrl: authorizationUrl };
106
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aexol/spectral",
3
- "version": "0.9.254",
3
+ "version": "0.9.255",
4
4
  "description": "AI coding agent for Aexol with relay-based browser access.",
5
5
  "type": "module",
6
6
  "private": false,