studiograph 1.3.3-next.9 → 1.3.4
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/dist/agent/orchestrator.d.ts +2 -0
- package/dist/agent/orchestrator.js +13 -5
- package/dist/agent/orchestrator.js.map +1 -1
- package/dist/agent/skills/sync-configuration.md +4 -29
- package/dist/agent/skills/sync-setup.md +2 -4
- package/dist/agent/tools/ops-tools.js +15 -126
- package/dist/agent/tools/ops-tools.js.map +1 -1
- package/dist/agent/tools/sync-tools.d.ts +7 -6
- package/dist/agent/tools/sync-tools.js +205 -178
- package/dist/agent/tools/sync-tools.js.map +1 -1
- package/dist/cli/commands/about.d.ts +13 -0
- package/dist/cli/commands/about.js +97 -0
- package/dist/cli/commands/about.js.map +1 -0
- package/dist/cli/commands/clone.d.ts +5 -2
- package/dist/cli/commands/clone.js +131 -62
- package/dist/cli/commands/clone.js.map +1 -1
- package/dist/cli/commands/connector.d.ts +2 -16
- package/dist/cli/commands/connector.js +32 -109
- package/dist/cli/commands/connector.js.map +1 -1
- package/dist/cli/commands/deploy.d.ts +0 -1
- package/dist/cli/commands/deploy.js +13 -103
- package/dist/cli/commands/deploy.js.map +1 -1
- package/dist/cli/commands/init.js +6 -93
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/join.js +51 -1
- package/dist/cli/commands/join.js.map +1 -1
- package/dist/cli/commands/redeploy.js +1 -2
- package/dist/cli/commands/redeploy.js.map +1 -1
- package/dist/cli/commands/serve.d.ts +1 -3
- package/dist/cli/commands/serve.js +29 -109
- package/dist/cli/commands/serve.js.map +1 -1
- package/dist/cli/commands/start.js +1 -1
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/sync-collection.d.ts +14 -0
- package/dist/cli/commands/sync-collection.js +366 -0
- package/dist/cli/commands/sync-collection.js.map +1 -0
- package/dist/cli/commands/sync.js +518 -82
- package/dist/cli/commands/sync.js.map +1 -1
- package/dist/cli/index.js +12 -30
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/setup-wizard.d.ts +0 -13
- package/dist/cli/setup-wizard.js +6 -81
- package/dist/cli/setup-wizard.js.map +1 -1
- package/dist/core/types.d.ts +140 -21
- package/dist/core/types.js +15 -4
- package/dist/core/types.js.map +1 -1
- package/dist/core/workspace.d.ts +11 -4
- package/dist/core/workspace.js +61 -26
- package/dist/core/workspace.js.map +1 -1
- package/dist/integrations/asana.d.ts +26 -0
- package/dist/integrations/asana.js +77 -0
- package/dist/integrations/asana.js.map +1 -0
- package/dist/integrations/figma-local.d.ts +16 -0
- package/dist/integrations/figma-local.js +10 -0
- package/dist/integrations/figma-local.js.map +1 -0
- package/dist/integrations/figma.d.ts +17 -0
- package/dist/integrations/figma.js +16 -0
- package/dist/integrations/figma.js.map +1 -0
- package/dist/integrations/granola.d.ts +24 -0
- package/dist/integrations/granola.js +59 -0
- package/dist/integrations/granola.js.map +1 -0
- package/dist/integrations/linear.d.ts +14 -0
- package/dist/integrations/linear.js +70 -0
- package/dist/integrations/linear.js.map +1 -0
- package/dist/integrations/paper-local.d.ts +14 -0
- package/dist/integrations/paper-local.js +10 -0
- package/dist/integrations/paper-local.js.map +1 -0
- package/dist/integrations/paper.d.ts +2 -0
- package/dist/integrations/paper.js +10 -0
- package/dist/integrations/paper.js.map +1 -0
- package/dist/integrations/pipedrive.d.ts +26 -0
- package/dist/integrations/pipedrive.js +97 -0
- package/dist/integrations/pipedrive.js.map +1 -0
- package/dist/integrations/registry.d.ts +15 -0
- package/dist/integrations/registry.js +27 -0
- package/dist/integrations/registry.js.map +1 -0
- package/dist/integrations/types.d.ts +34 -0
- package/dist/integrations/types.js +9 -0
- package/dist/integrations/types.js.map +1 -0
- package/dist/mcp/connector-manager.d.ts +45 -31
- package/dist/mcp/connector-manager.js +164 -116
- package/dist/mcp/connector-manager.js.map +1 -1
- package/dist/mcp/server-oauth-provider.d.ts +56 -0
- package/dist/mcp/server-oauth-provider.js +138 -0
- package/dist/mcp/server-oauth-provider.js.map +1 -0
- package/dist/server/chrome/chrome.css +142 -28
- package/dist/server/chrome/chrome.js +51 -25
- package/dist/server/collab-authority.d.ts +70 -0
- package/dist/server/collab-authority.js +218 -0
- package/dist/server/collab-authority.js.map +1 -0
- package/dist/server/collab.d.ts +29 -0
- package/dist/server/collab.js +195 -0
- package/dist/server/collab.js.map +1 -0
- package/dist/server/commit-scheduler.d.ts +1 -1
- package/dist/server/commit-scheduler.js +18 -4
- package/dist/server/commit-scheduler.js.map +1 -1
- package/dist/server/index.d.ts +0 -2
- package/dist/server/index.js +89 -18
- package/dist/server/index.js.map +1 -1
- package/dist/server/routes/auth-api.d.ts +6 -0
- package/dist/server/routes/auth-api.js +55 -0
- package/dist/server/routes/auth-api.js.map +1 -1
- package/dist/server/routes/collab.d.ts +6 -0
- package/dist/server/routes/collab.js +10 -0
- package/dist/server/routes/collab.js.map +1 -0
- package/dist/server/routes/git-http.d.ts +1 -1
- package/dist/server/routes/git-http.js +53 -15
- package/dist/server/routes/git-http.js.map +1 -1
- package/dist/server/routes/graph-api.d.ts +2 -2
- package/dist/server/routes/graph-api.js +59 -55
- package/dist/server/routes/graph-api.js.map +1 -1
- package/dist/server/routes/mcp.d.ts +12 -0
- package/dist/server/routes/mcp.js +35 -0
- package/dist/server/routes/mcp.js.map +1 -0
- package/dist/server/routes/permissions-api.d.ts +2 -1
- package/dist/server/routes/permissions-api.js +16 -2
- package/dist/server/routes/permissions-api.js.map +1 -1
- package/dist/server/routes/sync-api.d.ts +26 -0
- package/dist/server/routes/sync-api.js +757 -0
- package/dist/server/routes/sync-api.js.map +1 -0
- package/dist/server/routes/ws.d.ts +4 -2
- package/dist/server/routes/ws.js +100 -4
- package/dist/server/routes/ws.js.map +1 -1
- package/dist/server/session-manager.d.ts +40 -0
- package/dist/server/session-manager.js +132 -0
- package/dist/server/session-manager.js.map +1 -0
- package/dist/server/ws-hub.d.ts +95 -1
- package/dist/server/ws-hub.js +192 -5
- package/dist/server/ws-hub.js.map +1 -1
- package/dist/server/yjs-manager.d.ts +59 -0
- package/dist/server/yjs-manager.js +194 -0
- package/dist/server/yjs-manager.js.map +1 -0
- package/dist/services/auth-service.d.ts +30 -2
- package/dist/services/auth-service.js +116 -11
- package/dist/services/auth-service.js.map +1 -1
- package/dist/services/git.d.ts +6 -0
- package/dist/services/git.js +32 -2
- package/dist/services/git.js.map +1 -1
- package/dist/services/sync/collection-sync.d.ts +73 -0
- package/dist/services/sync/collection-sync.js +726 -0
- package/dist/services/sync/collection-sync.js.map +1 -0
- package/dist/services/sync/commit.js +5 -20
- package/dist/services/sync/commit.js.map +1 -1
- package/dist/services/sync/data-fetcher.d.ts +31 -0
- package/dist/services/sync/data-fetcher.js +12 -0
- package/dist/services/sync/data-fetcher.js.map +1 -0
- package/dist/services/sync/entity-refresh.d.ts +30 -0
- package/dist/services/sync/entity-refresh.js +275 -0
- package/dist/services/sync/entity-refresh.js.map +1 -0
- package/dist/services/sync/frontmatter-extractor.d.ts +2 -2
- package/dist/services/sync/frontmatter-extractor.js +1 -2
- package/dist/services/sync/frontmatter-extractor.js.map +1 -1
- package/dist/services/sync/graph-match.js +1 -1
- package/dist/services/sync/graph-match.js.map +1 -1
- package/dist/services/sync/mcp-client.d.ts +16 -4
- package/dist/services/sync/mcp-client.js +34 -20
- package/dist/services/sync/mcp-client.js.map +1 -1
- package/dist/services/sync/prompts.js +1 -1
- package/dist/services/sync/reconciler.js +1 -2
- package/dist/services/sync/reconciler.js.map +1 -1
- package/dist/services/sync/rest-client.d.ts +40 -0
- package/dist/services/sync/rest-client.js +100 -0
- package/dist/services/sync/rest-client.js.map +1 -0
- package/dist/services/sync/source-config.d.ts +23 -1
- package/dist/services/sync/source-config.js +112 -16
- package/dist/services/sync/source-config.js.map +1 -1
- package/dist/services/sync/source-definitions/asana.d.ts +3 -4
- package/dist/services/sync/source-definitions/asana.js +7 -13
- package/dist/services/sync/source-definitions/asana.js.map +1 -1
- package/dist/services/sync/source-definitions/definitions.d.ts +5 -18
- package/dist/services/sync/source-definitions/definitions.js +4 -22
- package/dist/services/sync/source-definitions/definitions.js.map +1 -1
- package/dist/services/sync/source-definitions/granola.d.ts +1 -1
- package/dist/services/sync/source-definitions/granola.js +11 -18
- package/dist/services/sync/source-definitions/granola.js.map +1 -1
- package/dist/services/sync/source-definitions/linear.d.ts +1 -1
- package/dist/services/sync/source-definitions/linear.js +17 -15
- package/dist/services/sync/source-definitions/linear.js.map +1 -1
- package/dist/services/sync/source-definitions/pipedrive.d.ts +1 -1
- package/dist/services/sync/source-definitions/pipedrive.js +6 -15
- package/dist/services/sync/source-definitions/pipedrive.js.map +1 -1
- package/dist/services/sync/staging.js +1 -2
- package/dist/services/sync/staging.js.map +1 -1
- package/dist/services/sync/structured-extractor.d.ts +8 -2
- package/dist/services/sync/structured-extractor.js +243 -35
- package/dist/services/sync/structured-extractor.js.map +1 -1
- package/dist/services/sync/types.d.ts +192 -23
- package/dist/services/sync/unstructured-extractor.d.ts +1 -3
- package/dist/services/sync/unstructured-extractor.js +2 -14
- package/dist/services/sync/unstructured-extractor.js.map +1 -1
- package/dist/utils/git.d.ts +24 -20
- package/dist/utils/git.js +99 -65
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/preflight.d.ts +1 -15
- package/dist/utils/preflight.js +1 -35
- package/dist/utils/preflight.js.map +1 -1
- package/dist/web/_app/immutable/assets/0.CupILLQs.css +1 -0
- package/dist/web/_app/immutable/assets/3.CtJi4Cy9.css +1 -0
- package/dist/web/_app/immutable/assets/5.CydFyZSu.css +1 -0
- package/dist/web/_app/immutable/assets/6.kqeOo0OW.css +1 -0
- package/dist/web/_app/immutable/assets/7.CseIx7qQ.css +1 -0
- package/dist/web/_app/immutable/assets/{8.Sm6jB3a0.css → 8.BYpFDZHK.css} +1 -1
- package/dist/web/_app/immutable/assets/AppShell.Ch_ef9hJ.css +1 -0
- package/dist/web/_app/immutable/assets/ChatPanel.CP-_8txt.css +1 -0
- package/dist/web/_app/immutable/chunks/0oxpWEgM.js +1 -0
- package/dist/web/_app/immutable/chunks/B1y7Wy5O.js +18 -0
- package/dist/web/_app/immutable/chunks/B7eduG_j.js +64 -0
- package/dist/web/_app/immutable/chunks/BBLgaWN8.js +1 -0
- package/dist/web/_app/immutable/chunks/BCB5cYCz.js +2 -0
- package/dist/web/_app/immutable/chunks/{aosHekRC.js → BPUy9_sS.js} +1 -1
- package/dist/web/_app/immutable/chunks/BVBRzmeQ.js +7 -0
- package/dist/web/_app/immutable/chunks/{CUzqHQY_.js → BXuvR8Ks.js} +2 -1
- package/dist/web/_app/immutable/chunks/BeBar3OL.js +1 -0
- package/dist/web/_app/immutable/chunks/BuOTIbJu.js +1 -0
- package/dist/web/_app/immutable/chunks/CLFba8FK.js +5 -0
- package/dist/web/_app/immutable/chunks/CQCkXCml.js +1 -0
- package/dist/web/_app/immutable/chunks/CXuhHL4d.js +1 -0
- package/dist/web/_app/immutable/chunks/Cg9NOuOl.js +27 -0
- package/dist/web/_app/immutable/chunks/Cs5oz2oJ.js +5 -0
- package/dist/web/_app/immutable/chunks/Cs_ROD7H.js +2 -0
- package/dist/web/_app/immutable/chunks/D2aTbzFm.js +3 -0
- package/dist/web/_app/immutable/chunks/D4FXhiC2.js +1 -0
- package/dist/web/_app/immutable/chunks/D4VHRYeB.js +1 -0
- package/dist/web/_app/immutable/chunks/DCGSm8Hl.js +1 -0
- package/dist/web/_app/immutable/chunks/DP09rP34.js +2 -0
- package/dist/web/_app/immutable/chunks/DiP47fAp.js +1 -0
- package/dist/web/_app/immutable/chunks/DptGlK8O.js +1 -0
- package/dist/web/_app/immutable/chunks/O0fx2ss6.js +1 -0
- package/dist/web/_app/immutable/chunks/xBRYfpah.js +1 -0
- package/dist/web/_app/immutable/entry/app.FgnywZP_.js +2 -0
- package/dist/web/_app/immutable/entry/start.Bsa-zlPf.js +1 -0
- package/dist/web/_app/immutable/nodes/0.D3SW-LMc.js +10 -0
- package/dist/web/_app/immutable/nodes/1.y0c5TQTP.js +1 -0
- package/dist/web/_app/immutable/nodes/2.BQfSep9-.js +1 -0
- package/dist/web/_app/immutable/nodes/3.CC4Y-xMM.js +11 -0
- package/dist/web/_app/immutable/nodes/4.Dp0Z-oPW.js +4 -0
- package/dist/web/_app/immutable/nodes/5.gjZ03DON.js +2 -0
- package/dist/web/_app/immutable/nodes/6.dRNIwcJQ.js +1 -0
- package/dist/web/_app/immutable/nodes/7.I4Gjes3o.js +2 -0
- package/dist/web/_app/immutable/nodes/8.Dj14D7uH.js +1 -0
- package/dist/web/_app/version.json +1 -1
- package/dist/web/index.html +10 -12
- package/package.json +4 -2
- package/dist/web/_app/immutable/assets/0.CF0XhAap.css +0 -1
- package/dist/web/_app/immutable/assets/3.BJy7pVXi.css +0 -1
- package/dist/web/_app/immutable/assets/4.Ad16uh9o.css +0 -1
- package/dist/web/_app/immutable/assets/6.Bm2i7O0j.css +0 -1
- package/dist/web/_app/immutable/assets/7.Cn2DG-J6.css +0 -1
- package/dist/web/_app/immutable/assets/AppShell.CztjTuKY.css +0 -1
- package/dist/web/_app/immutable/assets/ChatPanel.RFD5GGYI.css +0 -1
- package/dist/web/_app/immutable/assets/editor.CPAf2SRV.css +0 -1
- package/dist/web/_app/immutable/chunks/4QY4j-jX.js +0 -1
- package/dist/web/_app/immutable/chunks/B3Kdf1r4.js +0 -6
- package/dist/web/_app/immutable/chunks/BIo3H1KR.js +0 -2
- package/dist/web/_app/immutable/chunks/BJLM1w2L.js +0 -23
- package/dist/web/_app/immutable/chunks/BLCwEMdm.js +0 -1
- package/dist/web/_app/immutable/chunks/BSYvCVJt.js +0 -1
- package/dist/web/_app/immutable/chunks/Ba5JX1o9.js +0 -1
- package/dist/web/_app/immutable/chunks/Bj34y868.js +0 -64
- package/dist/web/_app/immutable/chunks/BrWpHgBJ.js +0 -1
- package/dist/web/_app/immutable/chunks/C3g_lwol.js +0 -1
- package/dist/web/_app/immutable/chunks/CXnPm09s.js +0 -1
- package/dist/web/_app/immutable/chunks/ClOTom10.js +0 -1
- package/dist/web/_app/immutable/chunks/CtT4aw_G.js +0 -1
- package/dist/web/_app/immutable/chunks/Dh_H7Owr.js +0 -18
- package/dist/web/_app/immutable/chunks/DnlgZ_Tk.js +0 -5
- package/dist/web/_app/immutable/chunks/DtVH--hH.js +0 -6
- package/dist/web/_app/immutable/chunks/Dzd9kdLj.js +0 -2
- package/dist/web/_app/immutable/chunks/L91a_BGe.js +0 -1
- package/dist/web/_app/immutable/chunks/bHAllEMt.js +0 -1
- package/dist/web/_app/immutable/entry/app.CdrgaaFb.js +0 -2
- package/dist/web/_app/immutable/entry/start.t9LMjt48.js +0 -1
- package/dist/web/_app/immutable/nodes/0.P-Xfebn4.js +0 -2
- package/dist/web/_app/immutable/nodes/1.DiZlq1e6.js +0 -1
- package/dist/web/_app/immutable/nodes/2.ByIZ5J2p.js +0 -1
- package/dist/web/_app/immutable/nodes/3.D7JhktsZ.js +0 -1
- package/dist/web/_app/immutable/nodes/4.BtMeWbPx.js +0 -16
- package/dist/web/_app/immutable/nodes/5.CCYG1pbQ.js +0 -4
- package/dist/web/_app/immutable/nodes/6.CL_Ah04j.js +0 -2
- package/dist/web/_app/immutable/nodes/7.BMTaosAj.js +0 -1
- package/dist/web/_app/immutable/nodes/8.mrPg67cz.js +0 -1
- /package/dist/web/_app/immutable/assets/{5.BhKgiXd2.css → 4.BhKgiXd2.css} +0 -0
|
@@ -4,25 +4,21 @@
|
|
|
4
4
|
* Connects the Studiograph agent to third-party MCP servers so the agent can
|
|
5
5
|
* query external data sources on demand.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* Only HTTP transport is supported (Streamable HTTP). Connectors are configured
|
|
8
|
+
* with a URL and optional headers — same format as Cursor/Claude Code MCP configs.
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
-
* Requires `url` and `token` fields. Token can be a literal string or a
|
|
11
|
-
* $ENV_VAR reference resolved at runtime.
|
|
10
|
+
* Two-layer config:
|
|
12
11
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* Workspace layer (.studiograph/connectors/<name>.json)
|
|
13
|
+
* Non-secret transport config committed to git. Secrets replaced with
|
|
14
|
+
* $ENV_VAR placeholders resolved at runtime.
|
|
16
15
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* Connector configs are stored per-user at ~/.studiograph/connectors/<name>.json
|
|
22
|
-
* (mode 0600 — never committed to git).
|
|
16
|
+
* Homedir layer (~/.studiograph/connectors/<name>.json)
|
|
17
|
+
* Full config with literal secrets (mode 0600, never committed).
|
|
18
|
+
* When present, homedir fields override workspace fields.
|
|
23
19
|
*
|
|
24
20
|
* Each connector's tools are injected into the agent with a namespaced prefix:
|
|
25
|
-
* linear__search_issues,
|
|
21
|
+
* linear__search_issues, etc.
|
|
26
22
|
*
|
|
27
23
|
* Connection failures are non-fatal — the failing connector is skipped with a warning.
|
|
28
24
|
*/
|
|
@@ -31,63 +27,118 @@ import { join } from 'path';
|
|
|
31
27
|
import { homedir } from 'os';
|
|
32
28
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
33
29
|
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
34
|
-
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
35
|
-
import { auth } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
36
|
-
import { ConnectorOAuthProvider, waitForOAuthCallback } from './oauth-provider.js';
|
|
37
30
|
export const CONNECTORS_DIR = join(homedir(), '.studiograph', 'connectors');
|
|
31
|
+
/** Pre-listed connectors — derived from integration registry. */
|
|
32
|
+
export { KNOWN_CONNECTORS } from '../integrations/registry.js';
|
|
38
33
|
// ── ConnectorManager ──────────────────────────────────────────────────────────
|
|
39
34
|
export class ConnectorManager {
|
|
40
35
|
// ── config persistence ────────────────────────────────────────────────────
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
console.warn(`[connectors] Skipping malformed config (missing name): ${entry}`);
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
const resolved = ConnectorManager._resolveType(raw);
|
|
62
|
-
if (!ConnectorManager._validate(resolved, entry))
|
|
63
|
-
continue;
|
|
64
|
-
configs.push(resolved);
|
|
65
|
-
}
|
|
66
|
-
catch {
|
|
67
|
-
console.warn(`[connectors] Could not parse ${entry} — skipping`);
|
|
68
|
-
}
|
|
36
|
+
/**
|
|
37
|
+
* Load all connector configs, merging workspace + homedir layers.
|
|
38
|
+
* When workspacePath is provided, reads .studiograph/connectors/ first,
|
|
39
|
+
* then overlays homedir configs (homedir fields win).
|
|
40
|
+
*/
|
|
41
|
+
static loadConfigs(workspacePath) {
|
|
42
|
+
const workspaceConfigs = workspacePath
|
|
43
|
+
? ConnectorManager._readDir(join(workspacePath, '.studiograph', 'connectors'))
|
|
44
|
+
: [];
|
|
45
|
+
const homedirConfigs = ConnectorManager._readDir(CONNECTORS_DIR);
|
|
46
|
+
// Merge: workspace as base, homedir overrides
|
|
47
|
+
const merged = new Map();
|
|
48
|
+
for (const c of workspaceConfigs)
|
|
49
|
+
merged.set(c.name, c);
|
|
50
|
+
for (const c of homedirConfigs) {
|
|
51
|
+
const base = merged.get(c.name);
|
|
52
|
+
merged.set(c.name, base ? ConnectorManager._merge(base, c) : c);
|
|
69
53
|
}
|
|
70
|
-
return
|
|
54
|
+
return Array.from(merged.values());
|
|
71
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Load connector configs from workspace .studiograph/connectors/ only.
|
|
58
|
+
* Used by the config bundle export endpoint.
|
|
59
|
+
*/
|
|
60
|
+
static loadWorkspaceConfigs(workspacePath) {
|
|
61
|
+
return ConnectorManager._readDir(join(workspacePath, '.studiograph', 'connectors'));
|
|
62
|
+
}
|
|
63
|
+
/** Save full config to homedir (mode 0600, never committed). */
|
|
72
64
|
static saveConfig(config) {
|
|
73
65
|
mkdirSync(CONNECTORS_DIR, { recursive: true });
|
|
74
66
|
const path = join(CONNECTORS_DIR, `${config.name}.json`);
|
|
75
67
|
writeFileSync(path, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
|
|
76
68
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
69
|
+
/** Save sanitized config to workspace .studiograph/connectors/ (git-tracked). */
|
|
70
|
+
static saveWorkspaceConfig(config, workspacePath) {
|
|
71
|
+
const dir = join(workspacePath, '.studiograph', 'connectors');
|
|
72
|
+
mkdirSync(dir, { recursive: true });
|
|
73
|
+
const stripped = ConnectorManager.stripSecrets(config);
|
|
74
|
+
const path = join(dir, `${config.name}.json`);
|
|
75
|
+
writeFileSync(path, JSON.stringify(stripped, null, 2) + '\n');
|
|
83
76
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (
|
|
88
|
-
|
|
77
|
+
static removeConfig(name, workspacePath) {
|
|
78
|
+
let removed = false;
|
|
79
|
+
const hdPath = join(CONNECTORS_DIR, `${name}.json`);
|
|
80
|
+
if (existsSync(hdPath)) {
|
|
81
|
+
unlinkSync(hdPath);
|
|
82
|
+
removed = true;
|
|
83
|
+
}
|
|
84
|
+
if (workspacePath) {
|
|
85
|
+
const wsPath = join(workspacePath, '.studiograph', 'connectors', `${name}.json`);
|
|
86
|
+
if (existsSync(wsPath)) {
|
|
87
|
+
unlinkSync(wsPath);
|
|
88
|
+
removed = true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return removed;
|
|
92
|
+
}
|
|
93
|
+
/** Load a single connector, merging workspace + homedir layers. */
|
|
94
|
+
static loadConfig(name, workspacePath) {
|
|
95
|
+
let wsConfig = null;
|
|
96
|
+
if (workspacePath) {
|
|
97
|
+
const wsPath = join(workspacePath, '.studiograph', 'connectors', `${name}.json`);
|
|
98
|
+
if (existsSync(wsPath)) {
|
|
99
|
+
try {
|
|
100
|
+
wsConfig = (JSON.parse(readFileSync(wsPath, 'utf-8')));
|
|
101
|
+
}
|
|
102
|
+
catch { /* skip */ }
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
let hdConfig = null;
|
|
106
|
+
const hdPath = join(CONNECTORS_DIR, `${name}.json`);
|
|
107
|
+
if (existsSync(hdPath)) {
|
|
108
|
+
try {
|
|
109
|
+
hdConfig = (JSON.parse(readFileSync(hdPath, 'utf-8')));
|
|
110
|
+
}
|
|
111
|
+
catch { /* skip */ }
|
|
89
112
|
}
|
|
90
|
-
|
|
113
|
+
if (!wsConfig && !hdConfig)
|
|
114
|
+
return null;
|
|
115
|
+
if (!wsConfig)
|
|
116
|
+
return hdConfig;
|
|
117
|
+
if (!hdConfig)
|
|
118
|
+
return wsConfig;
|
|
119
|
+
return ConnectorManager._merge(wsConfig, hdConfig);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Strip secret fields from a connector config, replacing them with $ENV_VAR
|
|
123
|
+
* placeholders. Safe to commit to git.
|
|
124
|
+
*/
|
|
125
|
+
static stripSecrets(config) {
|
|
126
|
+
const stripped = { ...config };
|
|
127
|
+
// Strip Authorization header
|
|
128
|
+
if (stripped.headers) {
|
|
129
|
+
stripped.headers = { ...stripped.headers };
|
|
130
|
+
for (const [key, value] of Object.entries(stripped.headers)) {
|
|
131
|
+
if (key.toLowerCase() === 'authorization' && !value.startsWith('$')) {
|
|
132
|
+
stripped.headers[key] = `$${config.name.toUpperCase().replace(/-/g, '_')}_AUTH`;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return stripped;
|
|
137
|
+
}
|
|
138
|
+
/** Expands $ENV_VAR references; returns the literal string otherwise. */
|
|
139
|
+
static resolveEnvVar(value) {
|
|
140
|
+
// Replace $ENV_VAR references anywhere in the string
|
|
141
|
+
return value.replace(/\$([A-Z_][A-Z0-9_]*)/g, (match, name) => process.env[name] ?? match);
|
|
91
142
|
}
|
|
92
143
|
// ── tool building ─────────────────────────────────────────────────────────
|
|
93
144
|
/**
|
|
@@ -114,80 +165,77 @@ export class ConnectorManager {
|
|
|
114
165
|
console.warn(`[connectors] ${config.name} skipped — local server not running (${config.url})`);
|
|
115
166
|
}
|
|
116
167
|
else {
|
|
117
|
-
console.warn(`[connectors] Failed to connect to "${config.name}" (${config.
|
|
168
|
+
console.warn(`[connectors] Failed to connect to "${config.name}" (${config.url}): ${msg}`);
|
|
118
169
|
}
|
|
119
170
|
}
|
|
120
171
|
}
|
|
121
172
|
return tools;
|
|
122
173
|
}
|
|
123
174
|
// ── private helpers ───────────────────────────────────────────────────────
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (!config.command) {
|
|
135
|
-
console.warn(`[connectors] stdio connector "${config.name}" missing "command" — skipping`);
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
175
|
+
/** Read all valid connector configs from a directory. */
|
|
176
|
+
static _readDir(dir) {
|
|
177
|
+
if (!existsSync(dir))
|
|
178
|
+
return [];
|
|
179
|
+
let entries;
|
|
180
|
+
try {
|
|
181
|
+
entries = readdirSync(dir);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return [];
|
|
138
185
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
186
|
+
const configs = [];
|
|
187
|
+
for (const entry of entries) {
|
|
188
|
+
if (!entry.endsWith('.json'))
|
|
189
|
+
continue;
|
|
190
|
+
try {
|
|
191
|
+
const raw = JSON.parse(readFileSync(join(dir, entry), 'utf-8'));
|
|
192
|
+
if (typeof raw.name !== 'string' || !raw.name) {
|
|
193
|
+
console.warn(`[connectors] Skipping malformed config (missing name): ${entry}`);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const resolved = (raw);
|
|
197
|
+
if (!ConnectorManager._validate(resolved, entry))
|
|
198
|
+
continue;
|
|
199
|
+
configs.push(resolved);
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
console.warn(`[connectors] Could not parse ${entry} — skipping`);
|
|
143
203
|
}
|
|
144
204
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
205
|
+
return configs;
|
|
206
|
+
}
|
|
207
|
+
/** Merge two configs for the same connector — overlay fields win over base. */
|
|
208
|
+
static _merge(base, overlay) {
|
|
209
|
+
const merged = { ...base };
|
|
210
|
+
for (const [key, value] of Object.entries(overlay)) {
|
|
211
|
+
if (value !== undefined && value !== null) {
|
|
212
|
+
if (key === 'headers' && merged.headers) {
|
|
213
|
+
merged.headers = { ...merged.headers, ...value };
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
merged[key] = value;
|
|
217
|
+
}
|
|
149
218
|
}
|
|
150
219
|
}
|
|
220
|
+
return merged;
|
|
221
|
+
}
|
|
222
|
+
static _validate(config, filename) {
|
|
223
|
+
if (!config.url) {
|
|
224
|
+
console.warn(`[connectors] connector "${config.name}" missing "url" — skipping`);
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
151
227
|
return true;
|
|
152
228
|
}
|
|
153
229
|
static async _buildConnectorTools(config) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
env: config.env,
|
|
160
|
-
stderr: 'ignore',
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
else if (config.type === 'oauth') {
|
|
164
|
-
// Pre-authorize before connecting.
|
|
165
|
-
// The SDK only auto-triggers OAuth on 401, but some servers (Figma) return 403
|
|
166
|
-
// for unauthenticated requests. We drive the flow manually to handle both.
|
|
167
|
-
const authProvider = new ConnectorOAuthProvider(config.name);
|
|
168
|
-
const result = await auth(authProvider, {
|
|
169
|
-
serverUrl: config.url,
|
|
170
|
-
});
|
|
171
|
-
if (result === 'REDIRECT') {
|
|
172
|
-
// Browser was opened — wait for the user to authorize
|
|
173
|
-
console.log(`[connectors] ${config.name} requires authorization — waiting for browser...`);
|
|
174
|
-
const code = await waitForOAuthCallback();
|
|
175
|
-
// Exchange the authorization code for tokens
|
|
176
|
-
await auth(authProvider, {
|
|
177
|
-
serverUrl: config.url,
|
|
178
|
-
authorizationCode: code,
|
|
179
|
-
});
|
|
230
|
+
// Resolve any $ENV_VAR references in headers
|
|
231
|
+
const headers = {};
|
|
232
|
+
if (config.headers) {
|
|
233
|
+
for (const [key, value] of Object.entries(config.headers)) {
|
|
234
|
+
headers[key] = ConnectorManager.resolveEnvVar(value);
|
|
180
235
|
}
|
|
181
|
-
transport = new StreamableHTTPClientTransport(new URL(config.url), {
|
|
182
|
-
authProvider,
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
const requestInit = config.token
|
|
187
|
-
? { headers: { Authorization: `Bearer ${ConnectorManager.resolveToken(config.token)}` } }
|
|
188
|
-
: {};
|
|
189
|
-
transport = new StreamableHTTPClientTransport(new URL(config.url), { requestInit });
|
|
190
236
|
}
|
|
237
|
+
const requestInit = Object.keys(headers).length > 0 ? { headers } : {};
|
|
238
|
+
const transport = new StreamableHTTPClientTransport(new URL(config.url), { requestInit });
|
|
191
239
|
const client = new Client({ name: 'studiograph', version: '1.0.0' });
|
|
192
240
|
await client.connect(transport);
|
|
193
241
|
const { tools: remoteTools } = await client.listTools();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connector-manager.js","sourceRoot":"","sources":["../../src/mcp/connector-manager.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"connector-manager.js","sourceRoot":"","sources":["../../src/mcp/connector-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-Side OAuth Provider for MCP Connectors
|
|
3
|
+
*
|
|
4
|
+
* Implements OAuthClientProvider backed by SQLite (per-user tokens)
|
|
5
|
+
* instead of local files. Used by the web UI OAuth flow:
|
|
6
|
+
*
|
|
7
|
+
* 1. User clicks "Connect" → POST /api/connectors/:name/oauth/authorize
|
|
8
|
+
* 2. Server calls auth(provider, { serverUrl }) → SDK discovers metadata,
|
|
9
|
+
* registers client, generates PKCE, calls redirectToAuthorization(url)
|
|
10
|
+
* 3. Provider stores the auth URL (doesn't open a browser)
|
|
11
|
+
* 4. Route returns { authorizationUrl } → frontend opens in new tab
|
|
12
|
+
* 5. User authorizes → callback to GET /api/oauth/callback/:name?code=...
|
|
13
|
+
* 6. Server calls auth(provider, { serverUrl, authorizationCode: code })
|
|
14
|
+
* 7. SDK exchanges code for tokens → provider.saveTokens() → SQLite
|
|
15
|
+
*
|
|
16
|
+
* Unlike ConnectorOAuthProvider (file-backed, opens browser), this works
|
|
17
|
+
* on remote deployments (Railway) and stores tokens per-user.
|
|
18
|
+
*/
|
|
19
|
+
import type { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
20
|
+
import type { OAuthClientMetadata, OAuthClientInformationMixed, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
21
|
+
import type { AuthService } from '../services/auth-service.js';
|
|
22
|
+
import type { OAuthAppConfig } from '../integrations/types.js';
|
|
23
|
+
/** Encode userId + connectorName + origin into the OAuth state parameter.
|
|
24
|
+
* The origin is included so the auth proxy can redirect back to the correct instance. */
|
|
25
|
+
export declare function encodeOAuthState(userId: number, connectorName: string, origin?: string): string;
|
|
26
|
+
/** Decode the OAuth state parameter. */
|
|
27
|
+
export declare function decodeOAuthState(state: string): {
|
|
28
|
+
userId: number;
|
|
29
|
+
connectorName: string;
|
|
30
|
+
origin?: string;
|
|
31
|
+
} | null;
|
|
32
|
+
export declare class ServerOAuthProvider implements OAuthClientProvider {
|
|
33
|
+
private connectorName;
|
|
34
|
+
private userId;
|
|
35
|
+
private authService;
|
|
36
|
+
/** Set by redirectToAuthorization() — read by the route handler after auth() returns. */
|
|
37
|
+
authorizationUrl: string | null;
|
|
38
|
+
private redirectUri;
|
|
39
|
+
private serverUrl;
|
|
40
|
+
/** Pre-registered OAuth app config (client_id + optional secret). */
|
|
41
|
+
private oauthApp?;
|
|
42
|
+
constructor(connectorName: string, userId: number, authService: AuthService, serverUrl: string, oauthApp?: OAuthAppConfig);
|
|
43
|
+
get redirectUrl(): URL;
|
|
44
|
+
get clientMetadata(): OAuthClientMetadata;
|
|
45
|
+
state(): Promise<string>;
|
|
46
|
+
clientInformation(): Promise<OAuthClientInformationMixed | undefined>;
|
|
47
|
+
saveClientInformation(info: OAuthClientInformationMixed): Promise<void>;
|
|
48
|
+
tokens(): Promise<OAuthTokens | undefined>;
|
|
49
|
+
saveTokens(tokens: OAuthTokens): Promise<void>;
|
|
50
|
+
redirectToAuthorization(authorizationUrl: URL): Promise<void>;
|
|
51
|
+
saveCodeVerifier(codeVerifier: string): Promise<void>;
|
|
52
|
+
codeVerifier(): Promise<string>;
|
|
53
|
+
invalidateCredentials(scope: 'all' | 'client' | 'tokens' | 'verifier'): Promise<void>;
|
|
54
|
+
private _load;
|
|
55
|
+
private _save;
|
|
56
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-Side OAuth Provider for MCP Connectors
|
|
3
|
+
*
|
|
4
|
+
* Implements OAuthClientProvider backed by SQLite (per-user tokens)
|
|
5
|
+
* instead of local files. Used by the web UI OAuth flow:
|
|
6
|
+
*
|
|
7
|
+
* 1. User clicks "Connect" → POST /api/connectors/:name/oauth/authorize
|
|
8
|
+
* 2. Server calls auth(provider, { serverUrl }) → SDK discovers metadata,
|
|
9
|
+
* registers client, generates PKCE, calls redirectToAuthorization(url)
|
|
10
|
+
* 3. Provider stores the auth URL (doesn't open a browser)
|
|
11
|
+
* 4. Route returns { authorizationUrl } → frontend opens in new tab
|
|
12
|
+
* 5. User authorizes → callback to GET /api/oauth/callback/:name?code=...
|
|
13
|
+
* 6. Server calls auth(provider, { serverUrl, authorizationCode: code })
|
|
14
|
+
* 7. SDK exchanges code for tokens → provider.saveTokens() → SQLite
|
|
15
|
+
*
|
|
16
|
+
* Unlike ConnectorOAuthProvider (file-backed, opens browser), this works
|
|
17
|
+
* on remote deployments (Railway) and stores tokens per-user.
|
|
18
|
+
*/
|
|
19
|
+
/** Encode userId + connectorName + origin into the OAuth state parameter.
|
|
20
|
+
* The origin is included so the auth proxy can redirect back to the correct instance. */
|
|
21
|
+
export function encodeOAuthState(userId, connectorName, origin) {
|
|
22
|
+
const payload = { u: userId, c: connectorName };
|
|
23
|
+
if (origin)
|
|
24
|
+
payload.o = origin;
|
|
25
|
+
return Buffer.from(JSON.stringify(payload)).toString('base64url');
|
|
26
|
+
}
|
|
27
|
+
/** Decode the OAuth state parameter. */
|
|
28
|
+
export function decodeOAuthState(state) {
|
|
29
|
+
try {
|
|
30
|
+
const parsed = JSON.parse(Buffer.from(state, 'base64url').toString('utf-8'));
|
|
31
|
+
if (typeof parsed.u === 'number' && typeof parsed.c === 'string') {
|
|
32
|
+
return { userId: parsed.u, connectorName: parsed.c, origin: parsed.o };
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Auth proxy URL for pre-registered OAuth apps (single callback URL per provider). */
|
|
41
|
+
const AUTH_PROXY_URL = process.env.STUDIOGRAPH_AUTH_PROXY_URL ?? 'https://auth.studiograph.com';
|
|
42
|
+
export class ServerOAuthProvider {
|
|
43
|
+
connectorName;
|
|
44
|
+
userId;
|
|
45
|
+
authService;
|
|
46
|
+
/** Set by redirectToAuthorization() — read by the route handler after auth() returns. */
|
|
47
|
+
authorizationUrl = null;
|
|
48
|
+
redirectUri;
|
|
49
|
+
serverUrl;
|
|
50
|
+
/** Pre-registered OAuth app config (client_id + optional secret). */
|
|
51
|
+
oauthApp;
|
|
52
|
+
constructor(connectorName, userId, authService, serverUrl, oauthApp) {
|
|
53
|
+
this.connectorName = connectorName;
|
|
54
|
+
this.userId = userId;
|
|
55
|
+
this.authService = authService;
|
|
56
|
+
this.serverUrl = serverUrl.replace(/\/+$/, '');
|
|
57
|
+
this.oauthApp = oauthApp;
|
|
58
|
+
if (oauthApp) {
|
|
59
|
+
// Pre-registered app: callback goes through the auth proxy
|
|
60
|
+
this.redirectUri = `${AUTH_PROXY_URL}/callback/${encodeURIComponent(connectorName)}`;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
// Dynamic registration: callback goes directly to this instance
|
|
64
|
+
this.redirectUri = `${this.serverUrl}/api/oauth/callback/${encodeURIComponent(connectorName)}`;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
get redirectUrl() {
|
|
68
|
+
return new URL(this.redirectUri);
|
|
69
|
+
}
|
|
70
|
+
get clientMetadata() {
|
|
71
|
+
return {
|
|
72
|
+
redirect_uris: [this.redirectUri],
|
|
73
|
+
client_name: 'Studiograph',
|
|
74
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
75
|
+
response_types: ['code'],
|
|
76
|
+
token_endpoint_auth_method: this.oauthApp?.client_secret_env ? 'client_secret_post' : 'none',
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
async state() {
|
|
80
|
+
// Include origin URL so the auth proxy can redirect back to this instance
|
|
81
|
+
return encodeOAuthState(this.userId, this.connectorName, this.oauthApp ? this.serverUrl : undefined);
|
|
82
|
+
}
|
|
83
|
+
async clientInformation() {
|
|
84
|
+
// Pre-registered client info takes priority — skips dynamic registration
|
|
85
|
+
if (this.oauthApp) {
|
|
86
|
+
const info = { client_id: this.oauthApp.client_id };
|
|
87
|
+
if (this.oauthApp.client_secret_env) {
|
|
88
|
+
info.client_secret = process.env[this.oauthApp.client_secret_env] ?? '';
|
|
89
|
+
}
|
|
90
|
+
return info;
|
|
91
|
+
}
|
|
92
|
+
// Fall back to dynamically registered client info from storage
|
|
93
|
+
return this._load().clientInfo;
|
|
94
|
+
}
|
|
95
|
+
async saveClientInformation(info) {
|
|
96
|
+
const data = this._load();
|
|
97
|
+
data.clientInfo = info;
|
|
98
|
+
this._save(data);
|
|
99
|
+
}
|
|
100
|
+
async tokens() {
|
|
101
|
+
return this._load().tokens;
|
|
102
|
+
}
|
|
103
|
+
async saveTokens(tokens) {
|
|
104
|
+
const data = this._load();
|
|
105
|
+
data.tokens = tokens;
|
|
106
|
+
this._save(data);
|
|
107
|
+
}
|
|
108
|
+
async redirectToAuthorization(authorizationUrl) {
|
|
109
|
+
// Don't open a browser — store the URL for the route handler to return
|
|
110
|
+
this.authorizationUrl = authorizationUrl.toString();
|
|
111
|
+
}
|
|
112
|
+
async saveCodeVerifier(codeVerifier) {
|
|
113
|
+
const data = this._load();
|
|
114
|
+
data.codeVerifier = codeVerifier;
|
|
115
|
+
this._save(data);
|
|
116
|
+
}
|
|
117
|
+
async codeVerifier() {
|
|
118
|
+
return this._load().codeVerifier ?? '';
|
|
119
|
+
}
|
|
120
|
+
async invalidateCredentials(scope) {
|
|
121
|
+
const data = this._load();
|
|
122
|
+
if (scope === 'all' || scope === 'tokens')
|
|
123
|
+
data.tokens = undefined;
|
|
124
|
+
if (scope === 'all' || scope === 'client')
|
|
125
|
+
data.clientInfo = undefined;
|
|
126
|
+
if (scope === 'all' || scope === 'verifier')
|
|
127
|
+
data.codeVerifier = undefined;
|
|
128
|
+
this._save(data);
|
|
129
|
+
}
|
|
130
|
+
// ── storage helpers ──────────────────────────────────────────────────────
|
|
131
|
+
_load() {
|
|
132
|
+
return this.authService.getOAuthData(this.userId, this.connectorName) ?? {};
|
|
133
|
+
}
|
|
134
|
+
_save(data) {
|
|
135
|
+
this.authService.saveOAuthData(this.userId, this.connectorName, data);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=server-oauth-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-oauth-provider.js","sourceRoot":"","sources":["../../src/mcp/server-oauth-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAmBH;0FAC0F;AAC1F,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,aAAqB,EAAE,MAAe;IACrF,MAAM,OAAO,GAAwB,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC;IACrE,IAAI,MAAM;QAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC;IAC/B,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AACpE,CAAC;AAED,wCAAwC;AACxC,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7E,IAAI,OAAO,MAAM,CAAC,CAAC,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;YACjE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;QACzE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,uFAAuF;AACvF,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,8BAA8B,CAAC;AAEhG,MAAM,OAAO,mBAAmB;IAWpB;IACA;IACA;IAZV,yFAAyF;IACzF,gBAAgB,GAAkB,IAAI,CAAC;IAE/B,WAAW,CAAS;IACpB,SAAS,CAAS;IAE1B,qEAAqE;IAC7D,QAAQ,CAAkB;IAElC,YACU,aAAqB,EACrB,MAAc,EACd,WAAwB,EAChC,SAAiB,EACjB,QAAyB;QAJjB,kBAAa,GAAb,aAAa,CAAQ;QACrB,WAAM,GAAN,MAAM,CAAQ;QACd,gBAAW,GAAX,WAAW,CAAa;QAIhC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC/C,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAEzB,IAAI,QAAQ,EAAE,CAAC;YACb,2DAA2D;YAC3D,IAAI,CAAC,WAAW,GAAG,GAAG,cAAc,aAAa,kBAAkB,CAAC,aAAa,CAAC,EAAE,CAAC;QACvF,CAAC;aAAM,CAAC;YACN,gEAAgE;YAChE,IAAI,CAAC,WAAW,GAAG,GAAG,IAAI,CAAC,SAAS,uBAAuB,kBAAkB,CAAC,aAAa,CAAC,EAAE,CAAC;QACjG,CAAC;IACH,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,cAAc;QAChB,OAAO;YACL,aAAa,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC;YACjC,WAAW,EAAE,aAAa;YAC1B,WAAW,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;YACpD,cAAc,EAAE,CAAC,MAAM,CAAC;YACxB,0BAA0B,EAAE,IAAI,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,MAAM;SAC7F,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,KAAK;QACT,0EAA0E;QAC1E,OAAO,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACvG,CAAC;IAED,KAAK,CAAC,iBAAiB;QACrB,yEAAyE;QACzE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,GAAgC,EAAE,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YACjF,IAAI,IAAI,CAAC,QAAQ,CAAC,iBAAiB,EAAE,CAAC;gBACpC,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC;YAC1E,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,+DAA+D;QAC/D,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,IAAiC;QAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,MAAM;QACV,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,MAAmB;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,uBAAuB,CAAC,gBAAqB;QACjD,uEAAuE;QACvE,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC,QAAQ,EAAE,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,YAAoB;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,YAAY,IAAI,EAAE,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,KAA+C;QACzE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,QAAQ;YAAE,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QACnE,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,QAAQ;YAAE,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QACvE,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,UAAU;YAAE,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;QAC3E,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,4EAA4E;IAEpE,KAAK;QACX,OAAQ,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,CAAqB,IAAI,EAAE,CAAC;IACnG,CAAC;IAEO,KAAK,CAAC,IAAqB;QACjC,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IACxE,CAAC;CACF"}
|