japan-seasons-mcp 0.3.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 (46) hide show
  1. package/.github/workflows/ci.yml +67 -0
  2. package/.github/workflows/scrape-fruit-farms.yml +62 -0
  3. package/README.md +220 -0
  4. package/dist/api.d.ts +2 -0
  5. package/dist/api.js +148 -0
  6. package/dist/api.js.map +1 -0
  7. package/dist/index.d.ts +2 -0
  8. package/dist/index.js +471 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/lib/areas.d.ts +11 -0
  11. package/dist/lib/areas.js +146 -0
  12. package/dist/lib/areas.js.map +1 -0
  13. package/dist/lib/cache.d.ts +19 -0
  14. package/dist/lib/cache.js +89 -0
  15. package/dist/lib/cache.js.map +1 -0
  16. package/dist/lib/fetch.d.ts +1 -0
  17. package/dist/lib/fetch.js +106 -0
  18. package/dist/lib/fetch.js.map +1 -0
  19. package/dist/lib/koyo.d.ts +54 -0
  20. package/dist/lib/koyo.js +175 -0
  21. package/dist/lib/koyo.js.map +1 -0
  22. package/dist/lib/logger.d.ts +5 -0
  23. package/dist/lib/logger.js +7 -0
  24. package/dist/lib/logger.js.map +1 -0
  25. package/dist/lib/romaji.d.ts +6 -0
  26. package/dist/lib/romaji.js +130 -0
  27. package/dist/lib/romaji.js.map +1 -0
  28. package/dist/lib/sakura-forecast.d.ts +96 -0
  29. package/dist/lib/sakura-forecast.js +431 -0
  30. package/dist/lib/sakura-forecast.js.map +1 -0
  31. package/dist/lib/weather.d.ts +43 -0
  32. package/dist/lib/weather.js +68 -0
  33. package/dist/lib/weather.js.map +1 -0
  34. package/package.json +58 -0
  35. package/playwright-verify.cjs +291 -0
  36. package/playwright-verify.py +334 -0
  37. package/public/flowers.json +398 -0
  38. package/public/fruit-farms.json +4210 -0
  39. package/public/index.html +1864 -0
  40. package/scrape-fruit-farms.py +225 -0
  41. package/scrape-jalan.py +156 -0
  42. package/scrape-navitime-explore.py +85 -0
  43. package/scrape-pagination-explore.py +56 -0
  44. package/test-audit.py +201 -0
  45. package/test-popups.js +99 -0
  46. package/test-popups.py +112 -0
