fix(maps): prevent server crash when legacy Google photo URLs are stored as placeIds

Migration 107 only rewrote image_url rows matching /places/%/photos/%; URLs using
the /place-photos/ or /places/<opaque> paths survived the upgrade and were passed
verbatim to the Places API, producing a malformed request whose empty/HTML response
body threw SyntaxError before detailsRes.ok was checked. The resulting rejection was
leaked by placePhotoCache.setInFlight via an unhandled .finally() chain, triggering
Node 22's default unhandledRejection=throw and terminating the process.

- placePhotoCache: add .catch() after .finally() to prevent unhandled rejection crash
- mapsService: reject URL-shaped placeIds early; read response as text before JSON.parse
- migrations: add migration to rewrite remaining googleusercontent/places.googleapis URLs
- MapView/MapViewGL: prefer stable proxy URL form of image_url before google_place_id

Fixes #770
This commit is contained in:
jubnl
2026-04-21 00:13:35 +02:00
parent 16b81a8356
commit 2aad8f465c
5 changed files with 45 additions and 6 deletions
+21
View File
@@ -1906,6 +1906,27 @@ function runMigrations(db: Database.Database): void {
CREATE INDEX IF NOT EXISTS idx_day_accommodations_end_day_id ON day_accommodations(end_day_id);
`);
},
// Migration: backfill remaining legacy Google photo URLs missed by Migration 107.
// Migration 107 matched /places/%/photos/% only; lh3.googleusercontent.com URLs use
// /place-photos/ or /places/<opaque-id> paths and were skipped. Rewrite any remaining
// google-hosted URL to the stable proxy form using the row's google_place_id.
() => {
db.exec(`
UPDATE places
SET image_url = '/api/maps/place-photo/' || google_place_id || '/bytes',
updated_at = CURRENT_TIMESTAMP
WHERE google_place_id IS NOT NULL
AND image_url IS NOT NULL
AND image_url != ''
AND image_url NOT LIKE '/api/maps/place-photo/%'
AND (
image_url LIKE 'http://%googleusercontent.com/%'
OR image_url LIKE 'https://%googleusercontent.com/%'
OR image_url LIKE 'http://%places.googleapis.com/%'
OR image_url LIKE 'https://%places.googleapis.com/%'
)
`);
},
];
if (currentVersion < migrations.length) {