@nitrostack/cli 1.0.0

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 (100) hide show
  1. package/README.md +131 -0
  2. package/dist/commands/build.d.ts +6 -0
  3. package/dist/commands/build.d.ts.map +1 -0
  4. package/dist/commands/build.js +185 -0
  5. package/dist/commands/dev.d.ts +7 -0
  6. package/dist/commands/dev.d.ts.map +1 -0
  7. package/dist/commands/dev.js +365 -0
  8. package/dist/commands/generate-types.d.ts +8 -0
  9. package/dist/commands/generate-types.d.ts.map +1 -0
  10. package/dist/commands/generate-types.js +219 -0
  11. package/dist/commands/generate.d.ts +12 -0
  12. package/dist/commands/generate.d.ts.map +1 -0
  13. package/dist/commands/generate.js +375 -0
  14. package/dist/commands/init.d.ts +7 -0
  15. package/dist/commands/init.d.ts.map +1 -0
  16. package/dist/commands/init.js +324 -0
  17. package/dist/commands/install.d.ts +10 -0
  18. package/dist/commands/install.d.ts.map +1 -0
  19. package/dist/commands/install.js +80 -0
  20. package/dist/commands/start.d.ts +6 -0
  21. package/dist/commands/start.d.ts.map +1 -0
  22. package/dist/commands/start.js +70 -0
  23. package/dist/commands/upgrade.d.ts +10 -0
  24. package/dist/commands/upgrade.d.ts.map +1 -0
  25. package/dist/commands/upgrade.js +214 -0
  26. package/dist/index.d.ts +11 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +94 -0
  29. package/dist/mcp-dev-wrapper.d.ts +15 -0
  30. package/dist/mcp-dev-wrapper.d.ts.map +1 -0
  31. package/dist/mcp-dev-wrapper.js +187 -0
  32. package/dist/ui/branding.d.ts +31 -0
  33. package/dist/ui/branding.d.ts.map +1 -0
  34. package/dist/ui/branding.js +136 -0
  35. package/package.json +69 -0
  36. package/templates/typescript-oauth/.env.example +27 -0
  37. package/templates/typescript-oauth/OAUTH_SETUP.md +592 -0
  38. package/templates/typescript-oauth/README.md +263 -0
  39. package/templates/typescript-oauth/package.json +29 -0
  40. package/templates/typescript-oauth/src/app.module.ts +92 -0
  41. package/templates/typescript-oauth/src/guards/oauth.guard.ts +126 -0
  42. package/templates/typescript-oauth/src/health/system.health.ts +55 -0
  43. package/templates/typescript-oauth/src/index.ts +63 -0
  44. package/templates/typescript-oauth/src/modules/flights/booking.tools.ts +323 -0
  45. package/templates/typescript-oauth/src/modules/flights/flights.module.ts +14 -0
  46. package/templates/typescript-oauth/src/modules/flights/flights.prompts.ts +228 -0
  47. package/templates/typescript-oauth/src/modules/flights/flights.resources.ts +215 -0
  48. package/templates/typescript-oauth/src/modules/flights/flights.tools.ts +457 -0
  49. package/templates/typescript-oauth/src/services/duffel.service.ts +285 -0
  50. package/templates/typescript-oauth/src/widgets/app/airport-search/page.tsx +270 -0
  51. package/templates/typescript-oauth/src/widgets/app/flight-details/page.tsx +261 -0
  52. package/templates/typescript-oauth/src/widgets/app/flight-search-results/page.tsx +378 -0
  53. package/templates/typescript-oauth/src/widgets/app/globals.css +167 -0
  54. package/templates/typescript-oauth/src/widgets/app/layout.tsx +18 -0
  55. package/templates/typescript-oauth/src/widgets/app/order-cancellation/page.tsx +207 -0
  56. package/templates/typescript-oauth/src/widgets/app/order-summary/page.tsx +245 -0
  57. package/templates/typescript-oauth/src/widgets/app/payment-confirmation/page.tsx +152 -0
  58. package/templates/typescript-oauth/src/widgets/app/seat-selection/page.tsx +486 -0
  59. package/templates/typescript-oauth/src/widgets/next-env.d.ts +5 -0
  60. package/templates/typescript-oauth/src/widgets/next.config.js +45 -0
  61. package/templates/typescript-oauth/src/widgets/package-lock.json +4493 -0
  62. package/templates/typescript-oauth/src/widgets/package.json +24 -0
  63. package/templates/typescript-oauth/src/widgets/tsconfig.json +28 -0
  64. package/templates/typescript-oauth/src/widgets/widget-manifest.json +395 -0
  65. package/templates/typescript-oauth/tsconfig.json +23 -0
  66. package/templates/typescript-pizzaz/README.md +252 -0
  67. package/templates/typescript-pizzaz/package.json +34 -0
  68. package/templates/typescript-pizzaz/src/app.module.ts +28 -0
  69. package/templates/typescript-pizzaz/src/index.ts +30 -0
  70. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.data.ts +106 -0
  71. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.module.ts +11 -0
  72. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.service.ts +60 -0
  73. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.tools.ts +197 -0
  74. package/templates/typescript-pizzaz/src/widgets/app/layout.tsx +18 -0
  75. package/templates/typescript-pizzaz/src/widgets/app/pizza-list/page.tsx +272 -0
  76. package/templates/typescript-pizzaz/src/widgets/app/pizza-map/page.tsx +216 -0
  77. package/templates/typescript-pizzaz/src/widgets/app/pizza-shop/page.tsx +374 -0
  78. package/templates/typescript-pizzaz/src/widgets/components/CompactShopCard.tsx +144 -0
  79. package/templates/typescript-pizzaz/src/widgets/components/PizzaCard.tsx +191 -0
  80. package/templates/typescript-pizzaz/src/widgets/next.config.js +45 -0
  81. package/templates/typescript-pizzaz/src/widgets/package.json +30 -0
  82. package/templates/typescript-pizzaz/src/widgets/tsconfig.json +28 -0
  83. package/templates/typescript-pizzaz/src/widgets/widget-manifest.json +253 -0
  84. package/templates/typescript-pizzaz/tsconfig.json +30 -0
  85. package/templates/typescript-starter/README.md +320 -0
  86. package/templates/typescript-starter/package.json +25 -0
  87. package/templates/typescript-starter/src/app.module.ts +34 -0
  88. package/templates/typescript-starter/src/health/system.health.ts +55 -0
  89. package/templates/typescript-starter/src/index.ts +29 -0
  90. package/templates/typescript-starter/src/modules/calculator/calculator.module.ts +12 -0
  91. package/templates/typescript-starter/src/modules/calculator/calculator.prompts.ts +73 -0
  92. package/templates/typescript-starter/src/modules/calculator/calculator.resources.ts +59 -0
  93. package/templates/typescript-starter/src/modules/calculator/calculator.tools.ts +166 -0
  94. package/templates/typescript-starter/src/widgets/app/calculator-result/page.tsx +180 -0
  95. package/templates/typescript-starter/src/widgets/app/layout.tsx +18 -0
  96. package/templates/typescript-starter/src/widgets/next.config.js +45 -0
  97. package/templates/typescript-starter/src/widgets/package.json +24 -0
  98. package/templates/typescript-starter/src/widgets/tsconfig.json +28 -0
  99. package/templates/typescript-starter/src/widgets/widget-manifest.json +48 -0
  100. package/templates/typescript-starter/tsconfig.json +23 -0
