@mailwoman/resolver-wof-sqlite 10.0.0 → 10.2.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 (477) hide show
  1. package/README.md +9 -8
  2. package/lib/address/point/interpolation.ts +45 -39
  3. package/lib/address/point/schema.ts +17 -40
  4. package/lib/address/point.ts +316 -0
  5. package/lib/{address/index.ts → address.ts} +1 -1
  6. package/lib/ancestry/backfill.ts +20 -86
  7. package/lib/{ancestry/index.ts → ancestry.ts} +19 -15
  8. package/lib/build/candidate.ts +122 -174
  9. package/lib/build/population-corrections.ts +64 -0
  10. package/lib/build/slim.ts +44 -114
  11. package/lib/candidate/alias-bags.ts +16 -17
  12. package/lib/candidate/ancestors/schema.ts +77 -61
  13. package/lib/candidate/ancestors/sidecar.ts +15 -22
  14. package/lib/candidate/country-display-names.ts +6 -20
  15. package/lib/candidate/extract-fold.ts +10 -55
  16. package/lib/candidate/fts.ts +5 -23
  17. package/lib/candidate/importance.ts +65 -68
  18. package/lib/candidate/lookup.ts +124 -415
  19. package/lib/candidate/name-roles.ts +15 -33
  20. package/lib/candidate/own-name.ts +35 -32
  21. package/lib/candidate/place-attrs.ts +20 -13
  22. package/lib/candidate/schema.ts +29 -65
  23. package/lib/candidate/scoring.ts +54 -93
  24. package/lib/capital-schema.ts +21 -17
  25. package/lib/capitals.ts +29 -27
  26. package/lib/coincident-roles.ts +85 -55
  27. package/lib/convention/schema.ts +15 -16
  28. package/lib/convention.ts +144 -0
  29. package/lib/coverage-manifest-schema.ts +40 -45
  30. package/lib/currency-backfill.ts +34 -79
  31. package/lib/env.ts +1 -1
  32. package/lib/exact-match.ts +32 -21
  33. package/lib/extracts.ts +97 -74
  34. package/lib/fst/autocomplete.ts +54 -37
  35. package/lib/fst/builder.ts +37 -41
  36. package/lib/fst/deserialize-web.ts +16 -17
  37. package/lib/fst/format.ts +41 -23
  38. package/lib/fst/freshness.ts +43 -120
  39. package/lib/fst/matcher.ts +7 -5
  40. package/lib/fst/serialize.ts +54 -74
  41. package/lib/fst/types.ts +78 -75
  42. package/lib/{fst/index.ts → fst.ts} +1 -0
  43. package/lib/fts/query.ts +5 -36
  44. package/lib/fts.ts +280 -0
  45. package/lib/geonames/aliases.ts +73 -144
  46. package/lib/geonames/postal.ts +162 -71
  47. package/lib/index.ts +9 -8
  48. package/lib/interpolation.ts +48 -100
  49. package/lib/lookup.ts +155 -270
  50. package/lib/name-score.ts +9 -7
  51. package/lib/nsul/lookup.ts +37 -54
  52. package/lib/nsul/schema.ts +16 -43
  53. package/lib/paths.ts +159 -0
  54. package/lib/place-importance-schema.ts +62 -169
  55. package/lib/poi/lookup.ts +104 -121
  56. package/lib/poi/schema.ts +42 -26
  57. package/lib/polygon-schema.ts +10 -6
  58. package/lib/postal/city/alias/lookup.ts +22 -40
  59. package/lib/postal/city/alias/schema.ts +14 -10
  60. package/lib/postal/city/candidate-schema.ts +26 -20
  61. package/lib/postcode-point-lookup.ts +8 -27
  62. package/lib/primary-preference.ts +46 -126
  63. package/lib/proximity-rerank.ts +44 -33
  64. package/lib/ranking-weights.ts +105 -78
  65. package/lib/region-keys.ts +70 -42
  66. package/lib/reverse.ts +149 -86
  67. package/lib/schema.ts +73 -50
  68. package/lib/search-fetch.ts +90 -68
  69. package/lib/sqlite/convention-source.ts +15 -23
  70. package/lib/sqlite/utils.ts +19 -22
  71. package/lib/street/centroid/schema.ts +37 -42
  72. package/lib/street/{centroid/index.ts → centroid.ts} +16 -25
  73. package/lib/street/morphology/fst/builder.ts +60 -42
  74. package/lib/street/morphology/fst/loader.ts +40 -32
  75. package/lib/street/name-lookup.ts +45 -41
  76. package/lib/street/normalize.ts +88 -219
  77. package/lib/street/segment-schema.ts +116 -43
  78. package/lib/{street/index.ts → street.ts} +1 -1
  79. package/lib/types.ts +109 -150
  80. package/lib/unified-schema.ts +29 -29
  81. package/lib/uprn/existence.ts +30 -19
  82. package/lib/uprn/lookup.ts +29 -68
  83. package/lib/uprn/schema.ts +18 -40
  84. package/lib/weights-overlay-linker.ts +236 -252
  85. package/out/address/point/interpolation.d.ts +20 -23
  86. package/out/address/point/interpolation.d.ts.map +1 -1
  87. package/out/address/point/interpolation.js +42 -39
  88. package/out/address/point/interpolation.js.map +1 -1
  89. package/out/address/point/schema.d.ts +12 -35
  90. package/out/address/point/schema.d.ts.map +1 -1
  91. package/out/address/point/schema.js +3 -19
  92. package/out/address/point/schema.js.map +1 -1
  93. package/out/address/point.d.ts +57 -0
  94. package/out/address/point.d.ts.map +1 -0
  95. package/out/address/point.js +206 -0
  96. package/out/address/point.js.map +1 -0
  97. package/out/{address/index.js → address.d.ts} +2 -2
  98. package/out/address.d.ts.map +1 -0
  99. package/out/{address/index.d.ts → address.js} +2 -2
  100. package/out/address.js.map +1 -0
  101. package/out/ancestry/backfill.d.ts +11 -64
  102. package/out/ancestry/backfill.d.ts.map +1 -1
  103. package/out/ancestry/backfill.js +14 -74
  104. package/out/ancestry/backfill.js.map +1 -1
  105. package/out/ancestry.d.ts +49 -0
  106. package/out/ancestry.d.ts.map +1 -0
  107. package/out/ancestry.js +59 -0
  108. package/out/ancestry.js.map +1 -0
  109. package/out/build/candidate.d.ts +82 -112
  110. package/out/build/candidate.d.ts.map +1 -1
  111. package/out/build/candidate.js +17 -100
  112. package/out/build/candidate.js.map +1 -1
  113. package/out/build/population-corrections.d.ts +52 -0
  114. package/out/build/population-corrections.d.ts.map +1 -0
  115. package/out/build/population-corrections.js +40 -0
  116. package/out/build/population-corrections.js.map +1 -0
  117. package/out/build/slim.d.ts +8 -44
  118. package/out/build/slim.d.ts.map +1 -1
  119. package/out/build/slim.js +33 -94
  120. package/out/build/slim.js.map +1 -1
  121. package/out/candidate/alias-bags.d.ts +6 -6
  122. package/out/candidate/alias-bags.d.ts.map +1 -1
  123. package/out/candidate/alias-bags.js +16 -17
  124. package/out/candidate/alias-bags.js.map +1 -1
  125. package/out/candidate/ancestors/schema.d.ts +73 -57
  126. package/out/candidate/ancestors/schema.d.ts.map +1 -1
  127. package/out/candidate/ancestors/schema.js +56 -48
  128. package/out/candidate/ancestors/schema.js.map +1 -1
  129. package/out/candidate/ancestors/sidecar.d.ts +3 -8
  130. package/out/candidate/ancestors/sidecar.d.ts.map +1 -1
  131. package/out/candidate/ancestors/sidecar.js +15 -22
  132. package/out/candidate/ancestors/sidecar.js.map +1 -1
  133. package/out/candidate/country-display-names.d.ts +5 -15
  134. package/out/candidate/country-display-names.d.ts.map +1 -1
  135. package/out/candidate/country-display-names.js +6 -20
  136. package/out/candidate/country-display-names.js.map +1 -1
  137. package/out/candidate/extract-fold.d.ts +7 -15
  138. package/out/candidate/extract-fold.d.ts.map +1 -1
  139. package/out/candidate/extract-fold.js +5 -47
  140. package/out/candidate/extract-fold.js.map +1 -1
  141. package/out/candidate/fts.d.ts +5 -23
  142. package/out/candidate/fts.d.ts.map +1 -1
  143. package/out/candidate/fts.js +5 -23
  144. package/out/candidate/fts.js.map +1 -1
  145. package/out/candidate/importance.d.ts +60 -65
  146. package/out/candidate/importance.d.ts.map +1 -1
  147. package/out/candidate/importance.js +56 -63
  148. package/out/candidate/importance.js.map +1 -1
  149. package/out/candidate/lookup.d.ts +18 -55
  150. package/out/candidate/lookup.d.ts.map +1 -1
  151. package/out/candidate/lookup.js +82 -385
  152. package/out/candidate/lookup.js.map +1 -1
  153. package/out/candidate/name-roles.d.ts +9 -21
  154. package/out/candidate/name-roles.d.ts.map +1 -1
  155. package/out/candidate/name-roles.js +15 -33
  156. package/out/candidate/name-roles.js.map +1 -1
  157. package/out/candidate/own-name.d.ts +23 -25
  158. package/out/candidate/own-name.d.ts.map +1 -1
  159. package/out/candidate/own-name.js +35 -32
  160. package/out/candidate/own-name.js.map +1 -1
  161. package/out/candidate/place-attrs.d.ts +20 -13
  162. package/out/candidate/place-attrs.d.ts.map +1 -1
  163. package/out/candidate/place-attrs.js +4 -5
  164. package/out/candidate/place-attrs.js.map +1 -1
  165. package/out/candidate/schema.d.ts +27 -62
  166. package/out/candidate/schema.d.ts.map +1 -1
  167. package/out/candidate/schema.js +10 -22
  168. package/out/candidate/schema.js.map +1 -1
  169. package/out/candidate/scoring.d.ts +7 -8
  170. package/out/candidate/scoring.d.ts.map +1 -1
  171. package/out/candidate/scoring.js +52 -89
  172. package/out/candidate/scoring.js.map +1 -1
  173. package/out/capital-schema.d.ts +21 -17
  174. package/out/capital-schema.d.ts.map +1 -1
  175. package/out/capital-schema.js +17 -15
  176. package/out/capital-schema.js.map +1 -1
  177. package/out/capitals.d.ts +27 -25
  178. package/out/capitals.d.ts.map +1 -1
  179. package/out/capitals.js +23 -21
  180. package/out/capitals.js.map +1 -1
  181. package/out/coincident-roles.d.ts +60 -43
  182. package/out/coincident-roles.d.ts.map +1 -1
  183. package/out/coincident-roles.js +72 -50
  184. package/out/coincident-roles.js.map +1 -1
  185. package/out/convention/schema.d.ts +14 -14
  186. package/out/convention/schema.d.ts.map +1 -1
  187. package/out/convention/schema.js +6 -4
  188. package/out/convention/schema.js.map +1 -1
  189. package/out/convention.d.ts +97 -0
  190. package/out/convention.d.ts.map +1 -0
  191. package/out/convention.js +81 -0
  192. package/out/convention.js.map +1 -0
  193. package/out/coverage-manifest-schema.d.ts +34 -39
  194. package/out/coverage-manifest-schema.d.ts.map +1 -1
  195. package/out/coverage-manifest-schema.js +25 -34
  196. package/out/coverage-manifest-schema.js.map +1 -1
  197. package/out/currency-backfill.d.ts +16 -38
  198. package/out/currency-backfill.d.ts.map +1 -1
  199. package/out/currency-backfill.js +19 -46
  200. package/out/currency-backfill.js.map +1 -1
  201. package/out/env.d.ts +1 -1
  202. package/out/env.js +1 -1
  203. package/out/exact-match.d.ts +19 -10
  204. package/out/exact-match.d.ts.map +1 -1
  205. package/out/exact-match.js +32 -21
  206. package/out/exact-match.js.map +1 -1
  207. package/out/extracts.d.ts +66 -55
  208. package/out/extracts.d.ts.map +1 -1
  209. package/out/extracts.js +63 -55
  210. package/out/extracts.js.map +1 -1
  211. package/out/fst/autocomplete.d.ts +29 -21
  212. package/out/fst/autocomplete.d.ts.map +1 -1
  213. package/out/fst/autocomplete.js +39 -28
  214. package/out/fst/autocomplete.js.map +1 -1
  215. package/out/fst/builder.d.ts.map +1 -1
  216. package/out/fst/builder.js +37 -41
  217. package/out/fst/builder.js.map +1 -1
  218. package/out/fst/deserialize-web.d.ts +4 -4
  219. package/out/fst/deserialize-web.d.ts.map +1 -1
  220. package/out/fst/deserialize-web.js +15 -16
  221. package/out/fst/deserialize-web.js.map +1 -1
  222. package/out/fst/format.d.ts +41 -23
  223. package/out/fst/format.d.ts.map +1 -1
  224. package/out/fst/format.js +41 -23
  225. package/out/fst/format.js.map +1 -1
  226. package/out/fst/freshness.d.ts +19 -81
  227. package/out/fst/freshness.d.ts.map +1 -1
  228. package/out/fst/freshness.js +31 -94
  229. package/out/fst/freshness.js.map +1 -1
  230. package/out/fst/matcher.d.ts +5 -4
  231. package/out/fst/matcher.d.ts.map +1 -1
  232. package/out/fst/matcher.js +2 -2
  233. package/out/fst/matcher.js.map +1 -1
  234. package/out/fst/serialize.d.ts +28 -28
  235. package/out/fst/serialize.d.ts.map +1 -1
  236. package/out/fst/serialize.js +53 -71
  237. package/out/fst/serialize.js.map +1 -1
  238. package/out/fst/types.d.ts +78 -74
  239. package/out/fst/types.d.ts.map +1 -1
  240. package/out/fst/types.js +1 -4
  241. package/out/fst/types.js.map +1 -1
  242. package/out/{fst/index.js → fst.d.ts} +2 -1
  243. package/out/fst.d.ts.map +1 -0
  244. package/out/{fst/index.d.ts → fst.js} +2 -1
  245. package/out/fst.js.map +1 -0
  246. package/out/fts/query.d.ts +2 -27
  247. package/out/fts/query.d.ts.map +1 -1
  248. package/out/fts/query.js +5 -36
  249. package/out/fts/query.js.map +1 -1
  250. package/out/fts.d.ts +126 -0
  251. package/out/fts.d.ts.map +1 -0
  252. package/out/fts.js +188 -0
  253. package/out/fts.js.map +1 -0
  254. package/out/geonames/aliases.d.ts +26 -62
  255. package/out/geonames/aliases.d.ts.map +1 -1
  256. package/out/geonames/aliases.js +45 -117
  257. package/out/geonames/aliases.js.map +1 -1
  258. package/out/geonames/postal.d.ts +84 -44
  259. package/out/geonames/postal.d.ts.map +1 -1
  260. package/out/geonames/postal.js +115 -73
  261. package/out/geonames/postal.js.map +1 -1
  262. package/out/{geonames/index.js → geonames.d.ts} +1 -1
  263. package/out/geonames.d.ts.map +1 -0
  264. package/out/{geonames/index.d.ts → geonames.js} +1 -1
  265. package/out/geonames.js.map +1 -0
  266. package/out/index.d.ts +9 -8
  267. package/out/index.d.ts.map +1 -1
  268. package/out/index.js +6 -5
  269. package/out/index.js.map +1 -1
  270. package/out/interpolation.d.ts +18 -55
  271. package/out/interpolation.d.ts.map +1 -1
  272. package/out/interpolation.js +27 -69
  273. package/out/interpolation.js.map +1 -1
  274. package/out/lookup.d.ts +23 -51
  275. package/out/lookup.d.ts.map +1 -1
  276. package/out/lookup.js +136 -234
  277. package/out/lookup.js.map +1 -1
  278. package/out/name-score.d.ts +2 -2
  279. package/out/name-score.d.ts.map +1 -1
  280. package/out/name-score.js +9 -7
  281. package/out/name-score.js.map +1 -1
  282. package/out/nsul/lookup.d.ts +33 -34
  283. package/out/nsul/lookup.d.ts.map +1 -1
  284. package/out/nsul/lookup.js +26 -40
  285. package/out/nsul/lookup.js.map +1 -1
  286. package/out/nsul/schema.d.ts +16 -43
  287. package/out/nsul/schema.d.ts.map +1 -1
  288. package/out/nsul/schema.js +9 -35
  289. package/out/nsul/schema.js.map +1 -1
  290. package/out/{nsul/index.d.ts → nsul.d.ts} +1 -1
  291. package/out/nsul.d.ts.map +1 -0
  292. package/out/{nsul/index.js → nsul.js} +1 -1
  293. package/out/nsul.js.map +1 -0
  294. package/out/paths.d.ts +124 -0
  295. package/out/paths.d.ts.map +1 -0
  296. package/out/paths.js +104 -0
  297. package/out/paths.js.map +1 -0
  298. package/out/place-importance-schema.d.ts +51 -143
  299. package/out/place-importance-schema.d.ts.map +1 -1
  300. package/out/place-importance-schema.js +28 -143
  301. package/out/place-importance-schema.js.map +1 -1
  302. package/out/poi/lookup.d.ts +40 -47
  303. package/out/poi/lookup.d.ts.map +1 -1
  304. package/out/poi/lookup.js +69 -96
  305. package/out/poi/lookup.js.map +1 -1
  306. package/out/poi/schema.d.ts +41 -25
  307. package/out/poi/schema.d.ts.map +1 -1
  308. package/out/poi/schema.js +25 -17
  309. package/out/poi/schema.js.map +1 -1
  310. package/out/{poi/index.js → poi.d.ts} +1 -1
  311. package/out/poi.d.ts.map +1 -0
  312. package/out/{poi/index.d.ts → poi.js} +1 -1
  313. package/out/poi.js.map +1 -0
  314. package/out/polygon-schema.d.ts +10 -6
  315. package/out/polygon-schema.d.ts.map +1 -1
  316. package/out/polygon-schema.js +2 -2
  317. package/out/polygon-schema.js.map +1 -1
  318. package/out/postal/city/alias/lookup.d.ts +20 -23
  319. package/out/postal/city/alias/lookup.d.ts.map +1 -1
  320. package/out/postal/city/alias/lookup.js +17 -30
  321. package/out/postal/city/alias/lookup.js.map +1 -1
  322. package/out/postal/city/alias/schema.d.ts +14 -10
  323. package/out/postal/city/alias/schema.d.ts.map +1 -1
  324. package/out/postal/city/alias/schema.js +10 -8
  325. package/out/postal/city/alias/schema.js.map +1 -1
  326. package/out/postal/city/candidate-schema.d.ts +25 -19
  327. package/out/postal/city/candidate-schema.d.ts.map +1 -1
  328. package/out/postal/city/candidate-schema.js +21 -17
  329. package/out/postal/city/candidate-schema.js.map +1 -1
  330. package/out/{postal/index.d.ts → postal.d.ts} +1 -1
  331. package/out/postal.d.ts.map +1 -0
  332. package/out/{postal/index.js → postal.js} +1 -1
  333. package/out/postal.js.map +1 -0
  334. package/out/postcode-point-lookup.d.ts +6 -24
  335. package/out/postcode-point-lookup.d.ts.map +1 -1
  336. package/out/postcode-point-lookup.js +5 -17
  337. package/out/postcode-point-lookup.js.map +1 -1
  338. package/out/primary-preference.d.ts +38 -92
  339. package/out/primary-preference.d.ts.map +1 -1
  340. package/out/primary-preference.js +15 -99
  341. package/out/primary-preference.js.map +1 -1
  342. package/out/proximity-rerank.d.ts +41 -30
  343. package/out/proximity-rerank.d.ts.map +1 -1
  344. package/out/proximity-rerank.js +38 -29
  345. package/out/proximity-rerank.js.map +1 -1
  346. package/out/ranking-weights.d.ts +98 -64
  347. package/out/ranking-weights.d.ts.map +1 -1
  348. package/out/ranking-weights.js +26 -25
  349. package/out/ranking-weights.js.map +1 -1
  350. package/out/region-keys.d.ts +50 -31
  351. package/out/region-keys.d.ts.map +1 -1
  352. package/out/region-keys.js +68 -40
  353. package/out/region-keys.js.map +1 -1
  354. package/out/reverse.d.ts +78 -50
  355. package/out/reverse.d.ts.map +1 -1
  356. package/out/reverse.js +98 -61
  357. package/out/reverse.js.map +1 -1
  358. package/out/schema.d.ts +72 -49
  359. package/out/schema.d.ts.map +1 -1
  360. package/out/schema.js +4 -5
  361. package/out/schema.js.map +1 -1
  362. package/out/search-fetch.d.ts +16 -12
  363. package/out/search-fetch.d.ts.map +1 -1
  364. package/out/search-fetch.js +83 -63
  365. package/out/search-fetch.js.map +1 -1
  366. package/out/sqlite/convention-source.d.ts +12 -16
  367. package/out/sqlite/convention-source.d.ts.map +1 -1
  368. package/out/sqlite/convention-source.js +13 -22
  369. package/out/sqlite/convention-source.js.map +1 -1
  370. package/out/sqlite/utils.d.ts +19 -19
  371. package/out/sqlite/utils.d.ts.map +1 -1
  372. package/out/sqlite/utils.js +14 -15
  373. package/out/sqlite/utils.js.map +1 -1
  374. package/out/street/centroid/schema.d.ts +37 -42
  375. package/out/street/centroid/schema.d.ts.map +1 -1
  376. package/out/street/centroid/schema.js +9 -21
  377. package/out/street/centroid/schema.js.map +1 -1
  378. package/out/street/centroid.d.ts +30 -0
  379. package/out/street/centroid.d.ts.map +1 -0
  380. package/out/street/{centroid/index.js → centroid.js} +13 -24
  381. package/out/street/centroid.js.map +1 -0
  382. package/out/street/morphology/fst/builder.d.ts +20 -10
  383. package/out/street/morphology/fst/builder.d.ts.map +1 -1
  384. package/out/street/morphology/fst/builder.js +44 -34
  385. package/out/street/morphology/fst/builder.js.map +1 -1
  386. package/out/street/morphology/fst/loader.d.ts +33 -26
  387. package/out/street/morphology/fst/loader.d.ts.map +1 -1
  388. package/out/street/morphology/fst/loader.js +23 -22
  389. package/out/street/morphology/fst/loader.js.map +1 -1
  390. package/out/street/name-lookup.d.ts +24 -18
  391. package/out/street/name-lookup.d.ts.map +1 -1
  392. package/out/street/name-lookup.js +34 -35
  393. package/out/street/name-lookup.js.map +1 -1
  394. package/out/street/normalize.d.ts +35 -136
  395. package/out/street/normalize.d.ts.map +1 -1
  396. package/out/street/normalize.js +77 -194
  397. package/out/street/normalize.js.map +1 -1
  398. package/out/street/segment-schema.d.ts +79 -39
  399. package/out/street/segment-schema.d.ts.map +1 -1
  400. package/out/street/segment-schema.js +71 -21
  401. package/out/street/segment-schema.js.map +1 -1
  402. package/out/{street/index.js → street.d.ts} +2 -2
  403. package/out/street.d.ts.map +1 -0
  404. package/out/{street/index.d.ts → street.js} +2 -2
  405. package/out/street.js.map +1 -0
  406. package/out/types.d.ts +84 -149
  407. package/out/types.d.ts.map +1 -1
  408. package/out/types.js +0 -6
  409. package/out/types.js.map +1 -1
  410. package/out/unified-schema.d.ts +8 -12
  411. package/out/unified-schema.d.ts.map +1 -1
  412. package/out/unified-schema.js +29 -29
  413. package/out/unified-schema.js.map +1 -1
  414. package/out/uprn/existence.d.ts +28 -17
  415. package/out/uprn/existence.d.ts.map +1 -1
  416. package/out/uprn/existence.js +26 -16
  417. package/out/uprn/existence.js.map +1 -1
  418. package/out/uprn/lookup.d.ts +14 -44
  419. package/out/uprn/lookup.d.ts.map +1 -1
  420. package/out/uprn/lookup.js +21 -57
  421. package/out/uprn/lookup.js.map +1 -1
  422. package/out/uprn/schema.d.ts +18 -40
  423. package/out/uprn/schema.d.ts.map +1 -1
  424. package/out/uprn/schema.js +10 -32
  425. package/out/uprn/schema.js.map +1 -1
  426. package/out/{uprn/index.d.ts → uprn.d.ts} +1 -1
  427. package/out/uprn.d.ts.map +1 -0
  428. package/out/{uprn/index.js → uprn.js} +1 -1
  429. package/out/uprn.js.map +1 -0
  430. package/out/weights-overlay-linker.d.ts +138 -144
  431. package/out/weights-overlay-linker.d.ts.map +1 -1
  432. package/out/weights-overlay-linker.js +105 -159
  433. package/out/weights-overlay-linker.js.map +1 -1
  434. package/package.json +91 -596
  435. package/lib/address/point/index.ts +0 -328
  436. package/lib/convention/index.ts +0 -154
  437. package/lib/fts/index.ts +0 -361
  438. package/out/address/index.d.ts.map +0 -1
  439. package/out/address/index.js.map +0 -1
  440. package/out/address/point/index.d.ts +0 -53
  441. package/out/address/point/index.d.ts.map +0 -1
  442. package/out/address/point/index.js +0 -222
  443. package/out/address/point/index.js.map +0 -1
  444. package/out/ancestry/index.d.ts +0 -45
  445. package/out/ancestry/index.d.ts.map +0 -1
  446. package/out/ancestry/index.js +0 -55
  447. package/out/ancestry/index.js.map +0 -1
  448. package/out/convention/index.d.ts +0 -106
  449. package/out/convention/index.d.ts.map +0 -1
  450. package/out/convention/index.js +0 -93
  451. package/out/convention/index.js.map +0 -1
  452. package/out/fst/index.d.ts.map +0 -1
  453. package/out/fst/index.js.map +0 -1
  454. package/out/fts/index.d.ts +0 -184
  455. package/out/fts/index.d.ts.map +0 -1
  456. package/out/fts/index.js +0 -277
  457. package/out/fts/index.js.map +0 -1
  458. package/out/geonames/index.d.ts.map +0 -1
  459. package/out/geonames/index.js.map +0 -1
  460. package/out/nsul/index.d.ts.map +0 -1
  461. package/out/nsul/index.js.map +0 -1
  462. package/out/poi/index.d.ts.map +0 -1
  463. package/out/poi/index.js.map +0 -1
  464. package/out/postal/index.d.ts.map +0 -1
  465. package/out/postal/index.js.map +0 -1
  466. package/out/street/centroid/index.d.ts +0 -40
  467. package/out/street/centroid/index.d.ts.map +0 -1
  468. package/out/street/centroid/index.js.map +0 -1
  469. package/out/street/index.d.ts.map +0 -1
  470. package/out/street/index.js.map +0 -1
  471. package/out/uprn/index.d.ts.map +0 -1
  472. package/out/uprn/index.js.map +0 -1
  473. /package/lib/{geonames/index.ts → geonames.ts} +0 -0
  474. /package/lib/{nsul/index.ts → nsul.ts} +0 -0
  475. /package/lib/{poi/index.ts → poi.ts} +0 -0
  476. /package/lib/{postal/index.ts → postal.ts} +0 -0
  477. /package/lib/{uprn/index.ts → uprn.ts} +0 -0
