Files
arah2/web/index.html
T

101 lines
5.7 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>arah²</title>
<script src="https://telegram.org/js/telegram-web-app.js"></script>
</head>
<body>
<div id="app"></div>
<script type="module">
/* D-11 Mock-Telegram profile: ?mock=android|ios|tdesktop|macos|web + ?scheme=light|dark + ?pin=1 + ?locale=en|ms + ?fixdelay + ?sessiondelay + ?dest=<id> + ?fixpair=<pair-id> + ?drive=<fixture-name> (06-08: the drive replay is read inside the mock module — installMockWebApp replaces navigator.geolocation with the committed fixture's stream)
Harness-only: served from web/dist-harness, never deployed.
The WHOLE block below is inside `if (__ARAHARAH_HARNESS__)` — Vite's `define`
replaces that identifier with `false` in the production build, so the branch is
dead-code-eliminated and web/dist/index.html carries neither installMockWebApp
nor the fetch stubs (BA5 scans ALL of web/dist HTML as well as its JS assets).
No storage writes may appear here — the harness profile lives in a
module-scope global (window.__ARAHARAH_MOCK__), never in browser storage (D-07). */
if (__ARAHARAH_HARNESS__) {
const q = new URLSearchParams(location.search);
const profile = q.get("mock") || "android";
const scheme = q.get("scheme") === "dark" ? "dark" : "light";
const locale = q.get("locale") === "ms" ? "ms" : "en";
/* The ONBD-02 destination profile (?dest=<id>, 04-04): the value needs
* NO stub on the reader path — page.goto preserves the query string, so
* window.location.search already carries it and the app's real
* readDestinationId parses it. It is threaded to the mock as startParam
* so the SECONDARY carrier (the signed initData's start_param field) is
* exercisable from the harness too. */
const dest = q.get("dest") || null;
/* Boot-stage photography knobs (harness-only): at localhost speeds the
whole session→chain→fix sequence resolves in a few ms, so the staged
BOOT-01 (validating) and BOOT-02 (acquiring) cards cannot hold on
screen. ?sessiondelay=<ms> holds the validating card; ?fixdelay=<ms>
holds the acquiring card (a delayed LocationManager delivery).
Production and the plain dev fallback never pass either. */
const sessionDelayMs = Number.parseInt(q.get("sessiondelay") || "0", 10);
const fixDelayMs = Number.parseInt(q.get("fixdelay") || "0", 10);
/* The 05-05 route profile (?fixpair=<pair-id>): the mock's Telegram fix
* becomes the PAIR'S PINNED PUBLIC ORIGIN, resolved from the committed
* fixture corpus through the harness-only route-profiles module (D-12 —
* the harness introduces no user coordinate; a ?lat/?lng knob is
* deliberately absent). An unknown pairId keeps the default fix — the
* boot must never wedge. The dynamic import lives inside this
* __ARAHARAH_HARNESS__ branch, so production dead-code-eliminates the
* module (BA5 greps web/dist for its sentinel). */
const fixpair = q.get("fixpair");
let telegramFix = { lat: 3.1513, lng: 101.6958, accuracyM: 12, headingDeg: null };
if (fixpair) {
const { getRouteProfileOrigin } = await import("/src/mock/route-profiles.ts");
const origin = getRouteProfileOrigin(fixpair);
if (origin) telegramFix = { lat: origin.lat, lng: origin.lng, accuracyM: 12, headingDeg: null };
}
// Set BEFORE main.ts is imported — this is the marker main.ts's install guard checks.
window.__ARAHARAH_MOCK__ = { profile, scheme, locale, dest };
// Stub the endpoints the app calls, OUTSIDE any dead-code-eliminated branch. These
// live in the runner page (not in main.ts) precisely so no import.meta.env guard can
// strip them: the harness bundle must reach LIVE without a Worker in the loop.
const realFetch = window.fetch.bind(window);
const fakeToken = "00000000-0000-4000-8000-000000000001";
window.fetch = async (input, init) => {
const url = typeof input === "string" ? input : (input && input.url) || "";
if (url.includes("/api/session") && (!init || init.method === "POST")) {
// The session gate is HMAC-validated server-side; offline the harness
// short-circuits it with a fake token the stubbed /api/location also accepts.
if (sessionDelayMs > 0) await new Promise((r) => setTimeout(r, sessionDelayMs));
return new Response(JSON.stringify({ token: fakeToken }), { status: 200, headers: { "content-type": "application/json" } });
}
if (url.includes("/api/location") && (!init || init.method === "GET")) {
const body = q.get("pin") === "1"
? { pin: { latitude: 3.1513, longitude: 101.6958, horizontal_accuracy: 8 } }
: { pin: null };
return new Response(JSON.stringify(body), { status: 200, headers: { "content-type": "application/json" } });
}
if (url.includes("/api/location-fallback")) {
return new Response(JSON.stringify({ ok: true }), { status: 200, headers: { "content-type": "application/json" } });
}
return realFetch(input, init);
};
const { installMockWebApp } = await import("/src/mock/telegram-mock.ts");
installMockWebApp({
platform: profile,
colorScheme: scheme,
languageCode: locale,
grantLocation: profile !== "tdesktop",
deliveryDelayMs: fixDelayMs > 0 ? fixDelayMs : undefined,
telegramFix,
startParam: dest ?? undefined,
});
}
await import("/src/main.ts");
</script>
</body>
</html>