nitrostack 1.0.0 → 1.0.2
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/CHANGELOG.md +30 -0
- package/dist/cli/index.js +4 -1
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
- package/src/studio/README.md +140 -0
- package/src/studio/app/api/auth/fetch-metadata/route.ts +71 -0
- package/src/studio/app/api/auth/register-client/route.ts +67 -0
- package/src/studio/app/api/chat/route.ts +123 -0
- package/src/studio/app/api/health/checks/route.ts +42 -0
- package/src/studio/app/api/health/route.ts +13 -0
- package/src/studio/app/api/init/route.ts +85 -0
- package/src/studio/app/api/ping/route.ts +13 -0
- package/src/studio/app/api/prompts/[name]/route.ts +21 -0
- package/src/studio/app/api/prompts/route.ts +13 -0
- package/src/studio/app/api/resources/[...uri]/route.ts +18 -0
- package/src/studio/app/api/resources/route.ts +13 -0
- package/src/studio/app/api/roots/route.ts +13 -0
- package/src/studio/app/api/sampling/route.ts +14 -0
- package/src/studio/app/api/tools/[name]/call/route.ts +41 -0
- package/src/studio/app/api/tools/route.ts +23 -0
- package/src/studio/app/api/widget-examples/route.ts +44 -0
- package/src/studio/app/auth/callback/page.tsx +160 -0
- package/src/studio/app/auth/page.tsx +543 -0
- package/src/studio/app/chat/page.tsx +530 -0
- package/src/studio/app/chat/page.tsx.backup +390 -0
- package/src/studio/app/globals.css +410 -0
- package/src/studio/app/health/page.tsx +177 -0
- package/src/studio/app/layout.tsx +48 -0
- package/src/studio/app/page.tsx +337 -0
- package/src/studio/app/page.tsx.backup +346 -0
- package/src/studio/app/ping/page.tsx +204 -0
- package/src/studio/app/prompts/page.tsx +228 -0
- package/src/studio/app/resources/page.tsx +313 -0
- package/src/studio/components/EnlargeModal.tsx +116 -0
- package/src/studio/components/Sidebar.tsx +133 -0
- package/src/studio/components/ToolCard.tsx +108 -0
- package/src/studio/components/WidgetRenderer.tsx +99 -0
- package/src/studio/lib/api.ts +207 -0
- package/src/studio/lib/llm-service.ts +361 -0
- package/src/studio/lib/mcp-client.ts +168 -0
- package/src/studio/lib/store.ts +192 -0
- package/src/studio/lib/theme-provider.tsx +50 -0
- package/src/studio/lib/types.ts +107 -0
- package/src/studio/lib/widget-loader.ts +90 -0
- package/src/studio/middleware.ts +27 -0
- package/src/studio/next.config.js +16 -0
- package/src/studio/package-lock.json +2696 -0
- package/src/studio/package.json +34 -0
- package/src/studio/postcss.config.mjs +10 -0
- package/src/studio/tailwind.config.ts +67 -0
- package/src/studio/tsconfig.json +41 -0
- package/templates/typescript-auth/.env.example +23 -0
- package/templates/typescript-auth/src/app.module.ts +103 -0
- package/templates/typescript-auth/src/db/database.ts +163 -0
- package/templates/typescript-auth/src/db/seed.ts +374 -0
- package/templates/typescript-auth/src/db/setup.ts +87 -0
- package/templates/typescript-auth/src/events/analytics.service.ts +52 -0
- package/templates/typescript-auth/src/events/notification.service.ts +40 -0
- package/templates/typescript-auth/src/filters/global-exception.filter.ts +28 -0
- package/templates/typescript-auth/src/guards/README.md +75 -0
- package/templates/typescript-auth/src/guards/jwt.guard.ts +105 -0
- package/templates/typescript-auth/src/health/database.health.ts +41 -0
- package/templates/typescript-auth/src/index.ts +26 -0
- package/templates/typescript-auth/src/interceptors/transform.interceptor.ts +24 -0
- package/templates/typescript-auth/src/middleware/logging.middleware.ts +42 -0
- package/templates/typescript-auth/src/modules/addresses/addresses.module.ts +16 -0
- package/templates/typescript-auth/src/modules/addresses/addresses.prompts.ts +114 -0
- package/templates/typescript-auth/src/modules/addresses/addresses.resources.ts +40 -0
- package/templates/typescript-auth/src/modules/addresses/addresses.tools.ts +241 -0
- package/templates/typescript-auth/src/modules/auth/auth.module.ts +16 -0
- package/templates/typescript-auth/src/modules/auth/auth.prompts.ts +147 -0
- package/templates/typescript-auth/src/modules/auth/auth.resources.ts +84 -0
- package/templates/typescript-auth/src/modules/auth/auth.tools.ts +139 -0
- package/templates/typescript-auth/src/modules/cart/cart.module.ts +16 -0
- package/templates/typescript-auth/src/modules/cart/cart.prompts.ts +95 -0
- package/templates/typescript-auth/src/modules/cart/cart.resources.ts +44 -0
- package/templates/typescript-auth/src/modules/cart/cart.tools.ts +281 -0
- package/templates/typescript-auth/src/modules/orders/orders.module.ts +16 -0
- package/templates/typescript-auth/src/modules/orders/orders.prompts.ts +88 -0
- package/templates/typescript-auth/src/modules/orders/orders.resources.ts +48 -0
- package/templates/typescript-auth/src/modules/orders/orders.tools.ts +281 -0
- package/templates/typescript-auth/src/modules/products/products.module.ts +16 -0
- package/templates/typescript-auth/src/modules/products/products.prompts.ts +146 -0
- package/templates/typescript-auth/src/modules/products/products.resources.ts +98 -0
- package/templates/typescript-auth/src/modules/products/products.tools.ts +266 -0
- package/templates/typescript-auth/src/pipes/validation.pipe.ts +42 -0
- package/templates/typescript-auth/src/services/database.service.ts +90 -0
- package/templates/typescript-auth/src/widgets/app/add-to-cart/page.tsx +122 -0
- package/templates/typescript-auth/src/widgets/app/address-added/page.tsx +116 -0
- package/templates/typescript-auth/src/widgets/app/address-deleted/page.tsx +105 -0
- package/templates/typescript-auth/src/widgets/app/address-list/page.tsx +139 -0
- package/templates/typescript-auth/src/widgets/app/address-updated/page.tsx +153 -0
- package/templates/typescript-auth/src/widgets/app/cart-cleared/page.tsx +86 -0
- package/templates/typescript-auth/src/widgets/app/cart-updated/page.tsx +116 -0
- package/templates/typescript-auth/src/widgets/app/categories/page.tsx +134 -0
- package/templates/typescript-auth/src/widgets/app/layout.tsx +21 -0
- package/templates/typescript-auth/src/widgets/app/login-result/page.tsx +129 -0
- package/templates/typescript-auth/src/widgets/app/order-confirmation/page.tsx +206 -0
- package/templates/typescript-auth/src/widgets/app/order-details/page.tsx +225 -0
- package/templates/typescript-auth/src/widgets/app/order-history/page.tsx +218 -0
- package/templates/typescript-auth/src/widgets/app/product-card/page.tsx +121 -0
- package/templates/typescript-auth/src/widgets/app/products-grid/page.tsx +173 -0
- package/templates/typescript-auth/src/widgets/app/shopping-cart/page.tsx +187 -0
- package/templates/typescript-auth/src/widgets/app/whoami/page.tsx +165 -0
- package/templates/typescript-auth/src/widgets/next.config.js +38 -0
- package/templates/typescript-auth/src/widgets/package.json +18 -0
- package/templates/typescript-auth/src/widgets/styles/ecommerce.ts +169 -0
- package/templates/typescript-auth/src/widgets/tsconfig.json +28 -0
- package/templates/typescript-auth/src/widgets/types/tool-data.ts +141 -0
- package/templates/typescript-auth/src/widgets/widget-manifest.json +464 -0
- package/templates/typescript-auth/tsconfig.json +27 -0
- package/templates/typescript-auth-api-key/.env +15 -0
- package/templates/typescript-auth-api-key/.env.example +4 -0
- package/templates/typescript-auth-api-key/src/app.module.ts +38 -0
- package/templates/typescript-auth-api-key/src/guards/apikey.guard.ts +47 -0
- package/templates/typescript-auth-api-key/src/guards/multi-auth.guard.ts +157 -0
- package/templates/typescript-auth-api-key/src/health/system.health.ts +55 -0
- package/templates/typescript-auth-api-key/src/index.ts +47 -0
- package/templates/typescript-auth-api-key/src/modules/calculator/calculator.module.ts +12 -0
- package/templates/typescript-auth-api-key/src/modules/calculator/calculator.prompts.ts +73 -0
- package/templates/typescript-auth-api-key/src/modules/calculator/calculator.resources.ts +60 -0
- package/templates/typescript-auth-api-key/src/modules/calculator/calculator.tools.ts +71 -0
- package/templates/typescript-auth-api-key/src/modules/demo/demo.module.ts +18 -0
- package/templates/typescript-auth-api-key/src/modules/demo/demo.tools.ts +155 -0
- package/templates/typescript-auth-api-key/src/modules/demo/multi-auth.tools.ts +123 -0
- package/templates/typescript-auth-api-key/src/widgets/app/calculator-operations/page.tsx +133 -0
- package/templates/typescript-auth-api-key/src/widgets/app/calculator-result/page.tsx +134 -0
- package/templates/typescript-auth-api-key/src/widgets/app/layout.tsx +14 -0
- package/templates/typescript-auth-api-key/src/widgets/next.config.js +37 -0
- package/templates/typescript-auth-api-key/src/widgets/package.json +24 -0
- package/templates/typescript-auth-api-key/src/widgets/tsconfig.json +28 -0
- package/templates/typescript-auth-api-key/src/widgets/widget-manifest.json +48 -0
- package/templates/typescript-auth-api-key/tsconfig.json +23 -0
- package/templates/typescript-oauth/.env.example +91 -0
- package/templates/typescript-oauth/src/app.module.ts +89 -0
- package/templates/typescript-oauth/src/guards/oauth.guard.ts +127 -0
- package/templates/typescript-oauth/src/index.ts +74 -0
- package/templates/typescript-oauth/src/modules/demo/demo.module.ts +16 -0
- package/templates/typescript-oauth/src/modules/demo/demo.tools.ts +190 -0
- package/templates/typescript-oauth/src/widgets/app/calculator-operations/page.tsx +133 -0
- package/templates/typescript-oauth/src/widgets/app/calculator-result/page.tsx +134 -0
- package/templates/typescript-oauth/src/widgets/app/layout.tsx +14 -0
- package/templates/typescript-oauth/src/widgets/next.config.js +37 -0
- package/templates/typescript-oauth/src/widgets/package.json +24 -0
- package/templates/typescript-oauth/src/widgets/tsconfig.json +28 -0
- package/templates/typescript-oauth/src/widgets/widget-manifest.json +48 -0
- package/templates/typescript-oauth/tsconfig.json +23 -0
- package/templates/typescript-starter/.env.example +4 -0
- package/templates/typescript-starter/src/app.module.ts +34 -0
- package/templates/typescript-starter/src/health/system.health.ts +55 -0
- package/templates/typescript-starter/src/index.ts +27 -0
- package/templates/typescript-starter/src/modules/calculator/calculator.module.ts +12 -0
- package/templates/typescript-starter/src/modules/calculator/calculator.prompts.ts +73 -0
- package/templates/typescript-starter/src/modules/calculator/calculator.resources.ts +60 -0
- package/templates/typescript-starter/src/modules/calculator/calculator.tools.ts +71 -0
- package/templates/typescript-starter/src/widgets/app/calculator-operations/page.tsx +133 -0
- package/templates/typescript-starter/src/widgets/app/calculator-result/page.tsx +134 -0
- package/templates/typescript-starter/src/widgets/app/layout.tsx +14 -0
- package/templates/typescript-starter/src/widgets/next.config.js +37 -0
- package/templates/typescript-starter/src/widgets/package.json +24 -0
- package/templates/typescript-starter/src/widgets/tsconfig.json +28 -0
- package/templates/typescript-starter/src/widgets/widget-manifest.json +48 -0
- package/templates/typescript-starter/tsconfig.json +23 -0
- package/LICENSE_URLS_UPDATE_COMPLETE.md +0 -388
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { getMcpClient } from '@/lib/mcp-client';
|
|
3
|
+
|
|
4
|
+
export async function GET(
|
|
5
|
+
request: NextRequest,
|
|
6
|
+
{ params }: { params: { uri: string[] } }
|
|
7
|
+
) {
|
|
8
|
+
try {
|
|
9
|
+
const client = getMcpClient();
|
|
10
|
+
const uri = params.uri.join('/');
|
|
11
|
+
const decodedUri = decodeURIComponent(uri);
|
|
12
|
+
const result = await client.readResource(decodedUri);
|
|
13
|
+
return NextResponse.json(result);
|
|
14
|
+
} catch (error: any) {
|
|
15
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getMcpClient } from '@/lib/mcp-client';
|
|
3
|
+
|
|
4
|
+
export async function GET() {
|
|
5
|
+
try {
|
|
6
|
+
const client = getMcpClient();
|
|
7
|
+
const result = await client.listResources();
|
|
8
|
+
return NextResponse.json(result);
|
|
9
|
+
} catch (error: any) {
|
|
10
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getMcpClient } from '@/lib/mcp-client';
|
|
3
|
+
|
|
4
|
+
export async function GET() {
|
|
5
|
+
try {
|
|
6
|
+
const client = getMcpClient();
|
|
7
|
+
const result = await client.listRoots();
|
|
8
|
+
return NextResponse.json(result);
|
|
9
|
+
} catch (error: any) {
|
|
10
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { getMcpClient } from '@/lib/mcp-client';
|
|
3
|
+
|
|
4
|
+
export async function POST(request: NextRequest) {
|
|
5
|
+
try {
|
|
6
|
+
const client = getMcpClient();
|
|
7
|
+
const params = await request.json();
|
|
8
|
+
const result = await client.createCompletion(params);
|
|
9
|
+
return NextResponse.json(result);
|
|
10
|
+
} catch (error: any) {
|
|
11
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { getMcpClient } from '@/lib/mcp-client';
|
|
3
|
+
|
|
4
|
+
export async function POST(
|
|
5
|
+
request: NextRequest,
|
|
6
|
+
{ params }: { params: { name: string } }
|
|
7
|
+
) {
|
|
8
|
+
try {
|
|
9
|
+
const client = getMcpClient();
|
|
10
|
+
const body = await request.json();
|
|
11
|
+
|
|
12
|
+
// Extract args, JWT token, and API key from request body
|
|
13
|
+
const { args = {}, jwtToken, apiKey } = body;
|
|
14
|
+
|
|
15
|
+
// Inject auth tokens into tool arguments if available
|
|
16
|
+
const toolArgs = { ...args };
|
|
17
|
+
|
|
18
|
+
// Add _meta field for auth tokens
|
|
19
|
+
if (jwtToken || apiKey) {
|
|
20
|
+
toolArgs._meta = {
|
|
21
|
+
...(toolArgs._meta || {}),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
if (jwtToken) {
|
|
25
|
+
toolArgs._meta._jwt = jwtToken;
|
|
26
|
+
toolArgs._meta.authorization = `Bearer ${jwtToken}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (apiKey) {
|
|
30
|
+
toolArgs._meta.apiKey = apiKey;
|
|
31
|
+
toolArgs._meta['x-api-key'] = apiKey;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const result = await client.callTool(params.name, toolArgs);
|
|
36
|
+
return NextResponse.json(result);
|
|
37
|
+
} catch (error: any) {
|
|
38
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getMcpClient } from '@/lib/mcp-client';
|
|
3
|
+
|
|
4
|
+
export async function GET() {
|
|
5
|
+
try {
|
|
6
|
+
const client = getMcpClient();
|
|
7
|
+
|
|
8
|
+
// Check if connected, if not, throw error to trigger re-init
|
|
9
|
+
if (!client.isConnected()) {
|
|
10
|
+
console.error('❌ MCP client not connected in /api/tools');
|
|
11
|
+
return NextResponse.json({
|
|
12
|
+
error: 'MCP client not connected. Please refresh the page.'
|
|
13
|
+
}, { status: 500 });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const result = await client.listTools();
|
|
17
|
+
return NextResponse.json(result);
|
|
18
|
+
} catch (error: any) {
|
|
19
|
+
console.error('❌ Error in /api/tools:', error.message);
|
|
20
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getMcpClient } from '@/lib/mcp-client';
|
|
3
|
+
|
|
4
|
+
export async function GET() {
|
|
5
|
+
try {
|
|
6
|
+
const client = getMcpClient();
|
|
7
|
+
|
|
8
|
+
if (!client.isConnected()) {
|
|
9
|
+
return NextResponse.json({
|
|
10
|
+
error: 'MCP client not connected',
|
|
11
|
+
widgets: []
|
|
12
|
+
}, { status: 500 });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Read widget examples from MCP server as a resource
|
|
16
|
+
try {
|
|
17
|
+
const result = await client.readResource('widget://examples');
|
|
18
|
+
|
|
19
|
+
// Parse the widget examples data
|
|
20
|
+
const widgetData = JSON.parse(result.contents[0].text);
|
|
21
|
+
|
|
22
|
+
return NextResponse.json({
|
|
23
|
+
widgets: widgetData.widgets || [],
|
|
24
|
+
count: widgetData.widgets?.length || 0,
|
|
25
|
+
loaded: widgetData.loaded || false
|
|
26
|
+
});
|
|
27
|
+
} catch (resourceError: any) {
|
|
28
|
+
// Widget examples resource not available
|
|
29
|
+
console.log('No widget examples resource available');
|
|
30
|
+
return NextResponse.json({
|
|
31
|
+
widgets: [],
|
|
32
|
+
count: 0,
|
|
33
|
+
loaded: false
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
} catch (error: any) {
|
|
37
|
+
console.error('❌ Error in /api/widget-examples:', error.message);
|
|
38
|
+
return NextResponse.json(
|
|
39
|
+
{ error: 'Failed to fetch widget examples', widgets: [] },
|
|
40
|
+
{ status: 500 }
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { useRouter, useSearchParams } from 'next/navigation';
|
|
5
|
+
import { useStudioStore } from '@/lib/store';
|
|
6
|
+
import { Loader2, CheckCircle2, XCircle } from 'lucide-react';
|
|
7
|
+
|
|
8
|
+
export default function OAuthCallback() {
|
|
9
|
+
const router = useRouter();
|
|
10
|
+
const searchParams = useSearchParams();
|
|
11
|
+
const { oauthState, setJwtToken } = useStudioStore();
|
|
12
|
+
const [status, setStatus] = useState<'processing' | 'success' | 'error'>('processing');
|
|
13
|
+
const [message, setMessage] = useState('Processing authorization...');
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const handleCallback = async () => {
|
|
17
|
+
try {
|
|
18
|
+
// Get authorization code and state from URL
|
|
19
|
+
const code = searchParams.get('code');
|
|
20
|
+
const state = searchParams.get('state');
|
|
21
|
+
const error = searchParams.get('error');
|
|
22
|
+
const errorDescription = searchParams.get('error_description');
|
|
23
|
+
|
|
24
|
+
// Check for errors
|
|
25
|
+
if (error) {
|
|
26
|
+
setStatus('error');
|
|
27
|
+
setMessage(`Authorization failed: ${errorDescription || error}`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Validate state
|
|
32
|
+
const storedState = sessionStorage.getItem('oauth_state');
|
|
33
|
+
if (!state || state !== storedState) {
|
|
34
|
+
setStatus('error');
|
|
35
|
+
setMessage('Invalid state parameter. Possible CSRF attack.');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Validate code
|
|
40
|
+
if (!code) {
|
|
41
|
+
setStatus('error');
|
|
42
|
+
setMessage('Authorization code not received');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Get code verifier and client credentials
|
|
47
|
+
const codeVerifier = sessionStorage.getItem('oauth_code_verifier');
|
|
48
|
+
if (!codeVerifier) {
|
|
49
|
+
setStatus('error');
|
|
50
|
+
setMessage('Code verifier not found. Please try again.');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!oauthState.clientRegistration?.client_id) {
|
|
55
|
+
setStatus('error');
|
|
56
|
+
setMessage('Client ID not found. Please register again.');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!oauthState.authServerMetadata?.token_endpoint) {
|
|
61
|
+
setStatus('error');
|
|
62
|
+
setMessage('Token endpoint not found in server metadata');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
setMessage('Exchanging authorization code for tokens...');
|
|
67
|
+
|
|
68
|
+
// Exchange code for tokens
|
|
69
|
+
const tokenResponse = await fetch(oauthState.authServerMetadata.token_endpoint, {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers: {
|
|
72
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
73
|
+
},
|
|
74
|
+
body: new URLSearchParams({
|
|
75
|
+
grant_type: 'authorization_code',
|
|
76
|
+
code,
|
|
77
|
+
redirect_uri: 'http://localhost:3000/auth/callback',
|
|
78
|
+
client_id: oauthState.clientRegistration.client_id,
|
|
79
|
+
...(oauthState.clientRegistration.client_secret && {
|
|
80
|
+
client_secret: oauthState.clientRegistration.client_secret,
|
|
81
|
+
}),
|
|
82
|
+
code_verifier: codeVerifier,
|
|
83
|
+
}),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
if (!tokenResponse.ok) {
|
|
87
|
+
const errorData = await tokenResponse.json().catch(() => ({}));
|
|
88
|
+
setStatus('error');
|
|
89
|
+
setMessage(`Token exchange failed: ${errorData.error_description || errorData.error || tokenResponse.statusText}`);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const tokens = await tokenResponse.json();
|
|
94
|
+
|
|
95
|
+
// Store access token as JWT token
|
|
96
|
+
if (tokens.access_token) {
|
|
97
|
+
setJwtToken(tokens.access_token);
|
|
98
|
+
|
|
99
|
+
// Clean up session storage
|
|
100
|
+
sessionStorage.removeItem('oauth_code_verifier');
|
|
101
|
+
sessionStorage.removeItem('oauth_state');
|
|
102
|
+
|
|
103
|
+
setStatus('success');
|
|
104
|
+
setMessage('Authorization successful! Redirecting...');
|
|
105
|
+
|
|
106
|
+
// Redirect back to auth page after 2 seconds
|
|
107
|
+
setTimeout(() => {
|
|
108
|
+
router.push('/auth');
|
|
109
|
+
}, 2000);
|
|
110
|
+
} else {
|
|
111
|
+
setStatus('error');
|
|
112
|
+
setMessage('Access token not received');
|
|
113
|
+
}
|
|
114
|
+
} catch (error: any) {
|
|
115
|
+
console.error('OAuth callback error:', error);
|
|
116
|
+
setStatus('error');
|
|
117
|
+
setMessage(`Error: ${error.message || 'Unknown error occurred'}`);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
handleCallback();
|
|
122
|
+
}, [searchParams, oauthState, setJwtToken, router]);
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<div className="min-h-screen bg-background flex items-center justify-center p-8">
|
|
126
|
+
<div className="card p-8 max-w-md w-full text-center">
|
|
127
|
+
{status === 'processing' && (
|
|
128
|
+
<>
|
|
129
|
+
<Loader2 className="w-16 h-16 text-primary mx-auto mb-4 animate-spin" />
|
|
130
|
+
<h1 className="text-2xl font-bold text-foreground mb-2">Processing...</h1>
|
|
131
|
+
<p className="text-muted-foreground">{message}</p>
|
|
132
|
+
</>
|
|
133
|
+
)}
|
|
134
|
+
|
|
135
|
+
{status === 'success' && (
|
|
136
|
+
<>
|
|
137
|
+
<CheckCircle2 className="w-16 h-16 text-emerald-500 mx-auto mb-4" />
|
|
138
|
+
<h1 className="text-2xl font-bold text-foreground mb-2">Success!</h1>
|
|
139
|
+
<p className="text-muted-foreground">{message}</p>
|
|
140
|
+
</>
|
|
141
|
+
)}
|
|
142
|
+
|
|
143
|
+
{status === 'error' && (
|
|
144
|
+
<>
|
|
145
|
+
<XCircle className="w-16 h-16 text-red-500 mx-auto mb-4" />
|
|
146
|
+
<h1 className="text-2xl font-bold text-foreground mb-2">Authorization Failed</h1>
|
|
147
|
+
<p className="text-muted-foreground mb-4">{message}</p>
|
|
148
|
+
<button
|
|
149
|
+
onClick={() => router.push('/auth')}
|
|
150
|
+
className="btn btn-primary"
|
|
151
|
+
>
|
|
152
|
+
Back to Auth Page
|
|
153
|
+
</button>
|
|
154
|
+
</>
|
|
155
|
+
)}
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|