| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- /**
- * 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
- */
|