feat: add WebView XHR interceptor for mock train position injection

- Scrape & analyse all 19 internal APIs of train.jr-shikoku.co.jp/sp.html
  using puppeteer + Chromium remote debugging
- Save live-captured sample JSON for every API endpoint under
  lib/mockApi/mockData/ (station lists, lang, timetable, train positions, etc.)
- Add lib/mockApi/webviewXhrInterceptor.ts – generates a JS snippet that
  overrides XMLHttpRequest inside the WebView before page scripts run;
  intercepts /g?arg1=train&arg2=train (and optionally all static APIs)
  returning mock data instead of the real server response
- Add lib/mockApi/index.ts – convenience re-exports + MOCK_TRAIN_POSITIONS
  constant pre-populated with captured sample data
- Extend InjectJavascriptOptions with optional mockApiConfig field
- injectJavascriptData() prepends the interceptor JS when mockApiConfig is set
- TrainMenuContext gains mockApiEnabled / setMockApiEnabled and
  mockTrainPositions / setMockTrainPositions state; consumers can enable
  mock mode and inject custom TrainEntry[] without reloading the app

Co-authored-by: Copilot <[email protected]>
This commit is contained in:
harukin-expo-dev-env
2026-04-30 15:30:06 +00:00
co-authored by Copilot
parent 4d3176186f
commit eed51d31fa
23 changed files with 7620 additions and 0 deletions
+14
View File
@@ -2,6 +2,7 @@ import { INTERVALS, API_ENDPOINTS } from '@/constants';
import { TRAIN_TYPE_CONFIG } from './webview/trainTypeConfig';
import { TRAIN_ICON_MAP, TRAIN_ICON_REGEX } from './webview/trainIconMap';
import { STATION_DATA } from './webview/stationData';
import { generateXhrInterceptorJs, MockApiConfig } from './mockApi/webviewXhrInterceptor';
export interface InjectJavascriptOptions {
/** 地図スイッチ ("true" | "false") */
@@ -20,6 +21,12 @@ export interface InjectJavascriptOptions {
useElesite: string;
/** ダークモードかどうか */
isDark: boolean;
/**
* モックAPIの設定。指定した場合、WebView内の公式サイトAPIをインターセプトして
* モックデータを返すXHRインターセプターが注入されます。
* 未指定または null の場合、インターセプターは無効で通常通り公式APIに接続します。
*/
mockApiConfig?: MockApiConfig | null;
}
export const injectJavascriptData = ({
@@ -31,7 +38,13 @@ export const injectJavascriptData = ({
useUnyohub,
useElesite,
isDark,
mockApiConfig = null,
}: InjectJavascriptOptions): string => {
// XHRインターセプターを先頭に注入(モックモード有効時)
const xhrInterceptor = mockApiConfig
? generateXhrInterceptorJs(mockApiConfig)
: '';
// 一番上のメニュー非表示 地図スイッチによって切り替え
const topMenu =
mapSwitch != "true"
@@ -1392,6 +1405,7 @@ setStationMenuDialog.observe(document.querySelector('#disp'), {
`
: ``;
return (
xhrInterceptor +
bootData +
topMenu +
trainIcon +