Files
gods-eye-view/src/layers/transit/source.js
T
Sameh Khamis 2ba751ace8 feat: read the transit feed catalog through the transit source
Add getFeeds() to the transit source. It reads the public catalog route
the server already serves, so code outside the layer can find feeds
near a location without loading the layer.
2026-10-01 12:19:19 -07:00

52 lines
1.7 KiB
JavaScript

import { fetchTransitHistory } from '../../sources/transitHistory.js';
/** Request transit snapshots through caller-owned transport. */
export function createTransitSource({
fetchImpl = (...args) => fetch(...args),
} = {}) {
return {
/** Read the public catalog of enabled feeds. */
async getFeeds({ signal } = {}) {
signal?.throwIfAborted();
const response = await fetchImpl('/api/transit/feeds', {
signal,
headers: { Accept: 'application/json' },
});
if (!response.ok)
throw new Error('Transit feeds HTTP ' + response.status);
const body = await response.json();
signal?.throwIfAborted();
if (!Array.isArray(body?.feeds))
throw new Error('Malformed transit feed catalog');
return body.feeds;
},
getHistory(feedId, vehicleId, { signal } = {}) {
signal?.throwIfAborted();
return fetchTransitHistory(feedId, vehicleId, signal, fetchImpl);
},
requestSnapshot(feedId, { signal } = {}) {
signal?.throwIfAborted();
if (typeof feedId !== 'string' || !feedId || feedId.length > 160)
throw new TypeError('A transit feed identifier is required');
return Promise.resolve(
fetchImpl(`/api/transit/vehicles/${encodeURIComponent(feedId)}`, {
signal,
headers: { Accept: 'application/json' },
}),
).then((response) => {
signal?.throwIfAborted();
return {
ok: response.ok,
status: response.status,
headers: response.headers,
async json() {
const body = await response.json();
signal?.throwIfAborted();
return body;
},
};
});
},
};
}