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,123 @@
|
|
|
1
|
+
import { Injectable, ToolDecorator as Tool, UseGuards, z, ExecutionContext } from 'nitrostack';
|
|
2
|
+
import { MultiAuthGuard, DualAuthGuard } from '../../guards/multi-auth.guard.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Multi-Auth Demo Tools
|
|
6
|
+
*
|
|
7
|
+
* Demonstrates advanced authentication patterns:
|
|
8
|
+
* 1. Tools that accept EITHER JWT OR API key
|
|
9
|
+
* 2. Tools that require BOTH JWT AND API key
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
@Injectable()
|
|
13
|
+
export class MultiAuthTools {
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* FLEXIBLE AUTH - Accepts JWT OR API key
|
|
17
|
+
* Users can authenticate with either method
|
|
18
|
+
*/
|
|
19
|
+
@Tool({
|
|
20
|
+
name: 'get_flexible_data',
|
|
21
|
+
description: 'Get data using JWT token OR API key (either works)',
|
|
22
|
+
inputSchema: z.object({
|
|
23
|
+
query: z.string().describe('Search query'),
|
|
24
|
+
}),
|
|
25
|
+
})
|
|
26
|
+
@UseGuards(MultiAuthGuard)
|
|
27
|
+
async getFlexibleData(args: { query: string }, context?: ExecutionContext) {
|
|
28
|
+
const authMethod = (context?.metadata as any)?._authMethod || 'unknown';
|
|
29
|
+
const subject = context?.auth?.subject || 'unknown';
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
message: `Data retrieved successfully using ${authMethod}`,
|
|
33
|
+
authInfo: {
|
|
34
|
+
method: authMethod,
|
|
35
|
+
subject: subject,
|
|
36
|
+
flexibleAuth: true,
|
|
37
|
+
},
|
|
38
|
+
query: args.query,
|
|
39
|
+
results: [
|
|
40
|
+
{ id: 1, title: 'Result 1', data: 'Sample data 1' },
|
|
41
|
+
{ id: 2, title: 'Result 2', data: 'Sample data 2' },
|
|
42
|
+
{ id: 3, title: 'Result 3', data: 'Sample data 3' },
|
|
43
|
+
],
|
|
44
|
+
hint: 'This tool accepts either JWT token or API key. Try it with different auth methods!',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* DUAL AUTH - Requires BOTH JWT AND API key
|
|
50
|
+
* For highly sensitive operations
|
|
51
|
+
*/
|
|
52
|
+
@Tool({
|
|
53
|
+
name: 'perform_critical_action',
|
|
54
|
+
description: 'Perform critical action (requires BOTH JWT token AND API key)',
|
|
55
|
+
inputSchema: z.object({
|
|
56
|
+
actionType: z.enum(['delete_account', 'transfer_funds', 'change_permissions']).describe('Type of critical action'),
|
|
57
|
+
confirmation: z.boolean().describe('Confirmation (must be true)'),
|
|
58
|
+
}),
|
|
59
|
+
})
|
|
60
|
+
@UseGuards(DualAuthGuard)
|
|
61
|
+
async performCriticalAction(
|
|
62
|
+
args: { actionType: string; confirmation: boolean },
|
|
63
|
+
context?: ExecutionContext
|
|
64
|
+
) {
|
|
65
|
+
if (!args.confirmation) {
|
|
66
|
+
throw new Error('Confirmation required for critical actions');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const subject = context?.auth?.subject || 'unknown';
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
message: `Critical action "${args.actionType}" executed successfully`,
|
|
73
|
+
security: {
|
|
74
|
+
authMethod: 'JWT + API Key (Dual Authentication)',
|
|
75
|
+
subject: subject,
|
|
76
|
+
verified: true,
|
|
77
|
+
timestamp: new Date().toISOString(),
|
|
78
|
+
},
|
|
79
|
+
action: {
|
|
80
|
+
type: args.actionType,
|
|
81
|
+
status: 'completed',
|
|
82
|
+
confirmed: args.confirmation,
|
|
83
|
+
},
|
|
84
|
+
warning: '⚠️ This action required dual authentication for security',
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* AUTH INFO - Check which auth methods are active
|
|
90
|
+
* Uses flexible auth to demonstrate detection
|
|
91
|
+
*/
|
|
92
|
+
@Tool({
|
|
93
|
+
name: 'check_auth_methods',
|
|
94
|
+
description: 'Check which authentication methods are currently active',
|
|
95
|
+
inputSchema: z.object({}),
|
|
96
|
+
})
|
|
97
|
+
@UseGuards(MultiAuthGuard)
|
|
98
|
+
async checkAuthMethods(args: {}, context?: ExecutionContext) {
|
|
99
|
+
const hasJWT = !!(context?.metadata?._jwt || context?.metadata?.authorization);
|
|
100
|
+
const hasAPIKey = !!(context?.metadata?.apiKey || context?.metadata?.['x-api-key']);
|
|
101
|
+
const authMethod = (context?.metadata as any)?._authMethod || 'unknown';
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
message: 'Authentication methods detected',
|
|
105
|
+
activeAuth: {
|
|
106
|
+
method: authMethod,
|
|
107
|
+
jwt: hasJWT,
|
|
108
|
+
apiKey: hasAPIKey,
|
|
109
|
+
both: hasJWT && hasAPIKey,
|
|
110
|
+
},
|
|
111
|
+
subject: context?.auth?.subject || 'unknown',
|
|
112
|
+
scopes: context?.auth?.scopes || [],
|
|
113
|
+
recommendations: {
|
|
114
|
+
jwtOnly: hasJWT && !hasAPIKey ? '✓ Using JWT authentication' : null,
|
|
115
|
+
apiKeyOnly: !hasJWT && hasAPIKey ? '✓ Using API key authentication' : null,
|
|
116
|
+
both: hasJWT && hasAPIKey ? '✓ Using dual authentication (most secure!)' : null,
|
|
117
|
+
none: !hasJWT && !hasAPIKey ? '⚠️ No authentication detected (this should not happen)' : null,
|
|
118
|
+
},
|
|
119
|
+
hint: 'Set JWT token and/or API key in Studio Auth tab to see different combinations',
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { withToolData } from 'nitrostack/widgets';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Widget Metadata (stored in widget-manifest.json)
|
|
7
|
+
*
|
|
8
|
+
* This widget lists all available calculator operations.
|
|
9
|
+
*
|
|
10
|
+
* Example includes all four operations: add, subtract, multiply, divide
|
|
11
|
+
*
|
|
12
|
+
* Frontend developers: Edit widget-manifest.json to update examples
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
interface Operation {
|
|
16
|
+
name: string;
|
|
17
|
+
symbol: string;
|
|
18
|
+
description: string;
|
|
19
|
+
example: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface OperationsData {
|
|
23
|
+
operations: Operation[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function CalculatorOperations({ data }: { data: OperationsData }) {
|
|
27
|
+
const getOperationColor = (name: string) => {
|
|
28
|
+
const colors: Record<string, string> = {
|
|
29
|
+
add: '#10b981',
|
|
30
|
+
subtract: '#f59e0b',
|
|
31
|
+
multiply: '#3b82f6',
|
|
32
|
+
divide: '#8b5cf6'
|
|
33
|
+
};
|
|
34
|
+
return colors[name] || '#6b7280';
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div style={{
|
|
39
|
+
padding: '24px',
|
|
40
|
+
background: 'linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%)',
|
|
41
|
+
borderRadius: '16px',
|
|
42
|
+
maxWidth: '500px'
|
|
43
|
+
}}>
|
|
44
|
+
<h3 style={{
|
|
45
|
+
margin: '0 0 20px 0',
|
|
46
|
+
fontSize: '24px',
|
|
47
|
+
color: '#1f2937',
|
|
48
|
+
display: 'flex',
|
|
49
|
+
alignItems: 'center',
|
|
50
|
+
gap: '12px'
|
|
51
|
+
}}>
|
|
52
|
+
<span style={{ fontSize: '32px' }}>🔢</span>
|
|
53
|
+
Calculator Operations
|
|
54
|
+
</h3>
|
|
55
|
+
|
|
56
|
+
<div style={{ display: 'grid', gap: '12px' }}>
|
|
57
|
+
{data.operations.map((op) => (
|
|
58
|
+
<div
|
|
59
|
+
key={op.name}
|
|
60
|
+
style={{
|
|
61
|
+
background: 'white',
|
|
62
|
+
borderRadius: '12px',
|
|
63
|
+
padding: '16px',
|
|
64
|
+
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
|
|
65
|
+
borderLeft: `4px solid ${getOperationColor(op.name)}`
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
<div style={{
|
|
69
|
+
display: 'flex',
|
|
70
|
+
alignItems: 'center',
|
|
71
|
+
gap: '12px',
|
|
72
|
+
marginBottom: '8px'
|
|
73
|
+
}}>
|
|
74
|
+
<div style={{
|
|
75
|
+
width: '40px',
|
|
76
|
+
height: '40px',
|
|
77
|
+
borderRadius: '10px',
|
|
78
|
+
background: getOperationColor(op.name),
|
|
79
|
+
display: 'flex',
|
|
80
|
+
alignItems: 'center',
|
|
81
|
+
justifyContent: 'center',
|
|
82
|
+
color: 'white',
|
|
83
|
+
fontSize: '24px',
|
|
84
|
+
fontWeight: 'bold'
|
|
85
|
+
}}>
|
|
86
|
+
{op.symbol}
|
|
87
|
+
</div>
|
|
88
|
+
<div>
|
|
89
|
+
<div style={{
|
|
90
|
+
fontSize: '16px',
|
|
91
|
+
fontWeight: 'bold',
|
|
92
|
+
color: '#1f2937',
|
|
93
|
+
textTransform: 'capitalize'
|
|
94
|
+
}}>
|
|
95
|
+
{op.name}
|
|
96
|
+
</div>
|
|
97
|
+
<div style={{
|
|
98
|
+
fontSize: '14px',
|
|
99
|
+
color: '#6b7280'
|
|
100
|
+
}}>
|
|
101
|
+
{op.description}
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
<div style={{
|
|
106
|
+
marginTop: '12px',
|
|
107
|
+
padding: '8px 12px',
|
|
108
|
+
background: '#f9fafb',
|
|
109
|
+
borderRadius: '8px',
|
|
110
|
+
fontFamily: 'monospace',
|
|
111
|
+
fontSize: '14px',
|
|
112
|
+
color: '#374151'
|
|
113
|
+
}}>
|
|
114
|
+
{op.example}
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
))}
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
<div style={{
|
|
121
|
+
marginTop: '16px',
|
|
122
|
+
textAlign: 'center',
|
|
123
|
+
fontSize: '12px',
|
|
124
|
+
color: '#6b7280'
|
|
125
|
+
}}>
|
|
126
|
+
✨ Use the 'calculate' tool to perform these operations
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export default withToolData(CalculatorOperations);
|
|
133
|
+
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { withToolData } from 'nitrostack/widgets';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Widget Metadata (stored in widget-manifest.json)
|
|
7
|
+
*
|
|
8
|
+
* This widget displays calculation results with operation details.
|
|
9
|
+
*
|
|
10
|
+
* Examples defined in manifest:
|
|
11
|
+
* - Addition: 5 + 3 = 8
|
|
12
|
+
* - Multiplication: 6 × 7 = 42
|
|
13
|
+
* - Division: 20 ÷ 4 = 5
|
|
14
|
+
*
|
|
15
|
+
* Frontend developers: Edit widget-manifest.json to update examples
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
interface CalculatorData {
|
|
19
|
+
operation: string;
|
|
20
|
+
a: number;
|
|
21
|
+
b: number;
|
|
22
|
+
result: number;
|
|
23
|
+
expression: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function CalculatorResult({ data }: { data: CalculatorData }) {
|
|
27
|
+
const getOperationColor = (op: string) => {
|
|
28
|
+
const colors: Record<string, string> = {
|
|
29
|
+
add: '#10b981',
|
|
30
|
+
subtract: '#f59e0b',
|
|
31
|
+
multiply: '#3b82f6',
|
|
32
|
+
divide: '#8b5cf6'
|
|
33
|
+
};
|
|
34
|
+
return colors[op] || '#6b7280';
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const getOperationIcon = (op: string) => {
|
|
38
|
+
const icons: Record<string, string> = {
|
|
39
|
+
add: '➕',
|
|
40
|
+
subtract: '➖',
|
|
41
|
+
multiply: '✖️',
|
|
42
|
+
divide: '➗'
|
|
43
|
+
};
|
|
44
|
+
return icons[op] || '🔢';
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const color = getOperationColor(data.operation);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div style={{
|
|
51
|
+
padding: '24px',
|
|
52
|
+
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
53
|
+
borderRadius: '16px',
|
|
54
|
+
color: 'white',
|
|
55
|
+
maxWidth: '400px',
|
|
56
|
+
boxShadow: '0 10px 30px rgba(0,0,0,0.2)'
|
|
57
|
+
}}>
|
|
58
|
+
<div style={{
|
|
59
|
+
display: 'flex',
|
|
60
|
+
alignItems: 'center',
|
|
61
|
+
gap: '12px',
|
|
62
|
+
marginBottom: '20px'
|
|
63
|
+
}}>
|
|
64
|
+
<span style={{ fontSize: '32px' }}>
|
|
65
|
+
{getOperationIcon(data.operation)}
|
|
66
|
+
</span>
|
|
67
|
+
<div>
|
|
68
|
+
<h3 style={{ margin: 0, fontSize: '18px', opacity: 0.9 }}>
|
|
69
|
+
Calculator Result
|
|
70
|
+
</h3>
|
|
71
|
+
<p style={{ margin: '4px 0 0 0', fontSize: '14px', opacity: 0.7 }}>
|
|
72
|
+
{data.operation.charAt(0).toUpperCase() + data.operation.slice(1)}
|
|
73
|
+
</p>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<div style={{
|
|
78
|
+
background: 'rgba(255, 255, 255, 0.15)',
|
|
79
|
+
borderRadius: '12px',
|
|
80
|
+
padding: '20px',
|
|
81
|
+
backdropFilter: 'blur(10px)',
|
|
82
|
+
marginBottom: '16px'
|
|
83
|
+
}}>
|
|
84
|
+
<div style={{
|
|
85
|
+
fontSize: '28px',
|
|
86
|
+
fontWeight: 'bold',
|
|
87
|
+
textAlign: 'center',
|
|
88
|
+
marginBottom: '12px',
|
|
89
|
+
fontFamily: 'monospace'
|
|
90
|
+
}}>
|
|
91
|
+
{data.expression}
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<div style={{
|
|
95
|
+
display: 'flex',
|
|
96
|
+
justifyContent: 'space-around',
|
|
97
|
+
fontSize: '14px',
|
|
98
|
+
opacity: 0.9,
|
|
99
|
+
marginTop: '16px'
|
|
100
|
+
}}>
|
|
101
|
+
<div style={{ textAlign: 'center' }}>
|
|
102
|
+
<div style={{ fontSize: '12px', opacity: 0.7 }}>First</div>
|
|
103
|
+
<div style={{ fontWeight: 'bold', fontSize: '20px' }}>{data.a}</div>
|
|
104
|
+
</div>
|
|
105
|
+
<div style={{ textAlign: 'center' }}>
|
|
106
|
+
<div style={{ fontSize: '12px', opacity: 0.7 }}>Second</div>
|
|
107
|
+
<div style={{ fontWeight: 'bold', fontSize: '20px' }}>{data.b}</div>
|
|
108
|
+
</div>
|
|
109
|
+
<div style={{ textAlign: 'center' }}>
|
|
110
|
+
<div style={{ fontSize: '12px', opacity: 0.7 }}>Result</div>
|
|
111
|
+
<div style={{
|
|
112
|
+
fontWeight: 'bold',
|
|
113
|
+
fontSize: '24px',
|
|
114
|
+
color: '#fbbf24'
|
|
115
|
+
}}>
|
|
116
|
+
{data.result}
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<div style={{
|
|
123
|
+
fontSize: '12px',
|
|
124
|
+
textAlign: 'center',
|
|
125
|
+
opacity: 0.7
|
|
126
|
+
}}>
|
|
127
|
+
✨ NitroStack Calculator
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export default withToolData(CalculatorResult);
|
|
134
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** @type {import('next').NextConfig} */
|
|
2
|
+
const nextConfig = {
|
|
3
|
+
reactStrictMode: true,
|
|
4
|
+
transpilePackages: ['nitrostack'],
|
|
5
|
+
|
|
6
|
+
// Development optimizations to prevent cache corruption
|
|
7
|
+
...(process.env.NODE_ENV === 'development' && {
|
|
8
|
+
// Use memory cache instead of filesystem cache in dev to avoid stale chunks
|
|
9
|
+
webpack: (config, { isServer }) => {
|
|
10
|
+
// Disable persistent caching in development to prevent chunk reference errors
|
|
11
|
+
if (config.cache && config.cache.type === 'filesystem') {
|
|
12
|
+
config.cache = {
|
|
13
|
+
type: 'memory',
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Improve cache busting for new files
|
|
18
|
+
if (!isServer) {
|
|
19
|
+
config.cache = false; // Disable cache completely on client in dev
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return config;
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
// Disable build activity indicator which can cause issues
|
|
26
|
+
devIndicators: {
|
|
27
|
+
buildActivity: false,
|
|
28
|
+
buildActivityPosition: 'bottom-right',
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
// Faster dev server
|
|
32
|
+
compress: false,
|
|
33
|
+
}),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default nextConfig;
|
|
37
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "calculator-widgets",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"private": true,
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "next dev -p 3001",
|
|
8
|
+
"build": "next build",
|
|
9
|
+
"start": "next start -p 3001"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"next": "^14.2.5",
|
|
13
|
+
"react": "^18.3.1",
|
|
14
|
+
"react-dom": "^18.3.1",
|
|
15
|
+
"nitrostack": "^1.0.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^20",
|
|
19
|
+
"@types/react": "^18",
|
|
20
|
+
"@types/react-dom": "^18",
|
|
21
|
+
"typescript": "^5"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "preserve",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"plugins": [
|
|
17
|
+
{
|
|
18
|
+
"name": "next"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": ["./*"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
26
|
+
"exclude": ["node_modules"]
|
|
27
|
+
}
|
|
28
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0.0",
|
|
3
|
+
"widgets": [
|
|
4
|
+
{
|
|
5
|
+
"uri": "/calculator-result",
|
|
6
|
+
"name": "Calculator Result",
|
|
7
|
+
"description": "Displays the result of a calculation with operation details",
|
|
8
|
+
"examples": [
|
|
9
|
+
{
|
|
10
|
+
"name": "Addition Example",
|
|
11
|
+
"description": "Shows the result of adding 5 + 3",
|
|
12
|
+
"data": {
|
|
13
|
+
"operation": "add",
|
|
14
|
+
"a": 5,
|
|
15
|
+
"b": 3,
|
|
16
|
+
"result": 8,
|
|
17
|
+
"expression": "5 + 3 = 8"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "Multiplication Example",
|
|
22
|
+
"description": "Shows the result of multiplying 6 × 7",
|
|
23
|
+
"data": {
|
|
24
|
+
"operation": "multiply",
|
|
25
|
+
"a": 6,
|
|
26
|
+
"b": 7,
|
|
27
|
+
"result": 42,
|
|
28
|
+
"expression": "6 × 7 = 42"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"name": "Division Example",
|
|
33
|
+
"description": "Shows the result of dividing 20 ÷ 4",
|
|
34
|
+
"data": {
|
|
35
|
+
"operation": "divide",
|
|
36
|
+
"a": 20,
|
|
37
|
+
"b": 4,
|
|
38
|
+
"result": 5,
|
|
39
|
+
"expression": "20 ÷ 4 = 5"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"tags": ["calculator", "math", "result"]
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"generatedAt": "2025-01-01T00:00:00.000Z"
|
|
47
|
+
}
|
|
48
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"outDir": "./dist",
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"declaration": true,
|
|
15
|
+
"declarationMap": true,
|
|
16
|
+
"sourceMap": true,
|
|
17
|
+
"experimentalDecorators": true,
|
|
18
|
+
"emitDecoratorMetadata": true
|
|
19
|
+
},
|
|
20
|
+
"include": ["src/**/*"],
|
|
21
|
+
"exclude": ["node_modules", "dist", "src/widgets"]
|
|
22
|
+
}
|
|
23
|
+
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# OAuth 2.1 MCP Server Configuration
|
|
2
|
+
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# REQUIRED: Server Configuration
|
|
5
|
+
# =============================================================================
|
|
6
|
+
|
|
7
|
+
# Your MCP server's public URL (used for token audience binding - RFC 8707)
|
|
8
|
+
# This MUST match the URL where your MCP server is accessible
|
|
9
|
+
# Example: https://mcp.yourapp.com or http://localhost:3000 for development
|
|
10
|
+
RESOURCE_URI=https://mcp.example.com
|
|
11
|
+
|
|
12
|
+
# Your OAuth 2.1 authorization server URL
|
|
13
|
+
# This is the base URL of your OAuth provider (Auth0, Okta, Keycloak, etc.)
|
|
14
|
+
# Example for Auth0: https://your-tenant.auth0.com
|
|
15
|
+
# Example for Okta: https://your-domain.okta.com
|
|
16
|
+
AUTH_SERVER_URL=https://auth.example.com
|
|
17
|
+
|
|
18
|
+
# =============================================================================
|
|
19
|
+
# OPTIONAL: Token Configuration
|
|
20
|
+
# =============================================================================
|
|
21
|
+
|
|
22
|
+
# Expected token audience (defaults to RESOURCE_URI if not set)
|
|
23
|
+
# This MUST match the audience claim in access tokens
|
|
24
|
+
TOKEN_AUDIENCE=https://mcp.example.com
|
|
25
|
+
|
|
26
|
+
# Expected token issuer (recommended for security)
|
|
27
|
+
# This MUST match the issuer claim in access tokens
|
|
28
|
+
# Example for Auth0: https://your-tenant.auth0.com/
|
|
29
|
+
# Example for Okta: https://your-domain.okta.com/oauth2/default
|
|
30
|
+
TOKEN_ISSUER=https://auth.example.com/
|
|
31
|
+
|
|
32
|
+
# =============================================================================
|
|
33
|
+
# OPTIONAL: Token Introspection (for opaque tokens)
|
|
34
|
+
# =============================================================================
|
|
35
|
+
|
|
36
|
+
# If your OAuth provider issues opaque tokens (not JWTs), configure these:
|
|
37
|
+
|
|
38
|
+
# Token introspection endpoint (RFC 7662)
|
|
39
|
+
# Example for Auth0: https://your-tenant.auth0.com/oauth/token/introspection
|
|
40
|
+
# Example for Okta: https://your-domain.okta.com/oauth2/default/v1/introspect
|
|
41
|
+
# INTROSPECTION_ENDPOINT=https://auth.example.com/oauth/introspect
|
|
42
|
+
|
|
43
|
+
# Client credentials for introspection
|
|
44
|
+
# These are separate from your MCP client credentials
|
|
45
|
+
# INTROSPECTION_CLIENT_ID=your-introspection-client-id
|
|
46
|
+
# INTROSPECTION_CLIENT_SECRET=your-introspection-client-secret
|
|
47
|
+
|
|
48
|
+
# =============================================================================
|
|
49
|
+
# Provider-Specific Examples
|
|
50
|
+
# =============================================================================
|
|
51
|
+
|
|
52
|
+
# --- Auth0 Example ---
|
|
53
|
+
# RESOURCE_URI=https://mcp.yourapp.com
|
|
54
|
+
# AUTH_SERVER_URL=https://your-tenant.auth0.com
|
|
55
|
+
# TOKEN_AUDIENCE=https://mcp.yourapp.com
|
|
56
|
+
# TOKEN_ISSUER=https://your-tenant.auth0.com/
|
|
57
|
+
|
|
58
|
+
# --- Okta Example ---
|
|
59
|
+
# RESOURCE_URI=https://mcp.yourapp.com
|
|
60
|
+
# AUTH_SERVER_URL=https://your-domain.okta.com/oauth2/default
|
|
61
|
+
# TOKEN_AUDIENCE=api://mcp.yourapp.com
|
|
62
|
+
# TOKEN_ISSUER=https://your-domain.okta.com/oauth2/default
|
|
63
|
+
|
|
64
|
+
# --- Keycloak Example ---
|
|
65
|
+
# RESOURCE_URI=https://mcp.yourapp.com
|
|
66
|
+
# AUTH_SERVER_URL=https://keycloak.yourapp.com/realms/your-realm
|
|
67
|
+
# TOKEN_AUDIENCE=mcp-server
|
|
68
|
+
# TOKEN_ISSUER=https://keycloak.yourapp.com/realms/your-realm
|
|
69
|
+
|
|
70
|
+
# =============================================================================
|
|
71
|
+
# Setup Instructions
|
|
72
|
+
# =============================================================================
|
|
73
|
+
#
|
|
74
|
+
# 1. Copy this file to .env:
|
|
75
|
+
# cp .env.example .env
|
|
76
|
+
#
|
|
77
|
+
# 2. Configure your OAuth provider (see OAUTH_SETUP.md)
|
|
78
|
+
#
|
|
79
|
+
# 3. Update the values above with your provider's URLs
|
|
80
|
+
#
|
|
81
|
+
# 4. Start the server:
|
|
82
|
+
# npm run dev
|
|
83
|
+
#
|
|
84
|
+
# 5. Configure OAuth in HyperMCP Studio:
|
|
85
|
+
# - Open Studio (http://localhost:3000)
|
|
86
|
+
# - Go to Auth → OAuth 2.1 tab
|
|
87
|
+
# - Click "Discover & Register"
|
|
88
|
+
# - Complete the OAuth flow
|
|
89
|
+
#
|
|
90
|
+
# For detailed setup guides for each provider, see OAUTH_SETUP.md
|
|
91
|
+
|