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,147 @@
|
|
|
1
|
+
import { PromptDecorator as Prompt, ExecutionContext } from 'nitrostack';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Authentication Prompts
|
|
5
|
+
* Provides helpful prompts for authentication-related tasks
|
|
6
|
+
*/
|
|
7
|
+
export class AuthPrompts {
|
|
8
|
+
/**
|
|
9
|
+
* Authentication help prompt
|
|
10
|
+
*/
|
|
11
|
+
@Prompt({
|
|
12
|
+
name: 'auth-help',
|
|
13
|
+
description: 'Get help with authentication and login process',
|
|
14
|
+
arguments: [
|
|
15
|
+
{
|
|
16
|
+
name: 'issue',
|
|
17
|
+
description: 'The authentication issue you are facing',
|
|
18
|
+
required: false,
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
})
|
|
22
|
+
async authHelp(args: Record<string, any>, context: ExecutionContext) {
|
|
23
|
+
const issue = args.issue || 'general';
|
|
24
|
+
|
|
25
|
+
const baseMessages = [
|
|
26
|
+
{
|
|
27
|
+
role: 'user' as const,
|
|
28
|
+
content: `I need help with authentication in the e-commerce system. My issue: ${issue}`,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
role: 'assistant' as const,
|
|
32
|
+
content: `I'll help you with authentication. Here's what you need to know:
|
|
33
|
+
|
|
34
|
+
**Login Process:**
|
|
35
|
+
1. Use the \`login\` tool with email and password
|
|
36
|
+
2. You'll receive a JWT token valid for 24 hours
|
|
37
|
+
3. Include this token in subsequent requests
|
|
38
|
+
|
|
39
|
+
**Test Accounts:**
|
|
40
|
+
- alice@example.com / password123
|
|
41
|
+
- bob@example.com / password123
|
|
42
|
+
- charlie@example.com / password123
|
|
43
|
+
|
|
44
|
+
**Including Token:**
|
|
45
|
+
- In Inspector: Paste token in "JWT Token" field
|
|
46
|
+
- Or use: Authorization: Bearer <your-token>
|
|
47
|
+
|
|
48
|
+
**Protected Tools:**
|
|
49
|
+
The following tools require authentication:
|
|
50
|
+
- whoami - Get your profile
|
|
51
|
+
- add_to_cart - Add items to cart
|
|
52
|
+
- view_cart - View your cart
|
|
53
|
+
- create_order - Place orders
|
|
54
|
+
- get_order_history - View order history
|
|
55
|
+
- add_address - Manage addresses
|
|
56
|
+
|
|
57
|
+
**Common Issues:**
|
|
58
|
+
${issue === 'invalid-token' ? '- Token expired: Login again to get a new token\n- Invalid format: Ensure you copied the complete token' : ''}
|
|
59
|
+
${issue === 'unauthorized' ? '- Missing token: Make sure to login first\n- Wrong credentials: Check your email and password' : ''}
|
|
60
|
+
${issue === 'general' ? '- Token expired? Login again\n- Forgot which email? Use test accounts above\n- Need to test? All test users have password: password123' : ''}
|
|
61
|
+
|
|
62
|
+
**Security Notes:**
|
|
63
|
+
- Tokens expire after 24 hours for security
|
|
64
|
+
- Passwords are hashed with bcrypt
|
|
65
|
+
- Never share your token with others`,
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
return baseMessages;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* JWT token explanation prompt
|
|
74
|
+
*/
|
|
75
|
+
@Prompt({
|
|
76
|
+
name: 'jwt-explained',
|
|
77
|
+
description: 'Understand how JWT authentication works in this system',
|
|
78
|
+
})
|
|
79
|
+
async jwtExplained(args: Record<string, any>, context: ExecutionContext) {
|
|
80
|
+
return [
|
|
81
|
+
{
|
|
82
|
+
role: 'user' as const,
|
|
83
|
+
content: 'Explain how JWT authentication works in this e-commerce system',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
role: 'assistant' as const,
|
|
87
|
+
content: `**JWT Authentication in E-commerce MCP Server**
|
|
88
|
+
|
|
89
|
+
**What is JWT?**
|
|
90
|
+
JWT (JSON Web Token) is a secure way to transmit information between parties. It's a token that contains:
|
|
91
|
+
- User identity (subject)
|
|
92
|
+
- User information (email, name)
|
|
93
|
+
- Expiration time
|
|
94
|
+
- Digital signature
|
|
95
|
+
|
|
96
|
+
**How It Works Here:**
|
|
97
|
+
|
|
98
|
+
1. **Login** (Public)
|
|
99
|
+
- User provides email + password
|
|
100
|
+
- Server verifies with bcrypt
|
|
101
|
+
- Server generates JWT token
|
|
102
|
+
- Token valid for 24 hours
|
|
103
|
+
|
|
104
|
+
2. **Using Protected Tools**
|
|
105
|
+
- Client includes token in request
|
|
106
|
+
- Server automatically validates token
|
|
107
|
+
- If valid: grants access
|
|
108
|
+
- If invalid/missing: denies access
|
|
109
|
+
|
|
110
|
+
3. **Token Contents**
|
|
111
|
+
\`\`\`json
|
|
112
|
+
{
|
|
113
|
+
"sub": "user-id",
|
|
114
|
+
"email": "alice@example.com",
|
|
115
|
+
"name": "Alice Johnson",
|
|
116
|
+
"iat": 1234567890,
|
|
117
|
+
"exp": 1234654290
|
|
118
|
+
}
|
|
119
|
+
\`\`\`
|
|
120
|
+
|
|
121
|
+
**Security Features:**
|
|
122
|
+
- ✅ Tokens are signed (can't be tampered)
|
|
123
|
+
- ✅ Passwords hashed with bcrypt
|
|
124
|
+
- ✅ Tokens expire after 24 hours
|
|
125
|
+
- ✅ No password storage in tokens
|
|
126
|
+
|
|
127
|
+
**Developer Experience:**
|
|
128
|
+
With V3 decorators, authentication is automatic:
|
|
129
|
+
\`\`\`typescript
|
|
130
|
+
@UseGuards(JWTGuard)
|
|
131
|
+
async myProtectedTool(input, context) {
|
|
132
|
+
// context.auth is already populated!
|
|
133
|
+
const userId = context.auth.subject;
|
|
134
|
+
}
|
|
135
|
+
\`\`\`
|
|
136
|
+
|
|
137
|
+
**No Manual Checking Needed!**
|
|
138
|
+
The \`@UseGuards(JWTGuard)\` decorator handles:
|
|
139
|
+
- Token extraction
|
|
140
|
+
- Signature validation
|
|
141
|
+
- Expiry checking
|
|
142
|
+
- Context population`,
|
|
143
|
+
},
|
|
144
|
+
];
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ResourceDecorator as Resource, ExecutionContext } from 'nitrostack';
|
|
2
|
+
import { getDatabase } from '../../db/database.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Authentication Resources
|
|
6
|
+
* Provides auth-related resource endpoints
|
|
7
|
+
*/
|
|
8
|
+
export class AuthResources {
|
|
9
|
+
/**
|
|
10
|
+
* User schema resource
|
|
11
|
+
*/
|
|
12
|
+
@Resource({
|
|
13
|
+
uri: 'auth://schema/user',
|
|
14
|
+
name: 'User Schema',
|
|
15
|
+
description: 'Schema definition for user objects in the authentication system',
|
|
16
|
+
mimeType: 'application/json',
|
|
17
|
+
})
|
|
18
|
+
async getUserSchema(context: ExecutionContext) {
|
|
19
|
+
return {
|
|
20
|
+
type: 'json' as const,
|
|
21
|
+
data: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: {
|
|
24
|
+
id: { type: 'string', format: 'uuid', description: 'Unique user identifier' },
|
|
25
|
+
email: { type: 'string', format: 'email', description: 'User email address' },
|
|
26
|
+
name: { type: 'string', description: 'Full name' },
|
|
27
|
+
profile_picture: { type: 'string', format: 'uri', nullable: true, description: 'Profile picture URL' },
|
|
28
|
+
created_at: { type: 'string', format: 'date-time', description: 'Account creation timestamp' },
|
|
29
|
+
},
|
|
30
|
+
required: ['id', 'email', 'name'],
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Available test users resource
|
|
37
|
+
*/
|
|
38
|
+
@Resource({
|
|
39
|
+
uri: 'auth://test-users',
|
|
40
|
+
name: 'Test Users',
|
|
41
|
+
description: 'List of available test users for the demo',
|
|
42
|
+
mimeType: 'application/json',
|
|
43
|
+
})
|
|
44
|
+
async getTestUsers(context: ExecutionContext) {
|
|
45
|
+
return {
|
|
46
|
+
type: 'json' as const,
|
|
47
|
+
data: {
|
|
48
|
+
users: [
|
|
49
|
+
{ email: 'alice@example.com', password: 'password123', name: 'Alice Johnson' },
|
|
50
|
+
{ email: 'bob@example.com', password: 'password123', name: 'Bob Smith' },
|
|
51
|
+
{ email: 'charlie@example.com', password: 'password123', name: 'Charlie Brown' },
|
|
52
|
+
],
|
|
53
|
+
note: 'All test users have the same password: password123',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Authentication statistics
|
|
60
|
+
*/
|
|
61
|
+
@Resource({
|
|
62
|
+
uri: 'auth://stats',
|
|
63
|
+
name: 'Auth Statistics',
|
|
64
|
+
description: 'Authentication system statistics',
|
|
65
|
+
mimeType: 'application/json',
|
|
66
|
+
})
|
|
67
|
+
async getAuthStats(context: ExecutionContext) {
|
|
68
|
+
const db = getDatabase();
|
|
69
|
+
|
|
70
|
+
const totalUsers: any = db.prepare('SELECT COUNT(*) as count FROM users').get();
|
|
71
|
+
const recentLogins: any[] = db.prepare('SELECT email, created_at FROM users ORDER BY created_at DESC LIMIT 5').all();
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
type: 'json' as const,
|
|
75
|
+
data: {
|
|
76
|
+
totalUsers: totalUsers.count,
|
|
77
|
+
recentUsers: recentLogins,
|
|
78
|
+
authMethod: 'JWT with bcrypt password hashing',
|
|
79
|
+
tokenExpiry: '24 hours',
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { ToolDecorator as Tool, Widget, UseGuards, z, ExecutionContext } from 'nitrostack';
|
|
2
|
+
import bcrypt from 'bcryptjs';
|
|
3
|
+
import { getDatabase } from '../../db/database.js';
|
|
4
|
+
import { generateJWT } from 'nitrostack';
|
|
5
|
+
import { JWTGuard } from '../../guards/jwt.guard.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Authentication Tools
|
|
9
|
+
* Handles user authentication and profile management
|
|
10
|
+
*/
|
|
11
|
+
export class AuthTools {
|
|
12
|
+
/**
|
|
13
|
+
* Login tool - Authenticate user and return JWT token
|
|
14
|
+
* No authentication required (public endpoint)
|
|
15
|
+
*/
|
|
16
|
+
@Tool({
|
|
17
|
+
name: 'login',
|
|
18
|
+
description: 'Login with email and password to get a JWT token. Use this token in the Authorization header for authenticated requests.',
|
|
19
|
+
inputSchema: z.object({
|
|
20
|
+
email: z.string().email().describe('User email address'),
|
|
21
|
+
password: z.string().describe('User password'),
|
|
22
|
+
}),
|
|
23
|
+
examples: {
|
|
24
|
+
request: {
|
|
25
|
+
email: 'emily.johnson@x.dummyjson.com',
|
|
26
|
+
password: 'password123'
|
|
27
|
+
},
|
|
28
|
+
response: {
|
|
29
|
+
message: 'Login successful!',
|
|
30
|
+
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
31
|
+
user: {
|
|
32
|
+
id: 'user-emily',
|
|
33
|
+
email: 'emily.johnson@x.dummyjson.com',
|
|
34
|
+
name: 'Emily Johnson'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
@Widget('login-result')
|
|
40
|
+
async login(input: any, context: ExecutionContext) {
|
|
41
|
+
const db = getDatabase();
|
|
42
|
+
|
|
43
|
+
// Find user
|
|
44
|
+
const user: any = db.prepare('SELECT * FROM users WHERE email = ?').get(input.email);
|
|
45
|
+
|
|
46
|
+
if (!user) {
|
|
47
|
+
throw new Error('Invalid email or password');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Verify password
|
|
51
|
+
const valid = bcrypt.compareSync(input.password, user.password_hash);
|
|
52
|
+
|
|
53
|
+
if (!valid) {
|
|
54
|
+
throw new Error('Invalid email or password');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Generate JWT token
|
|
58
|
+
const token = generateJWT({
|
|
59
|
+
secret: process.env.JWT_SECRET!,
|
|
60
|
+
payload: {
|
|
61
|
+
sub: user.id,
|
|
62
|
+
email: user.email,
|
|
63
|
+
name: user.name,
|
|
64
|
+
},
|
|
65
|
+
expiresIn: '24h',
|
|
66
|
+
audience: process.env.JWT_AUDIENCE || 'ecommerce-mcp-server',
|
|
67
|
+
issuer: process.env.JWT_ISSUER || 'ecommerce-app',
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
context.logger.info(`User logged in: ${user.email}`);
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
message: 'Login successful!',
|
|
74
|
+
token,
|
|
75
|
+
user: {
|
|
76
|
+
id: user.id,
|
|
77
|
+
email: user.email,
|
|
78
|
+
name: user.name,
|
|
79
|
+
},
|
|
80
|
+
instructions: {
|
|
81
|
+
step1: 'Copy the token above',
|
|
82
|
+
step2: 'In the inspector, go to Chat tab',
|
|
83
|
+
step3: 'Paste the token in the "JWT Token" field (if available)',
|
|
84
|
+
step4: 'Or use: Authorization: Bearer <token>',
|
|
85
|
+
expiresIn: '24 hours',
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get current user information
|
|
92
|
+
* Requires JWT authentication
|
|
93
|
+
*/
|
|
94
|
+
@Tool({
|
|
95
|
+
name: 'whoami',
|
|
96
|
+
description: 'Get information about the currently authenticated user. Requires authentication.',
|
|
97
|
+
inputSchema: z.object({}),
|
|
98
|
+
examples: {
|
|
99
|
+
request: {},
|
|
100
|
+
response: {
|
|
101
|
+
user: {
|
|
102
|
+
id: 'user-emily',
|
|
103
|
+
email: 'emily.johnson@x.dummyjson.com',
|
|
104
|
+
name: 'Emily Johnson',
|
|
105
|
+
profile_picture: 'https://dummyjson.com/icon/emilys/128',
|
|
106
|
+
memberSince: '2024-01-01T00:00:00Z'
|
|
107
|
+
},
|
|
108
|
+
authenticated: true
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
@Widget('whoami')
|
|
113
|
+
@UseGuards(JWTGuard)
|
|
114
|
+
async whoami(input: any, context: ExecutionContext) {
|
|
115
|
+
// User is already authenticated by JWTGuard
|
|
116
|
+
const userId = context.auth?.subject;
|
|
117
|
+
|
|
118
|
+
const db = getDatabase();
|
|
119
|
+
const user: any = db.prepare(`
|
|
120
|
+
SELECT id, email, name, profile_picture, created_at FROM users WHERE id = ?
|
|
121
|
+
`).get(userId);
|
|
122
|
+
|
|
123
|
+
if (!user) {
|
|
124
|
+
throw new Error('User not found');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
user: {
|
|
129
|
+
id: user.id,
|
|
130
|
+
email: user.email,
|
|
131
|
+
name: user.name,
|
|
132
|
+
profile_picture: user.profile_picture,
|
|
133
|
+
memberSince: user.created_at,
|
|
134
|
+
},
|
|
135
|
+
authenticated: true,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Module } from 'nitrostack';
|
|
2
|
+
import { CartTools } from './cart.tools.js';
|
|
3
|
+
import { CartResources } from './cart.resources.js';
|
|
4
|
+
import { CartPrompts } from './cart.prompts.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Cart Module
|
|
8
|
+
* Provides shopping cart management, resources, and prompts
|
|
9
|
+
*/
|
|
10
|
+
@Module({
|
|
11
|
+
name: 'cart',
|
|
12
|
+
description: 'Shopping cart management',
|
|
13
|
+
controllers: [CartTools, CartResources, CartPrompts],
|
|
14
|
+
})
|
|
15
|
+
export class CartModule {}
|
|
16
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { PromptDecorator as Prompt, ExecutionContext } from 'nitrostack';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cart Prompts
|
|
5
|
+
* Provides helpful prompts for cart management
|
|
6
|
+
*/
|
|
7
|
+
export class CartPrompts {
|
|
8
|
+
/**
|
|
9
|
+
* Cart management help prompt
|
|
10
|
+
*/
|
|
11
|
+
@Prompt({
|
|
12
|
+
name: 'cart-management-help',
|
|
13
|
+
description: 'Get help managing your shopping cart',
|
|
14
|
+
})
|
|
15
|
+
async cartHelp(args: Record<string, any>, context: ExecutionContext) {
|
|
16
|
+
return [
|
|
17
|
+
{
|
|
18
|
+
role: 'user' as const,
|
|
19
|
+
content: 'I need help managing my shopping cart',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
role: 'assistant' as const,
|
|
23
|
+
content: `**Shopping Cart Management Guide**
|
|
24
|
+
|
|
25
|
+
**Available Tools (Requires Authentication):**
|
|
26
|
+
1. \`add_to_cart\` - Add products to cart
|
|
27
|
+
2. \`view_cart\` - View cart contents and total
|
|
28
|
+
3. \`update_cart_item\` - Change quantity or remove items
|
|
29
|
+
4. \`clear_cart\` - Empty entire cart
|
|
30
|
+
|
|
31
|
+
**Adding Items:**
|
|
32
|
+
\`\`\`
|
|
33
|
+
add_to_cart({
|
|
34
|
+
product_id: "product-uuid",
|
|
35
|
+
quantity: 2
|
|
36
|
+
})
|
|
37
|
+
\`\`\`
|
|
38
|
+
- Make sure to login first
|
|
39
|
+
- Check product stock availability
|
|
40
|
+
- Quantity must be > 0
|
|
41
|
+
|
|
42
|
+
**Viewing Cart:**
|
|
43
|
+
\`\`\`
|
|
44
|
+
view_cart({})
|
|
45
|
+
\`\`\`
|
|
46
|
+
- Shows all items with images
|
|
47
|
+
- Displays individual and total prices
|
|
48
|
+
- Item count included
|
|
49
|
+
|
|
50
|
+
**Updating Items:**
|
|
51
|
+
\`\`\`
|
|
52
|
+
update_cart_item({
|
|
53
|
+
product_id: "product-uuid",
|
|
54
|
+
quantity: 5 // or 0 to remove
|
|
55
|
+
})
|
|
56
|
+
\`\`\`
|
|
57
|
+
- Set quantity to 0 to remove item
|
|
58
|
+
- Must have sufficient stock
|
|
59
|
+
|
|
60
|
+
**Clearing Cart:**
|
|
61
|
+
\`\`\`
|
|
62
|
+
clear_cart({})
|
|
63
|
+
\`\`\`
|
|
64
|
+
- Removes ALL items
|
|
65
|
+
- Cannot be undone
|
|
66
|
+
|
|
67
|
+
**Common Operations:**
|
|
68
|
+
📦 **Add Multiple Items:**
|
|
69
|
+
Call \`add_to_cart\` multiple times with different product_ids
|
|
70
|
+
|
|
71
|
+
🔄 **Update Quantity:**
|
|
72
|
+
Use \`update_cart_item\` with new quantity
|
|
73
|
+
|
|
74
|
+
🗑️ **Remove Single Item:**
|
|
75
|
+
Use \`update_cart_item\` with quantity: 0
|
|
76
|
+
|
|
77
|
+
💰 **Check Total:**
|
|
78
|
+
Call \`view_cart\` to see current total
|
|
79
|
+
|
|
80
|
+
**Best Practices:**
|
|
81
|
+
✓ Login before adding to cart
|
|
82
|
+
✓ Check stock before adding large quantities
|
|
83
|
+
✓ Review cart before checkout
|
|
84
|
+
✓ Use \`view_cart\` to verify changes
|
|
85
|
+
|
|
86
|
+
**Tips:**
|
|
87
|
+
- Cart persists between sessions
|
|
88
|
+
- Items added increment existing quantities
|
|
89
|
+
- Checkout with \`create_order\` when ready
|
|
90
|
+
- Cart clears automatically after order`,
|
|
91
|
+
},
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ResourceDecorator as Resource, ExecutionContext } from 'nitrostack';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cart Resources
|
|
5
|
+
* Provides cart-related resource endpoints
|
|
6
|
+
*/
|
|
7
|
+
export class CartResources {
|
|
8
|
+
/**
|
|
9
|
+
* Cart schema resource
|
|
10
|
+
*/
|
|
11
|
+
@Resource({
|
|
12
|
+
uri: 'cart://schema',
|
|
13
|
+
name: 'Cart Schema',
|
|
14
|
+
description: 'Schema definition for shopping cart objects',
|
|
15
|
+
mimeType: 'application/json',
|
|
16
|
+
})
|
|
17
|
+
async getCartSchema(context: ExecutionContext) {
|
|
18
|
+
return {
|
|
19
|
+
type: 'json' as const,
|
|
20
|
+
data: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
items: {
|
|
24
|
+
type: 'array',
|
|
25
|
+
items: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
id: { type: 'string', description: 'Cart item ID' },
|
|
29
|
+
product_id: { type: 'string', description: 'Product ID' },
|
|
30
|
+
name: { type: 'string', description: 'Product name' },
|
|
31
|
+
price: { type: 'number', description: 'Product price' },
|
|
32
|
+
quantity: { type: 'integer', minimum: 1, description: 'Quantity in cart' },
|
|
33
|
+
image_url: { type: 'string', nullable: true, description: 'Product image' },
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
total: { type: 'number', description: 'Total cart value' },
|
|
38
|
+
itemCount: { type: 'integer', description: 'Number of items in cart' },
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|