integrate-sdk 0.6.4 → 0.6.6

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.
@@ -0,0 +1,268 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, {
5
+ get: all[name],
6
+ enumerable: true,
7
+ configurable: true,
8
+ set: (newValue) => all[name] = () => newValue
9
+ });
10
+ };
11
+
12
+ // src/adapters/base-handler.ts
13
+ var MCP_SERVER_URL = "https://mcp.integrate.dev/api/v1/mcp";
14
+
15
+ class OAuthHandler {
16
+ config;
17
+ serverUrl;
18
+ apiKey;
19
+ constructor(config) {
20
+ this.config = config;
21
+ if (!config || !config.providers) {
22
+ throw new Error("OAuthHandler requires a valid config with providers");
23
+ }
24
+ this.serverUrl = config.serverUrl || MCP_SERVER_URL;
25
+ this.apiKey = config.apiKey;
26
+ }
27
+ getHeaders(additionalHeaders) {
28
+ const headers = {
29
+ ...additionalHeaders
30
+ };
31
+ if (this.apiKey) {
32
+ headers["X-API-KEY"] = this.apiKey;
33
+ }
34
+ return headers;
35
+ }
36
+ async handleAuthorize(request) {
37
+ const providerConfig = this.config.providers[request.provider];
38
+ if (!providerConfig) {
39
+ throw new Error(`Provider ${request.provider} not configured. Add OAuth credentials to your API route configuration.`);
40
+ }
41
+ if (!providerConfig.clientId || !providerConfig.clientSecret) {
42
+ throw new Error(`Missing OAuth credentials for ${request.provider}. Check your environment variables.`);
43
+ }
44
+ const url = new URL("/oauth/authorize", this.serverUrl);
45
+ url.searchParams.set("provider", request.provider);
46
+ url.searchParams.set("client_id", providerConfig.clientId);
47
+ url.searchParams.set("client_secret", providerConfig.clientSecret);
48
+ url.searchParams.set("scope", request.scopes.join(","));
49
+ url.searchParams.set("state", request.state);
50
+ url.searchParams.set("code_challenge", request.codeChallenge);
51
+ url.searchParams.set("code_challenge_method", request.codeChallengeMethod);
52
+ const redirectUri = request.redirectUri || providerConfig.redirectUri;
53
+ if (redirectUri) {
54
+ url.searchParams.set("redirect_uri", redirectUri);
55
+ }
56
+ const response = await fetch(url.toString(), {
57
+ method: "GET",
58
+ headers: this.getHeaders()
59
+ });
60
+ if (!response.ok) {
61
+ const error = await response.text();
62
+ throw new Error(`MCP server failed to generate authorization URL: ${error}`);
63
+ }
64
+ const data = await response.json();
65
+ return data;
66
+ }
67
+ async handleCallback(request) {
68
+ const providerConfig = this.config.providers[request.provider];
69
+ if (!providerConfig) {
70
+ throw new Error(`Provider ${request.provider} not configured. Add OAuth credentials to your API route configuration.`);
71
+ }
72
+ if (!providerConfig.clientId || !providerConfig.clientSecret) {
73
+ throw new Error(`Missing OAuth credentials for ${request.provider}. Check your environment variables.`);
74
+ }
75
+ const url = new URL("/oauth/callback", this.serverUrl);
76
+ const response = await fetch(url.toString(), {
77
+ method: "POST",
78
+ headers: this.getHeaders({
79
+ "Content-Type": "application/json"
80
+ }),
81
+ body: JSON.stringify({
82
+ provider: request.provider,
83
+ code: request.code,
84
+ code_verifier: request.codeVerifier,
85
+ state: request.state,
86
+ client_id: providerConfig.clientId,
87
+ client_secret: providerConfig.clientSecret,
88
+ redirect_uri: providerConfig.redirectUri
89
+ })
90
+ });
91
+ if (!response.ok) {
92
+ const error = await response.text();
93
+ throw new Error(`MCP server failed to exchange authorization code: ${error}`);
94
+ }
95
+ const data = await response.json();
96
+ return data;
97
+ }
98
+ async handleStatus(provider, accessToken) {
99
+ const url = new URL("/oauth/status", this.serverUrl);
100
+ url.searchParams.set("provider", provider);
101
+ const response = await fetch(url.toString(), {
102
+ method: "GET",
103
+ headers: this.getHeaders({
104
+ Authorization: `Bearer ${accessToken}`
105
+ })
106
+ });
107
+ if (!response.ok) {
108
+ if (response.status === 401) {
109
+ return {
110
+ authorized: false
111
+ };
112
+ }
113
+ const error = await response.text();
114
+ throw new Error(`MCP server failed to check authorization status: ${error}`);
115
+ }
116
+ const data = await response.json();
117
+ return data;
118
+ }
119
+ async handleDisconnect(request, accessToken) {
120
+ if (!accessToken) {
121
+ throw new Error("No access token provided. Cannot disconnect provider.");
122
+ }
123
+ const url = new URL("/oauth/disconnect", this.serverUrl);
124
+ const response = await fetch(url.toString(), {
125
+ method: "POST",
126
+ headers: this.getHeaders({
127
+ "Content-Type": "application/json",
128
+ Authorization: `Bearer ${accessToken}`
129
+ }),
130
+ body: JSON.stringify({
131
+ provider: request.provider
132
+ })
133
+ });
134
+ if (!response.ok) {
135
+ const error = await response.text();
136
+ throw new Error(`MCP server failed to disconnect provider: ${error}`);
137
+ }
138
+ const data = await response.json();
139
+ return data;
140
+ }
141
+ }
142
+
143
+ // src/adapters/auto-routes.ts
144
+ var globalOAuthConfig = null;
145
+ function setGlobalOAuthConfig(config) {
146
+ globalOAuthConfig = config;
147
+ }
148
+ function getGlobalOAuthConfig() {
149
+ return globalOAuthConfig;
150
+ }
151
+ async function POST(req, context) {
152
+ if (!globalOAuthConfig) {
153
+ throw new Error("OAuth configuration not found. Did you configure oauthProviders in createMCPClient?");
154
+ }
155
+ const handler = new OAuthHandler(globalOAuthConfig);
156
+ const action = context?.params?.action;
157
+ if (!action) {
158
+ return createErrorResponse("Missing action parameter", 400);
159
+ }
160
+ try {
161
+ if (action === "authorize") {
162
+ const body = await parseRequestBody(req);
163
+ const result = await handler.handleAuthorize(body);
164
+ return createSuccessResponse(result);
165
+ }
166
+ if (action === "callback") {
167
+ const body = await parseRequestBody(req);
168
+ const result = await handler.handleCallback(body);
169
+ return createSuccessResponse(result);
170
+ }
171
+ if (action === "disconnect") {
172
+ const body = await parseRequestBody(req);
173
+ const accessToken = extractAccessToken(req);
174
+ if (!accessToken) {
175
+ return createErrorResponse("Missing or invalid Authorization header", 400);
176
+ }
177
+ if (!body.provider) {
178
+ return createErrorResponse("Missing provider in request body", 400);
179
+ }
180
+ const result = await handler.handleDisconnect({ provider: body.provider }, accessToken);
181
+ return createSuccessResponse(result);
182
+ }
183
+ return createErrorResponse(`Unknown action: ${action}`, 404);
184
+ } catch (error) {
185
+ console.error(`[OAuth ${action}] Error:`, error);
186
+ return createErrorResponse(error.message, 500);
187
+ }
188
+ }
189
+ async function GET(req, context) {
190
+ if (!globalOAuthConfig) {
191
+ throw new Error("OAuth configuration not found. Did you configure oauthProviders in createMCPClient?");
192
+ }
193
+ const handler = new OAuthHandler(globalOAuthConfig);
194
+ const action = context?.params?.action;
195
+ if (!action) {
196
+ return createErrorResponse("Missing action parameter", 400);
197
+ }
198
+ try {
199
+ if (action === "status") {
200
+ const provider = extractProvider(req);
201
+ const accessToken = extractAccessToken(req);
202
+ if (!provider) {
203
+ return createErrorResponse("Missing provider parameter", 400);
204
+ }
205
+ if (!accessToken) {
206
+ return createErrorResponse("Missing or invalid Authorization header", 400);
207
+ }
208
+ const result = await handler.handleStatus(provider, accessToken);
209
+ return createSuccessResponse(result);
210
+ }
211
+ return createErrorResponse(`Unknown action: ${action}`, 404);
212
+ } catch (error) {
213
+ console.error(`[OAuth ${action}] Error:`, error);
214
+ return createErrorResponse(error.message, 500);
215
+ }
216
+ }
217
+ async function parseRequestBody(req) {
218
+ if (typeof req.json === "function") {
219
+ return await req.json();
220
+ }
221
+ throw new Error("Unable to parse request body");
222
+ }
223
+ function extractAccessToken(req) {
224
+ if (req.headers?.get) {
225
+ const authHeader = req.headers.get("authorization");
226
+ if (authHeader && authHeader.startsWith("Bearer ")) {
227
+ return authHeader.substring(7);
228
+ }
229
+ }
230
+ return;
231
+ }
232
+ function extractProvider(req) {
233
+ let url;
234
+ if (req.nextUrl) {
235
+ url = new URL(req.nextUrl);
236
+ } else if (req.url) {
237
+ url = new URL(req.url);
238
+ } else {
239
+ return;
240
+ }
241
+ return url.searchParams.get("provider") || undefined;
242
+ }
243
+ function createSuccessResponse(data) {
244
+ if (typeof globalThis.NextResponse !== "undefined") {
245
+ const NextResponse = globalThis.NextResponse;
246
+ return NextResponse.json(data);
247
+ }
248
+ return new Response(JSON.stringify(data), {
249
+ status: 200,
250
+ headers: { "Content-Type": "application/json" }
251
+ });
252
+ }
253
+ function createErrorResponse(message, status) {
254
+ if (typeof globalThis.NextResponse !== "undefined") {
255
+ const NextResponse = globalThis.NextResponse;
256
+ return NextResponse.json({ error: message }, { status });
257
+ }
258
+ return new Response(JSON.stringify({ error: message }), {
259
+ status,
260
+ headers: { "Content-Type": "application/json" }
261
+ });
262
+ }
263
+ export {
264
+ setGlobalOAuthConfig,
265
+ getGlobalOAuthConfig,
266
+ POST,
267
+ GET
268
+ };
@@ -0,0 +1,144 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, {
5
+ get: all[name],
6
+ enumerable: true,
7
+ configurable: true,
8
+ set: (newValue) => all[name] = () => newValue
9
+ });
10
+ };
11
+
12
+ // src/adapters/base-handler.ts
13
+ var MCP_SERVER_URL = "https://mcp.integrate.dev/api/v1/mcp";
14
+
15
+ class OAuthHandler {
16
+ config;
17
+ serverUrl;
18
+ apiKey;
19
+ constructor(config) {
20
+ this.config = config;
21
+ if (!config || !config.providers) {
22
+ throw new Error("OAuthHandler requires a valid config with providers");
23
+ }
24
+ this.serverUrl = config.serverUrl || MCP_SERVER_URL;
25
+ this.apiKey = config.apiKey;
26
+ }
27
+ getHeaders(additionalHeaders) {
28
+ const headers = {
29
+ ...additionalHeaders
30
+ };
31
+ if (this.apiKey) {
32
+ headers["X-API-KEY"] = this.apiKey;
33
+ }
34
+ return headers;
35
+ }
36
+ async handleAuthorize(request) {
37
+ const providerConfig = this.config.providers[request.provider];
38
+ if (!providerConfig) {
39
+ throw new Error(`Provider ${request.provider} not configured. Add OAuth credentials to your API route configuration.`);
40
+ }
41
+ if (!providerConfig.clientId || !providerConfig.clientSecret) {
42
+ throw new Error(`Missing OAuth credentials for ${request.provider}. Check your environment variables.`);
43
+ }
44
+ const url = new URL("/oauth/authorize", this.serverUrl);
45
+ url.searchParams.set("provider", request.provider);
46
+ url.searchParams.set("client_id", providerConfig.clientId);
47
+ url.searchParams.set("client_secret", providerConfig.clientSecret);
48
+ url.searchParams.set("scope", request.scopes.join(","));
49
+ url.searchParams.set("state", request.state);
50
+ url.searchParams.set("code_challenge", request.codeChallenge);
51
+ url.searchParams.set("code_challenge_method", request.codeChallengeMethod);
52
+ const redirectUri = request.redirectUri || providerConfig.redirectUri;
53
+ if (redirectUri) {
54
+ url.searchParams.set("redirect_uri", redirectUri);
55
+ }
56
+ const response = await fetch(url.toString(), {
57
+ method: "GET",
58
+ headers: this.getHeaders()
59
+ });
60
+ if (!response.ok) {
61
+ const error = await response.text();
62
+ throw new Error(`MCP server failed to generate authorization URL: ${error}`);
63
+ }
64
+ const data = await response.json();
65
+ return data;
66
+ }
67
+ async handleCallback(request) {
68
+ const providerConfig = this.config.providers[request.provider];
69
+ if (!providerConfig) {
70
+ throw new Error(`Provider ${request.provider} not configured. Add OAuth credentials to your API route configuration.`);
71
+ }
72
+ if (!providerConfig.clientId || !providerConfig.clientSecret) {
73
+ throw new Error(`Missing OAuth credentials for ${request.provider}. Check your environment variables.`);
74
+ }
75
+ const url = new URL("/oauth/callback", this.serverUrl);
76
+ const response = await fetch(url.toString(), {
77
+ method: "POST",
78
+ headers: this.getHeaders({
79
+ "Content-Type": "application/json"
80
+ }),
81
+ body: JSON.stringify({
82
+ provider: request.provider,
83
+ code: request.code,
84
+ code_verifier: request.codeVerifier,
85
+ state: request.state,
86
+ client_id: providerConfig.clientId,
87
+ client_secret: providerConfig.clientSecret,
88
+ redirect_uri: providerConfig.redirectUri
89
+ })
90
+ });
91
+ if (!response.ok) {
92
+ const error = await response.text();
93
+ throw new Error(`MCP server failed to exchange authorization code: ${error}`);
94
+ }
95
+ const data = await response.json();
96
+ return data;
97
+ }
98
+ async handleStatus(provider, accessToken) {
99
+ const url = new URL("/oauth/status", this.serverUrl);
100
+ url.searchParams.set("provider", provider);
101
+ const response = await fetch(url.toString(), {
102
+ method: "GET",
103
+ headers: this.getHeaders({
104
+ Authorization: `Bearer ${accessToken}`
105
+ })
106
+ });
107
+ if (!response.ok) {
108
+ if (response.status === 401) {
109
+ return {
110
+ authorized: false
111
+ };
112
+ }
113
+ const error = await response.text();
114
+ throw new Error(`MCP server failed to check authorization status: ${error}`);
115
+ }
116
+ const data = await response.json();
117
+ return data;
118
+ }
119
+ async handleDisconnect(request, accessToken) {
120
+ if (!accessToken) {
121
+ throw new Error("No access token provided. Cannot disconnect provider.");
122
+ }
123
+ const url = new URL("/oauth/disconnect", this.serverUrl);
124
+ const response = await fetch(url.toString(), {
125
+ method: "POST",
126
+ headers: this.getHeaders({
127
+ "Content-Type": "application/json",
128
+ Authorization: `Bearer ${accessToken}`
129
+ }),
130
+ body: JSON.stringify({
131
+ provider: request.provider
132
+ })
133
+ });
134
+ if (!response.ok) {
135
+ const error = await response.text();
136
+ throw new Error(`MCP server failed to disconnect provider: ${error}`);
137
+ }
138
+ const data = await response.json();
139
+ return data;
140
+ }
141
+ }
142
+ export {
143
+ OAuthHandler
144
+ };
@@ -0,0 +1,152 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, {
5
+ get: all[name],
6
+ enumerable: true,
7
+ configurable: true,
8
+ set: (newValue) => all[name] = () => newValue
9
+ });
10
+ };
11
+
12
+ // src/oauth/pkce.ts
13
+ var exports_pkce = {};
14
+ __export(exports_pkce, {
15
+ parseState: () => parseState,
16
+ generateStateWithReturnUrl: () => generateStateWithReturnUrl,
17
+ generateState: () => generateState,
18
+ generateCodeVerifier: () => generateCodeVerifier,
19
+ generateCodeChallenge: () => generateCodeChallenge
20
+ });
21
+ function generateCodeVerifier() {
22
+ const array = new Uint8Array(32);
23
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
24
+ crypto.getRandomValues(array);
25
+ } else if (typeof globalThis !== "undefined" && globalThis.crypto) {
26
+ globalThis.crypto.getRandomValues(array);
27
+ } else {
28
+ throw new Error("crypto.getRandomValues is not available. Please use Node.js 19+ or a modern browser.");
29
+ }
30
+ return base64UrlEncode(array);
31
+ }
32
+ async function generateCodeChallenge(verifier) {
33
+ const encoder = new TextEncoder;
34
+ const data = encoder.encode(verifier);
35
+ let hashBuffer;
36
+ if (typeof crypto !== "undefined" && crypto.subtle) {
37
+ hashBuffer = await crypto.subtle.digest("SHA-256", data);
38
+ } else if (typeof globalThis !== "undefined" && globalThis.crypto?.subtle) {
39
+ hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", data);
40
+ } else {
41
+ throw new Error("crypto.subtle.digest is not available. Please use Node.js 19+ or a modern browser.");
42
+ }
43
+ return base64UrlEncode(new Uint8Array(hashBuffer));
44
+ }
45
+ function generateState() {
46
+ const array = new Uint8Array(16);
47
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
48
+ crypto.getRandomValues(array);
49
+ } else if (typeof globalThis !== "undefined" && globalThis.crypto) {
50
+ globalThis.crypto.getRandomValues(array);
51
+ } else {
52
+ throw new Error("crypto.getRandomValues is not available. Please use Node.js 19+ or a modern browser.");
53
+ }
54
+ return base64UrlEncode(array);
55
+ }
56
+ function generateStateWithReturnUrl(returnUrl) {
57
+ const csrf = generateState();
58
+ const stateData = returnUrl ? { csrf, returnUrl } : { csrf };
59
+ const encoder = new TextEncoder;
60
+ const jsonBytes = encoder.encode(JSON.stringify(stateData));
61
+ return base64UrlEncode(jsonBytes);
62
+ }
63
+ function parseState(state) {
64
+ try {
65
+ const decoded = base64UrlDecode(state);
66
+ const parsed = JSON.parse(decoded);
67
+ if (typeof parsed === "string") {
68
+ return { csrf: parsed };
69
+ } else if (parsed && typeof parsed === "object") {
70
+ return {
71
+ csrf: parsed.csrf || state,
72
+ returnUrl: parsed.returnUrl
73
+ };
74
+ }
75
+ return { csrf: state };
76
+ } catch {
77
+ return { csrf: state };
78
+ }
79
+ }
80
+ function base64UrlEncode(array) {
81
+ let base64 = "";
82
+ if (typeof Buffer !== "undefined") {
83
+ base64 = Buffer.from(array).toString("base64");
84
+ } else {
85
+ const binary = String.fromCharCode(...array);
86
+ base64 = btoa(binary);
87
+ }
88
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
89
+ }
90
+ function base64UrlDecode(str) {
91
+ let base64 = str.replace(/-/g, "+").replace(/_/g, "/");
92
+ while (base64.length % 4 !== 0) {
93
+ base64 += "=";
94
+ }
95
+ if (typeof Buffer !== "undefined") {
96
+ return Buffer.from(base64, "base64").toString("utf-8");
97
+ } else {
98
+ const binary = atob(base64);
99
+ const bytes = new Uint8Array(binary.length);
100
+ for (let i = 0;i < binary.length; i++) {
101
+ bytes[i] = binary.charCodeAt(i);
102
+ }
103
+ const decoder = new TextDecoder;
104
+ return decoder.decode(bytes);
105
+ }
106
+ }
107
+
108
+ // src/adapters/nextjs-oauth-redirect.ts
109
+ function createOAuthRedirectHandler(config) {
110
+ const defaultRedirectUrl = config?.redirectUrl || "/";
111
+ const errorRedirectUrl = config?.errorRedirectUrl || "/auth-error";
112
+ return async function GET(req) {
113
+ const { searchParams } = new URL(req.url);
114
+ const code = searchParams.get("code");
115
+ const state = searchParams.get("state");
116
+ const error = searchParams.get("error");
117
+ const errorDescription = searchParams.get("error_description");
118
+ if (error) {
119
+ const errorMsg = errorDescription || error;
120
+ console.error("[OAuth Redirect] Error:", errorMsg);
121
+ return Response.redirect(new URL(`${errorRedirectUrl}?error=${encodeURIComponent(errorMsg)}`, req.url));
122
+ }
123
+ if (!code || !state) {
124
+ console.error("[OAuth Redirect] Missing code or state parameter");
125
+ return Response.redirect(new URL(`${errorRedirectUrl}?error=${encodeURIComponent("Invalid OAuth callback")}`, req.url));
126
+ }
127
+ let returnUrl = defaultRedirectUrl;
128
+ try {
129
+ const stateData = parseState(state);
130
+ if (stateData.returnUrl) {
131
+ returnUrl = stateData.returnUrl;
132
+ }
133
+ } catch (e) {
134
+ try {
135
+ const referrer = req.headers?.get?.("referer") || req.headers?.get?.("referrer");
136
+ if (referrer) {
137
+ const referrerUrl = new URL(referrer);
138
+ const currentUrl = new URL(req.url);
139
+ if (referrerUrl.origin === currentUrl.origin) {
140
+ returnUrl = referrerUrl.pathname + referrerUrl.search;
141
+ }
142
+ }
143
+ } catch {}
144
+ }
145
+ const targetUrl = new URL(returnUrl, req.url);
146
+ targetUrl.hash = `oauth_callback=${encodeURIComponent(JSON.stringify({ code, state }))}`;
147
+ return Response.redirect(targetUrl);
148
+ };
149
+ }
150
+ export {
151
+ createOAuthRedirectHandler
152
+ };