@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.
- package/README.md +131 -0
- package/dist/commands/build.d.ts +6 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +185 -0
- package/dist/commands/dev.d.ts +7 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +365 -0
- package/dist/commands/generate-types.d.ts +8 -0
- package/dist/commands/generate-types.d.ts.map +1 -0
- package/dist/commands/generate-types.js +219 -0
- package/dist/commands/generate.d.ts +12 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +375 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +324 -0
- package/dist/commands/install.d.ts +10 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +80 -0
- package/dist/commands/start.d.ts +6 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +70 -0
- package/dist/commands/upgrade.d.ts +10 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +214 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +94 -0
- package/dist/mcp-dev-wrapper.d.ts +15 -0
- package/dist/mcp-dev-wrapper.d.ts.map +1 -0
- package/dist/mcp-dev-wrapper.js +187 -0
- package/dist/ui/branding.d.ts +31 -0
- package/dist/ui/branding.d.ts.map +1 -0
- package/dist/ui/branding.js +136 -0
- package/package.json +69 -0
- package/templates/typescript-oauth/.env.example +27 -0
- package/templates/typescript-oauth/OAUTH_SETUP.md +592 -0
- package/templates/typescript-oauth/README.md +263 -0
- package/templates/typescript-oauth/package.json +29 -0
- package/templates/typescript-oauth/src/app.module.ts +92 -0
- package/templates/typescript-oauth/src/guards/oauth.guard.ts +126 -0
- package/templates/typescript-oauth/src/health/system.health.ts +55 -0
- package/templates/typescript-oauth/src/index.ts +63 -0
- package/templates/typescript-oauth/src/modules/flights/booking.tools.ts +323 -0
- package/templates/typescript-oauth/src/modules/flights/flights.module.ts +14 -0
- package/templates/typescript-oauth/src/modules/flights/flights.prompts.ts +228 -0
- package/templates/typescript-oauth/src/modules/flights/flights.resources.ts +215 -0
- package/templates/typescript-oauth/src/modules/flights/flights.tools.ts +457 -0
- package/templates/typescript-oauth/src/services/duffel.service.ts +285 -0
- package/templates/typescript-oauth/src/widgets/app/airport-search/page.tsx +270 -0
- package/templates/typescript-oauth/src/widgets/app/flight-details/page.tsx +261 -0
- package/templates/typescript-oauth/src/widgets/app/flight-search-results/page.tsx +378 -0
- package/templates/typescript-oauth/src/widgets/app/globals.css +167 -0
- package/templates/typescript-oauth/src/widgets/app/layout.tsx +18 -0
- package/templates/typescript-oauth/src/widgets/app/order-cancellation/page.tsx +207 -0
- package/templates/typescript-oauth/src/widgets/app/order-summary/page.tsx +245 -0
- package/templates/typescript-oauth/src/widgets/app/payment-confirmation/page.tsx +152 -0
- package/templates/typescript-oauth/src/widgets/app/seat-selection/page.tsx +486 -0
- package/templates/typescript-oauth/src/widgets/next-env.d.ts +5 -0
- package/templates/typescript-oauth/src/widgets/next.config.js +45 -0
- package/templates/typescript-oauth/src/widgets/package-lock.json +4493 -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 +395 -0
- package/templates/typescript-oauth/tsconfig.json +23 -0
- package/templates/typescript-pizzaz/README.md +252 -0
- package/templates/typescript-pizzaz/package.json +34 -0
- package/templates/typescript-pizzaz/src/app.module.ts +28 -0
- package/templates/typescript-pizzaz/src/index.ts +30 -0
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.data.ts +106 -0
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.module.ts +11 -0
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.service.ts +60 -0
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.tools.ts +197 -0
- package/templates/typescript-pizzaz/src/widgets/app/layout.tsx +18 -0
- package/templates/typescript-pizzaz/src/widgets/app/pizza-list/page.tsx +272 -0
- package/templates/typescript-pizzaz/src/widgets/app/pizza-map/page.tsx +216 -0
- package/templates/typescript-pizzaz/src/widgets/app/pizza-shop/page.tsx +374 -0
- package/templates/typescript-pizzaz/src/widgets/components/CompactShopCard.tsx +144 -0
- package/templates/typescript-pizzaz/src/widgets/components/PizzaCard.tsx +191 -0
- package/templates/typescript-pizzaz/src/widgets/next.config.js +45 -0
- package/templates/typescript-pizzaz/src/widgets/package.json +30 -0
- package/templates/typescript-pizzaz/src/widgets/tsconfig.json +28 -0
- package/templates/typescript-pizzaz/src/widgets/widget-manifest.json +253 -0
- package/templates/typescript-pizzaz/tsconfig.json +30 -0
- package/templates/typescript-starter/README.md +320 -0
- package/templates/typescript-starter/package.json +25 -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 +29 -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 +59 -0
- package/templates/typescript-starter/src/modules/calculator/calculator.tools.ts +166 -0
- package/templates/typescript-starter/src/widgets/app/calculator-result/page.tsx +180 -0
- package/templates/typescript-starter/src/widgets/app/layout.tsx +18 -0
- package/templates/typescript-starter/src/widgets/next.config.js +45 -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
|
@@ -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
|
+
}
|