aeharding / aeharding/wingover

map: keep MapKit usable offline (tiles are already cached; reauth is the lock)

Abierto
#165 1 comentario 0 reacciones 0 asignados Ver en GitHub
offline
Lenguaje dominante
TypeScript
Estrellas
0
Forks
0
Merge medio
4 h 2 min
PR fusionados (30 d)
6

Descripción

Follow-on to #164. #164 guarantees the track always draws. This issue is about keeping the **basemap** too, so an in-flight restart out of coverage still shows the ground you were just flying over.

## The key finding: the tiles are already on the device

MapKit serves tiles with `cache-control: public, max-age=604800` (7 days), and WebKit's cache persists across launches. So a flight flown with service has already downloaded the tiles for that exact area. Nothing is missing offline. MapKit simply refuses to start, so the data is locked, not absent.

**Proven:** capture every MapKit response online, then load the app in a fresh browser with a hard network block, serving only the captured bytes. MapKit initialises completely and paints a full Apple basemap (terrain, labels, coastlines, attribution) with zero network. 75/75 replayed, no console errors.

Note `no-store` on the bootstrap does not prevent this. It binds the browser's HTTP cache, not storage we control.

## What actually blocks an offline relaunch

Only two responses. Everything else is already cached and long-lived.

| endpoint | cache-control | offline? |
|---|---|---|
| `/mk/6.0.x/libs/mapkit.core.*.js` | `max-age=31322996` (~362d) | cached, fine |
| `/md/v1/vtile`, `/ttile`, `/icon` | `max-age=604800` (7d), `s-maxage=2` | cached, fine |
| `/mk/6/mapkit.core.js` (version pointer) | `max-age=23..275` | **expires, blocks** |
| `/ma/bootstrap` (auth) | `max-age=0, no-cache, no-store` | **never cached, blocks** |

So a shim serving just those two from local storage could let WebKit's own cache supply the rest.

## Open question: does reauth cap it?

`/ma/bootstrap` returns an `accessKey` with `expiresInSeconds: 1800`, and the key embeds an issue timestamp. Forcing `expiresInSeconds: 0` in a replay produced an initialised map that painted **no tiles** (empty grid) - but that test *tells* MapKit the key is dead, which a verbatim replay does not. A stored bootstrap still says `1800`, so MapKit may compute the deadline from receipt and never learn otherwise, with no server present to disagree.

An experiment is running: capture untouched, wait out the full 30 minutes, replay verbatim. Result decides scope:

- **Tiles paint:** no practical ceiling; the shim is worth building.
- **Empty grid:** reauth caps continuity at ~30 min from last bootstrap, and only owned tiles give multi-hour coverage.

## Mechanism (PWA and native are different problems)

- **PWA** (`https://wingover.app`): service workers work. `src/sw.ts` (workbox) already exists. Note no `registerSW` call was found in `src/` or `index.html`, so the worker may not be registering at all today - worth checking separately.
- **Native** (`tauri://localhost`): a custom scheme, where WebKit does **not** run service workers. The PWA worker does nothing for the app. `NSURLProtocol` does not see WKWebView traffic and `setURLSchemeHandler` only handles custom schemes, so neither helps. The candidate is `WKWebsiteDataStore.proxyConfigurations` (public API, iOS 17+), routing webview traffic through a proxy we run. Untested.

## Before building

Apple's MapKit JS terms need a real read. Their own `max-age=604800` sanctions a browser cache; a custom store that replays their responses is a different question, and this ships on the App Store.

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.