@@ -3,13 +3,11 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * Schema for the unified WOF SQLite database we build from cloned WOF GeoJSON repos
7
- * (`scripts/build-unified-wof.ts`). This is the CANONICAL gazetteer — we never use the
8
- * off-the-shelf geocode.earth prebuilt dumps (they assign different WOF ids to the same place;
9
- * see the `feedback-custom-wof-db-only` memory). The table/column names match the resolver's
10
- * expectations (`lookup.ts`) so `WOFSQLitePlaceLookup` works unchanged, INCLUDING the `ancestors`
11
- * table (which lookup.ts's parent-constraint subquery needs) — see `populateAncestors`. The
12
- * `place_search` FTS5 + `place_bbox` R*Tree are built separately by `build-fts` (fts.ts).
6
+ * Schema for the unified WOF SQLite database built from cloned WOF GeoJSON repos
7
+ * (`scripts/build-unified-wof.ts`). The table and column names match the resolver's
8
+ * expectations (`lookup.ts`) so `WOFSQLitePlaceLookup` works unchanged. The `ancestors` table
9
+ * table is what lookup.ts's parent-constraint subquery reads (see `populateAncestors`).
10
+ * The `place_search` FTS5 and `place_bbox` R*Tree tables are built separately by `build-fts` (fts.ts).
13
11
  */
14
12
 
15
13
  import type { DatabaseClient } from "@mailwoman/sqlite/client"
@@ -17,13 +15,14 @@ import type { DatabaseClient } from "@mailwoman/sqlite/client"
17
15
  import type { WOFDatabase } from "#schema"
18
16
 
19
17
  export async function createUnifiedSchema(db: DatabaseClient<WOFDatabase>): Promise<void> {
20
- // PRAGMAs stay raw — not Kysely-modelled, and these tune the bulk build.
18
+ // PRAGMAs run raw because Kysely does not model them.
19
+ // They tune the bulk build.
21
20
  db.exec("PRAGMA journal_mode = WAL")
22
21
  db.exec("PRAGMA busy_timeout = 10000")
23
22
  db.exec("PRAGMA synchronous = OFF")
24
23
 
25
- // `db` wraps `db` for the DDL (the house idiom); the caller owns `db`'s lifecycle, so we don't
26
- // destroy it here. The bulk INSERTs (populateAncestors + build-unified-wof) stay on the raw handle.
24
+ // The caller owns `db`'s lifecycle, so this function does not destroy it.
25
+ // The bulk INSERTs (populateAncestors + build-unified-wof) run on the raw handle.
27
26
 
28
27
  await db.schema
29
28
  .createTable("spr")
@@ -47,12 +46,16 @@ export async function createUnifiedSchema(db: DatabaseClient<WOFDatabase>): Prom
47
46
  .addColumn("lastmodified", "integer", (c) => c.notNull().defaultTo(0))
48
47
  .execute()
49
48
 
50
- // `privateuse` carries WOF's x_<variant> kind (preferred | variant) / GeoNames' isPreferredName
51
- // ("preferred" | ""). `official` is the #936 ingest bit: 1 when the row's language is an official
52
- // language of the place's country (codex OFFICIAL_LANGUAGES) AND the row is a preferred form —
53
- // x_variant rows tagged with an official language ("MSP", "Frisco") stay 0. Primary-name mirror
54
- // rows stay 0 too: the name-exact tier already consults spr.name; `official` only marks the
55
- // ALIASES eligible to join it. Both are ingest-time facts, never computed at query time.
49
+ // `privateuse` represents WOF's x_<variant> kind (preferred | variant) or GeoNames'
50
+ // isPreferredName ("preferred" | "").
51
+ // `official` is the ingest bit.
52
+ // It is 1 when the row's language is an official language of the place's country
53
+ // (codex OFFICIAL_LANGUAGES) and the row is a preferred form. x_variant rows
54
+ // tagged with an official language ("MSP", "Frisco") stay 0.
55
+ // Primary-name mirror rows stay 0 too.
56
+ // The name-exact tier already consults spr.name.
57
+ // `official` only marks the aliases eligible to join it.
58
+ // Both are ingest-time facts, never computed at query time.
56
59
  await db.schema
57
60
  .createTable("names")
58
61
  .ifNotExists()
@@ -82,11 +85,12 @@ export async function createUnifiedSchema(db: DatabaseClient<WOFDatabase>): Prom
82
85
  .addColumn("population", "integer", (c) => c.notNull().defaultTo(0))
83
86
  .execute()
84
87
 
85
- // `ancestors` maps each place to every place above it in the hierarchy (and itself). The
86
- // resolver's parent-constraint scopes a child lookup to a parent's descendants via
87
- // `spr.id IN (SELECT id FROM ancestors WHERE ancestor_id = ?)`. The off-the-shelf WOF dumps
88
- // ship this table; our build derives it from the parent_id chain (see populateAncestors) since
89
- // we don't capture `wof:hierarchy`.
88
+ // `ancestors` maps each place to every place above it in the hierarchy (and itself).
89
+ // The resolver's parent-constraint scopes a child lookup to a parent's descendants
90
+ // via `spr.id IN (select id from ancestors where ancestor_id = ?)`.
91
+ // The off-the-shelf WOF dumps ship this table.
92
+ // Our build derives it from the parent_id chain (see populateAncestors)
93
+ // since we don't capture `wof:hierarchy`.
90
94
  await db.schema
91
95
  .createTable("ancestors")
92
96
  .ifNotExists()
@@ -98,11 +102,9 @@ export async function createUnifiedSchema(db: DatabaseClient<WOFDatabase>): Prom
98
102
  }
99
103
 
100
104
  /**
101
- * Populate the `ancestors` table by walking each place's `parent_id` chain in `spr` (transitive closure, including the
102
- * place itself). Idempotent: drops + rebuilds the table contents. Returns the row count. Run after `spr` is fully
103
- * ingested (build-unified-wof freeze phase) or standalone on an existing unified DB (`scripts/add-ancestors.ts`).
104
- * Sentinel/negative parent_ids and cycles terminate the walk. ~4 rows/place average; a transaction keeps the ~5M
105
- * inserts fast.
105
+ * Populate the `ancestors` table by walking each place's `parent_id` chain in `spr`
106
+ * to a transitive closure that includes the place itself.
107
+ * Run this after `spr` is fully ingested.
106
108
  */
107
109
  export function populateAncestors<DB>(db: DatabaseClient<DB>): number {
108
110
  db.exec("DELETE FROM ancestors")
@@ -126,7 +128,6 @@ export function populateAncestors<DB>(db: DatabaseClient<DB>): number {
126
128
  for (const r of rows) {
127
129
  insert.run(r.id, r.id, r.placetype)
128
130
 
129
- // self
130
131
  count++
131
132
  const seen = new Set<number>([r.id])
132
133
  let cur = r.parent_id
@@ -169,8 +170,7 @@ export async function createUnifiedIndexes(db: DatabaseClient<WOFDatabase>): Pro
169
170
  .columns(["other_source", "other_id"])
170
171
  .execute()
171
172
 
172
- // ancestor_id is the hot column (parent-constraint queries `WHERE ancestor_id = ?`); id supports
173
- // the reverse lookup.
173
+ // ancestor_id is the hot column for parent-constraint queries. id supports the reverse lookup.
174
174
  await db.schema.createIndex("ancestors_by_ancestor").ifNotExists().on("ancestors").column("ancestor_id").execute()
175
175
  await db.schema.createIndex("ancestors_by_id").ifNotExists().on("ancestors").column("id").execute()
176
176
  }
@@ -3,16 +3,16 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  * @file The consult `./lookup.ts`'s docstring instructs: "callers building negative evidence must consult
6
- * `readLayerCoverage`, not this reader alone." A bare `null` from `nearestUPRN` is two different facts — no UPRN here,
7
- * or nobody surveyed here — and this is the only place that separates them. It answers an {@link Exclusion} or `null`,
6
+ * `readLayerCoverage`, not this reader by itself." A bare `null` from `nearestUPRN` is two different facts — no uprn here,
7
+ * or an unsurveyed area — and this is the only place that separates them. It answers an {@link Exclusion} or `null`,
8
8
  * so a caller cannot read an unsurveyed cell as an empty one by accident.
9
9
  *
10
- * `radiusM` is a CALLER'S parameter with no default. There is no radius that is correct for both "which property is
11
- * this coordinate" and "is this street built at all", and picking one here would bury that choice where nobody
10
+ * `radiusM` is a caller'S parameter with no default. There is no radius that is correct for both "which property is
11
+ * this coordinate" and "is this street built at all", and picking one here would bury that choice where reviewers
12
12
  * reviewing an exclusion can see it.
13
13
  */
14
14
 
15
- import { readLayerCoverage, readLayerManifest, type LayerContractHandle } from "@mailwoman/core/layers"
15
+ import { readLayerCoverage, readLayerManifest, type layerschemahandle } from "@mailwoman/core/layers"
16
16
  import { foldIdentity, requireExclusionBasis, type Exclusion } from "@mailwoman/evidence"
17
17
  import { shortCellToParentInt } from "@mailwoman/spatial"
18
18
 
@@ -20,24 +20,31 @@ import type { UPRNLookup } from "#uprn/lookup"
20
20
  import { UPRN_COVERAGE_H3_RESOLUTION, UPRN_H3_RESOLUTION, uprnH3Cell } from "#uprn/schema"
21
21
 
22
22
  /**
23
- * The identity fold, on purpose: this probe keys on a COORDINATE, not a name, so there is no string folding for the
24
- * builder and the probe to disagree about. Passing the same identity as both `probeFold` and `layerFold` records that
25
- * the fold axis is not in play here, rather than silently omitting the check. It is not a stub.
23
+ * The identity fold, on purpose: this probe keys on a coordinate rather than a name,
24
+ * so there is no string folding for the builder and the probe to disagree about.
25
+ *
26
+ * The same identity in both `probeFold` and `layerFold` records that the fold axis
27
+ * is not in play here, rather than silently omitting the check.
28
+ * It is not a stub.
26
29
  */
27
30
  export const UPRN_EXISTENCE_FOLD = foldIdentity((s) => s)
28
31
 
29
32
  /**
30
- * The countries OS Open UPRN covers. Northern Ireland is outside the product, so a `null` there is unknown and must
31
- * never become evidence of absence; the country check is what keeps it out.
33
+ * The countries OS Open uprn covers.
34
+ *
35
+ * Northern Ireland is outside the product, so a `null` there is unknown
36
+ * and must never become evidence of absence.
37
+ * The country check is what keeps it out.
32
38
  */
33
39
  export const UPRN_COVERED_COUNTRIES: ReadonlySet<string> = new Set(["GB"])
34
40
 
35
41
  export interface UPRNAbsenceInput {
36
42
  lookup: UPRNLookup
37
43
  /**
38
- * The same file the lookup reads; the layer contract tables live beside the points.
44
+ * The same file the lookup reads.
45
+ * The layer interface tables live beside the points.
39
46
  */
40
- contractDB: LayerContractHandle
47
+ schemadb: layerschemahandle
41
48
  latitude: number
42
49
  longitude: number
43
50
  radiusM: number
@@ -48,27 +55,31 @@ export interface UPRNAbsenceInput {
48
55
  }
49
56
 
50
57
  /**
51
- * The coverage cell a coordinate falls in, derived from its stored res-9 cell exactly as the builder derives it — never
52
- * from the centroid, which lands in a different parent for a fraction of cells.
58
+ * The coverage cell a coordinate falls in, derived from its stored res-9 cell exactly
59
+ * as the builder derives it rather than from the centroid.
60
+ *
61
+ * The centroid lands in a different parent for a fraction of cells.
53
62
  */
54
63
  export function uprnCoverageCell(latitude: number, longitude: number): number {
55
64
  return shortCellToParentInt(uprnH3Cell(latitude, longitude), UPRN_H3_RESOLUTION, UPRN_COVERAGE_H3_RESOLUTION)
56
65
  }
57
66
 
58
67
  /**
59
- * An {@link Exclusion} when no UPRN lies within `radiusM` AND the layer's coverage licenses saying so; `null` on a hit
60
- * (presence is not this probe's business) and on every refusal (unsurveyed cell, `source_present` basis, a country the
61
- * product does not cover). Never throws on a refusal: the caller falls open to the ranking it already had.
68
+ * An {@link Exclusion} when no uprn lies within `radiusM` and the layer's coverage licenses
69
+ * saying so; `null` on a hit (presence is not this probe's business) and on every refusal
70
+ * (unsurveyed cell, `source_present` basis, a country the product does not cover).
71
+ *
72
+ * Never throws on a refusal: the caller falls open to the ranking it already had.
62
73
  */
63
74
  export async function uprnAbsenceAt(input: UPRNAbsenceInput): Promise<Exclusion | null> {
64
75
  const coverageCell = uprnCoverageCell(input.latitude, input.longitude)
65
- const coverage = await readLayerCoverage(input.contractDB, coverageCell)
76
+ const coverage = await readLayerCoverage(input.schemadb, coverageCell)
66
77
 
67
78
  if (!coverage) return null
68
79
 
69
80
  if (input.lookup.nearestUPRN(input.latitude, input.longitude, input.radiusM)) return null
70
81
 
71
- const manifest = await readLayerManifest(input.contractDB)
82
+ const manifest = await readLayerManifest(input.schemadb)
72
83
 
73
84
  return requireExclusionBasis({
74
85
  layer: manifest.name,
@@ -3,53 +3,32 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * Node reader for `uprn.db` — the OS Open UPRN layer (`uprn-schema.ts`). Two probes:
7
- *
8
- * - **`coordinateOf(uprn)`**: rowid B-tree hit on the `uprn` integer PK.
9
- * - **`nearestUPRN(lat, lon, radiusM)`**: bounded nearest-point search over the res-9 `h3_cell`
10
- * index — ring-by-ring `gridDisk` expansion with chunked `IN` probes and haversine ranking.
11
- * Rings stop as soon as geometry proves no unprobed cell could beat the best hit — a distance
12
- * bound, not POILookup's row-count accumulation, so the early exit can never strand a nearer
13
- * point in an unprobed ring.
14
- *
15
- * ## `null` is a claim, scoped by coverage
16
- *
17
- * OS designates Open UPRN complete for GB (every UPRN in AddressBase Premium with geometry), and
18
- * the builder writes `layer_coverage` with basis `designated` for every cell the product touches.
19
- * So a `null` from either probe inside a covered cell is evidence of absence — "no such published
20
- * GB UPRN" / "no UPRN within the radius". Outside coverage (Northern Ireland, the Isle of Man, the
21
- * Channel Islands, open water) it is UNKNOWN, per the meaning-of-zero rule — callers building
22
- * negative evidence must consult `readLayerCoverage`, not this reader alone.
23
- *
24
- * `latLngToCell`/`gridDisk` come from `h3-js`; the 48-bit short-cell packing is
25
- * `@mailwoman/spatial`'s `shortCellToInt` via `uprnFullCell` — never reimplemented here.
6
+ * Node reader for `uprn.db`, where a `null` is evidence of absence only inside published coverage, so callers building negative evidence must consult `readLayerCoverage`.
26
7
  */
27
8
 
28
9
  import { allRows } from "@mailwoman/core/utils"
29
- import { haversineKm, shortCellToInt, type H3Cell } from "@mailwoman/spatial"
10
+ import { haversineKm, shortCellToInt, type GeoCoordinate, type H3Cell } from "@mailwoman/spatial"
30
11
  import { DatabaseClient } from "@mailwoman/sqlite/client"
31
12
  import { gridDisk } from "h3-js"
13
+ import type { PathBuilderLike } from "path-ts"
32
14
 
33
15
  import type { UPRNDatabase } from "#uprn/schema"
34
16
  import { uprnFullCell } from "#uprn/schema"
35
17
  /**
36
- * Conservative FLOOR on how much CENTRE distance one unit of res-9 GRID distance buys, metres. Adjacent centres sit √3
37
- * × edge apart (avg edge 174.4 m → ≈302 m); the worst bearing across a ring costs a further ×0.866, and H3's projection
38
- * distortion shrinks edges by well under the slack this leaves (the true worst is ≈217 m per grid step). Dividing a
39
- * radius by this over-counts rings and can never miss a cell; multiplying a grid distance by it under-states reach and
40
- * can never end the ring walk early.
18
+ * Conservative floor, in meters, on the center distance one unit of res-9 grid distance buys,
19
+ * so multiplying a grid distance under-states reach and can never end the ring walk early.
41
20
  */
42
21
  const RES9_CENTER_SPACING_FLOOR_M = 150
43
22
 
44
23
  /**
45
- * Conservative CEILING on a res-9 cell's centre-to-vertex distance, metres (avg edge 174.4 m; distortion stays well
46
- * under this). A point within `radiusM` of the query sits in a cell whose CENTRE is within `radiusM` + this.
24
+ * Conservative ceiling, in meters, on a res-9 cell's center-to-vertex distance, so a point
25
+ * within `radiusM` of the query sits in a cell whose center is within `radiusM` plus this.
47
26
  */
48
27
  const RES9_CELL_RADIUS_CEILING_M = 300
49
28
 
50
29
  /**
51
- * Hard ceiling on `radiusM`. Keeps the probe bounded (10 km → ~72 rings ≈ 15.8k cells ≈ 18 `IN` chunks); a caller who
52
- * wants a wider search than "which property is this coordinate" has outgrown this reader and should say so loudly.
30
+ * Hard ceiling on `radiusM` that keeps the probe bounded, since a caller wanting a wider
31
+ * search than "which property is this coordinate" has outgrown this reader.
53
32
  */
54
33
  export const UPRN_MAX_NEAREST_RADIUS_M = 10_000
55
34
 
@@ -58,28 +37,23 @@ export const UPRN_MAX_NEAREST_RADIUS_M = 10_000
58
37
  */
59
38
  const CELL_PROBE_CHUNK = 900
60
39
 
61
- export interface UPRNCoordinate {
62
- latitude: number
63
- longitude: number
64
- }
65
-
66
40
  export interface UPRNNearestHit {
67
41
  uprn: number
68
42
  latitude: number
69
43
  longitude: number
70
44
  /**
71
- * Haversine distance from the query point, metres.
45
+ * Haversine distance from the query point, meters.
72
46
  */
73
47
  distanceM: number
74
48
  }
75
49
 
76
50
  export interface UPRNLookupOpts {
77
51
  /**
78
- * Path to a `uprn.db` built by `mailwoman`'s gazetteer pipeline. Opened read-only.
52
+ * Path to a `uprn.db` built by `mailwoman`'s gazetteer pipeline, opened read-only.
79
53
  */
80
- databasePath?: string
54
+ databasePath?: PathBuilderLike
81
55
  /**
82
- * Pre-opened handle (tests / shared connections). Mutually exclusive with `databasePath`.
56
+ * Pre-opened handle (tests / shared connections), mutually exclusive with `databasePath`.
83
57
  */
84
58
  database?: DatabaseClient<UPRNDatabase>
85
59
  }
@@ -91,54 +65,45 @@ interface UPRNRow {
91
65
  }
92
66
 
93
67
  /**
94
- * Node reader over `uprn.db`. `implements Disposable` so callers can `using lookup = new UPRNLookup(...)` — the same
95
- * precedent as {@link POILookup}.
68
+ * Node reader over `uprn.db`, disposable so callers can take it with `using`.
96
69
  */
97
70
  export class UPRNLookup implements Disposable {
98
71
  #db: DatabaseClient<UPRNDatabase>
99
72
  /**
100
- * Resources this instance opened. A connection handed in by a caller is NOT in here, so disposal cannot reach it —
101
- * ownership is membership rather than a flag a later branch has to check.
73
+ * Ownership is membership: a connection handed in by a caller is not in here,
74
+ * so disposal cannot reach it.
102
75
  */
103
- readonly #resources = new DisposableStack()
76
+ readonly #resources: DisposableStack
104
77
 
105
- /**
106
- * `uprn` → its point (rowid-alias PK hit).
107
- */
108
78
  readonly #coordinateProbe: ReturnType<DatabaseClient["prepare"]>
109
79
 
110
80
  constructor(opts: UPRNLookupOpts) {
81
+ using resources = new DisposableStack()
82
+
111
83
  if (opts.database) {
112
84
  this.#db = opts.database
113
85
  } else if (opts.databasePath) {
114
- this.#db = this.#resources.use(new DatabaseClient<UPRNDatabase>(opts.databasePath, { readOnly: true }))
86
+ this.#db = resources.use(new DatabaseClient<UPRNDatabase>(opts.databasePath, { readOnly: true }))
115
87
  } else {
116
88
  throw new Error("UPRNLookup needs `databasePath` or `database`")
117
89
  }
118
90
 
119
91
  this.#coordinateProbe = this.#db.prepare("SELECT lat, lon FROM uprn WHERE uprn = ?")
92
+ this.#resources = resources.move()
120
93
  }
121
94
 
122
95
  /**
123
- * The WGS84 point OS publishes for `uprn`, or `null` when the layer holds no such UPRN (see the module docstring for
124
- * what that `null` claims).
96
+ * The WGS84 point OS publishes for `uprn`, or `null` when the layer holds no such uprn.
125
97
  */
126
- coordinateOf(uprn: number): UPRNCoordinate | null {
98
+ coordinateOf(uprn: number): GeoCoordinate | null {
127
99
  const row = this.#coordinateProbe.get(uprn) as { lat: number; lon: number } | undefined
128
100
 
129
101
  return row ? { latitude: row.lat, longitude: row.lon } : null
130
102
  }
131
103
 
132
104
  /**
133
- * The single nearest UPRN within `radiusM` metres of the query point, or `null` when no UPRN lies inside the radius.
134
- *
135
- * Bounded two ways: `radiusM` is capped at {@link UPRN_MAX_NEAREST_RADIUS_M}, and rings expand outward only until no
136
- * unprobed cell could beat the best hit found so far (or the radius, when nothing has been found). The stop rule is
137
- * geometric — a cell at grid distance `g` holds no point nearer than `g` × spacing floor − cell radius, using the
138
- * same conservative constants the reach math uses — so unlike POILookup's row-count accumulation there is no
139
- * early-exit ambiguity: a break can never strand a nearer point in an unprobed ring. This is what keeps a
140
- * capped-radius call over dense ground at milliseconds instead of a full-disk fetch (measured 6.4 s → 13 ms for a 10
141
- * km radius over central London, 41.6M-row layer; an empty-sea miss at the cap runs the full expansion, 74 ms).
105
+ * The single nearest uprn within `radiusM` meters of the query point, or `null`
106
+ * when no uprn lies inside the radius.
142
107
  *
143
108
  * @throws {RangeError} When `radiusM` is not a positive finite number, or exceeds the cap.
144
109
  */
@@ -155,17 +120,14 @@ export class UPRNLookup implements Disposable {
155
120
  const seenCells = new Set<string>()
156
121
  let best: UPRNNearestHit | null = null
157
122
 
158
- // `ring` is H3 grid distance; the loop terminates because the break bound is at most radiusM, which the
159
- // RangeError above caps.
123
+ // The loop terminates because the break bound is at most `radiusM`.
124
+ // The RangeError above caps that value.
160
125
  for (let ring = 0; ; ring++) {
161
- // A cell at grid distance `ring` holds no point nearer than this. Once it exceeds what could still
162
- // win — the best hit so far, or the radius itself — further rings cannot improve the answer.
126
+ // Once this bound exceeds the best hit so far, or the radius, further rings cannot improve the answer.
163
127
  const closestPossibleM = ring * RES9_CENTER_SPACING_FLOOR_M - RES9_CELL_RADIUS_CEILING_M
164
128
 
165
129
  if (closestPossibleM > Math.min(radiusM, best?.distanceM ?? radiusM)) break
166
130
 
167
- // gridDisk(origin, ring) returns the WHOLE disk out to `ring`; diffing against what's already been
168
- // probed derives just this ring's new cells (the POILookup pattern).
169
131
  const diskCells = gridDisk(origin, ring) as string[]
170
132
  const newCells: number[] = []
171
133
 
@@ -180,7 +142,6 @@ export class UPRNLookup implements Disposable {
180
142
  const chunk = newCells.slice(i, i + CELL_PROBE_CHUNK)
181
143
  const placeholders = chunk.map(() => "?").join(", ")
182
144
 
183
- // Prepared fresh per chunk arity — a cold, per-call path, same posture as POILookup's batched hydration.
184
145
  const rows = allRows<UPRNRow>(
185
146
  this.#db.prepare(`SELECT uprn, lat, lon FROM uprn WHERE h3_cell IN (${placeholders})`),
186
147
  ...chunk
@@ -189,7 +150,7 @@ export class UPRNLookup implements Disposable {
189
150
  for (const row of rows) {
190
151
  const distanceM = haversineKm(latitude, longitude, row.lat, row.lon) * 1000
191
152
 
192
- if (distanceM <= radiusM && (best === null || distanceM < best.distanceM)) {
153
+ if (distanceM <= radiusM && (!best || distanceM < best.distanceM)) {
193
154
  best = { uprn: row.uprn, latitude: row.lat, longitude: row.lon, distanceM }
194
155
  }
195
156
  }
@@ -3,51 +3,27 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * Typed schema for `uprn.db` — the OS Open UPRN spatial layer: every GB Unique Property Reference
7
- * Number with its WGS84 point, so mailwoman results can carry UPRN as an interoperability key
8
- * beside our own `@mailwoman/address-id`. One rowid table keyed `uprn INTEGER PRIMARY KEY` (the
9
- * rowid alias — the optimal shape for an integer-PK point table; `WITHOUT ROWID` buys nothing
10
- * here), plus a secondary res-9 `h3_cell` index for the bounded nearest-point probe.
11
- *
12
- * ## Coordinates are OS's own WGS84 columns
13
- *
14
- * The source CSV publishes BOTH coordinate systems per row — OSGB36 eastings/northings AND WGS84
15
- * `LATITUDE`/`LONGITUDE`. This layer stores OS's own lat/lon verbatim and never reconverts from
16
- * eastings: `@mailwoman/spatial`'s `osgb36ToWGS84` is a 7-parameter Helmert with a measured p95 of
17
- * 4.18 m, and re-deriving what the publisher already computed (with OSTN15, exactly) would replace
18
- * their answer with a strictly worse one.
19
- *
20
- * ## Why `h3_cell` exists at all
21
- *
22
- * The layer contract requires every domain row to be addressable by at least one spine key —
23
- * `writeLayerManifest` throws on a manifest that declares none — and UPRN is its own id space, not
24
- * H3/WOF/address-id/street. The res-9 short cell (`shortCellToInt`, the same packing as poi.db and
25
- * the OSM situs extracts) is the spine that fits a point table, and its index doubles as the
26
- * `nearestUPRN` ring probe.
27
- *
28
- * The DB also embeds the layer-contract tables from `@mailwoman/core/layers`; the builder
29
- * (`packages/mailwoman/lib/gazetteer-pipeline/uprn-layer.ts`) writes the manifest and per-res-6-cell
30
- * coverage.
6
+ * Typed schema for `uprn.db`, storing OS's own WGS84 latitude/longitude verbatim rather than reconverting from the source's eastings.
31
7
  */
32
8
 
33
- import type { LayerContractDatabase } from "@mailwoman/core/layers"
9
+ import type { layerschemadatabase } from "@mailwoman/core/layers"
34
10
  import { shortCellToInt, type H3Cell } from "@mailwoman/spatial"
35
11
  import { latLngToCell } from "h3-js"
36
12
  import type { Kysely } from "kysely"
37
13
 
38
14
  /**
39
- * Resolution the `uprn` table's `h3_cell` column is keyed at — the shared layer-spine resolution (poi.db, the OSM situs
40
- * extracts).
15
+ * Resolution the `uprn` table's `h3_cell` column is keyed at, shared with the other layer spines.
41
16
  */
42
17
  export const UPRN_H3_RESOLUTION = 9
43
18
 
44
19
  /**
45
- * Resolution of the layer's `layer_coverage` cells — coarse, per the contract (matches poi.db).
20
+ * Resolution of the layer's `layer_coverage` cells, coarse per the layer interface
21
+ * and shared with the other spines.
46
22
  */
47
23
  export const UPRN_COVERAGE_H3_RESOLUTION = 6
48
24
 
49
25
  /**
50
- * One UPRN point. `uprn` is the rowid alias, so the primary probe (`coordinateOf`) is a rowid B-tree hit.
26
+ * One uprn point whose `uprn` is a rowid alias, making the primary probe a rowid B-tree hit.
51
27
  */
52
28
  export interface UPRNTable {
53
29
  /**
@@ -55,7 +31,7 @@ export interface UPRNTable {
55
31
  */
56
32
  uprn: number
57
33
  /**
58
- * WGS84 latitude, as OS published it (never reconverted from eastings — see the module docstring).
34
+ * WGS84 latitude, as OS published it, never reconverted from eastings.
59
35
  */
60
36
  lat: number
61
37
  /**
@@ -63,36 +39,38 @@ export interface UPRNTable {
63
39
  */
64
40
  lon: number
65
41
  /**
66
- * 48-bit short H3 cell at {@link UPRN_H3_RESOLUTION} (`uprnH3Cell`) — the layer-contract spine key and the
67
- * `nearestUPRN` probe index.
42
+ * 48-bit short H3 cell at {@link UPRN_H3_RESOLUTION} — the layer-interface spine key
43
+ * and the `nearestUPRN` probe index.
68
44
  */
69
45
  h3_cell: number
70
46
  }
71
47
 
72
48
  /**
73
- * Build-provenance key/value pairs the fixed `layer_manifest` columns have no room for: quality-drop counts, the header
74
- * as found, the upstream licence text verbatim (the Code-Point provenance discipline).
49
+ * Build-provenance key/value pairs the fixed `layer_manifest` columns have no room for,
50
+ * including the upstream license text verbatim.
75
51
  */
76
52
  export interface UPRNMetaTable {
77
53
  key: string
78
54
  value: string
79
55
  }
80
56
 
81
- export interface UPRNDatabase extends LayerContractDatabase {
57
+ export interface UPRNDatabase extends layerschemadatabase {
82
58
  uprn: UPRNTable
83
59
  uprn_meta: UPRNMetaTable
84
60
  }
85
61
 
86
62
  /**
87
- * The full res-9 cell for a UPRN point — the ONE derivation both the builder and every consumer share, so a fixture
88
- * built by a test and a row built by the real ingest can never disagree on which cell a coordinate keys to.
63
+ * The full res-9 cell for a UPRN point.
64
+ *
65
+ * This is the one derivation the builder and its consumers share so their cells cannot disagree.
89
66
  */
90
67
  export function uprnFullCell(latitude: number, longitude: number): H3Cell {
91
68
  return latLngToCell(latitude, longitude, UPRN_H3_RESOLUTION) as H3Cell
92
69
  }
93
70
 
94
71
  /**
95
- * The `h3_cell` column value for a UPRN point: {@link uprnFullCell} packed to the shared 48-bit short-cell integer.
72
+ * The `h3_cell` column value for a uprn point, packing {@link uprnFullCell} to
73
+ * the shared 48-bit short-cell integer.
96
74
  */
97
75
  export function uprnH3Cell(latitude: number, longitude: number): number {
98
76
  return shortCellToInt(uprnFullCell(latitude, longitude))
@@ -117,7 +95,7 @@ export async function createUPRNMetaTable(db: Kysely<UPRNDatabase>): Promise<voi
117
95
  }
118
96
 
119
97
  /**
120
- * Secondary index for the `nearestUPRN` ring probe. Builders call this AFTER the bulk load (index-after-load).
98
+ * Secondary index for the `nearestUPRN` ring probe, created after the bulk load.
121
99
  */
122
100
  export async function createUPRNIndexes(db: Kysely<UPRNDatabase>): Promise<void> {
123
101
  await db.schema.createIndex("uprn_h3_cell").on("uprn").column("h3_cell").execute()