googlemaps-kit 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -3
- package/dist/advanced/parsers.d.ts +1 -1
- package/dist/advanced/parsers.d.ts.map +1 -1
- package/dist/advanced/parsers.js +1 -1
- package/dist/advanced/parsers.js.map +1 -1
- package/dist/advanced.d.ts +2 -2
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js.map +1 -1
- package/dist/books.d.ts +30 -0
- package/dist/books.d.ts.map +1 -0
- package/dist/books.js +77 -0
- package/dist/books.js.map +1 -0
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +9 -11
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/tui/app.d.ts.map +1 -1
- package/dist/cli/tui/app.js +7 -7
- package/dist/cli/tui/app.js.map +1 -1
- package/dist/cli.js +14 -11
- package/dist/cli.js.map +1 -1
- package/dist/client/gmaps-client.d.ts +7 -29
- package/dist/client/gmaps-client.d.ts.map +1 -1
- package/dist/client/gmaps-client.js +15 -131
- package/dist/client/gmaps-client.js.map +1 -1
- package/dist/client/http-client.d.ts +3 -1
- package/dist/client/http-client.d.ts.map +1 -1
- package/dist/client/http-client.js +14 -3
- package/dist/client/http-client.js.map +1 -1
- package/dist/client/intent.d.ts +1 -11
- package/dist/client/intent.d.ts.map +1 -1
- package/dist/client/intent.js +17 -13
- package/dist/client/intent.js.map +1 -1
- package/dist/client/maps-tools.d.ts +8 -4
- package/dist/client/maps-tools.d.ts.map +1 -1
- package/dist/client/maps-tools.js +20 -11
- package/dist/client/maps-tools.js.map +1 -1
- package/dist/client/namespaces.d.ts +51 -19
- package/dist/client/namespaces.d.ts.map +1 -1
- package/dist/client/namespaces.js +82 -28
- package/dist/client/namespaces.js.map +1 -1
- package/dist/client/place-workflows.d.ts +7 -0
- package/dist/client/place-workflows.d.ts.map +1 -0
- package/dist/client/place-workflows.js +113 -0
- package/dist/client/place-workflows.js.map +1 -0
- package/dist/finance/client.d.ts +19 -0
- package/dist/finance/client.d.ts.map +1 -0
- package/dist/finance/client.js +75 -0
- package/dist/finance/client.js.map +1 -0
- package/dist/finance/parsers.d.ts +13 -0
- package/dist/finance/parsers.d.ts.map +1 -0
- package/dist/finance/parsers.js +146 -0
- package/dist/finance/parsers.js.map +1 -0
- package/dist/finance/types.d.ts +76 -0
- package/dist/finance/types.d.ts.map +1 -0
- package/dist/finance/types.js +2 -0
- package/dist/finance/types.js.map +1 -0
- package/dist/finance.d.ts +5 -0
- package/dist/finance.d.ts.map +1 -0
- package/dist/finance.js +4 -0
- package/dist/finance.js.map +1 -0
- package/dist/flights/client.d.ts +9 -0
- package/dist/flights/client.d.ts.map +1 -0
- package/dist/flights/client.js +14 -0
- package/dist/flights/client.js.map +1 -0
- package/dist/flights/parsers.d.ts +11 -0
- package/dist/flights/parsers.d.ts.map +1 -0
- package/dist/flights/parsers.js +64 -0
- package/dist/flights/parsers.js.map +1 -0
- package/dist/flights/types.d.ts +52 -0
- package/dist/flights/types.d.ts.map +1 -0
- package/dist/flights/types.js +2 -0
- package/dist/flights/types.js.map +1 -0
- package/dist/flights.d.ts +5 -0
- package/dist/flights.d.ts.map +1 -0
- package/dist/flights.js +4 -0
- package/dist/flights.js.map +1 -0
- package/dist/gemini-web/client.d.ts +16 -0
- package/dist/gemini-web/client.d.ts.map +1 -0
- package/dist/gemini-web/client.js +110 -0
- package/dist/gemini-web/client.js.map +1 -0
- package/dist/gemini-web/parsers.d.ts +5 -0
- package/dist/gemini-web/parsers.d.ts.map +1 -0
- package/dist/gemini-web/parsers.js +62 -0
- package/dist/gemini-web/parsers.js.map +1 -0
- package/dist/gemini-web/types.d.ts +47 -0
- package/dist/gemini-web/types.d.ts.map +1 -0
- package/dist/gemini-web/types.js +2 -0
- package/dist/gemini-web/types.js.map +1 -0
- package/dist/gemini-web.d.ts +5 -0
- package/dist/gemini-web.d.ts.map +1 -0
- package/dist/gemini-web.js +4 -0
- package/dist/gemini-web.js.map +1 -0
- package/dist/google-search/client.d.ts +16 -0
- package/dist/google-search/client.d.ts.map +1 -0
- package/dist/google-search/client.js +117 -0
- package/dist/google-search/client.js.map +1 -0
- package/dist/google-search/errors.d.ts +8 -0
- package/dist/google-search/errors.d.ts.map +1 -0
- package/dist/google-search/errors.js +13 -0
- package/dist/google-search/errors.js.map +1 -0
- package/dist/google-search/html.d.ts +12 -0
- package/dist/google-search/html.d.ts.map +1 -0
- package/dist/google-search/html.js +135 -0
- package/dist/google-search/html.js.map +1 -0
- package/dist/google-search/parsers.d.ts +6 -0
- package/dist/google-search/parsers.d.ts.map +1 -0
- package/dist/google-search/parsers.js +177 -0
- package/dist/google-search/parsers.js.map +1 -0
- package/dist/google-search/types.d.ts +66 -0
- package/dist/google-search/types.d.ts.map +1 -0
- package/dist/google-search/types.js +2 -0
- package/dist/google-search/types.js.map +1 -0
- package/dist/google-search.d.ts +6 -0
- package/dist/google-search.d.ts.map +1 -0
- package/dist/google-search.js +4 -0
- package/dist/google-search.js.map +1 -0
- package/dist/hotels/client.d.ts +9 -0
- package/dist/hotels/client.d.ts.map +1 -0
- package/dist/hotels/client.js +14 -0
- package/dist/hotels/client.js.map +1 -0
- package/dist/hotels/parsers.d.ts +7 -0
- package/dist/hotels/parsers.d.ts.map +1 -0
- package/dist/hotels/parsers.js +74 -0
- package/dist/hotels/parsers.js.map +1 -0
- package/dist/hotels/types.d.ts +55 -0
- package/dist/hotels/types.d.ts.map +1 -0
- package/dist/hotels/types.js +2 -0
- package/dist/hotels/types.js.map +1 -0
- package/dist/hotels.d.ts +4 -0
- package/dist/hotels.d.ts.map +1 -0
- package/dist/hotels.js +3 -0
- package/dist/hotels.js.map +1 -0
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/known-surfaces.d.ts +35 -5
- package/dist/known-surfaces.d.ts.map +1 -1
- package/dist/known-surfaces.js +35 -5
- package/dist/known-surfaces.js.map +1 -1
- package/dist/lens/client.d.ts +14 -0
- package/dist/lens/client.d.ts.map +1 -0
- package/dist/lens/client.js +116 -0
- package/dist/lens/client.js.map +1 -0
- package/dist/lens/errors.d.ts +8 -0
- package/dist/lens/errors.d.ts.map +1 -0
- package/dist/lens/errors.js +13 -0
- package/dist/lens/errors.js.map +1 -0
- package/dist/lens/types.d.ts +27 -0
- package/dist/lens/types.d.ts.map +1 -0
- package/dist/lens/types.js +2 -0
- package/dist/lens/types.js.map +1 -0
- package/dist/lens.d.ts +8 -0
- package/dist/lens.d.ts.map +1 -0
- package/dist/lens.js +5 -0
- package/dist/lens.js.map +1 -0
- package/dist/news.d.ts +46 -0
- package/dist/news.d.ts.map +1 -0
- package/dist/news.js +202 -0
- package/dist/news.js.map +1 -0
- package/dist/pagespeed/client.d.ts +28 -0
- package/dist/pagespeed/client.d.ts.map +1 -0
- package/dist/pagespeed/client.js +222 -0
- package/dist/pagespeed/client.js.map +1 -0
- package/dist/pagespeed/errors.d.ts +9 -0
- package/dist/pagespeed/errors.d.ts.map +1 -0
- package/dist/pagespeed/errors.js +15 -0
- package/dist/pagespeed/errors.js.map +1 -0
- package/dist/pagespeed/parsers.d.ts +7 -0
- package/dist/pagespeed/parsers.d.ts.map +1 -0
- package/dist/pagespeed/parsers.js +236 -0
- package/dist/pagespeed/parsers.js.map +1 -0
- package/dist/pagespeed/types.d.ts +156 -0
- package/dist/pagespeed/types.d.ts.map +1 -0
- package/dist/pagespeed/types.js +2 -0
- package/dist/pagespeed/types.js.map +1 -0
- package/dist/pagespeed/wire.d.ts +10 -0
- package/dist/pagespeed/wire.d.ts.map +1 -0
- package/dist/pagespeed/wire.js +96 -0
- package/dist/pagespeed/wire.js.map +1 -0
- package/dist/pagespeed.d.ts +6 -0
- package/dist/pagespeed.d.ts.map +1 -0
- package/dist/pagespeed.js +4 -0
- package/dist/pagespeed.js.map +1 -0
- package/dist/parsers/geocode.d.ts.map +1 -1
- package/dist/parsers/geocode.js +30 -1
- package/dist/parsers/geocode.js.map +1 -1
- package/dist/parsers/reviews.d.ts +8 -1
- package/dist/parsers/reviews.d.ts.map +1 -1
- package/dist/parsers/reviews.js +46 -9
- package/dist/parsers/reviews.js.map +1 -1
- package/dist/platform/catalog.d.ts +18 -0
- package/dist/platform/catalog.d.ts.map +1 -0
- package/dist/platform/catalog.js +320 -0
- package/dist/platform/catalog.js.map +1 -0
- package/dist/platform/parity.d.ts +12 -0
- package/dist/platform/parity.d.ts.map +1 -0
- package/dist/platform/parity.js +25 -0
- package/dist/platform/parity.js.map +1 -0
- package/dist/services/elevation.d.ts +6 -4
- package/dist/services/elevation.d.ts.map +1 -1
- package/dist/services/elevation.js +39 -4
- package/dist/services/elevation.js.map +1 -1
- package/dist/services/environment/air-quality.d.ts +39 -0
- package/dist/services/environment/air-quality.d.ts.map +1 -0
- package/dist/services/environment/air-quality.js +82 -0
- package/dist/services/environment/air-quality.js.map +1 -0
- package/dist/services/environment/weather.d.ts +42 -0
- package/dist/services/environment/weather.d.ts.map +1 -0
- package/dist/services/environment/weather.js +63 -0
- package/dist/services/environment/weather.js.map +1 -0
- package/dist/services/geocode.d.ts +5 -1
- package/dist/services/geocode.d.ts.map +1 -1
- package/dist/services/geocode.js +13 -0
- package/dist/services/geocode.js.map +1 -1
- package/dist/services/keyed.d.ts +80 -0
- package/dist/services/keyed.d.ts.map +1 -0
- package/dist/services/keyed.js +152 -0
- package/dist/services/keyed.js.map +1 -0
- package/dist/services/knowledge.d.ts +6 -2
- package/dist/services/knowledge.d.ts.map +1 -1
- package/dist/services/knowledge.js +30 -5
- package/dist/services/knowledge.js.map +1 -1
- package/dist/services/mobility.d.ts.map +1 -1
- package/dist/services/mobility.js +13 -2
- package/dist/services/mobility.js.map +1 -1
- package/dist/services/nearby-search.d.ts +32 -0
- package/dist/services/nearby-search.d.ts.map +1 -0
- package/dist/services/nearby-search.js +85 -0
- package/dist/services/nearby-search.js.map +1 -0
- package/dist/services/panorama.d.ts +8 -1
- package/dist/services/panorama.d.ts.map +1 -1
- package/dist/services/panorama.js +48 -0
- package/dist/services/panorama.js.map +1 -1
- package/dist/services/photos.d.ts.map +1 -1
- package/dist/services/photos.js +9 -2
- package/dist/services/photos.js.map +1 -1
- package/dist/services/places.d.ts.map +1 -1
- package/dist/services/places.js +1 -0
- package/dist/services/places.js.map +1 -1
- package/dist/services/reviews.d.ts.map +1 -1
- package/dist/services/reviews.js +4 -1
- package/dist/services/reviews.js.map +1 -1
- package/dist/services/search.d.ts +8 -3
- package/dist/services/search.d.ts.map +1 -1
- package/dist/services/search.js +28 -9
- package/dist/services/search.js.map +1 -1
- package/dist/translate.d.ts +75 -0
- package/dist/translate.d.ts.map +1 -0
- package/dist/translate.js +126 -0
- package/dist/translate.js.map +1 -0
- package/dist/travel-google/common.d.ts +24 -0
- package/dist/travel-google/common.d.ts.map +1 -0
- package/dist/travel-google/common.js +72 -0
- package/dist/travel-google/common.js.map +1 -0
- package/dist/trends/client.d.ts +17 -0
- package/dist/trends/client.d.ts.map +1 -0
- package/dist/trends/client.js +86 -0
- package/dist/trends/client.js.map +1 -0
- package/dist/trends/errors.d.ts +8 -0
- package/dist/trends/errors.d.ts.map +1 -0
- package/dist/trends/errors.js +13 -0
- package/dist/trends/errors.js.map +1 -0
- package/dist/trends/links.d.ts +8 -0
- package/dist/trends/links.d.ts.map +1 -0
- package/dist/trends/links.js +71 -0
- package/dist/trends/links.js.map +1 -0
- package/dist/trends/parsers.d.ts +5 -0
- package/dist/trends/parsers.d.ts.map +1 -0
- package/dist/trends/parsers.js +126 -0
- package/dist/trends/parsers.js.map +1 -0
- package/dist/trends/types.d.ts +71 -0
- package/dist/trends/types.d.ts.map +1 -0
- package/dist/trends/types.js +2 -0
- package/dist/trends/types.js.map +1 -0
- package/dist/trends.d.ts +9 -0
- package/dist/trends.d.ts.map +1 -0
- package/dist/trends.js +8 -0
- package/dist/trends.js.map +1 -0
- package/dist/types/common.d.ts +28 -2
- package/dist/types/common.d.ts.map +1 -1
- package/dist/types/common.js.map +1 -1
- package/dist/types/directions.d.ts +1 -1
- package/dist/types/directions.d.ts.map +1 -1
- package/dist/types/dx.d.ts +23 -10
- package/dist/types/dx.d.ts.map +1 -1
- package/dist/types/panorama.d.ts +19 -0
- package/dist/types/panorama.d.ts.map +1 -1
- package/dist/types/reviews.d.ts +3 -4
- package/dist/types/reviews.d.ts.map +1 -1
- package/dist/types/suggest.d.ts +4 -6
- package/dist/types/suggest.d.ts.map +1 -1
- package/dist/utils/google-web.d.ts +24 -0
- package/dist/utils/google-web.d.ts.map +1 -0
- package/dist/utils/google-web.js +150 -0
- package/dist/utils/google-web.js.map +1 -0
- package/dist/utils/place-ref.d.ts +14 -4
- package/dist/utils/place-ref.d.ts.map +1 -1
- package/dist/utils/place-ref.js +49 -1
- package/dist/utils/place-ref.js.map +1 -1
- package/dist/youtube/client.d.ts +19 -0
- package/dist/youtube/client.d.ts.map +1 -0
- package/dist/youtube/client.js +115 -0
- package/dist/youtube/client.js.map +1 -0
- package/dist/youtube/errors.d.ts +8 -0
- package/dist/youtube/errors.d.ts.map +1 -0
- package/dist/youtube/errors.js +13 -0
- package/dist/youtube/errors.js.map +1 -0
- package/dist/youtube/parsers.d.ts +9 -0
- package/dist/youtube/parsers.d.ts.map +1 -0
- package/dist/youtube/parsers.js +213 -0
- package/dist/youtube/parsers.js.map +1 -0
- package/dist/youtube/types.d.ts +90 -0
- package/dist/youtube/types.d.ts.map +1 -0
- package/dist/youtube/types.js +2 -0
- package/dist/youtube/types.js.map +1 -0
- package/dist/youtube.d.ts +9 -0
- package/dist/youtube.d.ts.map +1 -0
- package/dist/youtube.js +6 -0
- package/dist/youtube.js.map +1 -0
- package/docs/books.md +18 -0
- package/docs/environment-research.md +65 -0
- package/docs/finance-research.md +153 -0
- package/docs/finance.md +43 -0
- package/docs/gemini-web.md +36 -0
- package/docs/google-ai-books-research.md +53 -0
- package/docs/google-media-research.md +105 -0
- package/docs/google-search-research.md +36 -0
- package/docs/google-search.md +53 -0
- package/docs/google-services-research.md +135 -0
- package/docs/google-travel-research.md +86 -0
- package/docs/internal/reverse-engineering.md +85 -0
- package/docs/lens.md +54 -0
- package/docs/maps-revalidation.md +31 -0
- package/docs/news.md +35 -0
- package/docs/pagespeed-research.md +153 -0
- package/docs/pagespeed.md +135 -0
- package/docs/reviews-research.md +33 -0
- package/docs/translate.md +78 -0
- package/docs/trends-research.md +82 -0
- package/docs/trends.md +75 -0
- package/docs/youtube.md +72 -0
- package/package.json +77 -2
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Reverse-engineering notes — Maps web client internals
|
|
2
|
+
|
|
3
|
+
Field notes from deobfuscating the Google Maps web app bundles
|
|
4
|
+
(`maps.m.en.*` bootstrap + lazy modules) and its Web Worker loaders. Everything
|
|
5
|
+
documented here is implemented somewhere in `src/`; this file records *how the
|
|
6
|
+
client does it* so future changes can be re-derived.
|
|
7
|
+
|
|
8
|
+
## Bundle layout
|
|
9
|
+
|
|
10
|
+
| Piece | URL shape | Notes |
|
|
11
|
+
|-------|-----------|-------|
|
|
12
|
+
| Bootstrap | `/maps/_/js/k=maps.m.en.<key>.O/m=<initial>/am=<am>/rs=<rs>` | WIZ loader, `eptZe` = batchexecute prefix |
|
|
13
|
+
| Lazy modules | same + `ck=` client key | The server validates module *sets*; arbitrary lists 404 |
|
|
14
|
+
| Workers / WASM | `/maps/_/wa/<wli-entry>[.loader.js]` | `_/js/` → `_/wa/` swap decoded from `_.bTc` |
|
|
15
|
+
|
|
16
|
+
The `wli` preload hints in the page HTML (`m.<bundle>.<feature>.O`) name the
|
|
17
|
+
worker bundles: `smIQCHgOkp8` → **mapcore** (3D renderer),
|
|
18
|
+
`7P4nUyqPXWw` → **loadSv** (Street View), `syLOIf-d1F0` → **loadSvVtl**
|
|
19
|
+
(SV vector tiles), `yDBEh32NTLI` → labeler.
|
|
20
|
+
|
|
21
|
+
Workers are Emscripten shells; the renderers are WASM sidecars fetched
|
|
22
|
+
relative to the loader (`renderer_binary_web_release.wasm`,
|
|
23
|
+
`streetview_imp_wasm_cc_binary.wasm`, …). Message protocol is
|
|
24
|
+
`{ command, payload }` with transferable `ArrayBuffer`s (command 6 =
|
|
25
|
+
label/paint prep).
|
|
26
|
+
|
|
27
|
+
## vt layer descriptors (`_.er`)
|
|
28
|
+
|
|
29
|
+
Named overlay layers serialise into the `/maps/vt?pb=` layer block as
|
|
30
|
+
field 1 = type enum, field 2 = name string, field 3 = per-layer number,
|
|
31
|
+
field 4 = repeated key/value app options:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
!2m2!1e5!2sshading hillshade raster (global, z8+)
|
|
35
|
+
!2m2!1e6!2scontours contour lines (z13–15)
|
|
36
|
+
!2m2!1e2!2sair-quality-heatmap AQI heatmap (z5–15, city detail)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The JS switch also defines traffic (+`incidents`/`incidents_text`/
|
|
40
|
+
`seconds_into_week` options), transit (+`sp=2`, number 999999), bike,
|
|
41
|
+
`svv` (SV coverage vectors with camera/epoch options), indoor,
|
|
42
|
+
`crisis2`, `area-busyness`, `hotel-categorical-search`, `lore-p13n`,
|
|
43
|
+
`lore-rec`, `travel-map-reachability`. Those answer only inside the full
|
|
44
|
+
client style context — probed directly they return a valid-but-blank ~220-byte
|
|
45
|
+
placeholder PNG. That placeholder is how "no data" is signalled for the
|
|
46
|
+
working layers too.
|
|
47
|
+
|
|
48
|
+
## rocktree octree (`kh.google.com/rt/<planetoid>`)
|
|
49
|
+
|
|
50
|
+
- `PlanetoidMetadata` → root epoch (key field 1 → subfield 2) and radius.
|
|
51
|
+
- `BulkMetadata/pb=!1m2!1s<path>!2u<epoch>` → nodes carry packed
|
|
52
|
+
path+flags (level = low 2 bits + 1, 3 bits per octant), per-node epochs,
|
|
53
|
+
quantised OBB (centre deltas × metres-per-texel + Euler angles), and
|
|
54
|
+
imagery epoch. Flag bit 16 = NodeData requires `!3u{imageryEpoch}` —
|
|
55
|
+
sending it unrequested yields HTTP 404; flag bit 8 = metadata-only node.
|
|
56
|
+
- `NodeData/pb=!1m2!1s<path>!2u<epoch>!2e1[!3u<img>]!4b0` → globe-from-mesh
|
|
57
|
+
matrix (16 doubles), meshes whose vertices are three byte planes of running
|
|
58
|
+
deltas, triangle strips encoded as back-references, UVs as two delta planes
|
|
59
|
+
mod a wrap value, plus a 512×512 JPEG texture.
|
|
60
|
+
- Planets: `earth` (r 6371010 m), `mars` (3389500 m), `moon` (1737400 m).
|
|
61
|
+
|
|
62
|
+
## Street View
|
|
63
|
+
|
|
64
|
+
- `photometa v1` pb includes section list ids; id **18** opts into the
|
|
65
|
+
quantised depth raster (512×256) shipped alongside tiles.
|
|
66
|
+
- Panorama tile pyramid geometry comes from `tileSizes` /
|
|
67
|
+
`maxTileDimensions` / `tileFaceSize`; there is no video endpoint — the web
|
|
68
|
+
client renders equirectangular panoramas from these tiles.
|
|
69
|
+
- Imagery: `streetviewpixels-pa.googleapis.com/v1/{thumbnail,tile}`
|
|
70
|
+
(`cb_client=maps_sv.tactile`), no auth.
|
|
71
|
+
- Legacy `GeoPhotoService.SingleImageQuery` is gone from current bundles;
|
|
72
|
+
photometa is the canonical metadata surface.
|
|
73
|
+
|
|
74
|
+
## batchexecute registrations (`_.cy`)
|
|
75
|
+
|
|
76
|
+
Service-path format (`/MapsService.Method` as rpcid) works anonymously;
|
|
77
|
+
legacy short ids require the WIZ `SNlM0e` token. Confirmed id ↔ path pairs:
|
|
78
|
+
`EvxQ3b`→GetAreaTraffic, `hspqX`→ListEntityPhotos, `T4jwAf`→GetViewportMetadata,
|
|
79
|
+
`JGUSi`→GetUserPrefs, `PDqRpc`→WriteUserPrefs, `erVIH`→GetMapDetails,
|
|
80
|
+
`EGR9cd`→CallAskMapsAgent (signed-in only).
|
|
81
|
+
|
|
82
|
+
## Worker sources
|
|
83
|
+
|
|
84
|
+
Loader sources (captured locally during analysis, not checked in) are
|
|
85
|
+
Emscripten glue; no Maps business logic ships in them.
|
package/docs/lens.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Google Lens
|
|
2
|
+
|
|
3
|
+
The Lens client starts an image search and returns Google's issued results URL.
|
|
4
|
+
It also builds image-URL navigation links. OCR and visual-match results remain
|
|
5
|
+
unverified because the observed results page required a traffic challenge.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { readFile } from 'node:fs/promises';
|
|
9
|
+
import { lens } from 'googlemaps-kit/lens';
|
|
10
|
+
|
|
11
|
+
const client = lens({ locale: 'en-US' });
|
|
12
|
+
const image = await readFile('/absolute/path/to/image-you-want-to-search.png');
|
|
13
|
+
const session = await client.createSearch(image, {
|
|
14
|
+
filename: 'image.png',
|
|
15
|
+
mimeType: 'image/png',
|
|
16
|
+
});
|
|
17
|
+
console.log(session.url);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`createSearch()` uploads the caller-supplied `Uint8Array` or `Blob` as multipart
|
|
21
|
+
`encoded_image`. The result contains the redirect URL and original redirect
|
|
22
|
+
status, location header and body. It stops at that redirect and does not load
|
|
23
|
+
results pages. Opening the URL can still require consent, sign-in, or a traffic
|
|
24
|
+
challenge.
|
|
25
|
+
|
|
26
|
+
`width` and `height`, when supplied together, populate the website's optional
|
|
27
|
+
`processed_image_dimensions` field. They should describe the supplied image.
|
|
28
|
+
The client does not resize or inspect image contents. PNG, JPEG, WebP and GIF
|
|
29
|
+
media types are accepted by its interface.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
const link = client.searchUrl('https://example.com/public-image.png');
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`searchUrl()` constructs the current shipped upload service's URL-image
|
|
36
|
+
navigation using `/v3/upload?url=...`. This is supported by static source evidence;
|
|
37
|
+
the URL-image path was not separately executed after the observed upload results
|
|
38
|
+
hit a challenge. Building the link performs no upload or request. Google's
|
|
39
|
+
[image-search help](https://support.google.com/websearch/answer/1325808?hl=en)
|
|
40
|
+
describes file upload and image-URL search in the consumer interface.
|
|
41
|
+
|
|
42
|
+
The live investigation used only a synthetic image containing test text. The
|
|
43
|
+
actual file upload returned HTTP 303, then its Google Search destination showed
|
|
44
|
+
an unusual-traffic CAPTCHA. No CAPTCHA was solved, and no OCR or visual-match
|
|
45
|
+
response schema is claimed from that session. The library therefore exposes
|
|
46
|
+
upload/navigation transport, without an unverified recognition parser.
|
|
47
|
+
|
|
48
|
+
Configuration accepts an injected `fetch`, `locale`, and `timeoutMs` (30 seconds
|
|
49
|
+
by default). Upload options accept an `AbortSignal`. `LensError.kind` distinguishes
|
|
50
|
+
`http`, `blocked`, `auth-required`, `rate-limit`, `parse`, `network`, and `timeout`.
|
|
51
|
+
Requests are issued once and redirects to challenge pages are reported explicitly.
|
|
52
|
+
|
|
53
|
+
Run offline tests with `npx vitest run tests/unit/lens`. The media live suite
|
|
54
|
+
covers YouTube; it does not repeat an upload into the observed Lens challenge.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Existing Maps capabilities
|
|
2
|
+
|
|
3
|
+
The Maps implementation predates the additional Google consumer clients.
|
|
4
|
+
This pass reused its source, wire builders, captured fixtures and explicit
|
|
5
|
+
surface-status catalog rather than treating every registered RPC as verified.
|
|
6
|
+
`src/known-surfaces.ts` and `src/platform/catalog.ts` retain the per-surface
|
|
7
|
+
working, partial, authentication and unsupported boundaries.
|
|
8
|
+
|
|
9
|
+
Representative anonymous live checks on 2026-10-29:
|
|
10
|
+
|
|
11
|
+
| Capability | Observed result |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| Reviews | Five-review page plus rating total/aggregate; 20 deduplicated reviews over two further pages |
|
|
14
|
+
| Forward geocoding | HSR Layout resolved to coordinates and its Bengaluru address |
|
|
15
|
+
| Reverse geocoding | Existing HSR fixture coordinates resolved to a Bengaluru address |
|
|
16
|
+
| Driving directions | HSR→Koramangala returned a 14-minute, 4.5km route with one leg and turn instructions |
|
|
17
|
+
| Viewport weather | Populated HSR response returned `28°` and `Sunny`, following an initial metadata stub |
|
|
18
|
+
|
|
19
|
+
These values describe captured checks, not fixed expected travel times or
|
|
20
|
+
weather. The existing core offline suite covers place/search parsers, reviews,
|
|
21
|
+
directions, tiles, photo/panorama formats and auth boundaries. This pass also
|
|
22
|
+
fixed authenticated review fallback cursor propagation and corrected two
|
|
23
|
+
supported environment-API request contracts; see [Reviews](reviews-research.md)
|
|
24
|
+
and [environment access](environment-research.md).
|
|
25
|
+
|
|
26
|
+
The consumer SDK is not full parity with every Maps Platform SKU. In particular,
|
|
27
|
+
keyed enterprise fields, authenticated Ask Maps/history, private lists,
|
|
28
|
+
session-dependent overlays, and endpoints marked unverified retain their
|
|
29
|
+
existing limits. Public Places' five-review cap and the consumer review page
|
|
30
|
+
protocol are separate contracts. Official API prices and credentials remain
|
|
31
|
+
documented in the [service inventory](google-services-research.md).
|
package/docs/news.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Google News public feeds
|
|
2
|
+
|
|
3
|
+
```ts
|
|
4
|
+
import { googleNews } from 'googlemaps-kit/news';
|
|
5
|
+
|
|
6
|
+
const news = googleNews({ language: 'en-US', country: 'US' });
|
|
7
|
+
const headlines = await news.headlines();
|
|
8
|
+
const results = await news.search('Google AI');
|
|
9
|
+
for (const article of results.articles) {
|
|
10
|
+
console.log(article.title, article.source?.name, article.publishedAt, article.url);
|
|
11
|
+
}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The client reads public `/rss` and `/rss/search` feeds without an API key or
|
|
15
|
+
browser. It returns channel metadata, titles, publication times, source names,
|
|
16
|
+
source homepages and article links. Article links remain Google's RSS redirect
|
|
17
|
+
URLs; the client does not claim to decode them into publisher article URLs.
|
|
18
|
+
Descriptions remain HTML strings supplied by the feed. Full articles, arbitrary
|
|
19
|
+
pagination, personalized feeds and a complete news index are outside this API.
|
|
20
|
+
|
|
21
|
+
Configure `fetch`, `timeoutMs`, `language`, `country`, and optional `edition`
|
|
22
|
+
(`US:en`, for example). Each method accepts locale overrides and `signal`.
|
|
23
|
+
Default deadline is 30 seconds including the response body. Errors propagate
|
|
24
|
+
as `GoogleWebError`; no automatic retries occur. XML parsing is limited to the
|
|
25
|
+
observed RSS contract, never evaluates HTML and rejects entity declarations.
|
|
26
|
+
CDATA contents are preserved verbatim, ordinary XML entities are decoded once,
|
|
27
|
+
and comments are ignored. The parser rejects mismatched or truncated elements
|
|
28
|
+
and bounds input to 10 million characters, 50,000 elements and 64 nesting levels.
|
|
29
|
+
|
|
30
|
+
The search feed returned HTTP 200 and valid public data on 2026-10-29. Its
|
|
31
|
+
`hl`, `gl`, `ceid`, and `q` parameters were captured directly. Feed metadata
|
|
32
|
+
includes Google's usage notice; the returned `copyright` field preserves it.
|
|
33
|
+
No general paid Google News query API was established in the official-source
|
|
34
|
+
[service catalog](google-services-research.md). Paid third-party news APIs are
|
|
35
|
+
separate products.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# PageSpeed Insights wire research
|
|
2
|
+
|
|
3
|
+
Investigated on 2026-10-29 against `pagespeed.web.dev`, build
|
|
4
|
+
`boq_chrome-lightbrary-ui_20261027.04_p0`. These are observations of Google's
|
|
5
|
+
public web client, not a claim that undocumented interfaces are stable.
|
|
6
|
+
|
|
7
|
+
## Evidence and verification
|
|
8
|
+
|
|
9
|
+
- Bootstrap HTML exposes `eptZe=/_/PagespeedUi/`, `cfb2h` as the build label,
|
|
10
|
+
`FdrFJe` as the page session identifier, and `pDzS6=3`.
|
|
11
|
+
- Browser network capture observed `nqfuif` with arguments
|
|
12
|
+
`["https://example.com/",3]`; that browser attempt received an automated-query
|
|
13
|
+
HTTP 429 page. Direct HTTP replay subsequently returned a successful creation
|
|
14
|
+
response. A browser failure therefore does not establish that the web RPC is
|
|
15
|
+
unavailable.
|
|
16
|
+
- Successful create, `LsX2he` poll, and `CBayme` get responses were captured.
|
|
17
|
+
Analysis `bidxril0yk` for `https://example.com/` contained six completed
|
|
18
|
+
records: page CrUX, origin CrUX, and Lighthouse for both mobile and desktop.
|
|
19
|
+
The saved analysis page also contained the complete analysis in its server
|
|
20
|
+
preload data (`ds:0`).
|
|
21
|
+
- The public `runPagespeed` endpoint was probed without an API key and returned
|
|
22
|
+
HTTP 429 with `quota_limit_value=0`. This is the observed quota state, not
|
|
23
|
+
evidence that every caller needs a key or that the web RPC shares that quota.
|
|
24
|
+
- Static analysis inspected 25 downloaded scripts, all parsed successfully,
|
|
25
|
+
totaling 257,599 AST nodes. Browser inventory evidence:
|
|
26
|
+
`ev_33511f751b9d5da9383dae0f6f3ad5ac7b56056f11c6fb9ab0b66a8fba60d3b8`.
|
|
27
|
+
Bundle analysis evidence:
|
|
28
|
+
`ev_a9a73ecc0dc732329bf2835d27fe016bb9717d1e528a9d905dbc0885dbfc864e`.
|
|
29
|
+
- Original captures and downloaded bundles remain in the untracked research
|
|
30
|
+
scratch directory. Shipped code and tests must not depend on those files.
|
|
31
|
+
|
|
32
|
+
## Transports and RPCs
|
|
33
|
+
|
|
34
|
+
Web calls POST form-encoded `f.req` to
|
|
35
|
+
`https://pagespeed.web.dev/_/PagespeedUi/data/batchexecute`. The observed request
|
|
36
|
+
used `rpcids`, `source-path=/analysis`, `f.sid`, `bl`, `hl`, `_reqid`, and `rt=c`.
|
|
37
|
+
Its body was `[[[rpcid, JSON.stringify(args), null, "generic"]]]` under `f.req`;
|
|
38
|
+
the observed anonymous create omitted `at`. Responses use Google's XSSI prefix,
|
|
39
|
+
length-framed JSON, and `wrb.fr` records containing JSON-encoded payloads.
|
|
40
|
+
|
|
41
|
+
| RPC | Purpose | Request arguments | Response | Evidence |
|
|
42
|
+
| --- | --- | --- | --- | --- |
|
|
43
|
+
| `nqfuif` | Create analysis | `[url, context, null, useOriginalUrl]`; trailing defaults can be omitted | Field 1 contains Analysis | Builder and successful live response |
|
|
44
|
+
| `CBayme` | Get saved analysis | `[analysisId]` | Analysis directly | Explicit `/Pagespeed.GetAnalysis` descriptor and successful live response |
|
|
45
|
+
| `LsX2he` | Refresh pending records | `[analysisId, [recordId, ...]]` | Field 1 is repeated Result | Polling code and successful live response |
|
|
46
|
+
| `deISwc` | Legacy report preparation; URL resolution is an inference | `[url, null, formFactor]` | Observed `[url, url]`; response getter reads field 2 as string | Legacy `/report` builder and live probe; no complete semantic descriptor |
|
|
47
|
+
| `zKzUAb` | Unknown | Unknown | Unknown | Descriptor only; request class `dIqFbe`, response `CAV36d`; no caller or field accesses found |
|
|
48
|
+
|
|
49
|
+
The create context comes from `WIZ_global_data.pDzS6`, observed as `3`. Its
|
|
50
|
+
semantic enum name is unknown. It must not be interpreted as mobile or desktop:
|
|
51
|
+
the successful creation produced both form factors. Static create code attaches
|
|
52
|
+
`X-Rawurl: <url>` and places the `use_original_url` boolean in field 4.
|
|
53
|
+
|
|
54
|
+
The official API is a separate JSON transport:
|
|
55
|
+
`GET https://www.googleapis.com/pagespeedonline/v5/runPagespeed`. Its options
|
|
56
|
+
and quota behavior must not be inferred from the web client's positional RPCs.
|
|
57
|
+
|
|
58
|
+
## Analysis and result layouts
|
|
59
|
+
|
|
60
|
+
Field numbers below are one-based protobuf field numbers; ordinary JSON array
|
|
61
|
+
indices are one less. This distinction matters when writing parsers.
|
|
62
|
+
|
|
63
|
+
| Analysis field | Meaning |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| 1 | Saved analysis ID |
|
|
66
|
+
| 2 | Analysis URL |
|
|
67
|
+
| 3 | Status; `1` initiates polling, `2` observed for completed analysis |
|
|
68
|
+
| 4 | Opaque context/location value; observed `3`, forwarded to the Lighthouse renderer |
|
|
69
|
+
| 5 | Repeated Result records |
|
|
70
|
+
| 6 | Map entries `[formFactor, originalUrl]`, used for redirect comparison |
|
|
71
|
+
| 7 | Timestamp `[seconds, nanos]`, displayed as the report creation time |
|
|
72
|
+
|
|
73
|
+
| Result field | Meaning |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| 1 | Original subject URL |
|
|
76
|
+
| 2 | Resolved/final subject URL; origin records omit the trailing slash |
|
|
77
|
+
| 3 | Form factor: `1` mobile, `2` desktop |
|
|
78
|
+
| 4 | Kind: `1` Lighthouse, `2` origin CrUX, `3` page CrUX |
|
|
79
|
+
| 5 | Unidentified data alternative; not exercised in the successful capture |
|
|
80
|
+
| 6 | CrUX record; mutually exclusive with fields 5 and 10 |
|
|
81
|
+
| 7 | Status: `1` pending, `2` complete |
|
|
82
|
+
| 8 | Error/status message; code field 1, message field 2 |
|
|
83
|
+
| 9 | Record ID used by polling and cache replacement |
|
|
84
|
+
| 10 | Lighthouse result serialized as a JSON string |
|
|
85
|
+
|
|
86
|
+
The UI polls every 3,000 ms, requesting only records whose status is `1`, and
|
|
87
|
+
replaces records by ID. It stops when none are pending. A completed record can
|
|
88
|
+
carry an error; completion does not imply successful Lighthouse or CrUX data.
|
|
89
|
+
The UI recognizes error code `5` as missing CrUX data. Redirect handling compares
|
|
90
|
+
the original and final URL's origin plus pathname, ignoring query and fragment.
|
|
91
|
+
|
|
92
|
+
Saved links use `/analysis/<analysisId>` or
|
|
93
|
+
`/analysis/<sanitizedUrl>/<analysisId>`, optionally with `form_factor=mobile` or
|
|
94
|
+
`form_factor=desktop`. The sanitized URL is decorative: retrieval uses the ID.
|
|
95
|
+
The UI removes the `url` query parameter after creation and retains the ID.
|
|
96
|
+
|
|
97
|
+
## CrUX layout and units
|
|
98
|
+
|
|
99
|
+
For `crux = result[5]` using zero-based JavaScript indices:
|
|
100
|
+
|
|
101
|
+
- `crux[0][0]` is the record key. Index 0 holds an origin URL; index 4 holds a
|
|
102
|
+
page URL. Index 2 is the CrUX device enum: `2` PHONE and `1` DESKTOP in the
|
|
103
|
+
successful capture. This is the reverse of the outer Result form-factor enum.
|
|
104
|
+
- `crux[1]` contains entries `[metricName, metricValue]`.
|
|
105
|
+
- For the observed numeric metrics, `distribution = metricValue[1]`.
|
|
106
|
+
`distribution[0][0]` contains histogram bins;
|
|
107
|
+
`distribution[1][0]` contains the 75th-percentile typed value.
|
|
108
|
+
- Each bin is `[typedStart, typedEndOrNull, density]`. A missing upper bound
|
|
109
|
+
denotes the final open-ended bin. Densities are fractions, not percentages.
|
|
110
|
+
- Typed values contain numeric milliseconds at index 1, or decimal strings at
|
|
111
|
+
index 2 for dimensionless CLS values. Preserve numeric zero.
|
|
112
|
+
- `crux[3]` is the collection period:
|
|
113
|
+
`[[startYear,startMonth,startDay],[endYear,endMonth,endDay]]`, with one-based
|
|
114
|
+
months. The successful capture covered 2026-09-30 through 2026-10-27.
|
|
115
|
+
|
|
116
|
+
Metrics can omit histograms while retaining a percentile, as observed for the
|
|
117
|
+
LCP image subparts. Entries can also have `null` values, as observed for
|
|
118
|
+
`navigation_types` and `largest_contentful_paint_resource_type`. Unknown metric
|
|
119
|
+
names and raw values should survive parsing; do not assume every entry has
|
|
120
|
+
three bins or a percentile.
|
|
121
|
+
|
|
122
|
+
The bootstrap metric configuration supplied these thresholds:
|
|
123
|
+
|
|
124
|
+
| Metric | UI enum | Good upper bound | Needs-improvement upper bound | Unit |
|
|
125
|
+
| --- | --- | --- | --- | --- |
|
|
126
|
+
| `largest_contentful_paint` | 1 | 2500 | 4000 | ms |
|
|
127
|
+
| `first_contentful_paint` | 2 | 1800 | 3000 | ms |
|
|
128
|
+
| `cumulative_layout_shift` | 3 | 0.10 | 0.25 | unitless |
|
|
129
|
+
| `experimental_time_to_first_byte` | 10 | 800 | 1800 | ms |
|
|
130
|
+
| `interaction_to_next_paint` | 11 | 200 | 500 | ms |
|
|
131
|
+
|
|
132
|
+
Static UI code includes metrics in the Core Web Vitals assessment only when
|
|
133
|
+
they have three histogram bins and a numeric or decimal percentile. It marks
|
|
134
|
+
the assessment unavailable if LCP or CLS is missing. It passes when their
|
|
135
|
+
percentiles are within the good thresholds and INP is also good when present;
|
|
136
|
+
missing INP alone does not fail the assessment. Good and needs-improvement
|
|
137
|
+
upper bounds are inclusive in the UI's percentile-based rating code.
|
|
138
|
+
|
|
139
|
+
## Lighthouse and remaining limits
|
|
140
|
+
|
|
141
|
+
Both successful Lighthouse records used Lighthouse 13.5.0, contained 159 audits,
|
|
142
|
+
and included all of `performance`,
|
|
143
|
+
`accessibility`, `best-practices`, `seo`, and `agentic-browsing`. Preserve the full
|
|
144
|
+
Lighthouse JSON, dynamic audit/category names, screenshots, warnings,
|
|
145
|
+
configuration, environment, and timings rather than hard-coding four categories.
|
|
146
|
+
Scores use the original 0–1 representation.
|
|
147
|
+
|
|
148
|
+
Unknowns remain explicit: the semantic name of the create context enum, the
|
|
149
|
+
field-5 Result alternative, the purpose and arguments of `zKzUAb`, all enum
|
|
150
|
+
values not exercised here, and the complete semantics of legacy `deISwc`.
|
|
151
|
+
Descriptor registration alone does not establish a working endpoint. No claim
|
|
152
|
+
is made that automated-query blocking, quotas, or saved-report retention are
|
|
153
|
+
constant across networks, sessions, or future builds.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# PageSpeed Insights
|
|
2
|
+
|
|
3
|
+
```ts
|
|
4
|
+
import { pageSpeed, PageSpeedError } from 'googlemaps-kit/pagespeed';
|
|
5
|
+
|
|
6
|
+
const speed = pageSpeed({ locale: 'en-US' });
|
|
7
|
+
const analysis = await speed.analyze('https://example.com/');
|
|
8
|
+
console.log(analysis.reportUrl);
|
|
9
|
+
|
|
10
|
+
for (const result of analysis.results) {
|
|
11
|
+
if (result.error) console.error(result.strategy, result.type, result.error);
|
|
12
|
+
if (result.lighthouse) console.log(result.strategy, result.lighthouse.categories);
|
|
13
|
+
if (result.fieldData) console.log(result.strategy, result.type, result.fieldData);
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The web transport uses the same create/get/poll RPCs as `pagespeed.web.dev`.
|
|
18
|
+
It requires Node 18+ and has no browser or API-key dependency. Creation starts
|
|
19
|
+
both mobile and desktop Lighthouse runs, plus separate page and origin CrUX
|
|
20
|
+
jobs for each strategy. The website controls their categories and test settings.
|
|
21
|
+
|
|
22
|
+
## Methods
|
|
23
|
+
|
|
24
|
+
| Method | Behavior |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| `analyze(url, options?)` | Create jobs, then wait for completion |
|
|
27
|
+
| `createAnalysis(url, options?)` | Return the initial analysis and pending result IDs |
|
|
28
|
+
| `getAnalysis(idOrReportUrl, options?)` | Retrieve a saved analysis |
|
|
29
|
+
| `pollAnalysis(analysisOrId, options?)` | Refresh pending records once, merging by result ID |
|
|
30
|
+
| `waitForAnalysis(analysisOrId, options?)` | Poll until jobs finish or the deadline expires |
|
|
31
|
+
| `runPagespeed(url, options?)` | Call the separate, documented v5 API |
|
|
32
|
+
|
|
33
|
+
All methods accept `signal`. Create accepts `useOriginalUrl`, matching the web
|
|
34
|
+
client's redirect option. Wait and analyze accept `pollIntervalMs` (default
|
|
35
|
+
3000), `timeoutMs` (default 180000), and `onProgress`. This timeout bounds the
|
|
36
|
+
waiting phase; `analyze` starts its wait after creation. Client configuration
|
|
37
|
+
`timeoutMs` separately bounds each HTTP request, including its body (default
|
|
38
|
+
120000). No request is retried automatically, avoiding duplicate analysis jobs.
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
const controller = new AbortController();
|
|
42
|
+
const started = await speed.createAnalysis('https://example.com/', {
|
|
43
|
+
signal: controller.signal,
|
|
44
|
+
});
|
|
45
|
+
console.log(started.id);
|
|
46
|
+
|
|
47
|
+
const completed = await speed.waitForAnalysis(started, {
|
|
48
|
+
signal: controller.signal,
|
|
49
|
+
timeoutMs: 240_000,
|
|
50
|
+
onProgress: report => console.log(report.results.map(r => [r.strategy, r.type, r.status])),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const saved = await speed.getAnalysis(completed.reportUrl);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Results and exports
|
|
57
|
+
|
|
58
|
+
Each `analysis.results` entry has `id`, `strategy`, `type`, `status`, and its
|
|
59
|
+
original wire `raw` value. `type` is `lighthouse`, `page`, `origin`, or `unknown`.
|
|
60
|
+
Unknown enum values also survive as `typeCode`, `statusCode`, and `strategyCode`.
|
|
61
|
+
An analysis being complete means its jobs have finished; inspect each result's
|
|
62
|
+
`error` and Lighthouse's `runtimeError` before using its scores.
|
|
63
|
+
|
|
64
|
+
`result.lighthouse` is the complete Lighthouse JSON. Scores remain on the
|
|
65
|
+
original 0–1 scale, and audits, category names, screenshots, diagnostics,
|
|
66
|
+
opportunities, environment, and configuration survive unchanged. It can be
|
|
67
|
+
saved as a Lighthouse report without converting it:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { writeFile } from 'node:fs/promises';
|
|
71
|
+
|
|
72
|
+
const mobile = analysis.results.find(r => r.type === 'lighthouse' && r.strategy === 'mobile');
|
|
73
|
+
if (mobile?.lighthouse) {
|
|
74
|
+
await writeFile('mobile.lighthouse.json', JSON.stringify(mobile.lighthouse, null, 2));
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Field-data results expose all metric names, 75th percentiles, histogram bins,
|
|
79
|
+
categorical fractions, collection dates, and `coreWebVitals`. Millisecond values
|
|
80
|
+
remain milliseconds; CLS is dimensionless; densities and fractions are 0–1.
|
|
81
|
+
Open-ended histogram bins omit `end`. Some metrics have only a percentile.
|
|
82
|
+
`coreWebVitals` is `passed`, `failed`, or `unavailable`; insufficient field data
|
|
83
|
+
is never turned into a zero score. Unknown metric payloads remain in `raw`.
|
|
84
|
+
|
|
85
|
+
`buildReportUrl(id, strategy?)` creates a shareable website URL.
|
|
86
|
+
`parseReportId(idOrReportUrl)` validates IDs and PageSpeed report links.
|
|
87
|
+
|
|
88
|
+
## Official v5 API
|
|
89
|
+
|
|
90
|
+
The official transport is explicit. A user-supplied API key is sent only to
|
|
91
|
+
Google's official API, never to the web RPC transport.
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const api = pageSpeed({ apiKey: process.env.PAGESPEED_API_KEY });
|
|
95
|
+
const report = await api.runPagespeed('https://example.com/', {
|
|
96
|
+
strategy: 'mobile',
|
|
97
|
+
categories: ['performance', 'accessibility', 'best-practices', 'seo'],
|
|
98
|
+
locale: 'en-US',
|
|
99
|
+
});
|
|
100
|
+
console.log(report.lighthouseResult?.categories.performance?.score);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
This method defaults to desktop and the API's performance-only category set.
|
|
104
|
+
It also accepts `captchaToken`, `utmCampaign`, and `utmSource`.
|
|
105
|
+
An omitted key uses Google's anonymous quota, which returned HTTP 429 with a
|
|
106
|
+
zero daily quota during this investigation. Supplying a key uses that project's
|
|
107
|
+
configured quota. See Google's [API reference](https://developers.google.com/speed/docs/insights/rest/v5/pagespeedapi/runpagespeed).
|
|
108
|
+
|
|
109
|
+
## Errors and coverage
|
|
110
|
+
|
|
111
|
+
`PageSpeedError.kind` distinguishes `http`, `rpc`, `parse`, `timeout`, and
|
|
112
|
+
`network`. HTTP errors expose `status` and, when supplied by Google,
|
|
113
|
+
`retryAfterMs`. RPC failures expose `rpcCode`. Caller cancellation propagates
|
|
114
|
+
the abort signal's reason. Missing field data and audit errors belong to the
|
|
115
|
+
individual job rather than failing unrelated jobs.
|
|
116
|
+
|
|
117
|
+
The [research ledger](pagespeed-research.md) records live evidence, wire slots,
|
|
118
|
+
and remaining unknowns. Create/get/poll succeeded without a browser using a
|
|
119
|
+
public example page. Undocumented endpoints, saved-report retention, network
|
|
120
|
+
blocking, and quotas can change. The uncalled `zKzUAb` descriptor and partially
|
|
121
|
+
understood legacy `deISwc` RPC are documented but are not exposed as invented
|
|
122
|
+
features.
|
|
123
|
+
|
|
124
|
+
Run the example from the repository with:
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
npx tsx examples/pagespeed.ts https://example.com/
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
It writes complete mobile and desktop Lighthouse JSON files. Offline coverage
|
|
131
|
+
lives under `tests/unit/pagespeed`; live coverage is opt-in:
|
|
132
|
+
|
|
133
|
+
```sh
|
|
134
|
+
npm run test:pagespeed:live
|
|
135
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Reviews validation
|
|
2
|
+
|
|
3
|
+
The repository already implements public Maps reviews through GetLocalBoqProxy,
|
|
4
|
+
embedded place-preview fallback, rating aggregates, and a signed-in legacy RPC.
|
|
5
|
+
Consumer review viewing and the paid Places API are distinct interfaces.
|
|
6
|
+
|
|
7
|
+
On 2026-10-29 `examples/reviews-list.ts` succeeded anonymously for the existing
|
|
8
|
+
CEVI fixture: one five-review page, 890 total ratings, aggregate score 4.3,
|
|
9
|
+
and 20 deduplicated reviews across two subsequent pages. These counts describe
|
|
10
|
+
that run and will change as reviews are added. No new authenticated live access
|
|
11
|
+
was performed during this investigation.
|
|
12
|
+
|
|
13
|
+
The audit found an authenticated fallback pagination bug: `listAll` updated its
|
|
14
|
+
local cursor but failed to pass it into `listRpc`, repeating the same page.
|
|
15
|
+
It now passes the updated token and preserves continuation when `maxPages`
|
|
16
|
+
stops the loop. Offline regression tests verify cursor progression, cross-page
|
|
17
|
+
deduplication and final-page exhaustion without network calls.
|
|
18
|
+
|
|
19
|
+
Current capabilities include review text, ratings, author metadata, photos,
|
|
20
|
+
owner replies, review attributes, translation metadata, pagination and aggregate
|
|
21
|
+
histograms where the endpoint returns them. Search/rating filters are applied
|
|
22
|
+
to fetched records locally, not represented as full server-side search.
|
|
23
|
+
`reviewCount` is the number returned; `totalReviews` is the place-wide total.
|
|
24
|
+
|
|
25
|
+
Google's supported public Places details API returns at most five relevance-sorted
|
|
26
|
+
reviews, with `reviews` in the Enterprise + Atmosphere field group. Authorized
|
|
27
|
+
Business Profile reviews are a separate interface for managed verified locations.
|
|
28
|
+
See [Places fields](https://developers.google.com/maps/documentation/places/web-service/place-details),
|
|
29
|
+
[Place reviews limit](https://developers.google.com/maps/documentation/places/web-service/reference/rest/v1/places)
|
|
30
|
+
and [Business Profile reviews](https://developers.google.com/my-business/reference/rest/v4/accounts.locations.reviews/list).
|
|
31
|
+
|
|
32
|
+
Private profiles, account actions, writing/deleting reviews, and bypassing
|
|
33
|
+
authentication are not capabilities of the anonymous review reader.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Google Translate consumer client
|
|
2
|
+
|
|
3
|
+
```ts
|
|
4
|
+
import { googleTranslate } from 'googlemaps-kit/translate';
|
|
5
|
+
|
|
6
|
+
const translate = googleTranslate();
|
|
7
|
+
const result = await translate.translate('Good morning', { from: 'en', to: 'hi' });
|
|
8
|
+
console.log(result.text, result.detectedLanguage);
|
|
9
|
+
|
|
10
|
+
const suggestions = await translate.suggest('hello', { from: 'en', to: 'es' });
|
|
11
|
+
const languages = await translate.languages();
|
|
12
|
+
const speechLanguages = await translate.speechLanguages();
|
|
13
|
+
const speech = await translate.speech(result.text, { language: 'hi' });
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`speech.audio` contains MP3 bytes and `speech.mimeType` is `audio/mpeg`.
|
|
17
|
+
The client uses anonymous TranslateWebserverUi calls. No API key or browser is
|
|
18
|
+
required at runtime. Configuration accepts `fetch`, `timeoutMs` (30 seconds by
|
|
19
|
+
default, including the response body), and interface `locale`. Every method
|
|
20
|
+
accepts `signal`; no request retries automatically.
|
|
21
|
+
|
|
22
|
+
Omit `from` to request language detection as part of translation. Output includes
|
|
23
|
+
translated groups/segments, their source text when returned, detected language,
|
|
24
|
+
and the unmodified positional `raw` response. Segments retain the website's
|
|
25
|
+
space-before flag; paragraph line breaks survive. Language support is discovered
|
|
26
|
+
from the server rather than inferred from a fixed list. The language selector
|
|
27
|
+
includes `auto` for detection; `to` and speech require a concrete language.
|
|
28
|
+
|
|
29
|
+
`GoogleWebError.kind` distinguishes blocking, HTTP, RPC, malformed responses,
|
|
30
|
+
deadlines and network errors. Google can reject individual requests or languages.
|
|
31
|
+
The client surfaces those failures instead of returning empty translated text.
|
|
32
|
+
|
|
33
|
+
This is a consumer text/speech interface. Google Cloud Translation's supported
|
|
34
|
+
paid API also offers enterprise features such as glossaries, custom models,
|
|
35
|
+
document layout preservation and regional processing; those capabilities are
|
|
36
|
+
outside this client. See [Cloud pricing](https://cloud.google.com/products/translate/pricing)
|
|
37
|
+
and [API editions](https://docs.cloud.google.com/translate/docs/api-overview).
|
|
38
|
+
|
|
39
|
+
## Evidence
|
|
40
|
+
|
|
41
|
+
On 2026-10-29, build `boq_translate-webserver_20261027.05_p0`, an ordinary
|
|
42
|
+
anonymous browser session and direct HTTP replay both returned successful data.
|
|
43
|
+
Captured calls:
|
|
44
|
+
|
|
45
|
+
| RPC | Shipped service name | Verified arguments |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| `MkEWBc` | `/DataService.GetTranslation` | `[[text, source, target, 1, null, 1], []]` |
|
|
48
|
+
| `AVdN8` | Translation suggestions | `[text, source, target]` |
|
|
49
|
+
| `jQ1olc` | `/DataService.GetTts` | `[text, language, null, null, [0]]` |
|
|
50
|
+
| `n9wk7` | `/DataService.GetSupportedLanguageNames` | `[]` |
|
|
51
|
+
| `ycyxUb` | `/DataService.GetSupportedTtsLanguages` | `[]` |
|
|
52
|
+
|
|
53
|
+
Bootstrap uses the current `cfb2h` build and string `FdrFJe` session ID from
|
|
54
|
+
`WIZ_global_data`; the anonymous capture had no `SNlM0e` token. Calls use
|
|
55
|
+
`/_/TranslateWebserverUi/data/batchexecute`, form-encoded `f.req`, XSSI and
|
|
56
|
+
length-framed `wrb.fr` responses. No private account state is needed.
|
|
57
|
+
|
|
58
|
+
The translation is in response field 2. Its field 1 contains groups; each group's
|
|
59
|
+
field 6 contains segments. Segment field 1 is translated text, field 3 is the
|
|
60
|
+
space-before flag, and field 7 is original text. Top-level field 3 is the detected
|
|
61
|
+
language. TTS field 1 is base64 MP3. Supported-language names are pairs in
|
|
62
|
+
response field 1. TTS language entries also contain an opaque numeric parameter
|
|
63
|
+
(`200` in this capture); only the language codes are normalized, with the full
|
|
64
|
+
entries retained in `raw`.
|
|
65
|
+
|
|
66
|
+
Verified sample pairs include English→Hindi, English→Spanish and detected
|
|
67
|
+
English→French with several sentences and a newline. Groups without segments
|
|
68
|
+
use their first field as fallback translated text, matching the shipped display
|
|
69
|
+
helper. Transliteration, images, documents, websites, account history,
|
|
70
|
+
saved translations, AI tools and advanced translation engines remain untested.
|
|
71
|
+
|
|
72
|
+
REA browser inventory evidence:
|
|
73
|
+
`ev_cd09166bd0dc1031d356ae2973023a91a61ae1c2f195729841e766a84702c022`.
|
|
74
|
+
Bundle evidence:
|
|
75
|
+
`ev_e3b423c389b0510f55c936ffcb7b1291548fc2c9ad057cc8975cb56fe1ddfe3b`
|
|
76
|
+
(52 scripts, 924,446 AST nodes, no parse failures). Static observations do not
|
|
77
|
+
prove every declared feature executed. Captured fixture provenance is recorded
|
|
78
|
+
in `tests/fixtures/translate/README.md`.
|