mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
refactor: add configurable Nominatim adapter and portable source helpers
This commit is contained in:
1 parent
2b1092bf89
commit
66eb6d6a7c
14 files changed
+646
-152
No files matched your search
@@ -1,57 +1,7 @@
|
||||
/**
|
||||
* Read a fetch() Response body as text with a hard byte cap. Rejects early on an
|
||||
* oversized Content-Length, then streams with a running cap so a chunked or
|
||||
* length-omitted response cannot blow past the limit. Throws { code:'RESPONSE_TOO_LARGE' }.
|
||||
*/
|
||||
export async function readResponseTextCapped(response, maxBytes, signal) {
|
||||
const tooLarge = () =>
|
||||
Object.assign(new Error('Upstream response too large'), {
|
||||
code: 'RESPONSE_TOO_LARGE',
|
||||
});
|
||||
const declared = Number(response.headers.get('content-length'));
|
||||
if (Number.isFinite(declared) && declared > maxBytes) {
|
||||
void response.body?.cancel().catch(() => {});
|
||||
throw tooLarge();
|
||||
}
|
||||
signal?.throwIfAborted();
|
||||
const reader = response.body?.getReader?.();
|
||||
if (!reader) {
|
||||
const text = await response.text();
|
||||
signal?.throwIfAborted();
|
||||
if (Buffer.byteLength(text) > maxBytes) throw tooLarge();
|
||||
return text;
|
||||
}
|
||||
const cancel = () => {
|
||||
void reader.cancel().catch(() => {});
|
||||
};
|
||||
signal?.addEventListener('abort', cancel, { once: true });
|
||||
const decoder = new TextDecoder();
|
||||
let out = '';
|
||||
let total = 0;
|
||||
try {
|
||||
for (;;) {
|
||||
signal?.throwIfAborted();
|
||||
const { done, value } = await reader.read();
|
||||
signal?.throwIfAborted();
|
||||
if (done) break;
|
||||
total += value.byteLength;
|
||||
if (total > maxBytes) throw tooLarge();
|
||||
out += decoder.decode(value, { stream: true });
|
||||
}
|
||||
return out + decoder.decode();
|
||||
} catch (error) {
|
||||
cancel();
|
||||
throw error;
|
||||
} finally {
|
||||
signal?.removeEventListener('abort', cancel);
|
||||
reader.releaseLock();
|
||||
}
|
||||
}
|
||||
|
||||
/** Parse a fetch() JSON response only after enforcing a hard byte cap. */
|
||||
export async function readResponseJsonCapped(response, maxBytes, signal) {
|
||||
return JSON.parse(await readResponseTextCapped(response, maxBytes, signal));
|
||||
}
|
||||
export {
|
||||
readResponseTextCapped,
|
||||
readResponseJsonCapped,
|
||||
} from '../../../src/sources/httpBody.js';
|
||||
|
||||
/**
|
||||
* Return the existing promise for a cache key, or create one and remove it
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { stripOverpassNoise } from '../../../src/sources/overpass.js';
|
||||
import {
|
||||
OVERPASS_MAX_AROUND_M,
|
||||
OVERPASS_MAX_BBOX_DEG,
|
||||
@@ -31,54 +32,6 @@ function isOverpassBoundaryQuery(cacheKey) {
|
||||
*
|
||||
* @returns {{ok:true, body:string} | {ok:false, error:string}}
|
||||
*/
|
||||
/**
|
||||
* Single-pass lexer: blank out quoted literals (→ empty quotes) and strip line
|
||||
* and block comments — recognizing each in one walk so a comment marker INSIDE a
|
||||
* quoted string is treated as string content, not a comment (and vice versa).
|
||||
* Chained regex replaces get the ordering wrong (a quoted slash-slash would hide
|
||||
* the rest of the line), which is exactly the bypass this avoids.
|
||||
*/
|
||||
function stripOverpassNoise(src) {
|
||||
let out = '';
|
||||
let i = 0;
|
||||
const n = src.length;
|
||||
while (i < n) {
|
||||
const c = src[i];
|
||||
if (c === '"' || c === "'") {
|
||||
const quote = c;
|
||||
i += 1;
|
||||
while (i < n) {
|
||||
if (src[i] === '\\') {
|
||||
i += 2;
|
||||
continue;
|
||||
} // escaped char
|
||||
if (src[i] === quote) {
|
||||
i += 1;
|
||||
break;
|
||||
} // closing quote
|
||||
i += 1;
|
||||
}
|
||||
out += quote + quote; // collapse the literal to empty quotes
|
||||
continue;
|
||||
}
|
||||
if (c === '/' && src[i + 1] === '*') {
|
||||
i += 2;
|
||||
while (i < n && !(src[i] === '*' && src[i + 1] === '/')) i += 1;
|
||||
i += 2;
|
||||
out += ' ';
|
||||
continue;
|
||||
}
|
||||
if (c === '/' && src[i + 1] === '/') {
|
||||
i += 2;
|
||||
while (i < n && src[i] !== '\n') i += 1;
|
||||
out += ' ';
|
||||
continue;
|
||||
}
|
||||
out += c;
|
||||
i += 1;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function sanitizeOverpassBody(rawBody) {
|
||||
let params;
|
||||
|
||||
Reference in new issue
Block a user