@@ -0,0 +1,67 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ schedule:
9
+ # Run daily at 9 AM JST (midnight UTC) to detect upstream API breakage
10
+ - cron: "0 0 * * *"
11
+
12
+ jobs:
13
+ build:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: actions/setup-node@v4
18
+ with:
19
+ node-version: 22
20
+ - run: npm ci
21
+ - run: npm run build
22
+
23
+ api-health:
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - name: Check n-kishou sakura API
27
+ run: |
28
+ STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://other-api-prod.n-kishou.co.jp/get-sakura-hw")
29
+ echo "Sakura API: $STATUS"
30
+ [ "$STATUS" = "200" ] || exit 1
31
+
32
+ - name: Check n-kishou spots API
33
+ run: |
34
+ STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://other-api-prod.n-kishou.co.jp/list-jr-points?type=sakura&filter_mode=forecast&area_mode=pref&area_code=13&sort_code=0")
35
+ echo "Spots API: $STATUS"
36
+ [ "$STATUS" = "200" ] || exit 1
37
+
38
+ - name: Check koyo forecast list
39
+ run: |
40
+ STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://tennavi-data-prod.n-kishou.co.jp/koyo/koyo_jma_forecast_list.json")
41
+ echo "Koyo forecast: $STATUS"
42
+ [ "$STATUS" = "200" ] || exit 1
43
+
44
+ - name: Check Kawazu cherry data
45
+ run: |
46
+ STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://tennavi-data-prod.n-kishou.co.jp/sakura/sakura_forecast_kawazu_list.json")
47
+ echo "Kawazu data: $STATUS"
48
+ [ "$STATUS" = "200" ] || exit 1
49
+
50
+ - name: Check weather API
51
+ run: |
52
+ STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://weather.tsukumijima.net/api/forecast/city/130010")
53
+ echo "Weather API: $STATUS"
54
+ [ "$STATUS" = "200" ] || exit 1
55
+
56
+ - name: Verify sakura API response structure
57
+ run: |
58
+ curl -s "https://other-api-prod.n-kishou.co.jp/get-sakura-hw" | python3 -c "
59
+ import json, sys
60
+ data = json.load(sys.stdin)
61
+ regions = data['result_list']['region']
62
+ assert len(regions) > 0, 'No regions returned'
63
+ sample = regions[0]['sample'][0]
64
+ assert 'bloom' in sample, 'Missing bloom data'
65
+ assert 'full' in sample, 'Missing full bloom data'
66
+ print(f'OK: {len(regions)} regions, structure valid')
67
+ "
@@ -0,0 +1,62 @@
1
+ name: Scrape Fruit Farm Spots
2
+
3
+ on:
4
+ schedule:
5
+ # Every Monday at 2am JST (Sunday 17:00 UTC)
6
+ - cron: '0 17 * * 0'
7
+ workflow_dispatch: # allow manual trigger
8
+
9
+ jobs:
10
+ scrape:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - name: Set up Python
16
+ uses: actions/setup-python@v5
17
+ with:
18
+ python-version: '3.12'
19
+
20
+ - name: Install Playwright
21
+ run: |
22
+ pip install playwright requests
23
+ playwright install chromium
24
+
25
+ - name: Scrape Navitime (base data)
26
+ run: python3 scrape-fruit-farms.py
27
+ timeout-minutes: 15
28
+
29
+ - name: Scrape Jalan (merge with existing)
30
+ run: python3 scrape-jalan.py
31
+ timeout-minutes: 30
32
+
33
+ - name: Validate output (fail fast if scrape broke)
34
+ run: |
35
+ python3 -c "
36
+ import json, sys
37
+ d = json.load(open('public/fruit-farms.json'))
38
+ total = d.get('total', 0)
39
+ coords = d.get('with_coords', 0)
40
+ print(f'Total spots: {total}, with coords: {coords}')
41
+ if total < 50:
42
+ print('ERROR: Too few spots — scraper likely broke or was blocked')
43
+ sys.exit(1)
44
+ if coords < 30:
45
+ print('ERROR: Too few coordinates — coordinate extraction broke')
46
+ sys.exit(1)
47
+ print('Validation passed')
48
+ "
49
+
50
+ - name: Check if data changed
51
+ id: check
52
+ run: |
53
+ git diff --quiet public/fruit-farms.json && echo "changed=false" >> $GITHUB_OUTPUT || echo "changed=true" >> $GITHUB_OUTPUT
54
+
55
+ - name: Commit updated farm data
56
+ if: steps.check.outputs.changed == 'true'
57
+ run: |
58
+ git config user.name "github-actions[bot]"
59
+ git config user.email "github-actions[bot]@users.noreply.github.com"
60
+ git add public/fruit-farms.json
61
+ git commit -m "chore: update fruit farm spots (weekly scrape)"
62
+ git push
package/README.md ADDED
@@ -0,0 +1,220 @@
1
+ <p align="center">
2
+ <h1 align="center">japan-sakura-koyo-mcp</h1>
3
+ <p align="center">
4
+ Real-time cherry blossom & autumn leaves forecast for Japan.<br>
5
+ 1,700+ spots. Live bloom data. Built for AI assistants.
6
+ </p>
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="https://www.npmjs.com/package/japan-sakura-koyo-mcp"><img src="https://img.shields.io/npm/v/japan-sakura-koyo-mcp" alt="npm"></a>
11
+ <a href="https://github.com/haomingkoo/japan-sakura-koyo-mcp/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="license"></a>
12
+ <a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-compatible-brightgreen" alt="MCP"></a>
13
+ </p>
14
+
15
+ ---
16
+
17
+ **Try it live:** [sakura.kooexperience.com](https://sakura.kooexperience.com) — interactive map with all 1,012 spots
18
+
19
+ **The problem:** You ask ChatGPT, Gemini, or Claude *"When should I visit Kyoto for cherry blossoms?"* and get a generic answer based on training data. The actual bloom date shifts by weeks every year depending on temperature.
20
+
21
+ **The fix:** This MCP server gives AI assistants access to **live forecast data** from the Japan Meteorological Corporation — the same source behind Japan's #1 cherry blossom app (SAKURA NAVI). Real dates. Real bloom percentages. Updated daily.
22
+
23
+ ## What You Get
24
+
25
+ | Data | Coverage | Updated |
26
+ |------|----------|---------|
27
+ | **Sakura forecast** | 48 JMA observation cities — forecast vs actual bloom dates, historical averages | Daily |
28
+ | **Sakura spots** | **1,012** parks, temples, gardens — bloom %, full bloom %, GPS coordinates | Daily 9AM JST |
29
+ | **Kawazu cherry** | 9 early-bloom spots in Izu Peninsula (Jan-Feb, deep pink variety) | Seasonal |
30
+ | **Koyo forecast** | 50+ cities — maple & ginkgo color change dates vs historical normal | Seasonal |
31
+ | **Koyo spots** | **687** autumn viewing spots — peak window (start/peak/end), popularity rating, GPS | Seasonal |
32
+ | **Weather** | 51 cities — 3-day forecast, temperature, rain probability | Hourly |
33
+
34
+ Every data point comes from a live API call. Nothing is hardcoded or hallucinated.
35
+
36
+ ## Quick Start
37
+
38
+ ### Use with Claude Desktop / Claude Code
39
+
40
+ Add to your MCP config:
41
+
42
+ ```json
43
+ {
44
+ "mcpServers": {
45
+ "japan-sakura-koyo": {
46
+ "command": "npx",
47
+ "args": ["japan-sakura-koyo-mcp"]
48
+ }
49
+ }
50
+ }
51
+ ```
52
+
53
+ Then ask Claude: *"I'm going to Japan April 10-15. Where should I see cherry blossoms?"*
54
+
55
+ ### Use with any MCP client (hosted)
56
+
57
+ Deploy and connect via URL:
58
+
59
+ ```bash
60
+ PORT=3000 npx japan-sakura-koyo-mcp --http
61
+ # MCP endpoint: http://localhost:3000/mcp
62
+ ```
63
+
64
+ Deploy to Railway, Fly.io, or Render — any MCP client connects with just a URL.
65
+
66
+ Or use our hosted instance: `https://sakura.kooexperience.com/mcp`
67
+
68
+ ## Tools
69
+
70
+ ### Cherry Blossom (Sakura)
71
+
72
+ **`get_sakura_forecast`** — Big picture across all of Japan
73
+ ```
74
+ "I want to see cherry blossoms in Japan"
75
+ → Returns 48 cities with bloom status, forecast dates, actual observation dates, historical averages
76
+ ```
77
+
78
+ **`get_sakura_spots`** — Drill into specific viewing spots
79
+ ```
80
+ "Show me cherry blossom spots in Kyoto"
81
+ → Returns 51 spots: Kiyomizu-dera, Arashiyama, Philosopher's Path... with bloom %, GPS
82
+ ```
83
+
84
+ **`get_sakura_best_dates`** — Match your travel dates
85
+ ```
86
+ "I'm traveling April 10-15"
87
+ → Returns cities where bloom overlaps your dates, ranked by timing
88
+ ```
89
+
90
+ **`get_kawazu_cherry`** — Early-season deep pink variety
91
+ ```
92
+ "I want to see cherry blossoms in February"
93
+ → Returns 9 Kawazu cherry spots in Izu Peninsula (blooms Jan-Feb, months before standard sakura)
94
+ ```
95
+
96
+ ### Autumn Leaves (Koyo)
97
+
98
+ **`get_koyo_forecast`** — Maple & ginkgo timing by city
99
+ ```
100
+ "When do autumn leaves peak in Japan?"
101
+ → Returns 50+ cities with maple/ginkgo dates and comparison to historical normal
102
+ ```
103
+
104
+ **`get_koyo_spots`** — Famous viewing spots
105
+ ```
106
+ "Best autumn leaves spots in Kyoto"
107
+ → Returns 52 spots: Arashiyama, Eikando, Tofukuji... with peak dates, popularity rating, GPS
108
+ ```
109
+
110
+ ### Weather
111
+
112
+ **`get_weather_forecast`** — 3-day forecast for trip planning
113
+ ```
114
+ "What's the weather in Osaka?"
115
+ → Temperature, rain probability (6-hour windows), wind, conditions
116
+ ```
117
+
118
+ ## Bloom Scale
119
+
120
+ The official Japan Meteorological Corporation scale, used for all 1,012 sakura spots:
121
+
122
+ ```
123
+ BLOOM RATE (progress toward first bloom)
124
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
125
+ 0% 60% 85% 100%
126
+ | Bud stage | Swelling | Opening | Bloom!
127
+ 花芽〜つぼみ 膨らみ始め 開き始め 開花
128
+
129
+ FULL BLOOM RATE (progress toward mankai/満開)
130
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
131
+ 0% 20% 40% 70% 90% 100%
132
+ | Open | 30% | 50% | 70% | Full bloom!
133
+ 開花 三分咲き 五分咲き 七分咲き 満開
134
+ ```
135
+
136
+ ## How It Works
137
+
138
+ ```
139
+ ┌──────────────────────────────────────────────┐
140
+ │ Japan Meteorological Corporation APIs │
141
+ │ (n-kishou.co.jp) │
142
+ │ │
143
+ │ get-sakura-hw → 48 city forecasts │
144
+ │ list-jr-points → 1,012 sakura spots │
145
+ │ list-jr-points → 687 koyo spots │
146
+ │ kawazu_info.json → Kawazu cherry data │
147
+ │ koyo_*.json → Autumn leaves forecasts │
148
+ └──────────────┬───────────────────────────────┘
149
+ │ live API calls (cached 1-6 hours)
150
+
151
+ ┌──────────────▼───────────────────────────────┐
152
+ │ japan-sakura-koyo-mcp │
153
+ │ │
154
+ │ stdio mode: npx japan-sakura-koyo-mcp │
155
+ │ HTTP mode: PORT=3000 ... --http │
156
+ │ │
157
+ │ 7 tools, 1 prompt template │
158
+ └──────────────┬───────────────────────────────┘
159
+ │ MCP protocol
160
+
161
+ ┌─────────┼─────────┐
162
+ │ │ │
163
+ Claude ChatGPT Gemini
164
+ ```
165
+
166
+ ## Season Guide
167
+
168
+ | When | What to See | Tool to Use |
169
+ |------|-------------|-------------|
170
+ | Jan-Feb | Kawazu cherry (deep pink, Izu Peninsula) | `get_kawazu_cherry` |
171
+ | Late Mar | Sakura begins in Kyushu, Shikoku, Kansai | `get_sakura_forecast` |
172
+ | Early Apr | Peak sakura in Tokyo, Osaka, Kyoto | `get_sakura_spots` |
173
+ | Mid Apr | Sakura moves to Tohoku | `get_sakura_best_dates` |
174
+ | Late Apr-May | Sakura reaches Hokkaido | `get_sakura_spots` |
175
+ | Oct-Nov | Autumn leaves begin in Hokkaido, mountains | `get_koyo_forecast` |
176
+ | Nov-Dec | Peak koyo in Kyoto, Tokyo, Kansai | `get_koyo_spots` |
177
+
178
+ ## Development
179
+
180
+ ```bash
181
+ git clone https://github.com/haomingkoo/japan-sakura-koyo-mcp.git
182
+ cd japan-sakura-koyo-mcp
183
+ npm install
184
+ npm run build
185
+ npm start # stdio mode
186
+ npm run start:http # HTTP mode on port 3000
187
+ ```
188
+
189
+ ## Data Sources
190
+
191
+ - **[Japan Meteorological Corporation](https://n-kishou.com)** (日本気象株式会社) — Sakura & koyo forecasts, bloom rates, 1,700+ viewing spots
192
+ - **[Japan Meteorological Agency](https://www.jma.go.jp)** (気象庁) — Weather forecasts via [tsukumijima API](https://weather.tsukumijima.net)
193
+
194
+ ## Web App
195
+
196
+ Visit [sakura.kooexperience.com](https://sakura.kooexperience.com) for the interactive frontend:
197
+
198
+ - **Interactive map** with all 1,012 sakura spots + marker clustering
199
+ - **Lifecycle colors** — orange (bud) → pink (bloom) → green (ended)
200
+ - **Plan My Trip** — type cities you're visiting, find nearby spots with distance
201
+ - **Near Me** — uses your location to find spots within 30km
202
+ - **Kawazu cherry ★ markers** on the map (early-bloom Jan-Feb variety)
203
+ - **Fuzzy search** — find spots even with typos
204
+ - **Romaji names** — all 1,700 spots romanized for international users
205
+ - **Google Maps + Navitime** route links on every spot
206
+ - **Weather forecast** card when viewing prefecture spots
207
+
208
+ ## Contributing
209
+
210
+ PRs welcome. Key areas:
211
+
212
+ - **Okinawa sakura** — Uses hikan-zakura (different species), currently not covered by the forecast API.
213
+ - **More data sources** — Plum blossom (ume), wisteria (fuji), sunflower (himawari) seasons.
214
+ - **Historical data** — JMA has bloom records back to 1953.
215
+ - **Multi-select prefectures** — View spots across multiple regions at once.
216
+ - **Nearby attractions** — Overlay famous landmarks near sakura spots.
217
+
218
+ ## License
219
+
220
+ MIT
package/dist/api.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ import type { IncomingMessage, ServerResponse } from "http";
2
+ export declare function handleApiRequest(req: IncomingMessage, res: ServerResponse, pathname: string, params: URLSearchParams): Promise<boolean>;
package/dist/api.js ADDED
@@ -0,0 +1,148 @@
1
+ import { readFileSync } from "fs";
2
+ import { resolve } from "path";
3
+ import { getSakuraForecast, getSakuraSpots, getKawazuForecast, findCities, findBestRegions, findPrefCode, } from "./lib/sakura-forecast.js";
4
+ import { getKoyoForecast, getKoyoSpots } from "./lib/koyo.js";
5
+ import { getWeatherForecast } from "./lib/weather.js";
6
+ function json(res, data, status = 200) {
7
+ res.writeHead(status, { "Content-Type": "application/json" });
8
+ res.end(JSON.stringify(data));
9
+ }
10
+ function error(res, msg, status = 400) {
11
+ json(res, { error: msg }, status);
12
+ }
13
+ export async function handleApiRequest(req, res, pathname, params) {
14
+ try {
15
+ // GET /api/sakura/forecast?city=Tokyo
16
+ if (pathname === "/api/sakura/forecast") {
17
+ const forecast = await getSakuraForecast();
18
+ const city = params.get("city");
19
+ if (city) {
20
+ const cities = findCities(forecast, city);
21
+ json(res, { cities });
22
+ }
23
+ else {
24
+ json(res, forecast);
25
+ }
26
+ return true;
27
+ }
28
+ // GET /api/sakura/spots?pref=Tokyo (or pref=13)
29
+ if (pathname === "/api/sakura/spots") {
30
+ const pref = params.get("pref");
31
+ if (!pref) {
32
+ error(res, "Missing ?pref= parameter");
33
+ return true;
34
+ }
35
+ const prefCode = findPrefCode(pref);
36
+ if (!prefCode) {
37
+ error(res, `Prefecture "${pref}" not found`);
38
+ return true;
39
+ }
40
+ const spots = await getSakuraSpots(prefCode);
41
+ json(res, spots);
42
+ return true;
43
+ }
44
+ // GET /api/sakura/best?start=2026-04-10&end=2026-04-15
45
+ if (pathname === "/api/sakura/best") {
46
+ const start = params.get("start");
47
+ const end = params.get("end");
48
+ if (!start || !end) {
49
+ error(res, "Missing ?start= and ?end= parameters");
50
+ return true;
51
+ }
52
+ const startDate = new Date(start);
53
+ const endDate = new Date(end);
54
+ if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
55
+ error(res, "Invalid date format. Use YYYY-MM-DD.");
56
+ return true;
57
+ }
58
+ const forecast = await getSakuraForecast();
59
+ const matches = findBestRegions(forecast, startDate, endDate);
60
+ json(res, { start, end, matches });
61
+ return true;
62
+ }
63
+ // GET /api/sakura/all-spots — load all 1,012 spots across Japan
64
+ if (pathname === "/api/sakura/all-spots") {
65
+ const allSpots = [];
66
+ const prefCodes = Array.from({ length: 47 }, (_, i) => String(i + 1).padStart(2, "0"));
67
+ const results = await Promise.allSettled(prefCodes.map(code => getSakuraSpots(code)));
68
+ for (const r of results) {
69
+ if (r.status === "fulfilled" && r.value.spots) {
70
+ allSpots.push(...r.value.spots);
71
+ }
72
+ }
73
+ json(res, { totalSpots: allSpots.length, spots: allSpots });
74
+ return true;
75
+ }
76
+ // GET /api/kawazu
77
+ if (pathname === "/api/kawazu") {
78
+ const data = await getKawazuForecast();
79
+ json(res, data);
80
+ return true;
81
+ }
82
+ // GET /api/koyo/forecast
83
+ if (pathname === "/api/koyo/forecast") {
84
+ const data = await getKoyoForecast();
85
+ json(res, data);
86
+ return true;
87
+ }
88
+ // GET /api/koyo/spots?pref=Kyoto
89
+ if (pathname === "/api/koyo/spots") {
90
+ const pref = params.get("pref");
91
+ if (!pref) {
92
+ error(res, "Missing ?pref= parameter");
93
+ return true;
94
+ }
95
+ const prefCode = findPrefCode(pref);
96
+ if (!prefCode) {
97
+ error(res, `Prefecture "${pref}" not found`);
98
+ return true;
99
+ }
100
+ const spots = await getKoyoSpots(prefCode);
101
+ json(res, spots);
102
+ return true;
103
+ }
104
+ // GET /api/fruit/farms — serve cached Navitime farm data
105
+ if (pathname === "/api/fruit/farms") {
106
+ try {
107
+ const farmsPath = resolve(process.cwd(), "public/fruit-farms.json");
108
+ const raw = readFileSync(farmsPath, "utf-8");
109
+ const data = JSON.parse(raw);
110
+ json(res, data);
111
+ }
112
+ catch {
113
+ json(res, { spots: [], scraped_at: null, total: 0, error: "Farm data not yet available. Run scrape-fruit-farms.py to populate." });
114
+ }
115
+ return true;
116
+ }
117
+ // GET /api/flowers — serve curated seasonal flower spots (wisteria, hydrangea, etc.)
118
+ if (pathname === "/api/flowers") {
119
+ try {
120
+ const flowersPath = resolve(process.cwd(), "public/flowers.json");
121
+ const raw = readFileSync(flowersPath, "utf-8");
122
+ const data = JSON.parse(raw);
123
+ json(res, data);
124
+ }
125
+ catch {
126
+ json(res, { spots: [], total: 0, error: "Flowers data not available." });
127
+ }
128
+ return true;
129
+ }
130
+ // GET /api/weather?city=Tokyo
131
+ if (pathname === "/api/weather") {
132
+ const city = params.get("city");
133
+ if (!city) {
134
+ error(res, "Missing ?city= parameter");
135
+ return true;
136
+ }
137
+ const data = await getWeatherForecast(city);
138
+ json(res, data);
139
+ return true;
140
+ }
141
+ return false; // not an API route
142
+ }
143
+ catch (e) {
144
+ error(res, e.message, 500);
145
+ return true;
146
+ }
147
+ }
148
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};