integrate-sdk 0.3.13 → 0.4.1

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/index.js CHANGED
@@ -223,20 +223,19 @@ class OAuthHandler {
223
223
  const data = await response.json();
224
224
  return data;
225
225
  }
226
- async handleStatus(provider, sessionToken) {
226
+ async handleStatus(provider, accessToken) {
227
227
  const url = new URL("/oauth/status", this.serverUrl);
228
228
  url.searchParams.set("provider", provider);
229
229
  const response = await fetch(url.toString(), {
230
230
  method: "GET",
231
231
  headers: {
232
- "X-Session-Token": sessionToken
232
+ Authorization: `Bearer ${accessToken}`
233
233
  }
234
234
  });
235
235
  if (!response.ok) {
236
236
  if (response.status === 401) {
237
237
  return {
238
- authorized: false,
239
- provider
238
+ authorized: false
240
239
  };
241
240
  }
242
241
  const error = await response.text();
@@ -245,6 +244,28 @@ class OAuthHandler {
245
244
  const data = await response.json();
246
245
  return data;
247
246
  }
247
+ async handleDisconnect(request, accessToken) {
248
+ if (!accessToken) {
249
+ throw new Error("No access token provided. Cannot disconnect provider.");
250
+ }
251
+ const url = new URL("/oauth/disconnect", this.serverUrl);
252
+ const response = await fetch(url.toString(), {
253
+ method: "POST",
254
+ headers: {
255
+ "Content-Type": "application/json",
256
+ Authorization: `Bearer ${accessToken}`
257
+ },
258
+ body: JSON.stringify({
259
+ provider: request.provider
260
+ })
261
+ });
262
+ if (!response.ok) {
263
+ const error = await response.text();
264
+ throw new Error(`MCP server failed to disconnect provider: ${error}`);
265
+ }
266
+ const data = await response.json();
267
+ return data;
268
+ }
248
269
  }
249
270
  var MCP_SERVER_URL2 = "https://mcp.integrate.dev/api/v1/mcp";
250
271
 
@@ -279,20 +300,40 @@ function createNextOAuthHandler(config) {
279
300
  async status(req) {
280
301
  try {
281
302
  const provider = req.nextUrl.searchParams.get("provider");
282
- const sessionToken = req.headers.get("x-session-token");
303
+ const authHeader = req.headers.get("authorization");
283
304
  if (!provider) {
284
305
  return Response.json({ error: "Missing provider query parameter" }, { status: 400 });
285
306
  }
286
- if (!sessionToken) {
287
- return Response.json({ error: "Missing X-Session-Token header" }, { status: 400 });
307
+ if (!authHeader || !authHeader.startsWith("Bearer ")) {
308
+ return Response.json({ error: "Missing or invalid Authorization header" }, { status: 400 });
288
309
  }
289
- const result = await handler.handleStatus(provider, sessionToken);
310
+ const accessToken = authHeader.substring(7);
311
+ const result = await handler.handleStatus(provider, accessToken);
290
312
  return Response.json(result);
291
313
  } catch (error) {
292
314
  console.error("[OAuth Status] Error:", error);
293
315
  return Response.json({ error: error.message || "Failed to check authorization status" }, { status: 500 });
294
316
  }
295
317
  },
318
+ async disconnect(req) {
319
+ try {
320
+ const authHeader = req.headers.get("authorization");
321
+ if (!authHeader || !authHeader.startsWith("Bearer ")) {
322
+ return Response.json({ error: "Missing or invalid Authorization header" }, { status: 400 });
323
+ }
324
+ const accessToken = authHeader.substring(7);
325
+ const body = await req.json();
326
+ const { provider } = body;
327
+ if (!provider) {
328
+ return Response.json({ error: "Missing provider in request body" }, { status: 400 });
329
+ }
330
+ const result = await handler.handleDisconnect({ provider }, accessToken);
331
+ return Response.json(result);
332
+ } catch (error) {
333
+ console.error("[OAuth Disconnect] Error:", error);
334
+ return Response.json({ error: error.message || "Failed to disconnect provider" }, { status: 500 });
335
+ }
336
+ },
296
337
  createRoutes() {
297
338
  return {
298
339
  async POST(req, context) {
@@ -304,6 +345,9 @@ function createNextOAuthHandler(config) {
304
345
  if (action === "callback") {
305
346
  return handlers.callback(req);
306
347
  }
348
+ if (action === "disconnect") {
349
+ return handlers.disconnect(req);
350
+ }
307
351
  return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
308
352
  },
309
353
  async GET(req, context) {
@@ -781,7 +825,7 @@ function sendCallbackToOpener(params) {
781
825
  // src/oauth/manager.ts
782
826
  class OAuthManager {
783
827
  pendingAuths = new Map;
784
- sessionToken;
828
+ providerTokens = new Map;
785
829
  windowManager;
786
830
  flowConfig;
787
831
  oauthApiBase;
@@ -847,11 +891,19 @@ class OAuthManager {
847
891
  }
848
892
  try {
849
893
  const response = await this.exchangeCodeForToken(pendingAuth.provider, code, pendingAuth.codeVerifier, state);
850
- this.sessionToken = response.sessionToken;
851
- this.saveSessionToken(response.sessionToken);
894
+ const tokenData = {
895
+ accessToken: response.accessToken,
896
+ refreshToken: response.refreshToken,
897
+ tokenType: response.tokenType,
898
+ expiresIn: response.expiresIn,
899
+ expiresAt: response.expiresAt,
900
+ scopes: response.scopes
901
+ };
902
+ this.providerTokens.set(pendingAuth.provider, tokenData);
903
+ this.saveProviderToken(pendingAuth.provider, tokenData);
852
904
  this.pendingAuths.delete(state);
853
905
  this.removePendingAuthFromStorage(state);
854
- return response.sessionToken;
906
+ return { ...tokenData, provider: pendingAuth.provider };
855
907
  } catch (error) {
856
908
  this.pendingAuths.delete(state);
857
909
  this.removePendingAuthFromStorage(state);
@@ -859,7 +911,8 @@ class OAuthManager {
859
911
  }
860
912
  }
861
913
  async checkAuthStatus(provider) {
862
- if (!this.sessionToken) {
914
+ const tokenData = this.providerTokens.get(provider);
915
+ if (!tokenData) {
863
916
  return {
864
917
  authorized: false,
865
918
  provider
@@ -870,7 +923,7 @@ class OAuthManager {
870
923
  const response = await fetch(url, {
871
924
  method: "GET",
872
925
  headers: {
873
- "X-Session-Token": this.sessionToken
926
+ Authorization: `Bearer ${tokenData.accessToken}`
874
927
  }
875
928
  });
876
929
  if (!response.ok) {
@@ -880,7 +933,7 @@ class OAuthManager {
880
933
  };
881
934
  }
882
935
  const status = await response.json();
883
- return status;
936
+ return { ...status, provider };
884
937
  } catch (error) {
885
938
  console.error("Failed to check auth status:", error);
886
939
  return {
@@ -890,8 +943,9 @@ class OAuthManager {
890
943
  }
891
944
  }
892
945
  async disconnectProvider(provider) {
893
- if (!this.sessionToken) {
894
- throw new Error("No session token available. Cannot disconnect provider.");
946
+ const tokenData = this.providerTokens.get(provider);
947
+ if (!tokenData) {
948
+ throw new Error(`No access token available for provider "${provider}". Cannot disconnect provider.`);
895
949
  }
896
950
  try {
897
951
  const url = `${this.oauthApiBase}/disconnect`;
@@ -899,7 +953,7 @@ class OAuthManager {
899
953
  method: "POST",
900
954
  headers: {
901
955
  "Content-Type": "application/json",
902
- "X-Session-Token": this.sessionToken
956
+ Authorization: `Bearer ${tokenData.accessToken}`
903
957
  },
904
958
  body: JSON.stringify({ provider })
905
959
  });
@@ -907,25 +961,43 @@ class OAuthManager {
907
961
  const errorText = await response.text();
908
962
  throw new Error(`Failed to disconnect provider: ${errorText}`);
909
963
  }
964
+ this.providerTokens.delete(provider);
965
+ this.clearProviderToken(provider);
910
966
  } catch (error) {
911
967
  console.error("Failed to disconnect provider:", error);
912
968
  throw error;
913
969
  }
914
970
  }
915
- getSessionToken() {
916
- return this.sessionToken;
971
+ getProviderToken(provider) {
972
+ return this.providerTokens.get(provider);
917
973
  }
918
- setSessionToken(token) {
919
- this.sessionToken = token;
920
- this.saveSessionToken(token);
974
+ getAllProviderTokens() {
975
+ return new Map(this.providerTokens);
921
976
  }
922
- clearSessionToken() {
923
- this.sessionToken = undefined;
924
- if (typeof window !== "undefined" && window.sessionStorage) {
977
+ setProviderToken(provider, tokenData) {
978
+ this.providerTokens.set(provider, tokenData);
979
+ this.saveProviderToken(provider, tokenData);
980
+ }
981
+ clearProviderToken(provider) {
982
+ this.providerTokens.delete(provider);
983
+ if (typeof window !== "undefined" && window.localStorage) {
925
984
  try {
926
- window.sessionStorage.removeItem("integrate_session_token");
985
+ window.localStorage.removeItem(`integrate_token_${provider}`);
927
986
  } catch (error) {
928
- console.error("Failed to clear session token from sessionStorage:", error);
987
+ console.error(`Failed to clear token for ${provider} from localStorage:`, error);
988
+ }
989
+ }
990
+ }
991
+ clearAllProviderTokens() {
992
+ const providers = Array.from(this.providerTokens.keys());
993
+ this.providerTokens.clear();
994
+ if (typeof window !== "undefined" && window.localStorage) {
995
+ for (const provider of providers) {
996
+ try {
997
+ window.localStorage.removeItem(`integrate_token_${provider}`);
998
+ } catch (error) {
999
+ console.error(`Failed to clear token for ${provider} from localStorage:`, error);
1000
+ }
929
1001
  }
930
1002
  }
931
1003
  }
@@ -947,12 +1019,35 @@ class OAuthManager {
947
1019
  }
948
1020
  }
949
1021
  }
950
- saveSessionToken(token) {
951
- if (typeof window !== "undefined" && window.sessionStorage) {
1022
+ saveProviderToken(provider, tokenData) {
1023
+ if (typeof window !== "undefined" && window.localStorage) {
1024
+ try {
1025
+ const key = `integrate_token_${provider}`;
1026
+ window.localStorage.setItem(key, JSON.stringify(tokenData));
1027
+ } catch (error) {
1028
+ console.error(`Failed to save token for ${provider} to localStorage:`, error);
1029
+ }
1030
+ }
1031
+ }
1032
+ loadProviderToken(provider) {
1033
+ if (typeof window !== "undefined" && window.localStorage) {
952
1034
  try {
953
- window.sessionStorage.setItem("integrate_session_token", token);
1035
+ const key = `integrate_token_${provider}`;
1036
+ const stored = window.localStorage.getItem(key);
1037
+ if (stored) {
1038
+ return JSON.parse(stored);
1039
+ }
954
1040
  } catch (error) {
955
- console.error("Failed to save session token to sessionStorage:", error);
1041
+ console.error(`Failed to load token for ${provider} from localStorage:`, error);
1042
+ }
1043
+ }
1044
+ return;
1045
+ }
1046
+ loadAllProviderTokens(providers) {
1047
+ for (const provider of providers) {
1048
+ const tokenData = this.loadProviderToken(provider);
1049
+ if (tokenData) {
1050
+ this.providerTokens.set(provider, tokenData);
956
1051
  }
957
1052
  }
958
1053
  }
@@ -1140,23 +1235,15 @@ class MCPClient {
1140
1235
  this.maxReauthRetries = config.maxReauthRetries ?? 1;
1141
1236
  this.connectionMode = config.connectionMode ?? "lazy";
1142
1237
  this.oauthManager = new OAuthManager(config.oauthApiBase || "/api/integrate/oauth", config.oauthFlow);
1143
- let sessionToken = config.sessionToken;
1144
- if (!sessionToken) {
1145
- const storedToken = this.loadSessionToken();
1146
- if (storedToken) {
1147
- sessionToken = storedToken;
1148
- }
1149
- }
1150
- if (sessionToken) {
1151
- this.oauthManager.setSessionToken(sessionToken);
1152
- this.transport.setHeader("X-Session-Token", sessionToken);
1153
- }
1238
+ const providers = this.plugins.filter((p) => p.oauth).map((p) => p.oauth.provider);
1239
+ this.oauthManager.loadAllProviderTokens(providers);
1154
1240
  for (const plugin of this.plugins) {
1155
1241
  for (const toolName of plugin.tools) {
1156
1242
  this.enabledToolNames.add(toolName);
1157
1243
  }
1158
1244
  if (plugin.oauth) {
1159
- this.authState.set(plugin.oauth.provider, { authenticated: true });
1245
+ const hasToken = this.oauthManager.getProviderToken(plugin.oauth.provider) !== undefined;
1246
+ this.authState.set(plugin.oauth.provider, { authenticated: hasToken });
1160
1247
  }
1161
1248
  }
1162
1249
  this.github = this.createPluginProxy("github");
@@ -1297,30 +1384,36 @@ class MCPClient {
1297
1384
  if (!this.availableTools.has(name)) {
1298
1385
  throw new Error(`Tool "${name}" is not available on the server. Available tools: ${Array.from(this.availableTools.keys()).join(", ")}`);
1299
1386
  }
1387
+ const provider = this.getProviderForTool(name);
1388
+ if (provider) {
1389
+ const tokenData = this.oauthManager.getProviderToken(provider);
1390
+ if (tokenData) {
1391
+ this.transport.setHeader("Authorization", `Bearer ${tokenData.accessToken}`);
1392
+ }
1393
+ }
1300
1394
  const params = {
1301
1395
  name,
1302
1396
  arguments: args
1303
1397
  };
1304
1398
  try {
1305
1399
  const response = await this.transport.sendRequest("tools/call" /* TOOLS_CALL */, params);
1306
- const provider = this.getProviderForTool(name);
1307
1400
  if (provider) {
1308
1401
  this.authState.set(provider, { authenticated: true });
1309
1402
  }
1310
1403
  return response;
1311
1404
  } catch (error) {
1312
- const provider = this.getProviderForTool(name);
1313
- const parsedError = parseServerError(error, { toolName: name, provider });
1405
+ const provider2 = this.getProviderForTool(name);
1406
+ const parsedError = parseServerError(error, { toolName: name, provider: provider2 });
1314
1407
  if (isAuthError(parsedError) && retryCount < this.maxReauthRetries) {
1315
- if (provider) {
1316
- this.authState.set(provider, {
1408
+ if (provider2) {
1409
+ this.authState.set(provider2, {
1317
1410
  authenticated: false,
1318
1411
  lastError: parsedError
1319
1412
  });
1320
1413
  }
1321
- if (this.onReauthRequired && provider) {
1414
+ if (this.onReauthRequired && provider2) {
1322
1415
  const reauthSuccess = await this.onReauthRequired({
1323
- provider,
1416
+ provider: provider2,
1324
1417
  error: parsedError,
1325
1418
  toolName: name
1326
1419
  });
@@ -1371,35 +1464,8 @@ class MCPClient {
1371
1464
  off(event, handler) {
1372
1465
  this.eventEmitter.off(event, handler);
1373
1466
  }
1374
- saveSessionToken(token) {
1375
- if (typeof window !== "undefined" && window.sessionStorage) {
1376
- try {
1377
- window.sessionStorage.setItem("integrate_session_token", token);
1378
- } catch (error) {
1379
- console.error("Failed to save session token to sessionStorage:", error);
1380
- }
1381
- }
1382
- }
1383
- loadSessionToken() {
1384
- if (typeof window !== "undefined" && window.sessionStorage) {
1385
- try {
1386
- return window.sessionStorage.getItem("integrate_session_token") || undefined;
1387
- } catch (error) {
1388
- console.error("Failed to load session token from sessionStorage:", error);
1389
- return;
1390
- }
1391
- }
1392
- return;
1393
- }
1394
1467
  clearSessionToken() {
1395
- if (typeof window !== "undefined" && window.sessionStorage) {
1396
- try {
1397
- window.sessionStorage.removeItem("integrate_session_token");
1398
- } catch (error) {
1399
- console.error("Failed to clear session token from sessionStorage:", error);
1400
- }
1401
- }
1402
- this.oauthManager.clearSessionToken();
1468
+ this.oauthManager.clearAllProviderTokens();
1403
1469
  }
1404
1470
  async disconnectProvider(provider) {
1405
1471
  const plugin = this.plugins.find((p) => p.oauth?.provider === provider);
@@ -1479,10 +1545,13 @@ class MCPClient {
1479
1545
  this.eventEmitter.emit("auth:started", { provider });
1480
1546
  try {
1481
1547
  await this.oauthManager.initiateFlow(provider, plugin.oauth);
1482
- const sessionToken = this.oauthManager.getSessionToken();
1483
- if (sessionToken) {
1484
- this.saveSessionToken(sessionToken);
1485
- this.eventEmitter.emit("auth:complete", { provider, sessionToken });
1548
+ const tokenData = this.oauthManager.getProviderToken(provider);
1549
+ if (tokenData) {
1550
+ this.eventEmitter.emit("auth:complete", {
1551
+ provider,
1552
+ accessToken: tokenData.accessToken,
1553
+ expiresAt: tokenData.expiresAt
1554
+ });
1486
1555
  }
1487
1556
  this.authState.set(provider, { authenticated: true });
1488
1557
  } catch (error) {
@@ -1492,18 +1561,13 @@ class MCPClient {
1492
1561
  }
1493
1562
  async handleOAuthCallback(params) {
1494
1563
  try {
1495
- const sessionToken = await this.oauthManager.handleCallback(params.code, params.state);
1496
- this.saveSessionToken(sessionToken);
1497
- this.transport.setHeader("X-Session-Token", sessionToken);
1498
- for (const plugin of this.plugins) {
1499
- if (plugin.oauth) {
1500
- this.authState.set(plugin.oauth.provider, { authenticated: true });
1501
- this.eventEmitter.emit("auth:complete", {
1502
- provider: plugin.oauth.provider,
1503
- sessionToken
1504
- });
1505
- }
1506
- }
1564
+ const result = await this.oauthManager.handleCallback(params.code, params.state);
1565
+ this.authState.set(result.provider, { authenticated: true });
1566
+ this.eventEmitter.emit("auth:complete", {
1567
+ provider: result.provider,
1568
+ accessToken: result.accessToken,
1569
+ expiresAt: result.expiresAt
1570
+ });
1507
1571
  } catch (error) {
1508
1572
  this.eventEmitter.emit("auth:error", {
1509
1573
  provider: "unknown",
@@ -1512,12 +1576,12 @@ class MCPClient {
1512
1576
  throw error;
1513
1577
  }
1514
1578
  }
1515
- getSessionToken() {
1516
- return this.oauthManager.getSessionToken();
1579
+ getProviderToken(provider) {
1580
+ return this.oauthManager.getProviderToken(provider);
1517
1581
  }
1518
- setSessionToken(token) {
1519
- this.oauthManager.setSessionToken(token);
1520
- this.transport.setHeader("X-Session-Token", token);
1582
+ setProviderToken(provider, tokenData) {
1583
+ this.oauthManager.setProviderToken(provider, tokenData);
1584
+ this.authState.set(provider, { authenticated: true });
1521
1585
  }
1522
1586
  async reauthenticate(provider) {
1523
1587
  const state = this.authState.get(provider);
package/dist/oauth.js CHANGED
@@ -85,20 +85,19 @@ class OAuthHandler {
85
85
  const data = await response.json();
86
86
  return data;
87
87
  }
88
- async handleStatus(provider, sessionToken) {
88
+ async handleStatus(provider, accessToken) {
89
89
  const url = new URL("/oauth/status", this.serverUrl);
90
90
  url.searchParams.set("provider", provider);
91
91
  const response = await fetch(url.toString(), {
92
92
  method: "GET",
93
93
  headers: {
94
- "X-Session-Token": sessionToken
94
+ Authorization: `Bearer ${accessToken}`
95
95
  }
96
96
  });
97
97
  if (!response.ok) {
98
98
  if (response.status === 401) {
99
99
  return {
100
- authorized: false,
101
- provider
100
+ authorized: false
102
101
  };
103
102
  }
104
103
  const error = await response.text();
@@ -107,6 +106,28 @@ class OAuthHandler {
107
106
  const data = await response.json();
108
107
  return data;
109
108
  }
109
+ async handleDisconnect(request, accessToken) {
110
+ if (!accessToken) {
111
+ throw new Error("No access token provided. Cannot disconnect provider.");
112
+ }
113
+ const url = new URL("/oauth/disconnect", this.serverUrl);
114
+ const response = await fetch(url.toString(), {
115
+ method: "POST",
116
+ headers: {
117
+ "Content-Type": "application/json",
118
+ Authorization: `Bearer ${accessToken}`
119
+ },
120
+ body: JSON.stringify({
121
+ provider: request.provider
122
+ })
123
+ });
124
+ if (!response.ok) {
125
+ const error = await response.text();
126
+ throw new Error(`MCP server failed to disconnect provider: ${error}`);
127
+ }
128
+ const data = await response.json();
129
+ return data;
130
+ }
110
131
  }
111
132
  var MCP_SERVER_URL = "https://mcp.integrate.dev/api/v1/mcp";
112
133
 
@@ -132,6 +153,18 @@ async function POST(req, context) {
132
153
  const result = await handler.handleCallback(body);
133
154
  return createSuccessResponse(result);
134
155
  }
156
+ if (action === "disconnect") {
157
+ const body = await parseRequestBody(req);
158
+ const accessToken = extractAccessToken(req);
159
+ if (!accessToken) {
160
+ return createErrorResponse("Missing or invalid Authorization header", 400);
161
+ }
162
+ if (!body.provider) {
163
+ return createErrorResponse("Missing provider in request body", 400);
164
+ }
165
+ const result = await handler.handleDisconnect({ provider: body.provider }, accessToken);
166
+ return createSuccessResponse(result);
167
+ }
135
168
  return createErrorResponse(`Unknown action: ${action}`, 404);
136
169
  } catch (error) {
137
170
  console.error(`[OAuth ${action}] Error:`, error);
@@ -149,11 +182,15 @@ async function GET(req, context) {
149
182
  }
150
183
  try {
151
184
  if (action === "status") {
152
- const { provider, sessionToken } = parseQueryParams(req);
153
- if (!provider || !sessionToken) {
154
- return createErrorResponse("Missing provider or session token", 400);
185
+ const provider = extractProvider(req);
186
+ const accessToken = extractAccessToken(req);
187
+ if (!provider) {
188
+ return createErrorResponse("Missing provider parameter", 400);
189
+ }
190
+ if (!accessToken) {
191
+ return createErrorResponse("Missing or invalid Authorization header", 400);
155
192
  }
156
- const result = await handler.handleStatus(provider, sessionToken);
193
+ const result = await handler.handleStatus(provider, accessToken);
157
194
  return createSuccessResponse(result);
158
195
  }
159
196
  return createErrorResponse(`Unknown action: ${action}`, 404);
@@ -168,18 +205,25 @@ async function parseRequestBody(req) {
168
205
  }
169
206
  throw new Error("Unable to parse request body");
170
207
  }
171
- function parseQueryParams(req) {
208
+ function extractAccessToken(req) {
209
+ if (req.headers?.get) {
210
+ const authHeader = req.headers.get("authorization");
211
+ if (authHeader && authHeader.startsWith("Bearer ")) {
212
+ return authHeader.substring(7);
213
+ }
214
+ }
215
+ return;
216
+ }
217
+ function extractProvider(req) {
172
218
  let url;
173
219
  if (req.nextUrl) {
174
220
  url = new URL(req.nextUrl);
175
221
  } else if (req.url) {
176
222
  url = new URL(req.url);
177
223
  } else {
178
- return {};
224
+ return;
179
225
  }
180
- const provider = url.searchParams.get("provider") || undefined;
181
- const sessionToken = req.headers?.get?.("x-session-token") || undefined;
182
- return { provider, sessionToken };
226
+ return url.searchParams.get("provider") || undefined;
183
227
  }
184
228
  function createSuccessResponse(data) {
185
229
  if (typeof globalThis.NextResponse !== "undefined") {