feat(outlines): restore voice outlines without public Overpass

use bundled place boundaries and shared OpenFreeMap tiles before a guarded Nominatim fallback

preserve multipart shapes, holes and cancellation,
and keep pending annotations visible while ground sampling finishes across frames

keep non-Latin name distinctions when selecting provider results,
and retain an outline anchor only when it lies in filled geometry
This commit is contained in:
manjunath committed 2026-10-27 13:24:02 +00:00
commit d4434aa6d7
1489 files changed
+196442 -12353

No files matched your search

+216 -119
View File
@@ -207,60 +207,61 @@ test('polygon-selected tiles keep nearest-first order and cached revisits issue
);
});
test('compatible consumers share bounded decoded ownership without sharing local lifetimes', async () => {
const sharedDecodedCache = createSharedDecodedTileCache({
maxEntries: 2,
maxCacheBytes: 100,
test('a configured tileJsonUrl sets the tile origin, and a foreign tiles[0] is still refused', async () => {
// Without an explicit allowedOrigin the mirror's own TileJSON is honoured…
const mirrored = createVectorTileSource({
tileJsonUrl: 'http://127.0.0.1:12348/planet',
decode: () => [],
fetchImpl: async () =>
Response.json({ tiles: ['http://127.0.0.1:12348/p/{z}/{x}/{y}.pbf'] }),
});
let decodes = 0,
requests = 0;
const common = {
...options,
template: meta.tiles[0],
sharedDecodedCache,
decode: () => {
decodes++;
return { roads: ['road'], outlines: ['outline'] };
},
fetchImpl: async () => {
requests++;
return new Response(new Uint8Array([1, 2, 3]));
},
};
const roads = createVectorTileSource({
...common,
selectDecoded: (value) => value.roads,
assert.equal(
(await mirrored.getMetadata()).template,
'http://127.0.0.1:12348/p/{z}/{x}/{y}.pbf',
);
// …while a TileJSON that names a different host is refused rather than
// silently fetched, which is what the origin check is for.
const foreign = createVectorTileSource({
tileJsonUrl: 'http://127.0.0.1:12348/planet',
decode: () => [],
fetchImpl: async () =>
Response.json({
tiles: ['https://tiles.example/planet/{z}/{x}/{y}.pbf'],
}),
});
const outlines = createVectorTileSource({
...common,
selectDecoded: (value) => value.outlines,
await assert.rejects(foreign.getMetadata(), { retryable: false });
});
test('an explicit allowedOrigin still wins over the one derived from tileJsonUrl', async () => {
const source = createVectorTileSource({
tileJsonUrl: 'http://127.0.0.1:12348/planet',
allowedOrigin: 'https://tiles.example',
decode: () => [],
fetchImpl: async () =>
Response.json({
tiles: ['https://tiles.example/planet/{z}/{x}/{y}.pbf'],
}),
});
const tiles = [{ z: 14, x: 3743, y: 6745 }];
assert.deepEqual((await roads.fetchBounds(box, { zoom: 14, tiles })).tiles, [
['road'],
]);
roads.clear();
assert.deepEqual(
(await outlines.fetchBounds(box, { zoom: 14, tiles })).tiles,
[['outline']],
assert.equal(
(await source.getMetadata()).template,
'https://tiles.example/planet/{z}/{x}/{y}.pbf',
);
assert.equal(requests, 1);
assert.equal(decodes, 1);
assert.deepEqual(sharedDecodedCache.stats(), { entries: 1, bytes: 12 });
});
test('shared decoded tiles are isolated from consumer mutation', async () => {
const sharedDecodedCache = createSharedDecodedTileCache();
let decodes = 0,
requests = 0;
let decodes = 0;
let requests = 0;
const decode = () => {
decodes++;
return { roads: [{ name: 'Congress Avenue', coordinates: [[-97, 30]] }] };
};
const common = {
...options,
template: meta.tiles[0],
sharedDecodedCache,
decode: () => {
decodes++;
return { roads: [{ name: 'Congress Avenue', coordinates: [[-97, 30]] }] };
},
decode,
selectDecoded: (value) => value.roads,
fetchImpl: async () => {
requests++;
@@ -269,95 +270,39 @@ test('shared decoded tiles are isolated from consumer mutation', async () => {
};
const first = createVectorTileSource(common);
const second = createVectorTileSource(common);
const third = createVectorTileSource(common);
const tiles = [{ z: 14, x: 3743, y: 6745 }];
const firstResult = await first.fetchBounds(box, { zoom: 14, tiles });
firstResult.tiles[0][0].name = 'first mutation';
firstResult.tiles[0][0].name = 'mutated';
firstResult.tiles[0][0].coordinates[0][0] = 0;
const secondResult = await second.fetchBounds(box, { zoom: 14, tiles });
assert.equal(secondResult.tiles[0][0].name, 'Congress Avenue');
assert.equal(secondResult.tiles[0][0].coordinates[0][0], -97);
secondResult.tiles[0][0].name = 'second mutation';
secondResult.tiles[0][0].coordinates[0][0] = 1;
const thirdResult = await third.fetchBounds(box, { zoom: 14, tiles });
assert.equal(thirdResult.tiles[0][0].name, 'Congress Avenue');
assert.equal(thirdResult.tiles[0][0].coordinates[0][0], -97);
assert.equal(requests, 1);
assert.equal(decodes, 1);
});
test('one source isolates in-flight and completed cache results from consumer mutation', async () => {
const sharedDecodedCache = createSharedDecodedTileCache();
let decodes = 0,
requests = 0,
releaseResponse;
const responseReady = new Promise((resolve) => {
releaseResponse = resolve;
});
let requestStarted;
const started = new Promise((resolve) => {
requestStarted = resolve;
});
const source = createVectorTileSource({
...options,
template: meta.tiles[0],
sharedDecodedCache,
decode: () => {
decodes++;
return { roads: [{ name: 'Congress Avenue', coordinates: [[-97, 30]] }] };
},
selectDecoded: (value) => value.roads,
fetchImpl: async () => {
requests++;
requestStarted();
await responseReady;
return new Response(new Uint8Array([1, 2, 3]));
},
});
const tiles = [{ z: 14, x: 3743, y: 6745 }];
const firstPending = source.fetchBounds(box, { zoom: 14, tiles });
await started;
const concurrentPending = source.fetchBounds(box, { zoom: 14, tiles });
releaseResponse();
const firstResult = await firstPending;
const concurrentResult = await concurrentPending;
firstResult.tiles[0][0].name = 'first mutation';
firstResult.tiles[0][0].coordinates[0][0] = 0;
assert.equal(concurrentResult.tiles[0][0].name, 'Congress Avenue');
assert.equal(concurrentResult.tiles[0][0].coordinates[0][0], -97);
concurrentResult.tiles[0][0].name = 'concurrent mutation';
concurrentResult.tiles[0][0].coordinates[0][0] = 1;
const cachedResult = await source.fetchBounds(box, { zoom: 14, tiles });
assert.equal(cachedResult.tiles[0][0].name, 'Congress Avenue');
assert.equal(cachedResult.tiles[0][0].coordinates[0][0], -97);
assert.equal(requests, 1);
assert.equal(decodes, 1);
});
test('compatible consumers share one in-flight fetch and survive one consumer clearing', async () => {
const sharedDecodedCache = createSharedDecodedTileCache();
let requests = 0,
decodes = 0,
releaseResponse;
let requests = 0;
let decodes = 0;
let releaseResponse;
let requestStarted;
const responseReady = new Promise((resolve) => {
releaseResponse = resolve;
});
let requestStarted;
const started = new Promise((resolve) => {
requestStarted = resolve;
});
const decode = () => {
decodes++;
return { roads: ['road'], outlines: ['outline'] };
};
const common = {
...options,
template: meta.tiles[0],
sharedDecodedCache,
decode: () => {
decodes++;
return { roads: ['road'], outlines: ['outline'] };
},
decode,
fetchImpl: async () => {
requests++;
requestStarted();
@@ -387,10 +332,114 @@ test('compatible consumers share one in-flight fetch and survive one consumer cl
assert.equal(decodes, 1);
});
test('queued shared hits preserve sibling ownership and cannot refill after clear', async (t) => {
const sharedDecodedCache = createSharedDecodedTileCache();
let requests = 0,
decodes = 0,
selections = 0;
const geometry = [
{
name: 'Congress Avenue',
coordinates: [
[-97, 30],
[-97, 31],
],
},
];
const common = {
...options,
template: meta.tiles[0],
sharedDecodedCache,
decode: () => {
decodes++;
return { roads: geometry };
},
selectDecoded: (value) => {
selections++;
return value.roads;
},
fetchImpl: async () => {
requests++;
return new Response(new Uint8Array([1, 2, 3]));
},
};
const tiles = [{ z: 14, x: 3743, y: 6745 }];
await createVectorTileSource(common).fetchBounds(box, { zoom: 14, tiles });
selections = 0;
const scheduler = Object.getOwnPropertyDescriptor(globalThis, 'scheduler');
let queued = Promise.withResolvers();
let resume;
Object.defineProperty(globalThis, 'scheduler', {
configurable: true,
value: {
yield: () =>
new Promise((resolve) => {
resume = resolve;
queued.resolve();
}),
},
});
t.after(() => {
resume?.();
if (scheduler) Object.defineProperty(globalThis, 'scheduler', scheduler);
else delete globalThis.scheduler;
});
const source = createVectorTileSource(common);
const controller = new AbortController();
const cancelled = source.fetchBounds(box, {
zoom: 14,
tiles,
signal: controller.signal,
});
const rejected = assert.rejects(cancelled, { name: 'AbortError' });
const sibling = source.fetchBounds(box, { zoom: 14, tiles });
await queued.promise;
controller.abort();
await rejected;
resume();
assert.deepEqual((await sibling).tiles, [geometry]);
assert.equal(selections, 1);
assert.deepEqual(source.getStats(), {
tilesFetched: 0,
cacheEntries: 1,
cacheBytes: 12,
});
selections = 0;
queued = Promise.withResolvers();
const cleared = createVectorTileSource(common);
let published = 0;
const pending = cleared.fetchBounds(box, {
zoom: 14,
tiles,
onTile: () => published++,
});
const clearRejected = assert.rejects(pending, { name: 'AbortError' });
await queued.promise;
cleared.clear();
resume();
await clearRejected;
assert.equal(selections, 0);
assert.equal(published, 0);
assert.deepEqual(cleared.getStats(), {
tilesFetched: 0,
cacheEntries: 0,
cacheBytes: 0,
});
queued = Promise.withResolvers();
const fresh = cleared.fetchBounds(box, { zoom: 14, tiles });
await queued.promise;
resume();
assert.deepEqual((await fresh).tiles, [geometry]);
assert.equal(requests, 1);
assert.equal(decodes, 1);
});
test('shared ownership recharges materialized projections and evicts over budget', () => {
const shared = createSharedDecodedTileCache({ maxCacheBytes: 100 });
let resize,
releases = 0;
let resize;
let releases = 0;
const decoded = {
bindSharedCacheEntry(update) {
resize = update;
@@ -405,26 +454,30 @@ test('shared ownership recharges materialized projections and evicts over budget
assert.deepEqual(shared.stats(), { entries: 1, bytes: 80 });
resize(101);
assert.deepEqual(shared.stats(), { entries: 0, bytes: 0 });
assert.equal(entry.size, 101, 'the returned entry retains its real size');
assert.equal(releases, 1, 'self-eviction releases decoded ownership once');
assert.equal(entry.size, 101);
assert.equal(releases, 1);
shared.clear();
assert.equal(releases, 1, 'clearing after eviction does not release twice');
assert.equal(releases, 1);
});
test('shared clear releases entries and prevents a pending loader from refilling', async () => {
const shared = createSharedDecodedTileCache();
let releases = 0;
const decoded = {
releaseSharedCacheEntry() {
releases++;
shared.set(
'resident',
{
releaseSharedCacheEntry() {
releases++;
},
},
};
shared.set('resident', decoded, 12);
12,
);
shared.clear();
assert.deepEqual(shared.stats(), { entries: 0, bytes: 0 });
assert.equal(releases, 1);
let loaderStarted, resolveLoader;
let loaderStarted;
let resolveLoader;
const started = new Promise((resolve) => {
loaderStarted = resolve;
});
@@ -441,3 +494,47 @@ test('shared clear releases entries and prevents a pending loader from refilling
await assert.rejects(pending, { name: 'AbortError' });
assert.deepEqual(shared.stats(), { entries: 0, bytes: 0 });
});
test('shared decoded ownership is isolated by decoder identity', async () => {
const sharedDecodedCache = createSharedDecodedTileCache();
let requests = 0;
const common = {
...options,
template: meta.tiles[0],
sharedDecodedCache,
fetchImpl: async () => {
requests++;
return new Response(new Uint8Array([1]));
},
};
const a = createVectorTileSource({ ...common, decode: () => ['a'] });
const b = createVectorTileSource({ ...common, decode: () => ['b'] });
const tiles = [{ z: 14, x: 3743, y: 6745 }];
assert.deepEqual((await a.fetchBounds(box, { zoom: 14, tiles })).tiles, [
['a'],
]);
assert.deepEqual((await b.fetchBounds(box, { zoom: 14, tiles })).tiles, [
['b'],
]);
assert.equal(requests, 2);
});
test('clear prevents an old generation from starting tile I/O', async () => {
let requests = 0;
const source = createVectorTileSource({
...options,
template: meta.tiles[0],
fetchImpl: async () => {
requests++;
return new Response(new Uint8Array([1]));
},
});
await source.getMetadata();
const pending = source.fetchBounds(box, {
zoom: 14,
tiles: [{ z: 14, x: 3743, y: 6745 }],
});
source.clear();
await assert.rejects(pending, { name: 'AbortError' });
assert.equal(requests, 0);
});