@mapbox/mcp-server 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/resources/place-photo/PlacePhotoResource.d.ts +57 -0
- package/dist/commonjs/resources/place-photo/PlacePhotoResource.d.ts.map +1 -0
- package/dist/commonjs/resources/place-photo/PlacePhotoResource.js +202 -0
- package/dist/commonjs/resources/place-photo/PlacePhotoResource.js.map +1 -0
- package/dist/commonjs/resources/resourceRegistry.d.ts +3 -1
- package/dist/commonjs/resources/resourceRegistry.d.ts.map +1 -1
- package/dist/commonjs/resources/resourceRegistry.js +5 -0
- package/dist/commonjs/resources/resourceRegistry.js.map +1 -1
- package/dist/commonjs/resources/tool-response/ToolResponseResource.d.ts +20 -0
- package/dist/commonjs/resources/tool-response/ToolResponseResource.d.ts.map +1 -0
- package/dist/commonjs/resources/tool-response/ToolResponseResource.js +83 -0
- package/dist/commonjs/resources/tool-response/ToolResponseResource.js.map +1 -0
- package/dist/commonjs/resources/ui-apps/mapAppHtml.d.ts.map +1 -1
- package/dist/commonjs/resources/ui-apps/mapAppHtml.js +484 -11
- package/dist/commonjs/resources/ui-apps/mapAppHtml.js.map +1 -1
- package/dist/commonjs/tools/category-list-tool/CategoryListTool.d.ts.map +1 -1
- package/dist/commonjs/tools/category-list-tool/CategoryListTool.input.schema.js +1 -1
- package/dist/commonjs/tools/category-list-tool/CategoryListTool.input.schema.js.map +1 -1
- package/dist/commonjs/tools/category-list-tool/CategoryListTool.js +1 -1
- package/dist/commonjs/tools/category-list-tool/CategoryListTool.js.map +1 -1
- package/dist/commonjs/tools/directions-tool/DirectionsTool.d.ts.map +1 -1
- package/dist/commonjs/tools/directions-tool/DirectionsTool.input.schema.js +3 -3
- package/dist/commonjs/tools/directions-tool/DirectionsTool.input.schema.js.map +1 -1
- package/dist/commonjs/tools/directions-tool/DirectionsTool.js +17 -17
- package/dist/commonjs/tools/directions-tool/DirectionsTool.js.map +1 -1
- package/dist/commonjs/tools/ground-location-tool/GroundLocationTool.d.ts.map +1 -1
- package/dist/commonjs/tools/ground-location-tool/GroundLocationTool.js +1 -1
- package/dist/commonjs/tools/ground-location-tool/GroundLocationTool.js.map +1 -1
- package/dist/commonjs/tools/isochrone-tool/IsochroneTool.d.ts.map +1 -1
- package/dist/commonjs/tools/isochrone-tool/IsochroneTool.js +6 -13
- package/dist/commonjs/tools/isochrone-tool/IsochroneTool.js.map +1 -1
- package/dist/commonjs/tools/render-map-tool/RenderMapTool.d.ts.map +1 -1
- package/dist/commonjs/tools/render-map-tool/RenderMapTool.input.schema.d.ts +4 -0
- package/dist/commonjs/tools/render-map-tool/RenderMapTool.input.schema.d.ts.map +1 -1
- package/dist/commonjs/tools/render-map-tool/RenderMapTool.input.schema.js +18 -2
- package/dist/commonjs/tools/render-map-tool/RenderMapTool.input.schema.js.map +1 -1
- package/dist/commonjs/tools/render-map-tool/RenderMapTool.js +9 -5
- package/dist/commonjs/tools/render-map-tool/RenderMapTool.js.map +1 -1
- package/dist/commonjs/tools/render-map-tool/RenderMapTool.output.schema.d.ts +4 -0
- package/dist/commonjs/tools/render-map-tool/RenderMapTool.output.schema.d.ts.map +1 -1
- package/dist/commonjs/utils/directionsRef.d.ts +27 -0
- package/dist/commonjs/utils/directionsRef.d.ts.map +1 -0
- package/dist/commonjs/utils/directionsRef.js +52 -0
- package/dist/commonjs/utils/directionsRef.js.map +1 -0
- package/dist/commonjs/utils/index.d.ts +8 -0
- package/dist/commonjs/utils/index.d.ts.map +1 -1
- package/dist/commonjs/utils/index.js +23 -1
- package/dist/commonjs/utils/index.js.map +1 -1
- package/dist/commonjs/utils/mapAppPayload.d.ts +21 -0
- package/dist/commonjs/utils/mapAppPayload.d.ts.map +1 -1
- package/dist/commonjs/utils/mapAppPayload.js +5 -1
- package/dist/commonjs/utils/mapAppPayload.js.map +1 -1
- package/dist/commonjs/utils/responseRef.d.ts +33 -0
- package/dist/commonjs/utils/responseRef.d.ts.map +1 -0
- package/dist/commonjs/utils/responseRef.js +73 -0
- package/dist/commonjs/utils/responseRef.js.map +1 -0
- package/dist/commonjs/utils/serverInstructions.d.ts +2 -2
- package/dist/commonjs/utils/serverInstructions.js +2 -2
- package/dist/commonjs/utils/storeMapPayload.js +1 -1
- package/dist/commonjs/utils/storeMapPayload.js.map +1 -1
- package/dist/commonjs/utils/urlSafety.d.ts +6 -0
- package/dist/commonjs/utils/urlSafety.d.ts.map +1 -1
- package/dist/commonjs/utils/urlSafety.js +15 -4
- package/dist/commonjs/utils/urlSafety.js.map +1 -1
- package/dist/commonjs/version.json +3 -3
- package/dist/esm/resources/place-photo/PlacePhotoResource.d.ts +57 -0
- package/dist/esm/resources/place-photo/PlacePhotoResource.d.ts.map +1 -0
- package/dist/esm/resources/place-photo/PlacePhotoResource.js +198 -0
- package/dist/esm/resources/place-photo/PlacePhotoResource.js.map +1 -0
- package/dist/esm/resources/resourceRegistry.d.ts +3 -1
- package/dist/esm/resources/resourceRegistry.d.ts.map +1 -1
- package/dist/esm/resources/resourceRegistry.js +5 -0
- package/dist/esm/resources/resourceRegistry.js.map +1 -1
- package/dist/esm/resources/tool-response/ToolResponseResource.d.ts +20 -0
- package/dist/esm/resources/tool-response/ToolResponseResource.d.ts.map +1 -0
- package/dist/esm/resources/tool-response/ToolResponseResource.js +79 -0
- package/dist/esm/resources/tool-response/ToolResponseResource.js.map +1 -0
- package/dist/esm/resources/ui-apps/mapAppHtml.d.ts.map +1 -1
- package/dist/esm/resources/ui-apps/mapAppHtml.js +484 -11
- package/dist/esm/resources/ui-apps/mapAppHtml.js.map +1 -1
- package/dist/esm/tools/category-list-tool/CategoryListTool.d.ts.map +1 -1
- package/dist/esm/tools/category-list-tool/CategoryListTool.input.schema.js +1 -1
- package/dist/esm/tools/category-list-tool/CategoryListTool.input.schema.js.map +1 -1
- package/dist/esm/tools/category-list-tool/CategoryListTool.js +1 -1
- package/dist/esm/tools/category-list-tool/CategoryListTool.js.map +1 -1
- package/dist/esm/tools/directions-tool/DirectionsTool.d.ts.map +1 -1
- package/dist/esm/tools/directions-tool/DirectionsTool.input.schema.js +3 -3
- package/dist/esm/tools/directions-tool/DirectionsTool.input.schema.js.map +1 -1
- package/dist/esm/tools/directions-tool/DirectionsTool.js +17 -17
- package/dist/esm/tools/directions-tool/DirectionsTool.js.map +1 -1
- package/dist/esm/tools/ground-location-tool/GroundLocationTool.d.ts.map +1 -1
- package/dist/esm/tools/ground-location-tool/GroundLocationTool.js +1 -1
- package/dist/esm/tools/ground-location-tool/GroundLocationTool.js.map +1 -1
- package/dist/esm/tools/isochrone-tool/IsochroneTool.d.ts.map +1 -1
- package/dist/esm/tools/isochrone-tool/IsochroneTool.js +6 -13
- package/dist/esm/tools/isochrone-tool/IsochroneTool.js.map +1 -1
- package/dist/esm/tools/render-map-tool/RenderMapTool.d.ts.map +1 -1
- package/dist/esm/tools/render-map-tool/RenderMapTool.input.schema.d.ts +4 -0
- package/dist/esm/tools/render-map-tool/RenderMapTool.input.schema.d.ts.map +1 -1
- package/dist/esm/tools/render-map-tool/RenderMapTool.input.schema.js +18 -2
- package/dist/esm/tools/render-map-tool/RenderMapTool.input.schema.js.map +1 -1
- package/dist/esm/tools/render-map-tool/RenderMapTool.js +9 -5
- package/dist/esm/tools/render-map-tool/RenderMapTool.js.map +1 -1
- package/dist/esm/tools/render-map-tool/RenderMapTool.output.schema.d.ts +4 -0
- package/dist/esm/tools/render-map-tool/RenderMapTool.output.schema.d.ts.map +1 -1
- package/dist/esm/utils/directionsRef.d.ts +27 -0
- package/dist/esm/utils/directionsRef.d.ts.map +1 -0
- package/dist/esm/utils/directionsRef.js +49 -0
- package/dist/esm/utils/directionsRef.js.map +1 -0
- package/dist/esm/utils/index.d.ts +8 -0
- package/dist/esm/utils/index.d.ts.map +1 -1
- package/dist/esm/utils/index.js +15 -0
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/mapAppPayload.d.ts +21 -0
- package/dist/esm/utils/mapAppPayload.d.ts.map +1 -1
- package/dist/esm/utils/mapAppPayload.js +5 -1
- package/dist/esm/utils/mapAppPayload.js.map +1 -1
- package/dist/esm/utils/responseRef.d.ts +33 -0
- package/dist/esm/utils/responseRef.d.ts.map +1 -0
- package/dist/esm/utils/responseRef.js +68 -0
- package/dist/esm/utils/responseRef.js.map +1 -0
- package/dist/esm/utils/serverInstructions.d.ts +2 -2
- package/dist/esm/utils/serverInstructions.js +2 -2
- package/dist/esm/utils/storeMapPayload.js +1 -1
- package/dist/esm/utils/storeMapPayload.js.map +1 -1
- package/dist/esm/utils/urlSafety.d.ts +6 -0
- package/dist/esm/utils/urlSafety.d.ts.map +1 -1
- package/dist/esm/utils/urlSafety.js +14 -4
- package/dist/esm/utils/urlSafety.js.map +1 -1
- package/dist/esm/version.json +3 -3
- package/package.json +9 -2
|
@@ -75,12 +75,51 @@ function renderMapAppHtml(params) {
|
|
|
75
75
|
box-shadow: 0 2px 6px rgba(0,0,0,0.4);
|
|
76
76
|
cursor: pointer;
|
|
77
77
|
}
|
|
78
|
+
#side-panel {
|
|
79
|
+
position: absolute; top: 12px; right: 12px; bottom: 12px; z-index: 10;
|
|
80
|
+
width: 280px; max-width: calc(100% - 24px);
|
|
81
|
+
background: rgba(15, 23, 42, 0.88); color: #f1f5f9;
|
|
82
|
+
border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.3);
|
|
83
|
+
display: flex; flex-direction: column; overflow: hidden;
|
|
84
|
+
}
|
|
85
|
+
#side-panel .panel-head {
|
|
86
|
+
padding: 10px 12px; font-size: 13px; font-weight: 600;
|
|
87
|
+
border-bottom: 1px solid rgba(255,255,255,0.12); flex: 0 0 auto;
|
|
88
|
+
display: flex; justify-content: space-between; gap: 8px; cursor: pointer;
|
|
89
|
+
}
|
|
90
|
+
/* Click the heading to collapse the list (see togglePanel). */
|
|
91
|
+
#side-panel .panel-head::after { content: '▾'; opacity: 0.7; }
|
|
92
|
+
#side-panel.collapsed { bottom: auto; }
|
|
93
|
+
#side-panel.collapsed .panel-list { display: none; }
|
|
94
|
+
#side-panel.collapsed .panel-head { border-bottom: none; }
|
|
95
|
+
#side-panel.collapsed .panel-head::after { content: '▸'; }
|
|
96
|
+
#side-panel .panel-list { list-style: none; margin: 0; padding: 6px; overflow-y: auto; flex: 1; }
|
|
97
|
+
#side-panel .panel-item {
|
|
98
|
+
display: flex; align-items: flex-start; gap: 6px; padding: 6px; border-radius: 6px; cursor: pointer;
|
|
99
|
+
}
|
|
100
|
+
#side-panel .panel-item:hover { background: rgba(255,255,255,0.08); }
|
|
101
|
+
/* Only added once a photo has loaded (see loadPanelPhoto), at the end of
|
|
102
|
+
the row so names stay aligned whether or not a row has one. */
|
|
103
|
+
#side-panel .panel-thumb {
|
|
104
|
+
flex: 0 0 auto; width: 40px; height: 40px; border-radius: 6px; margin-left: auto;
|
|
105
|
+
background-size: cover; background-position: center;
|
|
106
|
+
}
|
|
107
|
+
/* Visit-order badge, matching the numbered map marker. */
|
|
108
|
+
#side-panel .panel-badge {
|
|
109
|
+
flex: 0 0 auto; width: 20px; height: 20px; border-radius: 50%; margin-top: 1px;
|
|
110
|
+
background: #f97316; color: #1a0f04;
|
|
111
|
+
display: flex; align-items: center; justify-content: center;
|
|
112
|
+
font-size: 10px; font-weight: 700;
|
|
113
|
+
}
|
|
114
|
+
#side-panel .panel-name { font-size: 12.5px; font-weight: 600; }
|
|
115
|
+
#side-panel .panel-meta { font-size: 11px; color: #cbd5e1; margin-top: 2px; }
|
|
78
116
|
</style>
|
|
79
117
|
</head>
|
|
80
118
|
<body>
|
|
81
119
|
<div id="map"></div>
|
|
82
120
|
<div id="summary" style="display:none"></div>
|
|
83
121
|
<div id="legend" style="display:none"></div>
|
|
122
|
+
<div id="side-panel" style="display:none"></div>
|
|
84
123
|
<div id="loading">Loading…</div>
|
|
85
124
|
<div id="error" style="display:none"></div>
|
|
86
125
|
${initialDataScript}
|
|
@@ -94,6 +133,11 @@ ${initialDataScript}
|
|
|
94
133
|
var errorEl = document.getElementById('error');
|
|
95
134
|
var summaryEl = document.getElementById('summary');
|
|
96
135
|
var legendEl = document.getElementById('legend');
|
|
136
|
+
var panelEl = document.getElementById('side-panel');
|
|
137
|
+
// Populated by buildSearchMiniPayload's marker tagging so the panel (click
|
|
138
|
+
// -> flyTo) and Place Details enrichment can find a marker by mapbox_id
|
|
139
|
+
// without re-querying the map for it.
|
|
140
|
+
var markersById = {};
|
|
97
141
|
|
|
98
142
|
var map = null;
|
|
99
143
|
var mapLoaded = false;
|
|
@@ -113,7 +157,9 @@ ${initialDataScript}
|
|
|
113
157
|
var messageId = 0;
|
|
114
158
|
var pendingRequests = new Map();
|
|
115
159
|
|
|
116
|
-
|
|
160
|
+
// timeoutMs (optional) rejects a request nobody answers, for hosts that
|
|
161
|
+
// don't implement the method.
|
|
162
|
+
function sendRequest(method, params, timeoutMs) {
|
|
117
163
|
var id = ++messageId;
|
|
118
164
|
try {
|
|
119
165
|
window.parent.postMessage({
|
|
@@ -122,6 +168,13 @@ ${initialDataScript}
|
|
|
122
168
|
} catch (_) {}
|
|
123
169
|
return new Promise(function(resolve, reject) {
|
|
124
170
|
pendingRequests.set(id, { resolve: resolve, reject: reject });
|
|
171
|
+
if (timeoutMs) {
|
|
172
|
+
setTimeout(function() {
|
|
173
|
+
if (!pendingRequests.has(id)) return;
|
|
174
|
+
pendingRequests.delete(id);
|
|
175
|
+
reject(new Error(method + ' timed out'));
|
|
176
|
+
}, timeoutMs);
|
|
177
|
+
}
|
|
125
178
|
});
|
|
126
179
|
}
|
|
127
180
|
function sendNotification(method, params) {
|
|
@@ -156,13 +209,22 @@ ${initialDataScript}
|
|
|
156
209
|
}
|
|
157
210
|
});
|
|
158
211
|
|
|
212
|
+
// Set once a host answers ui/initialize, even with an error. A page from
|
|
213
|
+
// export_map_html_tool framed by some other site never gets an answer.
|
|
214
|
+
var hostAnswered = false;
|
|
159
215
|
sendRequest('ui/initialize', {
|
|
160
216
|
protocolVersion: '2026-01-26',
|
|
161
217
|
appCapabilities: {},
|
|
162
218
|
appInfo: { name: 'Mapbox Map', version: '1.0.0' }
|
|
163
219
|
}).then(
|
|
164
|
-
function() {
|
|
165
|
-
|
|
220
|
+
function() {
|
|
221
|
+
hostAnswered = true;
|
|
222
|
+
sendNotification('ui/notifications/initialized', {});
|
|
223
|
+
},
|
|
224
|
+
function() {
|
|
225
|
+
hostAnswered = true;
|
|
226
|
+
sendNotification('ui/notifications/initialized', {});
|
|
227
|
+
}
|
|
166
228
|
);
|
|
167
229
|
|
|
168
230
|
// --- Map setup ------------------------------------------------------------
|
|
@@ -366,6 +428,13 @@ ${initialDataScript}
|
|
|
366
428
|
trackedLayerIds = [];
|
|
367
429
|
trackedSourceIds = [];
|
|
368
430
|
trackedMarkers = [];
|
|
431
|
+
markersById = {};
|
|
432
|
+
panelEl.style.display = 'none';
|
|
433
|
+
clearPanel();
|
|
434
|
+
// Place Details responses still in flight belong to the old render.
|
|
435
|
+
panelGeneration += 1;
|
|
436
|
+
panelCount = 0;
|
|
437
|
+
panelIds = {};
|
|
369
438
|
}
|
|
370
439
|
|
|
371
440
|
function bboxAccumulator() {
|
|
@@ -451,14 +520,108 @@ ${initialDataScript}
|
|
|
451
520
|
if (m.popup) marker.setPopup(new mapboxgl.Popup().setText(m.popup));
|
|
452
521
|
marker.addTo(map);
|
|
453
522
|
trackedMarkers.push(marker);
|
|
523
|
+
// Tagged by buildSearchMiniPayload with the result's mapbox_id so the
|
|
524
|
+
// side panel (click-to-flyTo) and Place Details enrichment can look the
|
|
525
|
+
// marker back up later without walking trackedMarkers.
|
|
526
|
+
if (m.id) markersById[m.id] = { marker: marker, popupText: m.popup || '' };
|
|
454
527
|
bbox.extend(m.coordinates);
|
|
455
528
|
}
|
|
456
529
|
|
|
530
|
+
// Guarantees a marker that opts into the side panel (has .id) also gets
|
|
531
|
+
// a visible number on the map matching its panel row, unless the caller
|
|
532
|
+
// already gave it an explicit label. Without this, a caller that builds
|
|
533
|
+
// plain unlabeled pins for POI markers (observed live: Claude did this
|
|
534
|
+
// for inline markers, leaving the map showing generic blue pins with no
|
|
535
|
+
// way to tell which panel row is which) breaks the whole point of the
|
|
536
|
+
// panel numbering. Mutates markers in place, so it must run before
|
|
537
|
+
// addOneMarker draws them.
|
|
538
|
+
//
|
|
539
|
+
// Numbering runs across the whole render, not per call: a render can
|
|
540
|
+
// draw inline markers and then merge in self-fetched search results, and
|
|
541
|
+
// each set arrives numbered from 1. The first set keeps the caller's
|
|
542
|
+
// numbers when they're unique (a visit order, say); a later set, or one
|
|
543
|
+
// with repeated numbers, is renumbered to continue the panel's count.
|
|
544
|
+
// Letter labels ("A") are kept as they are. A place already in the panel
|
|
545
|
+
// this render is dropped rather than drawn and listed twice. Returns the
|
|
546
|
+
// markers to draw.
|
|
547
|
+
function applyPanelNumbering(markers) {
|
|
548
|
+
if (!Array.isArray(markers)) return [];
|
|
549
|
+
var seen = {};
|
|
550
|
+
var fresh = markers.filter(function(m) {
|
|
551
|
+
if (!m || !m.id) return true;
|
|
552
|
+
if (panelIds[m.id] || seen[m.id]) return false;
|
|
553
|
+
seen[m.id] = true;
|
|
554
|
+
return true;
|
|
555
|
+
});
|
|
556
|
+
var keep = panelCount === 0;
|
|
557
|
+
var used = {};
|
|
558
|
+
fresh.forEach(function(m) {
|
|
559
|
+
if (!m || !m.id || !isWholeNumber(m.label)) return;
|
|
560
|
+
if (used[m.label]) keep = false;
|
|
561
|
+
used[m.label] = true;
|
|
562
|
+
});
|
|
563
|
+
if (keep) {
|
|
564
|
+
Object.keys(used).forEach(function(n) {
|
|
565
|
+
panelCount = Math.max(panelCount, parseInt(n, 10));
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
fresh.forEach(function(m) {
|
|
569
|
+
if (!m || !m.id) return;
|
|
570
|
+
if (m.label && (keep || !isWholeNumber(m.label))) return;
|
|
571
|
+
panelCount += 1;
|
|
572
|
+
var n = String(panelCount);
|
|
573
|
+
if (!m.label) {
|
|
574
|
+
if (m.style !== 'start' && m.style !== 'end') m.style = 'numbered';
|
|
575
|
+
if (!m.color) m.color = '#f97316';
|
|
576
|
+
} else if (typeof m.popup === 'string' && m.popup.indexOf(m.label + '. ') === 0) {
|
|
577
|
+
// Search popups start with the old number ("3. Name").
|
|
578
|
+
m.popup = n + '. ' + m.popup.slice(String(m.label).length + 2);
|
|
579
|
+
}
|
|
580
|
+
m.label = n;
|
|
581
|
+
});
|
|
582
|
+
return fresh;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function isWholeNumber(label) {
|
|
586
|
+
if (label === undefined || label === null || label === '') return false;
|
|
587
|
+
var n = parseInt(label, 10);
|
|
588
|
+
return n > 0 && String(n) === String(label);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Bottom padding that keeps fitted data out from under the legend
|
|
592
|
+
// (bottom-left), unless the map is too short to spare the room.
|
|
593
|
+
function bottomPadding() {
|
|
594
|
+
if (legendEl.style.display !== 'block') return 50;
|
|
595
|
+
var bottom = (legendEl.offsetHeight || 0) + 24;
|
|
596
|
+
var el = document.getElementById('map');
|
|
597
|
+
var height = (el && el.clientHeight) || window.innerHeight || 0;
|
|
598
|
+
if (bottom <= 50 || (height && height - bottom - 70 < 160)) return 50;
|
|
599
|
+
return bottom;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// Right padding that keeps fitted data out from under an open panel. On
|
|
603
|
+
// a narrow map there's no room beside it, so fit as if it weren't there
|
|
604
|
+
// (the panel starts collapsed there anyway; see appendPanelRows).
|
|
605
|
+
function rightPadding() {
|
|
606
|
+
if (panelEl.style.display !== 'flex' || panelCollapsed) return 30;
|
|
607
|
+
var right = (panelEl.offsetWidth || 280) + 24;
|
|
608
|
+
var mapWidth = mapContainerWidth();
|
|
609
|
+
if (mapWidth && mapWidth - right < 240) return 30;
|
|
610
|
+
return right;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function mapContainerWidth() {
|
|
614
|
+
var el = document.getElementById('map');
|
|
615
|
+
return (el && el.clientWidth) || window.innerWidth || 0;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
var lastFitBounds = null;
|
|
457
619
|
function fitToBounds(bounds) {
|
|
620
|
+
lastFitBounds = bounds;
|
|
458
621
|
setTimeout(function() {
|
|
459
622
|
map.resize();
|
|
460
623
|
map.fitBounds(bounds, {
|
|
461
|
-
padding: { top: 70, bottom:
|
|
624
|
+
padding: { top: 70, bottom: bottomPadding(), left: 30, right: rightPadding() },
|
|
462
625
|
duration: 600
|
|
463
626
|
});
|
|
464
627
|
}, 60);
|
|
@@ -474,13 +637,13 @@ ${initialDataScript}
|
|
|
474
637
|
(Array.isArray(payload.layers) ? payload.layers : []).forEach(function(layer) {
|
|
475
638
|
addOneLayer(layer, bbox);
|
|
476
639
|
});
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
});
|
|
640
|
+
var markers = applyPanelNumbering(payload.markers);
|
|
641
|
+
markers.forEach(function(m) { addOneMarker(m, bbox); });
|
|
480
642
|
if (payload.summary && summaryEl.style.display === 'none') {
|
|
481
643
|
summaryEl.textContent = payload.summary;
|
|
482
644
|
summaryEl.style.display = 'block';
|
|
483
645
|
}
|
|
646
|
+
maybeShowSidePanel(markers, payload.summary);
|
|
484
647
|
var bounds = bbox.bounds();
|
|
485
648
|
if (bounds) fitToBounds(bounds);
|
|
486
649
|
}
|
|
@@ -519,10 +682,14 @@ ${initialDataScript}
|
|
|
519
682
|
|
|
520
683
|
var bbox = bboxAccumulator();
|
|
521
684
|
var layers = Array.isArray(payload.layers) ? payload.layers : [];
|
|
522
|
-
var markers = Array.isArray(payload.markers) ? payload.markers : [];
|
|
523
|
-
|
|
524
685
|
layers.forEach(function(layer) { addOneLayer(layer, bbox); });
|
|
686
|
+
var markers = applyPanelNumbering(payload.markers);
|
|
525
687
|
markers.forEach(function(m) { addOneMarker(m, bbox); });
|
|
688
|
+
// Covers both inline markers (a caller-composed payload) and self-fetch
|
|
689
|
+
// markers (merged in later via mergeAdditionalPayload) — see
|
|
690
|
+
// maybeShowSidePanel below. Whichever path produced id-bearing POI
|
|
691
|
+
// markers gets the same results panel.
|
|
692
|
+
maybeShowSidePanel(markers, payload.summary);
|
|
526
693
|
|
|
527
694
|
// Legend
|
|
528
695
|
if (Array.isArray(payload.legend) && payload.legend.length > 0) {
|
|
@@ -1233,12 +1400,22 @@ ${initialDataScript}
|
|
|
1233
1400
|
popupParts.push(Math.round(props.distance) + ' m');
|
|
1234
1401
|
}
|
|
1235
1402
|
var coords = f.geometry.coordinates;
|
|
1403
|
+
// id/name/category/distanceMeters are the same generic POI fields an
|
|
1404
|
+
// inline (hand-composed) marker can carry — see maybeShowSidePanel,
|
|
1405
|
+
// which builds the results panel from either source identically.
|
|
1406
|
+
// mapbox_id is missing on the rare result that lacks one; the panel
|
|
1407
|
+
// just skips that row rather than show an unclickable/unenrichable
|
|
1408
|
+
// entry.
|
|
1236
1409
|
markers.push({
|
|
1410
|
+
id: props.mapbox_id,
|
|
1237
1411
|
coordinates: coords,
|
|
1238
1412
|
style: 'numbered',
|
|
1239
1413
|
label: String(i + 1),
|
|
1240
1414
|
color: '#f97316',
|
|
1241
|
-
popup: popupParts.join(' — ')
|
|
1415
|
+
popup: popupParts.join(' — '),
|
|
1416
|
+
name: props.name || ('Result ' + (i + 1)),
|
|
1417
|
+
category: Array.isArray(props.poi_category) ? props.poi_category[0] : undefined,
|
|
1418
|
+
distanceMeters: typeof props.distance === 'number' ? props.distance : undefined
|
|
1242
1419
|
});
|
|
1243
1420
|
features.push({
|
|
1244
1421
|
type: 'Feature',
|
|
@@ -1270,6 +1447,296 @@ ${initialDataScript}
|
|
|
1270
1447
|
return { summary: summary, layers: layers, markers: markers };
|
|
1271
1448
|
}
|
|
1272
1449
|
|
|
1450
|
+
// --- Side panel: result list + Place Details enrichment ----------------
|
|
1451
|
+
// Triggered generically by maybeShowSidePanel for ANY marker set that
|
|
1452
|
+
// includes id-bearing entries — self-fetch search/category-search
|
|
1453
|
+
// results (via mergeAdditionalPayload) and hand-composed inline markers
|
|
1454
|
+
// from render_map_tool's own "markers" input (via renderBody) both funnel
|
|
1455
|
+
// through the same path. Renders the initial (Search Box-only, or
|
|
1456
|
+
// whatever the caller already provided) list immediately so the panel
|
|
1457
|
+
// never blocks on the slower enrichment call. sourceLabel is plain text
|
|
1458
|
+
// shown as the panel heading (e.g. the query, category, or the payload's
|
|
1459
|
+
// own summary).
|
|
1460
|
+
function derivePanelItems(markers) {
|
|
1461
|
+
if (!Array.isArray(markers)) return [];
|
|
1462
|
+
var items = [];
|
|
1463
|
+
markers.forEach(function(m) {
|
|
1464
|
+
if (!m || !m.id) return;
|
|
1465
|
+
// The pin's own label, so a row reads the same as its pin ("A" too).
|
|
1466
|
+
var badge = isWholeNumber(m.label) ? parseInt(m.label, 10)
|
|
1467
|
+
: (m.label ? String(m.label) : items.length + 1);
|
|
1468
|
+
items.push({
|
|
1469
|
+
id: m.id,
|
|
1470
|
+
number: badge,
|
|
1471
|
+
name: m.name || ('Result ' + (items.length + 1)),
|
|
1472
|
+
category: m.category,
|
|
1473
|
+
distanceMeters: typeof m.distanceMeters === 'number' ? m.distanceMeters : undefined,
|
|
1474
|
+
color: m.color
|
|
1475
|
+
});
|
|
1476
|
+
});
|
|
1477
|
+
return items;
|
|
1478
|
+
}
|
|
1479
|
+
// Exposed so tests can exercise the pure derivation logic without a DOM.
|
|
1480
|
+
window.__derivePanelItems = derivePanelItems;
|
|
1481
|
+
|
|
1482
|
+
// Adds rows for places not yet in this render's panel and enriches just
|
|
1483
|
+
// those. A response is applied only if no newer render has started since
|
|
1484
|
+
// (panelGeneration), so a slow lookup can't write into a newer panel.
|
|
1485
|
+
function maybeShowSidePanel(markers, summary) {
|
|
1486
|
+
var items = derivePanelItems(markers).filter(function(it) {
|
|
1487
|
+
return !panelIds[it.id];
|
|
1488
|
+
});
|
|
1489
|
+
if (items.length === 0) return;
|
|
1490
|
+
items.forEach(function(it) { panelIds[it.id] = true; });
|
|
1491
|
+
appendPanelRows(items, summary || 'Results');
|
|
1492
|
+
var generation = panelGeneration;
|
|
1493
|
+
fetchPlaceDetailsBatch(
|
|
1494
|
+
items.map(function(it) { return it.id; }),
|
|
1495
|
+
TOKEN,
|
|
1496
|
+
API_ENDPOINT
|
|
1497
|
+
).then(function(result) {
|
|
1498
|
+
if (generation === panelGeneration) enrichSidePanel(result);
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
// Keyed by mapbox_id -> { li, meta } elements, so enrichSidePanel can
|
|
1503
|
+
// update a row directly once Place Details resolves, without re-parsing
|
|
1504
|
+
// panelEl's markup back into a queryable DOM (innerHTML + querySelector
|
|
1505
|
+
// round-trips don't work in every MCP Apps host's iframe sandbox, and
|
|
1506
|
+
// building real nodes up front is simpler to reason about either way).
|
|
1507
|
+
// Reset by clearPanel, same lifecycle as the panel itself.
|
|
1508
|
+
var panelRowsById = {};
|
|
1509
|
+
// Bumped by teardown(), so responses from an earlier render are dropped.
|
|
1510
|
+
var panelGeneration = 0;
|
|
1511
|
+
// Id-bearing markers numbered so far this render, and the ids listed.
|
|
1512
|
+
var panelCount = 0;
|
|
1513
|
+
var panelIds = {};
|
|
1514
|
+
// The viewer's collapse choice, kept across renders; null until the first
|
|
1515
|
+
// panel decides a default from the map's width.
|
|
1516
|
+
var panelCollapsed = null;
|
|
1517
|
+
var panelListEl = null;
|
|
1518
|
+
|
|
1519
|
+
function buildPanelRow(it) {
|
|
1520
|
+
var li = document.createElement('li');
|
|
1521
|
+
li.className = 'panel-item';
|
|
1522
|
+
|
|
1523
|
+
var badge = document.createElement('span');
|
|
1524
|
+
badge.className = 'panel-badge';
|
|
1525
|
+
badge.textContent = String(it.number);
|
|
1526
|
+
// Match the pin when the caller colored it (e.g. gray for "other
|
|
1527
|
+
// results" next to a legend); the default orange is in the CSS.
|
|
1528
|
+
if (typeof it.color === 'string' && it.color.toLowerCase() !== '#f97316' &&
|
|
1529
|
+
(/^#[0-9a-f]{3,8}$/i).test(it.color)) {
|
|
1530
|
+
badge.style.background = it.color;
|
|
1531
|
+
badge.style.color = '#fff';
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
var name = document.createElement('div');
|
|
1535
|
+
name.className = 'panel-name';
|
|
1536
|
+
name.textContent = it.name;
|
|
1537
|
+
|
|
1538
|
+
var metaParts = [];
|
|
1539
|
+
if (it.category) metaParts.push(it.category);
|
|
1540
|
+
if (typeof it.distanceMeters === 'number') {
|
|
1541
|
+
metaParts.push(Math.round(it.distanceMeters) + ' m');
|
|
1542
|
+
}
|
|
1543
|
+
var meta = document.createElement('div');
|
|
1544
|
+
meta.className = 'panel-meta';
|
|
1545
|
+
meta.textContent = metaParts.join(' · ');
|
|
1546
|
+
|
|
1547
|
+
var body = document.createElement('div');
|
|
1548
|
+
body.appendChild(name);
|
|
1549
|
+
body.appendChild(meta);
|
|
1550
|
+
li.appendChild(badge);
|
|
1551
|
+
li.appendChild(body);
|
|
1552
|
+
|
|
1553
|
+
li.addEventListener('click', function() {
|
|
1554
|
+
var entry = markersById[it.id];
|
|
1555
|
+
if (entry) map.flyTo({ center: entry.marker.getLngLat(), zoom: 15, duration: 500 });
|
|
1556
|
+
});
|
|
1557
|
+
|
|
1558
|
+
panelRowsById[it.id] = { li: li, meta: meta };
|
|
1559
|
+
return li;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
function clearPanel() {
|
|
1563
|
+
while (panelEl.firstChild) panelEl.removeChild(panelEl.firstChild);
|
|
1564
|
+
panelRowsById = {};
|
|
1565
|
+
panelListEl = null;
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
function applyPanelCollapsed() {
|
|
1569
|
+
panelEl.className = panelCollapsed ? 'collapsed' : '';
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
function togglePanel() {
|
|
1573
|
+
panelCollapsed = !panelCollapsed;
|
|
1574
|
+
applyPanelCollapsed();
|
|
1575
|
+
if (lastFitBounds) fitToBounds(lastFitBounds);
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
// Creates the panel on the render's first id-bearing markers, and adds
|
|
1579
|
+
// rows to it for later ones (e.g. search results merged in after inline
|
|
1580
|
+
// markers), so every numbered pin has a row.
|
|
1581
|
+
function appendPanelRows(items, sourceLabel) {
|
|
1582
|
+
if (!Array.isArray(items) || items.length === 0) return;
|
|
1583
|
+
if (!panelListEl) {
|
|
1584
|
+
var head = document.createElement('div');
|
|
1585
|
+
head.className = 'panel-head';
|
|
1586
|
+
head.textContent = sourceLabel || 'Results';
|
|
1587
|
+
head.addEventListener('click', togglePanel);
|
|
1588
|
+
|
|
1589
|
+
panelListEl = document.createElement('ul');
|
|
1590
|
+
panelListEl.className = 'panel-list';
|
|
1591
|
+
|
|
1592
|
+
panelEl.appendChild(head);
|
|
1593
|
+
panelEl.appendChild(panelListEl);
|
|
1594
|
+
// On a narrow map the open panel would cover most of it.
|
|
1595
|
+
if (panelCollapsed === null) {
|
|
1596
|
+
var width = mapContainerWidth();
|
|
1597
|
+
panelCollapsed = width > 0 && width < 560;
|
|
1598
|
+
}
|
|
1599
|
+
applyPanelCollapsed();
|
|
1600
|
+
panelEl.style.display = 'flex';
|
|
1601
|
+
}
|
|
1602
|
+
var list = panelListEl;
|
|
1603
|
+
items.forEach(function(it) { list.appendChild(buildPanelRow(it)); });
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
// Search Box results mix Mapbox-native POI ids (decode to
|
|
1607
|
+
// "urn:mbxpoi:<uuid>") with OSM-sourced ones (decode to
|
|
1608
|
+
// "urn:mbxpoi-osm:n<osm-node-id>") — confirmed live against a real
|
|
1609
|
+
// category_search_tool-style query near Herndon, VA, where 2 of 10
|
|
1610
|
+
// "cafe" results were OSM-sourced. The Places API's batch endpoint
|
|
1611
|
+
// rejects the ENTIRE request with a 422 if even one id isn't its native
|
|
1612
|
+
// scheme (same 422 PlaceDetailsTool.ts already works around server-side
|
|
1613
|
+
// for boundary ids) — so filter client-side before sending, rather than
|
|
1614
|
+
// let one incompatible id in a 10-result batch silently zero out
|
|
1615
|
+
// enrichment for the other 9. The prefix alone isn't enough: near Union
|
|
1616
|
+
// Square, SF, a Starbucks decodes to "urn:mbxpoi:mapbox-n408854", which
|
|
1617
|
+
// the endpoint also rejects, so require the UUID form.
|
|
1618
|
+
var PLACES_ID = /^urn:mbxpoi:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1619
|
+
function isPlacesApiCompatibleId(id) {
|
|
1620
|
+
if (typeof id !== 'string' || id.length === 0) return false;
|
|
1621
|
+
try {
|
|
1622
|
+
return PLACES_ID.test(atob(id));
|
|
1623
|
+
} catch (e) {
|
|
1624
|
+
return false;
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
// Places API Details endpoint — batch form. Mirrors the single-record
|
|
1629
|
+
// GET src/tools/place-details-tool/PlaceDetailsTool.ts calls server-side,
|
|
1630
|
+
// but the panel needs details for every result at once, so this uses the
|
|
1631
|
+
// POST /details/retrieve batch form (up to 100 ids) instead of one
|
|
1632
|
+
// request per pin. Docs: https://docs.mapbox.com/api/search/places/
|
|
1633
|
+
// Like every other self-fetch call, this runs client-side against the
|
|
1634
|
+
// public token — the Places API's docs list no secret scope requirement
|
|
1635
|
+
// for this endpoint, same as Search Box/Directions/etc.
|
|
1636
|
+
function fetchPlaceDetailsBatch(ids, publicToken, apiEndpoint) {
|
|
1637
|
+
var compatibleIds = (Array.isArray(ids) ? ids : []).filter(isPlacesApiCompatibleId);
|
|
1638
|
+
if (compatibleIds.length === 0) return Promise.resolve(null);
|
|
1639
|
+
var qp = new URLSearchParams();
|
|
1640
|
+
qp.append('access_token', publicToken);
|
|
1641
|
+
var url = apiEndpoint + 'places/v1/details/retrieve?' + qp.toString();
|
|
1642
|
+
var post = function(batch, retried) {
|
|
1643
|
+
return fetch(url, {
|
|
1644
|
+
method: 'POST',
|
|
1645
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1646
|
+
body: JSON.stringify({ ids: batch })
|
|
1647
|
+
}).then(function(res) {
|
|
1648
|
+
// 206 is a partial batch (some ids missing/unprocessed) — still
|
|
1649
|
+
// has usable "results", so treat it the same as 200.
|
|
1650
|
+
if (res.ok || res.status === 206) return res.json();
|
|
1651
|
+
// A 422 names the one id it rejected ("Invalid mapbox_id format:
|
|
1652
|
+
// <id>"), in case an id format slips past the filter above. Drop
|
|
1653
|
+
// that id and try once more, rather than lose the whole batch.
|
|
1654
|
+
if (res.status !== 422 || retried) return null;
|
|
1655
|
+
return res.json().then(function(body) {
|
|
1656
|
+
var msg = body && typeof body.message === 'string' ? body.message : '';
|
|
1657
|
+
var bad = msg.slice(msg.lastIndexOf(' ') + 1).split('=')[0];
|
|
1658
|
+
var rest = batch.filter(function(id) { return id.split('=')[0] !== bad; });
|
|
1659
|
+
if (!bad || rest.length === batch.length || rest.length === 0) return null;
|
|
1660
|
+
return post(rest, true);
|
|
1661
|
+
});
|
|
1662
|
+
});
|
|
1663
|
+
};
|
|
1664
|
+
return post(compatibleIds.slice(0, 100), false)
|
|
1665
|
+
// Enrichment is a nice-to-have on top of an already-rendered panel —
|
|
1666
|
+
// Public Preview quota (1,000 records/month) or a transient error
|
|
1667
|
+
// here should never surface as a map error, just leave the
|
|
1668
|
+
// Search-Box-only rows as they are.
|
|
1669
|
+
.catch(function() { return null; });
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
// Place Details photos are hosted wherever each business's site hosts
|
|
1673
|
+
// them, so the in-chat CSP (mapAppCsp.ts) can't allow them. Inside a host,
|
|
1674
|
+
// the page asks the server for the photo (PlacePhotoResource, by mapbox_id)
|
|
1675
|
+
// and shows it as a data: URL. A standalone page from export_map_html_tool
|
|
1676
|
+
// has no host and no CSP, so it loads the photo URL directly.
|
|
1677
|
+
var MAX_PANEL_PHOTOS = 10;
|
|
1678
|
+
var EMBEDDED = window.parent !== window;
|
|
1679
|
+
var PHOTO_TYPES = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
|
|
1680
|
+
var PHOTO_TIMEOUT_MS = 15000;
|
|
1681
|
+
|
|
1682
|
+
function loadPanelPhoto(row, id, photoUrl) {
|
|
1683
|
+
var show = function(src) {
|
|
1684
|
+
// A later render may have replaced the panel while this loaded.
|
|
1685
|
+
if (panelRowsById[id] !== row) return;
|
|
1686
|
+
var thumb = document.createElement('span');
|
|
1687
|
+
thumb.className = 'panel-thumb';
|
|
1688
|
+
thumb.style.backgroundImage = 'url("' + src.replace(/"/g, '') + '")';
|
|
1689
|
+
row.li.appendChild(thumb);
|
|
1690
|
+
};
|
|
1691
|
+
if (!EMBEDDED || !hostAnswered) {
|
|
1692
|
+
// No MCP host (a standalone or framed exported page), so no CSP of
|
|
1693
|
+
// ours either. Load it first: some sites refuse hotlinked photos (403), which
|
|
1694
|
+
// would leave an empty box in the row.
|
|
1695
|
+
if (photoUrl.indexOf('https://') !== 0 || typeof Image !== 'function') return;
|
|
1696
|
+
var img = new Image();
|
|
1697
|
+
img.onload = function() { show(photoUrl); };
|
|
1698
|
+
img.src = photoUrl;
|
|
1699
|
+
return;
|
|
1700
|
+
}
|
|
1701
|
+
// Hosts that don't support resources/read (ChatGPT) may never answer.
|
|
1702
|
+
sendRequest('resources/read', {
|
|
1703
|
+
uri: 'mapbox://place-photo/' + encodeURIComponent(id)
|
|
1704
|
+
}, PHOTO_TIMEOUT_MS).then(function(rr) {
|
|
1705
|
+
var c = rr && Array.isArray(rr.contents) ? rr.contents[0] : null;
|
|
1706
|
+
if (c && typeof c.blob === 'string' &&
|
|
1707
|
+
PHOTO_TYPES.indexOf(c.mimeType) !== -1) {
|
|
1708
|
+
show('data:' + c.mimeType + ';base64,' + c.blob);
|
|
1709
|
+
}
|
|
1710
|
+
}, function() {});
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
function enrichSidePanel(detailsResult) {
|
|
1714
|
+
if (!detailsResult || !Array.isArray(detailsResult.results)) return;
|
|
1715
|
+
var photosRequested = 0;
|
|
1716
|
+
detailsResult.results.forEach(function(place) {
|
|
1717
|
+
if (!place || !place.mapbox_id) return;
|
|
1718
|
+
var row = panelRowsById[place.mapbox_id];
|
|
1719
|
+
if (row) {
|
|
1720
|
+
var photoUrl = place.photos && place.photos[0] && place.photos[0].url;
|
|
1721
|
+
if (typeof photoUrl === 'string' && photosRequested < MAX_PANEL_PHOTOS) {
|
|
1722
|
+
photosRequested++;
|
|
1723
|
+
loadPanelPhoto(row, place.mapbox_id, photoUrl);
|
|
1724
|
+
}
|
|
1725
|
+
if (place.score && typeof place.score.popularity === 'number') {
|
|
1726
|
+
var extra = Math.round(place.score.popularity * 100) + '% popularity';
|
|
1727
|
+
row.meta.textContent = row.meta.textContent ? row.meta.textContent + ' · ' + extra : extra;
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
var entry = markersById[place.mapbox_id];
|
|
1732
|
+
if (entry && place.phone) {
|
|
1733
|
+
entry.marker.setPopup(
|
|
1734
|
+
new mapboxgl.Popup().setText(entry.popupText + ' — ' + place.phone)
|
|
1735
|
+
);
|
|
1736
|
+
}
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1273
1740
|
function selfFetchSearch(params) {
|
|
1274
1741
|
if (!TOKEN || !isSafeSearchParams(params)) {
|
|
1275
1742
|
showError('Could not fetch search results: missing token or invalid parameters.');
|
|
@@ -1599,11 +2066,15 @@ ${initialDataScript}
|
|
|
1599
2066
|
parts.push(Math.round(poi.distance_meters) + ' m');
|
|
1600
2067
|
}
|
|
1601
2068
|
markers.push({
|
|
2069
|
+
id: poi.id,
|
|
1602
2070
|
coordinates: [poi.longitude, poi.latitude],
|
|
1603
2071
|
style: 'numbered',
|
|
1604
2072
|
label: String(i + 1),
|
|
1605
2073
|
color: '#f97316',
|
|
1606
|
-
popup: parts.join(' — ')
|
|
2074
|
+
popup: parts.join(' — '),
|
|
2075
|
+
name: poi.name,
|
|
2076
|
+
category: poi.category,
|
|
2077
|
+
distanceMeters: typeof poi.distance_meters === 'number' ? poi.distance_meters : undefined
|
|
1607
2078
|
});
|
|
1608
2079
|
});
|
|
1609
2080
|
return { summary: place, layers: [], markers: markers };
|
|
@@ -1662,8 +2133,10 @@ ${initialDataScript}
|
|
|
1662
2133
|
var props = f.properties || {};
|
|
1663
2134
|
var coords = (f.geometry && f.geometry.coordinates) || [params.longitude, params.latitude];
|
|
1664
2135
|
return {
|
|
2136
|
+
id: props.mapbox_id,
|
|
1665
2137
|
name: props.name || 'Unknown',
|
|
1666
2138
|
address: props.full_address || props.place_formatted,
|
|
2139
|
+
category: Array.isArray(props.poi_category) ? props.poi_category[0] : undefined,
|
|
1667
2140
|
longitude: coords[0],
|
|
1668
2141
|
latitude: coords[1],
|
|
1669
2142
|
distance_meters: props.distance
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mapAppHtml.js","sourceRoot":"","sources":["../../../../src/resources/ui-apps/mapAppHtml.ts"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,kCAAkC;;;AAqBlC,
|
|
1
|
+
{"version":3,"file":"mapAppHtml.js","sourceRoot":"","sources":["../../../../src/resources/ui-apps/mapAppHtml.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CategoryListTool.d.ts","sourceRoot":"","sources":["../../../../src/tools/category-list-tool/CategoryListTool.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAiBjF;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,kBAAkB,CACtD,OAAO,uBAAuB,EAC9B,OAAO,0BAA0B,CAClC;IACC,IAAI,SAAwB;IAC5B,WAAW,
|
|
1
|
+
{"version":3,"file":"CategoryListTool.d.ts","sourceRoot":"","sources":["../../../../src/tools/category-list-tool/CategoryListTool.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAiBjF;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,kBAAkB,CACtD,OAAO,uBAAuB,EAC9B,OAAO,0BAA0B,CAClC;IACC,IAAI,SAAwB;IAC5B,WAAW,SACgY;IAC3Y,WAAW;;;;;;MAMT;gBAEU,MAAM,EAAE;QAAE,WAAW,EAAE,WAAW,CAAA;KAAE;cAQhC,OAAO,CACrB,KAAK,EAAE,iBAAiB,EACxB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC;CAmE3B"}
|
|
@@ -12,7 +12,7 @@ exports.CategoryListInputSchema = zod_1.z.object({
|
|
|
12
12
|
.min(1)
|
|
13
13
|
.max(100)
|
|
14
14
|
.optional()
|
|
15
|
-
.describe('Number of categories to return (1-100).
|
|
15
|
+
.describe('Number of categories to return (1-100). If not specified, returns all categories.'),
|
|
16
16
|
offset: zod_1.z
|
|
17
17
|
.number()
|
|
18
18
|
.min(0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CategoryListTool.input.schema.js","sourceRoot":"","sources":["../../../../src/tools/category-list-tool/CategoryListTool.input.schema.ts"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,kCAAkC;;;AAElC,6BAAwB;AACxB,uDAAyD;AAE5C,QAAA,uBAAuB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC9C,QAAQ,EAAE,0BAAc,CAAC,QAAQ,EAAE;IACnC,KAAK,EAAE,OAAC;SACL,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,GAAG,CAAC;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,
|
|
1
|
+
{"version":3,"file":"CategoryListTool.input.schema.js","sourceRoot":"","sources":["../../../../src/tools/category-list-tool/CategoryListTool.input.schema.ts"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,kCAAkC;;;AAElC,6BAAwB;AACxB,uDAAyD;AAE5C,QAAA,uBAAuB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC9C,QAAQ,EAAE,0BAAc,CAAC,QAAQ,EAAE;IACnC,KAAK,EAAE,OAAC;SACL,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,GAAG,CAAC;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,mFAAmF,CACpF;IACH,MAAM,EAAE,OAAC;SACN,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,EAAE;SACV,OAAO,CAAC,CAAC,CAAC;SACV,QAAQ,CAAC,4DAA4D,CAAC;CAC1E,CAAC,CAAC"}
|
|
@@ -12,7 +12,7 @@ const CategoryListTool_output_schema_js_1 = require("./CategoryListTool.output.s
|
|
|
12
12
|
*/
|
|
13
13
|
class CategoryListTool extends MapboxApiBasedTool_js_1.MapboxApiBasedTool {
|
|
14
14
|
name = 'category_list_tool';
|
|
15
|
-
description = '[DEPRECATED: Use resource_reader_tool with "mapbox://categories" URI instead] Tool for retrieving the list of supported categories from Mapbox Search API. This tool is kept for backward compatibility with clients that do not support MCP resources. Use this when another function requires a list of categories. Returns all available category IDs by default.
|
|
15
|
+
description = '[DEPRECATED: Use resource_reader_tool with "mapbox://categories" URI instead] Tool for retrieving the list of supported categories from Mapbox Search API. This tool is kept for backward compatibility with clients that do not support MCP resources. Use this when another function requires a list of categories. Returns all available category IDs by default. Supports limit/offset pagination.';
|
|
16
16
|
annotations = {
|
|
17
17
|
title: 'Category List Tool (Deprecated)',
|
|
18
18
|
readOnlyHint: true,
|