@merit-systems/echo-next-sdk 0.0.4 → 0.0.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.
- package/dist/client.d.ts +18 -1
- package/dist/client.js +20 -1
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +33 -5
- package/dist/index.js +75 -28
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/client.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { EchoConfig, EchoClient } from '@merit-systems/echo-typescript-sdk';
|
|
2
|
+
|
|
1
3
|
interface EchoClientConfig {
|
|
2
4
|
basePath?: string;
|
|
3
5
|
}
|
|
@@ -5,5 +7,20 @@ interface EchoClientConfig {
|
|
|
5
7
|
* Sign in to Echo (client-side only)
|
|
6
8
|
*/
|
|
7
9
|
declare function signIn(config?: EchoClientConfig): void;
|
|
10
|
+
/**
|
|
11
|
+
* Create an Echo client for client-side usage (React components, hooks)
|
|
12
|
+
* Uses relative URLs that work in the browser
|
|
13
|
+
*/
|
|
14
|
+
declare function createEchoClient(config?: EchoConfig): EchoClient;
|
|
15
|
+
/**
|
|
16
|
+
* Pre-configured Echo client for client-side usage
|
|
17
|
+
* Ready to use in React components
|
|
18
|
+
*/
|
|
19
|
+
declare const echoClient: EchoClient;
|
|
20
|
+
/**
|
|
21
|
+
* React hook to get the Echo client
|
|
22
|
+
* Provides a consistent way to access the client in components
|
|
23
|
+
*/
|
|
24
|
+
declare function useEcho(config?: EchoConfig): EchoClient;
|
|
8
25
|
|
|
9
|
-
export { type EchoClientConfig, signIn };
|
|
26
|
+
export { type EchoClientConfig, createEchoClient, echoClient, signIn, useEcho };
|
package/dist/client.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/client.ts
|
|
2
|
+
import { EchoClient } from "@merit-systems/echo-typescript-sdk";
|
|
2
3
|
function signIn(config) {
|
|
3
4
|
if (typeof window === "undefined") {
|
|
4
5
|
console.warn("signIn() can only be called in client components");
|
|
@@ -7,7 +8,25 @@ function signIn(config) {
|
|
|
7
8
|
const basePath = config?.basePath || "/api/echo";
|
|
8
9
|
window.location.href = `${window.location.origin}${basePath}/signin`;
|
|
9
10
|
}
|
|
11
|
+
function createEchoClient(config) {
|
|
12
|
+
const proxyPath = config?.basePath ? `${config.basePath}/proxy` : "/api/echo/proxy";
|
|
13
|
+
return new EchoClient({
|
|
14
|
+
baseUrl: proxyPath,
|
|
15
|
+
// No apiKey needed - proxy handles authentication automatically
|
|
16
|
+
apiKey: "next-sdk-proxy"
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
var echoClient = createEchoClient();
|
|
20
|
+
function useEcho(config) {
|
|
21
|
+
if (config) {
|
|
22
|
+
return createEchoClient(config);
|
|
23
|
+
}
|
|
24
|
+
return echoClient;
|
|
25
|
+
}
|
|
10
26
|
export {
|
|
11
|
-
|
|
27
|
+
createEchoClient,
|
|
28
|
+
echoClient,
|
|
29
|
+
signIn,
|
|
30
|
+
useEcho
|
|
12
31
|
};
|
|
13
32
|
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import { EchoClient, EchoConfig } from '@merit-systems/echo-typescript-sdk';\n\nexport interface EchoClientConfig {\n basePath?: string;\n}\n\n/**\n * Sign in to Echo (client-side only)\n */\nexport function signIn(config?: EchoClientConfig) {\n if (typeof window === 'undefined') {\n console.warn('signIn() can only be called in client components');\n return;\n }\n\n const basePath = config?.basePath || '/api/echo';\n window.location.href = `${window.location.origin}${basePath}/signin`;\n}\n\n/**\n * Create an Echo client for client-side usage (React components, hooks)\n * Uses relative URLs that work in the browser\n */\nexport function createEchoClient(config?: EchoConfig): EchoClient {\n const proxyPath = config?.basePath\n ? `${config.basePath}/proxy`\n : '/api/echo/proxy';\n\n return new EchoClient({\n baseUrl: proxyPath,\n // No apiKey needed - proxy handles authentication automatically\n apiKey: 'next-sdk-proxy',\n });\n}\n\n/**\n * Pre-configured Echo client for client-side usage\n * Ready to use in React components\n */\nexport const echoClient = createEchoClient();\n\n/**\n * React hook to get the Echo client\n * Provides a consistent way to access the client in components\n */\nexport function useEcho(config?: EchoConfig): EchoClient {\n if (config) {\n return createEchoClient(config);\n }\n return echoClient;\n}\n"],"mappings":";AAAA,SAAS,kBAA8B;AAShC,SAAS,OAAO,QAA2B;AAChD,MAAI,OAAO,WAAW,aAAa;AACjC,YAAQ,KAAK,kDAAkD;AAC/D;AAAA,EACF;AAEA,QAAM,WAAW,QAAQ,YAAY;AACrC,SAAO,SAAS,OAAO,GAAG,OAAO,SAAS,MAAM,GAAG,QAAQ;AAC7D;AAMO,SAAS,iBAAiB,QAAiC;AAChE,QAAM,YAAY,QAAQ,WACtB,GAAG,OAAO,QAAQ,WAClB;AAEJ,SAAO,IAAI,WAAW;AAAA,IACpB,SAAS;AAAA;AAAA,IAET,QAAQ;AAAA,EACV,CAAC;AACH;AAMO,IAAM,aAAa,iBAAiB;AAMpC,SAAS,QAAQ,QAAiC;AACvD,MAAI,QAAQ;AACV,WAAO,iBAAiB,MAAM;AAAA,EAChC;AACA,SAAO;AACT;","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,20 +1,48 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OpenAIProvider, AnthropicProvider, GoogleGenerativeAIProvider } from '@merit-systems/echo-typescript-sdk';
|
|
2
2
|
import { NextRequest } from 'next/server';
|
|
3
3
|
|
|
4
|
+
interface RefreshTokenResponse {
|
|
5
|
+
access_token: string;
|
|
6
|
+
token_type: string;
|
|
7
|
+
expires_in: number;
|
|
8
|
+
refresh_token: string;
|
|
9
|
+
refresh_token_expires_in: number;
|
|
10
|
+
scope: string;
|
|
11
|
+
user: {
|
|
12
|
+
id: string;
|
|
13
|
+
email: string;
|
|
14
|
+
name: string;
|
|
15
|
+
};
|
|
16
|
+
echo_app: {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
description: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
4
23
|
interface EchoConfig {
|
|
24
|
+
/**
|
|
25
|
+
* Echo App ID.
|
|
26
|
+
*/
|
|
5
27
|
appId: string;
|
|
28
|
+
/**
|
|
29
|
+
* Base path of API URL.
|
|
30
|
+
* @default /api/echo
|
|
31
|
+
*/
|
|
6
32
|
basePath?: string;
|
|
33
|
+
/** @internal */
|
|
7
34
|
baseRouterUrl?: string;
|
|
35
|
+
/** @internal */
|
|
8
36
|
baseEchoUrl?: string;
|
|
9
37
|
}
|
|
10
38
|
type AppRouteHandlers = Record<'GET' | 'POST', (req: NextRequest) => Promise<Response>>;
|
|
11
39
|
type EchoResult = {
|
|
12
40
|
handlers: AppRouteHandlers;
|
|
13
|
-
getUser: () => Promise<
|
|
41
|
+
getUser: () => Promise<RefreshTokenResponse['user'] | null>;
|
|
14
42
|
isSignedIn: () => Promise<boolean>;
|
|
15
|
-
openai:
|
|
16
|
-
anthropic:
|
|
17
|
-
google:
|
|
43
|
+
openai: OpenAIProvider;
|
|
44
|
+
anthropic: AnthropicProvider;
|
|
45
|
+
google: GoogleGenerativeAIProvider;
|
|
18
46
|
};
|
|
19
47
|
|
|
20
48
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { cookies } from "next/headers";
|
|
3
|
-
import { NextResponse as
|
|
4
|
-
import { EchoClient as EchoClient2 } from "@merit-systems/echo-typescript-sdk";
|
|
3
|
+
import { NextResponse as NextResponse3 } from "next/server";
|
|
5
4
|
|
|
6
|
-
// src/
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
5
|
+
// src/providers/anthropic.ts
|
|
6
|
+
import {
|
|
7
|
+
createEchoAnthropic as createEchoAnthropicBase
|
|
8
|
+
} from "@merit-systems/echo-typescript-sdk";
|
|
11
9
|
|
|
12
10
|
// src/auth/token-manager.ts
|
|
13
11
|
import {
|
|
@@ -15,6 +13,12 @@ import {
|
|
|
15
13
|
} from "@merit-systems/echo-typescript-sdk";
|
|
16
14
|
import { cookies as getCookies } from "next/headers";
|
|
17
15
|
|
|
16
|
+
// src/config.ts
|
|
17
|
+
import { ECHO_BASE_URL } from "@merit-systems/echo-typescript-sdk";
|
|
18
|
+
function resolveEchoBaseUrl(config) {
|
|
19
|
+
return config.baseEchoUrl || ECHO_BASE_URL;
|
|
20
|
+
}
|
|
21
|
+
|
|
18
22
|
// src/auth/jwt-utils.ts
|
|
19
23
|
import { jwtDecode } from "jwt-decode";
|
|
20
24
|
function shouldRefreshToken(token) {
|
|
@@ -95,9 +99,6 @@ async function getEchoToken(config) {
|
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
// src/providers/anthropic.ts
|
|
98
|
-
import {
|
|
99
|
-
createEchoAnthropic as createEchoAnthropicBase
|
|
100
|
-
} from "@merit-systems/echo-typescript-sdk";
|
|
101
102
|
function createEchoAnthropic(config) {
|
|
102
103
|
return createEchoAnthropicBase(config, async () => getEchoToken(config));
|
|
103
104
|
}
|
|
@@ -118,8 +119,44 @@ function createEchoOpenAI(config) {
|
|
|
118
119
|
return createEchoOpenAIBase(config, async () => getEchoToken(config));
|
|
119
120
|
}
|
|
120
121
|
|
|
121
|
-
// src/
|
|
122
|
+
// src/proxy/index.ts
|
|
122
123
|
import { NextResponse } from "next/server";
|
|
124
|
+
async function handleEchoClientProxy(req, config) {
|
|
125
|
+
const proxyPath = req.nextUrl.pathname.replace(/^.*\/proxy/, "");
|
|
126
|
+
const baseUrl = config.baseEchoUrl || "https://echo.merit.systems";
|
|
127
|
+
const targetUrl = `${baseUrl}${proxyPath}`;
|
|
128
|
+
const headers = new Headers(req.headers);
|
|
129
|
+
headers.delete("host");
|
|
130
|
+
headers.delete("accept-encoding");
|
|
131
|
+
headers.set("accept-encoding", "identity");
|
|
132
|
+
headers.delete("if-none-match");
|
|
133
|
+
headers.delete("if-modified-since");
|
|
134
|
+
const accessToken = await getEchoToken(config);
|
|
135
|
+
if (!accessToken) {
|
|
136
|
+
return NextResponse.json(
|
|
137
|
+
{ error: "Authentication required" },
|
|
138
|
+
{ status: 401 }
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
142
|
+
try {
|
|
143
|
+
const response = await fetch(targetUrl, {
|
|
144
|
+
method: req.method,
|
|
145
|
+
headers,
|
|
146
|
+
...req.method !== "GET" && req.method !== "HEAD" && { body: req.body }
|
|
147
|
+
});
|
|
148
|
+
return response;
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.error("Proxy request failed:", error);
|
|
151
|
+
return NextResponse.json(
|
|
152
|
+
{ error: "Proxy request failed" },
|
|
153
|
+
{ status: 500 }
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// src/auth/oauth-handlers.ts
|
|
159
|
+
import { NextResponse as NextResponse2 } from "next/server";
|
|
123
160
|
async function generateCodeChallenge() {
|
|
124
161
|
const codeVerifier = Array.from(crypto.getRandomValues(new Uint8Array(32))).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
125
162
|
const encoder = new TextEncoder();
|
|
@@ -143,7 +180,7 @@ async function handleSignIn(req, config) {
|
|
|
143
180
|
const { codeVerifier, codeChallenge } = await generateCodeChallenge();
|
|
144
181
|
redirectUrl.searchParams.set("code_challenge", codeChallenge);
|
|
145
182
|
redirectUrl.searchParams.set("code_challenge_method", "S256");
|
|
146
|
-
const response =
|
|
183
|
+
const response = NextResponse2.redirect(redirectUrl.toString());
|
|
147
184
|
response.cookies.set("echo_code_verifier", codeVerifier, {
|
|
148
185
|
httpOnly: true,
|
|
149
186
|
secure: process.env.NODE_ENV === "production",
|
|
@@ -160,11 +197,11 @@ async function handleCallback(req, config) {
|
|
|
160
197
|
const code = req.nextUrl.searchParams.get("code");
|
|
161
198
|
const state = req.nextUrl.searchParams.get("state");
|
|
162
199
|
if (!code || !state) {
|
|
163
|
-
return
|
|
200
|
+
return NextResponse2.json({ error: "Invalid request" }, { status: 400 });
|
|
164
201
|
}
|
|
165
202
|
const codeVerifier = req.cookies.get("echo_code_verifier")?.value;
|
|
166
203
|
if (!codeVerifier) {
|
|
167
|
-
return
|
|
204
|
+
return NextResponse2.json(
|
|
168
205
|
{ error: "Code verifier not found. Please try signing in again." },
|
|
169
206
|
{ status: 400 }
|
|
170
207
|
);
|
|
@@ -186,13 +223,13 @@ async function handleCallback(req, config) {
|
|
|
186
223
|
body: params.toString()
|
|
187
224
|
});
|
|
188
225
|
if (!tokenResponse.ok) {
|
|
189
|
-
return
|
|
226
|
+
return NextResponse2.json(
|
|
190
227
|
{ error: "Token exchange failed" },
|
|
191
228
|
{ status: 500 }
|
|
192
229
|
);
|
|
193
230
|
}
|
|
194
231
|
const tokenData = await tokenResponse.json();
|
|
195
|
-
const response =
|
|
232
|
+
const response = NextResponse2.redirect(`${origin}`);
|
|
196
233
|
response.cookies.set("echo_code_verifier", "", {
|
|
197
234
|
httpOnly: true,
|
|
198
235
|
secure: process.env.NODE_ENV === "production",
|
|
@@ -217,6 +254,13 @@ async function handleCallback(req, config) {
|
|
|
217
254
|
maxAge: tokenData.refresh_token_expires_in,
|
|
218
255
|
path: "/"
|
|
219
256
|
});
|
|
257
|
+
response.cookies.set("echo_user_info", JSON.stringify(tokenData.user), {
|
|
258
|
+
httpOnly: true,
|
|
259
|
+
secure: process.env.NODE_ENV === "production",
|
|
260
|
+
sameSite: "lax",
|
|
261
|
+
maxAge: tokenData.refresh_token_expires_in,
|
|
262
|
+
path: "/"
|
|
263
|
+
});
|
|
220
264
|
response.cookies.set(
|
|
221
265
|
"echo_refresh_token_expires",
|
|
222
266
|
String(Math.floor(Date.now() / 1e3) + tokenData.refresh_token_expires_in),
|
|
@@ -234,12 +278,12 @@ async function handleRefresh(req, config) {
|
|
|
234
278
|
try {
|
|
235
279
|
const token = await getEchoToken(config);
|
|
236
280
|
if (!token) {
|
|
237
|
-
return
|
|
281
|
+
return NextResponse2.json({ error: "No token found" }, { status: 401 });
|
|
238
282
|
}
|
|
239
|
-
return
|
|
283
|
+
return NextResponse2.json({ success: true });
|
|
240
284
|
} catch (error) {
|
|
241
285
|
console.error("Error refreshing token:", error);
|
|
242
|
-
return
|
|
286
|
+
return NextResponse2.json(
|
|
243
287
|
{ error: "Error refreshing token" },
|
|
244
288
|
{ status: 500 }
|
|
245
289
|
);
|
|
@@ -252,7 +296,11 @@ function Echo(config) {
|
|
|
252
296
|
const { pathname } = req.nextUrl;
|
|
253
297
|
const basePath = config.basePath || "/api/echo";
|
|
254
298
|
const path = pathname.replace(basePath, "");
|
|
299
|
+
if (path.startsWith("/proxy")) {
|
|
300
|
+
return handleEchoClientProxy(req, config);
|
|
301
|
+
}
|
|
255
302
|
switch (path) {
|
|
303
|
+
// all the auth stuff
|
|
256
304
|
case "/signin":
|
|
257
305
|
return handleSignIn(req, config);
|
|
258
306
|
case "/callback":
|
|
@@ -260,18 +308,17 @@ function Echo(config) {
|
|
|
260
308
|
case "/refresh":
|
|
261
309
|
return handleRefresh(req, config);
|
|
262
310
|
default:
|
|
263
|
-
|
|
311
|
+
console.error("Unknown path", path);
|
|
312
|
+
return NextResponse3.error();
|
|
264
313
|
}
|
|
265
314
|
};
|
|
266
315
|
const getUser = async () => {
|
|
267
316
|
const cookieStore = await cookies();
|
|
268
|
-
const
|
|
269
|
-
if (!
|
|
317
|
+
const userInfo = cookieStore.get("echo_user_info")?.value;
|
|
318
|
+
if (!userInfo) {
|
|
270
319
|
return null;
|
|
271
320
|
}
|
|
272
|
-
const
|
|
273
|
-
const echo = new EchoClient2({ apiKey: accessToken, baseUrl });
|
|
274
|
-
const user = await echo.users.getUserInfo();
|
|
321
|
+
const user = JSON.parse(userInfo);
|
|
275
322
|
return user;
|
|
276
323
|
};
|
|
277
324
|
const isSignedIn = async () => {
|
|
@@ -287,15 +334,15 @@ function Echo(config) {
|
|
|
287
334
|
return expiryTime > now;
|
|
288
335
|
};
|
|
289
336
|
return {
|
|
290
|
-
//
|
|
337
|
+
// HTTP handlers for Next.js API routes
|
|
291
338
|
handlers: {
|
|
292
339
|
GET: httpHandler,
|
|
293
340
|
POST: httpHandler
|
|
294
341
|
},
|
|
295
|
-
//
|
|
342
|
+
// Authentication utilities (server-side only)
|
|
296
343
|
getUser,
|
|
297
344
|
isSignedIn,
|
|
298
|
-
//
|
|
345
|
+
// AI provider clients
|
|
299
346
|
openai: createEchoOpenAI(config),
|
|
300
347
|
anthropic: createEchoAnthropic(config),
|
|
301
348
|
google: createEchoGoogle(config)
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/auth/token-manager.ts","../src/auth/jwt-utils.ts","../src/providers/anthropic.ts","../src/providers/google.ts","../src/providers/openai.ts","../src/auth/oauth-handlers.ts"],"sourcesContent":["import { cookies } from 'next/headers';\nimport { NextRequest, NextResponse } from 'next/server';\n\nimport { EchoClient } from '@merit-systems/echo-typescript-sdk';\nimport { resolveEchoBaseUrl } from './config';\nimport { EchoConfig, EchoResult } from './types';\n\nimport { createEchoAnthropic } from 'providers/anthropic';\nimport { createEchoGoogle } from 'providers/google';\nimport { createEchoOpenAI } from 'providers/openai';\n\nimport {\n handleCallback,\n handleRefresh,\n handleSignIn,\n} from './auth/oauth-handlers';\n\n/**\n * Echo SDK for Next.js\n * Provides OAuth authentication and token management for Echo API integration\n */\nexport default function Echo(config: EchoConfig): EchoResult {\n /**\n * HTTP handler for OAuth routes (signin and callback)\n */\n const httpHandler = async (req: NextRequest): Promise<Response> => {\n const { pathname } = req.nextUrl;\n const basePath = config.basePath || '/api/echo';\n const path = pathname.replace(basePath, '');\n\n switch (path) {\n case '/signin':\n return handleSignIn(req, config);\n\n case '/callback':\n return handleCallback(req, config);\n\n case '/refresh':\n return handleRefresh(req, config);\n\n default:\n return NextResponse.error();\n }\n };\n\n /**\n * Get current user info with automatic token refresh\n */\n const getUser = async () => {\n // read only access token, if expired we are fucked\n const cookieStore = await cookies();\n const accessToken = cookieStore.get('echo_access_token')?.value;\n if (!accessToken) {\n return null;\n }\n const baseUrl = resolveEchoBaseUrl(config);\n const echo = new EchoClient({ apiKey: accessToken, baseUrl });\n const user = await echo.users.getUserInfo();\n return user;\n };\n\n const isSignedIn = async () => {\n const cookieStore = await cookies();\n const refreshTokenExpiry = cookieStore.get(\n 'echo_refresh_token_expires'\n )?.value;\n\n if (!refreshTokenExpiry) {\n return false; // No expiry stored\n }\n\n const expiryTime = parseInt(refreshTokenExpiry);\n const now = Math.floor(Date.now() / 1000);\n\n return expiryTime > now; // True if not expired\n };\n\n return {\n // http handlers\n handlers: {\n GET: httpHandler,\n POST: httpHandler,\n },\n\n // echo auth\n getUser,\n isSignedIn,\n\n // providers\n openai: createEchoOpenAI(config),\n anthropic: createEchoAnthropic(config),\n google: createEchoGoogle(config),\n };\n}\n","import { ECHO_BASE_URL } from '@merit-systems/echo-typescript-sdk';\nimport type { EchoConfig } from './types';\n\nexport function resolveEchoBaseUrl(config: EchoConfig): string {\n return config.baseEchoUrl || ECHO_BASE_URL;\n}\n","import {\n EchoClient,\n EchoConfig,\n User,\n} from '@merit-systems/echo-typescript-sdk';\nimport { cookies as getCookies } from 'next/headers';\nimport { resolveEchoBaseUrl } from '../config';\nimport { shouldRefreshToken } from './jwt-utils';\n\nexport interface RefreshTokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token: string;\n refresh_token_expires_in: number;\n scope: string;\n user: {\n id: string;\n email: string;\n name: string;\n };\n echo_app: {\n id: string;\n name: string;\n description: string;\n };\n}\n\n/**\n * Refresh an access token using a refresh token\n * @param refreshToken - The refresh token to use\n * @param appId - The Echo app ID\n * @returns Promise resolving to the new token data\n */\nexport async function performTokenRefresh(\n refreshToken: string,\n config: EchoConfig\n): Promise<RefreshTokenResponse> {\n return fetch(`${resolveEchoBaseUrl(config)}/api/oauth/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: config.appId,\n }),\n }).then(async r => {\n if (r.ok) {\n const tokenData = (await r.json()) as RefreshTokenResponse;\n return tokenData;\n }\n return Promise.reject(new Error(await r.text()));\n });\n}\n\n/**\n * Get a valid Echo token, refreshing if necessary\n * @param appId - The Echo app ID for token refresh\n * @returns Promise resolving to a valid access token or null if authentication failed\n */\nexport async function getEchoToken(config: EchoConfig): Promise<string | null> {\n const cookies = await getCookies();\n const accessToken = cookies.get('echo_access_token')?.value;\n\n // Check if token needs refresh\n if (!accessToken || shouldRefreshToken(accessToken)) {\n const refreshToken = cookies.get('echo_refresh_token')?.value;\n\n if (!refreshToken) {\n console.log('No refresh token found');\n return null;\n }\n\n try {\n const refreshResult = await performTokenRefresh(refreshToken, config);\n\n // Set new tokens in cookies\n cookies.set('echo_access_token', refreshResult.access_token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: refreshResult.expires_in,\n path: '/',\n });\n\n cookies.set('echo_refresh_token', refreshResult.refresh_token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: refreshResult.refresh_token_expires_in,\n path: '/',\n });\n\n // Store refresh token expiry time for checking\n cookies.set(\n 'echo_refresh_token_expires',\n String(\n Math.floor(Date.now() / 1000) + refreshResult.refresh_token_expires_in\n ),\n {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: refreshResult.refresh_token_expires_in,\n path: '/',\n }\n );\n\n return refreshResult.access_token;\n } catch (error) {\n console.error('Token refresh failed:', refreshToken, error);\n return null;\n }\n }\n\n return accessToken;\n}\n\nexport async function getUser(config: EchoConfig): Promise<User> {\n const echo = await getEchoClient(config);\n if (!echo) {\n throw new Error('User not signed in');\n }\n return echo.users.getUserInfo();\n}\n\nexport async function getEchoClient(\n config: EchoConfig\n): Promise<EchoClient | null> {\n const token = await getEchoToken(config);\n if (!token) {\n return null;\n }\n return new EchoClient({\n baseUrl: resolveEchoBaseUrl(config),\n apiKey: token,\n });\n}\n","import { jwtDecode } from 'jwt-decode';\n\ninterface JwtPayload {\n exp?: number;\n}\n\n/**\n * Check if a JWT token needs to be refreshed\n * @param token - The JWT access token to check\n * @returns true if token should be refreshed, false otherwise\n */\nexport function shouldRefreshToken(token: string): boolean {\n try {\n const decoded = jwtDecode<JwtPayload>(token);\n if (!decoded.exp) return true;\n\n const now = Math.floor(Date.now() / 1000);\n // Refresh if token expires within 30 seconds\n const bufferTime = 30;\n return decoded.exp <= now + bufferTime;\n } catch {\n return true; // If we can't decode, assume it needs refresh\n }\n}\n","import { getEchoToken } from '../auth/token-manager';\nimport {\n createEchoAnthropic as createEchoAnthropicBase,\n EchoAnthropicProvider,\n EchoConfig,\n} from '@merit-systems/echo-typescript-sdk';\n\nexport function createEchoAnthropic(config: EchoConfig): EchoAnthropicProvider {\n return createEchoAnthropicBase(config, async () => getEchoToken(config));\n}\n","import {\n createEchoGoogle as createEchoGoogleBase,\n EchoConfig,\n EchoGoogleProvider,\n} from '@merit-systems/echo-typescript-sdk';\nimport { getEchoToken } from '../auth/token-manager';\n\nexport function createEchoGoogle(config: EchoConfig): EchoGoogleProvider {\n return createEchoGoogleBase(config, async () => getEchoToken(config));\n}\n","import { getEchoToken } from '../auth/token-manager';\nimport {\n createEchoOpenAI as createEchoOpenAIBase,\n EchoConfig,\n EchoOpenAIProvider,\n} from '@merit-systems/echo-typescript-sdk';\n\nexport function createEchoOpenAI(config: EchoConfig): EchoOpenAIProvider {\n return createEchoOpenAIBase(config, async () => getEchoToken(config));\n}\n","import { EchoConfig } from '@merit-systems/echo-typescript-sdk';\nimport { NextRequest, NextResponse } from 'next/server';\nimport { resolveEchoBaseUrl } from '../config';\nimport { getEchoToken, RefreshTokenResponse } from './token-manager';\n\n/**\n * Generate PKCE code challenge and verifier\n * @returns Object containing code verifier and challenge\n */\nasync function generateCodeChallenge(): Promise<{\n codeVerifier: string;\n codeChallenge: string;\n}> {\n const codeVerifier = Array.from(crypto.getRandomValues(new Uint8Array(32)))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('');\n\n const encoder = new TextEncoder();\n const codeChallengeBuffer = await crypto.subtle.digest(\n 'SHA-256',\n encoder.encode(codeVerifier)\n );\n\n const codeChallenge = btoa(\n String.fromCharCode(...new Uint8Array(codeChallengeBuffer))\n )\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n\n return { codeVerifier, codeChallenge };\n}\n\n/**\n * Handle OAuth signin request - redirect to Echo authorization server\n * @param req - The incoming Next.js request\n * @param config - Echo configuration\n * @returns NextResponse with redirect to authorization server\n */\nexport async function handleSignIn(\n req: NextRequest,\n config: EchoConfig\n): Promise<NextResponse> {\n const { origin } = req.nextUrl;\n const basePath = config.basePath || '/api/echo';\n\n const baseUrl = resolveEchoBaseUrl(config);\n\n const redirectUrl = new URL(`${baseUrl}/api/oauth/authorize`);\n redirectUrl.searchParams.set('client_id', config.appId);\n redirectUrl.searchParams.set('redirect_uri', `${origin}${basePath}/callback`);\n redirectUrl.searchParams.set('response_type', 'code');\n\n const { codeVerifier, codeChallenge } = await generateCodeChallenge();\n\n redirectUrl.searchParams.set('code_challenge', codeChallenge);\n redirectUrl.searchParams.set('code_challenge_method', 'S256');\n\n // Create response with redirect and set cookie for code verifier\n const response = NextResponse.redirect(redirectUrl.toString());\n\n // Set the code verifier in a secure cookie that will be available during callback\n response.cookies.set('echo_code_verifier', codeVerifier, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: 300, // 5 minutes - same as auth code TTL\n path: '/',\n });\n\n return response;\n}\n\n/**\n * Handle OAuth callback - exchange authorization code for tokens\n * @param req - The incoming Next.js request\n * @param config - Echo configuration\n * @returns NextResponse with redirect to home page and tokens set as cookies\n */\nexport async function handleCallback(\n req: NextRequest,\n config: EchoConfig\n): Promise<NextResponse> {\n const { origin } = req.nextUrl;\n const basePath = config.basePath || '/api/echo';\n\n const code = req.nextUrl.searchParams.get('code');\n const state = req.nextUrl.searchParams.get('state');\n\n if (!code || !state) {\n return NextResponse.json({ error: 'Invalid request' }, { status: 400 });\n }\n\n // Retrieve the code verifier from the cookie\n const codeVerifier = req.cookies.get('echo_code_verifier')?.value;\n\n if (!codeVerifier) {\n return NextResponse.json(\n { error: 'Code verifier not found. Please try signing in again.' },\n { status: 400 }\n );\n }\n\n // Exchange the code for a token from the token endpoint\n const tokenEndpoint = `${resolveEchoBaseUrl(config)}/api/oauth/token`;\n\n const params = new URLSearchParams();\n params.set('grant_type', 'authorization_code');\n params.set('code', code);\n params.set('redirect_uri', `${origin}${basePath}/callback`);\n params.set('client_id', config.appId);\n params.set('code_verifier', codeVerifier);\n\n const tokenResponse = await fetch(tokenEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'x-client-user-agent': req.headers.get('user-agent') || '',\n 'x-client-ip':\n req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || '',\n },\n body: params.toString(),\n });\n\n if (!tokenResponse.ok) {\n return NextResponse.json(\n { error: 'Token exchange failed' },\n { status: 500 }\n );\n }\n\n const tokenData = (await tokenResponse.json()) as RefreshTokenResponse;\n\n const response = NextResponse.redirect(`${origin}`);\n\n // Clear the code verifier cookie after successful token exchange\n response.cookies.set('echo_code_verifier', '', {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: 0, // Expire immediately\n path: '/',\n });\n\n // Set the access token as a cookie\n response.cookies.set('echo_access_token', tokenData.access_token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: tokenData.expires_in, // expires_in is typically in seconds\n path: '/',\n });\n\n tokenData.refresh_token_expires_in;\n\n response.cookies.set('echo_refresh_token', tokenData.refresh_token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: tokenData.refresh_token_expires_in,\n path: '/',\n });\n\n // Store refresh token expiry time for checking\n response.cookies.set(\n 'echo_refresh_token_expires',\n String(Math.floor(Date.now() / 1000) + tokenData.refresh_token_expires_in),\n {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: tokenData.refresh_token_expires_in,\n path: '/',\n }\n );\n\n return response;\n}\n\nexport async function handleRefresh(\n req: NextRequest,\n config: EchoConfig\n): Promise<NextResponse> {\n try {\n const token = await getEchoToken(config);\n if (!token) {\n return NextResponse.json({ error: 'No token found' }, { status: 401 });\n }\n\n return NextResponse.json({ success: true });\n } catch (error) {\n console.error('Error refreshing token:', error);\n return NextResponse.json(\n { error: 'Error refreshing token' },\n { status: 500 }\n );\n }\n}\n"],"mappings":"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","names":["NextResponse","EchoClient","cookies","NextResponse","EchoClient"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/providers/anthropic.ts","../src/auth/token-manager.ts","../src/config.ts","../src/auth/jwt-utils.ts","../src/providers/google.ts","../src/providers/openai.ts","../src/proxy/index.ts","../src/auth/oauth-handlers.ts"],"sourcesContent":["import { cookies } from 'next/headers';\nimport { NextRequest, NextResponse } from 'next/server';\n\nimport { EchoConfig, EchoResult } from './types';\n\nimport { createEchoAnthropic } from 'providers/anthropic';\nimport { createEchoGoogle } from 'providers/google';\nimport { createEchoOpenAI } from 'providers/openai';\n\nimport { RefreshTokenResponse } from 'auth/token-manager';\nimport { handleEchoClientProxy } from 'proxy';\nimport {\n handleCallback,\n handleRefresh,\n handleSignIn,\n} from './auth/oauth-handlers';\n\n/**\n * Echo SDK for Next.js\n * Provides OAuth authentication and token management for Echo API integration\n */\nexport default function Echo(config: EchoConfig): EchoResult {\n /**\n * HTTP handler for OAuth routes (signin and callback)\n */\n const httpHandler = async (req: NextRequest): Promise<Response> => {\n const { pathname } = req.nextUrl;\n const basePath = config.basePath || '/api/echo';\n const path = pathname.replace(basePath, '');\n\n if (path.startsWith('/proxy')) {\n return handleEchoClientProxy(req, config);\n }\n\n switch (path) {\n // all the auth stuff\n case '/signin':\n return handleSignIn(req, config);\n\n case '/callback':\n return handleCallback(req, config);\n\n case '/refresh':\n return handleRefresh(req, config);\n\n default:\n console.error('Unknown path', path);\n return NextResponse.error();\n }\n };\n\n /**\n * Get current user info with automatic token refresh\n */\n const getUser = async () => {\n // read only access token, if expired we are fucked\n const cookieStore = await cookies();\n const userInfo = cookieStore.get('echo_user_info')?.value;\n if (!userInfo) {\n return null;\n }\n const user = JSON.parse(userInfo) as RefreshTokenResponse['user'];\n return user;\n };\n\n const isSignedIn = async () => {\n const cookieStore = await cookies();\n const refreshTokenExpiry = cookieStore.get(\n 'echo_refresh_token_expires'\n )?.value;\n\n if (!refreshTokenExpiry) {\n return false; // No expiry stored\n }\n\n const expiryTime = parseInt(refreshTokenExpiry);\n const now = Math.floor(Date.now() / 1000);\n\n return expiryTime > now; // True if not expired\n };\n\n return {\n // HTTP handlers for Next.js API routes\n handlers: {\n GET: httpHandler,\n POST: httpHandler,\n },\n\n // Authentication utilities (server-side only)\n getUser,\n isSignedIn,\n\n // AI provider clients\n openai: createEchoOpenAI(config),\n anthropic: createEchoAnthropic(config),\n google: createEchoGoogle(config),\n };\n}\n","import {\n AnthropicProvider,\n createEchoAnthropic as createEchoAnthropicBase,\n EchoConfig,\n} from '@merit-systems/echo-typescript-sdk';\nimport { getEchoToken } from '../auth/token-manager';\n\nexport function createEchoAnthropic(config: EchoConfig): AnthropicProvider {\n return createEchoAnthropicBase(config, async () => getEchoToken(config));\n}\n","import {\n EchoClient,\n EchoConfig,\n User,\n} from '@merit-systems/echo-typescript-sdk';\nimport { cookies as getCookies } from 'next/headers';\nimport { resolveEchoBaseUrl } from '../config';\nimport { shouldRefreshToken } from './jwt-utils';\n\nexport interface RefreshTokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token: string;\n refresh_token_expires_in: number;\n scope: string;\n user: {\n id: string;\n email: string;\n name: string;\n };\n echo_app: {\n id: string;\n name: string;\n description: string;\n };\n}\n\n/**\n * Refresh an access token using a refresh token\n * @param refreshToken - The refresh token to use\n * @param appId - The Echo app ID\n * @returns Promise resolving to the new token data\n */\nexport async function performTokenRefresh(\n refreshToken: string,\n config: EchoConfig\n): Promise<RefreshTokenResponse> {\n return fetch(`${resolveEchoBaseUrl(config)}/api/oauth/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: config.appId,\n }),\n }).then(async r => {\n if (r.ok) {\n const tokenData = (await r.json()) as RefreshTokenResponse;\n return tokenData;\n }\n return Promise.reject(new Error(await r.text()));\n });\n}\n\n/**\n * Get a valid Echo token, refreshing if necessary\n * @param appId - The Echo app ID for token refresh\n * @returns Promise resolving to a valid access token or null if authentication failed\n */\nexport async function getEchoToken(config: EchoConfig): Promise<string | null> {\n const cookies = await getCookies();\n const accessToken = cookies.get('echo_access_token')?.value;\n\n // Check if token needs refresh\n if (!accessToken || shouldRefreshToken(accessToken)) {\n const refreshToken = cookies.get('echo_refresh_token')?.value;\n\n if (!refreshToken) {\n console.log('No refresh token found');\n return null;\n }\n\n try {\n const refreshResult = await performTokenRefresh(refreshToken, config);\n\n // Set new tokens in cookies\n cookies.set('echo_access_token', refreshResult.access_token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: refreshResult.expires_in,\n path: '/',\n });\n\n cookies.set('echo_refresh_token', refreshResult.refresh_token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: refreshResult.refresh_token_expires_in,\n path: '/',\n });\n\n // Store refresh token expiry time for checking\n cookies.set(\n 'echo_refresh_token_expires',\n String(\n Math.floor(Date.now() / 1000) + refreshResult.refresh_token_expires_in\n ),\n {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: refreshResult.refresh_token_expires_in,\n path: '/',\n }\n );\n\n return refreshResult.access_token;\n } catch (error) {\n console.error('Token refresh failed:', refreshToken, error);\n return null;\n }\n }\n\n return accessToken;\n}\n\nexport async function getUser(config: EchoConfig): Promise<User> {\n const echo = await getEchoClient(config);\n if (!echo) {\n throw new Error('User not signed in');\n }\n return echo.users.getUserInfo();\n}\n\nexport async function getEchoClient(\n config: EchoConfig\n): Promise<EchoClient | null> {\n const token = await getEchoToken(config);\n if (!token) {\n return null;\n }\n return new EchoClient({\n baseUrl: resolveEchoBaseUrl(config),\n apiKey: token,\n });\n}\n","import { ECHO_BASE_URL } from '@merit-systems/echo-typescript-sdk';\nimport type { EchoConfig } from './types';\n\nexport function resolveEchoBaseUrl(config: EchoConfig): string {\n return config.baseEchoUrl || ECHO_BASE_URL;\n}\n","import { jwtDecode } from 'jwt-decode';\n\ninterface JwtPayload {\n exp?: number;\n}\n\n/**\n * Check if a JWT token needs to be refreshed\n * @param token - The JWT access token to check\n * @returns true if token should be refreshed, false otherwise\n */\nexport function shouldRefreshToken(token: string): boolean {\n try {\n const decoded = jwtDecode<JwtPayload>(token);\n if (!decoded.exp) return true;\n\n const now = Math.floor(Date.now() / 1000);\n // Refresh if token expires within 30 seconds\n const bufferTime = 30;\n return decoded.exp <= now + bufferTime;\n } catch {\n return true; // If we can't decode, assume it needs refresh\n }\n}\n","import {\n createEchoGoogle as createEchoGoogleBase,\n EchoConfig,\n GoogleGenerativeAIProvider,\n} from '@merit-systems/echo-typescript-sdk';\nimport { getEchoToken } from '../auth/token-manager';\n\nexport function createEchoGoogle(\n config: EchoConfig\n): GoogleGenerativeAIProvider {\n return createEchoGoogleBase(config, async () => getEchoToken(config));\n}\n","import { getEchoToken } from '../auth/token-manager';\nimport {\n createEchoOpenAI as createEchoOpenAIBase,\n EchoConfig,\n OpenAIProvider,\n} from '@merit-systems/echo-typescript-sdk';\n\nexport function createEchoOpenAI(config: EchoConfig): OpenAIProvider {\n return createEchoOpenAIBase(config, async () => getEchoToken(config));\n}\n","import { NextRequest, NextResponse } from 'next/server';\nimport { getEchoToken } from '../auth/token-manager';\nimport { EchoConfig } from '../types';\n\n/**\n * Proxy requests to Echo service with automatic authentication\n */\nexport async function handleEchoClientProxy(\n req: NextRequest,\n config: EchoConfig\n): Promise<Response> {\n const proxyPath = req.nextUrl.pathname.replace(/^.*\\/proxy/, '');\n const baseUrl = config.baseEchoUrl || 'https://echo.merit.systems';\n const targetUrl = `${baseUrl}${proxyPath}`;\n\n const headers = new Headers(req.headers);\n headers.delete('host');\n // Don't ask upstream to compress\n headers.delete('accept-encoding');\n headers.set('accept-encoding', 'identity');\n\n // Optional: also drop conditional headers to avoid weirdness\n headers.delete('if-none-match');\n headers.delete('if-modified-since');\n\n // Get valid token using existing function (handles refresh automatically)\n const accessToken = await getEchoToken(config);\n\n if (!accessToken) {\n return NextResponse.json(\n { error: 'Authentication required' },\n { status: 401 }\n );\n }\n // Inject the valid token\n headers.set('Authorization', `Bearer ${accessToken}`);\n try {\n const response = await fetch(targetUrl, {\n method: req.method,\n headers,\n ...(req.method !== 'GET' && req.method !== 'HEAD' && { body: req.body }),\n });\n\n return response;\n } catch (error) {\n console.error('Proxy request failed:', error);\n return NextResponse.json(\n { error: 'Proxy request failed' },\n { status: 500 }\n );\n }\n}\n","import { EchoConfig } from '@merit-systems/echo-typescript-sdk';\nimport { NextRequest, NextResponse } from 'next/server';\nimport { resolveEchoBaseUrl } from '../config';\nimport { getEchoToken, RefreshTokenResponse } from './token-manager';\n\n/**\n * Generate PKCE code challenge and verifier\n * @returns Object containing code verifier and challenge\n */\nasync function generateCodeChallenge(): Promise<{\n codeVerifier: string;\n codeChallenge: string;\n}> {\n const codeVerifier = Array.from(crypto.getRandomValues(new Uint8Array(32)))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('');\n\n const encoder = new TextEncoder();\n const codeChallengeBuffer = await crypto.subtle.digest(\n 'SHA-256',\n encoder.encode(codeVerifier)\n );\n\n const codeChallenge = btoa(\n String.fromCharCode(...new Uint8Array(codeChallengeBuffer))\n )\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n\n return { codeVerifier, codeChallenge };\n}\n\n/**\n * Handle OAuth signin request - redirect to Echo authorization server\n * @param req - The incoming Next.js request\n * @param config - Echo configuration\n * @returns NextResponse with redirect to authorization server\n */\nexport async function handleSignIn(\n req: NextRequest,\n config: EchoConfig\n): Promise<NextResponse> {\n const { origin } = req.nextUrl;\n const basePath = config.basePath || '/api/echo';\n\n const baseUrl = resolveEchoBaseUrl(config);\n\n const redirectUrl = new URL(`${baseUrl}/api/oauth/authorize`);\n redirectUrl.searchParams.set('client_id', config.appId);\n redirectUrl.searchParams.set('redirect_uri', `${origin}${basePath}/callback`);\n redirectUrl.searchParams.set('response_type', 'code');\n\n const { codeVerifier, codeChallenge } = await generateCodeChallenge();\n\n redirectUrl.searchParams.set('code_challenge', codeChallenge);\n redirectUrl.searchParams.set('code_challenge_method', 'S256');\n\n // Create response with redirect and set cookie for code verifier\n const response = NextResponse.redirect(redirectUrl.toString());\n\n // Set the code verifier in a secure cookie that will be available during callback\n response.cookies.set('echo_code_verifier', codeVerifier, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: 300, // 5 minutes - same as auth code TTL\n path: '/',\n });\n\n return response;\n}\n\n/**\n * Handle OAuth callback - exchange authorization code for tokens\n * @param req - The incoming Next.js request\n * @param config - Echo configuration\n * @returns NextResponse with redirect to home page and tokens set as cookies\n */\nexport async function handleCallback(\n req: NextRequest,\n config: EchoConfig\n): Promise<NextResponse> {\n const { origin } = req.nextUrl;\n const basePath = config.basePath || '/api/echo';\n\n const code = req.nextUrl.searchParams.get('code');\n const state = req.nextUrl.searchParams.get('state');\n\n if (!code || !state) {\n return NextResponse.json({ error: 'Invalid request' }, { status: 400 });\n }\n\n // Retrieve the code verifier from the cookie\n const codeVerifier = req.cookies.get('echo_code_verifier')?.value;\n\n if (!codeVerifier) {\n return NextResponse.json(\n { error: 'Code verifier not found. Please try signing in again.' },\n { status: 400 }\n );\n }\n\n // Exchange the code for a token from the token endpoint\n const tokenEndpoint = `${resolveEchoBaseUrl(config)}/api/oauth/token`;\n\n const params = new URLSearchParams();\n params.set('grant_type', 'authorization_code');\n params.set('code', code);\n params.set('redirect_uri', `${origin}${basePath}/callback`);\n params.set('client_id', config.appId);\n params.set('code_verifier', codeVerifier);\n\n const tokenResponse = await fetch(tokenEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'x-client-user-agent': req.headers.get('user-agent') || '',\n 'x-client-ip':\n req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || '',\n },\n body: params.toString(),\n });\n\n if (!tokenResponse.ok) {\n return NextResponse.json(\n { error: 'Token exchange failed' },\n { status: 500 }\n );\n }\n\n const tokenData = (await tokenResponse.json()) as RefreshTokenResponse;\n\n const response = NextResponse.redirect(`${origin}`);\n\n // Clear the code verifier cookie after successful token exchange\n response.cookies.set('echo_code_verifier', '', {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: 0, // Expire immediately\n path: '/',\n });\n\n // Set the access token as a cookie\n response.cookies.set('echo_access_token', tokenData.access_token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: tokenData.expires_in, // expires_in is typically in seconds\n path: '/',\n });\n\n tokenData.refresh_token_expires_in;\n\n response.cookies.set('echo_refresh_token', tokenData.refresh_token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: tokenData.refresh_token_expires_in,\n path: '/',\n });\n\n response.cookies.set('echo_user_info', JSON.stringify(tokenData.user), {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: tokenData.refresh_token_expires_in,\n path: '/',\n });\n\n // Store refresh token expiry time for checking\n response.cookies.set(\n 'echo_refresh_token_expires',\n String(Math.floor(Date.now() / 1000) + tokenData.refresh_token_expires_in),\n {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n maxAge: tokenData.refresh_token_expires_in,\n path: '/',\n }\n );\n\n return response;\n}\n\nexport async function handleRefresh(\n req: NextRequest,\n config: EchoConfig\n): Promise<NextResponse> {\n try {\n const token = await getEchoToken(config);\n if (!token) {\n return NextResponse.json({ error: 'No token found' }, { status: 401 });\n }\n\n return NextResponse.json({ success: true });\n } catch (error) {\n console.error('Error refreshing token:', error);\n return NextResponse.json(\n { error: 'Error refreshing token' },\n { status: 500 }\n );\n }\n}\n"],"mappings":"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","names":["NextResponse","cookies","NextResponse","NextResponse","NextResponse"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@merit-systems/echo-next-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Next.js SDK for Echo",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"author": "Merit Systems",
|
|
38
38
|
"license": "MIT",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@merit-systems/echo-typescript-sdk": "1.0.
|
|
40
|
+
"@merit-systems/echo-typescript-sdk": "1.0.13",
|
|
41
41
|
"ai": "^5.0.17",
|
|
42
42
|
"jwt-decode": "^4.0.0"
|
|
43
43
|
},
|