nitrostack 1.0.0 → 1.0.1

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.
Files changed (115) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/package.json +1 -1
  3. package/templates/typescript-auth/.env.example +23 -0
  4. package/templates/typescript-auth/src/app.module.ts +103 -0
  5. package/templates/typescript-auth/src/db/database.ts +163 -0
  6. package/templates/typescript-auth/src/db/seed.ts +374 -0
  7. package/templates/typescript-auth/src/db/setup.ts +87 -0
  8. package/templates/typescript-auth/src/events/analytics.service.ts +52 -0
  9. package/templates/typescript-auth/src/events/notification.service.ts +40 -0
  10. package/templates/typescript-auth/src/filters/global-exception.filter.ts +28 -0
  11. package/templates/typescript-auth/src/guards/README.md +75 -0
  12. package/templates/typescript-auth/src/guards/jwt.guard.ts +105 -0
  13. package/templates/typescript-auth/src/health/database.health.ts +41 -0
  14. package/templates/typescript-auth/src/index.ts +26 -0
  15. package/templates/typescript-auth/src/interceptors/transform.interceptor.ts +24 -0
  16. package/templates/typescript-auth/src/middleware/logging.middleware.ts +42 -0
  17. package/templates/typescript-auth/src/modules/addresses/addresses.module.ts +16 -0
  18. package/templates/typescript-auth/src/modules/addresses/addresses.prompts.ts +114 -0
  19. package/templates/typescript-auth/src/modules/addresses/addresses.resources.ts +40 -0
  20. package/templates/typescript-auth/src/modules/addresses/addresses.tools.ts +241 -0
  21. package/templates/typescript-auth/src/modules/auth/auth.module.ts +16 -0
  22. package/templates/typescript-auth/src/modules/auth/auth.prompts.ts +147 -0
  23. package/templates/typescript-auth/src/modules/auth/auth.resources.ts +84 -0
  24. package/templates/typescript-auth/src/modules/auth/auth.tools.ts +139 -0
  25. package/templates/typescript-auth/src/modules/cart/cart.module.ts +16 -0
  26. package/templates/typescript-auth/src/modules/cart/cart.prompts.ts +95 -0
  27. package/templates/typescript-auth/src/modules/cart/cart.resources.ts +44 -0
  28. package/templates/typescript-auth/src/modules/cart/cart.tools.ts +281 -0
  29. package/templates/typescript-auth/src/modules/orders/orders.module.ts +16 -0
  30. package/templates/typescript-auth/src/modules/orders/orders.prompts.ts +88 -0
  31. package/templates/typescript-auth/src/modules/orders/orders.resources.ts +48 -0
  32. package/templates/typescript-auth/src/modules/orders/orders.tools.ts +281 -0
  33. package/templates/typescript-auth/src/modules/products/products.module.ts +16 -0
  34. package/templates/typescript-auth/src/modules/products/products.prompts.ts +146 -0
  35. package/templates/typescript-auth/src/modules/products/products.resources.ts +98 -0
  36. package/templates/typescript-auth/src/modules/products/products.tools.ts +266 -0
  37. package/templates/typescript-auth/src/pipes/validation.pipe.ts +42 -0
  38. package/templates/typescript-auth/src/services/database.service.ts +90 -0
  39. package/templates/typescript-auth/src/widgets/app/add-to-cart/page.tsx +122 -0
  40. package/templates/typescript-auth/src/widgets/app/address-added/page.tsx +116 -0
  41. package/templates/typescript-auth/src/widgets/app/address-deleted/page.tsx +105 -0
  42. package/templates/typescript-auth/src/widgets/app/address-list/page.tsx +139 -0
  43. package/templates/typescript-auth/src/widgets/app/address-updated/page.tsx +153 -0
  44. package/templates/typescript-auth/src/widgets/app/cart-cleared/page.tsx +86 -0
  45. package/templates/typescript-auth/src/widgets/app/cart-updated/page.tsx +116 -0
  46. package/templates/typescript-auth/src/widgets/app/categories/page.tsx +134 -0
  47. package/templates/typescript-auth/src/widgets/app/layout.tsx +21 -0
  48. package/templates/typescript-auth/src/widgets/app/login-result/page.tsx +129 -0
  49. package/templates/typescript-auth/src/widgets/app/order-confirmation/page.tsx +206 -0
  50. package/templates/typescript-auth/src/widgets/app/order-details/page.tsx +225 -0
  51. package/templates/typescript-auth/src/widgets/app/order-history/page.tsx +218 -0
  52. package/templates/typescript-auth/src/widgets/app/product-card/page.tsx +121 -0
  53. package/templates/typescript-auth/src/widgets/app/products-grid/page.tsx +173 -0
  54. package/templates/typescript-auth/src/widgets/app/shopping-cart/page.tsx +187 -0
  55. package/templates/typescript-auth/src/widgets/app/whoami/page.tsx +165 -0
  56. package/templates/typescript-auth/src/widgets/next.config.js +38 -0
  57. package/templates/typescript-auth/src/widgets/package.json +18 -0
  58. package/templates/typescript-auth/src/widgets/styles/ecommerce.ts +169 -0
  59. package/templates/typescript-auth/src/widgets/tsconfig.json +28 -0
  60. package/templates/typescript-auth/src/widgets/types/tool-data.ts +141 -0
  61. package/templates/typescript-auth/src/widgets/widget-manifest.json +464 -0
  62. package/templates/typescript-auth/tsconfig.json +27 -0
  63. package/templates/typescript-auth-api-key/.env +15 -0
  64. package/templates/typescript-auth-api-key/.env.example +4 -0
  65. package/templates/typescript-auth-api-key/src/app.module.ts +38 -0
  66. package/templates/typescript-auth-api-key/src/guards/apikey.guard.ts +47 -0
  67. package/templates/typescript-auth-api-key/src/guards/multi-auth.guard.ts +157 -0
  68. package/templates/typescript-auth-api-key/src/health/system.health.ts +55 -0
  69. package/templates/typescript-auth-api-key/src/index.ts +47 -0
  70. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.module.ts +12 -0
  71. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.prompts.ts +73 -0
  72. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.resources.ts +60 -0
  73. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.tools.ts +71 -0
  74. package/templates/typescript-auth-api-key/src/modules/demo/demo.module.ts +18 -0
  75. package/templates/typescript-auth-api-key/src/modules/demo/demo.tools.ts +155 -0
  76. package/templates/typescript-auth-api-key/src/modules/demo/multi-auth.tools.ts +123 -0
  77. package/templates/typescript-auth-api-key/src/widgets/app/calculator-operations/page.tsx +133 -0
  78. package/templates/typescript-auth-api-key/src/widgets/app/calculator-result/page.tsx +134 -0
  79. package/templates/typescript-auth-api-key/src/widgets/app/layout.tsx +14 -0
  80. package/templates/typescript-auth-api-key/src/widgets/next.config.js +37 -0
  81. package/templates/typescript-auth-api-key/src/widgets/package.json +24 -0
  82. package/templates/typescript-auth-api-key/src/widgets/tsconfig.json +28 -0
  83. package/templates/typescript-auth-api-key/src/widgets/widget-manifest.json +48 -0
  84. package/templates/typescript-auth-api-key/tsconfig.json +23 -0
  85. package/templates/typescript-oauth/.env.example +91 -0
  86. package/templates/typescript-oauth/src/app.module.ts +89 -0
  87. package/templates/typescript-oauth/src/guards/oauth.guard.ts +127 -0
  88. package/templates/typescript-oauth/src/index.ts +74 -0
  89. package/templates/typescript-oauth/src/modules/demo/demo.module.ts +16 -0
  90. package/templates/typescript-oauth/src/modules/demo/demo.tools.ts +190 -0
  91. package/templates/typescript-oauth/src/widgets/app/calculator-operations/page.tsx +133 -0
  92. package/templates/typescript-oauth/src/widgets/app/calculator-result/page.tsx +134 -0
  93. package/templates/typescript-oauth/src/widgets/app/layout.tsx +14 -0
  94. package/templates/typescript-oauth/src/widgets/next.config.js +37 -0
  95. package/templates/typescript-oauth/src/widgets/package.json +24 -0
  96. package/templates/typescript-oauth/src/widgets/tsconfig.json +28 -0
  97. package/templates/typescript-oauth/src/widgets/widget-manifest.json +48 -0
  98. package/templates/typescript-oauth/tsconfig.json +23 -0
  99. package/templates/typescript-starter/.env.example +4 -0
  100. package/templates/typescript-starter/src/app.module.ts +34 -0
  101. package/templates/typescript-starter/src/health/system.health.ts +55 -0
  102. package/templates/typescript-starter/src/index.ts +27 -0
  103. package/templates/typescript-starter/src/modules/calculator/calculator.module.ts +12 -0
  104. package/templates/typescript-starter/src/modules/calculator/calculator.prompts.ts +73 -0
  105. package/templates/typescript-starter/src/modules/calculator/calculator.resources.ts +60 -0
  106. package/templates/typescript-starter/src/modules/calculator/calculator.tools.ts +71 -0
  107. package/templates/typescript-starter/src/widgets/app/calculator-operations/page.tsx +133 -0
  108. package/templates/typescript-starter/src/widgets/app/calculator-result/page.tsx +134 -0
  109. package/templates/typescript-starter/src/widgets/app/layout.tsx +14 -0
  110. package/templates/typescript-starter/src/widgets/next.config.js +37 -0
  111. package/templates/typescript-starter/src/widgets/package.json +24 -0
  112. package/templates/typescript-starter/src/widgets/tsconfig.json +28 -0
  113. package/templates/typescript-starter/src/widgets/widget-manifest.json +48 -0
  114. package/templates/typescript-starter/tsconfig.json +23 -0
  115. package/LICENSE_URLS_UPDATE_COMPLETE.md +0 -388
