mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
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:
commit
d4434aa6d7
1489 files changed
+196442
-12353
No files matched your search
+216
-119
@@ -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);
|
||||
});
|
||||
Reference in new issue
Block a user