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.
Files changed (343) hide show
  1. package/README.md +56 -3
  2. package/dist/advanced/parsers.d.ts +1 -1
  3. package/dist/advanced/parsers.d.ts.map +1 -1
  4. package/dist/advanced/parsers.js +1 -1
  5. package/dist/advanced/parsers.js.map +1 -1
  6. package/dist/advanced.d.ts +2 -2
  7. package/dist/advanced.d.ts.map +1 -1
  8. package/dist/advanced.js.map +1 -1
  9. package/dist/books.d.ts +30 -0
  10. package/dist/books.d.ts.map +1 -0
  11. package/dist/books.js +77 -0
  12. package/dist/books.js.map +1 -0
  13. package/dist/cli/run.d.ts.map +1 -1
  14. package/dist/cli/run.js +9 -11
  15. package/dist/cli/run.js.map +1 -1
  16. package/dist/cli/tui/app.d.ts.map +1 -1
  17. package/dist/cli/tui/app.js +7 -7
  18. package/dist/cli/tui/app.js.map +1 -1
  19. package/dist/cli.js +14 -11
  20. package/dist/cli.js.map +1 -1
  21. package/dist/client/gmaps-client.d.ts +7 -29
  22. package/dist/client/gmaps-client.d.ts.map +1 -1
  23. package/dist/client/gmaps-client.js +15 -131
  24. package/dist/client/gmaps-client.js.map +1 -1
  25. package/dist/client/http-client.d.ts +3 -1
  26. package/dist/client/http-client.d.ts.map +1 -1
  27. package/dist/client/http-client.js +14 -3
  28. package/dist/client/http-client.js.map +1 -1
  29. package/dist/client/intent.d.ts +1 -11
  30. package/dist/client/intent.d.ts.map +1 -1
  31. package/dist/client/intent.js +17 -13
  32. package/dist/client/intent.js.map +1 -1
  33. package/dist/client/maps-tools.d.ts +8 -4
  34. package/dist/client/maps-tools.d.ts.map +1 -1
  35. package/dist/client/maps-tools.js +20 -11
  36. package/dist/client/maps-tools.js.map +1 -1
  37. package/dist/client/namespaces.d.ts +51 -19
  38. package/dist/client/namespaces.d.ts.map +1 -1
  39. package/dist/client/namespaces.js +82 -28
  40. package/dist/client/namespaces.js.map +1 -1
  41. package/dist/client/place-workflows.d.ts +7 -0
  42. package/dist/client/place-workflows.d.ts.map +1 -0
  43. package/dist/client/place-workflows.js +113 -0
  44. package/dist/client/place-workflows.js.map +1 -0
  45. package/dist/finance/client.d.ts +19 -0
  46. package/dist/finance/client.d.ts.map +1 -0
  47. package/dist/finance/client.js +75 -0
  48. package/dist/finance/client.js.map +1 -0
  49. package/dist/finance/parsers.d.ts +13 -0
  50. package/dist/finance/parsers.d.ts.map +1 -0
  51. package/dist/finance/parsers.js +146 -0
  52. package/dist/finance/parsers.js.map +1 -0
  53. package/dist/finance/types.d.ts +76 -0
  54. package/dist/finance/types.d.ts.map +1 -0
  55. package/dist/finance/types.js +2 -0
  56. package/dist/finance/types.js.map +1 -0
  57. package/dist/finance.d.ts +5 -0
  58. package/dist/finance.d.ts.map +1 -0
  59. package/dist/finance.js +4 -0
  60. package/dist/finance.js.map +1 -0
  61. package/dist/flights/client.d.ts +9 -0
  62. package/dist/flights/client.d.ts.map +1 -0
  63. package/dist/flights/client.js +14 -0
  64. package/dist/flights/client.js.map +1 -0
  65. package/dist/flights/parsers.d.ts +11 -0
  66. package/dist/flights/parsers.d.ts.map +1 -0
  67. package/dist/flights/parsers.js +64 -0
  68. package/dist/flights/parsers.js.map +1 -0
  69. package/dist/flights/types.d.ts +52 -0
  70. package/dist/flights/types.d.ts.map +1 -0
  71. package/dist/flights/types.js +2 -0
  72. package/dist/flights/types.js.map +1 -0
  73. package/dist/flights.d.ts +5 -0
  74. package/dist/flights.d.ts.map +1 -0
  75. package/dist/flights.js +4 -0
  76. package/dist/flights.js.map +1 -0
  77. package/dist/gemini-web/client.d.ts +16 -0
  78. package/dist/gemini-web/client.d.ts.map +1 -0
  79. package/dist/gemini-web/client.js +110 -0
  80. package/dist/gemini-web/client.js.map +1 -0
  81. package/dist/gemini-web/parsers.d.ts +5 -0
  82. package/dist/gemini-web/parsers.d.ts.map +1 -0
  83. package/dist/gemini-web/parsers.js +62 -0
  84. package/dist/gemini-web/parsers.js.map +1 -0
  85. package/dist/gemini-web/types.d.ts +47 -0
  86. package/dist/gemini-web/types.d.ts.map +1 -0
  87. package/dist/gemini-web/types.js +2 -0
  88. package/dist/gemini-web/types.js.map +1 -0
  89. package/dist/gemini-web.d.ts +5 -0
  90. package/dist/gemini-web.d.ts.map +1 -0
  91. package/dist/gemini-web.js +4 -0
  92. package/dist/gemini-web.js.map +1 -0
  93. package/dist/google-search/client.d.ts +16 -0
  94. package/dist/google-search/client.d.ts.map +1 -0
  95. package/dist/google-search/client.js +117 -0
  96. package/dist/google-search/client.js.map +1 -0
  97. package/dist/google-search/errors.d.ts +8 -0
  98. package/dist/google-search/errors.d.ts.map +1 -0
  99. package/dist/google-search/errors.js +13 -0
  100. package/dist/google-search/errors.js.map +1 -0
  101. package/dist/google-search/html.d.ts +12 -0
  102. package/dist/google-search/html.d.ts.map +1 -0
  103. package/dist/google-search/html.js +135 -0
  104. package/dist/google-search/html.js.map +1 -0
  105. package/dist/google-search/parsers.d.ts +6 -0
  106. package/dist/google-search/parsers.d.ts.map +1 -0
  107. package/dist/google-search/parsers.js +177 -0
  108. package/dist/google-search/parsers.js.map +1 -0
  109. package/dist/google-search/types.d.ts +66 -0
  110. package/dist/google-search/types.d.ts.map +1 -0
  111. package/dist/google-search/types.js +2 -0
  112. package/dist/google-search/types.js.map +1 -0
  113. package/dist/google-search.d.ts +6 -0
  114. package/dist/google-search.d.ts.map +1 -0
  115. package/dist/google-search.js +4 -0
  116. package/dist/google-search.js.map +1 -0
  117. package/dist/hotels/client.d.ts +9 -0
  118. package/dist/hotels/client.d.ts.map +1 -0
  119. package/dist/hotels/client.js +14 -0
  120. package/dist/hotels/client.js.map +1 -0
  121. package/dist/hotels/parsers.d.ts +7 -0
  122. package/dist/hotels/parsers.d.ts.map +1 -0
  123. package/dist/hotels/parsers.js +74 -0
  124. package/dist/hotels/parsers.js.map +1 -0
  125. package/dist/hotels/types.d.ts +55 -0
  126. package/dist/hotels/types.d.ts.map +1 -0
  127. package/dist/hotels/types.js +2 -0
  128. package/dist/hotels/types.js.map +1 -0
  129. package/dist/hotels.d.ts +4 -0
  130. package/dist/hotels.d.ts.map +1 -0
  131. package/dist/hotels.js +3 -0
  132. package/dist/hotels.js.map +1 -0
  133. package/dist/index.d.ts +9 -5
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +3 -1
  136. package/dist/index.js.map +1 -1
  137. package/dist/known-surfaces.d.ts +35 -5
  138. package/dist/known-surfaces.d.ts.map +1 -1
  139. package/dist/known-surfaces.js +35 -5
  140. package/dist/known-surfaces.js.map +1 -1
  141. package/dist/lens/client.d.ts +14 -0
  142. package/dist/lens/client.d.ts.map +1 -0
  143. package/dist/lens/client.js +116 -0
  144. package/dist/lens/client.js.map +1 -0
  145. package/dist/lens/errors.d.ts +8 -0
  146. package/dist/lens/errors.d.ts.map +1 -0
  147. package/dist/lens/errors.js +13 -0
  148. package/dist/lens/errors.js.map +1 -0
  149. package/dist/lens/types.d.ts +27 -0
  150. package/dist/lens/types.d.ts.map +1 -0
  151. package/dist/lens/types.js +2 -0
  152. package/dist/lens/types.js.map +1 -0
  153. package/dist/lens.d.ts +8 -0
  154. package/dist/lens.d.ts.map +1 -0
  155. package/dist/lens.js +5 -0
  156. package/dist/lens.js.map +1 -0
  157. package/dist/news.d.ts +46 -0
  158. package/dist/news.d.ts.map +1 -0
  159. package/dist/news.js +202 -0
  160. package/dist/news.js.map +1 -0
  161. package/dist/pagespeed/client.d.ts +28 -0
  162. package/dist/pagespeed/client.d.ts.map +1 -0
  163. package/dist/pagespeed/client.js +222 -0
  164. package/dist/pagespeed/client.js.map +1 -0
  165. package/dist/pagespeed/errors.d.ts +9 -0
  166. package/dist/pagespeed/errors.d.ts.map +1 -0
  167. package/dist/pagespeed/errors.js +15 -0
  168. package/dist/pagespeed/errors.js.map +1 -0
  169. package/dist/pagespeed/parsers.d.ts +7 -0
  170. package/dist/pagespeed/parsers.d.ts.map +1 -0
  171. package/dist/pagespeed/parsers.js +236 -0
  172. package/dist/pagespeed/parsers.js.map +1 -0
  173. package/dist/pagespeed/types.d.ts +156 -0
  174. package/dist/pagespeed/types.d.ts.map +1 -0
  175. package/dist/pagespeed/types.js +2 -0
  176. package/dist/pagespeed/types.js.map +1 -0
  177. package/dist/pagespeed/wire.d.ts +10 -0
  178. package/dist/pagespeed/wire.d.ts.map +1 -0
  179. package/dist/pagespeed/wire.js +96 -0
  180. package/dist/pagespeed/wire.js.map +1 -0
  181. package/dist/pagespeed.d.ts +6 -0
  182. package/dist/pagespeed.d.ts.map +1 -0
  183. package/dist/pagespeed.js +4 -0
  184. package/dist/pagespeed.js.map +1 -0
  185. package/dist/parsers/geocode.d.ts.map +1 -1
  186. package/dist/parsers/geocode.js +30 -1
  187. package/dist/parsers/geocode.js.map +1 -1
  188. package/dist/parsers/reviews.d.ts +8 -1
  189. package/dist/parsers/reviews.d.ts.map +1 -1
  190. package/dist/parsers/reviews.js +46 -9
  191. package/dist/parsers/reviews.js.map +1 -1
  192. package/dist/platform/catalog.d.ts +18 -0
  193. package/dist/platform/catalog.d.ts.map +1 -0
  194. package/dist/platform/catalog.js +320 -0
  195. package/dist/platform/catalog.js.map +1 -0
  196. package/dist/platform/parity.d.ts +12 -0
  197. package/dist/platform/parity.d.ts.map +1 -0
  198. package/dist/platform/parity.js +25 -0
  199. package/dist/platform/parity.js.map +1 -0
  200. package/dist/services/elevation.d.ts +6 -4
  201. package/dist/services/elevation.d.ts.map +1 -1
  202. package/dist/services/elevation.js +39 -4
  203. package/dist/services/elevation.js.map +1 -1
  204. package/dist/services/environment/air-quality.d.ts +39 -0
  205. package/dist/services/environment/air-quality.d.ts.map +1 -0
  206. package/dist/services/environment/air-quality.js +82 -0
  207. package/dist/services/environment/air-quality.js.map +1 -0
  208. package/dist/services/environment/weather.d.ts +42 -0
  209. package/dist/services/environment/weather.d.ts.map +1 -0
  210. package/dist/services/environment/weather.js +63 -0
  211. package/dist/services/environment/weather.js.map +1 -0
  212. package/dist/services/geocode.d.ts +5 -1
  213. package/dist/services/geocode.d.ts.map +1 -1
  214. package/dist/services/geocode.js +13 -0
  215. package/dist/services/geocode.js.map +1 -1
  216. package/dist/services/keyed.d.ts +80 -0
  217. package/dist/services/keyed.d.ts.map +1 -0
  218. package/dist/services/keyed.js +152 -0
  219. package/dist/services/keyed.js.map +1 -0
  220. package/dist/services/knowledge.d.ts +6 -2
  221. package/dist/services/knowledge.d.ts.map +1 -1
  222. package/dist/services/knowledge.js +30 -5
  223. package/dist/services/knowledge.js.map +1 -1
  224. package/dist/services/mobility.d.ts.map +1 -1
  225. package/dist/services/mobility.js +13 -2
  226. package/dist/services/mobility.js.map +1 -1
  227. package/dist/services/nearby-search.d.ts +32 -0
  228. package/dist/services/nearby-search.d.ts.map +1 -0
  229. package/dist/services/nearby-search.js +85 -0
  230. package/dist/services/nearby-search.js.map +1 -0
  231. package/dist/services/panorama.d.ts +8 -1
  232. package/dist/services/panorama.d.ts.map +1 -1
  233. package/dist/services/panorama.js +48 -0
  234. package/dist/services/panorama.js.map +1 -1
  235. package/dist/services/photos.d.ts.map +1 -1
  236. package/dist/services/photos.js +9 -2
  237. package/dist/services/photos.js.map +1 -1
  238. package/dist/services/places.d.ts.map +1 -1
  239. package/dist/services/places.js +1 -0
  240. package/dist/services/places.js.map +1 -1
  241. package/dist/services/reviews.d.ts.map +1 -1
  242. package/dist/services/reviews.js +4 -1
  243. package/dist/services/reviews.js.map +1 -1
  244. package/dist/services/search.d.ts +8 -3
  245. package/dist/services/search.d.ts.map +1 -1
  246. package/dist/services/search.js +28 -9
  247. package/dist/services/search.js.map +1 -1
  248. package/dist/translate.d.ts +75 -0
  249. package/dist/translate.d.ts.map +1 -0
  250. package/dist/translate.js +126 -0
  251. package/dist/translate.js.map +1 -0
  252. package/dist/travel-google/common.d.ts +24 -0
  253. package/dist/travel-google/common.d.ts.map +1 -0
  254. package/dist/travel-google/common.js +72 -0
  255. package/dist/travel-google/common.js.map +1 -0
  256. package/dist/trends/client.d.ts +17 -0
  257. package/dist/trends/client.d.ts.map +1 -0
  258. package/dist/trends/client.js +86 -0
  259. package/dist/trends/client.js.map +1 -0
  260. package/dist/trends/errors.d.ts +8 -0
  261. package/dist/trends/errors.d.ts.map +1 -0
  262. package/dist/trends/errors.js +13 -0
  263. package/dist/trends/errors.js.map +1 -0
  264. package/dist/trends/links.d.ts +8 -0
  265. package/dist/trends/links.d.ts.map +1 -0
  266. package/dist/trends/links.js +71 -0
  267. package/dist/trends/links.js.map +1 -0
  268. package/dist/trends/parsers.d.ts +5 -0
  269. package/dist/trends/parsers.d.ts.map +1 -0
  270. package/dist/trends/parsers.js +126 -0
  271. package/dist/trends/parsers.js.map +1 -0
  272. package/dist/trends/types.d.ts +71 -0
  273. package/dist/trends/types.d.ts.map +1 -0
  274. package/dist/trends/types.js +2 -0
  275. package/dist/trends/types.js.map +1 -0
  276. package/dist/trends.d.ts +9 -0
  277. package/dist/trends.d.ts.map +1 -0
  278. package/dist/trends.js +8 -0
  279. package/dist/trends.js.map +1 -0
  280. package/dist/types/common.d.ts +28 -2
  281. package/dist/types/common.d.ts.map +1 -1
  282. package/dist/types/common.js.map +1 -1
  283. package/dist/types/directions.d.ts +1 -1
  284. package/dist/types/directions.d.ts.map +1 -1
  285. package/dist/types/dx.d.ts +23 -10
  286. package/dist/types/dx.d.ts.map +1 -1
  287. package/dist/types/panorama.d.ts +19 -0
  288. package/dist/types/panorama.d.ts.map +1 -1
  289. package/dist/types/reviews.d.ts +3 -4
  290. package/dist/types/reviews.d.ts.map +1 -1
  291. package/dist/types/suggest.d.ts +4 -6
  292. package/dist/types/suggest.d.ts.map +1 -1
  293. package/dist/utils/google-web.d.ts +24 -0
  294. package/dist/utils/google-web.d.ts.map +1 -0
  295. package/dist/utils/google-web.js +150 -0
  296. package/dist/utils/google-web.js.map +1 -0
  297. package/dist/utils/place-ref.d.ts +14 -4
  298. package/dist/utils/place-ref.d.ts.map +1 -1
  299. package/dist/utils/place-ref.js +49 -1
  300. package/dist/utils/place-ref.js.map +1 -1
  301. package/dist/youtube/client.d.ts +19 -0
  302. package/dist/youtube/client.d.ts.map +1 -0
  303. package/dist/youtube/client.js +115 -0
  304. package/dist/youtube/client.js.map +1 -0
  305. package/dist/youtube/errors.d.ts +8 -0
  306. package/dist/youtube/errors.d.ts.map +1 -0
  307. package/dist/youtube/errors.js +13 -0
  308. package/dist/youtube/errors.js.map +1 -0
  309. package/dist/youtube/parsers.d.ts +9 -0
  310. package/dist/youtube/parsers.d.ts.map +1 -0
  311. package/dist/youtube/parsers.js +213 -0
  312. package/dist/youtube/parsers.js.map +1 -0
  313. package/dist/youtube/types.d.ts +90 -0
  314. package/dist/youtube/types.d.ts.map +1 -0
  315. package/dist/youtube/types.js +2 -0
  316. package/dist/youtube/types.js.map +1 -0
  317. package/dist/youtube.d.ts +9 -0
  318. package/dist/youtube.d.ts.map +1 -0
  319. package/dist/youtube.js +6 -0
  320. package/dist/youtube.js.map +1 -0
  321. package/docs/books.md +18 -0
  322. package/docs/environment-research.md +65 -0
  323. package/docs/finance-research.md +153 -0
  324. package/docs/finance.md +43 -0
  325. package/docs/gemini-web.md +36 -0
  326. package/docs/google-ai-books-research.md +53 -0
  327. package/docs/google-media-research.md +105 -0
  328. package/docs/google-search-research.md +36 -0
  329. package/docs/google-search.md +53 -0
  330. package/docs/google-services-research.md +135 -0
  331. package/docs/google-travel-research.md +86 -0
  332. package/docs/internal/reverse-engineering.md +85 -0
  333. package/docs/lens.md +54 -0
  334. package/docs/maps-revalidation.md +31 -0
  335. package/docs/news.md +35 -0
  336. package/docs/pagespeed-research.md +153 -0
  337. package/docs/pagespeed.md +135 -0
  338. package/docs/reviews-research.md +33 -0
  339. package/docs/translate.md +78 -0
  340. package/docs/trends-research.md +82 -0
  341. package/docs/trends.md +75 -0
  342. package/docs/youtube.md +72 -0
  343. 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`.