Merge upstream/main into pr/google-street-view

Conflicts with upstream's Street Level provider composition and share-state
codec, resolved:

- Street View's switch moves from its own share option (`g`) to upstream's
  provider-switch field (`r`, e.g. `0.r.google-1`); a link without it keeps
  Street View off. Docs and the browser gate follow.
- createApplicationStreetLevel keeps upstream's injectable provider list;
  its default, once the application supplies its Street Level source, is
  Mapillary plus Google Street View. Without that source there are none, as
  upstream intends.
- The coverage hint keeps upstream's empty-composition message and joins
  every switched-on provider's hint otherwise.
- CHANGELOG, README and SECURITY keep both sides' entries.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Said TurkseverandClaude Opus 5.5 committed 2026-10-12 11:32:05 +01:00
commit 76db4114ff
80 files changed
+3845 -201

No files matched your search

+80 -5
View File
@@ -1,3 +1,4 @@
import { encodeParams, decodeParams } from '../layers/streetLevel/params.js';
import { readShellSource } from '../testSupport/readShellSource.mjs';
import { expandApplicationHtml } from '../../build/application-html.js';
import { readLayerSource } from '../testSupport/readLayerSource.mjs';
@@ -2670,14 +2671,14 @@ test('Street Level: every option round-trips through a share link and stored sta
state.enabledLayerIds = ['street-level'];
state.options['street-level'] = {
mapillary: false,
google: true,
providerSwitches: '',
pano: 'flat',
sinceDays: MAX_SINCE_DAYS,
};
const decoded = decodeLayerStateParams(new URLSearchParams(encode(state)));
assert.deepEqual(decoded.options['street-level'], {
mapillary: false,
google: true,
providerSwitches: '',
pano: 'flat',
sinceDays: MAX_SINCE_DAYS,
});
@@ -2705,12 +2706,16 @@ test('Street Level: the link codec accepts exactly the windows the filter keeps'
test('Street Level: a link without the provider switches keeps Mapillary on and Street View off', () => {
assert.deepEqual(streetLevelOptions(''), {
mapillary: true,
google: false,
providerSwitches: '',
pano: 'all',
sinceDays: 0,
});
assert.equal(streetLevelOptions('0.g.1').google, true);
assert.equal(createDefaultLayerState().options['street-level'].google, false);
// Street View rides the shared provider-switch field, off unless lit.
assert.equal(streetLevelOptions('0.r.google-1').providerSwitches, 'google-1');
assert.equal(
createDefaultLayerState().options['street-level'].providerSwitches,
'',
);
assert.equal(streetLevelOptions('0.p.f').mapillary, true);
assert.equal(streetLevelOptions('0.m.0').mapillary, false);
assert.equal(
@@ -2718,3 +2723,73 @@ test('Street Level: a link without the provider switches keeps Mapillary on and
true,
);
});
test('explicit provider switches reach durable state without adopting unrelated live switches', () => {
const manager = new DataLayerManager({});
const providers = new Map([
['mapillary', true],
['alpha', true],
['beta', true],
]);
const filter = { pano: 'all', sinceDays: 0 };
for (const id of REGISTERED_LAYER_IDS) {
manager.register(
id === 'street-level'
? {
...fakeLayer(id),
getParams: () => encodeParams({ providers, filter }),
setParams(params) {
const decoded = decodeParams(params, {
providerIds: providers.keys(),
filter,
});
for (const [id, on] of decoded.providers) providers.set(id, on);
return true;
},
}
: fakeLayer(id),
);
}
manager.finalizeRegistrations(LAYER_STATE_REGISTRY);
const storage = memoryStorage();
const coordinator = new LayerStateCoordinator(manager, shareSink(), {
storage,
});
try {
providers.set('beta', false); // Passive state does not belong to the next action.
assert.equal(
manager.setLayerParams(
'street-level',
{ alpha: false },
{ origin: 'user' },
),
true,
);
let saved = parseStoredLayerState(storage.getItem(LAYER_STATE_STORAGE_KEY));
assert.equal(saved.options['street-level'].providerSwitches, 'alpha-0');
const shared = decodeLayerStateParams(new URLSearchParams(encode(saved)));
const restored = decodeParams(shared.options['street-level'], {
providerIds: ['beta', 'alpha'],
filter,
});
assert.deepEqual([...restored.providers], [['alpha', false]]);
manager.setLayerParams('street-level', { beta: true }, { origin: 'user' });
saved = parseStoredLayerState(storage.getItem(LAYER_STATE_STORAGE_KEY));
assert.equal(
saved.options['street-level'].providerSwitches,
'alpha-0*beta-1',
);
manager.setLayerParams(
'street-level',
{ alpha: true },
{ origin: 'local-restore' },
);
saved = parseStoredLayerState(storage.getItem(LAYER_STATE_STORAGE_KEY));
assert.equal(
saved.options['street-level'].providerSwitches,
'alpha-0*beta-1',
);
} finally {
coordinator.destroy();
}
});