forked from c-fu/arah2
feat(03-02): Fix type + three source adapters (telegram/webview/chat-pin) — GEO-01 wrappers
- types.ts: the shared Fix shape + LocationState machine (type-only, D-04/D-05/D-07) - telegram.ts: version-gated LocationManager init/getLocation, hard 8s timeout (Pitfall 3), null-safe telegramLocationSupported (plain browser/Desktop = false, not TypeError), looksStale + haversine + the Android nudge (issue #56 navbar read DISCARDED, then retry) - webview.ts: one-shot geolocation read, maximumAge: 0 (freshness axis), 8s timeout - chat-pin.ts: bounded 60s poll of GET /api/location (Bearer token) + POST /api/location-fallback throw-on-fail so the ASK VIA CHAT handler can revalidate (D-03) - telegram/webapp.ts created early (Rule 3: task 1 imports TelegramWebAppLike from task 3's file; declared the narrow hand-rolled interface now, verbatim per plan)
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* webview.ts — source 2: navigator.geolocation inside the WebView, and the
|
||||
* Android freshness nudge's reading hand (D-04, D-05).
|
||||
* -------------------------------------------------------------------
|
||||
* maximumAge: 0 is load-bearing — D-05 requires the freshest fix, and a
|
||||
* cached position would silently defeat the freshness axis (the whole
|
||||
* point of the nudge is to force a NEW read, not to re-read a cache).
|
||||
* Success AND timeout both resolve; the error callback resolves null so
|
||||
* the chain advances instead of rejecting. Timeout present for the same
|
||||
* reason as the telegram wrapper: wedging ACQUIRING is never acceptable.
|
||||
*/
|
||||
import type { Fix } from "./types.ts";
|
||||
|
||||
export function webviewLocationSupported(): boolean {
|
||||
return typeof navigator !== "undefined" && typeof navigator.geolocation?.getCurrentPosition === "function";
|
||||
}
|
||||
|
||||
export function readWebviewFix(options: { timeoutMs?: number; nowMs?: () => number } = {}): Promise<Fix | null> {
|
||||
const timeoutMs = options.timeoutMs ?? 8000;
|
||||
if (!webviewLocationSupported()) return Promise.resolve(null); // Desktop Telegram, plain browsers without permission
|
||||
return new Promise((resolve) => {
|
||||
let settled = false;
|
||||
const done = (fix: Fix | null): void => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
clearTimeout(timer);
|
||||
resolve(fix);
|
||||
};
|
||||
const timer = setTimeout(() => done(null), timeoutMs);
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(pos) =>
|
||||
done({
|
||||
lat: pos.coords.latitude,
|
||||
lng: pos.coords.longitude,
|
||||
accuracyM: pos.coords.accuracy ?? null,
|
||||
headingDeg: pos.coords.heading ?? null,
|
||||
ts: (options.nowMs ?? Date.now)(),
|
||||
source: "webview",
|
||||
}),
|
||||
() => done(null), // denial / unavailability = null; the chain's normal signal (no error object escapes)
|
||||
{ enableHighAccuracy: true, timeout: timeoutMs, maximumAge: 0 },
|
||||
);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user