mcp-google-map 0.9.0 → 0.13.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 +7 -3
- package/dist/{chunk-OAML6T2D.js → chunk-VCFXCLJF.js} +4 -4
- package/dist/chunk-VCFXCLJF.js.map +1 -0
- package/dist/cli.d.ts +11 -2
- package/dist/cli.js +399 -194
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/resources/skills/README.md +8 -3
- package/src/resources/skills/eatspot-discovery/DEBUG.md +71 -0
- package/src/resources/skills/eatspot-discovery/SKILL.md +6 -64
- package/src/resources/skills/manifest.json +3 -2
- package/dist/chunk-OAML6T2D.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# mcp-google-map (0.
|
|
1
|
+
# mcp-google-map (0.13.0)
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
4
|
<img src="https://img.shields.io/badge/node-%3E%3D22-339933?style=flat-square&logo=nodedotjs&logoColor=white" alt="Node.js >= 22">
|
|
@@ -164,7 +164,9 @@ mcp-google-map doctor --live --probes geocoding,routes # probe only the selecte
|
|
|
164
164
|
mcp-google-map exec geocode '{"address":"Tokyo Tower"}' # one tool call from the terminal
|
|
165
165
|
mcp-google-map batch-geocode -i addresses.txt -o results.json
|
|
166
166
|
mcp-google-map enable pi claude # enable MCP registration + skills for specific CLIs
|
|
167
|
+
mcp-google-map api-key "AIza..." # save the API key in the user settings and refresh every enabled CLI registration
|
|
167
168
|
mcp-google-map install # register the stdio server and install skills in every enabled CLI
|
|
169
|
+
mcp-google-map install --debug-skills # also append each skill's packaged debug overlay to the installed SKILL.md
|
|
168
170
|
mcp-google-map uninstall # reciprocal removal of install in every enabled CLI
|
|
169
171
|
mcp-google-map show # CLI Configuration and Installation Status tables
|
|
170
172
|
mcp-google-map --env-file /path/to/.env doctor # load an explicit environment file
|
|
@@ -178,9 +180,11 @@ mcp-google-map snippet --client cursor # print an MCP client re
|
|
|
178
180
|
- `snippet` prints a valid `mcpServers` JSON registration to stdout (guidance notes on stderr) and never writes or edits configuration files; by default it embeds a literal placeholder, and `--env-key NAME` emits a `${NAME}` reference whose expansion is client-specific.
|
|
179
181
|
- `--env-file <path>` loads exactly the given environment file for any command and exits 1 with a JSON error when the file is missing (no implicit `.env` fallback).
|
|
180
182
|
- `enable <cli>` / `disable <cli>` manage the persisted enabled-CLI set at `~/.config/mcp-google-map/config.json`; accepted names (case-insensitive): `pi`, `openclaw`, `codex`, `antigravity`, `claude`; unsupported names exit 2 listing the supported ones.
|
|
181
|
-
- `
|
|
183
|
+
- `api-key <key>` validates the key (20-50 characters of letters, digits, hyphens, underscores), saves it as `apiKey` in the persisted settings at `~/.config/mcp-google-map/config.json` (masked in the JSON output), and immediately re-runs `install` for every enabled CLI; invalid keys fail with a JSON error and persist nothing.
|
|
184
|
+
- `install` registers for every enabled CLI the stdio server entry `mcp-google-map` (`npx -y mcp-google-map start --stdio`) and installs every bundled skill; the embedded `GOOGLE_MAPS_API_KEY` is resolved with priority `--apikey`, the persisted `api-key` settings, then the `GOOGLE_MAPS_API_KEY` environment — when none resolves, a literal placeholder that names the `api-key` command is embedded instead; `uninstall` is the reciprocal removal. Per-CLI targets: pi `~/.pi/agent/mcp.json` + `~/.pi/agent/skills`, openclaw `~/.openclaw/openclaw.json` + `~/.openclaw/workspace/skills`, codex `~/.codex/config.toml` (`mcp_servers` table) + `~/.codex/skills`, antigravity `~/.gemini/settings.json` + `~/.gemini/config/skills`, claude `~/.claude.json` + `~/.claude/skills`. Existing unrelated configuration entries are always preserved.
|
|
185
|
+
- `install --debug-skills` appends each skill's packaged debug overlay (declared by the manifest `debug` field, e.g. `eatspot-discovery/DEBUG.md`) to the installed `SKILL.md`; without the flag the debug file is neither copied nor appended, so installed skills carry no debug instructions. `--upgrade` and `api-key` always reinstall without the overlay, and `show` reports `OK` for skills installed in either mode.
|
|
182
186
|
- `show` prints two human-readable tables: CLI Configuration (CLI, Enabled, MCP Config Path, Skills Config Path for all five CLIs) and Installation Status (Type, Name, CLI, Enabled, Installed with OK/MISSING/STALE per enabled CLI).
|
|
183
|
-
- HTTP mode starts even without an API key and logs a warning; stdio mode and the CLI commands require a key (`--apikey` or `GOOGLE_MAPS_API_KEY`). When no HTTP instance can start (invalid or taken port), the process exits non-zero.
|
|
187
|
+
- HTTP mode starts even without an API key and logs a warning (per-request header keys remain supported); stdio mode resolves the effective key with priority `--apikey`, `GOOGLE_MAPS_API_KEY`, then the persisted `api-key` settings, and exits 1 with a JSON error on stderr inviting `mcp-google-map api-key <key>` when no key resolves; the CLI commands require a key (`--apikey` or `GOOGLE_MAPS_API_KEY`). When no HTTP instance can start (invalid or taken port), the process exits non-zero.
|
|
184
188
|
|
|
185
189
|
## Registering in an MCP client
|
|
186
190
|
|
|
@@ -94,7 +94,7 @@ function buildRouteModifiers(params, travelMode) {
|
|
|
94
94
|
}
|
|
95
95
|
var RoutesService = class {
|
|
96
96
|
constructor(apiKey) {
|
|
97
|
-
this.apiKey = apiKey ||
|
|
97
|
+
this.apiKey = apiKey || "";
|
|
98
98
|
if (!this.apiKey) {
|
|
99
99
|
throw new Error("Google Maps API Key is required");
|
|
100
100
|
}
|
|
@@ -285,7 +285,7 @@ var GoogleMapsTools = class {
|
|
|
285
285
|
constructor(apiKey) {
|
|
286
286
|
this.defaultLanguage = Language.en;
|
|
287
287
|
this.client = new Client({});
|
|
288
|
-
this.apiKey = apiKey ||
|
|
288
|
+
this.apiKey = apiKey || "";
|
|
289
289
|
if (!this.apiKey) {
|
|
290
290
|
throw new Error("Google Maps API Key is required");
|
|
291
291
|
}
|
|
@@ -771,7 +771,7 @@ var NewPlacesService = class {
|
|
|
771
771
|
"places.currentOpeningHours.weekdayDescriptions",
|
|
772
772
|
"nextPageToken"
|
|
773
773
|
].join(",");
|
|
774
|
-
this.apiKey = apiKey ||
|
|
774
|
+
this.apiKey = apiKey || "";
|
|
775
775
|
this.client = new PlacesClient({ apiKey: this.apiKey });
|
|
776
776
|
if (!this.apiKey) {
|
|
777
777
|
throw new Error("Google Maps API Key is required");
|
|
@@ -1857,4 +1857,4 @@ export {
|
|
|
1857
1857
|
PlacesSearcher,
|
|
1858
1858
|
Logger
|
|
1859
1859
|
};
|
|
1860
|
-
//# sourceMappingURL=chunk-
|
|
1860
|
+
//# sourceMappingURL=chunk-VCFXCLJF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/services/toolclass.ts","../src/services/RoutesService.ts","../src/services/NewPlacesService.ts","../src/services/PlacesSearcher.ts","../src/index.ts"],"sourcesContent":["import { Client, Language } from \"@googlemaps/google-maps-services-js\";\nimport dotenv from \"dotenv\";\nimport { Logger } from \"../index.js\";\nimport { RoutesService } from \"./RoutesService.js\";\n\ndotenv.config();\n\ninterface GeocodeResult {\n lat: number;\n lng: number;\n formatted_address?: string;\n place_id?: string;\n}\n\n/**\n * Extracts a meaningful, actionable error message from Google Maps API errors.\n */\nfunction extractErrorMessage(error: any): string {\n const statusCode = error?.response?.status;\n const apiError = error?.response?.data?.error_message;\n const apiStatus = error?.response?.data?.status;\n\n // Map common HTTP status codes to actionable messages\n if (statusCode === 403) {\n return \"API key invalid or required API not enabled. Check: console.cloud.google.com → APIs & Services → Enable the relevant API (Places, Geocoding, etc.)\";\n }\n if (statusCode === 429) {\n return \"API quota exceeded. Wait and retry, or check quota at console.cloud.google.com → Quotas\";\n }\n\n // Map Google Maps API status codes\n if (apiStatus === \"ZERO_RESULTS\") {\n return \"No results found. Try broader search terms or a larger radius.\";\n }\n if (apiStatus === \"OVER_QUERY_LIMIT\") {\n return \"API quota exceeded. Wait and retry, or upgrade your billing plan.\";\n }\n if (apiStatus === \"REQUEST_DENIED\") {\n return `Request denied by Google Maps API. ${apiError || \"Check your API key and enabled APIs.\"}`;\n }\n if (apiStatus === \"INVALID_REQUEST\") {\n return `Invalid request parameters. ${apiError || \"Check your input values.\"}`;\n }\n\n if (apiError) {\n return `${apiError} (HTTP ${statusCode})`;\n }\n\n return error instanceof Error ? error.message : String(error);\n}\n\nexport class GoogleMapsTools {\n private client: Client;\n private readonly defaultLanguage: Language = Language.en;\n private apiKey: string;\n\n constructor(apiKey?: string) {\n this.client = new Client({});\n // Only the explicitly provided key is accepted; empty aborts below (REQ-019).\n this.apiKey = apiKey || \"\";\n if (!this.apiKey) {\n throw new Error(\"Google Maps API Key is required\");\n }\n }\n\n private async geocodeAddress(address: string): Promise<GeocodeResult> {\n try {\n const response = await this.client.geocode({\n params: {\n address: address,\n key: this.apiKey,\n language: this.defaultLanguage,\n },\n });\n\n if (response.data.results.length === 0) {\n throw new Error(`No location found for address: \"${address}\"`);\n }\n\n const result = response.data.results[0];\n const location = result.geometry.location;\n return {\n lat: location.lat,\n lng: location.lng,\n formatted_address: result.formatted_address,\n place_id: result.place_id,\n };\n } catch (error: any) {\n Logger.error(\"Error in geocodeAddress:\", error);\n throw new Error(`Failed to geocode address \"${address}\": ${extractErrorMessage(error)}`);\n }\n }\n\n private parseCoordinates(coordString: string): GeocodeResult {\n const coords = coordString.split(\",\").map((c) => parseFloat(c.trim()));\n if (coords.length !== 2 || isNaN(coords[0]) || isNaN(coords[1])) {\n throw new Error(\n `Invalid coordinate format: \"${coordString}\". Please use \"latitude,longitude\" format (e.g., \"25.033,121.564\"`\n );\n }\n return { lat: coords[0], lng: coords[1] };\n }\n\n async getLocation(center: { value: string; isCoordinates: boolean }): Promise<GeocodeResult> {\n if (center.isCoordinates) {\n return this.parseCoordinates(center.value);\n }\n return this.geocodeAddress(center.value);\n }\n\n async geocode(address: string): Promise<{\n location: { lat: number; lng: number };\n formatted_address: string;\n place_id: string;\n }> {\n try {\n const result = await this.geocodeAddress(address);\n return {\n location: { lat: result.lat, lng: result.lng },\n formatted_address: result.formatted_address || \"\",\n place_id: result.place_id || \"\",\n };\n } catch (error: any) {\n Logger.error(\"Error in geocode:\", error);\n throw new Error(`Failed to geocode address \"${address}\": ${extractErrorMessage(error)}`);\n }\n }\n\n async reverseGeocode(\n latitude: number,\n longitude: number\n ): Promise<{\n formatted_address: string;\n place_id: string;\n address_components: any[];\n }> {\n try {\n const response = await this.client.reverseGeocode({\n params: {\n latlng: { lat: latitude, lng: longitude },\n language: this.defaultLanguage,\n key: this.apiKey,\n },\n });\n\n if (response.data.results.length === 0) {\n throw new Error(`No address found for coordinates: (${latitude}, ${longitude})`);\n }\n\n const result = response.data.results[0];\n return {\n formatted_address: result.formatted_address,\n place_id: result.place_id,\n address_components: result.address_components,\n };\n } catch (error: any) {\n Logger.error(\"Error in reverseGeocode:\", error);\n throw new Error(\n `Failed to reverse geocode coordinates (${latitude}, ${longitude}): ${extractErrorMessage(error)}`\n );\n }\n }\n\n async searchAlongRoute(params: {\n textQuery: string;\n origin: string;\n destination: string;\n mode?: string;\n maxResults?: number;\n }): Promise<{ places: any[]; route: { distance: string; duration: string; polyline: string } }> {\n try {\n // Step 1: Get directions via Routes API to obtain the encoded polyline\n const routesService = new RoutesService(this.apiKey);\n const directions = await routesService.computeRoutes({\n origin: params.origin,\n destination: params.destination,\n mode: params.mode || \"walking\",\n });\n\n const polyline = directions.routes[0]?.polyline?.encodedPolyline;\n if (!polyline) {\n throw new Error(\"Could not get route polyline\");\n }\n\n // Step 2: Call Places searchText REST API with searchAlongRouteParameters\n const maxResults = Math.min(params.maxResults || 5, 20);\n const fieldMask =\n \"places.displayName,places.id,places.formattedAddress,places.location,places.rating,places.userRatingCount,places.currentOpeningHours.openNow\";\n\n const response = await fetch(\"https://places.googleapis.com/v1/places:searchText\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Goog-Api-Key\": this.apiKey,\n \"X-Goog-FieldMask\": fieldMask,\n },\n body: JSON.stringify({\n textQuery: params.textQuery,\n searchAlongRouteParameters: {\n polyline: {\n encodedPolyline: polyline,\n },\n },\n maxResultCount: maxResults,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData?.error?.message || `HTTP ${response.status}`);\n }\n\n const data = await response.json();\n const places = (data.places || []).map((place: any) => ({\n name: place.displayName?.text || \"\",\n place_id: place.id || \"\",\n formatted_address: place.formattedAddress || \"\",\n location: {\n lat: place.location?.latitude || 0,\n lng: place.location?.longitude || 0,\n },\n rating: place.rating || 0,\n user_ratings_total: place.userRatingCount || 0,\n open_now: place.currentOpeningHours?.openNow ?? null,\n }));\n\n return {\n places,\n route: {\n distance: directions.total_distance.text,\n duration: directions.total_duration.text,\n polyline,\n },\n };\n } catch (error: any) {\n Logger.error(\"Error in searchAlongRoute:\", error);\n throw new Error(error.message || \"Failed to search along route\");\n }\n }\n\n async getWeather(\n latitude: number,\n longitude: number,\n type: \"current\" | \"forecast_daily\" | \"forecast_hourly\" = \"current\",\n forecastDays?: number,\n forecastHours?: number\n ): Promise<any> {\n try {\n const baseParams = `key=${this.apiKey}&location.latitude=${latitude}&location.longitude=${longitude}`;\n let url: string;\n\n switch (type) {\n case \"forecast_daily\": {\n const days = Math.min(Math.max(forecastDays || 5, 1), 10);\n url = `https://weather.googleapis.com/v1/forecast/days:lookup?${baseParams}&days=${days}`;\n break;\n }\n case \"forecast_hourly\": {\n const hours = Math.min(Math.max(forecastHours || 24, 1), 240);\n url = `https://weather.googleapis.com/v1/forecast/hours:lookup?${baseParams}&hours=${hours}`;\n break;\n }\n default:\n url = `https://weather.googleapis.com/v1/currentConditions:lookup?${baseParams}`;\n }\n\n const response = await fetch(url);\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n const msg = errorData?.error?.message || `HTTP ${response.status}`;\n\n if (msg.includes(\"not supported for this location\")) {\n throw new Error(\n `Weather data is not available for this location (${latitude}, ${longitude}). ` +\n \"The Google Weather API has limited coverage — China, Japan, South Korea, Cuba, Iran, North Korea, and Syria are unsupported. \" +\n \"Try a location in North America, Europe, or Oceania.\"\n );\n }\n\n throw new Error(msg);\n }\n\n const data = await response.json();\n\n if (type === \"current\") {\n return {\n temperature: data.temperature,\n feelsLike: data.feelsLikeTemperature,\n humidity: data.relativeHumidity,\n wind: data.wind,\n conditions: data.weatherCondition?.description?.text || data.weatherCondition?.type,\n uvIndex: data.uvIndex,\n precipitation: data.precipitation,\n visibility: data.visibility,\n pressure: data.airPressure,\n cloudCover: data.cloudCover,\n isDayTime: data.isDaytime,\n };\n }\n\n // forecast_daily or forecast_hourly — return as-is with light cleanup\n return data;\n } catch (error: any) {\n Logger.error(\"Error in getWeather:\", error);\n throw new Error(error.message || `Failed to get weather for (${latitude}, ${longitude})`);\n }\n }\n\n async getAirQuality(\n latitude: number,\n longitude: number,\n includeHealthRecommendations: boolean = true,\n includePollutants: boolean = false\n ): Promise<any> {\n try {\n const url = `https://airquality.googleapis.com/v1/currentConditions:lookup?key=${this.apiKey}`;\n\n const extraComputations: string[] = [];\n if (includeHealthRecommendations) {\n extraComputations.push(\"HEALTH_RECOMMENDATIONS\");\n }\n if (includePollutants) {\n extraComputations.push(\"POLLUTANT_CONCENTRATION\");\n }\n\n const body: any = {\n location: { latitude, longitude },\n };\n if (extraComputations.length > 0) {\n body.extraComputations = extraComputations;\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n const msg = errorData?.error?.message || `HTTP ${response.status}`;\n throw new Error(msg);\n }\n\n const data = await response.json();\n\n // Extract the primary index\n const indexes = data.indexes || [];\n const primaryIndex = indexes[0];\n\n const result: any = {\n dateTime: data.dateTime,\n regionCode: data.regionCode,\n aqi: primaryIndex?.aqi,\n category: primaryIndex?.category,\n dominantPollutant: primaryIndex?.dominantPollutant,\n color: primaryIndex?.color,\n };\n\n // Include all available indexes (universal + local)\n if (indexes.length > 1) {\n result.indexes = indexes.map((idx: any) => ({\n code: idx.code,\n displayName: idx.displayName,\n aqi: idx.aqi,\n category: idx.category,\n dominantPollutant: idx.dominantPollutant,\n }));\n }\n\n // Health recommendations\n if (data.healthRecommendations) {\n result.healthRecommendations = data.healthRecommendations;\n }\n\n // Pollutants\n if (data.pollutants) {\n result.pollutants = data.pollutants.map((p: any) => ({\n code: p.code,\n displayName: p.displayName,\n concentration: p.concentration,\n additionalInfo: p.additionalInfo,\n }));\n }\n\n return result;\n } catch (error: any) {\n Logger.error(\"Error in getAirQuality:\", error);\n throw new Error(error.message || `Failed to get air quality for (${latitude}, ${longitude})`);\n }\n }\n\n async getStaticMap(params: {\n center?: string;\n zoom?: number;\n size?: string;\n maptype?: string;\n markers?: string[];\n path?: string[];\n }): Promise<{ base64: string; size: number; dimensions: string }> {\n try {\n const dimensions = params.size || \"600x400\";\n const queryParts: string[] = [\n `key=${this.apiKey}`,\n `size=${dimensions}`,\n `maptype=${params.maptype || \"roadmap\"}`,\n ];\n\n if (params.center) {\n queryParts.push(`center=${encodeURIComponent(params.center)}`);\n }\n if (params.zoom !== undefined) {\n queryParts.push(`zoom=${params.zoom}`);\n }\n if (params.markers) {\n for (const marker of params.markers) {\n queryParts.push(`markers=${encodeURIComponent(marker)}`);\n }\n }\n if (params.path) {\n for (const p of params.path) {\n queryParts.push(`path=${encodeURIComponent(p)}`);\n }\n }\n\n const url = `https://maps.googleapis.com/maps/api/staticmap?${queryParts.join(\"&\")}`;\n\n // Check URL length limit\n if (url.length > 16384) {\n throw new Error(`URL exceeds 16,384 character limit (${url.length}). Reduce markers or path points.`);\n }\n\n const response = await fetch(url);\n\n if (!response.ok) {\n const contentType = response.headers.get(\"content-type\") || \"\";\n if (contentType.includes(\"application/json\") || contentType.includes(\"text/\")) {\n const errorText = await response.text();\n throw new Error(`Static Maps API error: ${errorText}`);\n }\n throw new Error(`Static Maps API returned HTTP ${response.status}`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n const buffer = Buffer.from(arrayBuffer);\n const base64 = buffer.toString(\"base64\");\n\n return {\n base64,\n size: buffer.length,\n dimensions,\n };\n } catch (error: any) {\n Logger.error(\"Error in getStaticMap:\", error);\n throw new Error(error.message || \"Failed to generate static map\");\n }\n }\n\n async getTimezone(\n latitude: number,\n longitude: number,\n timestamp?: number\n ): Promise<{ timeZoneId: string; timeZoneName: string; utcOffset: number; dstOffset: number; localTime: string }> {\n try {\n const ts = timestamp ? Math.floor(timestamp / 1000) : Math.floor(Date.now() / 1000);\n\n const response = await this.client.timezone({\n params: {\n location: { lat: latitude, lng: longitude },\n timestamp: ts,\n key: this.apiKey,\n },\n });\n\n const result = response.data;\n\n if (result.status !== \"OK\") {\n throw new Error(`Timezone API returned status: ${result.status}`);\n }\n\n const totalOffset = (result.rawOffset + result.dstOffset) * 1000;\n const localTime = new Date(ts * 1000 + totalOffset).toISOString().replace(\"Z\", \"\");\n\n return {\n timeZoneId: result.timeZoneId,\n timeZoneName: result.timeZoneName,\n utcOffset: result.rawOffset,\n dstOffset: result.dstOffset,\n localTime,\n };\n } catch (error: any) {\n Logger.error(\"Error in getTimezone:\", error);\n throw new Error(`Failed to get timezone for (${latitude}, ${longitude}): ${extractErrorMessage(error)}`);\n }\n }\n\n async getElevation(\n locations: Array<{ latitude: number; longitude: number }>\n ): Promise<Array<{ elevation: number; location: { lat: number; lng: number } }>> {\n try {\n const formattedLocations = locations.map((loc) => ({\n lat: loc.latitude,\n lng: loc.longitude,\n }));\n\n const response = await this.client.elevation({\n params: {\n locations: formattedLocations,\n key: this.apiKey,\n },\n });\n\n const result = response.data;\n\n if (result.status !== \"OK\") {\n throw new Error(`Failed to get elevation data with status: ${result.status}`);\n }\n\n return result.results.map((item: any, index: number) => ({\n elevation: item.elevation,\n location: formattedLocations[index],\n }));\n } catch (error: any) {\n Logger.error(\"Error in getElevation:\", error);\n throw new Error(\n `Failed to get elevation data for ${locations.length} location(s): ${extractErrorMessage(error)}`\n );\n }\n }\n}\n","import { Logger } from \"../index.js\";\n\nconst ROUTES_API_BASE = \"https://routes.googleapis.com\";\n\n/** Travel mode mapping: legacy lowercase → Routes API uppercase */\nconst TRAVEL_MODE_MAP: Record<string, string> = {\n driving: \"DRIVE\",\n walking: \"WALK\",\n bicycling: \"BICYCLE\",\n transit: \"TRANSIT\",\n};\n\n/** FieldMask for computeRoutes */\nconst COMPUTE_ROUTES_FIELD_MASK = [\n \"routes.distanceMeters\",\n \"routes.duration\",\n \"routes.description\",\n \"routes.polyline.encodedPolyline\",\n \"routes.legs.distanceMeters\",\n \"routes.legs.duration\",\n \"routes.legs.startLocation\",\n \"routes.legs.endLocation\",\n \"routes.legs.steps.navigationInstruction\",\n \"routes.legs.steps.distanceMeters\",\n \"routes.legs.steps.staticDuration\",\n \"routes.legs.steps.startLocation\",\n \"routes.legs.steps.endLocation\",\n \"routes.legs.steps.transitDetails\",\n \"routes.legs.polyline\",\n \"routes.optimizedIntermediateWaypointIndex\",\n].join(\",\");\n\n/** FieldMask for computeRouteMatrix */\nconst COMPUTE_ROUTE_MATRIX_FIELD_MASK = \"originIndex,destinationIndex,distanceMeters,duration,status,condition\";\n\n/**\n * Parse Routes API duration string (\"1234s\") to seconds.\n */\nexport function parseDuration(duration: string | undefined): number {\n if (!duration) return 0;\n const match = duration.match(/^(\\d+)s$/);\n return match ? parseInt(match[1], 10) : 0;\n}\n\n/**\n * Format meters to human-readable distance.\n */\nexport function formatDistance(meters: number): string {\n if (meters >= 1000) {\n return `${(meters / 1000).toFixed(1)} km`;\n }\n return `${meters} m`;\n}\n\n/**\n * Format seconds to human-readable duration.\n */\nexport function formatDuration(seconds: number): string {\n if (seconds >= 3600) {\n const hours = Math.floor(seconds / 3600);\n const mins = Math.round((seconds % 3600) / 60);\n return mins > 0\n ? `${hours} hour${hours > 1 ? \"s\" : \"\"} ${mins} min${mins > 1 ? \"s\" : \"\"}`\n : `${hours} hour${hours > 1 ? \"s\" : \"\"}`;\n }\n const mins = Math.round(seconds / 60);\n return `${mins} min${mins !== 1 ? \"s\" : \"\"}`;\n}\n\nexport const COORDINATE_STRING_PATTERN = /^\\s*(-?\\d+\\.?\\d*)\\s*,\\s*(-?\\d+\\.?\\d*)\\s*$/;\n\nexport type RouteWaypoint = { latLng: { latitude: number; longitude: number } } | { placeId: string };\nexport type WaypointInput = string | RouteWaypoint;\n\n/**\n * Format a waypoint for human-readable error messages.\n */\nfunction describeWaypoint(waypoint: WaypointInput): string {\n if (typeof waypoint === \"string\") {\n return waypoint;\n }\n if (\"placeId\" in waypoint) {\n return `placeId:${waypoint.placeId}`;\n }\n return `${waypoint.latLng.latitude},${waypoint.latLng.longitude}`;\n}\n\n/**\n * Convert address/coordinates string or structured waypoint to Routes API Waypoint.\n *\n * NOTE: must stay synchronous and take exactly one argument. computeRoutes below\n * calls params.intermediates.map(toWaypoint), so a second parameter would silently\n * bind the array index, and returning a promise would serialise as {}.\n */\nfunction toWaypoint(location: WaypointInput): any {\n if (typeof location !== \"string\") {\n return \"placeId\" in location ? { placeId: location.placeId } : { location: { latLng: location.latLng } };\n }\n const coordMatch = location.match(COORDINATE_STRING_PATTERN);\n if (coordMatch) {\n return {\n location: {\n latLng: {\n latitude: parseFloat(coordMatch[1]),\n longitude: parseFloat(coordMatch[2]),\n },\n },\n };\n }\n return { address: location };\n}\n\nfunction buildRouteModifiers(params: { avoidTolls?: boolean; avoidHighways?: boolean }, travelMode: string): any {\n const routeModifiers: Record<string, boolean> = {};\n\n if (params.avoidTolls) {\n routeModifiers.avoidTolls = true;\n }\n if (params.avoidHighways) {\n routeModifiers.avoidHighways = true;\n }\n\n if (Object.keys(routeModifiers).length === 0) {\n return undefined;\n }\n\n if (travelMode !== \"DRIVE\") {\n throw new Error('Route modifiers \"avoid_tolls\" and \"avoid_highways\" are only supported with mode \"driving\".');\n }\n\n return routeModifiers;\n}\n\n/**\n * Routes API REST client.\n *\n * Uses native fetch() to call Google Routes API endpoints.\n * Follows the same pattern as getWeather/getAirQuality/searchAlongRoute.\n */\nexport class RoutesService {\n private apiKey: string;\n\n constructor(apiKey?: string) {\n // Only the explicitly provided key is accepted; empty aborts below (REQ-019).\n this.apiKey = apiKey || \"\";\n if (!this.apiKey) {\n throw new Error(\"Google Maps API Key is required\");\n }\n }\n\n /**\n * Compute routes using Routes API.\n * Returns response compatible with existing DirectionsResponse.data interface.\n */\n async computeRoutes(params: {\n origin: WaypointInput;\n destination: WaypointInput;\n mode?: string;\n departureTime?: Date;\n arrivalTime?: Date;\n intermediates?: WaypointInput[];\n optimizeWaypointOrder?: boolean;\n avoidTolls?: boolean;\n avoidHighways?: boolean;\n /** What to call the endpoints in error messages. Defaults to the waypoints themselves. */\n originLabel?: string;\n destinationLabel?: string;\n }): Promise<{\n routes: any[];\n summary: string;\n total_distance: { value: number; text: string };\n total_duration: { value: number; text: string };\n arrival_time: string;\n departure_time: string;\n optimizedIntermediateWaypointIndex?: number[];\n }> {\n const travelMode = TRAVEL_MODE_MAP[params.mode || \"driving\"] || \"DRIVE\";\n\n const requestBody: any = {\n origin: toWaypoint(params.origin),\n destination: toWaypoint(params.destination),\n travelMode,\n computeAlternativeRoutes: false,\n };\n\n // routingPreference only valid for DRIVE mode\n if (travelMode === \"DRIVE\") {\n requestBody.routingPreference = \"TRAFFIC_AWARE\";\n }\n\n const routeModifiers = buildRouteModifiers(params, travelMode);\n if (routeModifiers) {\n requestBody.routeModifiers = routeModifiers;\n }\n\n // Departure/arrival time (only set if explicitly provided — Routes API rejects past timestamps)\n if (params.arrivalTime) {\n requestBody.arrivalTime = params.arrivalTime.toISOString();\n } else if (params.departureTime) {\n requestBody.departureTime = params.departureTime.toISOString();\n }\n\n // Intermediates for multi-stop\n if (params.intermediates && params.intermediates.length > 0) {\n requestBody.intermediates = params.intermediates.map(toWaypoint);\n }\n\n // Waypoint optimization (not supported for TRANSIT, requires at least 2 intermediates)\n if (\n params.optimizeWaypointOrder &&\n params.intermediates &&\n params.intermediates.length > 1 &&\n travelMode !== \"TRANSIT\"\n ) {\n requestBody.optimizeWaypointOrder = true;\n }\n\n const response = await fetch(`${ROUTES_API_BASE}/directions/v2:computeRoutes`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Goog-Api-Key\": this.apiKey,\n \"X-Goog-FieldMask\": COMPUTE_ROUTES_FIELD_MASK,\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n const msg = errorData?.error?.message || `HTTP ${response.status}`;\n throw new Error(msg);\n }\n\n const data = await response.json();\n\n if (!data.routes || data.routes.length === 0) {\n const mode = params.mode || \"driving\";\n if (mode === \"transit\") {\n throw new Error(\n `No transit route found from \"${params.originLabel ?? describeWaypoint(params.origin)}\" ` +\n `to \"${params.destinationLabel ?? describeWaypoint(params.destination)}\". ` +\n `The Google Routes API does not support transit directions in some regions (notably Japan and India). ` +\n `Try using mode \"driving\" or \"walking\" instead, or use a regional transit service for public transportation details.`\n );\n }\n throw new Error(\n `No route found from \"${params.originLabel ?? describeWaypoint(params.origin)}\" ` +\n `to \"${params.destinationLabel ?? describeWaypoint(params.destination)}\" with mode: ${mode}`\n );\n }\n\n const route = data.routes[0];\n const totalDistanceMeters = route.distanceMeters || 0;\n const totalDurationSeconds = parseDuration(route.duration);\n\n return {\n routes: data.routes,\n summary: route.description || \"\",\n total_distance: {\n value: totalDistanceMeters,\n text: formatDistance(totalDistanceMeters),\n },\n total_duration: {\n value: totalDurationSeconds,\n text: formatDuration(totalDurationSeconds),\n },\n arrival_time: \"\",\n departure_time: \"\",\n ...(route.optimizedIntermediateWaypointIndex\n ? { optimizedIntermediateWaypointIndex: route.optimizedIntermediateWaypointIndex }\n : {}),\n };\n }\n\n /**\n * Compute route matrix using Routes API.\n * Returns response compatible with existing DistanceMatrixResponse.data interface.\n */\n async computeRouteMatrix(params: {\n origins: string[];\n destinations: string[];\n mode?: string;\n departureTime?: Date;\n avoidTolls?: boolean;\n avoidHighways?: boolean;\n }): Promise<{\n distances: any[][];\n durations: any[][];\n origin_addresses: string[];\n destination_addresses: string[];\n warning?: string;\n }> {\n const travelMode = TRAVEL_MODE_MAP[params.mode || \"driving\"] || \"DRIVE\";\n\n const requestBody: any = {\n origins: params.origins.map((o) => ({ waypoint: toWaypoint(o) })),\n destinations: params.destinations.map((d) => ({ waypoint: toWaypoint(d) })),\n travelMode,\n };\n\n // routingPreference only valid for DRIVE mode\n if (travelMode === \"DRIVE\") {\n requestBody.routingPreference = \"TRAFFIC_AWARE\";\n }\n\n const routeModifiers = buildRouteModifiers(params, travelMode);\n if (routeModifiers) {\n requestBody.routeModifiers = routeModifiers;\n }\n\n if (params.departureTime) {\n requestBody.departureTime = params.departureTime.toISOString();\n }\n\n const response = await fetch(`${ROUTES_API_BASE}/distanceMatrix/v2:computeRouteMatrix`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Goog-Api-Key\": this.apiKey,\n \"X-Goog-FieldMask\": COMPUTE_ROUTE_MATRIX_FIELD_MASK,\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n const msg = errorData?.error?.message || `HTTP ${response.status}`;\n throw new Error(msg);\n }\n\n const elements: any[] = await response.json();\n\n // Rebuild 2D matrix from flat array\n const rowCount = params.origins.length;\n const colCount = params.destinations.length;\n const distances: any[][] = Array.from({ length: rowCount }, () => Array(colCount).fill(null));\n const durations: any[][] = Array.from({ length: rowCount }, () => Array(colCount).fill(null));\n\n let routeNotFoundCount = 0;\n for (const element of elements) {\n const i = element.originIndex;\n const j = element.destinationIndex;\n if (i === undefined || j === undefined) continue;\n if (element.condition === \"ROUTE_NOT_FOUND\") {\n routeNotFoundCount++;\n continue;\n }\n\n const distMeters = element.distanceMeters || 0;\n const durSeconds = parseDuration(element.duration);\n\n distances[i][j] = {\n value: distMeters,\n text: formatDistance(distMeters),\n };\n durations[i][j] = {\n value: durSeconds,\n text: formatDuration(durSeconds),\n };\n }\n\n const totalPairs = rowCount * colCount;\n\n // All pairs failed — likely a regional transit limitation\n if (routeNotFoundCount === totalPairs && travelMode === \"TRANSIT\") {\n throw new Error(\n `No transit routes found for any origin/destination pair. ` +\n `The Google Routes API does not support transit directions in some regions (notably Japan and India). ` +\n `Try using mode \"driving\" or \"walking\" instead, or use a regional transit service for public transportation details.`\n );\n }\n\n // Routes API doesn't return resolved addresses; use input strings\n return {\n distances,\n durations,\n origin_addresses: params.origins,\n destination_addresses: params.destinations,\n ...(routeNotFoundCount > 0 && travelMode === \"TRANSIT\"\n ? {\n warning: `${routeNotFoundCount} of ${totalPairs} origin/destination pairs returned no transit route. The Google Routes API has limited transit coverage in some regions.`,\n }\n : {}),\n };\n }\n}\n","import { PlacesClient } from \"@googlemaps/places\";\nimport { Logger } from \"../index.js\";\n\nexport class NewPlacesService {\n private client: PlacesClient;\n private readonly apiKey: string;\n private readonly defaultLanguage: string = \"en\";\n private readonly placeFieldMask: string = [\n \"displayName\",\n \"name\",\n \"id\",\n \"formattedAddress\",\n \"location\",\n \"utcOffsetMinutes\",\n \"primaryType\",\n \"types\",\n \"regularOpeningHours.periods\",\n \"regularOpeningHours.weekdayDescriptions\",\n \"currentOpeningHours.openNow\",\n \"currentOpeningHours.periods\",\n \"currentOpeningHours.weekdayDescriptions\",\n \"nationalPhoneNumber\",\n \"websiteUri\",\n \"priceLevel\",\n \"rating\",\n \"userRatingCount\",\n \"editorialSummary\",\n \"reviews.rating\",\n \"reviews.text\",\n \"reviews.publishTime\",\n \"reviews.authorAttribution.displayName\",\n \"reviews.authorAttribution.uri\",\n \"reviews.authorAttribution.photoUri\",\n \"reviews.googleMapsUri\",\n \"reviews.flagContentUri\",\n \"reviews.relativePublishTimeDescription\",\n \"photos.heightPx\",\n \"photos.widthPx\",\n \"photos.name\",\n \"photos.authorAttributions\",\n \"photos.googleMapsUri\",\n \"photos.flagContentUri\",\n \"googleMapsUri\",\n // Parking & Accessibility\n \"parkingOptions\",\n \"accessibilityOptions\",\n // Food & Drink\n \"servesVegetarianFood\",\n \"servesBeer\",\n \"servesWine\",\n \"servesCocktails\",\n \"servesBreakfast\",\n \"servesLunch\",\n \"servesDinner\",\n \"servesBrunch\",\n \"servesCoffee\",\n \"servesDessert\",\n // Dining options\n \"dineIn\",\n \"delivery\",\n \"takeout\",\n \"curbsidePickup\",\n \"reservable\",\n // Pricing (Money structure preserved as returned by the API)\n \"priceRange\",\n \"businessStatus\",\n // Atmosphere\n \"goodForGroups\",\n \"goodForChildren\",\n \"goodForWatchingSports\",\n \"liveMusic\",\n \"outdoorSeating\",\n \"allowsDogs\",\n \"menuForChildren\",\n \"restroom\",\n // Payment\n \"paymentOptions\",\n // AI Summaries (region-limited)\n \"reviewSummary\",\n \"generativeSummary\",\n ].join(\",\");\n\n private readonly searchNearbyFieldMask: string = [\n \"places.displayName\",\n \"places.name\",\n \"places.id\",\n \"places.formattedAddress\",\n \"places.location\",\n \"places.rating\",\n \"places.userRatingCount\",\n \"places.currentOpeningHours.openNow\",\n \"places.primaryType\",\n \"places.priceLevel\",\n \"places.types\",\n \"places.businessStatus\",\n \"places.googleMapsUri\",\n \"places.priceRange\",\n ].join(\",\");\n\n /**\n * FieldMask for Text Search (New). Includes every field required for\n * budget/quality/category/opening-hours validation (price levels, price range\n * with the original Money structure, types, business status, regular and\n * current opening hours) plus nextPageToken for pagination.\n */\n private readonly searchTextFieldMask: string = [\n \"places.id\",\n \"places.displayName\",\n \"places.formattedAddress\",\n \"places.location\",\n \"places.primaryType\",\n \"places.types\",\n \"places.businessStatus\",\n \"places.googleMapsUri\",\n \"places.priceLevel\",\n \"places.priceRange\",\n \"places.rating\",\n \"places.userRatingCount\",\n \"places.regularOpeningHours.periods\",\n \"places.regularOpeningHours.weekdayDescriptions\",\n \"places.currentOpeningHours.openNow\",\n \"places.currentOpeningHours.periods\",\n \"places.currentOpeningHours.weekdayDescriptions\",\n \"nextPageToken\",\n ].join(\",\");\n constructor(apiKey?: string) {\n // Only the explicitly provided key is accepted; empty aborts below (REQ-019).\n this.apiKey = apiKey || \"\";\n this.client = new PlacesClient({ apiKey: this.apiKey });\n\n if (!this.apiKey) {\n throw new Error(\"Google Maps API Key is required\");\n }\n }\n\n async searchNearby(params: {\n location: { lat: number; lng: number };\n keyword?: string;\n radius?: number;\n maxResultCount?: number;\n }): Promise<any[]> {\n try {\n const request: any = {\n locationRestriction: {\n circle: {\n center: {\n latitude: params.location.lat,\n longitude: params.location.lng,\n },\n radius: params.radius || 1000,\n },\n },\n maxResultCount: Math.min(params.maxResultCount || 20, 20),\n languageCode: this.defaultLanguage,\n };\n\n if (params.keyword) {\n request.includedTypes = [params.keyword];\n }\n\n const [response] = await this.client.searchNearby(request, {\n otherArgs: {\n headers: {\n \"X-Goog-FieldMask\": this.searchNearbyFieldMask,\n },\n },\n });\n\n return (response.places || []).map((place: any) => this.transformSearchResult(place));\n } catch (error: any) {\n Logger.error(\"Error in searchNearby (New API):\", error);\n throw new Error(`Failed to search nearby places: ${this.extractErrorMessage(error)}`);\n }\n }\n\n /**\n * Backward-compatible Text Search (New) returning only the transformed\n * places array.\n */\n async searchText(params: {\n textQuery: string;\n locationBias?: { lat: number; lng: number; radius?: number };\n openNow?: boolean;\n minRating?: number;\n includedType?: string;\n strictTypeFiltering?: boolean;\n priceLevels?: string[];\n pageSize?: number;\n pageToken?: string;\n languageCode?: string;\n maxResultCount?: number;\n }): Promise<any[]> {\n const result = await this.searchTextFull(params);\n return result.places;\n }\n\n /**\n * Text Search (New) with the full eatspot-discovery filter surface (REQ-027, REQ-109):\n * - priceLevels: cumulative server-side economic filter (enum strings)\n * - strictTypeFiltering: strict place-type filtering\n * - minRating, includedType, openNow: server-side filters\n * - locationBias, pageSize/pageToken: geographic bias and pagination\n * - includeRaw: attaches the original API payload (raw_place per result and\n * the full raw_response) so callers can validate against real data.\n */\n async searchTextFull(params: {\n textQuery: string;\n locationBias?: { lat: number; lng: number; radius?: number };\n openNow?: boolean;\n minRating?: number;\n includedType?: string;\n strictTypeFiltering?: boolean;\n priceLevels?: string[];\n pageSize?: number;\n pageToken?: string;\n languageCode?: string;\n maxResultCount?: number;\n includeRaw?: boolean;\n }): Promise<{\n places: any[];\n nextPageToken?: string;\n fieldMask: string;\n raw?: any;\n }> {\n try {\n const request: any = {\n textQuery: params.textQuery,\n languageCode: params.languageCode || this.defaultLanguage,\n };\n\n // NOTE ON PAGINATION: the SearchTextRequest proto shipped with\n // @googlemaps/places (verified up to v3.1.0) does not include\n // page_size/page_token, so those fields are silently dropped during\n // protobuf serialization. maxResultCount (1-20) is the effective result\n // limiter available with the official SDK; pageSize is accepted as an\n // alias and translated to maxResultCount.\n const requestedCount = params.pageSize ?? params.maxResultCount ?? 10;\n request.maxResultCount = Math.min(Math.max(1, Math.round(requestedCount)), 20);\n if (params.pageToken) {\n request.pageToken = params.pageToken; // forwarded; dropped by current SDK protos\n }\n\n if (params.locationBias) {\n request.locationBias = {\n circle: {\n center: {\n latitude: params.locationBias.lat,\n longitude: params.locationBias.lng,\n },\n radius: params.locationBias.radius || 5000,\n },\n };\n }\n\n if (params.openNow) {\n request.openNow = true;\n }\n\n if (params.minRating != null) {\n request.minRating = params.minRating;\n }\n\n if (params.includedType) {\n request.includedType = params.includedType;\n }\n\n if (params.strictTypeFiltering != null) {\n request.strictTypeFiltering = params.strictTypeFiltering;\n }\n\n if (params.priceLevels?.length) {\n request.priceLevels = params.priceLevels;\n }\n\n if (params.pageToken) {\n request.pageToken = params.pageToken;\n }\n\n const [response] = await this.client.searchText(request, {\n otherArgs: {\n headers: {\n \"X-Goog-FieldMask\": this.searchTextFieldMask,\n },\n },\n });\n\n const places = (response.places || []).map((place: any) => {\n const transformed = this.transformSearchResult(place);\n return params.includeRaw ? { ...transformed, raw_place: place } : transformed;\n });\n\n // ISearchTextResponse typings in @googlemaps/places@2.x predate Text Search\n // pagination, but the REST API does return nextPageToken when requested in\n // the field mask — read it through an any-typed view of the response.\n const paginated = response as any;\n\n return {\n places,\n ...(paginated.nextPageToken ? { nextPageToken: paginated.nextPageToken } : {}),\n fieldMask: this.searchTextFieldMask,\n ...(params.includeRaw ? { raw: response } : {}),\n };\n } catch (error: any) {\n Logger.error(\"Error in searchText (New API):\", error);\n throw new Error(`Failed to search places: ${this.extractErrorMessage(error)}`);\n }\n }\n\n async getPhotoUri(photoName: string, maxWidthPx: number = 800): Promise<string> {\n try {\n const [response] = await this.client.getPhotoMedia({\n name: `${photoName}/media`,\n maxWidthPx,\n skipHttpRedirect: true,\n });\n return response.photoUri || \"\";\n } catch (error: any) {\n Logger.error(\"Error in getPhotoUri:\", error);\n throw new Error(`Failed to get photo URI: ${this.extractErrorMessage(error)}`);\n }\n }\n\n async getPlaceDetails(placeId: string, includeRaw: boolean = false): Promise<any> {\n try {\n const placeName = `places/${placeId}`;\n\n const [place] = await this.client.getPlace(\n {\n name: placeName,\n languageCode: this.defaultLanguage,\n },\n {\n otherArgs: {\n headers: {\n \"X-Goog-FieldMask\": this.placeFieldMask,\n },\n },\n }\n );\n\n // Use only Places (New) reviews: the legacy reviews endpoint does not\n // provide the per-review Google Maps source link required for display.\n const transformed = this.transformPlaceResponse(place);\n return includeRaw ? { ...transformed, raw_place: place, field_mask: this.placeFieldMask } : transformed;\n } catch (error: any) {\n Logger.error(\"Error in getPlaceDetails (New API):\", error);\n throw new Error(`Failed to get place details for ${placeId}: ${this.extractErrorMessage(error)}`);\n }\n }\n\n private transformSearchResult(place: any) {\n return {\n name: place.displayName?.text || \"\",\n place_id: this.extractLegacyPlaceId(place),\n formatted_address: place.formattedAddress || \"\",\n geometry: {\n location: {\n lat: place.location?.latitude || 0,\n lng: place.location?.longitude || 0,\n },\n },\n primary_type: place.primaryType || null,\n types: place.types || [],\n business_status: place.businessStatus || null,\n google_maps_uri: place.googleMapsUri || null,\n price_level: place.priceLevel || null,\n // Raw Money object preserved exactly as returned by the API\n // ({ startPrice/endPrice: { currencyCode, units, nanos } })\n price_range: place.priceRange || null,\n rating: place.rating || 0,\n user_ratings_total: place.userRatingCount || 0,\n opening_hours: {\n open_now: place.currentOpeningHours?.openNow ?? null,\n },\n regular_opening_hours: place.regularOpeningHours || null,\n current_opening_hours: place.currentOpeningHours || null,\n };\n }\n\n private transformPlaceResponse(place: any) {\n // Build parking info (only include truthy values)\n const parking = place.parkingOptions\n ? Object.fromEntries(Object.entries(place.parkingOptions).filter(([, v]) => v === true))\n : undefined;\n\n // Build accessibility info (only include truthy values)\n const accessibility = place.accessibilityOptions\n ? Object.fromEntries(Object.entries(place.accessibilityOptions).filter(([, v]) => v === true))\n : undefined;\n\n // Build dining_options (only include truthy values)\n const diningOptions: Record<string, boolean> = {};\n if (place.dineIn) diningOptions.dine_in = true;\n if (place.delivery) diningOptions.delivery = true;\n if (place.takeout) diningOptions.takeout = true;\n if (place.curbsidePickup) diningOptions.curbside_pickup = true;\n if (place.reservable) diningOptions.reservable = true;\n\n // Build serves (only include truthy values)\n const serves: Record<string, boolean> = {};\n if (place.servesVegetarianFood) serves.vegetarian_food = true;\n if (place.servesBeer) serves.beer = true;\n if (place.servesWine) serves.wine = true;\n if (place.servesCocktails) serves.cocktails = true;\n if (place.servesBreakfast) serves.breakfast = true;\n if (place.servesLunch) serves.lunch = true;\n if (place.servesDinner) serves.dinner = true;\n if (place.servesBrunch) serves.brunch = true;\n if (place.servesCoffee) serves.coffee = true;\n if (place.servesDessert) serves.dessert = true;\n\n // Build atmosphere (only include truthy values)\n const atmosphere: Record<string, boolean> = {};\n if (place.goodForGroups) atmosphere.good_for_groups = true;\n if (place.goodForChildren) atmosphere.good_for_children = true;\n if (place.goodForWatchingSports) atmosphere.good_for_watching_sports = true;\n if (place.liveMusic) atmosphere.live_music = true;\n if (place.outdoorSeating) atmosphere.outdoor_seating = true;\n if (place.allowsDogs) atmosphere.allows_dogs = true;\n if (place.menuForChildren) atmosphere.menu_for_children = true;\n if (place.restroom) atmosphere.restroom = true;\n\n return {\n name: place.displayName?.text || place.name || \"\",\n place_id: this.extractLegacyPlaceId(place),\n formatted_address: place.formattedAddress || \"\",\n google_maps_uri: place.googleMapsUri || \"\",\n geometry: {\n location: {\n lat: place.location?.latitude || 0,\n lng: place.location?.longitude || 0,\n },\n },\n primary_type: place.primaryType || null,\n types: place.types || [],\n business_status: place.businessStatus || null,\n rating: place.rating || 0,\n user_ratings_total: place.userRatingCount || 0,\n // Raw Money object preserved exactly as returned by the API\n // ({ startPrice/endPrice: { currencyCode, units, nanos } })\n price_range: place.priceRange || null,\n opening_hours: place.regularOpeningHours\n ? {\n open_now: this.isCurrentlyOpen(\n place.regularOpeningHours,\n place.utcOffsetMinutes,\n place.currentOpeningHours\n ),\n weekday_text: this.formatOpeningHours(place.regularOpeningHours),\n }\n : undefined,\n current_opening_hours: place.currentOpeningHours || null,\n formatted_phone_number: place.nationalPhoneNumber || \"\",\n website: place.websiteUri || \"\",\n price_level: place.priceLevel || 0,\n editorial_summary: place.editorialSummary?.text || null,\n ...(Object.keys(parking || {}).length > 0 ? { parking } : {}),\n ...(Object.keys(accessibility || {}).length > 0 ? { accessibility } : {}),\n ...(Object.keys(diningOptions).length > 0 ? { dining_options: diningOptions } : {}),\n ...(Object.keys(serves).length > 0 ? { serves } : {}),\n ...(Object.keys(atmosphere).length > 0 ? { atmosphere } : {}),\n ...(place.paymentOptions\n ? {\n payment_options: Object.fromEntries(\n Object.entries(place.paymentOptions).filter(([k]) => !k.startsWith(\"_\"))\n ),\n }\n : {}),\n ...(place.reviewSummary?.text?.text\n ? {\n review_summary: place.reviewSummary.text.text,\n review_summary_attribution: {\n disclosure_text: place.reviewSummary.disclosureText?.text || \"\",\n flag_content_uri: place.reviewSummary.flagContentUri || \"\",\n reviews_uri: place.reviewSummary.reviewsUri || \"\",\n },\n }\n : {}),\n ...(place.generativeSummary?.overview?.text\n ? {\n generative_summary: place.generativeSummary.overview.text,\n generative_summary_attribution: {\n disclosure_text: place.generativeSummary.disclosureText?.text || \"\",\n flag_content_uri: place.generativeSummary.flagContentUri || \"\",\n },\n }\n : {}),\n reviews:\n place.reviews?.map((review: any) => ({\n rating: review.rating || 0,\n text: review.text?.text || \"\",\n language: review.text?.languageCode || null,\n time: review.publishTime?.seconds || 0,\n author_name: review.authorAttribution?.displayName || \"\",\n author_uri: review.authorAttribution?.uri || \"\",\n author_photo_uri: review.authorAttribution?.photoUri || \"\",\n google_maps_uri: review.googleMapsUri || \"\",\n flag_content_uri: review.flagContentUri || \"\",\n relative_publish_time_description: review.relativePublishTimeDescription || \"\",\n })) || [],\n photos:\n place.photos?.map((photo: any) => ({\n photo_reference: photo.name || \"\",\n height: photo.heightPx || 0,\n width: photo.widthPx || 0,\n google_maps_uri: photo.googleMapsUri || \"\",\n flag_content_uri: photo.flagContentUri || \"\",\n author_attributions:\n photo.authorAttributions?.map((author: any) => ({\n display_name: author.displayName || \"\",\n uri: author.uri || \"\",\n photo_uri: author.photoUri || \"\",\n })) || [],\n })) || [],\n };\n }\n\n private extractLegacyPlaceId(place: any): string {\n const resourceName = place?.name;\n\n if (typeof resourceName === \"string\" && resourceName.startsWith(\"places/\")) {\n const legacyId = resourceName.substring(\"places/\".length);\n if (legacyId) {\n return legacyId;\n }\n }\n\n return place?.id || \"\";\n }\n\n private isCurrentlyOpen(openingHours: any, utcOffsetMinutes?: number, currentOpeningHours?: any): boolean {\n if (typeof currentOpeningHours?.openNow === \"boolean\") {\n return currentOpeningHours.openNow;\n }\n\n if (typeof openingHours?.openNow === \"boolean\") {\n return openingHours.openNow;\n }\n\n const periods = openingHours?.periods;\n\n if (!Array.isArray(periods) || periods.length === 0) {\n return false;\n }\n\n const minutesInDay = 24 * 60;\n const minutesInWeek = minutesInDay * 7;\n\n const { day: localDay, minutes: localMinutes } = this.getLocalTimeComponents(utcOffsetMinutes);\n const localTimeValue = localDay * minutesInDay + localMinutes;\n\n const dayMapping = {\n SUNDAY: 0,\n MONDAY: 1,\n TUESDAY: 2,\n WEDNESDAY: 3,\n THURSDAY: 4,\n FRIDAY: 5,\n SATURDAY: 6,\n };\n\n const toDayNumber = (value: any): number | undefined => {\n if (typeof value === \"number\" && value >= 0 && value <= 6) {\n return value;\n }\n if (typeof value === \"string\") {\n const normalized = value.toUpperCase();\n if (normalized in dayMapping) {\n return dayMapping[normalized as keyof typeof dayMapping];\n }\n }\n return undefined;\n };\n\n const toMinutes = (time: any): number | undefined => {\n if (!time) {\n return undefined;\n }\n\n const hours = typeof time.hours === \"number\" ? time.hours : Number(time.hours ?? NaN);\n const minutes = typeof time.minutes === \"number\" ? time.minutes : Number(time.minutes ?? NaN);\n\n if (!Number.isFinite(hours) || !Number.isFinite(minutes)) {\n return undefined;\n }\n\n return hours * 60 + minutes;\n };\n\n for (const period of periods) {\n const openDay = toDayNumber(period?.openDay);\n const closeDay = toDayNumber(period?.closeDay ?? period?.openDay);\n const openMinutes = toMinutes(period?.openTime);\n const closeMinutes = toMinutes(period?.closeTime);\n\n if (openDay === undefined || openMinutes === undefined) {\n continue;\n }\n\n const start = openDay * minutesInDay + openMinutes;\n let end: number;\n\n if (closeDay === undefined || closeMinutes === undefined) {\n end = start + minutesInDay;\n } else {\n end = closeDay * minutesInDay + closeMinutes;\n }\n\n if (end <= start) {\n end += minutesInWeek;\n }\n\n let comparableLocalTime = localTimeValue;\n while (comparableLocalTime < start) {\n comparableLocalTime += minutesInWeek;\n }\n\n if (comparableLocalTime >= start && comparableLocalTime < end) {\n return true;\n }\n }\n\n return false;\n }\n\n private getLocalTimeComponents(utcOffsetMinutes?: number): { day: number; minutes: number } {\n const now = new Date();\n\n if (typeof utcOffsetMinutes === \"number\" && Number.isFinite(utcOffsetMinutes)) {\n const localTime = new Date(now.getTime() + utcOffsetMinutes * 60000);\n\n return {\n day: localTime.getUTCDay(),\n minutes: localTime.getUTCHours() * 60 + localTime.getUTCMinutes(),\n };\n }\n\n return {\n day: now.getDay(),\n minutes: now.getHours() * 60 + now.getMinutes(),\n };\n }\n\n private formatOpeningHours(openingHours: any): string[] {\n return openingHours?.weekdayDescriptions || [];\n }\n\n private extractErrorMessage(error: any): string {\n const statusCode = error?.code;\n const message = error?.message || error?.details;\n\n if (statusCode === 7 || statusCode === 403) {\n return \"API key invalid or Places API (New) not enabled. Check: console.cloud.google.com → APIs & Services → Enable 'Places API (New)'\";\n }\n if (statusCode === 8 || statusCode === 429) {\n return \"API quota exceeded. Wait and retry, or check quota at console.cloud.google.com → Quotas\";\n }\n\n return message || (error instanceof Error ? error.message : String(error));\n }\n}\n","import { GoogleMapsTools } from \"./toolclass.js\";\nimport { NewPlacesService } from \"./NewPlacesService.js\";\nimport {\n RoutesService,\n parseDuration,\n formatDistance,\n formatDuration,\n COORDINATE_STRING_PATTERN,\n type RouteWaypoint,\n} from \"./RoutesService.js\";\n\ninterface SearchResponse {\n success: boolean;\n error?: string;\n data?: any[];\n location?: any;\n nextPageToken?: string;\n fieldMask?: string;\n raw_response?: any;\n}\n\ninterface PlaceDetailsResponse {\n success: boolean;\n error?: string;\n data?: any;\n fieldMask?: string;\n}\n\ninterface GeocodeResponse {\n success: boolean;\n error?: string;\n data?: {\n location: { lat: number; lng: number };\n formatted_address: string;\n place_id: string;\n };\n}\n\ninterface ReverseGeocodeResponse {\n success: boolean;\n error?: string;\n data?: {\n formatted_address: string;\n place_id: string;\n address_components: any[];\n };\n}\n\ninterface DistanceMatrixResponse {\n success: boolean;\n error?: string;\n data?: {\n distances: any[][];\n durations: any[][];\n origin_addresses: string[];\n destination_addresses: string[];\n };\n}\n\ninterface DirectionsResponse {\n success: boolean;\n error?: string;\n data?: {\n routes: any[];\n summary: string;\n total_distance: { value: number; text: string };\n total_duration: { value: number; text: string };\n };\n}\n\ninterface TimezoneResponse {\n success: boolean;\n error?: string;\n data?: {\n timeZoneId: string;\n timeZoneName: string;\n utcOffset: number;\n dstOffset: number;\n localTime: string;\n };\n}\n\ninterface WeatherResponse {\n success: boolean;\n error?: string;\n data?: any;\n}\n\ninterface StaticMapResponse {\n success: boolean;\n error?: string;\n data?: {\n base64: string;\n size: number;\n dimensions: string;\n };\n}\n\ninterface AirQualityResponse {\n success: boolean;\n error?: string;\n data?: any;\n}\n\ninterface ElevationResponse {\n success: boolean;\n error?: string;\n data?: Array<{\n elevation: number;\n location: { lat: number; lng: number };\n }>;\n}\n\ninterface ResolvedLocation {\n originalName: string;\n address: string;\n lat: number;\n lng: number;\n placeId: string;\n}\n\n/**\n * Parse a \"latitude,longitude\" input, or null when it is not one or is out of range.\n */\nfunction parseCoordinateInput(input: string): { lat: number; lng: number } | null {\n const match = input.match(COORDINATE_STRING_PATTERN);\n if (!match) {\n return null;\n }\n const lat = parseFloat(match[1]);\n const lng = parseFloat(match[2]);\n if (!Number.isFinite(lat) || !Number.isFinite(lng)) {\n return null;\n }\n if (lat < -90 || lat > 90 || lng < -180 || lng > 180) {\n return null;\n }\n return { lat, lng };\n}\n\n/**\n * Place ID over coordinates: Routes snaps coordinates to the nearest road, which\n * may not be an entrance. Text Search can return a result without a place ID.\n */\nfunction toRouteWaypoint(loc: ResolvedLocation): RouteWaypoint {\n if (loc.placeId) {\n return { placeId: loc.placeId };\n }\n return { latLng: { latitude: loc.lat, longitude: loc.lng } };\n}\n\nexport class PlacesSearcher {\n private mapsTools: GoogleMapsTools;\n private newPlacesService: NewPlacesService;\n private routesService: RoutesService;\n\n constructor(apiKey?: string) {\n this.mapsTools = new GoogleMapsTools(apiKey);\n this.newPlacesService = new NewPlacesService(apiKey);\n this.routesService = new RoutesService(apiKey);\n }\n\n async searchNearby(params: {\n center: { value: string; isCoordinates: boolean };\n keyword?: string;\n radius?: number;\n openNow?: boolean;\n minRating?: number;\n }): Promise<SearchResponse> {\n try {\n const location = await this.mapsTools.getLocation(params.center);\n const places = await this.newPlacesService.searchNearby({\n location,\n keyword: params.keyword,\n radius: params.radius,\n });\n\n let filteredPlaces = places;\n if (params.openNow) {\n filteredPlaces = filteredPlaces.filter((p: any) => p.opening_hours?.open_now === true);\n }\n if (params.minRating) {\n filteredPlaces = filteredPlaces.filter((p: any) => (p.rating || 0) >= (params.minRating || 0));\n }\n\n return {\n location: location,\n success: true,\n data: filteredPlaces.map((place: any) => ({\n name: place.name,\n place_id: place.place_id,\n address: place.formatted_address,\n location: place.geometry.location,\n primary_type: place.primary_type || null,\n price_level: place.price_level || null,\n rating: place.rating,\n total_ratings: place.user_ratings_total,\n open_now: place.opening_hours?.open_now,\n })),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"An error occurred during search\",\n };\n }\n }\n\n async searchText(params: {\n query: string;\n locationBias?: { latitude: number; longitude: number; radius?: number };\n openNow?: boolean;\n minRating?: number;\n includedType?: string;\n strictTypeFiltering?: boolean;\n priceLevels?: string[];\n pageSize?: number;\n pageToken?: string;\n languageCode?: string;\n includeRaw?: boolean;\n }): Promise<SearchResponse> {\n try {\n const result = await this.newPlacesService.searchTextFull({\n textQuery: params.query,\n locationBias: params.locationBias\n ? {\n lat: params.locationBias.latitude,\n lng: params.locationBias.longitude,\n radius: params.locationBias.radius,\n }\n : undefined,\n openNow: params.openNow,\n minRating: params.minRating,\n includedType: params.includedType,\n strictTypeFiltering: params.strictTypeFiltering,\n priceLevels: params.priceLevels,\n pageSize: params.pageSize,\n pageToken: params.pageToken,\n languageCode: params.languageCode,\n includeRaw: params.includeRaw,\n });\n\n return {\n success: true,\n data: result.places.map((place: any) => ({\n name: place.name,\n place_id: place.place_id,\n address: place.formatted_address,\n location: place.geometry.location,\n primary_type: place.primary_type || null,\n types: place.types || [],\n business_status: place.business_status || null,\n google_maps_uri: place.google_maps_uri || null,\n price_level: place.price_level || null,\n price_range: place.price_range || null,\n rating: place.rating,\n total_ratings: place.user_ratings_total,\n open_now: place.opening_hours?.open_now,\n regular_opening_hours: place.regular_opening_hours || null,\n current_opening_hours: place.current_opening_hours || null,\n ...(place.raw_place ? { raw_place: place.raw_place } : {}),\n })),\n ...(result.nextPageToken ? { nextPageToken: result.nextPageToken } : {}),\n fieldMask: result.fieldMask,\n ...(params.includeRaw && result.raw ? { raw_response: result.raw } : {}),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"An error occurred during text search\",\n };\n }\n }\n\n async getPlaceDetails(\n placeId: string,\n maxPhotos: number = 0,\n includeRaw: boolean = false\n ): Promise<PlaceDetailsResponse> {\n try {\n const details = await this.newPlacesService.getPlaceDetails(placeId, includeRaw);\n\n // Resolve photo URLs if requested\n let photos:\n | Array<{\n url: string;\n width: number;\n height: number;\n google_maps_uri: string;\n flag_content_uri: string;\n author_attributions: Array<{ display_name: string; uri: string; photo_uri: string }>;\n }>\n | undefined;\n if (maxPhotos > 0 && details.photos?.length > 0) {\n const photosToFetch = details.photos.slice(0, maxPhotos);\n photos = [];\n for (const photo of photosToFetch) {\n try {\n const url = await this.newPlacesService.getPhotoUri(photo.photo_reference);\n photos.push({\n url,\n width: photo.width,\n height: photo.height,\n google_maps_uri: photo.google_maps_uri,\n flag_content_uri: photo.flag_content_uri,\n author_attributions: photo.author_attributions,\n });\n } catch {\n // Skip failed photos silently\n }\n }\n }\n\n return {\n success: true,\n ...(details.field_mask ? { fieldMask: details.field_mask } : {}),\n data: {\n name: details.name,\n address: details.formatted_address,\n google_maps_uri: details.google_maps_uri,\n location: details.geometry?.location,\n primary_type: details.primary_type || null,\n types: details.types || [],\n business_status: details.business_status || null,\n rating: details.rating,\n total_ratings: details.user_ratings_total,\n // Raw Money object (startPrice/endPrice: currencyCode/units/nanos)\n price_range: details.price_range || null,\n current_opening_hours: details.current_opening_hours || null,\n opening_hours: details.opening_hours,\n phone: details.formatted_phone_number,\n website: details.website,\n price_level: details.price_level,\n editorial_summary: details.editorial_summary || null,\n ...(details.parking ? { parking: details.parking } : {}),\n ...(details.accessibility ? { accessibility: details.accessibility } : {}),\n ...(details.dining_options ? { dining_options: details.dining_options } : {}),\n ...(details.serves ? { serves: details.serves } : {}),\n ...(details.atmosphere ? { atmosphere: details.atmosphere } : {}),\n ...(details.payment_options ? { payment_options: details.payment_options } : {}),\n ...(details.review_summary ? { review_summary: details.review_summary } : {}),\n ...(details.review_summary_attribution\n ? { review_summary_attribution: details.review_summary_attribution }\n : {}),\n ...(details.generative_summary ? { generative_summary: details.generative_summary } : {}),\n ...(details.generative_summary_attribution\n ? { generative_summary_attribution: details.generative_summary_attribution }\n : {}),\n photo_count: details.photos?.length || 0,\n ...(photos && photos.length > 0 ? { photos } : {}),\n ...(details.raw_place ? { raw_place: details.raw_place } : {}),\n reviews: details.reviews?.map((review: any) => ({\n rating: review.rating,\n text: review.text,\n language: review.language || null,\n time: review.time,\n author_name: review.author_name,\n author_uri: review.author_uri,\n author_photo_uri: review.author_photo_uri,\n google_maps_uri: review.google_maps_uri,\n flag_content_uri: review.flag_content_uri,\n relative_publish_time_description: review.relative_publish_time_description,\n })),\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"An error occurred while getting place details\",\n };\n }\n }\n\n async geocode(address: string): Promise<GeocodeResponse> {\n try {\n const result = await this.mapsTools.geocode(address);\n\n return {\n success: true,\n data: result,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"An error occurred while geocoding address\",\n };\n }\n }\n\n async reverseGeocode(latitude: number, longitude: number): Promise<ReverseGeocodeResponse> {\n try {\n const result = await this.mapsTools.reverseGeocode(latitude, longitude);\n\n return {\n success: true,\n data: result,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"An error occurred during reverse geocoding\",\n };\n }\n }\n\n async calculateDistanceMatrix(\n origins: string[],\n destinations: string[],\n mode: \"driving\" | \"walking\" | \"bicycling\" | \"transit\" = \"driving\",\n departure_time?: string,\n avoid_tolls?: boolean,\n avoid_highways?: boolean\n ): Promise<DistanceMatrixResponse> {\n try {\n const result = await this.routesService.computeRouteMatrix({\n origins,\n destinations,\n mode,\n ...(departure_time ? { departureTime: new Date(departure_time) } : {}),\n ...(avoid_tolls !== undefined ? { avoidTolls: avoid_tolls } : {}),\n ...(avoid_highways !== undefined ? { avoidHighways: avoid_highways } : {}),\n });\n\n return {\n success: true,\n data: result,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"An error occurred while calculating distance matrix\",\n };\n }\n }\n\n async getDirections(\n origin: string,\n destination: string,\n mode: \"driving\" | \"walking\" | \"bicycling\" | \"transit\" = \"driving\",\n departure_time?: string,\n arrival_time?: string,\n avoid_tolls?: boolean,\n avoid_highways?: boolean\n ): Promise<DirectionsResponse> {\n try {\n const departureTime = departure_time ? new Date(departure_time) : undefined;\n const arrivalTime = arrival_time ? new Date(arrival_time) : undefined;\n const result = await this.routesService.computeRoutes({\n origin,\n destination,\n mode,\n ...(departureTime ? { departureTime } : {}),\n ...(arrivalTime ? { arrivalTime } : {}),\n ...(avoid_tolls !== undefined ? { avoidTolls: avoid_tolls } : {}),\n ...(avoid_highways !== undefined ? { avoidHighways: avoid_highways } : {}),\n });\n\n return {\n success: true,\n data: result,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"An error occurred while getting directions\",\n };\n }\n }\n\n async getTimezone(latitude: number, longitude: number, timestamp?: number): Promise<TimezoneResponse> {\n try {\n const result = await this.mapsTools.getTimezone(latitude, longitude, timestamp);\n return { success: true, data: result };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"An error occurred while getting timezone\",\n };\n }\n }\n\n async getWeather(\n latitude: number,\n longitude: number,\n type: \"current\" | \"forecast_daily\" | \"forecast_hourly\" = \"current\",\n forecastDays?: number,\n forecastHours?: number\n ): Promise<WeatherResponse> {\n try {\n const result = await this.mapsTools.getWeather(latitude, longitude, type, forecastDays, forecastHours);\n return { success: true, data: result };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"An error occurred while getting weather\",\n };\n }\n }\n\n async getAirQuality(\n latitude: number,\n longitude: number,\n includeHealthRecommendations?: boolean,\n includePollutants?: boolean\n ): Promise<AirQualityResponse> {\n try {\n const result = await this.mapsTools.getAirQuality(\n latitude,\n longitude,\n includeHealthRecommendations,\n includePollutants\n );\n return { success: true, data: result };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"An error occurred while getting air quality\",\n };\n }\n }\n\n async getStaticMap(params: {\n center?: string;\n zoom?: number;\n size?: string;\n maptype?: string;\n markers?: string[];\n path?: string[];\n }): Promise<StaticMapResponse> {\n try {\n const result = await this.mapsTools.getStaticMap(params);\n return { success: true, data: result };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"An error occurred while generating static map\",\n };\n }\n }\n\n async searchAlongRoute(params: {\n textQuery: string;\n origin: string;\n destination: string;\n mode?: string;\n maxResults?: number;\n }): Promise<{ success: boolean; error?: string; data?: any }> {\n try {\n const result = await this.mapsTools.searchAlongRoute(params);\n return { success: true, data: result };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"An error occurred while searching along route\",\n };\n }\n }\n\n // --------------- Composite Tools ---------------\n\n /**\n * Resolve a location string to one concrete place, exactly once: geocoding\n * first, then Places Text Search for informal names it does not index.\n *\n * Throws rather than returning { success: false } — the plan_route and\n * explore_area actions JSON.stringify(result.data) without checking the flag,\n * so a failure object would surface as an empty success.\n */\n private async resolveLocation(input: string): Promise<ResolvedLocation> {\n if (COORDINATE_STRING_PATTERN.test(input)) {\n const coordinates = parseCoordinateInput(input);\n if (!coordinates) {\n throw new Error(`Failed to resolve location: ${input} (not a valid \"latitude,longitude\" pair)`);\n }\n // Already exact, so geocoding only supplies a display address and its failure\n // must not fail the stop. No place ID: the nearest addressable place would\n // silently move the caller's point. geocode() over reverseGeocode() because it\n // labels sparse areas better — \"Canada\" rather than a bare Plus Code.\n const displayGeocode = await this.geocode(input);\n return {\n originalName: input,\n address: displayGeocode.success && displayGeocode.data ? displayGeocode.data.formatted_address : input,\n lat: coordinates.lat,\n lng: coordinates.lng,\n placeId: \"\",\n };\n }\n\n const geo = await this.geocode(input);\n if (geo.success && geo.data) {\n return {\n originalName: input,\n address: geo.data.formatted_address,\n lat: geo.data.location.lat,\n lng: geo.data.location.lng,\n placeId: geo.data.place_id,\n };\n }\n\n // Any geocoding failure falls through, not just zero results: geocode() flattens\n // every error into { success: false } with no status code. A systemic failure\n // (bad key, exhausted quota) fails the text search too, and both errors are thrown.\n const textSearch = await this.searchText({ query: input });\n if (textSearch.success && textSearch.data && textSearch.data.length > 0) {\n const topMatch = textSearch.data[0];\n return {\n originalName: input,\n address: topMatch.address || topMatch.name,\n lat: topMatch.location.lat,\n lng: topMatch.location.lng,\n placeId: topMatch.place_id || \"\",\n };\n }\n\n throw new Error(\n `Failed to resolve location: ${input} (geocoding: ${geo.error || \"no result\"}; places text search: ${textSearch.error || \"no result\"})`\n );\n }\n\n async exploreArea(params: { location: string; types?: string[]; radius?: number; topN?: number }): Promise<any> {\n // \"tourist_attraction\" is the Places API (New) type name; a bare\n // \"attraction\" is rejected with INVALID_ARGUMENT: Unsupported types.\n const types = params.types || [\"restaurant\", \"cafe\", \"tourist_attraction\"];\n const radius = params.radius || 1000;\n const topN = params.topN || 3;\n\n // 1. Resolve location\n const resolved = await this.resolveLocation(params.location);\n const { lat, lng } = resolved;\n\n // 2. Search each type\n const categories: any[] = [];\n for (const type of types) {\n const search = await this.searchNearby({\n center: { value: `${lat},${lng}`, isCoordinates: true },\n keyword: type,\n radius,\n });\n if (!search.success || !search.data) continue;\n\n // 3. Get details for top N\n const topPlaces = search.data.slice(0, topN);\n const detailed = [];\n for (const place of topPlaces) {\n if (!place.place_id) continue;\n const details = await this.getPlaceDetails(place.place_id);\n detailed.push({\n name: place.name,\n address: place.address,\n rating: place.rating,\n total_ratings: place.total_ratings,\n open_now: place.open_now,\n phone: details.data?.phone,\n website: details.data?.website,\n });\n }\n categories.push({ type, count: search.data.length, top: detailed });\n }\n\n return {\n success: true,\n data: {\n location: { address: resolved.address, lat, lng },\n radius,\n categories,\n },\n };\n }\n\n async planRoute(params: {\n stops: string[];\n mode?: \"driving\" | \"walking\" | \"bicycling\" | \"transit\";\n optimize?: boolean;\n departure_time?: string;\n avoid_tolls?: boolean;\n avoid_highways?: boolean;\n }): Promise<any> {\n const mode = params.mode || \"driving\";\n const stops = params.stops;\n if (stops.length < 2) throw new Error(\"Need at least 2 stops\");\n\n // 1. Resolve all stops for display addresses and waypoints\n const resolvedStops: ResolvedLocation[] = [];\n for (const stop of stops) {\n resolvedStops.push(await this.resolveLocation(stop));\n }\n\n // 2. Single Routes API call handles optimization + all leg directions\n const origin = toRouteWaypoint(resolvedStops[0]);\n const destination = toRouteWaypoint(resolvedStops[resolvedStops.length - 1]);\n const intermediates = stops.length > 2 ? resolvedStops.slice(1, -1).map((s) => toRouteWaypoint(s)) : undefined;\n // Optimize if requested, > 3 stops (at least 2 intermediates), and not transit (transit doesn't support intermediates for optimization)\n const shouldOptimize = params.optimize !== false && stops.length > 3 && mode !== \"transit\";\n\n const routeResult = await this.routesService.computeRoutes({\n origin,\n destination,\n mode,\n intermediates,\n optimizeWaypointOrder: shouldOptimize,\n originLabel: stops[0],\n destinationLabel: stops[stops.length - 1],\n ...(params.departure_time ? { departureTime: new Date(params.departure_time) } : {}),\n ...(params.avoid_tolls !== undefined ? { avoidTolls: params.avoid_tolls } : {}),\n ...(params.avoid_highways !== undefined ? { avoidHighways: params.avoid_highways } : {}),\n });\n\n const route = routeResult.routes[0];\n const routeLegs = route?.legs || [];\n\n // 3. Determine ordered stops based on optimization result\n let orderedStops: typeof resolvedStops;\n if (shouldOptimize && routeResult.optimizedIntermediateWaypointIndex) {\n const optimizedOrder = routeResult.optimizedIntermediateWaypointIndex;\n const intermediateResolved = resolvedStops.slice(1, -1);\n orderedStops = [\n resolvedStops[0],\n ...optimizedOrder.map((i: number) => intermediateResolved[i]),\n resolvedStops[resolvedStops.length - 1],\n ];\n } else {\n orderedStops = resolvedStops;\n }\n\n // 4. Build legs from Routes API response\n const legs: any[] = [];\n let totalDistance = 0;\n let totalDuration = 0;\n\n for (let i = 0; i < orderedStops.length - 1; i++) {\n const leg = routeLegs[i];\n if (leg) {\n const distMeters = leg.distanceMeters || 0;\n const durSeconds = parseDuration(leg.duration);\n totalDistance += distMeters;\n totalDuration += durSeconds;\n legs.push({\n from: orderedStops[i].originalName,\n to: orderedStops[i + 1].originalName,\n distance: formatDistance(distMeters),\n duration: formatDuration(durSeconds),\n });\n } else {\n legs.push({\n from: orderedStops[i].originalName,\n to: orderedStops[i + 1].originalName,\n distance: \"unknown\",\n duration: \"unknown\",\n note: \"Directions unavailable for this segment\",\n });\n }\n }\n\n return {\n success: true,\n data: {\n mode,\n optimized: shouldOptimize,\n stops: orderedStops.map((s) => `${s.originalName} (${s.address})`),\n legs,\n total_distance: `${(totalDistance / 1000).toFixed(1)} km`,\n total_duration: `${Math.round(totalDuration / 60)} min`,\n },\n };\n }\n\n async comparePlaces(params: {\n query: string;\n userLocation?: { latitude: number; longitude: number };\n limit?: number;\n }): Promise<any> {\n const limit = params.limit || 5;\n\n // 1. Search\n const search = await this.searchText({ query: params.query });\n if (!search.success || !search.data) throw new Error(search.error || \"Search failed\");\n\n const places = search.data.slice(0, limit);\n\n // 2. Get details for each\n const compared: any[] = [];\n for (const place of places) {\n const details = await this.getPlaceDetails(place.place_id);\n compared.push({\n name: place.name,\n address: place.address,\n primary_type: details.data?.primary_type || place.primary_type || null,\n rating: place.rating,\n total_ratings: place.total_ratings,\n opening_hours: details.data?.opening_hours,\n phone: details.data?.phone,\n website: details.data?.website,\n price_level: details.data?.price_level,\n ...(details.data?.parking ? { parking: details.data.parking } : {}),\n ...(details.data?.serves ? { serves: details.data.serves } : {}),\n ...(details.data?.atmosphere ? { atmosphere: details.data.atmosphere } : {}),\n ...(details.data?.dining_options ? { dining_options: details.data.dining_options } : {}),\n });\n }\n\n // 3. Distance from user location (if provided)\n if (params.userLocation && compared.length > 0) {\n const origin = `${params.userLocation.latitude},${params.userLocation.longitude}`;\n const destinations = places.map((p: any) => `${p.location.lat},${p.location.lng}`);\n const matrix = await this.calculateDistanceMatrix([origin], destinations, \"driving\");\n if (matrix.success && matrix.data) {\n for (let i = 0; i < compared.length; i++) {\n compared[i].distance = matrix.data.distances[0]?.[i]?.text;\n compared[i].drive_time = matrix.data.durations[0]?.[i]?.text;\n }\n }\n }\n\n return { success: true, data: compared };\n }\n\n async getElevation(locations: Array<{ latitude: number; longitude: number }>): Promise<ElevationResponse> {\n try {\n const result = await this.mapsTools.getElevation(locations);\n\n return {\n success: true,\n data: result,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"An error occurred while getting elevation data\",\n };\n }\n }\n\n async localRankTracker(params: {\n keywords: string[];\n placeId: string;\n center: { latitude: number; longitude: number };\n gridSize?: number;\n gridSpacing?: number;\n }): Promise<any> {\n try {\n const gridSize = params.gridSize || 3;\n const spacingMeters = params.gridSpacing || 1000;\n const { latitude: centerLat, longitude: centerLng } = params.center;\n\n // Generate grid coordinates\n const half = Math.floor(gridSize / 2);\n const metersPerDegreeLat = 111320;\n const metersPerDegreeLng = 111320 * Math.cos((centerLat * Math.PI) / 180);\n\n const gridPoints: Array<{ row: number; col: number; lat: number; lng: number }> = [];\n for (let row = 0; row < gridSize; row++) {\n for (let col = 0; col < gridSize; col++) {\n const rowOffset = (row - half) * spacingMeters;\n const colOffset = (col - half) * spacingMeters;\n gridPoints.push({\n row,\n col,\n lat: centerLat + rowOffset / metersPerDegreeLat,\n lng: centerLng + colOffset / metersPerDegreeLng,\n });\n }\n }\n\n // Get target business name\n let targetName = \"\";\n try {\n const details = await this.getPlaceDetails(params.placeId);\n if (details.success && details.data) {\n targetName = details.data.name;\n }\n } catch {\n // ignore\n }\n\n // Scan each keyword across the grid\n const keywordResults = [];\n for (const keyword of params.keywords) {\n const gridResults = await this.scanKeywordGrid(keyword, params.placeId, gridPoints, spacingMeters);\n keywordResults.push({ keyword, ...gridResults });\n }\n\n // Single keyword: flat response (backward compatible)\n if (keywordResults.length === 1) {\n const kr = keywordResults[0];\n return {\n success: true,\n data: {\n target: { name: targetName, place_id: params.placeId },\n grid_size: `${gridSize}x${gridSize}`,\n grid_spacing_m: spacingMeters,\n keyword: kr.keyword,\n metrics: kr.metrics,\n grid: kr.grid,\n },\n };\n }\n\n // Multi-keyword: array of results\n return {\n success: true,\n data: {\n target: { name: targetName, place_id: params.placeId },\n grid_size: `${gridSize}x${gridSize}`,\n grid_spacing_m: spacingMeters,\n keywords: keywordResults.map((kr) => ({\n keyword: kr.keyword,\n metrics: kr.metrics,\n grid: kr.grid,\n })),\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"An error occurred during local rank tracking\",\n };\n }\n }\n\n private async scanKeywordGrid(\n keyword: string,\n placeId: string,\n gridPoints: Array<{ row: number; col: number; lat: number; lng: number }>,\n spacingMeters: number\n ) {\n const concurrency = 5;\n const gridResults: Array<{\n row: number;\n col: number;\n lat: number;\n lng: number;\n rank: number | null;\n top3: string[];\n }> = [];\n\n const searchOne = async (point: (typeof gridPoints)[0]) => {\n try {\n const places = await this.newPlacesService.searchText({\n textQuery: keyword,\n locationBias: { lat: point.lat, lng: point.lng, radius: spacingMeters / 2 },\n maxResultCount: 20,\n });\n\n const rank = places.findIndex((p: any) => p.place_id === placeId);\n const top3 = places.slice(0, 3).map((p: any) => p.name || \"\");\n\n return {\n row: point.row,\n col: point.col,\n lat: Math.round(point.lat * 1e6) / 1e6,\n lng: Math.round(point.lng * 1e6) / 1e6,\n rank: rank >= 0 ? rank + 1 : null,\n top3,\n };\n } catch {\n return {\n row: point.row,\n col: point.col,\n lat: Math.round(point.lat * 1e6) / 1e6,\n lng: Math.round(point.lng * 1e6) / 1e6,\n rank: null,\n top3: [] as string[],\n };\n }\n };\n\n for (let i = 0; i < gridPoints.length; i += concurrency) {\n const batch = gridPoints.slice(i, i + concurrency);\n const results = await Promise.all(batch.map(searchOne));\n gridResults.push(...results);\n }\n\n const rankedPoints = gridResults.filter((r) => r.rank !== null);\n const totalPoints = gridResults.length;\n const inTop3 = rankedPoints.filter((r) => r.rank! <= 3).length;\n\n const arp =\n rankedPoints.length > 0\n ? Math.round((rankedPoints.reduce((sum, r) => sum + r.rank!, 0) / rankedPoints.length) * 10) / 10\n : null;\n\n const atrp = Math.round((gridResults.reduce((sum, r) => sum + (r.rank ?? 21), 0) / totalPoints) * 10) / 10;\n\n const solv = Math.round((inTop3 / totalPoints) * 1000) / 10;\n\n return {\n metrics: {\n arp,\n atrp,\n solv,\n found_in: `${rankedPoints.length}/${totalPoints}`,\n },\n grid: gridResults,\n };\n }\n}\n","export const Logger = {\n log: (...args: any[]) => {\n console.error(\"[INFO]\", ...args);\n },\n error: (...args: any[]) => {\n console.error(\"[ERROR]\", ...args);\n },\n};\n\nexport { PlacesSearcher } from \"./services/PlacesSearcher.js\";\nexport { NewPlacesService } from \"./services/NewPlacesService.js\";\n"],"mappings":"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","names":["mins"]}
|
package/dist/cli.d.ts
CHANGED
|
@@ -138,10 +138,19 @@ declare function runEnableDisableCliCommand(name: string, enable: boolean, optio
|
|
|
138
138
|
home?: string;
|
|
139
139
|
streams?: ExecStreams;
|
|
140
140
|
}): number;
|
|
141
|
+
declare function runApiKeyCommand(key: string | undefined, options: {
|
|
142
|
+
home?: string;
|
|
143
|
+
resourcesRoot: string;
|
|
144
|
+
streams?: ExecStreams;
|
|
145
|
+
}): number;
|
|
146
|
+
declare function runAutoUpdateCommand(rawState: string | undefined, options?: {
|
|
147
|
+
home?: string;
|
|
148
|
+
streams?: ExecStreams;
|
|
149
|
+
}): number;
|
|
141
150
|
declare function runInstallUninstallCommand(operation: "install" | "uninstall", options: {
|
|
142
151
|
home?: string;
|
|
143
|
-
apiKey?: string;
|
|
144
152
|
resourcesRoot: string;
|
|
153
|
+
includeDebugSkills?: boolean;
|
|
145
154
|
streams?: ExecStreams;
|
|
146
155
|
}): number;
|
|
147
156
|
declare function runShowCommand(options: {
|
|
@@ -150,4 +159,4 @@ declare function runShowCommand(options: {
|
|
|
150
159
|
streams?: ExecStreams;
|
|
151
160
|
}): number;
|
|
152
161
|
|
|
153
|
-
export { DOCTOR_PROBES, type DoctorCheck, type DoctorLiveProbe, type DoctorOptions, type DoctorProbeId, type DoctorProbesParseResult, type DoctorReport, EXEC_TOOLS, type ServerStartupOutcome, type SetupCheck, type SetupDeps, type SetupFs, type SetupOptions, type SetupReport, type ShutdownExitHook, createShutdownHandler, execTool, extractEnvFileOption, installShutdownHandlers, parseDoctorProbes, runDoctor, runEnableDisableCliCommand, runExecCommand, runInstallUninstallCommand, runSetup, runShowCommand, runSnippetCommand, startServer };
|
|
162
|
+
export { DOCTOR_PROBES, type DoctorCheck, type DoctorLiveProbe, type DoctorOptions, type DoctorProbeId, type DoctorProbesParseResult, type DoctorReport, EXEC_TOOLS, type ServerStartupOutcome, type SetupCheck, type SetupDeps, type SetupFs, type SetupOptions, type SetupReport, type ShutdownExitHook, createShutdownHandler, execTool, extractEnvFileOption, installShutdownHandlers, parseDoctorProbes, runApiKeyCommand, runAutoUpdateCommand, runDoctor, runEnableDisableCliCommand, runExecCommand, runInstallUninstallCommand, runSetup, runShowCommand, runSnippetCommand, startServer };
|