feat(sources): add multiple sources

This commit is contained in:
vl.arkhangelskii
2026-09-21 04:51:23 +03:00
parent 1c187ed56b
commit 946b77540f
18 changed files with 1494 additions and 110 deletions
@@ -0,0 +1,5 @@
# Несколько source в стиле
`?source=central-fed-district,volga-fed-district` — сервер вешает отдельный vector source на каждый extract и клонирует слои (`water__volga-fed-district`). Один MapLibre style, несколько округов.
Кабинет: чекбоксы округов в редакторе. Инструкции обновлены.
@@ -0,0 +1,3 @@
# web-demo: чекбоксы округов
Селект источника заменён на чекбоксы. Стиль грузится с `?source=id1,id2`. Последний округ снять нельзя. Fit bounds объединяет выбранные extract.
@@ -6,6 +6,7 @@ using TileServer.Api.Http;
using TileServer.Application.Accounts; using TileServer.Application.Accounts;
using TileServer.Application.Configuration; using TileServer.Application.Configuration;
using TileServer.Application.Extracts; using TileServer.Application.Extracts;
using TileServer.Application.Styles;
using TileServer.Application.Tiles; using TileServer.Application.Tiles;
using TileServer.Domain.Exceptions; using TileServer.Domain.Exceptions;
using TileServer.Domain.Tiles; using TileServer.Domain.Tiles;
@@ -72,17 +73,19 @@ public sealed class PersonalDeliveryController(
{ {
var access = await ResolveAsync(slug, ct).ConfigureAwait(false); var access = await ResolveAsync(slug, ct).ConfigureAwait(false);
var token = AccessToken.Read(Request) ?? string.Empty; var token = AccessToken.Read(Request) ?? string.Empty;
var extract = string.IsNullOrWhiteSpace(source) var selected = ExtractSourceQuery.Resolve(source, extracts);
? extracts.GetAll().FirstOrDefault(e => e.Enabled) if (selected.Count == 0)
: extracts.Find(source);
if (extract is null)
{ {
throw new ResourceNotFoundException("Extract", source ?? "(none configured)"); throw new ResourceNotFoundException("Extract", source ?? "(none configured)");
} }
var tilesUrl = var root = PublicUrl.GetBase(Request, options);
$"{PublicUrl.GetBase(Request, options)}/u/{access.User.Slug}/tiles/{extract.Id}/{{z}}/{{x}}/{{y}}.pbf?v=3&token={Uri.EscapeDataString(token)}"; var bound = selected
var style = await styles.GetForDeliveryAsync(access.User.Slug, name, extract.Id, tilesUrl, ct) .Select(extract => new BoundExtract(
extract.Id,
$"{root}/u/{access.User.Slug}/tiles/{extract.Id}/{{z}}/{{x}}/{{y}}.pbf?v=3&token={Uri.EscapeDataString(token)}"))
.ToArray();
var style = await styles.GetForDeliveryAsync(access.User.Slug, name, bound, ct)
.ConfigureAwait(false); .ConfigureAwait(false);
var json = style.ToJsonString(); var json = style.ToJsonString();
usage.RecordStyle(access.User.Id, access.Token.Id, Encoding.UTF8.GetByteCount(json)); usage.RecordStyle(access.User.Id, access.Token.Id, Encoding.UTF8.GetByteCount(json));
@@ -17,5 +17,9 @@ public interface IUserStyleService
Task<IReadOnlyList<StyleListItem>> ListForDeliveryAsync(string slug, string baseUrl, string token, CancellationToken ct); Task<IReadOnlyList<StyleListItem>> ListForDeliveryAsync(string slug, string baseUrl, string token, CancellationToken ct);
Task<JsonObject> GetForDeliveryAsync(string slug, string name, string extractId, string tilesUrl, CancellationToken ct); Task<JsonObject> GetForDeliveryAsync(
string slug,
string name,
IReadOnlyList<BoundExtract> extracts,
CancellationToken ct);
} }
@@ -130,8 +130,7 @@ public sealed class UserStyleService(
public async Task<JsonObject> GetForDeliveryAsync( public async Task<JsonObject> GetForDeliveryAsync(
string slug, string slug,
string name, string name,
string extractId, IReadOnlyList<BoundExtract> extracts,
string tilesUrl,
CancellationToken ct) CancellationToken ct)
{ {
var styleName = ResourceName.Require(name, nameof(name)); var styleName = ResourceName.Require(name, nameof(name));
@@ -139,7 +138,7 @@ public sealed class UserStyleService(
?? throw new ResourceNotFoundException("User", slug); ?? throw new ResourceNotFoundException("User", slug);
var own = await styles.FindAsync(user.Id, styleName, ct).ConfigureAwait(false); var own = await styles.FindAsync(user.Id, styleName, ct).ConfigureAwait(false);
var raw = own is null ? catalog.GetRequired(styleName) : Parse(own.Json, styleName); var raw = own is null ? catalog.GetRequired(styleName) : Parse(own.Json, styleName);
return styleService.Bind(raw, extractId, tilesUrl); return styleService.Bind(raw, extracts);
} }
private static JsonObject Parse(string json, string name) private static JsonObject Parse(string json, string name)
@@ -0,0 +1,55 @@
using TileServer.Domain;
using TileServer.Domain.Exceptions;
using TileServer.Domain.Extracts;
namespace TileServer.Application.Extracts;
public static class ExtractSourceQuery
{
public const int MaxCount = 16;
public static IReadOnlyList<Extract> Resolve(string? source, IExtractCatalog catalog)
{
var ids = ParseIds(source, catalog);
var result = new List<Extract>(ids.Count);
foreach (var id in ids)
{
result.Add(catalog.Find(id) ?? throw new ResourceNotFoundException("Extract", id));
}
return result;
}
private static IReadOnlyList<string> ParseIds(string? source, IExtractCatalog catalog)
{
if (string.IsNullOrWhiteSpace(source))
{
var first = catalog.GetAll().FirstOrDefault(item => item.Enabled);
return first is null ? [] : [first.Id];
}
var seen = new HashSet<string>(StringComparer.Ordinal);
var ids = new List<string>();
foreach (var part in source.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
var id = ResourceName.Require(part, nameof(source));
if (!seen.Add(id))
{
continue;
}
ids.Add(id);
if (ids.Count >= MaxCount)
{
break;
}
}
if (ids.Count == 0)
{
throw new DomainValidationException("At least one source is required.");
}
return ids;
}
}
@@ -4,6 +4,8 @@ namespace TileServer.Application.Styles;
public sealed record StyleListItem(string Name, string Url); public sealed record StyleListItem(string Name, string Url);
public sealed record BoundExtract(string ExtractId, string TilesUrl);
public interface IStyleService public interface IStyleService
{ {
IReadOnlyList<StyleListItem> List(string baseUrl); IReadOnlyList<StyleListItem> List(string baseUrl);
@@ -12,5 +14,7 @@ public interface IStyleService
JsonObject Bind(JsonObject style, string extractId, string tilesUrl); JsonObject Bind(JsonObject style, string extractId, string tilesUrl);
JsonObject Bind(JsonObject style, IReadOnlyList<BoundExtract> extracts);
Task SaveAsync(string name, JsonObject style, CancellationToken ct); Task SaveAsync(string name, JsonObject style, CancellationToken ct);
} }
@@ -31,11 +31,26 @@ public sealed class StyleService(
} }
public JsonObject Bind(JsonObject style, string extractId, string tilesUrl) public JsonObject Bind(JsonObject style, string extractId, string tilesUrl)
=> Bind(style, [new BoundExtract(extractId, tilesUrl)]);
public JsonObject Bind(JsonObject style, IReadOnlyList<BoundExtract> extracts)
{ {
var extract = ResolveExtract(extractId); if (extracts.Count == 0)
{
throw new DomainValidationException("At least one extract is required.");
}
var clone = JsonNode.Parse(style.ToJsonString())?.AsObject() var clone = JsonNode.Parse(style.ToJsonString())?.AsObject()
?? throw new DomainValidationException("Style must be a JSON object."); ?? throw new DomainValidationException("Style must be a JSON object.");
BindRuntimeUrls(clone, extract, tilesUrl); var first = extracts[0];
BindRuntimeUrls(clone, ResolveExtract(first.ExtractId), first.TilesUrl);
var primaryKeys = VectorSourceKeys(clone);
for (var i = 1; i < extracts.Count; i++)
{
var extra = extracts[i];
AppendExtract(clone, ResolveExtract(extra.ExtractId), extra.TilesUrl, primaryKeys);
}
return clone; return clone;
} }
@@ -87,6 +102,71 @@ public sealed class StyleService(
} }
} }
private void AppendExtract(
JsonObject style,
Extract extract,
string tilesUrl,
IReadOnlyList<string> primarySourceKeys)
{
if (style["sources"] is not JsonObject sources || style["layers"] is not JsonArray layers)
{
throw new DomainValidationException("Style must have sources and layers.");
}
var metadata = tileStore.GetMetadata(extract.Id);
var minZoom = metadata?.MinZoom ?? extract.MinZoom;
var maxZoom = metadata?.MaxZoom ?? extract.MaxZoom;
var suffix = "__" + extract.Id;
var primary = primarySourceKeys.ToHashSet(StringComparer.Ordinal);
foreach (var key in primarySourceKeys)
{
sources[key + suffix] = CreateVectorSource(tilesUrl, minZoom, maxZoom);
}
var extras = new List<JsonNode>();
foreach (var node in layers)
{
if (node is not JsonObject layer)
{
continue;
}
var sourceName = layer["source"]?.GetValue<string>();
if (sourceName is null || !primary.Contains(sourceName))
{
continue;
}
var copy = JsonNode.Parse(layer.ToJsonString())?.AsObject()
?? throw new DomainValidationException("Layer clone failed.");
var id = layer["id"]?.GetValue<string>() ?? "layer";
copy["id"] = id + suffix;
copy["source"] = sourceName + suffix;
extras.Add(copy);
}
foreach (var extra in extras)
{
layers.Add(extra);
}
}
private static IReadOnlyList<string> VectorSourceKeys(JsonObject style)
{
if (style["sources"] is not JsonObject sources)
{
return [];
}
return sources
.Where(property =>
property.Value is JsonObject source &&
string.Equals(source["type"]?.GetValue<string>(), "vector", StringComparison.OrdinalIgnoreCase))
.Select(property => property.Key)
.ToArray();
}
private static JsonObject CreateVectorSource(string tilesUrl, int minZoom, int maxZoom) private static JsonObject CreateVectorSource(string tilesUrl, int minZoom, int maxZoom)
{ {
var source = new JsonObject var source = new JsonObject
@@ -131,6 +131,74 @@ public sealed class StyleServiceTests
Assert.Contains("token=ts_abc", tile, StringComparison.Ordinal); Assert.Contains("token=ts_abc", tile, StringComparison.Ordinal);
} }
[Fact]
public void Bind_MultipleExtracts_AddsSourcesAndClonesLayers()
{
var central = SampleExtract("central-fed-district", 37.6, 55.7);
var volga = SampleExtract("volga-fed-district", 45, 57);
var template = new JsonObject
{
["version"] = 8,
["sources"] = new JsonObject
{
["openmaptiles"] = new JsonObject { ["type"] = "vector" }
},
["layers"] = new JsonArray
{
new JsonObject
{
["id"] = "background",
["type"] = "background",
["paint"] = new JsonObject { ["background-color"] = "#000" }
},
new JsonObject
{
["id"] = "water",
["type"] = "fill",
["source"] = "openmaptiles",
["source-layer"] = "water"
}
}
};
var service = new StyleService(
new MemoryStyleCatalog(template),
new MemoryExtractCatalog(central, volga),
new MemoryTileStore(SampleMetadata(central)),
Options.Create(new TileServerOptions()));
var style = service.Bind(template, [
new BoundExtract(central.Id, "https://tile-server.ru/u/alice/tiles/central-fed-district/{z}/{x}/{y}.pbf?token=ts"),
new BoundExtract(volga.Id, "https://tile-server.ru/u/alice/tiles/volga-fed-district/{z}/{x}/{y}.pbf?token=ts")
]);
var sources = style["sources"]!.AsObject();
Assert.True(sources.ContainsKey("openmaptiles"));
Assert.True(sources.ContainsKey("openmaptiles__volga-fed-district"));
Assert.Contains("volga-fed-district", sources["openmaptiles__volga-fed-district"]!["tiles"]![0]!.GetValue<string>(), StringComparison.Ordinal);
var layers = style["layers"]!.AsArray();
Assert.Equal(3, layers.Count);
Assert.Equal("water__volga-fed-district", layers[2]!["id"]!.GetValue<string>());
Assert.Equal("openmaptiles__volga-fed-district", layers[2]!["source"]!.GetValue<string>());
Assert.Null(layers[0]!["source"]);
}
private static Extract SampleExtract(string id, double lon, double lat)
=> new()
{
Id = id,
Name = id,
Url = new Uri($"https://download.geofabrik.de/russia/{id}-latest.osm.pbf"),
CenterLon = lon,
CenterLat = lat,
MinZoom = 0,
MaxZoom = 14
};
private static TilesetMetadata SampleMetadata(Extract extract)
=> new(extract.Id, extract.Name, "pbf", 0, 0, 1, 1, 0, 0, 5, 0, 14, []);
private sealed class MemoryStyleCatalog(JsonObject style) : IStyleCatalog private sealed class MemoryStyleCatalog(JsonObject style) : IStyleCatalog
{ {
public IReadOnlyList<MapStyleInfo> List() => [new("osm-bright", DateTimeOffset.UnixEpoch)]; public IReadOnlyList<MapStyleInfo> List() => [new("osm-bright", DateTimeOffset.UnixEpoch)];
@@ -143,11 +211,11 @@ public sealed class StyleServiceTests
public Task SeedDefaultsAsync(CancellationToken ct) => Task.CompletedTask; public Task SeedDefaultsAsync(CancellationToken ct) => Task.CompletedTask;
} }
private sealed class MemoryExtractCatalog(Extract extract) : IExtractCatalog private sealed class MemoryExtractCatalog(params Extract[] extracts) : IExtractCatalog
{ {
public IReadOnlyList<Extract> GetAll() => [extract]; public IReadOnlyList<Extract> GetAll() => extracts;
public Extract? Find(string id) => id == extract.Id ? extract : null; public Extract? Find(string id) => extracts.FirstOrDefault(item => item.Id == id);
public Extract GetRequired(string id) public Extract GetRequired(string id)
=> Find(id) ?? throw new InvalidOperationException(id); => Find(id) ?? throw new InvalidOperationException(id);
+62 -46
View File
@@ -62,7 +62,7 @@ export function App() {
const [sources, setSources] = useState<SourceItem[]>([]); const [sources, setSources] = useState<SourceItem[]>([]);
const [styles, setStyles] = useState<StyleItem[]>([]); const [styles, setStyles] = useState<StyleItem[]>([]);
const [sync, setSync] = useState<SyncStatus | null>(null); const [sync, setSync] = useState<SyncStatus | null>(null);
const [sourceId, setSourceId] = useState(""); const [selectedSourceIds, setSelectedSourceIds] = useState<string[]>([]);
const [styleName, setStyleName] = useState("osm-bright"); const [styleName, setStyleName] = useState("osm-bright");
const [coords, setCoords] = useState("—"); const [coords, setCoords] = useState("—");
const [gotoError, setGotoError] = useState(""); const [gotoError, setGotoError] = useState("");
@@ -79,7 +79,8 @@ export function App() {
accessRef.current = access; accessRef.current = access;
const personal = isPersonal(access); const personal = isPersonal(access);
const source = sources.find((item) => item.id === sourceId) ?? sources[0]; const selectedSources = sources.filter((item) => selectedSourceIds.includes(item.id));
const source = selectedSources[0] ?? sources[0];
const updateHud = useCallback((map: MapLibreMap) => { const updateHud = useCallback((map: MapLibreMap) => {
const center = map.getCenter(); const center = map.getCenter();
@@ -132,18 +133,18 @@ export function App() {
return; return;
} }
if (!source || !styleName || !mapEl.current) { if (selectedSourceIds.length === 0 || !styleName || !mapEl.current) {
return; return;
} }
const styleKey = `${personal ? access.slug : "public"}|${source.id}|${styleName}|${source.status}|${source.builtAt ?? ""}`; const styleKey = `${access.slug}|${selectedSourceIds.join(",")}|${styleName}|${selectedSources.map((item) => `${item.status}:${item.builtAt ?? ""}`).join(";")}`;
if (mapRef.current && styleKeyRef.current === styleKey) { if (mapRef.current && styleKeyRef.current === styleKey) {
return; return;
} }
const style = await fetchJson<StyleSpecification>(styleUrl(access, styleName, source.id)); const style = await fetchJson<StyleSpecification>(styleUrl(access, styleName, selectedSourceIds));
const hashed = cameraFromHash(); const hashed = cameraFromHash();
const center = hashed ? [hashed.lon, hashed.lat] : (source.center ?? [37.6173, 55.7558]); const center = hashed ? [hashed.lon, hashed.lat] : (source?.center ?? [37.6173, 55.7558]);
const zoom = hashed ? hashed.zoom : 6; const zoom = hashed ? hashed.zoom : 6;
if (!mapRef.current) { if (!mapRef.current) {
@@ -177,13 +178,13 @@ export function App() {
} }
styleKeyRef.current = styleKey; styleKeyRef.current = styleKey;
const ready = source.status === "Ready"; const pending = selectedSources.find((item) => item.status !== "Ready");
setBanner( setBanner(
ready pending
? "" ? `Тайлы источника «${pending.name}» ещё не готовы (${formatStatus(pending.status)}). Первый прогон может занять часы.`
: `Тайлы источника «${source.name}» ещё не готовы (${formatStatus(source.status)}). Первый прогон может занять часы.` : ""
); );
}, [access, personal, source, styleName, syncGotoFromMap, updateHud]); }, [access, personal, selectedSourceIds, sources, source, styleName, syncGotoFromMap, updateHud]);
const refresh = useCallback(async () => { const refresh = useCallback(async () => {
const [sourceList, syncStatus] = await Promise.all([ const [sourceList, syncStatus] = await Promise.all([
@@ -196,9 +197,10 @@ export function App() {
setSources(sourceList); setSources(sourceList);
setStyles(styleList); setStyles(styleList);
setSync(syncStatus); setSync(syncStatus);
setSourceId((current) => setSelectedSourceIds((current) => {
sourceList.some((item) => item.id === current) ? current : (sourceList[0]?.id ?? "") const kept = current.filter((id) => sourceList.some((item) => item.id === id));
); return kept.length > 0 ? kept : sourceList[0] ? [sourceList[0].id] : [];
});
setStyleName((current) => setStyleName((current) =>
styleList.some((item) => item.name === current) styleList.some((item) => item.name === current)
? current ? current
@@ -254,16 +256,16 @@ export function App() {
}; };
const fitBounds = () => { const fitBounds = () => {
const bounds = source?.bounds; const boxes = selectedSources.map((item) => item.bounds).filter((item): item is NonNullable<typeof item> => Boolean(item));
const map = mapRef.current; const map = mapRef.current;
if (!map || !bounds) { if (!map || boxes.length === 0) {
setGotoError("У источника ещё нет bounds."); setGotoError("У выбранных источников ещё нет bounds.");
return; return;
} }
map.fitBounds( map.fitBounds(
[ [
[bounds.minLon, bounds.minLat], [Math.min(...boxes.map((b) => b.minLon)), Math.min(...boxes.map((b) => b.minLat))],
[bounds.maxLon, bounds.maxLat] [Math.max(...boxes.map((b) => b.maxLon)), Math.max(...boxes.map((b) => b.maxLat))]
], ],
{ padding: 48, maxZoom: 10 } { padding: 48, maxZoom: 10 }
); );
@@ -272,10 +274,13 @@ export function App() {
const startSync = async () => { const startSync = async () => {
setSyncing(true); setSyncing(true);
try { try {
const url = source const ids = selectedSourceIds.length > 0 ? selectedSourceIds : source ? [source.id] : [];
? serviceUrl(`/api/v1/sync/${encodeURIComponent(source.id)}`) for (const id of ids) {
: serviceUrl("/api/v1/sync"); await fetchJson(serviceUrl(`/api/v1/sync/${encodeURIComponent(id)}`), { method: "POST" });
await fetchJson(url, { method: "POST" }); }
if (ids.length === 0) {
await fetchJson(serviceUrl("/api/v1/sync"), { method: "POST" });
}
await refresh(); await refresh();
} catch (err: unknown) { } catch (err: unknown) {
setBanner(err instanceof Error ? err.message : "Не удалось запустить синхронизацию"); setBanner(err instanceof Error ? err.message : "Не удалось запустить синхронизацию");
@@ -284,7 +289,12 @@ export function App() {
} }
}; };
const status = source?.status; const mixedStatus = selectedSources.some((item) => item.status === "Failed")
? "Failed"
: selectedSources.every((item) => item.status === "Ready")
? "Ready"
: selectedSources[0]?.status;
const status = mixedStatus;
const pillClass = const pillClass =
status === "Ready" ? "pill pill--ok" : status === "Failed" ? "pill pill--fail" : "pill pill--work"; status === "Ready" ? "pill pill--ok" : status === "Failed" ? "pill pill--fail" : "pill pill--work";
const workerClass = [ const workerClass = [
@@ -365,26 +375,32 @@ export function App() {
</button> </button>
) : null} ) : null}
<span className={personal ? "pill pill--ok" : "pill"}>{personal ? "личный" : "публичный"}</span> <span className={personal ? "pill pill--ok" : "pill"}>{personal ? "личный" : "публичный"}</span>
<label className="field field--inline"> <fieldset className="field field--sources">
<span>Источник</span> <legend>Округа</legend>
<select <div className="source-checks">
value={sourceId} {sources.map((item) => {
onChange={(e) => { const checked = selectedSourceIds.includes(item.id);
const next = e.target.value; return (
setSourceId(next); <label key={item.id}>
const item = sources.find((s) => s.id === next); <input
if (mapRef.current && item?.center) { type="checkbox"
flyTo(item.center[1], item.center[0], Math.max(mapRef.current.getZoom(), 6)); checked={checked}
} onChange={() => {
}} setSelectedSourceIds((current) => {
> if (checked) {
{sources.map((item) => ( const next = current.filter((id) => id !== item.id);
<option key={item.id} value={item.id}> return next.length > 0 ? next : current;
{item.name} }
</option> return [...current, item.id];
))} });
</select> }}
</label> />
{item.name}
</label>
);
})}
</div>
</fieldset>
<label className="field field--inline"> <label className="field field--inline">
<span>Стиль</span> <span>Стиль</span>
<select value={styleName} onChange={(e) => setStyleName(e.target.value)}> <select value={styleName} onChange={(e) => setStyleName(e.target.value)}>
@@ -455,8 +471,8 @@ export function App() {
<dd>{sync?.isRunning ? "идёт синхронизация" : "ожидание"}</dd> <dd>{sync?.isRunning ? "идёт синхронизация" : "ожидание"}</dd>
</div> </div>
<div> <div>
<dt>Источник</dt> <dt>Округа</dt>
<dd>{formatStatus(status)}</dd> <dd>{selectedSources.length > 0 ? `${selectedSources.length}: ${formatStatus(status)}` : formatStatus(status)}</dd>
</div> </div>
<div> <div>
<dt>Скачан</dt> <dt>Скачан</dt>
+4 -3
View File
@@ -54,13 +54,14 @@ export function stylesListUrl(access: Access): string {
return serviceUrl("/api/v1/styles"); return serviceUrl("/api/v1/styles");
} }
export function styleUrl(access: Access, name: string, sourceId: string): string { export function styleUrl(access: Access, name: string, sourceIds: string[]): string {
const source = sourceIds.join(",");
if (isPersonal(access)) { if (isPersonal(access)) {
return serviceUrl( return serviceUrl(
`/u/${encodeURIComponent(access.slug)}/styles/${encodeURIComponent(name)}?source=${encodeURIComponent(sourceId)}&token=${encodeURIComponent(access.token)}` `/u/${encodeURIComponent(access.slug)}/styles/${encodeURIComponent(name)}?source=${encodeURIComponent(source)}&token=${encodeURIComponent(access.token)}`
); );
} }
return serviceUrl(`/api/v1/styles/${encodeURIComponent(name)}?source=${encodeURIComponent(sourceId)}`); return serviceUrl(`/api/v1/styles/${encodeURIComponent(name)}?source=${encodeURIComponent(source)}`);
} }
export function rewriteServiceUrl(url: string, access: Access): string { export function rewriteServiceUrl(url: string, access: Access): string {
+49
View File
@@ -123,6 +123,55 @@ body {
.field--inline { min-width: 10.5rem; } .field--inline { min-width: 10.5rem; }
.field--sources {
min-width: 16rem;
margin: 0;
padding: 0;
border: 0;
}
.field--sources legend {
padding: 0;
margin-bottom: 0.28rem;
}
.source-checks {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.35rem 0.75rem;
min-height: 2.75rem;
padding: 0.4rem 0.65rem;
border-radius: var(--radius-sm);
border: 1px solid var(--line-strong);
background: rgba(8, 11, 16, 0.72);
}
.source-checks label {
display: flex;
align-items: center;
gap: 0.4rem;
margin: 0;
padding: 0;
border: 0;
background: none;
min-height: 0;
color: var(--text);
font-size: 0.78rem;
letter-spacing: 0;
text-transform: none;
cursor: pointer;
}
.source-checks input {
width: 0.95rem;
height: 0.95rem;
min-height: 0;
margin: 0;
padding: 0;
accent-color: var(--accent);
}
.field--token { min-width: 14rem; } .field--token { min-width: 14rem; }
.field--token input { .field--token input {
+973
View File
@@ -0,0 +1,973 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@babel/code-frame@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.7.tgz#f2fbbfea87c44a21590ec515b778b2c26d8866e7"
integrity sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==
dependencies:
"@babel/helper-validator-identifier" "^7.29.7"
js-tokens "^4.0.0"
picocolors "^1.1.1"
"@babel/compat-data@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.7.tgz#6f0237f0f36d2e51c0570a636faed9d2d0efe629"
integrity sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==
"@babel/core@^7.28.0":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.7.tgz#80c10b17248082968b57a857b91640971f2070f7"
integrity sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==
dependencies:
"@babel/code-frame" "^7.29.7"
"@babel/generator" "^7.29.7"
"@babel/helper-compilation-targets" "^7.29.7"
"@babel/helper-module-transforms" "^7.29.7"
"@babel/helpers" "^7.29.7"
"@babel/parser" "^7.29.7"
"@babel/template" "^7.29.7"
"@babel/traverse" "^7.29.7"
"@babel/types" "^7.29.7"
"@jridgewell/remapping" "^2.3.5"
convert-source-map "^2.0.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.2.3"
semver "^6.3.1"
"@babel/generator@^7.29.7", "@babel/generator@^7.29.8":
version "7.29.8"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.8.tgz#4b0b887885422643339e09022148a4c4ebaa4979"
integrity sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==
dependencies:
"@babel/parser" "^7.29.8"
"@babel/types" "^7.29.8"
"@jridgewell/gen-mapping" "^0.3.12"
"@jridgewell/trace-mapping" "^0.3.28"
jsesc "^3.0.2"
"@babel/helper-compilation-targets@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz#7a1def704302401c47f64fa85589e974ae217042"
integrity sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==
dependencies:
"@babel/compat-data" "^7.29.7"
"@babel/helper-validator-option" "^7.29.7"
browserslist "^4.24.0"
lru-cache "^5.1.1"
semver "^6.3.1"
"@babel/helper-globals@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz#f04a96fbd8473241b1079243f5b3f03a3010ab7b"
integrity sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==
"@babel/helper-module-imports@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz#ef25048a518e828d7393fac5882ddd73921d7396"
integrity sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==
dependencies:
"@babel/traverse" "^7.29.7"
"@babel/types" "^7.29.7"
"@babel/helper-module-transforms@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz#b062747a5997ba138637201328bbff77960574ae"
integrity sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==
dependencies:
"@babel/helper-module-imports" "^7.29.7"
"@babel/helper-validator-identifier" "^7.29.7"
"@babel/traverse" "^7.29.7"
"@babel/helper-plugin-utils@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz#c0a0766f1a13617d8a17407d7ab8f9d486225ea4"
integrity sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==
"@babel/helper-string-parser@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz#7f0871d99824d23137d60f86fcf6130fd5a1b51f"
integrity sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==
"@babel/helper-validator-identifier@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz#bd87084ced0c796ec46bda492de6e83d29e89fc2"
integrity sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==
"@babel/helper-validator-option@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz#cf315be940213b354eb4abcc0bd01ebe3f73bc2a"
integrity sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==
"@babel/helpers@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.29.7.tgz#45abfde7548997e34376c3e69feb475cffb4a607"
integrity sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==
dependencies:
"@babel/template" "^7.29.7"
"@babel/types" "^7.29.7"
"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.29.7", "@babel/parser@^7.29.8":
version "7.29.9"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.9.tgz#e7ee0a24f752c5296c6455855ccb72662e67ea96"
integrity sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==
dependencies:
"@babel/types" "^7.29.8"
"@babel/plugin-transform-react-jsx-self@^7.27.1":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz#c24424527858220624fd59a5b1eab4fa413c803a"
integrity sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==
dependencies:
"@babel/helper-plugin-utils" "^7.29.7"
"@babel/plugin-transform-react-jsx-source@^7.27.1":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz#5cf25a3689906b58e2f0a2f2b374789e6627b15f"
integrity sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==
dependencies:
"@babel/helper-plugin-utils" "^7.29.7"
"@babel/template@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.29.7.tgz#4d9d4004f645cdd304de958c725162784ecac700"
integrity sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==
dependencies:
"@babel/code-frame" "^7.29.7"
"@babel/parser" "^7.29.7"
"@babel/types" "^7.29.7"
"@babel/traverse@^7.29.7":
version "7.29.8"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.8.tgz#4111014cdc71a0f95d9471907590baa0b8a6b28a"
integrity sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==
dependencies:
"@babel/code-frame" "^7.29.7"
"@babel/generator" "^7.29.8"
"@babel/helper-globals" "^7.29.7"
"@babel/parser" "^7.29.8"
"@babel/template" "^7.29.7"
"@babel/types" "^7.29.8"
debug "^4.3.1"
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.28.2", "@babel/types@^7.29.7", "@babel/types@^7.29.8":
version "7.29.8"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.8.tgz#1229eef31d85156d70fa3f4cd859376d0eaf6863"
integrity sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==
dependencies:
"@babel/helper-string-parser" "^7.29.7"
"@babel/helper-validator-identifier" "^7.29.7"
"@esbuild/aix-ppc64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz#80fcbe36130e58b7670511e888b8e88a259ed76c"
integrity sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==
"@esbuild/android-arm64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz#8aa4965f8d0a7982dc21734bf6601323a66da752"
integrity sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==
"@esbuild/android-arm@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.12.tgz#300712101f7f50f1d2627a162e6e09b109b6767a"
integrity sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==
"@esbuild/android-x64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.12.tgz#87dfb27161202bdc958ef48bb61b09c758faee16"
integrity sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==
"@esbuild/darwin-arm64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz#79197898ec1ff745d21c071e1c7cc3c802f0c1fd"
integrity sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==
"@esbuild/darwin-x64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz#146400a8562133f45c4d2eadcf37ddd09718079e"
integrity sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==
"@esbuild/freebsd-arm64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz#1c5f9ba7206e158fd2b24c59fa2d2c8bb47ca0fe"
integrity sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==
"@esbuild/freebsd-x64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz#ea631f4a36beaac4b9279fa0fcc6ca29eaeeb2b3"
integrity sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==
"@esbuild/linux-arm64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz#e1066bce58394f1b1141deec8557a5f0a22f5977"
integrity sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==
"@esbuild/linux-arm@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz#452cd66b20932d08bdc53a8b61c0e30baf4348b9"
integrity sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==
"@esbuild/linux-ia32@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz#b24f8acc45bcf54192c7f2f3be1b53e6551eafe0"
integrity sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==
"@esbuild/linux-loong64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz#f9cfffa7fc8322571fbc4c8b3268caf15bd81ad0"
integrity sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==
"@esbuild/linux-mips64el@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz#575a14bd74644ffab891adc7d7e60d275296f2cd"
integrity sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==
"@esbuild/linux-ppc64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz#75b99c70a95fbd5f7739d7692befe60601591869"
integrity sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==
"@esbuild/linux-riscv64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz#2e3259440321a44e79ddf7535c325057da875cd6"
integrity sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==
"@esbuild/linux-s390x@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz#17676cabbfe5928da5b2a0d6df5d58cd08db2663"
integrity sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==
"@esbuild/linux-x64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz#0583775685ca82066d04c3507f09524d3cd7a306"
integrity sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==
"@esbuild/netbsd-arm64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz#f04c4049cb2e252fe96b16fed90f70746b13f4a4"
integrity sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==
"@esbuild/netbsd-x64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz#77da0d0a0d826d7c921eea3d40292548b258a076"
integrity sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==
"@esbuild/openbsd-arm64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz#6296f5867aedef28a81b22ab2009c786a952dccd"
integrity sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==
"@esbuild/openbsd-x64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz#f8d23303360e27b16cf065b23bbff43c14142679"
integrity sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==
"@esbuild/openharmony-arm64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz#49e0b768744a3924be0d7fd97dd6ce9b2923d88d"
integrity sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==
"@esbuild/sunos-x64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz#a6ed7d6778d67e528c81fb165b23f4911b9b13d6"
integrity sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==
"@esbuild/win32-arm64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz#9ac14c378e1b653af17d08e7d3ce34caef587323"
integrity sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==
"@esbuild/win32-ia32@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz#918942dcbbb35cc14fca39afb91b5e6a3d127267"
integrity sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==
"@esbuild/win32-x64@0.25.12":
version "0.25.12"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz#9bdad8176be7811ad148d1f8772359041f46c6c5"
integrity sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==
"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5":
version "0.3.13"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f"
integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==
dependencies:
"@jridgewell/sourcemap-codec" "^1.5.0"
"@jridgewell/trace-mapping" "^0.3.24"
"@jridgewell/remapping@^2.3.5":
version "2.3.5"
resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1"
integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==
dependencies:
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.24"
"@jridgewell/resolve-uri@^3.1.0":
version "3.1.2"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz#f4c663e862f06dc98ca4d453862c46902789a18d"
integrity sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==
"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28":
version "0.3.31"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0"
integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==
dependencies:
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
"@mapbox/jsonlint-lines-primitives@^2.0.2", "@mapbox/jsonlint-lines-primitives@~2.0.2":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.3.tgz#7d7b0b971fbaf6d60953272db4df03020d3fb004"
integrity sha512-0SElaV0uMxEnxzBhhX9WTuPyUeMsAN/SS0i16tjuba4/mio63MG9khjC1a0JAiPGXAwvwm4UfHJURCN7nyudQg==
"@mapbox/point-geometry@^1.1.0", "@mapbox/point-geometry@~1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@mapbox/point-geometry/-/point-geometry-1.1.0.tgz#3328fb54b3a1273bc619bf0a6baad8de37181749"
integrity sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ==
"@mapbox/tiny-sdf@^2.1.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/@mapbox/tiny-sdf/-/tiny-sdf-2.2.0.tgz#95dae0dc371b8c55c53d70f3e25d56823427f4c8"
integrity sha512-LVL4wgI9YAum5V+LNVQO6QgFBPw7/MIIY4XJPNsPDMrjEwcE+JfKk1LuIl8GnF197ejVdC9QdPaxrx5gfgdGXg==
"@mapbox/unitbezier@^0.0.1":
version "0.0.1"
resolved "https://registry.yarnpkg.com/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz#d32deb66c7177e9e9dfc3bbd697083e2e657ff01"
integrity sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==
"@mapbox/unitbezier@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@mapbox/unitbezier/-/unitbezier-1.0.0.tgz#54319aff6c467bb1b909e04895c08cdb966bfbff"
integrity sha512-fqd515fjBmANKGGsQ286E2Wvj/XvDFpGzwJxq4CI6jMQue6Oy04uCKp+JWKF00xRTmk6cEu1jPJ9p3xqH8YWqQ==
"@mapbox/vector-tile@^2.0.4":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@mapbox/vector-tile/-/vector-tile-2.0.5.tgz#d00d894c9ad9350068a4e697e114c47d67072b54"
integrity sha512-pXj8m7KTsqZt+1jsE0xIpGvqTSbblfkuEJL/NJmNePMtEwxO8V3XMDo9WMSfDeqHvCtBI9Lmt4mGcGR10zecmw==
dependencies:
"@mapbox/point-geometry" "~1.1.0"
"@types/geojson" "^7946.0.16"
pbf "^4.0.2"
"@mapbox/whoots-js@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz#497c67a1cef50d1a2459ba60f315e448d2ad87fe"
integrity sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==
"@maplibre/geojson-vt@^6.1.0":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@maplibre/geojson-vt/-/geojson-vt-6.1.1.tgz#25a032435b4ce2236ea0ba911aff5fb6d5454fc1"
integrity sha512-FVMOcmSP/yqol45t7StApEyTL5/vmqBCuFhH9n+fFuINenhaX+YgHHIt1yJ86S8kln3uJLcMvmEU2cfn6E2eCQ==
dependencies:
kdbush "^4.1.0"
"@maplibre/maplibre-gl-style-spec@^24.8.1":
version "24.10.0"
resolved "https://registry.yarnpkg.com/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.10.0.tgz#ec1de19a468024749f0618d31bc9c7ff0641400e"
integrity sha512-lichxSiagMEBBrqHF0trtMQH9RKh+9jUlIJl0qW0QHvt2H/tbvUWdE+ZzI2Jd0/pT7j/iavLonlPu7EQ/ixTOw==
dependencies:
"@mapbox/jsonlint-lines-primitives" "~2.0.2"
"@mapbox/unitbezier" "^1.0.0"
json-stringify-pretty-compact "^4.0.0"
minimist "^1.2.8"
quickselect "^3.0.0"
tinyqueue "^3.0.0"
"@maplibre/mlt@^1.1.8":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@maplibre/mlt/-/mlt-1.3.0.tgz#3a9467d12a0b6edfcdba429dd3a260ca48f11129"
integrity sha512-7M2O7ABM80Oi8XPkfkrjKB8mOBIxGoVgkA52Mu4RMWoBvvMdagQ522+WxVYujZsMpqIr3BpzrTbXrm4k8lCzCQ==
dependencies:
"@mapbox/point-geometry" "^1.1.0"
"@maplibre/vt-pbf@^4.3.0":
version "4.3.2"
resolved "https://registry.yarnpkg.com/@maplibre/vt-pbf/-/vt-pbf-4.3.2.tgz#cfcdbdadaf88b4cb8645e43c8eead77cd6546030"
integrity sha512-j6p0AdjvAR19Z3XaCysle7A4ZSo08tYOzxD0Y9NQylwPAkwJJeYub5b2eVucdeDh7erhv69DahoLOevDRERRUw==
dependencies:
"@mapbox/point-geometry" "^1.1.0"
"@types/geojson" "^7946.0.16"
pbf "^5.1.0"
"@napi-rs/lzma-linux-x64-gnu@1.5.1":
version "1.5.1"
resolved "https://registry.yarnpkg.com/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz#e57d4306966078662038094fb38eb9146dc3aea9"
integrity sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==
"@rolldown/pluginutils@1.0.0-beta.27":
version "1.0.0-beta.27"
resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz#47d2bf4cef6d470b22f5831b420f8964e0bf755f"
integrity sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==
"@rollup/rollup-android-arm-eabi@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.63.4.tgz#e1d06062fb451578b3fb0bdea3360daaa1395f44"
integrity sha512-I+BSHzTAhKN2n7ZwGZsegGcZjDpLqFOMAtJz/u6uFGe0pUFbq56dEHjqJV/ZUdRJtNXNxA+hREUatZBvMR3Oiw==
"@rollup/rollup-android-arm64@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.63.4.tgz#2e81dec4e9e879c95c8266e30da67074c4998224"
integrity sha512-pu3BdjS2LtEzRu2elmGzS3fIeWSZy4BMDIaLNwjorO76+k2d0LMluijhsDx3KQyQBQ/lLUZCQA9/s6csvUfuhw==
"@rollup/rollup-darwin-arm64@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.63.4.tgz#f48f92f44454aed23d013f7cdb6da0dc2cb598ae"
integrity sha512-xfSrj9MHnWK9GaSqT9U0ImHtH/N8WZlHLx4cZHiuLcqs640hvZ3hLPd5UR2AZS57FaE8HrRUSpltbZdWRxHiDA==
"@rollup/rollup-darwin-x64@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.63.4.tgz#39b0b2ad27c49b40aec71fb20210e2e3be5fdbd0"
integrity sha512-bqU99PLJb/dqb3S0GIMdeuyAEETSUgZBoqXYd3Sd+WCsV+MmPhnN6JrotWyir31+QgH7EvvE5/mwGJlEoci8Fw==
"@rollup/rollup-freebsd-arm64@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.63.4.tgz#0c85d18f5b9228b7195adbbbc97c1adaf41b8106"
integrity sha512-JinsFZ5G40oXQb+sUuiA5x689vhr6dDYK0H0NL+rwKdL6CqnmYN8PE4ZwfRSoIjrCxqTQG/SLfTtSvHeGxoVlw==
"@rollup/rollup-freebsd-x64@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.63.4.tgz#0c6c27471ea950213aad76418f075c96f57e9533"
integrity sha512-GAdA4UxpiNm27cLHr2GqXBpAD0x9FqwYBY7/YSP0Ss0/PNi4k8gbviqpIpYbVSRBaS2ZcegXEzgTQMbRNCwxCw==
"@rollup/rollup-linux-arm-gnueabihf@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.63.4.tgz#28cba40d417fb3d2c1536941b02143a2bdda72be"
integrity sha512-qDd6NoA1znaLjp4jR5U/KWCdLAKDJNB8W9ChbbDaKbo0xA+Atln5HK6LFCZ4oJQpemtRZA288DCirFRjrspptw==
"@rollup/rollup-linux-arm-musleabihf@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.63.4.tgz#c9f06aa876d6d312012a2048d9e5533c581a7341"
integrity sha512-WtB5Tz5KTNINb8ZA+8sQ7bmjuS1JrRT7YverYIhUGdWWDlpzVWmIwuZE+jidkEXUn1l0zrEkaIMa8dHF3NGcsA==
"@rollup/rollup-linux-arm64-gnu@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.63.4.tgz#b26376804ca32b3dcc8f68930f765394fb4e4814"
integrity sha512-VcQ3L1tjnkKzWjryAVaFhHEWcqOfICX9uxVVoDzm2t0DpgKRHd2zOpVrJc0xsWeBZcBFyYROCIBdyR/fS174pg==
"@rollup/rollup-linux-arm64-musl@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.63.4.tgz#65f6f5deee9d30904b4d52ee3d45679055743cd1"
integrity sha512-6+ZQX6P5s0cMDN2Ypb8Lbm2+/sZYmZjdaYny992ujUU9UKi/4CWoJWsl1pNvjWJHNHGK51m+jKGLlh1ylb2ifQ==
"@rollup/rollup-linux-loong64-gnu@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.63.4.tgz#15d7e44538e967a3d6132f5b9f27f02346df6850"
integrity sha512-D72ZnvkFkBXOfzMMQLcwfPLyGkKb7HZ9/mf97B7v6/P5Lbv4oFOtSY/uHbS8lH6uKUOxoKiuokdb50XZSzzbJw==
"@rollup/rollup-linux-loong64-musl@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.63.4.tgz#7afad2b9e41941344883154f754b7f772ef16b01"
integrity sha512-piU6BxeqA3O9KSu3kRCIQQtNqFFaTu21SEV4FwaRZowpnj3bLaWPZHw+xFqCs0XlJ+aOH3PTRWGoglH+mKA/OA==
"@rollup/rollup-linux-ppc64-gnu@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.63.4.tgz#3f3131b1a9585851b2875c86a49f6e6deb9e68e0"
integrity sha512-/5PGpHwqt2EEEOUs1XwzubE/ucr0dWDQ+to3zqi4Ds7EWpwtQ79wXc4JBoxqj/OwpawTsKWzJxHfSuBOq3DrWA==
"@rollup/rollup-linux-ppc64-musl@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.63.4.tgz#463aeee26c62983c1fc235708d1b41baf4735f98"
integrity sha512-cX3beZDLWt7G2oJF+nhChiT+qtaihs+S2xi7ziGmVB+2pwPng6D0Ed0HmElQOgv2UsUmSJJLGwpBao/3TDx3VA==
"@rollup/rollup-linux-riscv64-gnu@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.63.4.tgz#cb495bd8cc978e17593e0d323b36fd95b5eab098"
integrity sha512-1uz2mGWHyptR7DgHHrlbdRAjXK7v7elGZ9lMja910/RP+ZYbX6xAmCiU9UZSX4hqmgtHMv6lr5l3kq1HIOpcag==
"@rollup/rollup-linux-riscv64-musl@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.63.4.tgz#655b69144b1e786e0bf8ac3b727f0d7fee590a08"
integrity sha512-nLS8topojxyz7SRpKR2IODRpQ0XPZ+xaOXvT3+hqK/Uy8Lo5HFgkkIBiIrCu5tL5YqzTvgovGw55PwpahTAGig==
"@rollup/rollup-linux-s390x-gnu@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.63.4.tgz#70b175b0361a7898acc294a6b14001e2c3ad99be"
integrity sha512-gs7DRKotr3l3q+jGPQBjH0ng1FjlEDm5ueQrkw5JtQvtLyEIcLASqAEaor56BhkKRzk+IcQzrcanBdb/bBQn8g==
"@rollup/rollup-linux-x64-gnu@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.63.4.tgz#0c68fa212df249f996b2d75e8fbb3766b1582ee8"
integrity sha512-791ET7W17NnScOZM7h4dX5hYspxE28htPFsb1awY/NRR8+PRNkS53e475rDdxXXDrP+kwnCcNWg9CX5ztn/Aqw==
"@rollup/rollup-linux-x64-musl@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.63.4.tgz#93af6206edf751469a43c3614164360136540838"
integrity sha512-iwZQRcmj7g88g3tzefIrQY7qvmuA/cfYwhrDtTBhsmukO4U2huVO5W+86XacUMRvdSFVAc6kZUZy21JaRwiB9w==
"@rollup/rollup-openbsd-x64@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.63.4.tgz#7c7680c4004fd602b59cd19f3294fa1b89d0c683"
integrity sha512-dVHFp9gRWrdTpnqQuGfCwd7hOQDatK1VCP2iWhLY/cGrOQs/ucFzJ6A5SRqbXX12ZDI8EUuejSM5kwg+ja7Png==
"@rollup/rollup-openharmony-arm64@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.63.4.tgz#f389ff4d8ee8a635ff51d76e8ff20b7db2292bce"
integrity sha512-t3NlauOW6gxZVVFcBEnO62Cb4wbyDFL416gTg1uFI/2tgqYQlf69FbSE115Ajre9I+c26Lk4mcmdFUsS/DGifQ==
"@rollup/rollup-win32-arm64-msvc@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.63.4.tgz#55a286f40f9d03c653ceb7183d6c6179ec312c75"
integrity sha512-xWuIaSye5FWZF8+UYtVEcHtRJDN5kN9Kfgxx3Kq8XIov9KSKbc1fiqQCm90SKrgQbUXZelbnUhnlUJmfSE7P9A==
"@rollup/rollup-win32-ia32-msvc@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.63.4.tgz#7eb577b64e2a39115182a87a2ea957608d8331f6"
integrity sha512-9ALJJUOg/ZflMJepVo2PlgsGxSaxN7SQ4Z8GoZfVlarWr6r3rkHUNsd/zAio7p4YMtChSMXPionxej4Hkf6CXQ==
"@rollup/rollup-win32-x64-gnu@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.63.4.tgz#0e7a7cd5f0db2f570fc312687d67baf21283a3f6"
integrity sha512-blj9z5qx/Pv4WU0W1NMFDB97e0JH5ed+aZGywW8WCvp/NhWX/4PFAq5uu6Q0AebNn+Vo6KzUYDT++JzTT5ojlQ==
"@rollup/rollup-win32-x64-msvc@4.63.4":
version "4.63.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.4.tgz#f8e11d8ac827db7695d50f1def4c00a7f3cd1510"
integrity sha512-Erx822VRBwLa124shbj+wNXe//BOgMEctDV0m1aqTQdNO1S69DgNUCFKC1RCeZfixs1J31l6igk1ziyXErbigQ==
"@types/babel__core@^7.20.5":
version "7.20.5"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017"
integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==
dependencies:
"@babel/parser" "^7.20.7"
"@babel/types" "^7.20.7"
"@types/babel__generator" "*"
"@types/babel__template" "*"
"@types/babel__traverse" "*"
"@types/babel__generator@*":
version "7.27.0"
resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9"
integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==
dependencies:
"@babel/types" "^7.0.0"
"@types/babel__template@*":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f"
integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==
dependencies:
"@babel/parser" "^7.1.0"
"@babel/types" "^7.0.0"
"@types/babel__traverse@*":
version "7.28.0"
resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz#07d713d6cce0d265c9849db0cbe62d3f61f36f74"
integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==
dependencies:
"@babel/types" "^7.28.2"
"@types/estree@1.0.9":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.9.tgz#cf3f0e876d7bee15a93ab925b82bf570a3904a24"
integrity sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==
"@types/geojson@^7946.0.16":
version "7946.0.16"
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.16.tgz#8ebe53d69efada7044454e3305c19017d97ced2a"
integrity sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==
"@types/prop-types@*":
version "15.7.15"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.15.tgz#e6e5a86d602beaca71ce5163fadf5f95d70931c7"
integrity sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==
"@types/react-dom@^18.3.5":
version "18.3.7"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.7.tgz#b89ddf2cd83b4feafcc4e2ea41afdfb95a0d194f"
integrity sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==
"@types/react@^18.3.18":
version "18.3.31"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.31.tgz#b5e95e28ffcceab8d982f33f2eb076e17653c2a4"
integrity sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==
dependencies:
"@types/prop-types" "*"
csstype "^3.2.2"
"@vitejs/plugin-react@^4.3.4":
version "4.7.0"
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz#647af4e7bb75ad3add578e762ad984b90f4a24b9"
integrity sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==
dependencies:
"@babel/core" "^7.28.0"
"@babel/plugin-transform-react-jsx-self" "^7.27.1"
"@babel/plugin-transform-react-jsx-source" "^7.27.1"
"@rolldown/pluginutils" "1.0.0-beta.27"
"@types/babel__core" "^7.20.5"
react-refresh "^0.17.0"
baseline-browser-mapping@^2.11.23:
version "2.11.25"
resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.11.25.tgz#88b942ce372bdf2d6a2652136bbf7826c65c77be"
integrity sha512-gMmEShwwq7FJqMwvfRwvCl00v4kN+KOfJqXn+f4nrufak5gNHJOksd/60Dvjuz7sI8Y5WiSFBa8FEYr+zoyqCw==
browserslist@^4.24.0:
version "4.29.0"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.29.0.tgz#e50e72c30c4b5f7ec894c09feb6ed525167f5344"
integrity sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==
dependencies:
baseline-browser-mapping "^2.11.23"
caniuse-lite "^1.0.30001810"
electron-to-chromium "^1.5.427"
node-releases "^2.0.55"
update-browserslist-db "^1.3.3"
caniuse-lite@^1.0.30001810:
version "1.0.30001810"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz#4970b477dea3278374de9bc43aa8f5d39fc3cda2"
integrity sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==
convert-source-map@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
csstype@^3.2.2:
version "3.2.3"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a"
integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==
debug@^4.1.0, debug@^4.3.1:
version "4.4.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a"
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
dependencies:
ms "^2.1.3"
earcut@^3.0.2:
version "3.2.3"
resolved "https://registry.yarnpkg.com/earcut/-/earcut-3.2.3.tgz#74aec19555a7e28773429826729d2e4bfeb19022"
integrity sha512-vnS4AVwp1KHAF13i1vp1/2D5evWy3k5u/iW/B81QVsUZtV8cv2tU0b2VNFlqvh4kYwrFMDdjPCfAmfyJW9y14Q==
electron-to-chromium@^1.5.427:
version "1.5.433"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.433.tgz#5c26b05c48030ff4a5566fcaa10dc452a1d1de3e"
integrity sha512-5lCAbyZBjtmUt/RAGHRqrL2q0oEFRThDAsZHHDn9XHa89Qw7gMYOeSicBTy+AHfvo0r6vwsZvqNJTQIQy1BLzA==
esbuild@^0.25.0:
version "0.25.12"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.12.tgz#97a1d041f4ab00c2fce2f838d2b9969a2d2a97a5"
integrity sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==
optionalDependencies:
"@esbuild/aix-ppc64" "0.25.12"
"@esbuild/android-arm" "0.25.12"
"@esbuild/android-arm64" "0.25.12"
"@esbuild/android-x64" "0.25.12"
"@esbuild/darwin-arm64" "0.25.12"
"@esbuild/darwin-x64" "0.25.12"
"@esbuild/freebsd-arm64" "0.25.12"
"@esbuild/freebsd-x64" "0.25.12"
"@esbuild/linux-arm" "0.25.12"
"@esbuild/linux-arm64" "0.25.12"
"@esbuild/linux-ia32" "0.25.12"
"@esbuild/linux-loong64" "0.25.12"
"@esbuild/linux-mips64el" "0.25.12"
"@esbuild/linux-ppc64" "0.25.12"
"@esbuild/linux-riscv64" "0.25.12"
"@esbuild/linux-s390x" "0.25.12"
"@esbuild/linux-x64" "0.25.12"
"@esbuild/netbsd-arm64" "0.25.12"
"@esbuild/netbsd-x64" "0.25.12"
"@esbuild/openbsd-arm64" "0.25.12"
"@esbuild/openbsd-x64" "0.25.12"
"@esbuild/openharmony-arm64" "0.25.12"
"@esbuild/sunos-x64" "0.25.12"
"@esbuild/win32-arm64" "0.25.12"
"@esbuild/win32-ia32" "0.25.12"
"@esbuild/win32-x64" "0.25.12"
escalade@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
fdir@^6.4.4, fdir@^6.5.0:
version "6.5.0"
resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350"
integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==
fsevents@~2.3.2, fsevents@~2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
gl-matrix@^3.4.4:
version "3.4.4"
resolved "https://registry.yarnpkg.com/gl-matrix/-/gl-matrix-3.4.4.tgz#7789ee4982f62c7a7af447ee488f3bd6b0c77003"
integrity sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
jsesc@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d"
integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==
json-stringify-pretty-compact@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz#cf4844770bddee3cb89a6170fe4b00eee5dbf1d4"
integrity sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==
json5@^2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
kdbush@^4.0.2, kdbush@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/kdbush/-/kdbush-4.1.0.tgz#d504bc0447a59be4fb75533a5c25e316b3ed8859"
integrity sha512-e9vurzrXJQrFX6ckpHP3bvj5l+9CnYzkxDNnNQ1h2QTqdWsUAJgXiKdGNcOa1EY85dU8KbQ+z/FdQdB7P+9yfQ==
loose-envify@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
lru-cache@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
dependencies:
yallist "^3.0.2"
maplibre-gl@^5.6.0:
version "5.24.0"
resolved "https://registry.yarnpkg.com/maplibre-gl/-/maplibre-gl-5.24.0.tgz#a8059371cdbeb04a62850ccc22cb37783928a10d"
integrity sha512-ALyFxgtd5R+65UqZ/++lOqwWcC0SNho9c27fYSyLmG7AfnAul2o46F05aDJGPbFU57wos9dgcIySHs0Xe6ia3A==
dependencies:
"@mapbox/jsonlint-lines-primitives" "^2.0.2"
"@mapbox/point-geometry" "^1.1.0"
"@mapbox/tiny-sdf" "^2.1.0"
"@mapbox/unitbezier" "^0.0.1"
"@mapbox/vector-tile" "^2.0.4"
"@mapbox/whoots-js" "^3.1.0"
"@maplibre/geojson-vt" "^6.1.0"
"@maplibre/maplibre-gl-style-spec" "^24.8.1"
"@maplibre/mlt" "^1.1.8"
"@maplibre/vt-pbf" "^4.3.0"
"@types/geojson" "^7946.0.16"
earcut "^3.0.2"
gl-matrix "^3.4.4"
kdbush "^4.0.2"
murmurhash-js "^1.0.0"
pbf "^4.0.1"
potpack "^2.1.0"
quickselect "^3.0.0"
tinyqueue "^3.0.0"
minimist@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
ms@^2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
murmurhash-js@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/murmurhash-js/-/murmurhash-js-1.0.0.tgz#b06278e21fc6c37fa5313732b0412bcb6ae15f51"
integrity sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==
nanoid@^3.3.18:
version "3.3.19"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.19.tgz#336d4aa4bcd4fb24d2cddede7ffeae40bec03f0a"
integrity sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==
node-releases@^2.0.55:
version "2.0.56"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.56.tgz#fff6a4093fe05d994a2a5e415eee5fcef874e6dc"
integrity sha512-x0InOIyzgdk+eyaWaRJFH5snEtiImgBgblZ2CyPrLmqqcuMQkEvcDPHbzqbD8eDsSeJbVOjn+crzyzHaM4D+/A==
pbf@^4.0.1, pbf@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/pbf/-/pbf-4.0.2.tgz#70f71a5c4df774438c1db482630146decb03e2d9"
integrity sha512-J0ajxARhZfpUEebxYs1vhMGMuLSXtBe1e+fFPDrf2uA2hgo+UshKfNUWOz92HJNz6/NFEXseQPddnHkTreWRqg==
dependencies:
resolve-protobuf-schema "^2.1.0"
pbf@^5.1.0:
version "5.1.2"
resolved "https://registry.yarnpkg.com/pbf/-/pbf-5.1.2.tgz#07c427819eda32f02f1ec9741558f61444f2e1c0"
integrity sha512-mnvGdvOrIvJOBGUEdGkrVXjN8E/VkIJCkf2eS1DH2yv82ORUlLttmDt0rWY38yYZmVwciZwBUvHM20qxBZf40w==
dependencies:
resolve-protobuf-schema "^2.1.0"
picocolors@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
picomatch@^4.0.2, picomatch@^4.0.4:
version "4.0.7"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.7.tgz#6313360034ccb36b3dc61ecbdff78121f90fe21f"
integrity sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==
postcss@^8.5.3:
version "8.5.28"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.28.tgz#da4563a99a06e62d6c1cd1acae363224bcaed6e9"
integrity sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==
dependencies:
nanoid "^3.3.18"
picocolors "^1.1.1"
source-map-js "^1.2.1"
potpack@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/potpack/-/potpack-2.1.0.tgz#fe548e2f9061e9937f17191c1ab6dd98ca30e02f"
integrity sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ==
protocol-buffers-schema@^3.3.1:
version "3.6.1"
resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.6.1.tgz#fd9a58a5c4e96385b964808f3ddd58f9ef18c3c8"
integrity sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==
quickselect@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-3.0.0.tgz#a37fc953867d56f095a20ac71c6d27063d2de603"
integrity sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==
react-dom@^18.3.1:
version "18.3.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
dependencies:
loose-envify "^1.1.0"
scheduler "^0.23.2"
react-refresh@^0.17.0:
version "0.17.0"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.17.0.tgz#b7e579c3657f23d04eccbe4ad2e58a8ed51e7e53"
integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==
react@^18.3.1:
version "18.3.1"
resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
dependencies:
loose-envify "^1.1.0"
resolve-protobuf-schema@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz#9ca9a9e69cf192bbdaf1006ec1973948aa4a3758"
integrity sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==
dependencies:
protocol-buffers-schema "^3.3.1"
rollup@^4.34.9:
version "4.63.4"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.63.4.tgz#cff29b8d6d959aee7cb5e44b0dad70074493dbf8"
integrity sha512-4U0liVayNIoLp3GFl1FcI8561WepLnZ1rqfraGh7S9B3Ur5F9S283y8Futii7RUU2C/97tOBmBy7nYvhoiOpbQ==
dependencies:
"@types/estree" "1.0.9"
optionalDependencies:
"@napi-rs/lzma-linux-x64-gnu" "1.5.1"
"@rollup/rollup-android-arm-eabi" "4.63.4"
"@rollup/rollup-android-arm64" "4.63.4"
"@rollup/rollup-darwin-arm64" "4.63.4"
"@rollup/rollup-darwin-x64" "4.63.4"
"@rollup/rollup-freebsd-arm64" "4.63.4"
"@rollup/rollup-freebsd-x64" "4.63.4"
"@rollup/rollup-linux-arm-gnueabihf" "4.63.4"
"@rollup/rollup-linux-arm-musleabihf" "4.63.4"
"@rollup/rollup-linux-arm64-gnu" "4.63.4"
"@rollup/rollup-linux-arm64-musl" "4.63.4"
"@rollup/rollup-linux-loong64-gnu" "4.63.4"
"@rollup/rollup-linux-loong64-musl" "4.63.4"
"@rollup/rollup-linux-ppc64-gnu" "4.63.4"
"@rollup/rollup-linux-ppc64-musl" "4.63.4"
"@rollup/rollup-linux-riscv64-gnu" "4.63.4"
"@rollup/rollup-linux-riscv64-musl" "4.63.4"
"@rollup/rollup-linux-s390x-gnu" "4.63.4"
"@rollup/rollup-linux-x64-gnu" "4.63.4"
"@rollup/rollup-linux-x64-musl" "4.63.4"
"@rollup/rollup-openbsd-x64" "4.63.4"
"@rollup/rollup-openharmony-arm64" "4.63.4"
"@rollup/rollup-win32-arm64-msvc" "4.63.4"
"@rollup/rollup-win32-ia32-msvc" "4.63.4"
"@rollup/rollup-win32-x64-gnu" "4.63.4"
"@rollup/rollup-win32-x64-msvc" "4.63.4"
fsevents "~2.3.2"
scheduler@^0.23.2:
version "0.23.2"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3"
integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==
dependencies:
loose-envify "^1.1.0"
semver@^6.3.1:
version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
source-map-js@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
tinyglobby@^0.2.13:
version "0.2.17"
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.17.tgz#562a9a6c9eb2b3b123d39719f9af5bb44fcd7631"
integrity sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==
dependencies:
fdir "^6.5.0"
picomatch "^4.0.4"
tinyqueue@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-3.0.0.tgz#101ea761ccc81f979e29200929e78f1556e3661e"
integrity sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==
typescript@^5.7.3:
version "5.9.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f"
integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==
update-browserslist-db@^1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz#197e21fb2561fa89f8b94fad605a2b296a18993a"
integrity sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==
dependencies:
escalade "^3.2.0"
picocolors "^1.1.1"
vite@^6.0.7:
version "6.4.3"
resolved "https://registry.yarnpkg.com/vite/-/vite-6.4.3.tgz#85a164db7ce706f2a776812efa2b340f1721858e"
integrity sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==
dependencies:
esbuild "^0.25.0"
fdir "^6.4.4"
picomatch "^4.0.2"
postcss "^8.5.3"
rollup "^4.34.9"
tinyglobby "^0.2.13"
optionalDependencies:
fsevents "~2.3.3"
yallist@^3.0.2:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
+18 -1
View File
@@ -124,9 +124,20 @@ const map = new maplibregl.Map({
<strong>3. URL</strong> <strong>3. URL</strong>
<p>MapLibre просит style JSON. Сервер сам подставит тайлы с тем же токеном.</p> <p>MapLibre просит style JSON. Сервер сам подставит тайлы с тем же токеном.</p>
</li> </li>
<li>
<strong>4. Несколько округов</strong>
<p>
В <code>source</code> перечислите id через запятую. Сервер добавит отдельный vector source на каждый extract и
скопирует слои. Один стиль несколько округов на одной карте.
</p>
</li>
</ol> </ol>
<CopyBlock label="Style JSON" value={styleUrl} /> <CopyBlock label="Style JSON" value={styleUrl} />
<CopyBlock
label="Несколько округов"
value={`${origin}/u/${slug}/styles/osm-bright?source=${sources.map((item) => item.id).join(",") || "central-fed-district,volga-fed-district"}${token ? `&token=${token}` : "&token=ts_…"}`}
/>
<CopyBlock label="Тайлы MVT" value={tilesUrl} /> <CopyBlock label="Тайлы MVT" value={tilesUrl} />
<h2 className="guides__h">HTML</h2> <h2 className="guides__h">HTML</h2>
@@ -141,7 +152,13 @@ const map = new maplibregl.Map({
<p>Живая карта с вашего аккаунта. Если токена нет сначала шаг 1.</p> <p>Живая карта с вашего аккаунта. Если токена нет сначала шаг 1.</p>
</div> </div>
{user && token ? ( {user && token ? (
<StylePreview slug={user.slug} name="osm-bright" source={source} token={token} nonce={0} /> <StylePreview
slug={user.slug}
name="osm-bright"
source={sources.map((item) => item.id).join(",") || source}
token={token}
nonce={0}
/>
) : ( ) : (
<div className="guide-result__empty">Нужен токен, чтобы нарисовать карту.</div> <div className="guide-result__empty">Нужен токен, чтобы нарисовать карту.</div>
)} )}
+28 -15
View File
@@ -1,28 +1,35 @@
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
import maplibregl, { type Map as MapLibreMap, type StyleSpecification } from "maplibre-gl"; import maplibregl, { type Map as MapLibreMap, type StyleSpecification } from "maplibre-gl";
import "maplibre-gl/dist/maplibre-gl.css"; import "maplibre-gl/dist/maplibre-gl.css";
import { bindStyleForPreview, type MapStyle, type StyleEdit } from "./styleModel"; import {
bindStyleForPreview,
primaryLayerId,
type ExtractBinding,
type MapStyle,
type StyleEdit
} from "./styleModel";
type Props = { type Props = {
style: MapStyle; style: MapStyle;
tilesUrl: string; bindings: ExtractBinding[];
selectedLayerId: string | null; selectedLayerId: string | null;
lastEdit: StyleEdit | null; lastEdit: StyleEdit | null;
styleEpoch: number; styleEpoch: number;
onSelectLayer: (layerId: string) => void; onSelectLayer: (layerId: string) => void;
}; };
export function LiveMap({ style, tilesUrl, selectedLayerId, lastEdit, styleEpoch, onSelectLayer }: Props) { export function LiveMap({ style, bindings, selectedLayerId, lastEdit, styleEpoch, onSelectLayer }: Props) {
const el = useRef<HTMLDivElement | null>(null); const el = useRef<HTMLDivElement | null>(null);
const mapRef = useRef<MapLibreMap | null>(null); const mapRef = useRef<MapLibreMap | null>(null);
const extras = bindings.slice(1).map((item) => item.extractId);
useEffect(() => { useEffect(() => {
if (!el.current || !tilesUrl) { if (!el.current || bindings.length === 0) {
return; return;
} }
const map = new maplibregl.Map({ const map = new maplibregl.Map({
container: el.current, container: el.current,
style: bindStyleForPreview(style, tilesUrl) as StyleSpecification, style: bindStyleForPreview(style, bindings) as StyleSpecification,
center: [37.6173, 55.7558], center: [37.6173, 55.7558],
zoom: 11, zoom: 11,
maxZoom: 18, maxZoom: 18,
@@ -33,7 +40,7 @@ export function LiveMap({ style, tilesUrl, selectedLayerId, lastEdit, styleEpoch
map.on("click", (event) => { map.on("click", (event) => {
const hit = map.queryRenderedFeatures(event.point)[0]; const hit = map.queryRenderedFeatures(event.point)[0];
if (hit?.layer?.id) { if (hit?.layer?.id) {
onSelectLayer(hit.layer.id); onSelectLayer(primaryLayerId(hit.layer.id, extras));
} }
}); });
mapRef.current = map; mapRef.current = map;
@@ -41,25 +48,31 @@ export function LiveMap({ style, tilesUrl, selectedLayerId, lastEdit, styleEpoch
map.remove(); map.remove();
mapRef.current = null; mapRef.current = null;
}; };
// Recreate only when tiles source changes. // Recreate when extract set changes.
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [tilesUrl, styleEpoch]); }, [bindings.map((item) => item.extractId).join(","), styleEpoch]);
useEffect(() => { useEffect(() => {
const map = mapRef.current; const map = mapRef.current;
if (!map || !lastEdit || !map.isStyleLoaded() || !map.getLayer(lastEdit.layerId)) { if (!map || !lastEdit || !map.isStyleLoaded()) {
return; return;
} }
const ids = [lastEdit.layerId, ...extras.map((id) => `${lastEdit.layerId}__${id}`)];
try { try {
if (lastEdit.target === "paint") { for (const layerId of ids) {
map.setPaintProperty(lastEdit.layerId, lastEdit.property, lastEdit.value); if (!map.getLayer(layerId)) {
} else { continue;
map.setLayoutProperty(lastEdit.layerId, lastEdit.property, lastEdit.value); }
if (lastEdit.target === "paint") {
map.setPaintProperty(layerId, lastEdit.property, lastEdit.value);
} else {
map.setLayoutProperty(layerId, lastEdit.property, lastEdit.value);
}
} }
} catch { } catch {
map.setStyle(bindStyleForPreview(style, tilesUrl) as StyleSpecification, { diff: true }); map.setStyle(bindStyleForPreview(style, bindings) as StyleSpecification, { diff: true });
} }
}, [lastEdit, style, tilesUrl]); }, [lastEdit, style, bindings, extras]);
return ( return (
<div <div
+37 -24
View File
@@ -10,6 +10,7 @@ import {
isMapStyle, isMapStyle,
tilesTemplate, tilesTemplate,
updateLayer, updateLayer,
type ExtractBinding,
type MapStyle, type MapStyle,
type StyleEdit, type StyleEdit,
type StyleLayer type StyleLayer
@@ -22,7 +23,7 @@ export function StyleEditorPage() {
const { user } = useAuth(); const { user } = useAuth();
const [style, setStyle] = useState<MapStyle | null>(null); const [style, setStyle] = useState<MapStyle | null>(null);
const [sources, setSources] = useState<SourceItem[]>([]); const [sources, setSources] = useState<SourceItem[]>([]);
const [source, setSource] = useState(""); const [selectedSourceIds, setSelectedSourceIds] = useState<string[]>([]);
const [selectedId, setSelectedId] = useState<string | null>(null); const [selectedId, setSelectedId] = useState<string | null>(null);
const [lastEdit, setLastEdit] = useState<StyleEdit | null>(null); const [lastEdit, setLastEdit] = useState<StyleEdit | null>(null);
const [styleEpoch, setStyleEpoch] = useState(0); const [styleEpoch, setStyleEpoch] = useState(0);
@@ -44,7 +45,7 @@ export function StyleEditorPage() {
setIsPreset(list.find((item) => item.name === name)?.isPreset ?? true); setIsPreset(list.find((item) => item.name === name)?.isPreset ?? true);
const enabled = sourceList.filter((item) => item.enabled); const enabled = sourceList.filter((item) => item.enabled);
setSources(enabled); setSources(enabled);
setSource((current) => current || enabled[0]?.id || ""); setSelectedSourceIds((current) => (current.length > 0 ? current : enabled[0] ? [enabled[0].id] : []));
const first = raw.layers?.[raw.layers.length - 1]?.id ?? null; const first = raw.layers?.[raw.layers.length - 1]?.id ?? null;
setSelectedId(first); setSelectedId(first);
setStyleEpoch((n) => n + 1); setStyleEpoch((n) => n + 1);
@@ -54,12 +55,15 @@ export function StyleEditorPage() {
const layers = style?.layers ?? []; const layers = style?.layers ?? [];
const selected: StyleLayer | null = layers.find((layer) => layer.id === selectedId) ?? null; const selected: StyleLayer | null = layers.find((layer) => layer.id === selectedId) ?? null;
const tilesUrl = useMemo(() => { const bindings: ExtractBinding[] = useMemo(() => {
if (!user || !source || !token) { if (!user || !token || selectedSourceIds.length === 0) {
return ""; return [];
} }
return tilesTemplate(user.slug, source, token); return selectedSourceIds.map((id) => ({
}, [user, source, token]); extractId: id,
tilesUrl: tilesTemplate(user.slug, id, token)
}));
}, [user, token, selectedSourceIds]);
const apply = (edit: StyleEdit) => { const apply = (edit: StyleEdit) => {
if (!style || isPreset) { if (!style || isPreset) {
@@ -86,22 +90,31 @@ export function StyleEditorPage() {
</span> </span>
</div> </div>
<div className="style-workspace__actions"> <div className="style-workspace__actions">
<label className="style-workspace__source"> <fieldset className="style-workspace__sources">
<span>Источник</span> <legend>Округа</legend>
<select {sources.map((item) => {
value={source} const checked = selectedSourceIds.includes(item.id);
onChange={(e) => { return (
setSource(e.target.value); <label key={item.id}>
setStyleEpoch((n) => n + 1); <input
}} type="checkbox"
> checked={checked}
{sources.map((item) => ( onChange={() => {
<option key={item.id} value={item.id}> setSelectedSourceIds((current) => {
if (checked) {
const next = current.filter((id) => id !== item.id);
return next.length > 0 ? next : current;
}
return [...current, item.id];
});
setStyleEpoch((n) => n + 1);
}}
/>
{item.name} {item.name}
</option> </label>
))} );
</select> })}
</label> </fieldset>
{!isPreset ? ( {!isPreset ? (
<> <>
<Button <Button
@@ -165,10 +178,10 @@ export function StyleEditorPage() {
onLayout={(property, value) => selected && apply({ layerId: selected.id, target: "layout", property, value })} onLayout={(property, value) => selected && apply({ layerId: selected.id, target: "layout", property, value })}
/> />
<section className="style-workspace__map"> <section className="style-workspace__map">
{style && tilesUrl ? ( {style && bindings.length > 0 ? (
<LiveMap <LiveMap
style={style} style={style}
tilesUrl={tilesUrl} bindings={bindings}
selectedLayerId={selectedId} selectedLayerId={selectedId}
lastEdit={lastEdit} lastEdit={lastEdit}
styleEpoch={styleEpoch} styleEpoch={styleEpoch}
+25
View File
@@ -67,6 +67,31 @@
color: var(--secondary-label); color: var(--secondary-label);
} }
.style-workspace__sources {
margin: 0;
padding: 0;
border: 0;
display: flex;
flex-wrap: wrap;
gap: 6px 12px;
max-width: 28rem;
font-size: var(--text-caption1);
color: var(--secondary-label);
}
.style-workspace__sources legend {
padding: 0;
margin-bottom: 4px;
}
.style-workspace__sources label {
display: flex;
align-items: center;
gap: 6px;
color: var(--label);
font-size: var(--text-footnote);
}
.style-workspace__source select { .style-workspace__source select {
min-height: 34px; min-height: 34px;
min-width: 14rem; min-width: 14rem;
+61 -5
View File
@@ -35,9 +35,35 @@ export function tilesTemplate(slug: string, source: string, token: string): stri
return `/u/${encodeURIComponent(slug)}/tiles/${encodeURIComponent(source)}/{z}/{x}/{y}.pbf?v=3&token=${encodeURIComponent(token)}`; return `/u/${encodeURIComponent(slug)}/tiles/${encodeURIComponent(source)}/{z}/{x}/{y}.pbf?v=3&token=${encodeURIComponent(token)}`;
} }
export function bindStyleForPreview(style: MapStyle, tilesUrl: string): MapStyle { export type ExtractBinding = {
extractId: string;
tilesUrl: string;
};
function applyVectorSource(source: Record<string, unknown>, tilesUrl: string): void {
source.type = "vector";
source.tiles = [tilesUrl];
source.scheme = "xyz";
delete source.url;
delete source.bounds;
}
function vectorKeys(style: MapStyle): string[] {
const sources = style.sources ?? {};
return Object.keys(sources).filter((key) => {
const source = sources[key];
return Boolean(source && typeof source === "object" && (source as { type?: string }).type === "vector");
});
}
export function bindStyleForPreview(style: MapStyle, bindings: ExtractBinding[]): MapStyle {
if (bindings.length === 0) {
return structuredClone(style);
}
const next = structuredClone(style); const next = structuredClone(style);
const sources = { ...(next.sources ?? {}) }; const sources = { ...(next.sources ?? {}) };
const first = bindings[0];
for (const key of Object.keys(sources)) { for (const key of Object.keys(sources)) {
const source = sources[key]; const source = sources[key];
if (!source || typeof source !== "object") { if (!source || typeof source !== "object") {
@@ -47,19 +73,49 @@ export function bindStyleForPreview(style: MapStyle, tilesUrl: string): MapStyle
if (vector.type !== "vector") { if (vector.type !== "vector") {
continue; continue;
} }
vector.tiles = [tilesUrl]; applyVectorSource(vector, first.tilesUrl);
vector.scheme = "xyz";
delete vector.url;
delete vector.bounds;
sources[key] = vector; sources[key] = vector;
} }
next.sources = sources; next.sources = sources;
if (!next.glyphs) { if (!next.glyphs) {
next.glyphs = "https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf"; next.glyphs = "https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf";
} }
const primary = vectorKeys(next);
const layers = [...(next.layers ?? [])];
for (const extra of bindings.slice(1)) {
const suffix = `__${extra.extractId}`;
for (const key of primary) {
const clone: Record<string, unknown> = { type: "vector" };
applyVectorSource(clone, extra.tilesUrl);
sources[key + suffix] = clone;
}
for (const layer of next.layers ?? []) {
if (!layer.source || !primary.includes(layer.source)) {
continue;
}
layers.push({
...structuredClone(layer),
id: `${layer.id}${suffix}`,
source: `${layer.source}${suffix}`
});
}
}
next.sources = sources;
next.layers = layers;
return next; return next;
} }
export function primaryLayerId(layerId: string, extraExtractIds: string[]): string {
for (const extractId of extraExtractIds) {
const suffix = `__${extractId}`;
if (layerId.endsWith(suffix)) {
return layerId.slice(0, -suffix.length);
}
}
return layerId;
}
export function updateLayer(style: MapStyle, edit: StyleEdit): MapStyle { export function updateLayer(style: MapStyle, edit: StyleEdit): MapStyle {
const next = structuredClone(style); const next = structuredClone(style);
const layer = next.layers?.find((item) => item.id === edit.layerId); const layer = next.layers?.find((item) => item.id === edit.layerId);