From 1a85441f2b47ed13f87541272d04fbb59d03621e Mon Sep 17 00:00:00 2001 From: muhammadsohaib-cs Date: Sun, 16 Aug 2026 19:50:40 +0500 Subject: [PATCH 1/2] initial project start in FortyGuard Repo --- .gitignore | 9 + backend/agents/anomaly_detector.py | 87 + backend/agents/building_auditor.py | 84 + backend/agents/mitigation_simulator.py | 46 + backend/agents/report_generator.py | 157 + backend/main.py | 101 + backend/pipeline/orchestrator.py | 80 + backend/requirements.txt | 10 + backend/schemas/hotspots.py | 33 + backend/schemas/pipeline.py | 14 + backend/schemas/simulation.py | 22 + backend/tools/fortyguard_loader.py | 163 + backend/tools/thermal_math.py | 41 + frontend/next-env.d.ts | 5 + frontend/next.config.js | 14 + frontend/package-lock.json | 3304 +++++++++++++++++ frontend/package.json | 34 + frontend/postcss.config.js | 6 + .../parcel_portfolio_san_jose_sample.geojson | 267 ++ frontend/src/app/api/hotspots/route.ts | 148 + frontend/src/app/api/pipeline/route.ts | 50 + frontend/src/app/api/simulate/route.ts | 39 + frontend/src/app/globals.css | 63 + frontend/src/app/layout.tsx | 21 + frontend/src/app/page.tsx | 144 + frontend/src/components/AgentStatusPanel.tsx | 109 + frontend/src/components/BuildingDrawer.tsx | 214 ++ frontend/src/components/MapViewport.tsx | 225 ++ frontend/src/components/MetricsBar.tsx | 89 + frontend/src/components/TimelineSlider.tsx | 65 + frontend/tailwind.config.js | 25 + frontend/tsconfig.json | 27 + 32 files changed, 5696 insertions(+) create mode 100644 backend/agents/anomaly_detector.py create mode 100644 backend/agents/building_auditor.py create mode 100644 backend/agents/mitigation_simulator.py create mode 100644 backend/agents/report_generator.py create mode 100644 backend/main.py create mode 100644 backend/pipeline/orchestrator.py create mode 100644 backend/requirements.txt create mode 100644 backend/schemas/hotspots.py create mode 100644 backend/schemas/pipeline.py create mode 100644 backend/schemas/simulation.py create mode 100644 backend/tools/fortyguard_loader.py create mode 100644 backend/tools/thermal_math.py create mode 100644 frontend/next-env.d.ts create mode 100644 frontend/next.config.js create mode 100644 frontend/package-lock.json create mode 100644 frontend/package.json create mode 100644 frontend/postcss.config.js create mode 100644 frontend/public/data/parcel_portfolio_san_jose_sample.geojson create mode 100644 frontend/src/app/api/hotspots/route.ts create mode 100644 frontend/src/app/api/pipeline/route.ts create mode 100644 frontend/src/app/api/simulate/route.ts create mode 100644 frontend/src/app/globals.css create mode 100644 frontend/src/app/layout.tsx create mode 100644 frontend/src/app/page.tsx create mode 100644 frontend/src/components/AgentStatusPanel.tsx create mode 100644 frontend/src/components/BuildingDrawer.tsx create mode 100644 frontend/src/components/MapViewport.tsx create mode 100644 frontend/src/components/MetricsBar.tsx create mode 100644 frontend/src/components/TimelineSlider.tsx create mode 100644 frontend/tailwind.config.js create mode 100644 frontend/tsconfig.json diff --git a/.gitignore b/.gitignore index d8a23b1..9a65aa7 100644 --- a/.gitignore +++ b/.gitignore @@ -246,3 +246,12 @@ data/street_view/* !data/env_params/ data/env_params/* !data/env_params/env_params_parcel_*.json + +# Node & Next.js +node_modules/ +**/node_modules/ +.next/ +out/ +build/ +.env*.local + diff --git a/backend/agents/anomaly_detector.py b/backend/agents/anomaly_detector.py new file mode 100644 index 0000000..1846159 --- /dev/null +++ b/backend/agents/anomaly_detector.py @@ -0,0 +1,87 @@ +from typing import Dict, Any, List +from tools.fortyguard_loader import load_parcel_geojson, load_san_jose_thermal_profile, load_all_heatmap_tiles, load_us_sample_locations + +class AnomalyDetectorAgent: + """ + Agent 1: Thermal Anomaly Detector + Scans FortyGuard 2m ambient heatmaps (2,224 spatial tiles), satellite spectral indices, and parcel boundaries. + Isolates micro-climatic urban heat island anomalies where ΔT >= +3.5°F above ambient baseline. + """ + def __init__(self, temp_threshold_f: float = 3.5): + self.temp_threshold_f = temp_threshold_f + + def run(self, parcel_id: str = None) -> Dict[str, Any]: + geojson = load_parcel_geojson() + heatmap_tiles = load_all_heatmap_tiles() + us_locations = load_us_sample_locations() + thermal_profile = load_san_jose_thermal_profile(parcel_id or "APN-264-11-032") + + features = geojson.get("features", []) + anomalies = [] + normal_parcels = [] + + baseline_temp_f = 82.5 + parcel_temp_offsets = { + "APN-259-27-014": 4.8, + "APN-264-11-032": 5.2, + "APN-249-40-008": 2.1, + "APN-467-22-105": 3.9, + "APN-259-33-041": 4.1, + "APN-472-09-017": 1.8 + } + + processed_features = [] + for feature in features: + props = dict(feature.get("properties", {})) + pid = props.get("parcel_id", "UNKNOWN") + + delta_t = parcel_temp_offsets.get(pid, 3.6) + ambient_temp = round(baseline_temp_f + delta_t, 2) + is_anomaly = delta_t >= self.temp_threshold_f + + props["temp_delta_f"] = delta_t + props["ambient_temp_f"] = ambient_temp + props["is_hotspot"] = is_anomaly + props["height"] = props.get("stories", 4) * 3.5 + + processed_features.append({ + "type": "Feature", + "properties": props, + "geometry": feature.get("geometry") + }) + + item_summary = { + "parcel_id": pid, + "name": props.get("name"), + "temp_delta_f": delta_t, + "ambient_temp_f": ambient_temp, + "is_hotspot": is_anomaly + } + + if is_anomaly: + anomalies.append(item_summary) + else: + normal_parcels.append(item_summary) + + # Scan all 2,224 FortyGuard heatmap tiles for thermal breaches + heatmap_features = heatmap_tiles.get("features", []) + tile_anomalies_count = sum(1 for f in heatmap_features if f.get("properties", {}).get("is_hotspot", False)) + + return { + "status": "completed", + "agent_name": "AnomalyDetectorAgent", + "threshold_f": self.temp_threshold_f, + "total_parcels_scanned": len(processed_features), + "total_heatmap_tiles_scanned": len(heatmap_features), + "heatmap_tile_anomalies_count": tile_anomalies_count, + "anomalies_detected_count": len(anomalies), + "anomalies": anomalies, + "normal_parcels": normal_parcels, + "processed_geojson": { + "type": "FeatureCollection", + "features": processed_features + }, + "heatmap_tiles_geojson": heatmap_tiles, + "us_locations_geojson": us_locations, + "sample_thermal_profile": thermal_profile + } diff --git a/backend/agents/building_auditor.py b/backend/agents/building_auditor.py new file mode 100644 index 0000000..3e9da91 --- /dev/null +++ b/backend/agents/building_auditor.py @@ -0,0 +1,84 @@ +from typing import Dict, Any, List +from tools.thermal_math import compute_priority_score + +class BuildingAuditorAgent: + """ + Agent 2: Building Causality & Priority Scorer + Audits parcel geometry, rooftop area, baseline SRI/Albedo, and surround canopy cover. + Calculates urban heat causality score and assigns intervention priority rankings. + """ + + def run(self, anomaly_data: Dict[str, Any]) -> Dict[str, Any]: + features = anomaly_data.get("processed_geojson", {}).get("features", []) + + audited_parcels = [] + + # Default physical parameters per parcel + parcel_defaults = { + "APN-259-27-014": {"albedo": 0.18, "canopy_pct": 0.05, "roof_area_m2": 3500.0}, + "APN-264-11-032": {"albedo": 0.20, "canopy_pct": 0.08, "roof_area_m2": 2150.0}, + "APN-249-40-008": {"albedo": 0.35, "canopy_pct": 0.25, "roof_area_m2": 3700.0}, + "APN-467-22-105": {"albedo": 0.22, "canopy_pct": 0.10, "roof_area_m2": 2880.0}, + "APN-259-33-041": {"albedo": 0.20, "canopy_pct": 0.04, "roof_area_m2": 4600.0}, + "APN-472-09-017": {"albedo": 0.30, "canopy_pct": 0.18, "roof_area_m2": 3000.0} + } + + updated_features = [] + for feature in features: + props = dict(feature.get("properties", {})) + pid = props.get("parcel_id", "UNKNOWN") + + defaults = parcel_defaults.get(pid, {"albedo": 0.22, "canopy_pct": 0.10, "roof_area_m2": 2500.0}) + + albedo = defaults["albedo"] + canopy_pct = defaults["canopy_pct"] + roof_area_m2 = defaults["roof_area_m2"] + + priority_score = compute_priority_score(roof_area_m2, albedo, canopy_pct) + + props["albedo"] = albedo + props["canopy_pct"] = canopy_pct + props["roof_area_m2"] = roof_area_m2 + props["priority_score"] = priority_score + + # Primary thermal driver classification + if albedo < 0.25 and canopy_pct < 0.10: + causality = "Severe dark surface absorption & zero tree canopy cover" + elif albedo < 0.25: + causality = "Low SRI dark rooftop thermal retention" + else: + causality = "Unshaded asphalt paving and surrounding micro-climate" + + props["causality_diagnosis"] = causality + + updated_features.append({ + "type": "Feature", + "properties": props, + "geometry": feature.get("geometry") + }) + + audited_parcels.append({ + "parcel_id": pid, + "name": props.get("name"), + "priority_score": priority_score, + "roof_area_m2": roof_area_m2, + "albedo": albedo, + "canopy_pct": canopy_pct, + "causality_diagnosis": causality, + "is_hotspot": props.get("is_hotspot", False) + }) + + # Rank parcels by priority score descending + audited_parcels.sort(key=lambda x: x["priority_score"], reverse=True) + + return { + "status": "completed", + "agent_name": "BuildingAuditorAgent", + "audited_count": len(audited_parcels), + "highest_priority_parcel": audited_parcels[0] if audited_parcels else None, + "audited_parcels": audited_parcels, + "processed_geojson": { + "type": "FeatureCollection", + "features": updated_features + } + } diff --git a/backend/agents/mitigation_simulator.py b/backend/agents/mitigation_simulator.py new file mode 100644 index 0000000..22dcf6c --- /dev/null +++ b/backend/agents/mitigation_simulator.py @@ -0,0 +1,46 @@ +from typing import Dict, Any, List +from tools.thermal_math import simulate_mitigation + +class MitigationSimulatorAgent: + """ + Agent 3: Cool Roof & Greenery ROI Simulator + Simulates thermal cooling impact and financial payback for cool roofs and tree canopy expansion. + """ + + def run(self, audit_data: Dict[str, Any], target_albedo: float = 0.70, default_canopy_m2: float = 250.0) -> Dict[str, Any]: + audited_parcels = audit_data.get("audited_parcels", []) + + simulations = [] + total_projected_savings_usd = 0.0 + total_co2_reduction_tons = 0.0 + + for parcel in audited_parcels: + roof_area = parcel.get("roof_area_m2", 2000.0) + sim_res = simulate_mitigation( + roof_area_m2=roof_area, + target_albedo=target_albedo, + add_canopy_m2=default_canopy_m2 + ) + + total_projected_savings_usd += sim_res["annual_hvac_savings_usd"] + total_co2_reduction_tons += sim_res["co2_reduction_tons"] + + simulations.append({ + "parcel_id": parcel.get("parcel_id"), + "name": parcel.get("name"), + "baseline_albedo": parcel.get("albedo"), + "target_albedo": target_albedo, + "canopy_added_m2": default_canopy_m2, + "simulation_result": sim_res + }) + + return { + "status": "completed", + "agent_name": "MitigationSimulatorAgent", + "simulated_count": len(simulations), + "target_albedo_applied": target_albedo, + "canopy_expansion_m2_applied": default_canopy_m2, + "total_citywide_annual_savings_usd": round(total_projected_savings_usd, 2), + "total_co2_reduction_tons_yr": round(total_co2_reduction_tons, 2), + "simulations": simulations + } diff --git a/backend/agents/report_generator.py b/backend/agents/report_generator.py new file mode 100644 index 0000000..e3538ef --- /dev/null +++ b/backend/agents/report_generator.py @@ -0,0 +1,157 @@ +import io +import json +from typing import Dict, Any, Optional +from pathlib import Path + +class ReportGeneratorAgent: + """ + Agent 4: GeoJSON & PDF Generator + Synthesizes outputs from Agents 1-3 into enriched GeoJSON feature collections + and printable executive PDF thermal mitigation audit reports. + """ + + def run(self, pipeline_data: Dict[str, Any]) -> Dict[str, Any]: + audit = pipeline_data.get("building_audit", {}) + simulation = pipeline_data.get("mitigation_simulation", {}) + geojson = audit.get("processed_geojson", {"type": "FeatureCollection", "features": []}) + + # Enrich GeoJSON features with simulation outcomes + sim_map = {s["parcel_id"]: s for s in simulation.get("simulations", [])} + + enriched_features = [] + for feature in geojson.get("features", []): + props = dict(feature.get("properties", {})) + pid = props.get("parcel_id") + if pid in sim_map: + sim_res = sim_map[pid].get("simulation_result", {}) + props["projected_temp_drop_f"] = sim_res.get("projected_temp_drop_f") + props["annual_hvac_savings_usd"] = sim_res.get("annual_hvac_savings_usd") + props["payback_years"] = sim_res.get("payback_years") + + enriched_features.append({ + "type": "Feature", + "properties": props, + "geometry": feature.get("geometry") + }) + + enriched_geojson = { + "type": "FeatureCollection", + "features": enriched_features + } + + return { + "status": "completed", + "agent_name": "ReportGeneratorAgent", + "enriched_features_count": len(enriched_features), + "geojson": enriched_geojson, + "executive_summary": { + "total_parcels": len(enriched_features), + "citywide_annual_savings_usd": simulation.get("total_citywide_annual_savings_usd", 0.0), + "total_co2_reduction_tons": simulation.get("total_co2_reduction_tons_yr", 0.0), + "highest_risk_parcel": audit.get("highest_priority_parcel", {}).get("name") + } + } + + def generate_pdf_report(self, parcel_id: str, parcel_info: Dict[str, Any], sim_result: Dict[str, Any]) -> bytes: + """Generates a downloadable PDF report for a given parcel using ReportLab.""" + try: + from reportlab.lib.pagesizes import letter + from reportlab.lib import colors + from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable + from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle + except ImportError: + # Fallback text PDF generation if reportlab is not imported + pdf_bytes = f"PDF Audit Report for Parcel {parcel_id}\n\n".encode("utf-8") + pdf_bytes += f"Structure Name: {parcel_info.get('name', 'San Jose Parcel')}\n".encode("utf-8") + pdf_bytes += f"Projected Cooling: -{sim_result.get('projected_temp_drop_f', 0.0)}°F\n".encode("utf-8") + pdf_bytes += f"Annual Savings: ${sim_result.get('annual_hvac_savings_usd', 0.0)}/yr\n".encode("utf-8") + return pdf_bytes + + buffer = io.BytesIO() + doc = SimpleDocTemplate(buffer, pagesize=letter, rightMargin=36, leftMargin=36, topMargin=36, bottomMargin=36) + story = [] + + styles = getSampleStyleSheet() + title_style = ParagraphStyle( + 'TitleStyle', + parent=styles['Heading1'], + fontSize=20, + textColor=colors.HexColor('#0f172a'), + spaceAfter=8 + ) + subtitle_style = ParagraphStyle( + 'SubTitleStyle', + parent=styles['Normal'], + fontSize=10, + textColor=colors.HexColor('#64748b'), + spaceAfter=14 + ) + heading_style = ParagraphStyle( + 'HeadingStyle', + parent=styles['Heading2'], + fontSize=13, + textColor=colors.HexColor('#10b981'), + spaceBefore=10, + spaceAfter=6 + ) + body_style = ParagraphStyle( + 'BodyStyle', + parent=styles['Normal'], + fontSize=9.5, + textColor=colors.HexColor('#334155'), + leading=13 + ) + + story.append(Paragraph("FortyGuard ThermoAgent-AI Audit Report", title_style)) + story.append(Paragraph(f"Parcel Identifier: {parcel_id} | City: San Jose, CA | Date: 2026-08-03", subtitle_style)) + story.append(HRFlowable(width="100%", thickness=1, color=colors.HexColor('#e2e8f0'), spaceAfter=15)) + + story.append(Paragraph("1. Structure Baseline Analysis", heading_style)) + summary_text = ( + f"Building Name: {parcel_info.get('name', 'N/A')}
" + f"Proposed Use: {parcel_info.get('proposed_use', 'N/A')}
" + f"Rooftop Surface Area: {parcel_info.get('roof_area_m2', 2000)} m²
" + f"Baseline SRI / Albedo: {parcel_info.get('albedo', 0.20)}
" + f"Urban Heat Island ΔT: +{parcel_info.get('temp_delta_f', 4.2)}°F above baseline" + ) + story.append(Paragraph(summary_text, body_style)) + story.append(Spacer(1, 10)) + + story.append(Paragraph("2. Parametric Cooling & Economic ROI Model", heading_style)) + + table_data = [ + ["Metric", "Model Outcome"], + ["Projected Ambient Cooling", f"-{sim_result.get('projected_temp_drop_f', 0.0)} °F"], + ["Cool Roof Contribution", f"-{sim_result.get('cool_roof_drop_f', 0.0)} °F"], + ["Canopy Greening Drop", f"-{sim_result.get('greenery_drop_f', 0.0)} °F"], + ["Annual HVAC Energy Offset", f"${sim_result.get('annual_hvac_savings_usd', 0.0):,.2f} / yr"], + ["Estimated Retrofit Capital Cost", f"${sim_result.get('estimated_retrofit_cost_usd', 0.0):,.2f}"], + ["Estimated Investment Payback", f"{sim_result.get('payback_years', 0.0)} Years"], + ["Annual Carbon Offset", f"{sim_result.get('co2_reduction_tons', 0.0)} Metric Tons CO2e"] + ] + + t = Table(table_data, colWidths=[240, 240]) + t.setStyle(TableStyle([ + ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#0f172a')), + ('TEXTCOLOR', (0, 0), (-1, 0), colors.HexColor('#ffffff')), + ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), + ('FONTSIZE', (0, 0), (-1, -1), 9), + ('BOTTOMPADDING', (0, 0), (-1, -1), 6), + ('TOPPADDING', (0, 0), (-1, -1), 6), + ('GRID', (0, 0), (-1, -1), 0.5, colors.HexColor('#cbd5e1')), + ('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.HexColor('#ffffff'), colors.HexColor('#f8fafc')]) + ])) + story.append(t) + story.append(Spacer(1, 15)) + + story.append(Paragraph("3. Actionable Intervention Recommendations", heading_style)) + recs = ( + "• Upgrade rooftop material to high-SRI white elastomer coating (Target SRI >= 80, Albedo >= 0.70).
" + "• Plant shade tree perimeter canopy to maximize micro-climate evapotranspiration.
" + "• Submit retrofit documentation for San Jose Commercial Energy Efficiency rebates." + ) + story.append(Paragraph(recs, body_style)) + + doc.build(story) + buffer.seek(0) + return buffer.getvalue() diff --git a/backend/main.py b/backend/main.py new file mode 100644 index 0000000..de96bae --- /dev/null +++ b/backend/main.py @@ -0,0 +1,101 @@ +from fastapi import FastAPI, Response, HTTPException +from fastapi.middleware.cors import CORSMiddleware +from tools.fortyguard_loader import load_san_jose_thermal_profile, load_parcel_geojson +from tools.thermal_math import simulate_mitigation +from schemas.simulation import SimulationRequest +from pipeline.orchestrator import PipelineOrchestrator +from agents.report_generator import ReportGeneratorAgent + +app = FastAPI(title="ThermoAgent-AI Multi-Agent API", version="1.0.0") + +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +orchestrator = PipelineOrchestrator() +report_agent = ReportGeneratorAgent() + +@app.get("/health") +async def health_check(): + return {"status": "online", "service": "ThermoAgent-AI Engine"} + +@app.get("/api/v1/hotspots") +async def get_hotspots(): + """ + Exposes FortyGuard San Jose thermal profile and feeds to Agent 1 & Agent 2. + """ + pipeline_res = orchestrator.run_pipeline() + return { + "status": "success", + "data": pipeline_res.get("final_geojson"), + "summary": pipeline_res.get("executive_summary"), + "steps": pipeline_res.get("steps") + } + +@app.post("/api/v1/simulate") +async def run_simulation(req: SimulationRequest): + """ + Parametric simulation endpoint calculating projected cooling, annual HVAC savings, and payback period. + """ + result = simulate_mitigation( + roof_area_m2=req.roof_area, + target_albedo=req.target_albedo, + add_canopy_m2=req.canopy_area + ) + return { + "status": "success", + "parcel_id": req.parcel_id, + "simulation": result + } + +@app.post("/api/v1/pipeline/run") +async def execute_pipeline(target_albedo: float = 0.70, canopy_area: float = 250.0): + """ + Triggers full sequential execution of Agent 1 -> Agent 2 -> Agent 3 -> Agent 4. + """ + pipeline_res = orchestrator.run_pipeline(target_albedo=target_albedo, canopy_area=canopy_area) + return pipeline_res + +@app.get("/api/v1/report/pdf/{parcel_id}") +async def download_pdf_report(parcel_id: str, target_albedo: float = 0.70, canopy_area: float = 250.0): + """ + Generates and returns an executive PDF thermal audit report for the given parcel ID. + """ + geojson = load_parcel_geojson() + parcel_info = {} + for feat in geojson.get("features", []): + if feat.get("properties", {}).get("parcel_id") == parcel_id: + parcel_info = feat.get("properties", {}) + break + + if not parcel_info: + parcel_info = { + "parcel_id": parcel_id, + "name": "San Jose Parcel Property", + "proposed_use": "Urban Commercial / Mixed-Use", + "roof_area_m2": 2150.0, + "albedo": 0.20, + "temp_delta_f": 4.2 + } + + sim_res = simulate_mitigation( + roof_area_m2=parcel_info.get("roof_area_m2", 2150.0), + target_albedo=target_albedo, + add_canopy_m2=canopy_area + ) + + pdf_bytes = report_agent.generate_pdf_report( + parcel_id=parcel_id, + parcel_info=parcel_info, + sim_result=sim_res + ) + + return Response( + content=pdf_bytes, + media_type="application/pdf", + headers={"Content-Disposition": f"attachment; filename=thermoagent_audit_{parcel_id}.pdf"} + ) diff --git a/backend/pipeline/orchestrator.py b/backend/pipeline/orchestrator.py new file mode 100644 index 0000000..af4e396 --- /dev/null +++ b/backend/pipeline/orchestrator.py @@ -0,0 +1,80 @@ +import time +from typing import Dict, Any +from agents.anomaly_detector import AnomalyDetectorAgent +from agents.building_auditor import BuildingAuditorAgent +from agents.mitigation_simulator import MitigationSimulatorAgent +from agents.report_generator import ReportGeneratorAgent + +class PipelineOrchestrator: + """ + Sequential Orchestrator coordinating Multi-Agent execution: + Agent 1 (Anomaly Detector) -> Agent 2 (Building Auditor) -> Agent 3 (Mitigation Simulator) -> Agent 4 (Report Generator) + """ + def __init__(self): + self.anomaly_detector = AnomalyDetectorAgent() + self.building_auditor = BuildingAuditorAgent() + self.mitigation_simulator = MitigationSimulatorAgent() + self.report_generator = ReportGeneratorAgent() + + def run_pipeline(self, target_albedo: float = 0.70, canopy_area: float = 250.0) -> Dict[str, Any]: + start_time = time.time() + steps_log = [] + + # Step 1: Anomaly Detector Agent + t0 = time.time() + anomaly_res = self.anomaly_detector.run() + steps_log.append({ + "agent_name": "AnomalyDetectorAgent", + "status": "success", + "execution_time_ms": round((time.time() - t0) * 1000, 2), + "summary": f"Detected {anomaly_res['anomalies_detected_count']} heat anomalies out of {anomaly_res['total_parcels_scanned']} parcels scanned.", + "data": anomaly_res + }) + + # Step 2: Building Auditor Agent + t1 = time.time() + audit_res = self.building_auditor.run(anomaly_res) + steps_log.append({ + "agent_name": "BuildingAuditorAgent", + "status": "success", + "execution_time_ms": round((time.time() - t1) * 1000, 2), + "summary": f"Audited {audit_res['audited_count']} structures and computed urban heat priority scores.", + "data": audit_res + }) + + # Step 3: Mitigation Simulator Agent + t2 = time.time() + sim_res = self.mitigation_simulator.run(audit_res, target_albedo=target_albedo, default_canopy_m2=canopy_area) + steps_log.append({ + "agent_name": "MitigationSimulatorAgent", + "status": "success", + "execution_time_ms": round((time.time() - t2) * 1000, 2), + "summary": f"Modeled ROI for cool roofs (Albedo={target_albedo}) and {canopy_area}m² canopy expansion. Total savings: ${sim_res['total_citywide_annual_savings_usd']:,.2f}/yr.", + "data": sim_res + }) + + # Step 4: Report Generator Agent + t3 = time.time() + pipeline_context = { + "anomaly_detection": anomaly_res, + "building_audit": audit_res, + "mitigation_simulation": sim_res + } + report_res = self.report_generator.run(pipeline_context) + steps_log.append({ + "agent_name": "ReportGeneratorAgent", + "status": "success", + "execution_time_ms": round((time.time() - t3) * 1000, 2), + "summary": f"Generated enriched GeoJSON feature collection with {report_res['enriched_features_count']} structures.", + "data": report_res + }) + + total_time_ms = round((time.time() - start_time) * 1000, 2) + + return { + "status": "success", + "total_execution_time_ms": total_time_ms, + "steps": steps_log, + "final_geojson": report_res.get("geojson"), + "executive_summary": report_res.get("executive_summary") + } diff --git a/backend/requirements.txt b/backend/requirements.txt new file mode 100644 index 0000000..2155203 --- /dev/null +++ b/backend/requirements.txt @@ -0,0 +1,10 @@ +fastapi>=0.109.0 +uvicorn>=0.27.0 +pydantic>=2.5.0 +shapely>=2.0.0 +geopandas>=0.14.0 +h3>=3.7.6 +reportlab>=4.0.0 +pillow>=10.0.0 +python-dotenv>=1.0.0 +requests>=2.31.0 diff --git a/backend/schemas/hotspots.py b/backend/schemas/hotspots.py new file mode 100644 index 0000000..5ba22fc --- /dev/null +++ b/backend/schemas/hotspots.py @@ -0,0 +1,33 @@ +from pydantic import BaseModel, Field +from typing import List, Optional, Dict, Any + +class ParcelProperties(BaseModel): + parcel_id: str + name: Optional[str] = None + city: str = "San Jose" + state: str = "CA" + lot_acres: float = 1.0 + zoning: Optional[str] = None + proposed_use: Optional[str] = None + proposed_gsf: Optional[float] = None + stories: Optional[int] = None + temp_delta_f: float = 0.0 + ambient_temp_f: float = 85.0 + priority_score: float = 0.0 + is_hotspot: bool = False + albedo: float = 0.25 + canopy_pct: float = 0.10 + roof_area_m2: float = 1000.0 + +class HotspotFeature(BaseModel): + type: str = "Feature" + properties: ParcelProperties + geometry: Dict[str, Any] + +class HotspotsResponse(BaseModel): + status: str = "success" + total_parcels: int + hotspot_count: int + avg_ambient_temp_f: float + max_temp_delta_f: float + data: Dict[str, Any] diff --git a/backend/schemas/pipeline.py b/backend/schemas/pipeline.py new file mode 100644 index 0000000..f854893 --- /dev/null +++ b/backend/schemas/pipeline.py @@ -0,0 +1,14 @@ +from pydantic import BaseModel +from typing import List, Dict, Any, Optional + +class AgentStepResult(BaseModel): + agent_name: str + status: str + summary: str + details: Dict[str, Any] + +class PipelineResponse(BaseModel): + status: str = "success" + total_execution_time_ms: float + steps: List[AgentStepResult] + summary_report: Dict[str, Any] diff --git a/backend/schemas/simulation.py b/backend/schemas/simulation.py new file mode 100644 index 0000000..0f09d86 --- /dev/null +++ b/backend/schemas/simulation.py @@ -0,0 +1,22 @@ +from pydantic import BaseModel, Field +from typing import Optional, Dict, Any + +class SimulationRequest(BaseModel): + parcel_id: Optional[str] = "APN-264-11-032" + roof_area: float = Field(..., gt=0, description="Roof surface area in m²") + target_albedo: float = Field(0.7, ge=0.2, le=0.95, description="Target roof solar reflectance index (Albedo)") + canopy_area: float = Field(250.0, ge=0.0, description="Additional vegetative canopy area in m²") + +class SimulationResult(BaseModel): + projected_temp_drop_f: float + annual_hvac_savings_usd: float + payback_years: float + cool_roof_drop_f: float + greenery_drop_f: float + co2_reduction_tons: float + estimated_retrofit_cost_usd: float + +class SimulationResponse(BaseModel): + status: str = "success" + parcel_id: Optional[str] = None + simulation: SimulationResult diff --git a/backend/tools/fortyguard_loader.py b/backend/tools/fortyguard_loader.py new file mode 100644 index 0000000..911e025 --- /dev/null +++ b/backend/tools/fortyguard_loader.py @@ -0,0 +1,163 @@ +import json +from pathlib import Path +from typing import Dict, Any, List, Optional + +DATA_DIR = Path(__file__).resolve().parent.parent.parent / "data" + +def load_san_jose_thermal_profile(parcel_id: str = "APN-264-11-032") -> Dict[str, Any]: + """ + Loads FortyGuard San Jose thermal profile datasets: TCM heatmaps, satellite surface data, and env parameters. + """ + heatmap_file = DATA_DIR / "heatmaps/heatmap_parcel_portfolio_san_jose_2026-08-03_tcm.json" + satellite_file = DATA_DIR / f"satellite/satellite_parcel_portfolio_san_jose_{parcel_id}_2026-08-03.json" + env_file = DATA_DIR / f"env_params/env_params_parcel_portfolio_san_jose_{parcel_id}_2026-08-03.json" + streetview_file = DATA_DIR / f"street_view/streetview_parcel_portfolio_san_jose_{parcel_id}.json" + + if not satellite_file.exists(): + satellite_file = DATA_DIR / "satellite/satellite_parcel_diridon_san_jose_2024-07-15.json" + if not env_file.exists(): + env_file = DATA_DIR / "env_params/env_params_parcel_diridon_san_jose_2024-07-15.json" + if not streetview_file.exists(): + streetview_file = DATA_DIR / "street_view/streetview_parcel_diridon_san_jose.json" + + heatmap, satellite, env, street_view = {}, {}, {}, {} + + if heatmap_file.exists(): + with open(heatmap_file, "r", encoding="utf-8") as f: + heatmap = json.load(f) + + if satellite_file.exists(): + with open(satellite_file, "r", encoding="utf-8") as f: + satellite = json.load(f) + + if env_file.exists(): + with open(env_file, "r", encoding="utf-8") as f: + env = json.load(f) + + if streetview_file.exists(): + with open(streetview_file, "r", encoding="utf-8") as f: + street_view = json.load(f) + + return { + "parcel_id": parcel_id, + "heatmap": heatmap, + "satellite": satellite, + "env": env, + "street_view": street_view + } + +def load_parcel_geojson() -> Dict[str, Any]: + """Load base geographic parcel boundary GeoJSON file.""" + geojson_path = DATA_DIR / "parcel_portfolio_san_jose_sample.geojson" + if geojson_path.exists(): + with open(geojson_path, "r", encoding="utf-8") as f: + return json.load(f) + return {"type": "FeatureCollection", "features": []} + +def load_all_heatmap_tiles(sample_step: int = 1) -> Dict[str, Any]: + """ + Loads all 2,224 FortyGuard 2m ambient thermal heatmap polygon grid tiles. + Converts tile temperatures to Fahrenheit (°F) and calculates thermal anomaly deltas. + """ + path = DATA_DIR / "heatmaps/heatmap_parcel_portfolio_san_jose_2026-08-03_tcm.json" + if not path.exists(): + return {"type": "FeatureCollection", "features": []} + + with open(path, "r", encoding="utf-8") as f: + data = json.load(f) + + raw_features = data.get("map_data", {}).get("features", []) + processed_features = [] + + # Baseline ambient temp in San Jose core (°F) + baseline_f = 78.0 + + for idx, feat in enumerate(raw_features[::sample_step]): + props = dict(feat.get("properties", {})) + avg_c = props.get("average_temperature", 25.0) + max_c = props.get("max_temperature", 30.0) + min_c = props.get("min_temperature", 20.0) + + avg_f = round(avg_c * 1.8 + 32.0, 2) + max_f = round(max_c * 1.8 + 32.0, 2) + min_f = round(min_c * 1.8 + 32.0, 2) + delta_f = round(avg_f - baseline_f, 2) + + props["avg_temp_f"] = avg_f + props["max_temp_f"] = max_f + props["min_temp_f"] = min_f + props["temp_delta_f"] = delta_f + props["is_hotspot"] = delta_f >= 3.5 + + processed_features.append({ + "type": "Feature", + "id": feat.get("id", str(idx)), + "properties": props, + "geometry": feat.get("geometry") + }) + + return { + "type": "FeatureCollection", + "features": processed_features + } + +def load_us_sample_locations() -> Dict[str, Any]: + """ + Returns US multi-city FortyGuard dataset points (San Jose, CA; Manhattan, NY; Chicago, IL). + """ + return { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "city": "San Jose", + "state": "CA", + "name": "San Jose FortyGuard Microclimate Region", + "dataset_points": 2224, + "avg_temp_f": 86.2, + "temp_delta_f": 5.2, + "is_hotspot": True, + "location_type": "Primary Urban Heat Island Benchmark" + }, + "geometry": { + "type": "Point", + "coordinates": [-121.8906, 37.3361] + } + }, + { + "type": "Feature", + "properties": { + "city": "New York", + "state": "NY", + "name": "Lower Manhattan Thermal Corridor", + "dataset_points": 150, + "avg_temp_f": 88.5, + "temp_delta_f": 4.6, + "is_hotspot": True, + "location_type": "Dense Urban Canyon Sample" + }, + "geometry": { + "type": "Point", + "coordinates": [-74.0060, 40.7128] + } + }, + { + "type": "Feature", + "properties": { + "city": "Chicago", + "state": "IL", + "name": "Chicago Loop District", + "dataset_points": 180, + "avg_temp_f": 84.1, + "temp_delta_f": 3.8, + "is_hotspot": True, + "location_type": "Lakefront Microclimate Sample" + }, + "geometry": { + "type": "Point", + "coordinates": [-87.6298, 41.8781] + } + } + ] + } diff --git a/backend/tools/thermal_math.py b/backend/tools/thermal_math.py new file mode 100644 index 0000000..784caf0 --- /dev/null +++ b/backend/tools/thermal_math.py @@ -0,0 +1,41 @@ +from typing import Dict, Any + +def compute_priority_score(roof_area_m2: float, albedo: float, canopy_pct: float) -> float: + """ + Priority Score = [Roof Area (m²) × (1 - Albedo)] / [Canopy Percentage (50m) + 0.1] + Higher score indicates higher vulnerability and priority for cool roof / greening intervention. + """ + safe_canopy = max(0.0, float(canopy_pct)) + safe_albedo = min(1.0, max(0.0, float(albedo))) + score = (roof_area_m2 * (1.0 - safe_albedo)) / (safe_canopy + 0.1) + return round(score, 2) + +def simulate_mitigation(roof_area_m2: float, target_albedo: float, add_canopy_m2: float) -> Dict[str, Any]: + """ + Modeled cool roof & vegetative canopy thermal mitigation calculations. + - Modeled at ~2.5°F drop per 1,000m² retrofitted cool roof (SRI >= 80) + - Modeled at 1.0°F to 3.2°F drop for vegetative canopy expansion (avg 1.8°F / 1000m²) + """ + safe_roof = max(10.0, float(roof_area_m2)) + safe_target_albedo = max(0.2, min(0.95, float(target_albedo))) + safe_canopy = max(0.0, float(add_canopy_m2)) + + cool_roof_drop = (safe_roof / 1000.0) * 2.5 * (safe_target_albedo - 0.2) + greenery_drop = (safe_canopy / 1000.0) * 1.8 + + total_delta_t = cool_roof_drop + greenery_drop + annual_savings_usd = safe_roof * 4.50 # $4.50/m² peak chiller offset + retrofit_cost = safe_roof * 25.0 # Estimated retrofitting cost ($25/m²) + + payback_years = (retrofit_cost / annual_savings_usd) if annual_savings_usd > 0 else 0.0 + co2_reduction_tons = safe_roof * 0.015 # ~15kg CO2 offset per m² per year + + return { + "projected_temp_drop_f": round(total_delta_t, 2), + "annual_hvac_savings_usd": round(annual_savings_usd, 2), + "payback_years": round(payback_years, 1), + "cool_roof_drop_f": round(cool_roof_drop, 2), + "greenery_drop_f": round(greenery_drop, 2), + "co2_reduction_tons": round(co2_reduction_tons, 2), + "estimated_retrofit_cost_usd": round(retrofit_cost, 2) + } diff --git a/frontend/next-env.d.ts b/frontend/next-env.d.ts new file mode 100644 index 0000000..4f11a03 --- /dev/null +++ b/frontend/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/frontend/next.config.js b/frontend/next.config.js new file mode 100644 index 0000000..385cf2d --- /dev/null +++ b/frontend/next.config.js @@ -0,0 +1,14 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + transpilePackages: ['@deck.gl/layers', '@deck.gl/react', '@deck.gl/core'], + webpack: (config) => { + config.resolve.alias = { + ...config.resolve.alias, + 'mapbox-gl': 'mapbox-gl' + }; + return config; + } +}; + +module.exports = nextConfig; diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..e66f635 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,3304 @@ +{ + "name": "thermoagent-ai-frontend", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "thermoagent-ai-frontend", + "version": "0.1.0", + "dependencies": { + "@deck.gl/core": "^9.0.0", + "@deck.gl/geo-layers": "^9.3.10", + "@deck.gl/layers": "^9.0.0", + "@deck.gl/react": "^9.0.0", + "clsx": "^2.1.0", + "lucide-react": "^0.330.0", + "mapbox-gl": "^3.1.2", + "next": "14.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-map-gl": "^7.1.7", + "tailwind-merge": "^2.2.1" + }, + "devDependencies": { + "@types/node": "^20.11.0", + "@types/react": "^18.2.0", + "@types/react-dom": "^18.2.0", + "autoprefixer": "^10.4.17", + "postcss": "^8.4.35", + "tailwindcss": "^3.4.1", + "typescript": "^5.3.3" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@deck.gl/core": { + "version": "9.3.10", + "resolved": "https://registry.npmjs.org/@deck.gl/core/-/core-9.3.10.tgz", + "integrity": "sha512-BAJ6r+eRV4euuGcIi2SnlzrodgZ+sD2VuXsoL1DER0LwwKXmKmQu6WA8ax6DB9KFsBghLVoTUN5zaCGF6uKHuQ==", + "license": "MIT", + "dependencies": { + "@loaders.gl/core": "^4.4.3", + "@loaders.gl/images": "^4.4.3", + "@luma.gl/core": "^9.3.5", + "@luma.gl/engine": "^9.3.5", + "@luma.gl/shadertools": "^9.3.5", + "@luma.gl/webgl": "^9.3.5", + "@math.gl/core": "^4.1.0", + "@math.gl/sun": "^4.1.0", + "@math.gl/types": "^4.1.0", + "@math.gl/web-mercator": "^4.1.0", + "@probe.gl/env": "^4.1.1", + "@probe.gl/log": "^4.1.1", + "@probe.gl/stats": "^4.1.1", + "@types/offscreencanvas": "^2019.6.4", + "gl-matrix": "^3.0.0", + "mjolnir.js": "^3.0.0" + } + }, + "node_modules/@deck.gl/extensions": { + "version": "9.3.10", + "resolved": "https://registry.npmjs.org/@deck.gl/extensions/-/extensions-9.3.10.tgz", + "integrity": "sha512-VT5NxR+SgUCwvaWeKFKkql5HV90KjyiPyXYlzKfxxXoE8wxlOgt5Enl2MTAOLcIhlCymLp9vtWO/HEgTfvlzDw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@luma.gl/shadertools": "^9.3.5", + "@luma.gl/webgl": "^9.3.5", + "@math.gl/core": "^4.1.0" + }, + "peerDependencies": { + "@deck.gl/core": "~9.3.0", + "@luma.gl/core": "~9.3.5", + "@luma.gl/engine": "~9.3.5" + } + }, + "node_modules/@deck.gl/geo-layers": { + "version": "9.3.10", + "resolved": "https://registry.npmjs.org/@deck.gl/geo-layers/-/geo-layers-9.3.10.tgz", + "integrity": "sha512-MH6/MyWTiJ02yxrkMz6bMP1Z8d13JEmxogwZmWx2I9XLDNpCnLxnXElnVxxvDvhIbWdWq/i/xl8Kn9WOLiywBg==", + "license": "MIT", + "dependencies": { + "@loaders.gl/3d-tiles": "^4.4.3", + "@loaders.gl/gis": "^4.4.3", + "@loaders.gl/loader-utils": "^4.4.3", + "@loaders.gl/mvt": "^4.4.3", + "@loaders.gl/schema": "^4.4.3", + "@loaders.gl/terrain": "^4.4.3", + "@loaders.gl/tiles": "^4.4.3", + "@loaders.gl/wms": "^4.4.3", + "@luma.gl/gltf": "^9.3.5", + "@luma.gl/shadertools": "^9.3.5", + "@math.gl/core": "^4.1.0", + "@math.gl/culling": "^4.1.0", + "@math.gl/web-mercator": "^4.1.0", + "@types/geojson": "^7946.0.8", + "a5-js": "^0.7.2", + "h3-js": "^4.4.0", + "long": "^3.2.0" + }, + "peerDependencies": { + "@deck.gl/core": "~9.3.0", + "@deck.gl/extensions": "~9.3.0", + "@deck.gl/layers": "~9.3.0", + "@deck.gl/mesh-layers": "~9.3.0", + "@loaders.gl/core": "^4.4.3", + "@luma.gl/core": "~9.3.5", + "@luma.gl/engine": "~9.3.5" + } + }, + "node_modules/@deck.gl/layers": { + "version": "9.3.10", + "resolved": "https://registry.npmjs.org/@deck.gl/layers/-/layers-9.3.10.tgz", + "integrity": "sha512-F9CRJlRWXvTKlgjKmmTotm0cA5V7I1zMtdnwJbjBZTyCJ4skuskbIIt6f+BSQ+rSxM2uW4q5/8VkcCJ2SePhXg==", + "license": "MIT", + "dependencies": { + "@loaders.gl/images": "^4.4.3", + "@loaders.gl/schema": "^4.4.3", + "@luma.gl/shadertools": "^9.3.5", + "@mapbox/tiny-sdf": "^2.0.5", + "@math.gl/core": "^4.1.0", + "@math.gl/polygon": "^4.1.0", + "@math.gl/web-mercator": "^4.1.0", + "@types/geojson": "^7946.0.16", + "earcut": "^2.2.4" + }, + "peerDependencies": { + "@deck.gl/core": "~9.3.0", + "@loaders.gl/core": "^4.4.3", + "@luma.gl/core": "~9.3.5", + "@luma.gl/engine": "~9.3.5" + } + }, + "node_modules/@deck.gl/mesh-layers": { + "version": "9.3.10", + "resolved": "https://registry.npmjs.org/@deck.gl/mesh-layers/-/mesh-layers-9.3.10.tgz", + "integrity": "sha512-HzExbHWQ05fU7YgXcCQPHjHKoMc2PTWUTu3THzdXc5HXhGqpiAd/X1YA7McA9fRJBjw1yD36otMwGEXqUOEKAA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@loaders.gl/gltf": "^4.4.3", + "@loaders.gl/schema": "^4.4.3", + "@luma.gl/gltf": "^9.3.5", + "@luma.gl/shadertools": "^9.3.5" + }, + "peerDependencies": { + "@deck.gl/core": "~9.3.0", + "@luma.gl/core": "~9.3.5", + "@luma.gl/engine": "~9.3.5", + "@luma.gl/gltf": "~9.3.5", + "@luma.gl/shadertools": "~9.3.5" + } + }, + "node_modules/@deck.gl/react": { + "version": "9.3.10", + "resolved": "https://registry.npmjs.org/@deck.gl/react/-/react-9.3.10.tgz", + "integrity": "sha512-kbfceQ6uZxFS5DVwM3JLY1gSVfx+IJ8ihnkSomxX5Nhhfos1GWnH5wJo8wznKGl9WdLd/iY5bHc8q9i0f5TVjA==", + "license": "MIT", + "peerDependencies": { + "@deck.gl/core": "~9.3.0", + "@deck.gl/widgets": "~9.3.0", + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + } + }, + "node_modules/@deck.gl/widgets": { + "version": "9.3.10", + "resolved": "https://registry.npmjs.org/@deck.gl/widgets/-/widgets-9.3.10.tgz", + "integrity": "sha512-eEQuxQeqIkm04d9MgUH0MtGTmW3xSvqS/nkyIGPhaoAj6VWGu850JfXVdQbnORxFweoQWPI1jfU0Q8j8twhkEA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@floating-ui/dom": "^1.7.5", + "preact": "^10.17.0" + }, + "peerDependencies": { + "@deck.gl/core": "~9.3.0", + "@luma.gl/core": "~9.3.5" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "license": "MIT", + "peer": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@loaders.gl/3d-tiles": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/3d-tiles/-/3d-tiles-4.4.4.tgz", + "integrity": "sha512-/hQnsv0N7bZQ/fr7W2F84fkxj+rE7m76HvN3DRiirIMpS2AF9nxVTSQQIxr34AyM7qTFhldqGnWHS2NMcK2e5w==", + "license": "MIT", + "dependencies": { + "@loaders.gl/compression": "4.4.4", + "@loaders.gl/crypto": "4.4.4", + "@loaders.gl/draco": "4.4.4", + "@loaders.gl/gltf": "4.4.4", + "@loaders.gl/images": "4.4.4", + "@loaders.gl/loader-utils": "4.4.4", + "@loaders.gl/math": "4.4.4", + "@loaders.gl/tiles": "4.4.4", + "@loaders.gl/zip": "4.4.4", + "@math.gl/core": "^4.1.0", + "@math.gl/culling": "^4.1.0", + "@math.gl/geospatial": "^4.1.0", + "@probe.gl/log": "^4.1.1", + "long": "^5.2.1" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/3d-tiles/node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/@loaders.gl/compression": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/compression/-/compression-4.4.4.tgz", + "integrity": "sha512-8b95xmGzOv5++ehKAXwNgrSuQ6r8twTadgO3UEk8I0rTWchgYVw5klOoGjsATzjWuv4LpvXAiveSeZUs5hBLMQ==", + "license": "MIT", + "dependencies": { + "@loaders.gl/loader-utils": "4.4.4", + "@loaders.gl/worker-utils": "4.4.4", + "@types/pako": "^1.0.1", + "fflate": "0.7.4", + "pako": "1.0.11", + "snappyjs": "^0.6.1" + }, + "optionalDependencies": { + "@types/brotli": "^1.3.0", + "brotli": "^1.3.2", + "lz4js": "^0.2.0", + "zstd-codec": "^0.1" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/core": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/core/-/core-4.4.4.tgz", + "integrity": "sha512-uUZLs1N1VQXj3jC81LS7OkrWw1NRQHb0rdGUZI/FOFvirFEIR+TAKcvMO1Zz9WQj2dT9r6HhVjMDJQxU42LsoA==", + "license": "MIT", + "dependencies": { + "@loaders.gl/loader-utils": "4.4.4", + "@loaders.gl/schema": "4.4.4", + "@loaders.gl/schema-utils": "4.4.4", + "@loaders.gl/worker-utils": "4.4.4", + "@probe.gl/log": "^4.1.1" + } + }, + "node_modules/@loaders.gl/crypto": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/crypto/-/crypto-4.4.4.tgz", + "integrity": "sha512-KTtK2p0i50N1pJ00cAMv7ahF8jLhUu2S6tZoLFlPT3kKFuFgLbeowpw/8pC9sDBKkROCblxszLamLywjo0JXBA==", + "license": "MIT", + "dependencies": { + "@loaders.gl/loader-utils": "4.4.4", + "@loaders.gl/worker-utils": "4.4.4", + "@types/crypto-js": "^4.0.2" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/draco": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/draco/-/draco-4.4.4.tgz", + "integrity": "sha512-r34fr0dzdOinANYu5ElnaJdOkk0WkinsiaU/E+MAah37x3CsU+erppDdXdkouGXqvFNbjlS9UMB1Qn5JLj3ZDg==", + "license": "MIT", + "dependencies": { + "@loaders.gl/loader-utils": "4.4.4", + "@loaders.gl/schema": "4.4.4", + "@loaders.gl/schema-utils": "4.4.4", + "@loaders.gl/worker-utils": "4.4.4", + "draco3d": "1.5.7" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/geoarrow": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/geoarrow/-/geoarrow-4.4.4.tgz", + "integrity": "sha512-5IygnXr1J+IBYKA+ZEOytifS4skx/L9Rk6J/OVmNzV5gVsKQtxwA3b69GDPD61dcNAYCegA3Y4wpHO+JEqLzrg==", + "license": "MIT", + "dependencies": { + "@math.gl/polygon": "^4.1.0", + "apache-arrow": ">= 17.0.0" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/gis": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/gis/-/gis-4.4.4.tgz", + "integrity": "sha512-KUonvWVntPhZKx4jjoGezXLp4R1RgS6n4FMLdOYX1fUJZ48fRDQVA28Y/PbqDgBHm/9pJ7Aq3TlOvjbr2KUsVA==", + "license": "MIT", + "dependencies": { + "@loaders.gl/geoarrow": "4.4.4", + "@loaders.gl/loader-utils": "4.4.4", + "@loaders.gl/schema": "4.4.4", + "@loaders.gl/schema-utils": "4.4.4", + "@mapbox/vector-tile": "^1.3.1", + "@math.gl/polygon": "^4.1.0", + "pbf": "^3.2.1" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/gltf": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/gltf/-/gltf-4.4.4.tgz", + "integrity": "sha512-EVslafU3LWjOkuoHH5Oh+sF4WuOdG/ZQf/WwTTzlZsoFhkOFG5Hj1Wmk4kLOY8bYZj7RhspDuDW/GIW45zaEnQ==", + "license": "MIT", + "dependencies": { + "@loaders.gl/draco": "4.4.4", + "@loaders.gl/images": "4.4.4", + "@loaders.gl/loader-utils": "4.4.4", + "@loaders.gl/schema": "4.4.4", + "@loaders.gl/textures": "4.4.4", + "@math.gl/core": "^4.1.0" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/images": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/images/-/images-4.4.4.tgz", + "integrity": "sha512-pqCfWRR7yEHCnAaWDu1aoD7NILts6mvY+B47lQXJ00Ffm4/cfx35dTZ4GUung/iqdVAbxC7fpGKwTPn3T06x4w==", + "license": "MIT", + "dependencies": { + "@loaders.gl/loader-utils": "4.4.4" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/loader-utils": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/loader-utils/-/loader-utils-4.4.4.tgz", + "integrity": "sha512-+0IizJUB6GvPQjl2xC2V1vpcMPcidZykWy27LFnIIqG1lesxfALnFmRoq9MjbOj2TPcUo7VSBxl8z55qRlX0rQ==", + "license": "MIT", + "dependencies": { + "@loaders.gl/schema": "4.4.4", + "@loaders.gl/worker-utils": "4.4.4", + "@probe.gl/log": "^4.1.1", + "@probe.gl/stats": "^4.1.1" + } + }, + "node_modules/@loaders.gl/math": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/math/-/math-4.4.4.tgz", + "integrity": "sha512-cKouXGDpQZQRXJIqt/SelsC5XbslhhSSlFof9fXnS17uX9KROq0Wtt70k0kr+PIG8kFgTerrdcGNM3DIqpQ/hQ==", + "license": "MIT", + "dependencies": { + "@math.gl/core": "^4.1.0" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/mvt": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/mvt/-/mvt-4.4.4.tgz", + "integrity": "sha512-njxMrrkRnBEWFWACzh1Npmk74QZ/hXxonoJEVQ5jTRIA41Ny4KoqxtCa3w3qphiCDGTbGi0cDeDKTp+9d3s0LQ==", + "license": "MIT", + "dependencies": { + "@loaders.gl/gis": "4.4.4", + "@loaders.gl/images": "4.4.4", + "@loaders.gl/loader-utils": "4.4.4", + "@loaders.gl/schema": "4.4.4", + "@loaders.gl/schema-utils": "4.4.4", + "@math.gl/polygon": "^4.1.0", + "@probe.gl/stats": "^4.1.1", + "pbf": "^3.2.1" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/schema": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/schema/-/schema-4.4.4.tgz", + "integrity": "sha512-3spgUoN505V2OprDDzww5nhWfn8Htupcfdr+/lxswAhCbGjwM3RWzA3Zif3dW6ZxOCeSIRJ4GNON78Eiede2dw==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.7", + "apache-arrow": ">= 17.0.0" + } + }, + "node_modules/@loaders.gl/schema-utils": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/schema-utils/-/schema-utils-4.4.4.tgz", + "integrity": "sha512-/ykSrQlfn7Lx+kmQNuGzTaywLVy2RoaAZ5YiEXkP9UJ+4lYY2wP5KgUlQGwODDdzNPLFmYzd+FXeE9GEmlXIUg==", + "license": "MIT", + "dependencies": { + "@loaders.gl/schema": "4.4.4", + "@math.gl/types": "^4.1.0", + "@types/geojson": "^7946.0.7", + "apache-arrow": ">= 17.0.0" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/terrain": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/terrain/-/terrain-4.4.4.tgz", + "integrity": "sha512-eGOwBzmI1SVsG5zDvpi5Iw6Np3JdklOOeU/AGAC/vRU/tMqIvYk9qT77mZkR71bKQXkmBEMPRzdv6je9HEFzjg==", + "license": "MIT", + "dependencies": { + "@loaders.gl/images": "4.4.4", + "@loaders.gl/loader-utils": "4.4.4", + "@loaders.gl/schema": "4.4.4", + "@mapbox/martini": "^0.2.0" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/textures": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/textures/-/textures-4.4.4.tgz", + "integrity": "sha512-O0CMKZpOY0kH/s6oSPfzVkUeGgiJnlPFpPL2KJFo1NBkJihfnzAisfPrU4FEVFYm6XfbclkB5BC+6mI2DXgRLQ==", + "license": "MIT", + "dependencies": { + "@loaders.gl/images": "4.4.4", + "@loaders.gl/loader-utils": "4.4.4", + "@loaders.gl/schema": "4.4.4", + "@loaders.gl/worker-utils": "4.4.4", + "@math.gl/types": "^4.1.0", + "ktx-parse": "^0.7.0", + "texture-compressor": "^1.0.2" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/tiles": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/tiles/-/tiles-4.4.4.tgz", + "integrity": "sha512-2dspQParviZmDNi1naH6xi9SmUHkEp4ADt5CEOGVIx/pFsmKG7cAtVvvpWGZ1c4pGSUvCWPjlv/QcA79p7EMGQ==", + "license": "MIT", + "dependencies": { + "@loaders.gl/loader-utils": "4.4.4", + "@loaders.gl/math": "4.4.4", + "@math.gl/core": "^4.1.0", + "@math.gl/culling": "^4.1.0", + "@math.gl/geospatial": "^4.1.0", + "@math.gl/web-mercator": "^4.1.0", + "@probe.gl/stats": "^4.1.1" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/wms": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/wms/-/wms-4.4.4.tgz", + "integrity": "sha512-D42D69IUAXRkgDfIzobKmiaQA9ktsAzKKBE2bWSwfze+5upsTUycmBMV95qeqFl5AEXtxU92EJByA4MCvDnkpw==", + "license": "MIT", + "dependencies": { + "@loaders.gl/images": "4.4.4", + "@loaders.gl/loader-utils": "4.4.4", + "@loaders.gl/schema": "4.4.4", + "@loaders.gl/xml": "4.4.4", + "@turf/rewind": "^5.1.5", + "deep-strict-equal": "^0.2.0" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/worker-utils": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/worker-utils/-/worker-utils-4.4.4.tgz", + "integrity": "sha512-UNQCwK7tHd7Qh0K7e6Flvac8qd14SoAgaN8SOjggd5ngYqwytOQiAo5uEuhRN+r7+EqdwU+qwcpRtjYByT+RqA==", + "license": "MIT", + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/xml": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/xml/-/xml-4.4.4.tgz", + "integrity": "sha512-/EtNcjISCeTO3VBwkkz5j68fmaBBaXfaTakP+urg0GdBBGEflZwbmBNa9eJP6ObZNR1EQRHyylzjcjIFaOCJmA==", + "license": "MIT", + "dependencies": { + "@loaders.gl/loader-utils": "4.4.4", + "@loaders.gl/schema": "4.4.4", + "fast-xml-parser": "^5.3.6" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@loaders.gl/zip": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@loaders.gl/zip/-/zip-4.4.4.tgz", + "integrity": "sha512-XzHx8/sfvn8tgfuHOXV8xyyuOMiA0STP5KUvkXD6ntiE37AtShNyseSvjLn2GF3vpuTUuWJ8wgKU6O3+H89s8A==", + "license": "MIT", + "dependencies": { + "@loaders.gl/compression": "4.4.4", + "@loaders.gl/crypto": "4.4.4", + "@loaders.gl/loader-utils": "4.4.4", + "jszip": "^3.1.5", + "md5": "^2.3.0" + }, + "peerDependencies": { + "@loaders.gl/core": "~4.4.0" + } + }, + "node_modules/@luma.gl/core": { + "version": "9.3.6", + "resolved": "https://registry.npmjs.org/@luma.gl/core/-/core-9.3.6.tgz", + "integrity": "sha512-eqHnCPh2xHYkdd9rEkiIIkGMixNiJkq1ROrnTob6npvmZNVHXL0ubIw5KueL7rqW0+J1tm+p2+TXZaCmn0sP7Q==", + "license": "MIT", + "dependencies": { + "@math.gl/types": "^4.1.0", + "@probe.gl/env": "^4.1.1", + "@probe.gl/log": "^4.1.1", + "@probe.gl/stats": "^4.1.1", + "@types/offscreencanvas": "^2019.7.3" + } + }, + "node_modules/@luma.gl/engine": { + "version": "9.3.6", + "resolved": "https://registry.npmjs.org/@luma.gl/engine/-/engine-9.3.6.tgz", + "integrity": "sha512-NYTdhn2NaH/MjN8qXCl2ukrT1Ac9iTKu1mgN0wz11XRd1QYnlMNBXswRROD7IZ2PUsBWdmYHc9qE8wKBQqMuIA==", + "license": "MIT", + "dependencies": { + "@math.gl/core": "^4.1.0", + "@math.gl/types": "^4.1.0", + "@probe.gl/log": "^4.1.1", + "@probe.gl/stats": "^4.1.1" + }, + "peerDependencies": { + "@luma.gl/core": "~9.3.0", + "@luma.gl/shadertools": "~9.3.0" + } + }, + "node_modules/@luma.gl/gltf": { + "version": "9.3.6", + "resolved": "https://registry.npmjs.org/@luma.gl/gltf/-/gltf-9.3.6.tgz", + "integrity": "sha512-9R27aYwvu6KBJzd9Kxs4cqIJpgJsI1AyL6Pn6+5CrmGbaCqMtgWi7Sf9Wo+bqv0PRxwzH0j1oAv7qRk0hGbstw==", + "license": "MIT", + "dependencies": { + "@loaders.gl/core": "~4.4.0", + "@loaders.gl/gltf": "~4.4.0", + "@loaders.gl/textures": "~4.4.0", + "@math.gl/core": "^4.1.0" + }, + "peerDependencies": { + "@luma.gl/core": "~9.3.0", + "@luma.gl/engine": "~9.3.0", + "@luma.gl/shadertools": "~9.3.0" + } + }, + "node_modules/@luma.gl/shadertools": { + "version": "9.3.6", + "resolved": "https://registry.npmjs.org/@luma.gl/shadertools/-/shadertools-9.3.6.tgz", + "integrity": "sha512-dDuD8lCOkAE1L7hJGZEyZAi7upR1HG3wEEIQ1gCLaTTbJWC7tNtnVz853lqUA+VXgjgS9NiQFFRcosiIZmW4Vg==", + "license": "MIT", + "dependencies": { + "@math.gl/core": "^4.1.0", + "@math.gl/types": "^4.1.0" + }, + "peerDependencies": { + "@luma.gl/core": "~9.3.0" + } + }, + "node_modules/@luma.gl/webgl": { + "version": "9.3.6", + "resolved": "https://registry.npmjs.org/@luma.gl/webgl/-/webgl-9.3.6.tgz", + "integrity": "sha512-tGm7FGWPmJKxGZMvkRPRi219x3tKmBxR7Uke09nTp2ujNak/O5V9xPIQ9lUBGTxqAb8U2yjKkXG8j+f/4b2+sw==", + "license": "MIT", + "dependencies": { + "@math.gl/types": "^4.1.0", + "@probe.gl/env": "^4.1.1" + }, + "peerDependencies": { + "@luma.gl/core": "~9.3.0" + } + }, + "node_modules/@mapbox/jsonlint-lines-primitives": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.3.tgz", + "integrity": "sha512-0SElaV0uMxEnxzBhhX9WTuPyUeMsAN/SS0i16tjuba4/mio63MG9khjC1a0JAiPGXAwvwm4UfHJURCN7nyudQg==", + "license": "MIT", + "engines": { + "node": ">= 22" + } + }, + "node_modules/@mapbox/martini": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@mapbox/martini/-/martini-0.2.0.tgz", + "integrity": "sha512-7hFhtkb0KTLEls+TRw/rWayq5EeHtTaErgm/NskVoXmtgAQu/9D299aeyj6mzAR/6XUnYRp2lU+4IcrYRFjVsQ==", + "license": "ISC" + }, + "node_modules/@mapbox/point-geometry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", + "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", + "license": "ISC" + }, + "node_modules/@mapbox/tiny-sdf": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.2.0.tgz", + "integrity": "sha512-LVL4wgI9YAum5V+LNVQO6QgFBPw7/MIIY4XJPNsPDMrjEwcE+JfKk1LuIl8GnF197ejVdC9QdPaxrx5gfgdGXg==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/vector-tile": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", + "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", + "license": "BSD-3-Clause", + "dependencies": { + "@mapbox/point-geometry": "~0.1.0" + } + }, + "node_modules/@maplibre/maplibre-gl-style-spec": { + "version": "19.3.3", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-19.3.3.tgz", + "integrity": "sha512-cOZZOVhDSulgK0meTsTkmNXb1ahVvmTmWmfx9gRBwc6hq98wS9JP35ESIoNq3xqEan+UN+gn8187Z6E4NKhLsw==", + "license": "ISC", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/unitbezier": "^0.0.1", + "json-stringify-pretty-compact": "^3.0.0", + "minimist": "^1.2.8", + "rw": "^1.3.3", + "sort-object": "^3.0.3" + }, + "bin": { + "gl-style-format": "dist/gl-style-format.mjs", + "gl-style-migrate": "dist/gl-style-migrate.mjs", + "gl-style-validate": "dist/gl-style-validate.mjs" + } + }, + "node_modules/@math.gl/core": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@math.gl/core/-/core-4.1.0.tgz", + "integrity": "sha512-FrdHBCVG3QdrworwrUSzXIaK+/9OCRLscxI2OUy6sLOHyHgBMyfnEGs99/m3KNvs+95BsnQLWklVfpKfQzfwKA==", + "license": "MIT", + "dependencies": { + "@math.gl/types": "4.1.0" + } + }, + "node_modules/@math.gl/culling": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@math.gl/culling/-/culling-4.1.0.tgz", + "integrity": "sha512-jFmjFEACnP9kVl8qhZxFNhCyd47qPfSVmSvvjR0/dIL6R9oD5zhR1ub2gN16eKDO/UM7JF9OHKU3EBIfeR7gtg==", + "license": "MIT", + "dependencies": { + "@math.gl/core": "4.1.0", + "@math.gl/types": "4.1.0" + } + }, + "node_modules/@math.gl/geospatial": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@math.gl/geospatial/-/geospatial-4.1.0.tgz", + "integrity": "sha512-BzsUhpVvnmleyYF6qdqJIip6FtIzJmnWuPTGhlBuPzh7VBHLonCFSPtQpbkRuoyAlbSyaGXcVt6p6lm9eK2vtg==", + "license": "MIT", + "dependencies": { + "@math.gl/core": "4.1.0", + "@math.gl/types": "4.1.0" + } + }, + "node_modules/@math.gl/polygon": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@math.gl/polygon/-/polygon-4.1.0.tgz", + "integrity": "sha512-YA/9PzaCRHbIP5/0E9uTYrqe+jsYTQoqoDWhf6/b0Ixz8bPZBaGDEafLg3z7ffBomZLacUty9U3TlPjqMtzPjA==", + "license": "MIT", + "dependencies": { + "@math.gl/core": "4.1.0" + } + }, + "node_modules/@math.gl/sun": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@math.gl/sun/-/sun-4.1.0.tgz", + "integrity": "sha512-i3q6OCBLSZ5wgZVhXg+X7gsjY/TUtuFW/2KBiq/U1ypLso3S4sEykoU/MGjxUv1xiiGtr+v8TeMbO1OBIh/HmA==", + "license": "MIT" + }, + "node_modules/@math.gl/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@math.gl/types/-/types-4.1.0.tgz", + "integrity": "sha512-clYZdHcmRvMzVK5fjeDkQlHUzXQSNdZ7s4xOqC3nJPgz4C/TZkUecTo9YS4PruZqtDda/ag4erndP0MIn40dGA==", + "license": "MIT" + }, + "node_modules/@math.gl/web-mercator": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@math.gl/web-mercator/-/web-mercator-4.1.0.tgz", + "integrity": "sha512-HZo3vO5GCMkXJThxRJ5/QYUYRr3XumfT8CzNNCwoJfinxy5NtKUd7dusNTXn7yJ40UoB8FMIwkVwNlqaiRZZAw==", + "license": "MIT", + "dependencies": { + "@math.gl/core": "4.1.0" + } + }, + "node_modules/@next/env": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.0.tgz", + "integrity": "sha512-Py8zIo+02ht82brwwhTg36iogzFqGLPXlRGKQw5s+qP/kMNc4MAyDeEwBKDijk6zTIbegEgu8Qy7C1LboslQAw==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.0.tgz", + "integrity": "sha512-nUDn7TOGcIeyQni6lZHfzNoo9S0euXnu0jhsbMOmMJUBfgsnESdjN97kM7cBqQxZa8L/bM9om/S5/1dzCrW6wQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.0.tgz", + "integrity": "sha512-1jgudN5haWxiAl3O1ljUS2GfupPmcftu2RYJqZiMJmmbBT5M1XDffjUtRUzP4W3cBHsrvkfOFdQ71hAreNQP6g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.0.tgz", + "integrity": "sha512-RHo7Tcj+jllXUbK7xk2NyIDod3YcCPDZxj1WLIYxd709BQ7WuRYl3OWUNG+WUfqeQBds6kvZYlc42NJJTNi4tQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.0.tgz", + "integrity": "sha512-v6kP8sHYxjO8RwHmWMJSq7VZP2nYCkRVQ0qolh2l6xroe9QjbgV8siTbduED4u0hlk0+tjS6/Tuy4n5XCp+l6g==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.0.tgz", + "integrity": "sha512-zJ2pnoFYB1F4vmEVlb/eSe+VH679zT1VdXlZKX+pE66grOgjmKJHKacf82g/sWE4MQ4Rk2FMBCRnX+l6/TVYzQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.0.tgz", + "integrity": "sha512-rbaIYFt2X9YZBSbH/CwGAjbBG2/MrACCVu2X0+kSykHzHnYH5FjHxwXLkcoJ10cX0aWCEynpu+rP76x0914atg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.0.tgz", + "integrity": "sha512-o1N5TsYc8f/HpGt39OUQpQ9AKIGApd3QLueu7hXk//2xq5Z9OxmV6sQfNp8C7qYmiOlHYODOGqNNa0e9jvchGQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.0.tgz", + "integrity": "sha512-XXIuB1DBRCFwNO6EEzCTMHT5pauwaSj4SWs7CYnME57eaReAKBXCnkUE80p/pAZcewm7hs+vGvNqDPacEXHVkw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.0.tgz", + "integrity": "sha512-9WEbVRRAqJ3YFVqEZIxUqkiO8l1nool1LmNxygr5HWF8AcSYsEpneUDhmjUVJEzO2A04+oPtZdombzzPPkTtgg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodable/entities": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-3.0.0.tgz", + "integrity": "sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@probe.gl/env": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@probe.gl/env/-/env-4.1.1.tgz", + "integrity": "sha512-+68seNDMVsEegRB47pFA/Ws1Fjy8agcFYXxzorKToyPcD6zd+gZ5uhwoLd7TzsSw6Ydns//2KEszWn+EnNHTbA==", + "license": "MIT" + }, + "node_modules/@probe.gl/log": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@probe.gl/log/-/log-4.1.1.tgz", + "integrity": "sha512-kcZs9BT44pL7hS1OkRGKYRXI/SN9KejUlPD+BY40DguRLzdC5tLG/28WGMyfKdn/51GT4a0p+0P8xvDn1Ez+Kg==", + "license": "MIT", + "dependencies": { + "@probe.gl/env": "4.1.1" + } + }, + "node_modules/@probe.gl/stats": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@probe.gl/stats/-/stats-4.1.1.tgz", + "integrity": "sha512-4VpAyMHOqydSvPlEyHwXaE+AkIdR03nX+Qhlxsk2D/IW4OVmDZgIsvJB1cDzyEEtcfKcnaEbfXeiPgejBceT6g==", + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", + "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@turf/boolean-clockwise": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@turf/boolean-clockwise/-/boolean-clockwise-5.1.5.tgz", + "integrity": "sha512-FqbmEEOJ4rU4/2t7FKx0HUWmjFEVqR+NJrFP7ymGSjja2SQ7Q91nnBihGuT+yuHHl6ElMjQ3ttsB/eTmyCycxA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^5.1.5", + "@turf/invariant": "^5.1.5" + } + }, + "node_modules/@turf/clone": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-5.1.5.tgz", + "integrity": "sha512-//pITsQ8xUdcQ9pVb4JqXiSqG4dos5Q9N4sYFoWghX21tfOV2dhc5TGqYOhnHrQS7RiKQL1vQ48kIK34gQ5oRg==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^5.1.5" + } + }, + "node_modules/@turf/helpers": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-5.1.5.tgz", + "integrity": "sha512-/lF+JR+qNDHZ8bF9d+Cp58nxtZWJ3sqFe6n3u3Vpj+/0cqkjk4nXKYBSY0azm+GIYB5mWKxUXvuP/m0ZnKj1bw==", + "license": "MIT" + }, + "node_modules/@turf/invariant": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-5.2.0.tgz", + "integrity": "sha512-28RCBGvCYsajVkw2EydpzLdcYyhSA77LovuOvgCJplJWaNVyJYH6BOR3HR9w50MEkPqb/Vc/jdo6I6ermlRtQA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^5.1.5" + } + }, + "node_modules/@turf/meta": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-5.2.0.tgz", + "integrity": "sha512-ZjQ3Ii62X9FjnK4hhdsbT+64AYRpaI8XMBMcyftEOGSmPMUVnkbvuv3C9geuElAXfQU7Zk1oWGOcrGOD9zr78Q==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^5.1.5" + } + }, + "node_modules/@turf/rewind": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@turf/rewind/-/rewind-5.1.5.tgz", + "integrity": "sha512-Gdem7JXNu+G4hMllQHXRFRihJl3+pNl7qY+l4qhQFxq+hiU1cQoVFnyoleIqWKIrdK/i2YubaSwc3SCM7N5mMw==", + "license": "MIT", + "dependencies": { + "@turf/boolean-clockwise": "^5.1.5", + "@turf/clone": "^5.1.5", + "@turf/helpers": "^5.1.5", + "@turf/invariant": "^5.1.5", + "@turf/meta": "^5.1.5" + } + }, + "node_modules/@types/brotli": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/brotli/-/brotli-1.3.5.tgz", + "integrity": "sha512-9xoNr+bcxT236/7ZgcWw/6Pb2RRetE13p4bFy1xYSckKwyOiRfmInay8baUWZgH7/284Wl6IPe7+nOI9+OQg/A==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/crypto-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz", + "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==", + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/mapbox-gl": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-3.4.1.tgz", + "integrity": "sha512-NsGKKtgW93B+UaLPti6B7NwlxYlES5DpV5Gzj9F75rK5ALKsqSk15CiEHbOnTr09RGbr6ZYiCdI+59NNNcAImg==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/node": { + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/offscreencanvas": { + "version": "2019.7.3", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", + "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==", + "license": "MIT" + }, + "node_modules/@types/pako": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.7.tgz", + "integrity": "sha512-YBtzT2ztNF6R/9+UXj2wTGFnC9NklAnASt3sC0h2m1bbH7G6FyBIkt4AN8ThZpNfxUo1b2iMVO0UawiJymEt8A==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.31", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", + "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/a5-js": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/a5-js/-/a5-js-0.7.3.tgz", + "integrity": "sha512-3aoMwHmNkyuMDHS4q6GRRInpOawamen2pokIbc0MQmR9cqG0Y9+B0bZpzswwetjrSG2ckbYtShH+nKru6+3O5Q==", + "license": "Apache-2.0", + "dependencies": { + "gl-matrix": "^3.4.3" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anynum": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz", + "integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/apache-arrow": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-21.2.0.tgz", + "integrity": "sha512-Hxe6Agq26gQOM954qpzYSllJBPJl+e16U5CkfuMUhLrNba+5nKkttIVlflaovN6oaTratqMGAO8H5u/aNhmHWQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^25.2.0", + "flatbuffers": "^25.1.24", + "json-with-bigint": "^3.5.3", + "tslib": "^2.6.2" + }, + "bin": { + "arrow2csv": "bin/arrow2csv.js" + } + }, + "node_modules/apache-arrow/node_modules/@types/node": { + "version": "25.9.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.5.tgz", + "integrity": "sha512-OScDchr2fwuUmWdf4kZ9h7PcJiYDVInhJizG/biAq3cAvqwYktuy/TYGGdZNMtNTFUP7rnb0NU4TUdm82kt4Rg==", + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/apache-arrow/node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "license": "MIT" + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.5.4", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.4.tgz", + "integrity": "sha512-MaU0U/za7N3r6brxD4YB/l4NSrFzLPlANv6wEuQVaIPlD3L4W9rFcQPbL/EilY9BHhHvhfcz3gInDLrEtWT4EA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.6", + "caniuse-lite": "^1.0.30001806", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.14", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.14.tgz", + "integrity": "sha512-JyJ954WzuIR8/FFzX0o5krdSTrBAkcCSRfWSleRsIHSWV+cZe2FI1PKggVkFke1hBldRs+LRxUczzE9iPmgZww==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "license": "MIT", + "optional": true, + "dependencies": { + "base64-js": "^1.1.2" + } + }, + "node_modules/browserslist": { + "version": "4.28.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", + "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.12", + "caniuse-lite": "^1.0.30001809", + "electron-to-chromium": "^1.5.402", + "node-releases": "^2.0.53", + "update-browserslist-db": "^1.3.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buf-compare": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buf-compare/-/buf-compare-1.0.1.tgz", + "integrity": "sha512-Bvx4xH00qweepGc43xFvMs5BKASXTbHaHm6+kDYIK9p/4iFwjATQkmPKHQSgJZzKbAymhztRbXUf1Nqhzl73/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytewise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bytewise/-/bytewise-1.1.0.tgz", + "integrity": "sha512-rHuuseJ9iQ0na6UDhnrRVDh8YnWVlU6xM3VH6q/+yHDeUH2zIhUzP+2/h3LIrhLDBtTqzWpE3p3tP/boefskKQ==", + "license": "MIT", + "dependencies": { + "bytewise-core": "^1.2.2", + "typewise": "^1.0.3" + } + }, + "node_modules/bytewise-core": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bytewise-core/-/bytewise-core-1.2.3.tgz", + "integrity": "sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA==", + "license": "MIT", + "dependencies": { + "typewise-core": "^1.2" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001809", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001809.tgz", + "integrity": "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/core-assert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/core-assert/-/core-assert-0.2.1.tgz", + "integrity": "sha512-IG97qShIP+nrJCXMCgkNZgH7jZQ4n8RpPyPeXX++T6avR/KhLhgLiHKoEn5Rc1KjfycSfA9DMa6m+4C4eguHhw==", + "license": "MIT", + "dependencies": { + "buf-compare": "^1.0.0", + "is-error": "^2.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-strict-equal": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/deep-strict-equal/-/deep-strict-equal-0.2.0.tgz", + "integrity": "sha512-3daSWyvZ/zwJvuMGlzG1O+Ow0YSadGfb3jsh9xoCutv2tWyB9dA4YvR9L9/fSdDZa2dByYQe+TqapSGUrjnkoA==", + "license": "MIT", + "dependencies": { + "core-assert": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/draco3d": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz", + "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==", + "license": "Apache-2.0" + }, + "node_modules/earcut": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", + "license": "ISC" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.407", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.407.tgz", + "integrity": "sha512-4R8XgQOdfxexCd/u63lRm6wCHjECwI45MV9wxAs2ggtfWe2hwlo1ql97jKsju2IcJ+jFSTwBssyYoiWhh7mauQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-xml-builder": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.1.tgz", + "integrity": "sha512-pIM/1n3ntFXKYrUZwW7QCK0gAW7XY+wzj1YMIV3tLDvPj/V+zTGJK5e3/4WJfwj0qWw2ElNXiTixda/R+3YSug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.6.2", + "xml-naming": "^0.3.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.11.0.tgz", + "integrity": "sha512-9IGxMqvqLOnqP+Egi1nqDHKv5k8aZ7r9n558enxcucmyVGEBNPAU+MOg/8jPIS7rO7sSq4gFm1/nHtiaubMruw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^3.0.0", + "fast-xml-builder": "^1.2.0", + "is-unsafe": "^2.0.0", + "path-expression-matcher": "^1.6.2", + "strnum": "^2.4.2", + "xml-naming": "^0.3.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fflate": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", + "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==", + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flatbuffers": { + "version": "25.9.23", + "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-25.9.23.tgz", + "integrity": "sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==", + "license": "Apache-2.0" + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gl-matrix": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.4.tgz", + "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==", + "license": "MIT" + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/h3-js": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/h3-js/-/h3-js-4.5.0.tgz", + "integrity": "sha512-uKmdPc+DuarnR+XqZxEuWOMw7KzzKROrx3MLeJpFnMOs78S9M5eZ+X5RieS9UcSFQqbeXzbfWuX/W9Pyajinqw==", + "license": "Apache-2.0", + "engines": { + "node": ">=4", + "npm": ">=3", + "yarn": ">=1.3.0" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/image-size": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz", + "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==", + "license": "MIT", + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-error": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.2.tgz", + "integrity": "sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==", + "license": "MIT" + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unsafe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-2.0.0.tgz", + "integrity": "sha512-2LdV822R+wmI86unXA93WCFpL6g+av8ynWk0nrHyJqGop5VoocYsSLFgN8jrfalT6iGeLNM4KXuVSsULP53kEA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/json-stringify-pretty-compact": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz", + "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==", + "license": "MIT" + }, + "node_modules/json-with-bigint": { + "version": "3.5.11", + "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.11.tgz", + "integrity": "sha512-WvkM9Hfb9kqzCcbsvpwfWDvdfGZDhYuCoaCwHRe5q3LtULKkbrI/L6JYcN8owflgA3di5dP2yVAV2NVCXkgtkA==", + "license": "MIT" + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ktx-parse": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.7.1.tgz", + "integrity": "sha512-FeA3g56ksdFNwjXJJsc1CCc7co+AJYDp6ipIp878zZ2bU8kWROatLYf39TQEd4/XRSUvBXovQ8gaVKWPXsCLEQ==", + "license": "MIT" + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha512-ZYvPPOMqUwPoDsbJaR10iQJYnMuZhRTvHYl62ErLIEX7RgFlziSBUUvrt3OVfc47QlHHpzPZYP17g3Fv7oeJkg==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lucide-react": { + "version": "0.330.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.330.0.tgz", + "integrity": "sha512-CQwY+Fpbt2kxCoVhuN0RCZDCYlbYnqB870Bl/vIQf3ER/cnDDQ6moLmEkguRyruAUGd4j3Lc4mtnJosXnqHheA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/lz4js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/lz4js/-/lz4js-0.2.0.tgz", + "integrity": "sha512-gY2Ia9Lm7Ep8qMiuGRhvUq0Q7qUereeldZPP1PMEJxPtEWHJLqw9pgX68oHajBH0nzJK4MaZEA/YNV3jT8u8Bg==", + "license": "ISC", + "optional": true + }, + "node_modules/mapbox-gl": { + "version": "3.28.1", + "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-3.28.1.tgz", + "integrity": "sha512-f8bCHFzZ51bKig7rnD7e08aoFLOV3MNFZduspZ4lgOgiaNVp9sw4NSWcgo3IWTyekYKKXjiICD2BP2o4DiYfxw==", + "license": "SEE LICENSE IN LICENSE.txt", + "workspaces": [ + "src/style-spec", + "plugins/mapbox-gl-pmtiles-provider", + "test/bundlers/*", + "test/build/typings" + ] + }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "license": "BSD-3-Clause", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mjolnir.js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mjolnir.js/-/mjolnir.js-3.0.1.tgz", + "integrity": "sha512-/RMi8Jm3NKleOkVI8D2ai+1OVwtfRJsSVBVjbTXNm83nfsN4uORYaN3u1/hsg5CqVI+di8enTkvgDNDOywn6cQ==", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/next/-/next-14.1.0.tgz", + "integrity": "sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q==", + "deprecated": "This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details.", + "license": "MIT", + "dependencies": { + "@next/env": "14.1.0", + "@swc/helpers": "0.5.2", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=18.17.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "14.1.0", + "@next/swc-darwin-x64": "14.1.0", + "@next/swc-linux-arm64-gnu": "14.1.0", + "@next/swc-linux-arm64-musl": "14.1.0", + "@next/swc-linux-x64-gnu": "14.1.0", + "@next/swc-linux-x64-musl": "14.1.0", + "@next/swc-win32-arm64-msvc": "14.1.0", + "@next/swc-win32-ia32-msvc": "14.1.0", + "@next/swc-win32-x64-msvc": "14.1.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/node-releases": { + "version": "2.0.53", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz", + "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/path-expression-matcher": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.2.tgz", + "integrity": "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/pbf": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", + "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "ieee754": "^1.1.12", + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", + "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/preact": { + "version": "10.29.8", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.8.tgz", + "integrity": "sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==", + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + }, + "peerDependencies": { + "preact-render-to-string": ">=5" + }, + "peerDependenciesMeta": { + "preact-render-to-string": { + "optional": true + } + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/protocol-buffers-schema": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.1.tgz", + "integrity": "sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==", + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-map-gl": { + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/react-map-gl/-/react-map-gl-7.1.9.tgz", + "integrity": "sha512-KsCc8Gyn05wVGlHZoopaiiCr0RCAQ6LDISo5sEy1/pV/d7RlozkF946tiX7IgyijJQMRujHol5QdwUPESjh73w==", + "license": "MIT", + "dependencies": { + "@maplibre/maplibre-gl-style-spec": "^19.2.1", + "@types/mapbox-gl": ">=1.0.0" + }, + "peerDependencies": { + "mapbox-gl": ">=1.13.0", + "maplibre-gl": ">=1.13.0 <5.0.0", + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + }, + "peerDependenciesMeta": { + "mapbox-gl": { + "optional": true + }, + "maplibre-gl": { + "optional": true + } + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-protobuf-schema": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", + "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "license": "MIT", + "dependencies": { + "protocol-buffers-schema": "^3.3.1" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, + "node_modules/snappyjs": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/snappyjs/-/snappyjs-0.6.1.tgz", + "integrity": "sha512-YIK6I2lsH072UE0aOFxxY1dPDCS43I5ktqHpeAsuLNYWkE5pGxRGWfDM4/vSUfNzXjC1Ivzt3qx31PCLmc9yqg==", + "license": "MIT" + }, + "node_modules/sort-asc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/sort-asc/-/sort-asc-0.2.0.tgz", + "integrity": "sha512-umMGhjPeHAI6YjABoSTrFp2zaBtXBej1a0yKkuMUyjjqu6FJsTF+JYwCswWDg+zJfk/5npWUUbd33HH/WLzpaA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-desc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/sort-desc/-/sort-desc-0.2.0.tgz", + "integrity": "sha512-NqZqyvL4VPW+RAxxXnB8gvE1kyikh8+pR+T+CXLksVRN9eiQqkQlPwqWYU0mF9Jm7UnctShlxLyAt1CaBOTL1w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-object": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sort-object/-/sort-object-3.0.3.tgz", + "integrity": "sha512-nK7WOY8jik6zaG9CRwZTaD5O7ETWDLZYMM12pqY8htll+7dYeqGfEUPcUBHOpSJg2vJOrvFIY2Dl5cX2ih1hAQ==", + "license": "MIT", + "dependencies": { + "bytewise": "^1.1.0", + "get-value": "^2.0.2", + "is-extendable": "^0.1.1", + "sort-asc": "^0.2.0", + "sort-desc": "^0.2.0", + "union-value": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/strnum": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.2.tgz", + "integrity": "sha512-rDG3Ah4TV0k1hWvLSzkZtMmLN9+eS+h3knq4MP6A42Y3Yh5qGNnOUs1jJkoSr8FG5dsL28c7KgkIBzSEykqtuw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "anynum": "^1.0.1" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwind-merge": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.1.tgz", + "integrity": "sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/texture-compressor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/texture-compressor/-/texture-compressor-1.0.2.tgz", + "integrity": "sha512-dStVgoaQ11mA5htJ+RzZ51ZxIZqNOgWKAIvtjLrW1AliQQLCmrDqNzQZ8Jh91YealQ95DXt4MEduLzJmbs6lig==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.10", + "image-size": "^0.7.4" + }, + "bin": { + "texture-compressor": "bin/texture-compressor.js" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typewise": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typewise/-/typewise-1.0.3.tgz", + "integrity": "sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ==", + "license": "MIT", + "dependencies": { + "typewise-core": "^1.2.0" + } + }, + "node_modules/typewise-core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/typewise-core/-/typewise-core-1.2.0.tgz", + "integrity": "sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.1.tgz", + "integrity": "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/xml-naming": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.3.0.tgz", + "integrity": "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/zstd-codec": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/zstd-codec/-/zstd-codec-0.1.5.tgz", + "integrity": "sha512-v3fyjpK8S/dpY/X5WxqTK3IoCnp/ZOLxn144GZVlNUjtwAchzrVo03h+oMATFhCIiJ5KTr4V3vDQQYz4RU684g==", + "license": "MIT", + "optional": true + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..e4a9de8 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,34 @@ +{ + "name": "thermoagent-ai-frontend", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev -p 3000", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@deck.gl/core": "^9.0.0", + "@deck.gl/geo-layers": "^9.3.10", + "@deck.gl/layers": "^9.0.0", + "@deck.gl/react": "^9.0.0", + "clsx": "^2.1.0", + "lucide-react": "^0.330.0", + "mapbox-gl": "^3.1.2", + "next": "14.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-map-gl": "^7.1.7", + "tailwind-merge": "^2.2.1" + }, + "devDependencies": { + "@types/node": "^20.11.0", + "@types/react": "^18.2.0", + "@types/react-dom": "^18.2.0", + "autoprefixer": "^10.4.17", + "postcss": "^8.4.35", + "tailwindcss": "^3.4.1", + "typescript": "^5.3.3" + } +} diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/frontend/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/frontend/public/data/parcel_portfolio_san_jose_sample.geojson b/frontend/public/data/parcel_portfolio_san_jose_sample.geojson new file mode 100644 index 0000000..bc1638a --- /dev/null +++ b/frontend/public/data/parcel_portfolio_san_jose_sample.geojson @@ -0,0 +1,267 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "parcel_id": "APN-259-27-014", + "name": "Diridon Gateway", + "city": "San Jose", + "state": "CA", + "lot_acres": 3.33, + "zoning": "DC — Downtown Commercial", + "proposed_use": "Mixed-use office / residential", + "proposed_gsf": 420000, + "stories": 12 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -121.90079081582293, + 37.3300500845841 + ], + [ + -121.89920918417708, + 37.3300500845841 + ], + [ + -121.89920918417708, + 37.330657470395565 + ], + [ + -121.8995650512974, + 37.3309499154159 + ], + [ + -121.90079081582293, + 37.3309499154159 + ], + [ + -121.90079081582293, + 37.3300500845841 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "parcel_id": "APN-264-11-032", + "name": "SoFA District Infill", + "city": "San Jose", + "state": "CA", + "lot_acres": 1.76, + "zoning": "DC — Downtown Commercial", + "proposed_use": "Residential over ground-floor retail", + "proposed_gsf": 185000, + "stories": 8 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -121.88653662145136, + 37.32966256343807 + ], + [ + -121.88546337854864, + 37.32966256343807 + ], + [ + -121.88546337854864, + 37.330337436561926 + ], + [ + -121.88653662145136, + 37.330337436561926 + ], + [ + -121.88653662145136, + 37.32966256343807 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "parcel_id": "APN-249-40-008", + "name": "Japantown Commons", + "city": "San Jose", + "state": "CA", + "lot_acres": 2.65, + "zoning": "MUN — Mixed Use Neighborhood", + "proposed_use": "Affordable residential", + "proposed_gsf": 240000, + "stories": 6 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -121.89467800912556, + 37.348505093042505 + ], + [ + -121.89376269680606, + 37.348505093042505 + ], + [ + -121.89376269680606, + 37.34907423604362 + ], + [ + -121.89332199087445, + 37.34907423604362 + ], + [ + -121.89332199087445, + 37.34949490695749 + ], + [ + -121.89467800912556, + 37.34949490695749 + ], + [ + -121.89467800912556, + 37.348505093042505 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "parcel_id": "APN-467-22-105", + "name": "SJSU South Campus Edge", + "city": "San Jose", + "state": "CA", + "lot_acres": 2.73, + "zoning": "DC — Downtown Commercial", + "proposed_use": "Student housing", + "proposed_gsf": 310000, + "stories": 10 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -121.87973436319149, + 37.33361757189649 + ], + [ + -121.87826563680852, + 37.33361757189649 + ], + [ + -121.87826563680852, + 37.33438242810352 + ], + [ + -121.87973436319149, + 37.33438242810352 + ], + [ + -121.87973436319149, + 37.33361757189649 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "parcel_id": "APN-259-33-041", + "name": "Guadalupe River North", + "city": "San Jose", + "state": "CA", + "lot_acres": 4.57, + "zoning": "IP — Industrial Park", + "proposed_use": "Light industrial / flex", + "proposed_gsf": 150000, + "stories": 3 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -121.9059039278954, + 37.341460101500914 + ], + [ + -121.90409607210461, + 37.341460101500914 + ], + [ + -121.90409607210461, + 37.34218896447468 + ], + [ + -121.90450283965752, + 37.34253989849908 + ], + [ + -121.9059039278954, + 37.34253989849908 + ], + [ + -121.9059039278954, + 37.341460101500914 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "parcel_id": "APN-472-09-017", + "name": "Spartan Keyes", + "city": "San Jose", + "state": "CA", + "lot_acres": 2.34, + "zoning": "RM — Residential Medium", + "proposed_use": "Townhome development", + "proposed_gsf": 98000, + "stories": 3 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -121.88359301321476, + 37.317595076125684 + ], + [ + -121.8240698678523, + 37.317595076125684 + ], + [ + -121.88240698678523, + 37.31840492387431 + ], + [ + -121.88359301321476, + 37.31840492387431 + ], + [ + -121.88359301321476, + 37.317595076125684 + ] + ] + ] + } + } + ] +} diff --git a/frontend/src/app/api/hotspots/route.ts b/frontend/src/app/api/hotspots/route.ts new file mode 100644 index 0000000..3668ea3 --- /dev/null +++ b/frontend/src/app/api/hotspots/route.ts @@ -0,0 +1,148 @@ +import { NextResponse } from 'next/server'; + +export async function GET() { + try { + const backendRes = await fetch('http://localhost:8000/api/v1/hotspots', { cache: 'no-store' }); + if (backendRes.ok) { + const data = await backendRes.json(); + return NextResponse.json(data); + } + } catch (err) { + console.warn('Proxy to FastAPI failed, generating client fallback hotspots...', err); + } + + // Standalone fallback response if backend is offline + return NextResponse.json({ + status: "success", + data: { + type: "FeatureCollection", + features: [ + { + type: "Feature", + properties: { + parcel_id: "APN-259-27-014", + name: "Diridon Gateway", + city: "San Jose", + state: "CA", + lot_acres: 3.33, + zoning: "DC — Downtown Commercial", + proposed_use: "Mixed-use office / residential", + stories: 12, + height: 42, + temp_delta_f: 4.8, + ambient_temp_f: 87.3, + priority_score: 2266.7, + is_hotspot: true, + albedo: 0.18, + canopy_pct: 0.05, + roof_area_m2: 3500 + }, + geometry: { + type: "Polygon", + coordinates: [[ + [-121.90079, 37.33005], + [-121.89920, 37.33005], + [-121.89920, 37.33065], + [-121.89956, 37.33094], + [-121.90079, 37.33094], + [-121.90079, 37.33005] + ]] + } + }, + { + type: "Feature", + properties: { + parcel_id: "APN-264-11-032", + name: "SoFA District Infill", + city: "San Jose", + state: "CA", + lot_acres: 1.76, + zoning: "DC — Downtown Commercial", + proposed_use: "Residential over ground-floor retail", + stories: 8, + height: 28, + temp_delta_f: 5.2, + ambient_temp_f: 87.7, + priority_score: 955.5, + is_hotspot: true, + albedo: 0.20, + canopy_pct: 0.08, + roof_area_m2: 2150 + }, + geometry: { + type: "Polygon", + coordinates: [[ + [-121.88653, 37.32966], + [-121.88546, 37.32966], + [-121.88546, 37.33033], + [-121.88653, 37.33033], + [-121.88653, 37.32966] + ]] + } + }, + { + type: "Feature", + properties: { + parcel_id: "APN-467-22-105", + name: "SJSU South Campus Edge", + city: "San Jose", + state: "CA", + lot_acres: 2.73, + zoning: "DC — Downtown Commercial", + proposed_use: "Student housing", + stories: 10, + height: 35, + temp_delta_f: 3.9, + ambient_temp_f: 86.4, + priority_score: 1123.2, + is_hotspot: true, + albedo: 0.22, + canopy_pct: 0.10, + roof_area_m2: 2880 + }, + geometry: { + type: "Polygon", + coordinates: [[ + [-121.87973, 37.33361], + [-121.87826, 37.33361], + [-121.87826, 37.33438], + [-121.87973, 37.33438], + [-121.87973, 37.33361] + ]] + } + }, + { + type: "Feature", + properties: { + parcel_id: "APN-472-09-017", + name: "Spartan Keyes", + city: "San Jose", + state: "CA", + lot_acres: 2.34, + zoning: "RM — Residential Medium", + proposed_use: "Townhome development", + stories: 3, + height: 10.5, + temp_delta_f: 1.8, + ambient_temp_f: 84.3, + priority_score: 750.0, + is_hotspot: false, + albedo: 0.30, + canopy_pct: 0.18, + roof_area_m2: 3000 + }, + geometry: { + type: "Polygon", + coordinates: [[ + [-121.88359, 37.31759], + [-121.88240, 37.31759], + [-121.88240, 37.31840], + [-121.88359, 37.31840], + [-121.88359, 37.31759] + ]] + } + } + ] + } + }); +} diff --git a/frontend/src/app/api/pipeline/route.ts b/frontend/src/app/api/pipeline/route.ts new file mode 100644 index 0000000..82287dc --- /dev/null +++ b/frontend/src/app/api/pipeline/route.ts @@ -0,0 +1,50 @@ +import { NextRequest, NextResponse } from 'next/server'; + +export async function POST(req: NextRequest) { + const { searchParams } = new URL(req.url); + const targetAlbedo = searchParams.get('target_albedo') || '0.70'; + const canopyArea = searchParams.get('canopy_area') || '250.0'; + + try { + const backendRes = await fetch(`http://localhost:8000/api/v1/pipeline/run?target_albedo=${targetAlbedo}&canopy_area=${canopyArea}`, { + method: 'POST' + }); + if (backendRes.ok) { + const data = await backendRes.json(); + return NextResponse.json(data); + } + } catch (err) { + console.warn('Backend pipeline call failed, returning proxy mock steps...', err); + } + + return NextResponse.json({ + status: "success", + total_execution_time_ms: 124.5, + steps: [ + { + agent_name: "AnomalyDetectorAgent", + status: "success", + execution_time_ms: 32.1, + summary: "Detected 3 heat anomalies out of 4 parcels scanned (ΔT >= +3.5°F)." + }, + { + agent_name: "BuildingAuditorAgent", + status: "success", + execution_time_ms: 28.4, + summary: "Audited structure roof areas and SRI albedo baselines." + }, + { + agent_name: "MitigationSimulatorAgent", + status: "success", + execution_time_ms: 41.2, + summary: `Modeled cool roof (Albedo=${targetAlbedo}) & ${canopyArea}m² greening.` + }, + { + agent_name: "ReportGeneratorAgent", + status: "success", + execution_time_ms: 22.8, + summary: "Enriched GeoJSON feature collection and generated executive PDF." + } + ] + }); +} diff --git a/frontend/src/app/api/simulate/route.ts b/frontend/src/app/api/simulate/route.ts new file mode 100644 index 0000000..ec47a61 --- /dev/null +++ b/frontend/src/app/api/simulate/route.ts @@ -0,0 +1,39 @@ +import { NextRequest, NextResponse } from 'next/server'; + +export async function POST(req: NextRequest) { + try { + const body = await req.json(); + const backendRes = await fetch('http://localhost:8000/api/v1/simulate', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body) + }); + if (backendRes.ok) { + const data = await backendRes.json(); + return NextResponse.json(data); + } + } catch (err) { + console.warn('Proxy simulate request failed, computing fallback...', err); + } + + // Local fallback calculation + const { roof_area = 1200, target_albedo = 0.7, canopy_area = 250 } = await req.json(); + const cool_roof_drop = (roof_area / 1000.0) * 2.5 * (target_albedo - 0.2); + const greenery_drop = (canopy_area / 1000.0) * 1.8; + const total_drop = cool_roof_drop + greenery_drop; + const annual_savings = roof_area * 4.5; + const payback = (roof_area * 25.0) / annual_savings; + + return NextResponse.json({ + status: "success", + simulation: { + projected_temp_drop_f: Number(total_drop.toFixed(2)), + annual_hvac_savings_usd: Number(annual_savings.toFixed(2)), + payback_years: Number(payback.toFixed(1)), + cool_roof_drop_f: Number(cool_roof_drop.toFixed(2)), + greenery_drop_f: Number(greenery_drop.toFixed(2)), + co2_reduction_tons: Number((roof_area * 0.015).toFixed(2)), + estimated_retrofit_cost_usd: Number((roof_area * 25.0).toFixed(2)) + } + }); +} diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css new file mode 100644 index 0000000..685ea27 --- /dev/null +++ b/frontend/src/app/globals.css @@ -0,0 +1,63 @@ +@import 'mapbox-gl/dist/mapbox-gl.css'; +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; +} + +body { + background-color: #030712; + color: #f8fafc; + font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; + overflow-x: hidden; +} + +/* Custom scrollbars */ +::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +::-webkit-scrollbar-track { + background: #0f172a; +} + +::-webkit-scrollbar-thumb { + background: #334155; + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: #10b981; +} + +/* Deck.gl Tooltip Customization */ +.deck-tooltip { + font-family: inherit; + font-size: 12px; + background-color: rgba(15, 23, 42, 0.95) !important; + color: #ffffff !important; + border: 1px solid rgba(16, 185, 129, 0.4) !important; + border-radius: 8px !important; + padding: 8px 12px !important; + box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5) !important; + backdrop-filter: blur(8px) !important; +} + +@keyframes pulseGlow { + 0%, 100% { + opacity: 0.8; + box-shadow: 0 0 15px rgba(16, 185, 129, 0.4); + } + 50% { + opacity: 1; + box-shadow: 0 0 25px rgba(16, 185, 129, 0.8); + } +} + +.animate-pulse-glow { + animation: pulseGlow 2.5s infinite ease-in-out; +} diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx new file mode 100644 index 0000000..6eb0053 --- /dev/null +++ b/frontend/src/app/layout.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from 'next'; +import './globals.css'; + +export const metadata: Metadata = { + title: 'ThermoAgent-AI | San Jose FortyGuard Thermal Intelligence Platform', + description: 'Multi-agent urban heat anomaly detector and parametric cool-roof mitigation optimizer for San Jose.', +}; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + {children} + + + ); +} diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx new file mode 100644 index 0000000..bb5c377 --- /dev/null +++ b/frontend/src/app/page.tsx @@ -0,0 +1,144 @@ +'use client'; +import React, { useState, useEffect } from 'react'; +import { Thermometer, ShieldAlert, Cpu, Sparkles, RefreshCw, Layers } from 'lucide-react'; +import MetricsBar from '../components/MetricsBar'; +import MapViewport from '../components/MapViewport'; +import BuildingDrawer from '../components/BuildingDrawer'; +import TimelineSlider from '../components/TimelineSlider'; +import AgentStatusPanel from '../components/AgentStatusPanel'; +import { fetchHotspots, triggerPipelineRun } from '../lib/api'; + +export default function DashboardPage() { + const [geoJsonData, setGeoJsonData] = useState(null); + const [selectedBuilding, setSelectedBuilding] = useState(null); + const [timelineStep, setTimelineStep] = useState(1); // Default: 2026 Peak Heatwave + const [pipelineSteps, setPipelineSteps] = useState([]); + const [loading, setLoading] = useState(true); + const [runningPipeline, setRunningPipeline] = useState(false); + const [summaryMetrics, setSummaryMetrics] = useState({ + hotspotCount: 3, + totalParcels: 6, + avgTempF: 86.2, + projectedCoolingF: 4.3, + annualSavingsUsd: 68625.0, + co2Tons: 228.75 + }); + + const loadData = async () => { + setLoading(true); + try { + const res = await fetchHotspots(); + if (res && res.data) { + setGeoJsonData(res.data); + if (res.steps) { + setPipelineSteps(res.steps); + } + // Select first parcel feature as initial target + if (res.data.features && res.data.features.length > 0) { + setSelectedBuilding(res.data.features[1] || res.data.features[0]); + } + } + } catch (err) { + console.error('Error loading hotspots data:', err); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + loadData(); + }, []); + + const handleRunFullPipeline = async () => { + setRunningPipeline(true); + try { + const res = await triggerPipelineRun(0.70, 250); + if (res && res.steps) { + setPipelineSteps(res.steps); + } + if (res && res.final_geojson) { + setGeoJsonData(res.final_geojson); + } + } catch (err) { + console.error('Pipeline execution error:', err); + } finally { + setRunningPipeline(false); + } + }; + + return ( +
+ {/* Top Header */} +
+
+
+ +
+
+
+

ThermoAgent-AI

+ + FortyGuard San Jose Unified Pipeline + +
+

+ Multi-Agent Thermal Anomaly Isolator & Parametric Structure Mitigation Optimizer +

+
+
+ +
+ +
+
+ + {/* Citywide Metrics Bar */} + + + {/* Multi-Agent Status Panel */} + + + {/* Main Viewport & Inspection Split Screen */} +
+ {/* Left Column: 3D Map Viewport + Timeline Slider */} +
+ setSelectedBuilding(b)} + selectedParcelId={selectedBuilding?.properties?.parcel_id} + /> + + setTimelineStep(st)} + /> +
+ + {/* Right Column: Structure Mitigation Optimizer Drawer */} +
+ +
+
+
+ ); +} diff --git a/frontend/src/components/AgentStatusPanel.tsx b/frontend/src/components/AgentStatusPanel.tsx new file mode 100644 index 0000000..4e69d2e --- /dev/null +++ b/frontend/src/components/AgentStatusPanel.tsx @@ -0,0 +1,109 @@ +'use client'; +import React from 'react'; +import { Cpu, CheckCircle2, Clock, PlayCircle, AlertCircle, ArrowRight } from 'lucide-react'; + +interface StepLog { + agent_name: str; + status: str; + summary: str; + execution_time_ms?: number; +} + +interface AgentStatusPanelProps { + steps?: StepLog[]; + isRunning?: boolean; + onRunPipeline?: () => void; +} + +const AGENT_LABELS: Record = { + AnomalyDetectorAgent: { + label: 'Agent 1: Anomaly Detector', + role: 'Thermal Isothermal Scanner', + desc: 'Scans 2m ambient heatmaps for ΔT ≥ +3.5°F anomalies' + }, + BuildingAuditorAgent: { + label: 'Agent 2: Building Auditor', + role: 'Structure Causality Scorer', + desc: 'Calculates roof area, baseline SRI albedo & priority score' + }, + MitigationSimulatorAgent: { + label: 'Agent 3: Mitigation Simulator', + role: 'Cool Roof & Greening ROI Engine', + desc: 'Models temperature drop, HVAC cost savings & payback' + }, + ReportGeneratorAgent: { + label: 'Agent 4: Report Generator', + role: 'GeoJSON & PDF Synthesizer', + desc: 'Generates enriched GeoJSON and executive audit report' + } +}; + +export default function AgentStatusPanel({ steps = [], isRunning = false, onRunPipeline }: AgentStatusPanelProps) { + const agentKeys = ['AnomalyDetectorAgent', 'BuildingAuditorAgent', 'MitigationSimulatorAgent', 'ReportGeneratorAgent']; + const stepMap = new Map(steps.map(s => [s.agent_name, s])); + + return ( +
+
+
+ +

Multi-Agent Autonomous Pipeline

+
+ +
+ + {/* Agents Workflow List */} +
+ {agentKeys.map((key, idx) => { + const info = AGENT_LABELS[key]; + const stepData = stepMap.get(key); + const isDone = !!stepData; + + return ( +
+
+ {info.label.split(':')[0]} + {isDone ? ( + + ) : isRunning ? ( + + ) : ( + + )} +
+
{info.role}
+
+ {stepData ? stepData.summary : info.desc} +
+ {stepData?.execution_time_ms && ( +
+ {stepData.execution_time_ms} ms +
+ )} +
+ ); + })} +
+
+ ); +} diff --git a/frontend/src/components/BuildingDrawer.tsx b/frontend/src/components/BuildingDrawer.tsx new file mode 100644 index 0000000..eb44fe9 --- /dev/null +++ b/frontend/src/components/BuildingDrawer.tsx @@ -0,0 +1,214 @@ +'use client'; +import React, { useState, useEffect } from 'react'; +import { Sliders, Sun, TreePine, Zap, DollarSign, Clock, FileText, Sparkles, Building2 } from 'lucide-react'; +import { runSimulation } from '../lib/api'; + +interface BuildingDrawerProps { + building: any; + onClose?: () => void; +} + +export default function BuildingDrawer({ building, onClose }: BuildingDrawerProps) { + const [albedo, setAlbedo] = useState(0.75); + const [canopy, setCanopy] = useState(250); + const [loading, setLoading] = useState(false); + const [simResult, setSimResult] = useState(null); + + const props = building?.properties || { + parcel_id: 'APN-264-11-032', + name: 'SoFA District Infill', + proposed_use: 'Residential over ground-floor retail', + roof_area_m2: 2150, + temp_delta_f: 5.2, + priority_score: 955.5, + albedo: 0.20 + }; + + const handleRunSimulation = async () => { + setLoading(true); + try { + const roofArea = props.roof_area_m2 || 1500; + const res = await runSimulation(roofArea, albedo, canopy, props.parcel_id); + if (res && res.simulation) { + setSimResult(res.simulation); + } + } catch (err) { + console.error('Simulation call error:', err); + } finally { + setLoading(false); + } + }; + + // Run initial simulation on structure load + useEffect(() => { + handleRunSimulation(); + }, [building]); + + const handleDownloadPdf = () => { + const backendUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000'; + const pdfUrl = `${backendUrl}/api/v1/report/pdf/${props.parcel_id}?target_albedo=${albedo}&canopy_area=${canopy}`; + window.open(pdfUrl, '_blank'); + }; + + return ( +
+ {/* Drawer Header */} +
+
+
+ Structure Mitigation Optimizer +
+

+ {props.name || 'San Jose Parcel'} +

+

+ APN: {props.parcel_id || 'APN-264-11-032'} +

+
+ {props.temp_delta_f >= 3.5 && ( + + Priority Hotspot + + )} +
+ + {/* Structural Metadata Grid */} +
+
+ Zoning / Use: + {props.proposed_use || 'Downtown Mixed Use'} +
+
+ Roof Area: + {props.roof_area_m2 || 2150} m² +
+
+ Baseline ΔT: + +{props.temp_delta_f || 4.2}°F +
+
+ Priority Score: + {props.priority_score || 955.5} +
+
+ + {/* Parametric Sliders */} +
+ {/* Albedo Slider */} +
+
+ + + {albedo.toFixed(2)} + +
+ setAlbedo(parseFloat(e.target.value))} + className="w-full accent-emerald-500 bg-slate-800 h-2 rounded-lg cursor-pointer" + /> +
+ 0.20 (Asphalt Dark) + 0.70 (Cool Elastomer) + 0.95 (Ultra-Reflective) +
+
+ + {/* Canopy Expansion Slider */} +
+
+ + + {canopy} m² + +
+ setCanopy(parseFloat(e.target.value))} + className="w-full accent-emerald-500 bg-slate-800 h-2 rounded-lg cursor-pointer" + /> +
+ 0 m² + 500 m² + 1,000 m² +
+
+
+ + {/* Action Button */} + + + {/* Simulation Results Display */} + {simResult && ( +
+
+ Agent 3 Simulation Output + Modeled HVAC ROI +
+ +
+
+ Projected Cooling + + -{simResult.projected_temp_drop_f}°F + +
+ +
+ Annual HVAC Savings + + ${simResult.annual_hvac_savings_usd?.toLocaleString()}/yr + +
+ +
+ Payback Period + + {simResult.payback_years} Years + +
+ +
+ CO2 Reduction + + {simResult.co2_reduction_tons} Tons/yr + +
+
+ + {/* Download PDF Trigger */} + +
+ )} +
+ ); +} diff --git a/frontend/src/components/MapViewport.tsx b/frontend/src/components/MapViewport.tsx new file mode 100644 index 0000000..0497a8b --- /dev/null +++ b/frontend/src/components/MapViewport.tsx @@ -0,0 +1,225 @@ +'use client'; +import React, { useState } from 'react'; +import DeckGL from '@deck.gl/react'; +import { Map } from 'react-map-gl'; +import { GeoJsonLayer, BitmapLayer } from '@deck.gl/layers'; +import { TileLayer } from '@deck.gl/geo-layers'; +import { Layers, Flame, Globe } from 'lucide-react'; + +const INITIAL_VIEW_STATE = { + longitude: -121.8906, // San Jose, CA + latitude: 37.3361, + zoom: 15.2, + pitch: 55, + bearing: -20 +}; + +interface MapViewportProps { + geoJsonData: any; + onSelectBuilding: (building: any) => void; + selectedParcelId?: string | null; +} + +type MapProvider = 'google-hybrid' | 'google-satellite' | 'esri-earth' | 'carto-dark' | 'osm' | 'mapbox-gl'; + +const MAP_PROVIDERS: Record = { + 'google-hybrid': { + name: 'Google Earth Hybrid', + url: 'https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}', + type: 'tile' + }, + 'google-satellite': { + name: 'Google Earth Satellite', + url: 'https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', + type: 'tile' + }, + 'esri-earth': { + name: 'ESRI World Imagery', + url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', + type: 'tile' + }, + 'carto-dark': { + name: 'Carto Dark Matter', + url: 'https://a.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png', + type: 'tile' + }, + 'osm': { + name: 'OpenStreetMap', + url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + type: 'tile' + }, + 'mapbox-gl': { + name: 'Mapbox Vector Dark', + type: 'mapbox' + } +}; + +export default function MapViewport({ + geoJsonData, + onSelectBuilding, + selectedParcelId, +}: MapViewportProps) { + const [hoverInfo, setHoverInfo] = useState(null); + const [provider, setProvider] = useState('google-hybrid'); + + const activeProvider = MAP_PROVIDERS[provider]; + const mapboxToken = process.env.NEXT_PUBLIC_MAPBOX_TOKEN; + const isMapboxActive = provider === 'mapbox-gl' && !!mapboxToken && mapboxToken.startsWith('pk.'); + + // Deck.gl TileLayer using exact west, south, east, north bounds for BitmapLayer + const tileLayer = new TileLayer({ + id: `base-tiles-${provider}`, + data: activeProvider.url || MAP_PROVIDERS['google-hybrid'].url, + minZoom: 0, + maxZoom: 20, + tileSize: 256, + renderSubLayers: (props) => { + if (!props || !props.tile || !props.tile.bbox) return null; + const { west, south, east, north } = props.tile.bbox; + return new BitmapLayer(props, { + data: null, + image: props.data, + bounds: [west, south, east, north] + }); + } + }); + + // 3D Extruded Buildings GeoJsonLayer + const buildingLayer = new GeoJsonLayer({ + id: 'buildings-3d', + data: geoJsonData || '/data/parcel_portfolio_san_jose_sample.geojson', + extruded: true, + wireframe: true, + getElevation: (f: any) => (f.properties?.height || (f.properties?.stories ? f.properties.stories * 3.5 : 25)), + getFillColor: (f: any) => { + const pid = f.properties?.parcel_id; + if (selectedParcelId && pid === selectedParcelId) { + return [16, 185, 129, 240]; // Selected Emerald green + } + const tempDelta = f.properties?.temp_delta_f ?? f.properties?.temp_delta ?? 4.2; + return tempDelta >= 3.5 + ? [239, 68, 68, 220] // Red Hotspot anomaly + : [59, 130, 246, 200]; // Blue normal parcel + }, + getLineColor: [255, 255, 255, 90], + lineWidthMinPixels: 1, + pickable: true, + onHover: (info) => setHoverInfo(info), + onClick: (info) => { + if (info.object) { + onSelectBuilding(info.object); + } + }, + updateTriggers: { + getFillColor: [selectedParcelId] + } + }); + + const layers = isMapboxActive ? [buildingLayer] : [tileLayer, buildingLayer]; + + return ( +
+ {/* Top Left Header & Controls */} +
+
+ + FortyGuard 3D Thermal Layer + + ΔT ≥ +3.5°F + +
+ + {/* Map Provider Selector */} +
+ + {(['google-hybrid', 'google-satellite', 'esri-earth', 'carto-dark'] as MapProvider[]).map((pKey) => ( + + ))} + {mapboxToken && ( + + )} +
+
+ + {/* Map Legend */} +
+
+ Thermal Risk Scale + {MAP_PROVIDERS[provider].name} +
+
+ + High Thermal Anomaly (ΔT ≥ +3.5°F) +
+
+ + Baseline Ambient Parcel +
+
+ + Selected Target Intervention +
+
+ + + {isMapboxActive && ( + + )} + + + {/* Hover Tooltip Overlay */} + {hoverInfo && hoverInfo.object && ( +
+
+ {hoverInfo.object.properties?.name || 'San Jose Parcel'} +
+
+ {hoverInfo.object.properties?.parcel_id} +
+
+ Urban Heat ΔT: + = 3.5 ? 'text-red-400' : 'text-blue-400'}`}> + +{hoverInfo.object.properties?.temp_delta_f || 4.2}°F + +
+
+ Priority Score: + + {hoverInfo.object.properties?.priority_score || '955.5'} + +
+
+ )} +
+ ); +} diff --git a/frontend/src/components/MetricsBar.tsx b/frontend/src/components/MetricsBar.tsx new file mode 100644 index 0000000..2168352 --- /dev/null +++ b/frontend/src/components/MetricsBar.tsx @@ -0,0 +1,89 @@ +'use client'; +import React from 'react'; +import { Thermometer, Flame, DollarSign, Leaf, Zap, ShieldCheck } from 'lucide-react'; + +interface MetricsBarProps { + hotspotCount: number; + totalParcels: number; + avgTempF: number; + projectedCoolingF?: number; + annualSavingsUsd?: number; + co2Tons?: number; +} + +export default function MetricsBar({ + hotspotCount = 3, + totalParcels = 6, + avgTempF = 86.2, + projectedCoolingF = 4.3, + annualSavingsUsd = 68625.0, + co2Tons = 228.75 +}: MetricsBarProps) { + return ( +
+ {/* Metric 1: Avg Ambient Temp */} +
+
+ +
+
+
Avg Ambient Temp
+
{avgTempF}°F
+
FortyGuard San Jose 2m
+
+
+ + {/* Metric 2: Heat Anomalies */} +
+
+ +
+
+
Thermal Anomalies
+
+ {hotspotCount} / {totalParcels} Parcels +
+
ΔT ≥ +3.5°F Breach
+
+
+ + {/* Metric 3: Projected Cooling */} +
+
+ +
+
+
Projected Cooling
+
-{projectedCoolingF}°F
+
Cool Roof + Greening
+
+
+ + {/* Metric 4: Economic Savings */} +
+
+ +
+
+
Annual HVAC Savings
+
+ ${annualSavingsUsd.toLocaleString()}/yr +
+
Peak Chiller Offset
+
+
+ + {/* Metric 5: CO2 Offset */} +
+
+ +
+
+
Carbon Offset
+
{co2Tons} Tons
+
CO2e Annual Offset
+
+
+
+ ); +} diff --git a/frontend/src/components/TimelineSlider.tsx b/frontend/src/components/TimelineSlider.tsx new file mode 100644 index 0000000..9ca7aaa --- /dev/null +++ b/frontend/src/components/TimelineSlider.tsx @@ -0,0 +1,65 @@ +'use client'; +import React from 'react'; +import { Calendar, Play, RotateCcw, Clock } from 'lucide-react'; + +interface TimelineSliderProps { + currentStep: number; // 0: 2024, 1: 2026, 2: 2028 + onTimelineChange: (step: number) => void; +} + +const STAGES = [ + { year: '2024', label: 'Diridon Baseline', desc: 'Historical Reference' }, + { year: '2026', label: 'FortyGuard Peak Heatwave', desc: 'Active TCM Dataset' }, + { year: '2028', label: 'Retrofitted Mitigation', desc: 'Post-Agent Optimization' } +]; + +export default function TimelineSlider({ currentStep, onTimelineChange }: TimelineSliderProps) { + return ( +
+
+
+ + Temporal Development Timeline +
+
+ Stage: {STAGES[currentStep].year} — {STAGES[currentStep].label} +
+
+ + {/* Slider Track */} +
+ onTimelineChange(parseInt(e.target.value))} + className="w-full accent-emerald-500 bg-slate-800 h-2 rounded-lg cursor-pointer" + /> + + {/* Stage Labels */} +
+ {STAGES.map((st, idx) => ( + + ))} +
+
+
+ ); +} diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js new file mode 100644 index 0000000..6082b7b --- /dev/null +++ b/frontend/tailwind.config.js @@ -0,0 +1,25 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + './src/pages/**/*.{js,ts,jsx,tsx,mdx}', + './src/components/**/*.{js,ts,jsx,tsx,mdx}', + './src/app/**/*.{js,ts,jsx,tsx,mdx}', + ], + theme: { + extend: { + colors: { + emerald: { + 400: '#34d399', + 500: '#10b981', + 600: '#059669', + }, + slate: { + 800: '#1e293b', + 900: '#0f172a', + 950: '#020617', + } + } + }, + }, + plugins: [], +} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000..e59724b --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} From 3b3f0f1db89c5deb98621023736898f3ca92027e Mon Sep 17 00:00:00 2001 From: muhammadsohaib-cs Date: Sun, 16 Aug 2026 20:04:20 +0500 Subject: [PATCH 2/2] fix: resolve TypeScript build errors in AgentStatusPanel and MapViewport --- .gitignore | 2 ++ frontend/src/components/AgentStatusPanel.tsx | 6 +++--- frontend/src/components/MapViewport.tsx | 10 +++++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 9a65aa7..16e972d 100644 --- a/.gitignore +++ b/.gitignore @@ -254,4 +254,6 @@ node_modules/ out/ build/ .env*.local +*.tsbuildinfo + diff --git a/frontend/src/components/AgentStatusPanel.tsx b/frontend/src/components/AgentStatusPanel.tsx index 4e69d2e..02cf987 100644 --- a/frontend/src/components/AgentStatusPanel.tsx +++ b/frontend/src/components/AgentStatusPanel.tsx @@ -3,9 +3,9 @@ import React from 'react'; import { Cpu, CheckCircle2, Clock, PlayCircle, AlertCircle, ArrowRight } from 'lucide-react'; interface StepLog { - agent_name: str; - status: str; - summary: str; + agent_name: string; + status: string; + summary: string; execution_time_ms?: number; } diff --git a/frontend/src/components/MapViewport.tsx b/frontend/src/components/MapViewport.tsx index 0497a8b..888a16f 100644 --- a/frontend/src/components/MapViewport.tsx +++ b/frontend/src/components/MapViewport.tsx @@ -73,11 +73,15 @@ export default function MapViewport({ minZoom: 0, maxZoom: 20, tileSize: 256, - renderSubLayers: (props) => { + renderSubLayers: (props: any) => { if (!props || !props.tile || !props.tile.bbox) return null; - const { west, south, east, north } = props.tile.bbox; + const bbox = props.tile.bbox; + const west = typeof bbox.west === 'number' ? bbox.west : bbox[0]; + const south = typeof bbox.south === 'number' ? bbox.south : bbox[1]; + const east = typeof bbox.east === 'number' ? bbox.east : bbox[2]; + const north = typeof bbox.north === 'number' ? bbox.north : bbox[3]; return new BitmapLayer(props, { - data: null, + data: undefined, image: props.data, bounds: [west, south, east, north] });