@@ -0,0 +1,252 @@
1
+ # 🍕 NitroStack Pizza Shop Finder
2
+
3
+ A comprehensive NitroStack template showcasing interactive pizza shop discovery with maps, lists, and detailed views. This template demonstrates the NitroStack Widget SDK for building beautiful, interactive widgets.
4
+
5
+ ## Features
6
+
7
+ ### 🎨 **Widget SDK Features**
8
+ - ✅ `useTheme()` - Automatic dark mode support
9
+ - ✅ `useWidgetState()` - Persistent favorites and view preferences
10
+ - ✅ `useMaxHeight()` - Responsive height-aware layouts
11
+ - ✅ `useDisplayMode()` - Fullscreen mode adaptation
12
+ - ✅ `useWidgetSDK()` - Tool calling, navigation, and external links
13
+ - ✅ `<WidgetLayout>` - Automatic RPC setup
14
+
15
+ ### 🗺️ **Three Interactive Widgets**
16
+ 1. **Pizza Map** - Interactive Mapbox map with markers and shop selection
17
+ 2. **Pizza List** - Grid/list view with sorting, filtering, and favorites
18
+ 3. **Pizza Shop** - Detailed shop information with contact actions
19
+
20
+ ### 📊 **MCP Tools**
21
+ - `show_pizza_map` - Display shops on an interactive map
22
+ - `show_pizza_list` - Show filterable list of shops
23
+ - `show_pizza_shop` - Display detailed shop information
24
+
25
+ ## 🚀 Quick Start
26
+
27
+ ### Prerequisites
28
+
29
+ ```bash
30
+ # Install NitroStack CLI globally
31
+ npm install -g nitrostack
32
+
33
+ # Or use npx
34
+ npx nitrostack --version
35
+ ```
36
+
37
+ ### Setup Your Project
38
+
39
+ ```bash
40
+ # Create a new project
41
+ nitrostack init my-pizza-app --template typescript-pizzaz
42
+ cd my-pizza-app
43
+
44
+ # Install all dependencies (root + widgets)
45
+ nitrostack install
46
+ ```
47
+
48
+ ### Configure Mapbox (Optional but Recommended)
49
+
50
+ The map widget uses Mapbox GL for beautiful interactive maps:
51
+
52
+ 1. Get a **free** API key from [Mapbox](https://www.mapbox.com/) (sign up takes 1 minute)
53
+ 2. Create `src/widgets/.env` file:
54
+
55
+ ```bash
56
+ NEXT_PUBLIC_MAPBOX_TOKEN=your_mapbox_token_here
57
+ ```
58
+
59
+ > **Note**: The template works without Mapbox, but the map widget will show a placeholder. You can still use the list and shop detail widgets.
60
+
61
+ ### Run Development Server
62
+
63
+ ```bash
64
+ npm run dev
65
+ ```
66
+
67
+ This starts:
68
+ - **MCP Server** - Hot reloads on code changes
69
+ - **Studio** on http://localhost:3000 - Visual testing environment
70
+ - **Widget Dev Server** on http://localhost:3001 - Hot module replacement
71
+
72
+ ### Test in Studio
73
+
74
+ Try these prompts in Studio chat:
75
+ - "Show me pizza shops on a map"
76
+ - "List all pizza shops"
77
+ - "Show me details for Tony's New York Pizza"
78
+ - "Find pizza shops with high ratings"
79
+
80
+ ## 📁 Project Structure
81
+
82
+ ```
83
+ typescript-pizzaz/
84
+ ├── src/
85
+ │ ├── index.ts # Main server entry
86
+ │ ├── app.module.ts # App module
87
+ │ └── modules/
88
+ │ └── pizzaz/
89
+ │ ├── pizzaz.data.ts # Pizza shop data
90
+ │ ├── pizzaz.service.ts # Business logic
91
+ │ ├── pizzaz.tools.ts # MCP tools
92
+ │ └── pizzaz.module.ts # Module definition
93
+ │ └── widgets/
94
+ │ ├── app/
95
+ │ │ ├── pizza-map/ # Map widget
96
+ │ │ ├── pizza-list/ # List widget
97
+ │ │ └── pizza-shop/ # Shop detail widget
98
+ │ └── components/
99
+ │ └── PizzaCard.tsx # Reusable card component
100
+ ├── package.json
101
+ └── README.md
102
+ ```
103
+
104
+ ## 🎨 Widget Features
105
+
106
+ ### Pizza Map Widget
107
+ - **Interactive Mapbox map** with custom markers
108
+ - **Shop sidebar** with quick selection
109
+ - **Fullscreen mode** for better exploration
110
+ - **Persistent favorites** using `useWidgetState()`
111
+ - **Theme-aware** map styles (light/dark)
112
+
113
+ ### Pizza List Widget
114
+ - **Grid/List view toggle** with state persistence
115
+ - **Sorting** by rating, name, or price
116
+ - **Favorites tracking** across sessions
117
+ - **Responsive layout** using `useMaxHeight()`
118
+ - **Filter panel** for advanced search
119
+
120
+ ### Pizza Shop Widget
121
+ - **Hero image** with overlay information
122
+ - **Contact actions** (call, directions, website)
123
+ - **Specialties showcase**
124
+ - **Related shops** recommendations
125
+ - **External link handling** via `useWidgetSDK()`
126
+
127
+ ## 🔧 Commands
128
+
129
+ ```bash
130
+ # Installation
131
+ npm install # Install all dependencies (root + widgets)
132
+ nitrostack install # Same as above
133
+
134
+ # Development
135
+ npm run dev # Start dev server with Studio
136
+ npm run build # Build TypeScript and widgets for production
137
+ npm start # Run production server
138
+
139
+ # Upgrade
140
+ npm run upgrade # Upgrade nitrostack to latest version
141
+
142
+ # Widget Management
143
+ npm run widget <command> # Run npm command in widgets directory
144
+ npm run widget add <pkg> # Add a widget dependency
145
+ ```
146
+
147
+ ## 🛠️ Customization
148
+
149
+ ### Adding More Shops
150
+
151
+ Edit `src/modules/pizzaz/pizzaz.data.ts`:
152
+
153
+ ```typescript
154
+ export const PIZZA_SHOPS: PizzaShop[] = [
155
+ {
156
+ id: 'my-pizza-shop',
157
+ name: 'My Pizza Shop',
158
+ description: 'Amazing pizza!',
159
+ address: '123 Main St, City, State 12345',
160
+ coords: [-122.4194, 37.7749], // [lng, lat]
161
+ rating: 4.5,
162
+ reviews: 100,
163
+ priceLevel: 2,
164
+ cuisine: ['Italian', 'Pizza'],
165
+ hours: { open: '11:00 AM', close: '10:00 PM' },
166
+ phone: '(555) 123-4567',
167
+ website: 'https://example.com',
168
+ image: 'https://images.unsplash.com/photo-...',
169
+ specialties: ['Margherita', 'Pepperoni'],
170
+ openNow: true,
171
+ },
172
+ // ... more shops
173
+ ];
174
+ ```
175
+
176
+ ### Changing Map Style
177
+
178
+ Edit `src/widgets/app/pizza-map/page.tsx`:
179
+
180
+ ```typescript
181
+ style: isDark
182
+ ? 'mapbox://styles/mapbox/dark-v11' // Dark mode style
183
+ : 'mapbox://styles/mapbox/streets-v12' // Light mode style
184
+ ```
185
+
186
+ ### Adding New Filters
187
+
188
+ Edit `src/modules/pizzaz/pizzaz.service.ts` to add more filter options.
189
+
190
+ ## 📚 SDK Features Demonstrated
191
+
192
+ ### Theme Awareness
193
+ ```typescript
194
+ const theme = useTheme(); // 'light' | 'dark'
195
+ const bgColor = theme === 'dark' ? '#000' : '#fff';
196
+ ```
197
+
198
+ ### State Persistence
199
+ ```typescript
200
+ const [state, setState] = useWidgetState(() => ({
201
+ favorites: [],
202
+ viewMode: 'grid',
203
+ }));
204
+
205
+ // State persists across widget reloads
206
+ setState({ ...state, favorites: [...state.favorites, shopId] });
207
+ ```
208
+
209
+ ### Responsive Layouts
210
+ ```typescript
211
+ const maxHeight = useMaxHeight();
212
+ return <div style={{ maxHeight }}>{content}</div>;
213
+ ```
214
+
215
+ ### Display Mode Adaptation
216
+ ```typescript
217
+ const displayMode = useDisplayMode(); // 'inline' | 'pip' | 'fullscreen'
218
+ const showSidebar = displayMode === 'fullscreen';
219
+ ```
220
+
221
+ ### External Links
222
+ ```typescript
223
+ const { openExternal } = useWidgetSDK();
224
+ openExternal('https://example.com');
225
+ ```
226
+
227
+ ## 🚀 Deployment
228
+
229
+ ### Build for Production
230
+
231
+ ```bash
232
+ npm run build
233
+ ```
234
+
235
+ ### Deploy Widgets
236
+
237
+ Widget HTML files will be generated in `src/widgets/out/` - these work identically in any MCP-compatible client including OpenAI ChatGPT.
238
+
239
+ ## 📚 Next Steps
240
+
241
+ - Try the **Starter Template** - Learn the basics
242
+ - Try the **Flight Booking Template** - API integration with Duffel
243
+ - Read the [NitroStack Documentation](https://nitrostack.ai/docs)
244
+ - Check out [Mapbox GL JS Documentation](https://docs.mapbox.com/mapbox-gl-js/)
245
+
246
+ ## License
247
+
248
+ MIT
249
+
250
+ ---
251
+
252
+ **Built with ❤️ using NitroStack**
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "nitrostack-pizzaz",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "description": "NitroStack Pizza Shop Finder - Interactive map widgets with Mapbox integration",
7
+ "scripts": {
8
+ "dev": "nitrostack-cli dev",
9
+ "build": "nitrostack-cli build",
10
+ "start": "npm run build && nitrostack-cli start",
11
+ "start:prod": "nitrostack-cli start",
12
+ "upgrade": "nitrostack-cli upgrade",
13
+ "install:all": "nitrostack-cli install",
14
+ "widget": "npm --prefix src/widgets"
15
+ },
16
+ "keywords": [
17
+ "nitrostack",
18
+ "mcp",
19
+ "pizza",
20
+ "map",
21
+ "widgets"
22
+ ],
23
+ "author": "",
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "nitrostack": "^1",
27
+ "zod": "^3.22.4",
28
+ "dotenv": "^16.3.1"
29
+ },
30
+ "devDependencies": {
31
+ "@nitrostack/cli": "^1",
32
+ "typescript": "^5.3.3"
33
+ }
34
+ }
@@ -0,0 +1,28 @@
1
+ import { McpApp, Module, ConfigModule } from 'nitrostack';
2
+ import { PizzazModule } from './modules/pizzaz/pizzaz.module.js';
3
+
4
+ /**
5
+ * Root Application Module
6
+ *
7
+ * Pizza shop finder with interactive maps.
8
+ * Showcases NitroStack Widget SDK features.
9
+ */
10
+ @McpApp({
11
+ module: AppModule,
12
+ server: {
13
+ name: 'pizzaz-finder',
14
+ version: '1.0.0'
15
+ },
16
+ logging: {
17
+ level: 'info'
18
+ }
19
+ })
20
+ @Module({
21
+ name: 'pizzaz',
22
+ description: 'Pizza shop finder with interactive maps',
23
+ imports: [
24
+ ConfigModule.forRoot(),
25
+ PizzazModule
26
+ ],
27
+ })
28
+ export class AppModule { }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Pizzaz MCP Server
3
+ *
4
+ * Pizza shop finder with interactive map widgets.
5
+ * Showcases NitroStack Widget SDK features including:
6
+ * - useTheme() for dark mode
7
+ * - useWidgetState() for persistent favorites
8
+ * - useDisplayMode() for fullscreen support
9
+ * - useMaxHeight() for responsive layouts
10
+ * - useWidgetSDK() for tool calling and navigation
11
+ */
12
+
13
+ import 'dotenv/config';
14
+ import { McpApplicationFactory } from 'nitrostack';
15
+ import { AppModule } from './app.module.js';
16
+
17
+ /**
18
+ * Bootstrap the application
19
+ */
20
+ async function bootstrap() {
21
+ // Create and start the MCP server
22
+ const server = await McpApplicationFactory.create(AppModule);
23
+ await server.start();
24
+ }
25
+
26
+ // Start the application
27
+ bootstrap().catch((error) => {
28
+ console.error('❌ Failed to start server:', error);
29
+ process.exit(1);
30
+ });
@@ -0,0 +1,106 @@
1
+ export interface PizzaShop {
2
+ id: string;
3
+ name: string;
4
+ description: string;
5
+ address: string;
6
+ coords: [number, number]; // [lng, lat]
7
+ rating: number;
8
+ reviews: number;
9
+ priceLevel: 1 | 2 | 3;
10
+ cuisine: string[];
11
+ hours: {
12
+ open: string;
13
+ close: string;
14
+ };
15
+ phone: string;
16
+ website?: string;
17
+ image: string;
18
+ specialties: string[];
19
+ openNow: boolean;
20
+ }
21
+
22
+ export const PIZZA_SHOPS: PizzaShop[] = [
23
+ {
24
+ id: 'tonys-pizza',
25
+ name: "Tony's New York Pizza",
26
+ description: "Authentic New York-style pizza with a crispy thin crust and fresh toppings",
27
+ address: "123 Main St, San Francisco, CA 94102",
28
+ coords: [-122.4194, 37.7749],
29
+ rating: 4.5,
30
+ reviews: 342,
31
+ priceLevel: 2,
32
+ cuisine: ['Italian', 'Pizza', 'New York Style'],
33
+ hours: { open: '11:00 AM', close: '10:00 PM' },
34
+ phone: '(415) 555-0123',
35
+ website: 'https://tonyspizza.example.com',
36
+ image: 'https://images.unsplash.com/photo-1513104890138-7c749659a591',
37
+ specialties: ['Margherita', 'Pepperoni', 'White Pizza'],
38
+ openNow: true,
39
+ },
40
+ {
41
+ id: 'bella-napoli',
42
+ name: 'Bella Napoli',
43
+ description: "Traditional Neapolitan pizza baked in a wood-fired oven",
44
+ address: "456 Market St, San Francisco, CA 94103",
45
+ coords: [-122.4089, 37.7858],
46
+ rating: 4.8,
47
+ reviews: 521,
48
+ priceLevel: 3,
49
+ cuisine: ['Italian', 'Pizza', 'Neapolitan'],
50
+ hours: { open: '12:00 PM', close: '11:00 PM' },
51
+ phone: '(415) 555-0456',
52
+ website: 'https://bellanapoli.example.com',
53
+ image: 'https://images.unsplash.com/photo-1574071318508-1cdbab80d002',
54
+ specialties: ['Marinara', 'Quattro Formaggi', 'Diavola'],
55
+ openNow: true,
56
+ },
57
+ {
58
+ id: 'slice-house',
59
+ name: 'The Slice House',
60
+ description: "Casual spot for creative pizza slices and craft beer",
61
+ address: "789 Valencia St, San Francisco, CA 94110",
62
+ coords: [-122.4216, 37.7599],
63
+ rating: 4.3,
64
+ reviews: 289,
65
+ priceLevel: 1,
66
+ cuisine: ['Pizza', 'American', 'Casual'],
67
+ hours: { open: '11:30 AM', close: '9:00 PM' },
68
+ phone: '(415) 555-0789',
69
+ image: 'https://images.unsplash.com/photo-1565299624946-b28f40a0ae38',
70
+ specialties: ['BBQ Chicken', 'Hawaiian', 'Veggie Supreme'],
71
+ openNow: true,
72
+ },
73
+ {
74
+ id: 'pizzeria-delfina',
75
+ name: 'Pizzeria Delfina',
76
+ description: "Upscale pizzeria with seasonal ingredients and house-made mozzarella",
77
+ address: "3611 18th St, San Francisco, CA 94110",
78
+ coords: [-122.4252, 37.7615],
79
+ rating: 4.6,
80
+ reviews: 678,
81
+ priceLevel: 3,
82
+ cuisine: ['Italian', 'Pizza', 'Fine Dining'],
83
+ hours: { open: '5:00 PM', close: '10:00 PM' },
84
+ phone: '(415) 555-3611',
85
+ website: 'https://pizzeriadelfina.example.com',
86
+ image: 'https://images.unsplash.com/photo-1571997478779-2adcbbe9ab2f',
87
+ specialties: ['Salsiccia', 'Funghi', 'Prosciutto e Rucola'],
88
+ openNow: false,
89
+ },
90
+ {
91
+ id: 'golden-boy',
92
+ name: 'Golden Boy Pizza',
93
+ description: "North Beach institution serving thick Sicilian-style squares",
94
+ address: "542 Green St, San Francisco, CA 94133",
95
+ coords: [-122.4102, 37.7999],
96
+ rating: 4.4,
97
+ reviews: 445,
98
+ priceLevel: 1,
99
+ cuisine: ['Pizza', 'Sicilian', 'Italian'],
100
+ hours: { open: '11:30 AM', close: '11:30 PM' },
101
+ phone: '(415) 555-0542',
102
+ image: 'https://images.unsplash.com/photo-1628840042765-356cda07504e',
103
+ specialties: ['Clam & Garlic', 'Pesto', 'Classic Cheese'],
104
+ openNow: true,
105
+ },
106
+ ];
@@ -0,0 +1,11 @@
1
+ import { Module } from 'nitrostack';
2
+ import { PizzazService } from './pizzaz.service.js';
3
+ import { PizzazTools } from './pizzaz.tools.js';
4
+
5
+ @Module({
6
+ name: 'pizzaz',
7
+ description: 'Pizza shop finder module',
8
+ controllers: [PizzazTools],
9
+ providers: [PizzazService],
10
+ })
11
+ export class PizzazModule { }
@@ -0,0 +1,60 @@
1
+ import { Injectable } from 'nitrostack';
2
+ import { PIZZA_SHOPS, type PizzaShop } from './pizzaz.data.js';
3
+
4
+ @Injectable()
5
+ export class PizzazService {
6
+ /**
7
+ * Get all pizza shops
8
+ */
9
+ getAllShops(): PizzaShop[] {
10
+ return PIZZA_SHOPS;
11
+ }
12
+
13
+ /**
14
+ * Get a specific pizza shop by ID
15
+ */
16
+ getShopById(id: string): PizzaShop | undefined {
17
+ return PIZZA_SHOPS.find(shop => shop.id === id);
18
+ }
19
+
20
+ /**
21
+ * Get pizza shops filtered by criteria
22
+ */
23
+ getShopsFiltered(filters: {
24
+ openNow?: boolean;
25
+ minRating?: number;
26
+ maxPrice?: number;
27
+ cuisine?: string;
28
+ }): PizzaShop[] {
29
+ let shops = [...PIZZA_SHOPS];
30
+
31
+ if (filters.openNow) {
32
+ shops = shops.filter(shop => shop.openNow);
33
+ }
34
+
35
+ if (filters.minRating !== undefined) {
36
+ shops = shops.filter(shop => shop.rating >= filters.minRating!);
37
+ }
38
+
39
+ if (filters.maxPrice !== undefined) {
40
+ shops = shops.filter(shop => shop.priceLevel <= filters.maxPrice!);
41
+ }
42
+
43
+ if (filters.cuisine) {
44
+ shops = shops.filter(shop =>
45
+ shop.cuisine.some(c => c.toLowerCase().includes(filters.cuisine!.toLowerCase()))
46
+ );
47
+ }
48
+
49
+ return shops;
50
+ }
51
+
52
+ /**
53
+ * Get shops sorted by rating
54
+ */
55
+ getTopRatedShops(limit: number = 5): PizzaShop[] {
56
+ return [...PIZZA_SHOPS]
57
+ .sort((a, b) => b.rating - a.rating)
58
+ .slice(0, limit);
59
+ }
60
+ }