integrate-sdk 0.5.7 → 0.5.8
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/README.md +82 -44
- package/dist/index.js +170 -89
- package/dist/server.js +190 -89
- package/dist/src/adapters/nextjs.d.ts +62 -0
- package/dist/src/adapters/nextjs.d.ts.map +1 -1
- package/dist/src/server.d.ts +51 -0
- package/dist/src/server.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,44 +26,58 @@ npm install integrate-sdk
|
|
|
26
26
|
bun add integrate-sdk
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
## Quick Start
|
|
29
|
+
## Quick Start (2 Files Only!)
|
|
30
30
|
|
|
31
|
-
### Server
|
|
31
|
+
### 1. Create Server Config
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Define your OAuth providers once:
|
|
34
34
|
|
|
35
35
|
```typescript
|
|
36
36
|
// lib/integrate-server.ts (server-side only!)
|
|
37
|
-
import {
|
|
37
|
+
import {
|
|
38
|
+
createMCPServer,
|
|
39
|
+
githubPlugin,
|
|
40
|
+
gmailPlugin,
|
|
41
|
+
} from "integrate-sdk/server";
|
|
38
42
|
|
|
39
|
-
export const { client: serverClient
|
|
43
|
+
export const { client: serverClient } = createMCPServer({
|
|
40
44
|
plugins: [
|
|
41
45
|
githubPlugin({
|
|
42
46
|
clientId: process.env.GITHUB_CLIENT_ID,
|
|
43
47
|
clientSecret: process.env.GITHUB_CLIENT_SECRET,
|
|
44
|
-
scopes: [
|
|
48
|
+
scopes: ["repo", "user"],
|
|
45
49
|
}),
|
|
46
50
|
gmailPlugin({
|
|
47
51
|
clientId: process.env.GMAIL_CLIENT_ID,
|
|
48
52
|
clientSecret: process.env.GMAIL_CLIENT_SECRET,
|
|
49
|
-
scopes: [
|
|
53
|
+
scopes: ["gmail.readonly"],
|
|
50
54
|
}),
|
|
51
55
|
],
|
|
52
56
|
});
|
|
53
57
|
```
|
|
54
58
|
|
|
55
|
-
|
|
59
|
+
### 2. Create Single Catch-All Route
|
|
60
|
+
|
|
61
|
+
That's it! Just import and export:
|
|
56
62
|
|
|
57
63
|
```typescript
|
|
58
|
-
// app/api/integrate/
|
|
59
|
-
|
|
64
|
+
// app/api/integrate/[...all]/route.ts
|
|
65
|
+
import { toNextJsHandler } from "integrate-sdk/server";
|
|
66
|
+
|
|
67
|
+
export const { POST, GET } = toNextJsHandler({
|
|
68
|
+
redirectUrl: "/dashboard",
|
|
69
|
+
});
|
|
60
70
|
```
|
|
61
71
|
|
|
72
|
+
This automatically uses your config from step 1 and handles ALL OAuth operations (authorize, callback, status, disconnect) in one file!
|
|
73
|
+
|
|
74
|
+
### 3. Use in Your App
|
|
75
|
+
|
|
62
76
|
Use the server client in API routes or server components:
|
|
63
77
|
|
|
64
78
|
```typescript
|
|
65
79
|
// app/api/repos/route.ts
|
|
66
|
-
import { serverClient } from
|
|
80
|
+
import { serverClient } from "@/lib/integrate-server";
|
|
67
81
|
|
|
68
82
|
export async function GET() {
|
|
69
83
|
// Automatically connects on first call - no manual setup needed!
|
|
@@ -77,34 +91,35 @@ export async function GET() {
|
|
|
77
91
|
Use in your client components (no secrets needed):
|
|
78
92
|
|
|
79
93
|
```typescript
|
|
80
|
-
|
|
81
|
-
import { createMCPClient, githubPlugin } from
|
|
94
|
+
"use client";
|
|
95
|
+
import { createMCPClient, githubPlugin } from "integrate-sdk";
|
|
82
96
|
|
|
83
97
|
const client = createMCPClient({
|
|
84
98
|
plugins: [
|
|
85
99
|
githubPlugin({
|
|
86
|
-
scopes: [
|
|
100
|
+
scopes: ["repo", "user"],
|
|
87
101
|
// No clientId or clientSecret needed!
|
|
88
102
|
}),
|
|
89
103
|
],
|
|
90
|
-
oauthFlow: { mode:
|
|
104
|
+
oauthFlow: { mode: "popup" },
|
|
91
105
|
});
|
|
92
106
|
|
|
93
107
|
// Authorize user (opens popup)
|
|
94
|
-
await client.authorize(
|
|
108
|
+
await client.authorize("github");
|
|
95
109
|
|
|
96
110
|
// Use the client - automatically connects!
|
|
97
111
|
const result = await client.github.createIssue({
|
|
98
|
-
owner:
|
|
99
|
-
repo:
|
|
100
|
-
title:
|
|
101
|
-
body:
|
|
112
|
+
owner: "owner",
|
|
113
|
+
repo: "repo",
|
|
114
|
+
title: "Bug report",
|
|
115
|
+
body: "Description of the bug",
|
|
102
116
|
});
|
|
103
117
|
|
|
104
|
-
console.log(
|
|
118
|
+
console.log("Issue created:", result);
|
|
105
119
|
```
|
|
106
120
|
|
|
107
121
|
**That's it!** The SDK automatically:
|
|
122
|
+
|
|
108
123
|
- ✅ Connects on first method call (no manual `connect()` needed)
|
|
109
124
|
- ✅ Cleans up on exit (no manual `disconnect()` needed)
|
|
110
125
|
- ✅ Manages OAuth tokens securely through your API routes
|
|
@@ -115,6 +130,7 @@ console.log('Issue created:', result);
|
|
|
115
130
|
The SDK automatically manages connections for you - no manual `connect()` or `disconnect()` calls needed!
|
|
116
131
|
|
|
117
132
|
**Features:**
|
|
133
|
+
|
|
118
134
|
- **Lazy Connection**: Automatically connects on first method call
|
|
119
135
|
- **Auto-Cleanup**: Cleans up on process exit
|
|
120
136
|
- **Singleton Pattern**: Reuses connections efficiently (configurable)
|
|
@@ -124,25 +140,25 @@ The SDK automatically manages connections for you - no manual `connect()` or `di
|
|
|
124
140
|
const client = createMCPClient({
|
|
125
141
|
plugins: [
|
|
126
142
|
githubPlugin({
|
|
127
|
-
scopes: [
|
|
143
|
+
scopes: ["repo", "user"],
|
|
128
144
|
}),
|
|
129
145
|
],
|
|
130
146
|
});
|
|
131
147
|
|
|
132
148
|
// Use immediately - no connect() needed!
|
|
133
|
-
await client.authorize(
|
|
134
|
-
await client.github.listRepos({ username:
|
|
149
|
+
await client.authorize("github");
|
|
150
|
+
await client.github.listRepos({ username: "octocat" });
|
|
135
151
|
|
|
136
152
|
// ✅ Want manual control? Use manual mode
|
|
137
153
|
const manualClient = createMCPClient({
|
|
138
|
-
plugins: [githubPlugin({ scopes: [
|
|
139
|
-
connectionMode:
|
|
154
|
+
plugins: [githubPlugin({ scopes: ["repo"] })],
|
|
155
|
+
connectionMode: "manual",
|
|
140
156
|
singleton: false,
|
|
141
157
|
});
|
|
142
158
|
|
|
143
159
|
await manualClient.connect();
|
|
144
|
-
await manualClient.authorize(
|
|
145
|
-
await manualClient.github.listRepos({ username:
|
|
160
|
+
await manualClient.authorize("github");
|
|
161
|
+
await manualClient.github.listRepos({ username: "octocat" });
|
|
146
162
|
await manualClient.disconnect();
|
|
147
163
|
```
|
|
148
164
|
|
|
@@ -165,7 +181,11 @@ Instead of generic tool calls, use typed methods with full autocomplete:
|
|
|
165
181
|
|
|
166
182
|
```typescript
|
|
167
183
|
// ✅ New: Typed methods with autocomplete
|
|
168
|
-
await client.github.createIssue({
|
|
184
|
+
await client.github.createIssue({
|
|
185
|
+
owner: "user",
|
|
186
|
+
repo: "project",
|
|
187
|
+
title: "Bug",
|
|
188
|
+
});
|
|
169
189
|
await client.gmail.sendEmail({ to: "user@example.com", subject: "Hello" });
|
|
170
190
|
```
|
|
171
191
|
|
|
@@ -180,14 +200,21 @@ await client.gmail.sendEmail({ to: "user@example.com", subject: "Hello" });
|
|
|
180
200
|
|
|
181
201
|
```typescript
|
|
182
202
|
// 1. Typed plugin methods (recommended for built-in plugins like GitHub/Gmail)
|
|
183
|
-
await client.github.createIssue({
|
|
203
|
+
await client.github.createIssue({
|
|
204
|
+
owner: "user",
|
|
205
|
+
repo: "project",
|
|
206
|
+
title: "Bug",
|
|
207
|
+
});
|
|
184
208
|
await client.gmail.sendEmail({ to: "user@example.com", subject: "Hello" });
|
|
185
209
|
|
|
186
210
|
// 2. Typed server methods (for server-level tools)
|
|
187
211
|
await client.server.listToolsByIntegration({ integration: "github" });
|
|
188
212
|
|
|
189
213
|
// 3. Direct tool calls (for other server-supported integrations)
|
|
190
|
-
await client._callToolByName("slack_send_message", {
|
|
214
|
+
await client._callToolByName("slack_send_message", {
|
|
215
|
+
channel: "#general",
|
|
216
|
+
text: "Hello",
|
|
217
|
+
});
|
|
191
218
|
```
|
|
192
219
|
|
|
193
220
|
## OAuth Authorization
|
|
@@ -195,16 +222,18 @@ await client._callToolByName("slack_send_message", { channel: "#general", text:
|
|
|
195
222
|
The SDK implements OAuth 2.0 Authorization Code Flow with PKCE for secure authorization.
|
|
196
223
|
|
|
197
224
|
**Key Features:**
|
|
225
|
+
|
|
198
226
|
- ✅ Popup or redirect flow modes
|
|
199
227
|
- ✅ Session token management
|
|
200
228
|
- ✅ Multiple provider support
|
|
201
229
|
- ✅ PKCE security
|
|
202
230
|
|
|
203
231
|
**Basic Usage:**
|
|
232
|
+
|
|
204
233
|
```typescript
|
|
205
234
|
// Check authorization
|
|
206
|
-
if (!await client.isAuthorized(
|
|
207
|
-
await client.authorize(
|
|
235
|
+
if (!(await client.isAuthorized("github"))) {
|
|
236
|
+
await client.authorize("github"); // Opens popup or redirects
|
|
208
237
|
}
|
|
209
238
|
|
|
210
239
|
// Use authorized client
|
|
@@ -212,6 +241,7 @@ const repos = await client.github.listOwnRepos({});
|
|
|
212
241
|
```
|
|
213
242
|
|
|
214
243
|
For complete OAuth setup including:
|
|
244
|
+
|
|
215
245
|
- Popup vs redirect flows
|
|
216
246
|
- Session token management
|
|
217
247
|
- Multiple providers
|
|
@@ -227,9 +257,13 @@ Access GitHub repositories, issues, pull requests, and more with type-safe metho
|
|
|
227
257
|
|
|
228
258
|
```typescript
|
|
229
259
|
// Available methods
|
|
230
|
-
await client.github.getRepo({ owner:
|
|
231
|
-
await client.github.createIssue({ owner:
|
|
232
|
-
await client.github.listPullRequests({
|
|
260
|
+
await client.github.getRepo({ owner: "facebook", repo: "react" });
|
|
261
|
+
await client.github.createIssue({ owner: "user", repo: "repo", title: "Bug" });
|
|
262
|
+
await client.github.listPullRequests({
|
|
263
|
+
owner: "user",
|
|
264
|
+
repo: "repo",
|
|
265
|
+
state: "open",
|
|
266
|
+
});
|
|
233
267
|
await client.github.listOwnRepos({});
|
|
234
268
|
```
|
|
235
269
|
|
|
@@ -241,9 +275,13 @@ Send emails, manage labels, and search messages with type-safe methods.
|
|
|
241
275
|
|
|
242
276
|
```typescript
|
|
243
277
|
// Available methods
|
|
244
|
-
await client.gmail.sendEmail({
|
|
245
|
-
|
|
246
|
-
|
|
278
|
+
await client.gmail.sendEmail({
|
|
279
|
+
to: "user@example.com",
|
|
280
|
+
subject: "Hello",
|
|
281
|
+
body: "Hi!",
|
|
282
|
+
});
|
|
283
|
+
await client.gmail.listEmails({ maxResults: 10, q: "is:unread" });
|
|
284
|
+
await client.gmail.searchEmails({ query: "from:notifications@github.com" });
|
|
247
285
|
```
|
|
248
286
|
|
|
249
287
|
[→ Gmail plugin documentation](https://integrate.dev/docs/plugins/gmail)
|
|
@@ -253,15 +291,15 @@ await client.gmail.searchEmails({ query: 'from:notifications@github.com' });
|
|
|
253
291
|
Use `genericOAuthPlugin` to configure any server-supported integration:
|
|
254
292
|
|
|
255
293
|
```typescript
|
|
256
|
-
import { genericOAuthPlugin } from
|
|
294
|
+
import { genericOAuthPlugin } from "integrate-sdk/server";
|
|
257
295
|
|
|
258
296
|
const slackPlugin = genericOAuthPlugin({
|
|
259
|
-
id:
|
|
260
|
-
provider:
|
|
297
|
+
id: "slack",
|
|
298
|
+
provider: "slack",
|
|
261
299
|
clientId: process.env.SLACK_CLIENT_ID,
|
|
262
300
|
clientSecret: process.env.SLACK_CLIENT_SECRET,
|
|
263
|
-
scopes: [
|
|
264
|
-
tools: [
|
|
301
|
+
scopes: ["chat:write", "channels:read"],
|
|
302
|
+
tools: ["slack_send_message", "slack_list_channels"],
|
|
265
303
|
});
|
|
266
304
|
```
|
|
267
305
|
|
package/dist/index.js
CHANGED
|
@@ -148,6 +148,102 @@ var init_errors = __esm(() => {
|
|
|
148
148
|
};
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
+
// src/oauth/pkce.ts
|
|
152
|
+
var exports_pkce = {};
|
|
153
|
+
__export(exports_pkce, {
|
|
154
|
+
parseState: () => parseState,
|
|
155
|
+
generateStateWithReturnUrl: () => generateStateWithReturnUrl,
|
|
156
|
+
generateState: () => generateState,
|
|
157
|
+
generateCodeVerifier: () => generateCodeVerifier,
|
|
158
|
+
generateCodeChallenge: () => generateCodeChallenge
|
|
159
|
+
});
|
|
160
|
+
function generateCodeVerifier() {
|
|
161
|
+
const array = new Uint8Array(32);
|
|
162
|
+
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
163
|
+
crypto.getRandomValues(array);
|
|
164
|
+
} else if (typeof globalThis !== "undefined" && globalThis.crypto) {
|
|
165
|
+
globalThis.crypto.getRandomValues(array);
|
|
166
|
+
} else {
|
|
167
|
+
throw new Error("crypto.getRandomValues is not available. Please use Node.js 19+ or a modern browser.");
|
|
168
|
+
}
|
|
169
|
+
return base64UrlEncode(array);
|
|
170
|
+
}
|
|
171
|
+
async function generateCodeChallenge(verifier) {
|
|
172
|
+
const encoder = new TextEncoder;
|
|
173
|
+
const data = encoder.encode(verifier);
|
|
174
|
+
let hashBuffer;
|
|
175
|
+
if (typeof crypto !== "undefined" && crypto.subtle) {
|
|
176
|
+
hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
177
|
+
} else if (typeof globalThis !== "undefined" && globalThis.crypto?.subtle) {
|
|
178
|
+
hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", data);
|
|
179
|
+
} else {
|
|
180
|
+
throw new Error("crypto.subtle.digest is not available. Please use Node.js 19+ or a modern browser.");
|
|
181
|
+
}
|
|
182
|
+
return base64UrlEncode(new Uint8Array(hashBuffer));
|
|
183
|
+
}
|
|
184
|
+
function generateState() {
|
|
185
|
+
const array = new Uint8Array(16);
|
|
186
|
+
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
187
|
+
crypto.getRandomValues(array);
|
|
188
|
+
} else if (typeof globalThis !== "undefined" && globalThis.crypto) {
|
|
189
|
+
globalThis.crypto.getRandomValues(array);
|
|
190
|
+
} else {
|
|
191
|
+
throw new Error("crypto.getRandomValues is not available. Please use Node.js 19+ or a modern browser.");
|
|
192
|
+
}
|
|
193
|
+
return base64UrlEncode(array);
|
|
194
|
+
}
|
|
195
|
+
function generateStateWithReturnUrl(returnUrl) {
|
|
196
|
+
const csrf = generateState();
|
|
197
|
+
const stateData = returnUrl ? { csrf, returnUrl } : { csrf };
|
|
198
|
+
const encoder = new TextEncoder;
|
|
199
|
+
const jsonBytes = encoder.encode(JSON.stringify(stateData));
|
|
200
|
+
return base64UrlEncode(jsonBytes);
|
|
201
|
+
}
|
|
202
|
+
function parseState(state) {
|
|
203
|
+
try {
|
|
204
|
+
const decoded = base64UrlDecode(state);
|
|
205
|
+
const parsed = JSON.parse(decoded);
|
|
206
|
+
if (typeof parsed === "string") {
|
|
207
|
+
return { csrf: parsed };
|
|
208
|
+
} else if (parsed && typeof parsed === "object") {
|
|
209
|
+
return {
|
|
210
|
+
csrf: parsed.csrf || state,
|
|
211
|
+
returnUrl: parsed.returnUrl
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
return { csrf: state };
|
|
215
|
+
} catch {
|
|
216
|
+
return { csrf: state };
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function base64UrlEncode(array) {
|
|
220
|
+
let base64 = "";
|
|
221
|
+
if (typeof Buffer !== "undefined") {
|
|
222
|
+
base64 = Buffer.from(array).toString("base64");
|
|
223
|
+
} else {
|
|
224
|
+
const binary = String.fromCharCode(...array);
|
|
225
|
+
base64 = btoa(binary);
|
|
226
|
+
}
|
|
227
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
228
|
+
}
|
|
229
|
+
function base64UrlDecode(str) {
|
|
230
|
+
let base64 = str.replace(/-/g, "+").replace(/_/g, "/");
|
|
231
|
+
while (base64.length % 4 !== 0) {
|
|
232
|
+
base64 += "=";
|
|
233
|
+
}
|
|
234
|
+
if (typeof Buffer !== "undefined") {
|
|
235
|
+
return Buffer.from(base64, "base64").toString("utf-8");
|
|
236
|
+
} else {
|
|
237
|
+
const binary = atob(base64);
|
|
238
|
+
const bytes = new Uint8Array(binary.length);
|
|
239
|
+
for (let i = 0;i < binary.length; i++) {
|
|
240
|
+
bytes[i] = binary.charCodeAt(i);
|
|
241
|
+
}
|
|
242
|
+
const decoder = new TextDecoder;
|
|
243
|
+
return decoder.decode(bytes);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
151
247
|
// src/protocol/jsonrpc.ts
|
|
152
248
|
function parseMessage(message) {
|
|
153
249
|
try {
|
|
@@ -369,95 +465,6 @@ function methodToToolName(methodName, pluginId) {
|
|
|
369
465
|
const snakeCaseMethod = camelToSnake(methodName);
|
|
370
466
|
return `${pluginId}_${snakeCaseMethod}`;
|
|
371
467
|
}
|
|
372
|
-
|
|
373
|
-
// src/oauth/pkce.ts
|
|
374
|
-
function generateCodeVerifier() {
|
|
375
|
-
const array = new Uint8Array(32);
|
|
376
|
-
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
377
|
-
crypto.getRandomValues(array);
|
|
378
|
-
} else if (typeof globalThis !== "undefined" && globalThis.crypto) {
|
|
379
|
-
globalThis.crypto.getRandomValues(array);
|
|
380
|
-
} else {
|
|
381
|
-
throw new Error("crypto.getRandomValues is not available. Please use Node.js 19+ or a modern browser.");
|
|
382
|
-
}
|
|
383
|
-
return base64UrlEncode(array);
|
|
384
|
-
}
|
|
385
|
-
async function generateCodeChallenge(verifier) {
|
|
386
|
-
const encoder = new TextEncoder;
|
|
387
|
-
const data = encoder.encode(verifier);
|
|
388
|
-
let hashBuffer;
|
|
389
|
-
if (typeof crypto !== "undefined" && crypto.subtle) {
|
|
390
|
-
hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
391
|
-
} else if (typeof globalThis !== "undefined" && globalThis.crypto?.subtle) {
|
|
392
|
-
hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", data);
|
|
393
|
-
} else {
|
|
394
|
-
throw new Error("crypto.subtle.digest is not available. Please use Node.js 19+ or a modern browser.");
|
|
395
|
-
}
|
|
396
|
-
return base64UrlEncode(new Uint8Array(hashBuffer));
|
|
397
|
-
}
|
|
398
|
-
function generateState() {
|
|
399
|
-
const array = new Uint8Array(16);
|
|
400
|
-
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
401
|
-
crypto.getRandomValues(array);
|
|
402
|
-
} else if (typeof globalThis !== "undefined" && globalThis.crypto) {
|
|
403
|
-
globalThis.crypto.getRandomValues(array);
|
|
404
|
-
} else {
|
|
405
|
-
throw new Error("crypto.getRandomValues is not available. Please use Node.js 19+ or a modern browser.");
|
|
406
|
-
}
|
|
407
|
-
return base64UrlEncode(array);
|
|
408
|
-
}
|
|
409
|
-
function generateStateWithReturnUrl(returnUrl) {
|
|
410
|
-
const csrf = generateState();
|
|
411
|
-
const stateData = returnUrl ? { csrf, returnUrl } : { csrf };
|
|
412
|
-
const encoder = new TextEncoder;
|
|
413
|
-
const jsonBytes = encoder.encode(JSON.stringify(stateData));
|
|
414
|
-
return base64UrlEncode(jsonBytes);
|
|
415
|
-
}
|
|
416
|
-
function parseState(state) {
|
|
417
|
-
try {
|
|
418
|
-
const decoded = base64UrlDecode(state);
|
|
419
|
-
const parsed = JSON.parse(decoded);
|
|
420
|
-
if (typeof parsed === "string") {
|
|
421
|
-
return { csrf: parsed };
|
|
422
|
-
} else if (parsed && typeof parsed === "object") {
|
|
423
|
-
return {
|
|
424
|
-
csrf: parsed.csrf || state,
|
|
425
|
-
returnUrl: parsed.returnUrl
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
return { csrf: state };
|
|
429
|
-
} catch {
|
|
430
|
-
return { csrf: state };
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
function base64UrlEncode(array) {
|
|
434
|
-
let base64 = "";
|
|
435
|
-
if (typeof Buffer !== "undefined") {
|
|
436
|
-
base64 = Buffer.from(array).toString("base64");
|
|
437
|
-
} else {
|
|
438
|
-
const binary = String.fromCharCode(...array);
|
|
439
|
-
base64 = btoa(binary);
|
|
440
|
-
}
|
|
441
|
-
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
442
|
-
}
|
|
443
|
-
function base64UrlDecode(str) {
|
|
444
|
-
let base64 = str.replace(/-/g, "+").replace(/_/g, "/");
|
|
445
|
-
while (base64.length % 4 !== 0) {
|
|
446
|
-
base64 += "=";
|
|
447
|
-
}
|
|
448
|
-
if (typeof Buffer !== "undefined") {
|
|
449
|
-
return Buffer.from(base64, "base64").toString("utf-8");
|
|
450
|
-
} else {
|
|
451
|
-
const binary = atob(base64);
|
|
452
|
-
const bytes = new Uint8Array(binary.length);
|
|
453
|
-
for (let i = 0;i < binary.length; i++) {
|
|
454
|
-
bytes[i] = binary.charCodeAt(i);
|
|
455
|
-
}
|
|
456
|
-
const decoder = new TextDecoder;
|
|
457
|
-
return decoder.decode(bytes);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
468
|
// src/oauth/window-manager.ts
|
|
462
469
|
function isBrowser() {
|
|
463
470
|
return typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
@@ -1747,6 +1754,80 @@ function createNextOAuthHandler(config) {
|
|
|
1747
1754
|
return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
|
|
1748
1755
|
}
|
|
1749
1756
|
};
|
|
1757
|
+
},
|
|
1758
|
+
toNextJsHandler(redirectConfig) {
|
|
1759
|
+
const defaultRedirectUrl = redirectConfig?.redirectUrl || "/";
|
|
1760
|
+
const errorRedirectUrl = redirectConfig?.errorRedirectUrl || "/auth-error";
|
|
1761
|
+
return {
|
|
1762
|
+
async POST(req, context) {
|
|
1763
|
+
const params = context.params instanceof Promise ? await context.params : context.params;
|
|
1764
|
+
const segments = params.all || [];
|
|
1765
|
+
if (segments.length === 2 && segments[0] === "oauth") {
|
|
1766
|
+
const action = segments[1];
|
|
1767
|
+
if (action === "authorize") {
|
|
1768
|
+
return handlers.authorize(req);
|
|
1769
|
+
}
|
|
1770
|
+
if (action === "callback") {
|
|
1771
|
+
return handlers.callback(req);
|
|
1772
|
+
}
|
|
1773
|
+
if (action === "disconnect") {
|
|
1774
|
+
return handlers.disconnect(req);
|
|
1775
|
+
}
|
|
1776
|
+
return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
|
|
1777
|
+
}
|
|
1778
|
+
return Response.json({ error: `Invalid route: /${segments.join("/")}` }, { status: 404 });
|
|
1779
|
+
},
|
|
1780
|
+
async GET(req, context) {
|
|
1781
|
+
const params = context.params instanceof Promise ? await context.params : context.params;
|
|
1782
|
+
const segments = params.all || [];
|
|
1783
|
+
if (segments.length === 2 && segments[0] === "oauth") {
|
|
1784
|
+
const action = segments[1];
|
|
1785
|
+
if (action === "status") {
|
|
1786
|
+
return handlers.status(req);
|
|
1787
|
+
}
|
|
1788
|
+
if (action === "callback") {
|
|
1789
|
+
const { searchParams } = new URL(req.url);
|
|
1790
|
+
const code = searchParams.get("code");
|
|
1791
|
+
const state = searchParams.get("state");
|
|
1792
|
+
const error = searchParams.get("error");
|
|
1793
|
+
const errorDescription = searchParams.get("error_description");
|
|
1794
|
+
if (error) {
|
|
1795
|
+
const errorMsg = errorDescription || error;
|
|
1796
|
+
console.error("[OAuth Redirect] Error:", errorMsg);
|
|
1797
|
+
return Response.redirect(new URL(`${errorRedirectUrl}?error=${encodeURIComponent(errorMsg)}`, req.url));
|
|
1798
|
+
}
|
|
1799
|
+
if (!code || !state) {
|
|
1800
|
+
console.error("[OAuth Redirect] Missing code or state parameter");
|
|
1801
|
+
return Response.redirect(new URL(`${errorRedirectUrl}?error=${encodeURIComponent("Invalid OAuth callback")}`, req.url));
|
|
1802
|
+
}
|
|
1803
|
+
let returnUrl = defaultRedirectUrl;
|
|
1804
|
+
try {
|
|
1805
|
+
const { parseState: parseState2 } = await Promise.resolve().then(() => exports_pkce);
|
|
1806
|
+
const stateData = parseState2(state);
|
|
1807
|
+
if (stateData.returnUrl) {
|
|
1808
|
+
returnUrl = stateData.returnUrl;
|
|
1809
|
+
}
|
|
1810
|
+
} catch (e) {
|
|
1811
|
+
try {
|
|
1812
|
+
const referrer = req.headers?.get?.("referer") || req.headers?.get?.("referrer");
|
|
1813
|
+
if (referrer) {
|
|
1814
|
+
const referrerUrl = new URL(referrer);
|
|
1815
|
+
const currentUrl = new URL(req.url);
|
|
1816
|
+
if (referrerUrl.origin === currentUrl.origin) {
|
|
1817
|
+
returnUrl = referrerUrl.pathname + referrerUrl.search;
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
} catch {}
|
|
1821
|
+
}
|
|
1822
|
+
const targetUrl = new URL(returnUrl, req.url);
|
|
1823
|
+
targetUrl.hash = `oauth_callback=${encodeURIComponent(JSON.stringify({ code, state }))}`;
|
|
1824
|
+
return Response.redirect(targetUrl);
|
|
1825
|
+
}
|
|
1826
|
+
return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
|
|
1827
|
+
}
|
|
1828
|
+
return Response.json({ error: `Invalid route: /${segments.join("/")}` }, { status: 404 });
|
|
1829
|
+
}
|
|
1830
|
+
};
|
|
1750
1831
|
}
|
|
1751
1832
|
};
|
|
1752
1833
|
return handlers;
|
package/dist/server.js
CHANGED
|
@@ -148,6 +148,102 @@ var init_errors = __esm(() => {
|
|
|
148
148
|
};
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
+
// src/oauth/pkce.ts
|
|
152
|
+
var exports_pkce = {};
|
|
153
|
+
__export(exports_pkce, {
|
|
154
|
+
parseState: () => parseState,
|
|
155
|
+
generateStateWithReturnUrl: () => generateStateWithReturnUrl,
|
|
156
|
+
generateState: () => generateState,
|
|
157
|
+
generateCodeVerifier: () => generateCodeVerifier,
|
|
158
|
+
generateCodeChallenge: () => generateCodeChallenge
|
|
159
|
+
});
|
|
160
|
+
function generateCodeVerifier() {
|
|
161
|
+
const array = new Uint8Array(32);
|
|
162
|
+
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
163
|
+
crypto.getRandomValues(array);
|
|
164
|
+
} else if (typeof globalThis !== "undefined" && globalThis.crypto) {
|
|
165
|
+
globalThis.crypto.getRandomValues(array);
|
|
166
|
+
} else {
|
|
167
|
+
throw new Error("crypto.getRandomValues is not available. Please use Node.js 19+ or a modern browser.");
|
|
168
|
+
}
|
|
169
|
+
return base64UrlEncode(array);
|
|
170
|
+
}
|
|
171
|
+
async function generateCodeChallenge(verifier) {
|
|
172
|
+
const encoder = new TextEncoder;
|
|
173
|
+
const data = encoder.encode(verifier);
|
|
174
|
+
let hashBuffer;
|
|
175
|
+
if (typeof crypto !== "undefined" && crypto.subtle) {
|
|
176
|
+
hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
177
|
+
} else if (typeof globalThis !== "undefined" && globalThis.crypto?.subtle) {
|
|
178
|
+
hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", data);
|
|
179
|
+
} else {
|
|
180
|
+
throw new Error("crypto.subtle.digest is not available. Please use Node.js 19+ or a modern browser.");
|
|
181
|
+
}
|
|
182
|
+
return base64UrlEncode(new Uint8Array(hashBuffer));
|
|
183
|
+
}
|
|
184
|
+
function generateState() {
|
|
185
|
+
const array = new Uint8Array(16);
|
|
186
|
+
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
187
|
+
crypto.getRandomValues(array);
|
|
188
|
+
} else if (typeof globalThis !== "undefined" && globalThis.crypto) {
|
|
189
|
+
globalThis.crypto.getRandomValues(array);
|
|
190
|
+
} else {
|
|
191
|
+
throw new Error("crypto.getRandomValues is not available. Please use Node.js 19+ or a modern browser.");
|
|
192
|
+
}
|
|
193
|
+
return base64UrlEncode(array);
|
|
194
|
+
}
|
|
195
|
+
function generateStateWithReturnUrl(returnUrl) {
|
|
196
|
+
const csrf = generateState();
|
|
197
|
+
const stateData = returnUrl ? { csrf, returnUrl } : { csrf };
|
|
198
|
+
const encoder = new TextEncoder;
|
|
199
|
+
const jsonBytes = encoder.encode(JSON.stringify(stateData));
|
|
200
|
+
return base64UrlEncode(jsonBytes);
|
|
201
|
+
}
|
|
202
|
+
function parseState(state) {
|
|
203
|
+
try {
|
|
204
|
+
const decoded = base64UrlDecode(state);
|
|
205
|
+
const parsed = JSON.parse(decoded);
|
|
206
|
+
if (typeof parsed === "string") {
|
|
207
|
+
return { csrf: parsed };
|
|
208
|
+
} else if (parsed && typeof parsed === "object") {
|
|
209
|
+
return {
|
|
210
|
+
csrf: parsed.csrf || state,
|
|
211
|
+
returnUrl: parsed.returnUrl
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
return { csrf: state };
|
|
215
|
+
} catch {
|
|
216
|
+
return { csrf: state };
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function base64UrlEncode(array) {
|
|
220
|
+
let base64 = "";
|
|
221
|
+
if (typeof Buffer !== "undefined") {
|
|
222
|
+
base64 = Buffer.from(array).toString("base64");
|
|
223
|
+
} else {
|
|
224
|
+
const binary = String.fromCharCode(...array);
|
|
225
|
+
base64 = btoa(binary);
|
|
226
|
+
}
|
|
227
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
228
|
+
}
|
|
229
|
+
function base64UrlDecode(str) {
|
|
230
|
+
let base64 = str.replace(/-/g, "+").replace(/_/g, "/");
|
|
231
|
+
while (base64.length % 4 !== 0) {
|
|
232
|
+
base64 += "=";
|
|
233
|
+
}
|
|
234
|
+
if (typeof Buffer !== "undefined") {
|
|
235
|
+
return Buffer.from(base64, "base64").toString("utf-8");
|
|
236
|
+
} else {
|
|
237
|
+
const binary = atob(base64);
|
|
238
|
+
const bytes = new Uint8Array(binary.length);
|
|
239
|
+
for (let i = 0;i < binary.length; i++) {
|
|
240
|
+
bytes[i] = binary.charCodeAt(i);
|
|
241
|
+
}
|
|
242
|
+
const decoder = new TextDecoder;
|
|
243
|
+
return decoder.decode(bytes);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
151
247
|
// src/protocol/jsonrpc.ts
|
|
152
248
|
function parseMessage(message) {
|
|
153
249
|
try {
|
|
@@ -369,95 +465,6 @@ function methodToToolName(methodName, pluginId) {
|
|
|
369
465
|
const snakeCaseMethod = camelToSnake(methodName);
|
|
370
466
|
return `${pluginId}_${snakeCaseMethod}`;
|
|
371
467
|
}
|
|
372
|
-
|
|
373
|
-
// src/oauth/pkce.ts
|
|
374
|
-
function generateCodeVerifier() {
|
|
375
|
-
const array = new Uint8Array(32);
|
|
376
|
-
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
377
|
-
crypto.getRandomValues(array);
|
|
378
|
-
} else if (typeof globalThis !== "undefined" && globalThis.crypto) {
|
|
379
|
-
globalThis.crypto.getRandomValues(array);
|
|
380
|
-
} else {
|
|
381
|
-
throw new Error("crypto.getRandomValues is not available. Please use Node.js 19+ or a modern browser.");
|
|
382
|
-
}
|
|
383
|
-
return base64UrlEncode(array);
|
|
384
|
-
}
|
|
385
|
-
async function generateCodeChallenge(verifier) {
|
|
386
|
-
const encoder = new TextEncoder;
|
|
387
|
-
const data = encoder.encode(verifier);
|
|
388
|
-
let hashBuffer;
|
|
389
|
-
if (typeof crypto !== "undefined" && crypto.subtle) {
|
|
390
|
-
hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
391
|
-
} else if (typeof globalThis !== "undefined" && globalThis.crypto?.subtle) {
|
|
392
|
-
hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", data);
|
|
393
|
-
} else {
|
|
394
|
-
throw new Error("crypto.subtle.digest is not available. Please use Node.js 19+ or a modern browser.");
|
|
395
|
-
}
|
|
396
|
-
return base64UrlEncode(new Uint8Array(hashBuffer));
|
|
397
|
-
}
|
|
398
|
-
function generateState() {
|
|
399
|
-
const array = new Uint8Array(16);
|
|
400
|
-
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
401
|
-
crypto.getRandomValues(array);
|
|
402
|
-
} else if (typeof globalThis !== "undefined" && globalThis.crypto) {
|
|
403
|
-
globalThis.crypto.getRandomValues(array);
|
|
404
|
-
} else {
|
|
405
|
-
throw new Error("crypto.getRandomValues is not available. Please use Node.js 19+ or a modern browser.");
|
|
406
|
-
}
|
|
407
|
-
return base64UrlEncode(array);
|
|
408
|
-
}
|
|
409
|
-
function generateStateWithReturnUrl(returnUrl) {
|
|
410
|
-
const csrf = generateState();
|
|
411
|
-
const stateData = returnUrl ? { csrf, returnUrl } : { csrf };
|
|
412
|
-
const encoder = new TextEncoder;
|
|
413
|
-
const jsonBytes = encoder.encode(JSON.stringify(stateData));
|
|
414
|
-
return base64UrlEncode(jsonBytes);
|
|
415
|
-
}
|
|
416
|
-
function parseState(state) {
|
|
417
|
-
try {
|
|
418
|
-
const decoded = base64UrlDecode(state);
|
|
419
|
-
const parsed = JSON.parse(decoded);
|
|
420
|
-
if (typeof parsed === "string") {
|
|
421
|
-
return { csrf: parsed };
|
|
422
|
-
} else if (parsed && typeof parsed === "object") {
|
|
423
|
-
return {
|
|
424
|
-
csrf: parsed.csrf || state,
|
|
425
|
-
returnUrl: parsed.returnUrl
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
return { csrf: state };
|
|
429
|
-
} catch {
|
|
430
|
-
return { csrf: state };
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
function base64UrlEncode(array) {
|
|
434
|
-
let base64 = "";
|
|
435
|
-
if (typeof Buffer !== "undefined") {
|
|
436
|
-
base64 = Buffer.from(array).toString("base64");
|
|
437
|
-
} else {
|
|
438
|
-
const binary = String.fromCharCode(...array);
|
|
439
|
-
base64 = btoa(binary);
|
|
440
|
-
}
|
|
441
|
-
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
442
|
-
}
|
|
443
|
-
function base64UrlDecode(str) {
|
|
444
|
-
let base64 = str.replace(/-/g, "+").replace(/_/g, "/");
|
|
445
|
-
while (base64.length % 4 !== 0) {
|
|
446
|
-
base64 += "=";
|
|
447
|
-
}
|
|
448
|
-
if (typeof Buffer !== "undefined") {
|
|
449
|
-
return Buffer.from(base64, "base64").toString("utf-8");
|
|
450
|
-
} else {
|
|
451
|
-
const binary = atob(base64);
|
|
452
|
-
const bytes = new Uint8Array(binary.length);
|
|
453
|
-
for (let i = 0;i < binary.length; i++) {
|
|
454
|
-
bytes[i] = binary.charCodeAt(i);
|
|
455
|
-
}
|
|
456
|
-
const decoder = new TextDecoder;
|
|
457
|
-
return decoder.decode(bytes);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
468
|
// src/oauth/window-manager.ts
|
|
462
469
|
function isBrowser() {
|
|
463
470
|
return typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
@@ -1749,6 +1756,80 @@ function createNextOAuthHandler(config) {
|
|
|
1749
1756
|
return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
|
|
1750
1757
|
}
|
|
1751
1758
|
};
|
|
1759
|
+
},
|
|
1760
|
+
toNextJsHandler(redirectConfig) {
|
|
1761
|
+
const defaultRedirectUrl = redirectConfig?.redirectUrl || "/";
|
|
1762
|
+
const errorRedirectUrl = redirectConfig?.errorRedirectUrl || "/auth-error";
|
|
1763
|
+
return {
|
|
1764
|
+
async POST(req, context) {
|
|
1765
|
+
const params = context.params instanceof Promise ? await context.params : context.params;
|
|
1766
|
+
const segments = params.all || [];
|
|
1767
|
+
if (segments.length === 2 && segments[0] === "oauth") {
|
|
1768
|
+
const action = segments[1];
|
|
1769
|
+
if (action === "authorize") {
|
|
1770
|
+
return handlers.authorize(req);
|
|
1771
|
+
}
|
|
1772
|
+
if (action === "callback") {
|
|
1773
|
+
return handlers.callback(req);
|
|
1774
|
+
}
|
|
1775
|
+
if (action === "disconnect") {
|
|
1776
|
+
return handlers.disconnect(req);
|
|
1777
|
+
}
|
|
1778
|
+
return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
|
|
1779
|
+
}
|
|
1780
|
+
return Response.json({ error: `Invalid route: /${segments.join("/")}` }, { status: 404 });
|
|
1781
|
+
},
|
|
1782
|
+
async GET(req, context) {
|
|
1783
|
+
const params = context.params instanceof Promise ? await context.params : context.params;
|
|
1784
|
+
const segments = params.all || [];
|
|
1785
|
+
if (segments.length === 2 && segments[0] === "oauth") {
|
|
1786
|
+
const action = segments[1];
|
|
1787
|
+
if (action === "status") {
|
|
1788
|
+
return handlers.status(req);
|
|
1789
|
+
}
|
|
1790
|
+
if (action === "callback") {
|
|
1791
|
+
const { searchParams } = new URL(req.url);
|
|
1792
|
+
const code = searchParams.get("code");
|
|
1793
|
+
const state = searchParams.get("state");
|
|
1794
|
+
const error = searchParams.get("error");
|
|
1795
|
+
const errorDescription = searchParams.get("error_description");
|
|
1796
|
+
if (error) {
|
|
1797
|
+
const errorMsg = errorDescription || error;
|
|
1798
|
+
console.error("[OAuth Redirect] Error:", errorMsg);
|
|
1799
|
+
return Response.redirect(new URL(`${errorRedirectUrl}?error=${encodeURIComponent(errorMsg)}`, req.url));
|
|
1800
|
+
}
|
|
1801
|
+
if (!code || !state) {
|
|
1802
|
+
console.error("[OAuth Redirect] Missing code or state parameter");
|
|
1803
|
+
return Response.redirect(new URL(`${errorRedirectUrl}?error=${encodeURIComponent("Invalid OAuth callback")}`, req.url));
|
|
1804
|
+
}
|
|
1805
|
+
let returnUrl = defaultRedirectUrl;
|
|
1806
|
+
try {
|
|
1807
|
+
const { parseState: parseState2 } = await Promise.resolve().then(() => exports_pkce);
|
|
1808
|
+
const stateData = parseState2(state);
|
|
1809
|
+
if (stateData.returnUrl) {
|
|
1810
|
+
returnUrl = stateData.returnUrl;
|
|
1811
|
+
}
|
|
1812
|
+
} catch (e) {
|
|
1813
|
+
try {
|
|
1814
|
+
const referrer = req.headers?.get?.("referer") || req.headers?.get?.("referrer");
|
|
1815
|
+
if (referrer) {
|
|
1816
|
+
const referrerUrl = new URL(referrer);
|
|
1817
|
+
const currentUrl = new URL(req.url);
|
|
1818
|
+
if (referrerUrl.origin === currentUrl.origin) {
|
|
1819
|
+
returnUrl = referrerUrl.pathname + referrerUrl.search;
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
} catch {}
|
|
1823
|
+
}
|
|
1824
|
+
const targetUrl = new URL(returnUrl, req.url);
|
|
1825
|
+
targetUrl.hash = `oauth_callback=${encodeURIComponent(JSON.stringify({ code, state }))}`;
|
|
1826
|
+
return Response.redirect(targetUrl);
|
|
1827
|
+
}
|
|
1828
|
+
return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
|
|
1829
|
+
}
|
|
1830
|
+
return Response.json({ error: `Invalid route: /${segments.join("/")}` }, { status: 404 });
|
|
1831
|
+
}
|
|
1832
|
+
};
|
|
1752
1833
|
}
|
|
1753
1834
|
};
|
|
1754
1835
|
return handlers;
|
|
@@ -1938,7 +2019,27 @@ var GET = async (req, context) => {
|
|
|
1938
2019
|
const routes = handler.createRoutes();
|
|
1939
2020
|
return routes.GET(req, context);
|
|
1940
2021
|
};
|
|
2022
|
+
function toNextJsHandler(redirectConfig) {
|
|
2023
|
+
const POST2 = async (req, context) => {
|
|
2024
|
+
if (!globalServerConfig) {
|
|
2025
|
+
return Response.json({ error: "OAuth not configured. Call createMCPServer() in your server initialization file first." }, { status: 500 });
|
|
2026
|
+
}
|
|
2027
|
+
const handler = createNextOAuthHandler(globalServerConfig);
|
|
2028
|
+
const routes = handler.toNextJsHandler(redirectConfig);
|
|
2029
|
+
return routes.POST(req, context);
|
|
2030
|
+
};
|
|
2031
|
+
const GET2 = async (req, context) => {
|
|
2032
|
+
if (!globalServerConfig) {
|
|
2033
|
+
return Response.json({ error: "OAuth not configured. Call createMCPServer() in your server initialization file first." }, { status: 500 });
|
|
2034
|
+
}
|
|
2035
|
+
const handler = createNextOAuthHandler(globalServerConfig);
|
|
2036
|
+
const routes = handler.toNextJsHandler(redirectConfig);
|
|
2037
|
+
return routes.GET(req, context);
|
|
2038
|
+
};
|
|
2039
|
+
return { POST: POST2, GET: GET2 };
|
|
2040
|
+
}
|
|
1941
2041
|
export {
|
|
2042
|
+
toNextJsHandler,
|
|
1942
2043
|
gmailPlugin,
|
|
1943
2044
|
githubPlugin,
|
|
1944
2045
|
genericOAuthPlugin,
|
|
@@ -265,6 +265,68 @@ export declare function createNextOAuthHandler(config: OAuthHandlerConfig): {
|
|
|
265
265
|
}>;
|
|
266
266
|
}): Promise<NextResponse>;
|
|
267
267
|
};
|
|
268
|
+
/**
|
|
269
|
+
* Create unified catch-all route handler
|
|
270
|
+
*
|
|
271
|
+
* This is the simplest way to set up OAuth routes - create a single catch-all
|
|
272
|
+
* route file that handles ALL OAuth actions including provider redirects.
|
|
273
|
+
*
|
|
274
|
+
* @param redirectConfig - Configuration for OAuth redirect behavior
|
|
275
|
+
* @returns Object with POST and GET handlers for Next.js catch-all routes
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* ```typescript
|
|
279
|
+
* // app/api/integrate/[...all]/route.ts
|
|
280
|
+
* import { createNextOAuthHandler } from 'integrate-sdk';
|
|
281
|
+
*
|
|
282
|
+
* const handler = createNextOAuthHandler({
|
|
283
|
+
* providers: {
|
|
284
|
+
* github: {
|
|
285
|
+
* clientId: process.env.GITHUB_CLIENT_ID!,
|
|
286
|
+
* clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
|
287
|
+
* },
|
|
288
|
+
* },
|
|
289
|
+
* });
|
|
290
|
+
*
|
|
291
|
+
* export const { POST, GET } = handler.toNextJsHandler({
|
|
292
|
+
* redirectUrl: '/',
|
|
293
|
+
* });
|
|
294
|
+
* ```
|
|
295
|
+
*
|
|
296
|
+
* This single route file handles:
|
|
297
|
+
* - POST /api/integrate/oauth/authorize - Get authorization URL
|
|
298
|
+
* - POST /api/integrate/oauth/callback - Exchange code for token
|
|
299
|
+
* - GET /api/integrate/oauth/callback - Provider OAuth redirect
|
|
300
|
+
* - GET /api/integrate/oauth/status - Check authorization status
|
|
301
|
+
* - POST /api/integrate/oauth/disconnect - Disconnect provider
|
|
302
|
+
*/
|
|
303
|
+
toNextJsHandler(redirectConfig?: {
|
|
304
|
+
/** URL to redirect to after OAuth callback (default: '/') */
|
|
305
|
+
redirectUrl?: string;
|
|
306
|
+
/** URL to redirect to on OAuth error (default: '/auth-error') */
|
|
307
|
+
errorRedirectUrl?: string;
|
|
308
|
+
}): {
|
|
309
|
+
/**
|
|
310
|
+
* POST handler for authorize, callback, and disconnect actions
|
|
311
|
+
*/
|
|
312
|
+
POST(req: NextRequest, context: {
|
|
313
|
+
params: {
|
|
314
|
+
all: string[];
|
|
315
|
+
} | Promise<{
|
|
316
|
+
all: string[];
|
|
317
|
+
}>;
|
|
318
|
+
}): Promise<NextResponse>;
|
|
319
|
+
/**
|
|
320
|
+
* GET handler for status action and OAuth provider redirects
|
|
321
|
+
*/
|
|
322
|
+
GET(req: NextRequest, context: {
|
|
323
|
+
params: {
|
|
324
|
+
all: string[];
|
|
325
|
+
} | Promise<{
|
|
326
|
+
all: string[];
|
|
327
|
+
}>;
|
|
328
|
+
}): Promise<NextResponse>;
|
|
329
|
+
};
|
|
268
330
|
};
|
|
269
331
|
export {};
|
|
270
332
|
//# sourceMappingURL=nextjs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nextjs.d.ts","sourceRoot":"","sources":["../../../src/adapters/nextjs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAgB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAG1E,KAAK,WAAW,GAAG,GAAG,CAAC;AACvB,KAAK,YAAY,GAAG,GAAG,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,kBAAkB;IAI7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAwCG;mBACkB,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAcxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyCG;kBACiB,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAcvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoCG;gBACe,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA+BrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuCG;oBACmB,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAiCzD;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;;QAGC;;WAEG;kBAEI,WAAW,WACP;YAAE,MAAM,EAAE;gBAAE,MAAM,EAAE,MAAM,CAAA;aAAE,GAAG,OAAO,CAAC;gBAAE,MAAM,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,GACpE,OAAO,CAAC,YAAY,CAAC;QAuBxB;;WAEG;iBAEI,WAAW,WACP;YAAE,MAAM,EAAE;gBAAE,MAAM,EAAE,MAAM,CAAA;aAAE,GAAG,OAAO,CAAC;gBAAE,MAAM,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,GACpE,OAAO,CAAC,YAAY,CAAC;;
|
|
1
|
+
{"version":3,"file":"nextjs.d.ts","sourceRoot":"","sources":["../../../src/adapters/nextjs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAgB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAG1E,KAAK,WAAW,GAAG,GAAG,CAAC;AACvB,KAAK,YAAY,GAAG,GAAG,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,kBAAkB;IAI7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAwCG;mBACkB,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAcxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyCG;kBACiB,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAcvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoCG;gBACe,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA+BrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuCG;oBACmB,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAiCzD;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;;QAGC;;WAEG;kBAEI,WAAW,WACP;YAAE,MAAM,EAAE;gBAAE,MAAM,EAAE,MAAM,CAAA;aAAE,GAAG,OAAO,CAAC;gBAAE,MAAM,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,GACpE,OAAO,CAAC,YAAY,CAAC;QAuBxB;;WAEG;iBAEI,WAAW,WACP;YAAE,MAAM,EAAE;gBAAE,MAAM,EAAE,MAAM,CAAA;aAAE,GAAG,OAAO,CAAC;gBAAE,MAAM,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,GACpE,OAAO,CAAC,YAAY,CAAC;;IAiB5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;qCAC8B;QAC/B,6DAA6D;QAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,iEAAiE;QACjE,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B;QAKG;;WAEG;kBAEI,WAAW,WACP;YAAE,MAAM,EAAE;gBAAE,GAAG,EAAE,MAAM,EAAE,CAAA;aAAE,GAAG,OAAO,CAAC;gBAAE,GAAG,EAAE,MAAM,EAAE,CAAA;aAAE,CAAC,CAAA;SAAE,GAClE,OAAO,CAAC,YAAY,CAAC;QAiCxB;;WAEG;iBAEI,WAAW,WACP;YAAE,MAAM,EAAE;gBAAE,GAAG,EAAE,MAAM,EAAE,CAAA;aAAE,GAAG,OAAO,CAAC;gBAAE,GAAG,EAAE,MAAM,EAAE,CAAA;aAAE,CAAC,CAAA;SAAE,GAClE,OAAO,CAAC,YAAY,CAAC;;EA+F/B"}
|
package/dist/src/server.d.ts
CHANGED
|
@@ -121,4 +121,55 @@ export declare const GET: (req: any, context: {
|
|
|
121
121
|
action: string;
|
|
122
122
|
}>;
|
|
123
123
|
}) => Promise<any>;
|
|
124
|
+
/**
|
|
125
|
+
* Create catch-all route handlers from the global server configuration
|
|
126
|
+
*
|
|
127
|
+
* This is a helper function to create POST and GET handlers for catch-all routes
|
|
128
|
+
* that use the configuration from createMCPServer().
|
|
129
|
+
*
|
|
130
|
+
* @param redirectConfig - Optional configuration for OAuth redirect behavior
|
|
131
|
+
* @returns Object with POST and GET handlers for Next.js catch-all routes
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```typescript
|
|
135
|
+
* // lib/integrate-server.ts
|
|
136
|
+
* import { createMCPServer, githubPlugin } from 'integrate-sdk/server';
|
|
137
|
+
*
|
|
138
|
+
* export const { client: serverClient } = createMCPServer({
|
|
139
|
+
* plugins: [
|
|
140
|
+
* githubPlugin({
|
|
141
|
+
* clientId: process.env.GITHUB_CLIENT_ID!,
|
|
142
|
+
* clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
|
143
|
+
* scopes: ['repo', 'user'],
|
|
144
|
+
* }),
|
|
145
|
+
* ],
|
|
146
|
+
* });
|
|
147
|
+
*
|
|
148
|
+
* // app/api/integrate/[...all]/route.ts
|
|
149
|
+
* import { toNextJsHandler } from 'integrate-sdk/server';
|
|
150
|
+
*
|
|
151
|
+
* export const { POST, GET } = toNextJsHandler({
|
|
152
|
+
* redirectUrl: '/dashboard',
|
|
153
|
+
* });
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
export declare function toNextJsHandler(redirectConfig?: {
|
|
157
|
+
redirectUrl?: string;
|
|
158
|
+
errorRedirectUrl?: string;
|
|
159
|
+
}): {
|
|
160
|
+
POST: (req: any, context: {
|
|
161
|
+
params: {
|
|
162
|
+
all: string[];
|
|
163
|
+
} | Promise<{
|
|
164
|
+
all: string[];
|
|
165
|
+
}>;
|
|
166
|
+
}) => Promise<any>;
|
|
167
|
+
GET: (req: any, context: {
|
|
168
|
+
params: {
|
|
169
|
+
all: string[];
|
|
170
|
+
} | Promise<{
|
|
171
|
+
all: string[];
|
|
172
|
+
}>;
|
|
173
|
+
}) => Promise<any>;
|
|
174
|
+
};
|
|
124
175
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/src/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAyCpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAgB,eAAe,CAAC,QAAQ,SAAS,SAAS,SAAS,EAAE,EACnE,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC;IAmE/B,2DAA2D;;IAG3D,4DAA4D;;;;;;;;IAG5D,2DAA2D;;;;;;;;EAG9D;AAYD,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE9E;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,IAAI,GACf,KAAK,GAAG,EACR,SAAS;IAAE,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,iBAYtE,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,GAAG,GACd,KAAK,GAAG,EACR,SAAS;IAAE,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,iBAYtE,CAAC"}
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAyCpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAgB,eAAe,CAAC,QAAQ,SAAS,SAAS,SAAS,EAAE,EACnE,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC;IAmE/B,2DAA2D;;IAG3D,4DAA4D;;;;;;;;IAG5D,2DAA2D;;;;;;;;EAG9D;AAYD,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE9E;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,IAAI,GACf,KAAK,GAAG,EACR,SAAS;IAAE,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,iBAYtE,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,GAAG,GACd,KAAK,GAAG,EACR,SAAS;IAAE,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,iBAYtE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,eAAe,CAAC,cAAc,CAAC,EAAE;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;gBAMQ,GAAG,WACC;QAAE,MAAM,EAAE;YAAE,GAAG,EAAE,MAAM,EAAE,CAAA;SAAE,GAAG,OAAO,CAAC;YAAE,GAAG,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE;eAmB9D,GAAG,WACC;QAAE,MAAM,EAAE;YAAE,GAAG,EAAE,MAAM,EAAE,CAAA;SAAE,GAAG,OAAO,CAAC;YAAE,GAAG,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE;EAetE"}
|