@@ -0,0 +1,281 @@
1
+ import { ToolDecorator as Tool, Widget, UseGuards, z, ExecutionContext } from 'nitrostack';
2
+ import { v4 as uuidv4 } from 'uuid';
3
+ import { getDatabase } from '../../db/database.js';
4
+ import { JWTGuard } from '../../guards/jwt.guard.js';
5
+
6
+ /**
7
+ * Orders Tools
8
+ * Handles order creation and management (requires authentication)
9
+ */
10
+ export class OrdersTools {
11
+ /**
12
+ * Create order from cart - Requires authentication
13
+ */
14
+ @Tool({
15
+ name: 'create_order',
16
+ description: 'Create an order from the current shopping cart. Requires authentication and at least one item in cart.',
17
+ inputSchema: z.object({
18
+ payment_method: z.enum(['credit_card', 'paypal', 'apple_pay']).describe('Payment method'),
19
+ shipping_address_id: z.string().optional().describe('Address ID for shipping. Uses default if not provided.'),
20
+ }),
21
+ examples: {
22
+ request: {
23
+ payment_method: 'credit_card',
24
+ shipping_address_id: 'addr-1'
25
+ },
26
+ response: {
27
+ message: 'Order created successfully!',
28
+ order: {
29
+ id: 'order-12345',
30
+ total: 39.97,
31
+ status: 'pending',
32
+ estimated_delivery: '3-5 business days',
33
+ payment_method: 'credit_card',
34
+ created_at: '2024-01-15T10:30:00Z',
35
+ items: [
36
+ {
37
+ id: 'prod-1',
38
+ product_id: 'prod-1',
39
+ name: 'Essence Mascara Lash Princess',
40
+ quantity: 2,
41
+ price: 9.99,
42
+ image_url: 'https://cdn.dummyjson.com/product-images/beauty/essence-mascara-lash-princess/thumbnail.webp'
43
+ },
44
+ {
45
+ id: 'prod-2',
46
+ product_id: 'prod-2',
47
+ name: 'Eyeshadow Palette with Mirror',
48
+ quantity: 1,
49
+ price: 19.99,
50
+ image_url: 'https://cdn.dummyjson.com/product-images/beauty/eyeshadow-palette-with-mirror/thumbnail.webp'
51
+ }
52
+ ]
53
+ }
54
+ }
55
+ }
56
+ })
57
+ @Widget('order-confirmation')
58
+ @UseGuards(JWTGuard)
59
+ async createOrder(input: any, context: ExecutionContext) {
60
+ const db = getDatabase();
61
+ const userId = context.auth?.subject;
62
+
63
+ // Get cart items
64
+ const cartItems: any[] = db.prepare(`
65
+ SELECT c.*, p.name, p.price, p.stock, p.image_url
66
+ FROM carts c
67
+ JOIN products p ON c.product_id = p.id
68
+ WHERE c.user_id = ?
69
+ `).all(userId);
70
+
71
+ if (cartItems.length === 0) {
72
+ throw new Error('Cart is empty. Add items to cart before creating an order.');
73
+ }
74
+
75
+ // Check stock availability
76
+ for (const item of cartItems) {
77
+ if (item.stock < item.quantity) {
78
+ throw new Error(`Insufficient stock for ${item.name}. Only ${item.stock} available.`);
79
+ }
80
+ }
81
+
82
+ // Get shipping address
83
+ let addressId = input.shipping_address_id;
84
+ if (!addressId) {
85
+ const defaultAddress: any = db.prepare(`
86
+ SELECT id FROM addresses WHERE user_id = ? AND is_default = 1
87
+ `).get(userId);
88
+
89
+ if (!defaultAddress) {
90
+ throw new Error('No shipping address found. Please add an address first.');
91
+ }
92
+
93
+ addressId = defaultAddress.id;
94
+ }
95
+
96
+ // Calculate total
97
+ const total = cartItems.reduce((sum, item) => sum + (item.price * item.quantity), 0);
98
+
99
+ // Create order
100
+ const orderId = uuidv4();
101
+ const now = new Date().toISOString();
102
+
103
+ db.prepare(`
104
+ INSERT INTO orders (id, user_id, total, status, payment_method, shipping_address_id, created_at)
105
+ VALUES (?, ?, ?, ?, ?, ?, ?)
106
+ `).run(orderId, userId, total, 'pending', input.payment_method, addressId, now);
107
+
108
+ // Create order items
109
+ for (const item of cartItems) {
110
+ const orderItemId = uuidv4();
111
+ db.prepare(`
112
+ INSERT INTO order_items (id, order_id, product_id, quantity, price)
113
+ VALUES (?, ?, ?, ?, ?)
114
+ `).run(orderItemId, orderId, item.product_id, item.quantity, item.price);
115
+
116
+ // Update product stock
117
+ db.prepare(`
118
+ UPDATE products SET stock = stock - ? WHERE id = ?
119
+ `).run(item.quantity, item.product_id);
120
+ }
121
+
122
+ // Clear cart
123
+ db.prepare(`
124
+ DELETE FROM carts WHERE user_id = ?
125
+ `).run(userId);
126
+
127
+ context.logger.info(`Order created: ${orderId}, total=$${total.toFixed(2)}`);
128
+
129
+ return {
130
+ message: 'Order created successfully!',
131
+ order: {
132
+ id: orderId,
133
+ total,
134
+ status: 'pending',
135
+ payment_method: input.payment_method,
136
+ created_at: now,
137
+ items: cartItems.map(item => ({
138
+ id: item.product_id,
139
+ name: item.name,
140
+ quantity: item.quantity,
141
+ price: item.price,
142
+ image_url: item.image_url,
143
+ })),
144
+ },
145
+ };
146
+ }
147
+
148
+ /**
149
+ * Get order history - Requires authentication
150
+ */
151
+ @Tool({
152
+ name: 'get_order_history',
153
+ description: 'Get the order history for the authenticated user. Requires authentication.',
154
+ inputSchema: z.object({}),
155
+ examples: {
156
+ request: {},
157
+ response: {
158
+ orders: [
159
+ {
160
+ id: 'order-12345',
161
+ total: 39.97,
162
+ status: 'pending',
163
+ created_at: '2024-01-15T10:30:00Z',
164
+ itemCount: 2
165
+ },
166
+ {
167
+ id: 'order-12344',
168
+ total: 89.96,
169
+ status: 'delivered',
170
+ created_at: '2024-01-10T14:20:00Z',
171
+ itemCount: 3
172
+ }
173
+ ],
174
+ totalOrders: 2,
175
+ pagination: {
176
+ page: 1,
177
+ totalPages: 1,
178
+ totalResults: 2
179
+ }
180
+ }
181
+ }
182
+ })
183
+ @Widget('order-history')
184
+ @UseGuards(JWTGuard)
185
+ async getOrderHistory(input: any, context: ExecutionContext) {
186
+ const db = getDatabase();
187
+ const userId = context.auth?.subject;
188
+
189
+ const orders: any[] = db.prepare(`
190
+ SELECT o.*, COUNT(oi.id) as itemCount
191
+ FROM orders o
192
+ LEFT JOIN order_items oi ON o.id = oi.order_id
193
+ WHERE o.user_id = ?
194
+ GROUP BY o.id
195
+ ORDER BY o.created_at DESC
196
+ `).all(userId);
197
+
198
+ context.logger.info(`Retrieved order history: ${orders.length} orders`);
199
+
200
+ return {
201
+ orders,
202
+ totalOrders: orders.length,
203
+ };
204
+ }
205
+
206
+ /**
207
+ * Get order details - Requires authentication
208
+ */
209
+ @Tool({
210
+ name: 'get_order_details',
211
+ description: 'Get detailed information about a specific order. Requires authentication.',
212
+ examples: {
213
+ request: {
214
+ order_id: 'order-12345'
215
+ },
216
+ response: {
217
+ order: {
218
+ id: 'order-12345',
219
+ total: 39.97,
220
+ status: 'pending',
221
+ payment_method: 'credit_card',
222
+ created_at: '2024-01-15T10:30:00Z'
223
+ },
224
+ items: [
225
+ {
226
+ id: 'prod-1',
227
+ product_id: 'prod-1',
228
+ name: 'Essence Mascara Lash Princess',
229
+ quantity: 2,
230
+ price: 9.99,
231
+ image_url: 'https://cdn.dummyjson.com/product-images/beauty/essence-mascara-lash-princess/thumbnail.webp'
232
+ },
233
+ {
234
+ id: 'prod-2',
235
+ product_id: 'prod-2',
236
+ name: 'Eyeshadow Palette with Mirror',
237
+ quantity: 1,
238
+ price: 19.99,
239
+ image_url: 'https://cdn.dummyjson.com/product-images/beauty/eyeshadow-palette-with-mirror/thumbnail.webp'
240
+ }
241
+ ]
242
+ }
243
+ },
244
+ inputSchema: z.object({
245
+ order_id: z.string().describe('The ID of the order to retrieve'),
246
+ }),
247
+ })
248
+ @Widget('order-details')
249
+ @UseGuards(JWTGuard)
250
+ async getOrderDetails(input: any, context: ExecutionContext) {
251
+ const db = getDatabase();
252
+ const userId = context.auth?.subject;
253
+
254
+ // Get order
255
+ const order: any = db.prepare(`
256
+ SELECT * FROM orders WHERE id = ? AND user_id = ?
257
+ `).get(input.order_id, userId);
258
+
259
+ if (!order) {
260
+ throw new Error(`Order with ID ${input.order_id} not found or you don't have access to it.`);
261
+ }
262
+
263
+ // Get order items
264
+ const items: any[] = db.prepare(`
265
+ SELECT oi.*, p.name, p.image_url
266
+ FROM order_items oi
267
+ JOIN products p ON oi.product_id = p.id
268
+ WHERE oi.order_id = ?
269
+ `).all(input.order_id);
270
+
271
+ context.logger.info(`Retrieved order details: ${input.order_id}`);
272
+
273
+ return {
274
+ order: {
275
+ ...order,
276
+ items,
277
+ },
278
+ };
279
+ }
280
+ }
281
+
@@ -0,0 +1,16 @@
1
+ import { Module } from 'nitrostack';
2
+ import { ProductsTools } from './products.tools.js';
3
+ import { ProductsResources } from './products.resources.js';
4
+ import { ProductsPrompts } from './products.prompts.js';
5
+
6
+ /**
7
+ * Products Module
8
+ * Provides product browsing, search, resources, and prompts
9
+ */
10
+ @Module({
11
+ name: 'products',
12
+ description: 'Product browsing, search, and details',
13
+ controllers: [ProductsTools, ProductsResources, ProductsPrompts],
14
+ })
15
+ export class ProductsModule {}
16
+
@@ -0,0 +1,146 @@
1
+ import { PromptDecorator as Prompt, ExecutionContext } from 'nitrostack';
2
+
3
+ /**
4
+ * Products Prompts
5
+ * Provides helpful prompts for product browsing and shopping
6
+ */
7
+ export class ProductsPrompts {
8
+ /**
9
+ * Product search help prompt
10
+ */
11
+ @Prompt({
12
+ name: 'product-search-help',
13
+ description: 'Get help with searching and browsing products',
14
+ arguments: [
15
+ {
16
+ name: 'looking_for',
17
+ description: 'What type of product you are looking for',
18
+ required: false,
19
+ },
20
+ ],
21
+ })
22
+ async productSearchHelp(args: Record<string, any>, context: ExecutionContext) {
23
+ const lookingFor = args.looking_for || 'general browsing';
24
+
25
+ return [
26
+ {
27
+ role: 'user' as const,
28
+ content: `I want to find products. I'm looking for: ${lookingFor}`,
29
+ },
30
+ {
31
+ role: 'assistant' as const,
32
+ content: `I'll help you find what you're looking for! Here's how to browse products:
33
+
34
+ **Available Tools:**
35
+ 1. \`browse_products\` - Browse all products with filters
36
+ 2. \`get_product_details\` - Get detailed info about a specific product
37
+ 3. \`get_categories\` - See all available categories
38
+
39
+ **Browsing Products:**
40
+ \`\`\`
41
+ tool: browse_products
42
+ parameters:
43
+ category: "All" | "Electronics" | "Clothing" | "Home" | "Books" | "Sports"
44
+ search: "optional search term"
45
+ page: 1
46
+ limit: 10
47
+ \`\`\`
48
+
49
+ **Filter by Category:**
50
+ - Electronics - Gadgets, devices, tech
51
+ - Clothing - Apparel and fashion
52
+ - Home - Furniture and home goods
53
+ - Books - Reading materials
54
+ - Sports - Athletic equipment
55
+
56
+ **Search by Name:**
57
+ Add a \`search\` parameter to find specific products:
58
+ \`\`\`
59
+ browse_products({ search: "laptop", category: "Electronics" })
60
+ \`\`\`
61
+
62
+ **Pagination:**
63
+ - \`page\`: Page number (starts at 1)
64
+ - \`limit\`: Items per page (1-50, default 10)
65
+
66
+ **Get Product Details:**
67
+ Once you find a product, use its ID to get full details:
68
+ \`\`\`
69
+ get_product_details({ product_id: "abc-123" })
70
+ \`\`\`
71
+
72
+ **Tips:**
73
+ ${lookingFor.toLowerCase().includes('electronic') ? '- Check the Electronics category\n- Look for items with high stock\n- Compare prices across products' : ''}
74
+ ${lookingFor.toLowerCase().includes('cloth') ? '- Browse the Clothing category\n- Check size availability in stock\n- Look for seasonal items' : ''}
75
+ - Use search to narrow down results
76
+ - Check stock levels before adding to cart
77
+ - View full details for complete specifications`,
78
+ },
79
+ ];
80
+ }
81
+
82
+ /**
83
+ * Shopping recommendations prompt
84
+ */
85
+ @Prompt({
86
+ name: 'shopping-recommendations',
87
+ description: 'Get personalized shopping recommendations and tips',
88
+ })
89
+ async shoppingRecommendations(args: Record<string, any>, context: ExecutionContext) {
90
+ return [
91
+ {
92
+ role: 'user' as const,
93
+ content: 'Give me shopping tips and recommendations for this e-commerce store',
94
+ },
95
+ {
96
+ role: 'assistant' as const,
97
+ content: `**Shopping Tips & Recommendations**
98
+
99
+ **Best Practices:**
100
+ 1. **Check Stock First**
101
+ - Use \`browse_products\` to see available items
102
+ - Look for "stock" field in product details
103
+ - Low stock items go fast!
104
+
105
+ 2. **Compare Products**
106
+ - Browse by category to see options
107
+ - Check prices across similar items
108
+ - Read full descriptions with \`get_product_details\`
109
+
110
+ 3. **Smart Shopping Flow**
111
+ \`\`\`
112
+ Step 1: Browse → browse_products
113
+ Step 2: View Details → get_product_details
114
+ Step 3: Add to Cart → add_to_cart (requires login)
115
+ Step 4: Review Cart → view_cart
116
+ Step 5: Place Order → create_order
117
+ \`\`\`
118
+
119
+ **Categories Overview:**
120
+ 📱 **Electronics** - Latest gadgets and tech
121
+ 👕 **Clothing** - Fashion and apparel
122
+ 🏠 **Home** - Furniture and decor
123
+ 📚 **Books** - Reading materials
124
+ ⚽ **Sports** - Athletic gear
125
+
126
+ **Money-Saving Tips:**
127
+ - Check all categories for deals
128
+ - Look for bundle opportunities
129
+ - Review cart before checkout
130
+ - Items in high stock are usually popular
131
+
132
+ **Before You Buy:**
133
+ ✓ Verify stock availability
134
+ ✓ Review product description
135
+ ✓ Check your cart total
136
+ ✓ Ensure shipping address is set
137
+
138
+ **Need Help?**
139
+ - Authentication issues? Use \`auth-help\` prompt
140
+ - Cart problems? Use \`cart-management-help\` prompt
141
+ - Order questions? Use \`order-help\` prompt`,
142
+ },
143
+ ];
144
+ }
145
+ }
146
+
@@ -0,0 +1,98 @@
1
+ import { ResourceDecorator as Resource, ExecutionContext } from 'nitrostack';
2
+ import { getDatabase } from '../../db/database.js';
3
+
4
+ /**
5
+ * Products Resources
6
+ * Provides product-related resource endpoints
7
+ */
8
+ export class ProductsResources {
9
+ /**
10
+ * Product schema resource
11
+ */
12
+ @Resource({
13
+ uri: 'products://schema/product',
14
+ name: 'Product Schema',
15
+ description: 'Schema definition for product objects',
16
+ mimeType: 'application/json',
17
+ })
18
+ async getProductSchema(context: ExecutionContext) {
19
+ return {
20
+ type: 'json' as const,
21
+ data: {
22
+ type: 'object',
23
+ properties: {
24
+ id: { type: 'string', format: 'uuid', description: 'Unique product identifier' },
25
+ name: { type: 'string', description: 'Product name' },
26
+ description: { type: 'string', description: 'Product description' },
27
+ price: { type: 'number', minimum: 0, description: 'Price in USD' },
28
+ category: { type: 'string', enum: ['Electronics', 'Clothing', 'Home', 'Books', 'Sports'], description: 'Product category' },
29
+ stock: { type: 'integer', minimum: 0, description: 'Available stock quantity' },
30
+ image_url: { type: 'string', format: 'uri', nullable: true, description: 'Product image URL' },
31
+ created_at: { type: 'string', format: 'date-time', description: 'Product creation timestamp' },
32
+ },
33
+ required: ['id', 'name', 'description', 'price', 'category', 'stock'],
34
+ },
35
+ };
36
+ }
37
+
38
+ /**
39
+ * Product categories resource
40
+ */
41
+ @Resource({
42
+ uri: 'products://categories',
43
+ name: 'Product Categories',
44
+ description: 'List of all available product categories',
45
+ mimeType: 'application/json',
46
+ })
47
+ async getCategories(context: ExecutionContext) {
48
+ const db = getDatabase();
49
+
50
+ const categories: any[] = db.prepare(`
51
+ SELECT DISTINCT category, COUNT(*) as count
52
+ FROM products
53
+ GROUP BY category
54
+ ORDER BY category
55
+ `).all();
56
+
57
+ return {
58
+ type: 'json' as const,
59
+ data: {
60
+ categories: categories.map(c => ({
61
+ name: c.category,
62
+ productCount: c.count,
63
+ })),
64
+ total: categories.length,
65
+ },
66
+ };
67
+ }
68
+
69
+ /**
70
+ * Product statistics resource
71
+ */
72
+ @Resource({
73
+ uri: 'products://stats',
74
+ name: 'Product Statistics',
75
+ description: 'Overall product catalog statistics',
76
+ mimeType: 'application/json',
77
+ })
78
+ async getProductStats(context: ExecutionContext) {
79
+ const db = getDatabase();
80
+
81
+ const totalProducts: any = db.prepare('SELECT COUNT(*) as count FROM products').get();
82
+ const totalValue: any = db.prepare('SELECT SUM(price * stock) as value FROM products').get();
83
+ const outOfStock: any = db.prepare('SELECT COUNT(*) as count FROM products WHERE stock = 0').get();
84
+ const lowStock: any = db.prepare('SELECT COUNT(*) as count FROM products WHERE stock > 0 AND stock <= 5').get();
85
+
86
+ return {
87
+ type: 'json' as const,
88
+ data: {
89
+ totalProducts: totalProducts.count,
90
+ totalInventoryValue: totalValue.value || 0,
91
+ outOfStock: outOfStock.count,
92
+ lowStock: lowStock.count,
93
+ categories: 5,
94
+ },
95
+ };
96
+ }
97
+ }
98
+