aeharding / aeharding/wingover

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

オープン
#165 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る
offline
主要言語
TypeScript
スター
0
フォーク
0
平均マージ
4時間 2分
マージ済み PR(30日)
6

説明

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.

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。