Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
| /** | |
| * Google Maps API Integration for Manus WebDev Templates | |
| * | |
| * Main function: makeRequest<T>(endpoint, params) - Makes authenticated requests to Google Maps APIs | |
| * All credentials are automatically injected. Array parameters use | as separator. | |
| * | |
| * See API examples below the type definitions for usage patterns. | |
| */ | |
| import { ENV } from "./env"; | |
| // ============================================================================ | |
| // Configuration | |
| // ============================================================================ | |
| type MapsConfig = { | |
| baseUrl: string; | |
| apiKey: string; | |
| }; | |
| function getMapsConfig(): MapsConfig { | |
| const baseUrl = ENV.forgeApiUrl; | |
| const apiKey = ENV.forgeApiKey; | |
| if (!baseUrl || !apiKey) { | |
| throw new Error( | |
| "Google Maps proxy credentials missing: set BUILT_IN_FORGE_API_URL and BUILT_IN_FORGE_API_KEY" | |
| ); | |
| } | |
| return { | |
| baseUrl: baseUrl.replace(/\/+$/, ""), | |
| apiKey, | |
| }; | |
| } | |
| // ============================================================================ | |
| // Core Request Handler | |
| // ============================================================================ | |
| interface RequestOptions { | |
| method?: "GET" | "POST"; | |
| body?: Record<string, unknown>; | |
| } | |
| /** | |
| * Make authenticated requests to Google Maps APIs | |
| * | |
| * @param endpoint - The API endpoint (e.g., "/maps/api/geocode/json") | |
| * @param params - Query parameters for the request | |
| * @param options - Additional request options | |
| * @returns The API response | |
| */ | |
| export async function makeRequest<T = unknown>( | |
| endpoint: string, | |
| params: Record<string, unknown> = {}, | |
| options: RequestOptions = {} | |
| ): Promise<T> { | |
| const { baseUrl, apiKey } = getMapsConfig(); | |
| // Construct full URL: baseUrl + /v1/maps/proxy + endpoint | |
| const url = new URL(`${baseUrl}/v1/maps/proxy${endpoint}`); | |
| // Add API key as query parameter (standard Google Maps API authentication) | |
| url.searchParams.append("key", apiKey); | |
| // Add other query parameters | |
| Object.entries(params).forEach(([key, value]) => { | |
| if (value !== undefined && value !== null) { | |
| url.searchParams.append(key, String(value)); | |
| } | |
| }); | |
| const response = await fetch(url.toString(), { | |
| method: options.method || "GET", | |
| headers: { | |
| "Content-Type": "application/json", | |
| }, | |
| body: options.body ? JSON.stringify(options.body) : undefined, | |
| }); | |
| if (!response.ok) { | |
| const errorText = await response.text(); | |
| throw new Error( | |
| `Google Maps API request failed (${response.status} ${response.statusText}): ${errorText}` | |
| ); | |
| } | |
| return (await response.json()) as T; | |
| } | |
| // ============================================================================ | |
| // Type Definitions | |
| // ============================================================================ | |
| export type TravelMode = "driving" | "walking" | "bicycling" | "transit"; | |
| export type MapType = "roadmap" | "satellite" | "terrain" | "hybrid"; | |
| export type SpeedUnit = "KPH" | "MPH"; | |
| export type LatLng = { | |
| lat: number; | |
| lng: number; | |
| }; | |
| export type DirectionsResult = { | |
| routes: Array<{ | |
| legs: Array<{ | |
| distance: { text: string; value: number }; | |
| duration: { text: string; value: number }; | |
| start_address: string; | |
| end_address: string; | |
| start_location: LatLng; | |
| end_location: LatLng; | |
| steps: Array<{ | |
| distance: { text: string; value: number }; | |
| duration: { text: string; value: number }; | |
| html_instructions: string; | |
| travel_mode: string; | |
| start_location: LatLng; | |
| end_location: LatLng; | |
| }>; | |
| }>; | |
| overview_polyline: { points: string }; | |
| summary: string; | |
| warnings: string[]; | |
| waypoint_order: number[]; | |
| }>; | |
| status: string; | |
| }; | |
| export type DistanceMatrixResult = { | |
| rows: Array<{ | |
| elements: Array<{ | |
| distance: { text: string; value: number }; | |
| duration: { text: string; value: number }; | |
| status: string; | |
| }>; | |
| }>; | |
| origin_addresses: string[]; | |
| destination_addresses: string[]; | |
| status: string; | |
| }; | |
| export type GeocodingResult = { | |
| results: Array<{ | |
| address_components: Array<{ | |
| long_name: string; | |
| short_name: string; | |
| types: string[]; | |
| }>; | |
| formatted_address: string; | |
| geometry: { | |
| location: LatLng; | |
| location_type: string; | |
| viewport: { | |
| northeast: LatLng; | |
| southwest: LatLng; | |
| }; | |
| }; | |
| place_id: string; | |
| types: string[]; | |
| }>; | |
| status: string; | |
| }; | |
| export type PlacesSearchResult = { | |
| results: Array<{ | |
| place_id: string; | |
| name: string; | |
| formatted_address: string; | |
| geometry: { | |
| location: LatLng; | |
| }; | |
| rating?: number; | |
| user_ratings_total?: number; | |
| business_status?: string; | |
| types: string[]; | |
| }>; | |
| status: string; | |
| }; | |
| export type PlaceDetailsResult = { | |
| result: { | |
| place_id: string; | |
| name: string; | |
| formatted_address: string; | |
| formatted_phone_number?: string; | |
| international_phone_number?: string; | |
| website?: string; | |
| rating?: number; | |
| user_ratings_total?: number; | |
| reviews?: Array<{ | |
| author_name: string; | |
| rating: number; | |
| text: string; | |
| time: number; | |
| }>; | |
| opening_hours?: { | |
| open_now: boolean; | |
| weekday_text: string[]; | |
| }; | |
| geometry: { | |
| location: LatLng; | |
| }; | |
| }; | |
| status: string; | |
| }; | |
| export type ElevationResult = { | |
| results: Array<{ | |
| elevation: number; | |
| location: LatLng; | |
| resolution: number; | |
| }>; | |
| status: string; | |
| }; | |
| export type TimeZoneResult = { | |
| dstOffset: number; | |
| rawOffset: number; | |
| status: string; | |
| timeZoneId: string; | |
| timeZoneName: string; | |
| }; | |
| export type RoadsResult = { | |
| snappedPoints: Array<{ | |
| location: LatLng; | |
| originalIndex?: number; | |
| placeId: string; | |
| }>; | |
| }; | |
| // ============================================================================ | |
| // Google Maps API Reference | |
| // ============================================================================ | |
| /** | |
| * GEOCODING - Convert between addresses and coordinates | |
| * Endpoint: /maps/api/geocode/json | |
| * Input: { address: string } OR { latlng: string } // latlng: "37.42,-122.08" | |
| * Output: GeocodingResult // results[0].geometry.location, results[0].formatted_address | |
| */ | |
| /** | |
| * DIRECTIONS - Get navigation routes between locations | |
| * Endpoint: /maps/api/directions/json | |
| * Input: { origin: string, destination: string, mode?: TravelMode, waypoints?: string, alternatives?: boolean } | |
| * Output: DirectionsResult // routes[0].legs[0].distance, duration, steps | |
| */ | |
| /** | |
| * DISTANCE MATRIX - Calculate travel times/distances for multiple origin-destination pairs | |
| * Endpoint: /maps/api/distancematrix/json | |
| * Input: { origins: string, destinations: string, mode?: TravelMode, units?: "metric"|"imperial" } // origins: "NYC|Boston" | |
| * Output: DistanceMatrixResult // rows[0].elements[1] = first origin to second destination | |
| */ | |
| /** | |
| * PLACE SEARCH - Find businesses/POIs by text query | |
| * Endpoint: /maps/api/place/textsearch/json | |
| * Input: { query: string, location?: string, radius?: number, type?: string } // location: "40.7,-74.0" | |
| * Output: PlacesSearchResult // results[].name, rating, geometry.location, place_id | |
| */ | |
| /** | |
| * NEARBY SEARCH - Find places near a specific location | |
| * Endpoint: /maps/api/place/nearbysearch/json | |
| * Input: { location: string, radius: number, type?: string, keyword?: string } // location: "40.7,-74.0" | |
| * Output: PlacesSearchResult | |
| */ | |
| /** | |
| * PLACE DETAILS - Get comprehensive information about a specific place | |
| * Endpoint: /maps/api/place/details/json | |
| * Input: { place_id: string, fields?: string } // fields: "name,rating,opening_hours,website" | |
| * Output: PlaceDetailsResult // result.name, rating, opening_hours, etc. | |
| */ | |
| /** | |
| * ELEVATION - Get altitude data for geographic points | |
| * Endpoint: /maps/api/elevation/json | |
| * Input: { locations?: string, path?: string, samples?: number } // locations: "39.73,-104.98|36.45,-116.86" | |
| * Output: ElevationResult // results[].elevation (meters) | |
| */ | |
| /** | |
| * TIME ZONE - Get timezone information for a location | |
| * Endpoint: /maps/api/timezone/json | |
| * Input: { location: string, timestamp: number } // timestamp: Math.floor(Date.now()/1000) | |
| * Output: TimeZoneResult // timeZoneId, timeZoneName | |
| */ | |
| /** | |
| * ROADS - Snap GPS traces to roads, find nearest roads, get speed limits | |
| * - /v1/snapToRoads: Input: { path: string, interpolate?: boolean } // path: "lat,lng|lat,lng" | |
| * - /v1/nearestRoads: Input: { points: string } // points: "lat,lng|lat,lng" | |
| * - /v1/speedLimits: Input: { path: string, units?: SpeedUnit } | |
| * Output: RoadsResult | |
| */ | |
| /** | |
| * PLACE AUTOCOMPLETE - Real-time place suggestions as user types | |
| * Endpoint: /maps/api/place/autocomplete/json | |
| * Input: { input: string, location?: string, radius?: number } | |
| * Output: { predictions: Array<{ description: string, place_id: string }> } | |
| */ | |
| /** | |
| * STATIC MAPS - Generate map images as URLs (for emails, reports, <img> tags) | |
| * Endpoint: /maps/api/staticmap | |
| * Input: URL params - center: string, zoom: number, size: string, markers?: string, maptype?: MapType | |
| * Output: Image URL (not JSON) - use directly in <img src={url} /> | |
| * Note: Construct URL manually with getMapsConfig() for auth | |
| */ | |