@mailwoman/resolver-wof-sqlite 9.2.0 → 9.3.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 (488) hide show
  1. package/README.md +16 -19
  2. package/lib/address/index.ts +9 -0
  3. package/{address-point-interpolation.ts → lib/address/point-interpolation.ts} +24 -22
  4. package/{address-point-schema.ts → lib/address/point-schema.ts} +18 -4
  5. package/{address-point.ts → lib/address/point.ts} +89 -27
  6. package/{ancestry-backfill.ts → lib/ancestry/backfill.ts} +14 -19
  7. package/{ancestry.ts → lib/ancestry/index.ts} +5 -3
  8. package/{build-candidate.ts → lib/build-candidate.ts} +84 -77
  9. package/{build-slim.ts → lib/build-slim.ts} +150 -165
  10. package/{candidate → lib/candidate}/alias-bags.ts +8 -6
  11. package/{candidate → lib/candidate}/ancestors-sidecar.ts +13 -15
  12. package/{candidate → lib/candidate}/country-display-names.ts +2 -2
  13. package/{candidate/shard-fold.ts → lib/candidate/extract-fold.ts} +26 -25
  14. package/{candidate → lib/candidate}/name-roles.ts +17 -16
  15. package/{candidate → lib/candidate}/own-name.ts +1 -1
  16. package/{candidate → lib/candidate}/place-attrs.ts +3 -3
  17. package/{candidate-ancestors-schema.ts → lib/candidate-ancestors-schema.ts} +4 -4
  18. package/{candidate-fts.ts → lib/candidate-fts.ts} +3 -3
  19. package/{candidate-importance.ts → lib/candidate-importance.ts} +53 -57
  20. package/{candidate-lookup.ts → lib/candidate-lookup.ts} +76 -73
  21. package/{candidate-schema.ts → lib/candidate-schema.ts} +5 -5
  22. package/{candidate-scoring.ts → lib/candidate-scoring.ts} +15 -22
  23. package/{capital-schema.ts → lib/capital-schema.ts} +5 -6
  24. package/{capitals.ts → lib/capitals.ts} +2 -2
  25. package/{coincident-roles.ts → lib/coincident-roles.ts} +8 -11
  26. package/{convention.ts → lib/convention/index.ts} +3 -3
  27. package/{convention-schema.ts → lib/convention/schema.ts} +2 -2
  28. package/{coverage-manifest-schema.ts → lib/coverage-manifest-schema.ts} +9 -10
  29. package/{currency-backfill.ts → lib/currency-backfill.ts} +126 -41
  30. package/lib/env.ts +50 -0
  31. package/{exact-match.ts → lib/exact-match.ts} +23 -14
  32. package/{sharding.ts → lib/extracts.ts} +61 -58
  33. package/{fst-autocomplete.ts → lib/fst/autocomplete.ts} +4 -4
  34. package/{fst-builder.ts → lib/fst/builder.ts} +17 -16
  35. package/{fst-deserialize-web.ts → lib/fst/deserialize-web.ts} +27 -87
  36. package/lib/fst/format.ts +106 -0
  37. package/{fst-freshness.ts → lib/fst/freshness.ts} +41 -74
  38. package/lib/fst/index.ts +14 -0
  39. package/{fst-matcher.ts → lib/fst/matcher.ts} +1 -1
  40. package/{fst-serialize.ts → lib/fst/serialize.ts} +37 -115
  41. package/{fst-types.ts → lib/fst/types.ts} +4 -2
  42. package/{fts.ts → lib/fts/index.ts} +24 -19
  43. package/{fts-query.ts → lib/fts/query.ts} +1 -1
  44. package/{geonames-aliases.ts → lib/geonames/aliases.ts} +13 -13
  45. package/lib/geonames/index.ts +8 -0
  46. package/{geonames-postal.ts → lib/geonames/postal.ts} +14 -13
  47. package/{index.ts → lib/index.ts} +37 -37
  48. package/{interpolation.ts → lib/interpolation.ts} +27 -25
  49. package/{lookup.ts → lib/lookup.ts} +129 -141
  50. package/lib/nsul/index.ts +8 -0
  51. package/lib/nsul/lookup.ts +144 -0
  52. package/lib/nsul/schema.ts +130 -0
  53. package/{place-importance-schema.ts → lib/place-importance-schema.ts} +7 -8
  54. package/lib/poi/index.ts +8 -0
  55. package/{poi-lookup.ts → lib/poi/lookup.ts} +22 -28
  56. package/{poi-schema.ts → lib/poi/schema.ts} +3 -4
  57. package/{postal-city-alias-lookup.ts → lib/postal/city-alias-lookup.ts} +14 -20
  58. package/{postal-city-candidate-schema.ts → lib/postal/city-candidate-schema.ts} +2 -2
  59. package/lib/postal/index.ts +9 -0
  60. package/{postcode-point-lookup.ts → lib/postcode-point-lookup.ts} +17 -15
  61. package/{primary-preference.ts → lib/primary-preference.ts} +29 -10
  62. package/{proximity-rerank.ts → lib/proximity-rerank.ts} +2 -2
  63. package/{ranking-weights.ts → lib/ranking-weights.ts} +30 -4
  64. package/{region-keys.ts → lib/region-keys.ts} +9 -9
  65. package/{reverse.ts → lib/reverse.ts} +34 -46
  66. package/{schema.ts → lib/schema.ts} +10 -0
  67. package/{search-fetch.ts → lib/search-fetch.ts} +29 -28
  68. package/{sqlite-convention-source.ts → lib/sqlite-convention-source.ts} +9 -10
  69. package/{sqlite-utils.ts → lib/sqlite-utils.ts} +14 -18
  70. package/{street-centroid-schema.ts → lib/street/centroid-schema.ts} +5 -5
  71. package/{street-centroid.ts → lib/street/centroid.ts} +14 -21
  72. package/lib/street/index.ts +13 -0
  73. package/{street-morphology-fst-builder.ts → lib/street/morphology-fst-builder.ts} +24 -14
  74. package/{street-morphology-fst-loader.ts → lib/street/morphology-fst-loader.ts} +14 -12
  75. package/{street-name-lookup.ts → lib/street/name-lookup.ts} +14 -30
  76. package/{street-normalize.ts → lib/street/normalize.ts} +44 -19
  77. package/{street-segment-schema.ts → lib/street/segment-schema.ts} +7 -7
  78. package/{types.ts → lib/types.ts} +18 -12
  79. package/{unified-schema.ts → lib/unified-schema.ts} +20 -24
  80. package/lib/uprn/existence.ts +84 -0
  81. package/lib/uprn/index.ts +9 -0
  82. package/{uprn-lookup.ts → lib/uprn/lookup.ts} +14 -18
  83. package/{uprn-schema.ts → lib/uprn/schema.ts} +3 -3
  84. package/lib/weights-overlay-linker.ts +878 -0
  85. package/out/address/index.d.ts +9 -0
  86. package/out/address/index.d.ts.map +1 -0
  87. package/out/address/index.js +9 -0
  88. package/out/address/index.js.map +1 -0
  89. package/out/{address-point-interpolation.d.ts → address/point-interpolation.d.ts} +11 -10
  90. package/out/address/point-interpolation.d.ts.map +1 -0
  91. package/out/{address-point-interpolation.js → address/point-interpolation.js} +18 -18
  92. package/out/address/point-interpolation.js.map +1 -0
  93. package/out/{address-point-schema.d.ts → address/point-schema.d.ts} +16 -6
  94. package/out/address/point-schema.d.ts.map +1 -0
  95. package/out/{address-point-schema.js → address/point-schema.js} +7 -3
  96. package/out/address/point-schema.js.map +1 -0
  97. package/out/{address-point.d.ts → address/point.d.ts} +16 -8
  98. package/out/address/point.d.ts.map +1 -0
  99. package/out/{address-point.js → address/point.js} +71 -20
  100. package/out/address/point.js.map +1 -0
  101. package/out/{ancestry-backfill.d.ts → ancestry/backfill.d.ts} +7 -5
  102. package/out/ancestry/backfill.d.ts.map +1 -0
  103. package/out/{ancestry-backfill.js → ancestry/backfill.js} +12 -16
  104. package/out/ancestry/backfill.js.map +1 -0
  105. package/out/{ancestry.d.ts → ancestry/index.d.ts} +4 -3
  106. package/out/ancestry/index.d.ts.map +1 -0
  107. package/out/{ancestry.js → ancestry/index.js} +3 -2
  108. package/out/ancestry/index.js.map +1 -0
  109. package/out/build-candidate.d.ts +30 -24
  110. package/out/build-candidate.d.ts.map +1 -1
  111. package/out/build-candidate.js +50 -52
  112. package/out/build-candidate.js.map +1 -1
  113. package/out/build-slim.d.ts +4 -4
  114. package/out/build-slim.d.ts.map +1 -1
  115. package/out/build-slim.js +124 -139
  116. package/out/build-slim.js.map +1 -1
  117. package/out/candidate/alias-bags.d.ts +5 -3
  118. package/out/candidate/alias-bags.d.ts.map +1 -1
  119. package/out/candidate/alias-bags.js +2 -2
  120. package/out/candidate/alias-bags.js.map +1 -1
  121. package/out/candidate/ancestors-sidecar.d.ts +9 -10
  122. package/out/candidate/ancestors-sidecar.d.ts.map +1 -1
  123. package/out/candidate/ancestors-sidecar.js +7 -7
  124. package/out/candidate/ancestors-sidecar.js.map +1 -1
  125. package/out/candidate/country-display-names.d.ts +1 -1
  126. package/out/candidate/country-display-names.d.ts.map +1 -1
  127. package/out/candidate/country-display-names.js +1 -1
  128. package/out/candidate/country-display-names.js.map +1 -1
  129. package/out/candidate/extract-fold.d.ts +32 -0
  130. package/out/candidate/extract-fold.d.ts.map +1 -0
  131. package/out/candidate/{shard-fold.js → extract-fold.js} +20 -20
  132. package/out/candidate/extract-fold.js.map +1 -0
  133. package/out/candidate/name-roles.d.ts +13 -11
  134. package/out/candidate/name-roles.d.ts.map +1 -1
  135. package/out/candidate/name-roles.js +11 -10
  136. package/out/candidate/name-roles.js.map +1 -1
  137. package/out/candidate/own-name.d.ts +1 -1
  138. package/out/candidate/own-name.d.ts.map +1 -1
  139. package/out/candidate/own-name.js +1 -1
  140. package/out/candidate/own-name.js.map +1 -1
  141. package/out/candidate/place-attrs.d.ts +3 -3
  142. package/out/candidate/place-attrs.d.ts.map +1 -1
  143. package/out/candidate/place-attrs.js +1 -1
  144. package/out/candidate/place-attrs.js.map +1 -1
  145. package/out/candidate-ancestors-schema.d.ts +4 -4
  146. package/out/candidate-ancestors-schema.d.ts.map +1 -1
  147. package/out/candidate-ancestors-schema.js +2 -2
  148. package/out/candidate-ancestors-schema.js.map +1 -1
  149. package/out/candidate-fts.d.ts +3 -3
  150. package/out/candidate-fts.d.ts.map +1 -1
  151. package/out/candidate-fts.js +1 -1
  152. package/out/candidate-fts.js.map +1 -1
  153. package/out/candidate-importance.d.ts +16 -16
  154. package/out/candidate-importance.d.ts.map +1 -1
  155. package/out/candidate-importance.js +46 -51
  156. package/out/candidate-importance.js.map +1 -1
  157. package/out/candidate-lookup.d.ts +11 -9
  158. package/out/candidate-lookup.d.ts.map +1 -1
  159. package/out/candidate-lookup.js +61 -58
  160. package/out/candidate-lookup.js.map +1 -1
  161. package/out/candidate-schema.d.ts +5 -5
  162. package/out/candidate-schema.d.ts.map +1 -1
  163. package/out/candidate-schema.js.map +1 -1
  164. package/out/candidate-scoring.d.ts +7 -7
  165. package/out/candidate-scoring.d.ts.map +1 -1
  166. package/out/candidate-scoring.js +10 -14
  167. package/out/candidate-scoring.js.map +1 -1
  168. package/out/capital-schema.d.ts +3 -3
  169. package/out/capital-schema.d.ts.map +1 -1
  170. package/out/capital-schema.js +2 -2
  171. package/out/capital-schema.js.map +1 -1
  172. package/out/capitals.d.ts +1 -1
  173. package/out/capitals.d.ts.map +1 -1
  174. package/out/capitals.js +2 -2
  175. package/out/capitals.js.map +1 -1
  176. package/out/coincident-roles.d.ts +6 -5
  177. package/out/coincident-roles.d.ts.map +1 -1
  178. package/out/coincident-roles.js +2 -4
  179. package/out/coincident-roles.js.map +1 -1
  180. package/out/{convention.d.ts → convention/index.d.ts} +4 -4
  181. package/out/convention/index.d.ts.map +1 -0
  182. package/out/{convention.js → convention/index.js} +2 -2
  183. package/out/convention/index.js.map +1 -0
  184. package/out/{convention-schema.d.ts → convention/schema.d.ts} +2 -2
  185. package/out/convention/schema.d.ts.map +1 -0
  186. package/out/{convention-schema.js → convention/schema.js} +3 -3
  187. package/out/convention/schema.js.map +1 -0
  188. package/out/coverage-manifest-schema.d.ts +8 -8
  189. package/out/coverage-manifest-schema.d.ts.map +1 -1
  190. package/out/coverage-manifest-schema.js +4 -4
  191. package/out/coverage-manifest-schema.js.map +1 -1
  192. package/out/currency-backfill.d.ts +51 -7
  193. package/out/currency-backfill.d.ts.map +1 -1
  194. package/out/currency-backfill.js +65 -49
  195. package/out/currency-backfill.js.map +1 -1
  196. package/out/env.d.ts +43 -0
  197. package/out/env.d.ts.map +1 -0
  198. package/out/env.js +48 -0
  199. package/out/env.js.map +1 -0
  200. package/out/exact-match.d.ts +5 -5
  201. package/out/exact-match.d.ts.map +1 -1
  202. package/out/exact-match.js +10 -11
  203. package/out/exact-match.js.map +1 -1
  204. package/out/extracts.d.ts +114 -0
  205. package/out/extracts.d.ts.map +1 -0
  206. package/out/{sharding.js → extracts.js} +38 -38
  207. package/out/extracts.js.map +1 -0
  208. package/out/{fst-autocomplete.d.ts → fst/autocomplete.d.ts} +2 -2
  209. package/out/fst/autocomplete.d.ts.map +1 -0
  210. package/out/{fst-autocomplete.js → fst/autocomplete.js} +3 -3
  211. package/out/fst/autocomplete.js.map +1 -0
  212. package/out/{fst-builder.d.ts → fst/builder.d.ts} +5 -5
  213. package/out/fst/builder.d.ts.map +1 -0
  214. package/out/{fst-builder.js → fst/builder.js} +14 -13
  215. package/out/fst/builder.js.map +1 -0
  216. package/out/{fst-deserialize-web.d.ts → fst/deserialize-web.d.ts} +3 -3
  217. package/out/fst/deserialize-web.d.ts.map +1 -0
  218. package/out/{fst-deserialize-web.js → fst/deserialize-web.js} +10 -74
  219. package/out/fst/deserialize-web.js.map +1 -0
  220. package/out/fst/format.d.ts +80 -0
  221. package/out/fst/format.d.ts.map +1 -0
  222. package/out/fst/format.js +91 -0
  223. package/out/fst/format.js.map +1 -0
  224. package/out/{fst-freshness.d.ts → fst/freshness.d.ts} +10 -13
  225. package/out/fst/freshness.d.ts.map +1 -0
  226. package/out/{fst-freshness.js → fst/freshness.js} +41 -73
  227. package/out/fst/freshness.js.map +1 -0
  228. package/out/fst/index.d.ts +14 -0
  229. package/out/fst/index.d.ts.map +1 -0
  230. package/out/fst/index.js +14 -0
  231. package/out/fst/index.js.map +1 -0
  232. package/out/{fst-matcher.d.ts → fst/matcher.d.ts} +2 -2
  233. package/out/fst/matcher.d.ts.map +1 -0
  234. package/out/{fst-matcher.js → fst/matcher.js} +1 -1
  235. package/out/fst/matcher.js.map +1 -0
  236. package/out/{fst-serialize.d.ts → fst/serialize.d.ts} +5 -10
  237. package/out/fst/serialize.d.ts.map +1 -0
  238. package/out/{fst-serialize.js → fst/serialize.js} +18 -98
  239. package/out/fst/serialize.js.map +1 -0
  240. package/out/{fst-types.d.ts → fst/types.d.ts} +4 -3
  241. package/out/fst/types.d.ts.map +1 -0
  242. package/out/{fst-types.js → fst/types.js} +1 -1
  243. package/out/fst/types.js.map +1 -0
  244. package/out/{fts.d.ts → fts/index.d.ts} +16 -9
  245. package/out/fts/index.d.ts.map +1 -0
  246. package/out/{fts.js → fts/index.js} +16 -11
  247. package/out/fts/index.js.map +1 -0
  248. package/out/{fts-query.d.ts → fts/query.d.ts} +2 -2
  249. package/out/fts/query.d.ts.map +1 -0
  250. package/out/{fts-query.js → fts/query.js} +1 -1
  251. package/out/fts/query.js.map +1 -0
  252. package/out/{geonames-aliases.d.ts → geonames/aliases.d.ts} +8 -6
  253. package/out/geonames/aliases.d.ts.map +1 -0
  254. package/out/{geonames-aliases.js → geonames/aliases.js} +7 -7
  255. package/out/geonames/aliases.js.map +1 -0
  256. package/out/geonames/index.d.ts +8 -0
  257. package/out/geonames/index.d.ts.map +1 -0
  258. package/out/geonames/index.js +8 -0
  259. package/out/geonames/index.js.map +1 -0
  260. package/out/{geonames-postal.d.ts → geonames/postal.d.ts} +10 -8
  261. package/out/geonames/postal.d.ts.map +1 -0
  262. package/out/{geonames-postal.js → geonames/postal.js} +9 -9
  263. package/out/geonames/postal.js.map +1 -0
  264. package/out/index.d.ts +32 -32
  265. package/out/index.d.ts.map +1 -1
  266. package/out/index.js +24 -24
  267. package/out/index.js.map +1 -1
  268. package/out/interpolation.d.ts +10 -9
  269. package/out/interpolation.d.ts.map +1 -1
  270. package/out/interpolation.js +20 -20
  271. package/out/interpolation.js.map +1 -1
  272. package/out/lookup.d.ts +21 -20
  273. package/out/lookup.d.ts.map +1 -1
  274. package/out/lookup.js +102 -112
  275. package/out/lookup.js.map +1 -1
  276. package/out/name-score.d.ts.map +1 -1
  277. package/out/name-score.js.map +1 -1
  278. package/out/nsul/index.d.ts +8 -0
  279. package/out/nsul/index.d.ts.map +1 -0
  280. package/out/nsul/index.js +8 -0
  281. package/out/nsul/index.js.map +1 -0
  282. package/out/nsul/lookup.d.ts +83 -0
  283. package/out/nsul/lookup.d.ts.map +1 -0
  284. package/out/nsul/lookup.js +80 -0
  285. package/out/nsul/lookup.js.map +1 -0
  286. package/out/nsul/schema.d.ts +100 -0
  287. package/out/nsul/schema.d.ts.map +1 -0
  288. package/out/nsul/schema.js +78 -0
  289. package/out/nsul/schema.js.map +1 -0
  290. package/out/place-importance-schema.d.ts +5 -5
  291. package/out/place-importance-schema.d.ts.map +1 -1
  292. package/out/place-importance-schema.js +3 -3
  293. package/out/place-importance-schema.js.map +1 -1
  294. package/out/poi/index.d.ts +8 -0
  295. package/out/poi/index.d.ts.map +1 -0
  296. package/out/poi/index.js +8 -0
  297. package/out/poi/index.js.map +1 -0
  298. package/out/{poi-lookup.d.ts → poi/lookup.d.ts} +8 -10
  299. package/out/poi/lookup.d.ts.map +1 -0
  300. package/out/{poi-lookup.js → poi/lookup.js} +14 -18
  301. package/out/poi/lookup.js.map +1 -0
  302. package/out/{poi-schema.d.ts → poi/schema.d.ts} +4 -4
  303. package/out/poi/schema.d.ts.map +1 -0
  304. package/out/{poi-schema.js → poi/schema.js} +1 -1
  305. package/out/poi/schema.js.map +1 -0
  306. package/out/polygon-schema.d.ts.map +1 -1
  307. package/out/polygon-schema.js.map +1 -1
  308. package/out/{postal-city-alias-lookup.d.ts → postal/city-alias-lookup.d.ts} +6 -5
  309. package/out/postal/city-alias-lookup.d.ts.map +1 -0
  310. package/out/{postal-city-alias-lookup.js → postal/city-alias-lookup.js} +11 -15
  311. package/out/postal/city-alias-lookup.js.map +1 -0
  312. package/out/{postal-city-alias-schema.d.ts → postal/city-alias-schema.d.ts} +1 -1
  313. package/out/{postal-city-alias-schema.d.ts.map → postal/city-alias-schema.d.ts.map} +1 -1
  314. package/out/{postal-city-alias-schema.js → postal/city-alias-schema.js} +1 -1
  315. package/out/{postal-city-alias-schema.js.map → postal/city-alias-schema.js.map} +1 -1
  316. package/out/{postal-city-candidate-schema.d.ts → postal/city-candidate-schema.d.ts} +3 -3
  317. package/out/{postal-city-candidate-schema.d.ts.map → postal/city-candidate-schema.d.ts.map} +1 -1
  318. package/out/{postal-city-candidate-schema.js → postal/city-candidate-schema.js} +2 -2
  319. package/out/{postal-city-candidate-schema.js.map → postal/city-candidate-schema.js.map} +1 -1
  320. package/out/postal/index.d.ts +9 -0
  321. package/out/postal/index.d.ts.map +1 -0
  322. package/out/postal/index.js +9 -0
  323. package/out/postal/index.js.map +1 -0
  324. package/out/postcode-point-lookup.d.ts +10 -10
  325. package/out/postcode-point-lookup.d.ts.map +1 -1
  326. package/out/postcode-point-lookup.js +13 -13
  327. package/out/postcode-point-lookup.js.map +1 -1
  328. package/out/primary-preference.d.ts +13 -5
  329. package/out/primary-preference.d.ts.map +1 -1
  330. package/out/primary-preference.js +16 -8
  331. package/out/primary-preference.js.map +1 -1
  332. package/out/proximity-rerank.d.ts +2 -2
  333. package/out/proximity-rerank.d.ts.map +1 -1
  334. package/out/proximity-rerank.js +2 -2
  335. package/out/proximity-rerank.js.map +1 -1
  336. package/out/ranking-weights.d.ts +15 -3
  337. package/out/ranking-weights.d.ts.map +1 -1
  338. package/out/ranking-weights.js +21 -3
  339. package/out/ranking-weights.js.map +1 -1
  340. package/out/region-keys.d.ts +8 -8
  341. package/out/region-keys.d.ts.map +1 -1
  342. package/out/region-keys.js +9 -9
  343. package/out/region-keys.js.map +1 -1
  344. package/out/reverse.d.ts +6 -6
  345. package/out/reverse.d.ts.map +1 -1
  346. package/out/reverse.js +20 -29
  347. package/out/reverse.js.map +1 -1
  348. package/out/schema.d.ts +9 -0
  349. package/out/schema.d.ts.map +1 -1
  350. package/out/schema.js.map +1 -1
  351. package/out/search-fetch.d.ts +12 -10
  352. package/out/search-fetch.d.ts.map +1 -1
  353. package/out/search-fetch.js +21 -20
  354. package/out/search-fetch.js.map +1 -1
  355. package/out/sqlite-convention-source.d.ts +7 -7
  356. package/out/sqlite-convention-source.d.ts.map +1 -1
  357. package/out/sqlite-convention-source.js +5 -5
  358. package/out/sqlite-convention-source.js.map +1 -1
  359. package/out/sqlite-utils.d.ts +8 -8
  360. package/out/sqlite-utils.d.ts.map +1 -1
  361. package/out/sqlite-utils.js +7 -8
  362. package/out/sqlite-utils.js.map +1 -1
  363. package/out/{street-centroid-schema.d.ts → street/centroid-schema.d.ts} +6 -6
  364. package/out/{street-centroid-schema.d.ts.map → street/centroid-schema.d.ts.map} +1 -1
  365. package/out/{street-centroid-schema.js → street/centroid-schema.js} +5 -5
  366. package/out/{street-centroid-schema.js.map → street/centroid-schema.js.map} +1 -1
  367. package/out/{street-centroid.d.ts → street/centroid.d.ts} +6 -6
  368. package/out/street/centroid.d.ts.map +1 -0
  369. package/out/{street-centroid.js → street/centroid.js} +13 -19
  370. package/out/street/centroid.js.map +1 -0
  371. package/out/street/index.d.ts +13 -0
  372. package/out/street/index.d.ts.map +1 -0
  373. package/out/street/index.js +13 -0
  374. package/out/street/index.js.map +1 -0
  375. package/out/{street-morphology-fst-builder.d.ts → street/morphology-fst-builder.d.ts} +4 -4
  376. package/out/street/morphology-fst-builder.d.ts.map +1 -0
  377. package/out/{street-morphology-fst-builder.js → street/morphology-fst-builder.js} +18 -13
  378. package/out/street/morphology-fst-builder.js.map +1 -0
  379. package/out/{street-morphology-fst-loader.d.ts → street/morphology-fst-loader.d.ts} +5 -5
  380. package/out/street/morphology-fst-loader.d.ts.map +1 -0
  381. package/out/{street-morphology-fst-loader.js → street/morphology-fst-loader.js} +11 -10
  382. package/out/street/morphology-fst-loader.js.map +1 -0
  383. package/out/{street-name-lookup.d.ts → street/name-lookup.d.ts} +4 -7
  384. package/out/street/name-lookup.d.ts.map +1 -0
  385. package/out/{street-name-lookup.js → street/name-lookup.js} +9 -23
  386. package/out/street/name-lookup.js.map +1 -0
  387. package/out/{street-normalize.d.ts → street/normalize.d.ts} +25 -14
  388. package/out/street/normalize.d.ts.map +1 -0
  389. package/out/{street-normalize.js → street/normalize.js} +36 -17
  390. package/out/street/normalize.js.map +1 -0
  391. package/out/{street-segment-schema.d.ts → street/segment-schema.d.ts} +8 -8
  392. package/out/{street-segment-schema.d.ts.map → street/segment-schema.d.ts.map} +1 -1
  393. package/out/{street-segment-schema.js → street/segment-schema.js} +4 -4
  394. package/out/{street-segment-schema.js.map → street/segment-schema.js.map} +1 -1
  395. package/out/types.d.ts +18 -12
  396. package/out/types.d.ts.map +1 -1
  397. package/out/types.js.map +1 -1
  398. package/out/unified-schema.d.ts +5 -4
  399. package/out/unified-schema.d.ts.map +1 -1
  400. package/out/unified-schema.js +15 -18
  401. package/out/unified-schema.js.map +1 -1
  402. package/out/uprn/existence.d.ts +53 -0
  403. package/out/uprn/existence.d.ts.map +1 -0
  404. package/out/uprn/existence.js +61 -0
  405. package/out/uprn/existence.js.map +1 -0
  406. package/out/uprn/index.d.ts +9 -0
  407. package/out/uprn/index.d.ts.map +1 -0
  408. package/out/uprn/index.js +9 -0
  409. package/out/uprn/index.js.map +1 -0
  410. package/out/{uprn-lookup.d.ts → uprn/lookup.d.ts} +4 -4
  411. package/out/uprn/lookup.d.ts.map +1 -0
  412. package/out/{uprn-lookup.js → uprn/lookup.js} +11 -14
  413. package/out/uprn/lookup.js.map +1 -0
  414. package/out/{uprn-schema.d.ts → uprn/schema.d.ts} +4 -4
  415. package/out/uprn/schema.d.ts.map +1 -0
  416. package/out/{uprn-schema.js → uprn/schema.js} +4 -4
  417. package/out/uprn/schema.js.map +1 -0
  418. package/out/weights-overlay-linker.d.ts +184 -26
  419. package/out/weights-overlay-linker.d.ts.map +1 -1
  420. package/out/weights-overlay-linker.js +338 -86
  421. package/out/weights-overlay-linker.js.map +1 -1
  422. package/package.json +465 -269
  423. package/out/address-point-interpolation.d.ts.map +0 -1
  424. package/out/address-point-interpolation.js.map +0 -1
  425. package/out/address-point-schema.d.ts.map +0 -1
  426. package/out/address-point-schema.js.map +0 -1
  427. package/out/address-point.d.ts.map +0 -1
  428. package/out/address-point.js.map +0 -1
  429. package/out/ancestry-backfill.d.ts.map +0 -1
  430. package/out/ancestry-backfill.js.map +0 -1
  431. package/out/ancestry.d.ts.map +0 -1
  432. package/out/ancestry.js.map +0 -1
  433. package/out/candidate/shard-fold.d.ts +0 -31
  434. package/out/candidate/shard-fold.d.ts.map +0 -1
  435. package/out/candidate/shard-fold.js.map +0 -1
  436. package/out/convention-schema.d.ts.map +0 -1
  437. package/out/convention-schema.js.map +0 -1
  438. package/out/convention.d.ts.map +0 -1
  439. package/out/convention.js.map +0 -1
  440. package/out/fst-autocomplete.d.ts.map +0 -1
  441. package/out/fst-autocomplete.js.map +0 -1
  442. package/out/fst-builder.d.ts.map +0 -1
  443. package/out/fst-builder.js.map +0 -1
  444. package/out/fst-deserialize-web.d.ts.map +0 -1
  445. package/out/fst-deserialize-web.js.map +0 -1
  446. package/out/fst-freshness.d.ts.map +0 -1
  447. package/out/fst-freshness.js.map +0 -1
  448. package/out/fst-matcher.d.ts.map +0 -1
  449. package/out/fst-matcher.js.map +0 -1
  450. package/out/fst-serialize.d.ts.map +0 -1
  451. package/out/fst-serialize.js.map +0 -1
  452. package/out/fst-types.d.ts.map +0 -1
  453. package/out/fst-types.js.map +0 -1
  454. package/out/fts-query.d.ts.map +0 -1
  455. package/out/fts-query.js.map +0 -1
  456. package/out/fts.d.ts.map +0 -1
  457. package/out/fts.js.map +0 -1
  458. package/out/geonames-aliases.d.ts.map +0 -1
  459. package/out/geonames-aliases.js.map +0 -1
  460. package/out/geonames-postal.d.ts.map +0 -1
  461. package/out/geonames-postal.js.map +0 -1
  462. package/out/poi-lookup.d.ts.map +0 -1
  463. package/out/poi-lookup.js.map +0 -1
  464. package/out/poi-schema.d.ts.map +0 -1
  465. package/out/poi-schema.js.map +0 -1
  466. package/out/postal-city-alias-lookup.d.ts.map +0 -1
  467. package/out/postal-city-alias-lookup.js.map +0 -1
  468. package/out/sharding.d.ts +0 -114
  469. package/out/sharding.d.ts.map +0 -1
  470. package/out/sharding.js.map +0 -1
  471. package/out/street-centroid.d.ts.map +0 -1
  472. package/out/street-centroid.js.map +0 -1
  473. package/out/street-morphology-fst-builder.d.ts.map +0 -1
  474. package/out/street-morphology-fst-builder.js.map +0 -1
  475. package/out/street-morphology-fst-loader.d.ts.map +0 -1
  476. package/out/street-morphology-fst-loader.js.map +0 -1
  477. package/out/street-name-lookup.d.ts.map +0 -1
  478. package/out/street-name-lookup.js.map +0 -1
  479. package/out/street-normalize.d.ts.map +0 -1
  480. package/out/street-normalize.js.map +0 -1
  481. package/out/uprn-lookup.d.ts.map +0 -1
  482. package/out/uprn-lookup.js.map +0 -1
  483. package/out/uprn-schema.d.ts.map +0 -1
  484. package/out/uprn-schema.js.map +0 -1
  485. package/weights-overlay-linker.ts +0 -377
  486. /package/{name-score.ts → lib/name-score.ts} +0 -0
  487. /package/{polygon-schema.ts → lib/polygon-schema.ts} +0 -0
  488. /package/{postal-city-alias-schema.ts → lib/postal/city-alias-schema.ts} +0 -0
@@ -23,8 +23,6 @@
23
23
  * `bbox` field on {@link FindPlaceQuery}).
24
24
  */
25
25
 
26
- import { DatabaseSync } from "node:sqlite"
27
-
28
26
  import { jaroWinkler, levenshteinSimilarity } from "@mailwoman/match/comparators"
29
27
  import {
30
28
  expandPlacetypeFilter,
@@ -33,6 +31,8 @@ import {
33
31
  type GazetteerArtifactCoverage,
34
32
  } from "@mailwoman/resolver"
35
33
  import { haversineKm } from "@mailwoman/spatial"
34
+ import { DatabaseClient } from "@mailwoman/sqlite/client"
35
+ import type { PathBuilderLike } from "path-ts"
36
36
 
37
37
  import {
38
38
  CANDIDATE_ANCESTOR_TABLE,
@@ -40,31 +40,31 @@ import {
40
40
  intervalContains,
41
41
  type CandidateAncestorTable,
42
42
  type IntervalLabel,
43
- } from "./candidate-ancestors-schema.ts"
44
- import { CANDIDATE_FTS_TABLE } from "./candidate-fts.ts"
45
- import type { CandidateTable, CountryCodeTable, PlacetypeCodeTable } from "./candidate-schema.ts"
46
- import { readGazetteerCoverageManifest } from "./coverage-manifest-schema.ts"
47
- import { referentialFromPopulation } from "./place-importance-schema.ts"
48
- import { POSTAL_CITY_CANDIDATE_TABLE, type PostalCityCandidateTable } from "./postal-city-candidate-schema.ts"
49
- import { rankByPrimaryPreference, type RankedRow, RERANK_FETCH } from "./primary-preference.ts"
50
- import { applyProximityRerank } from "./proximity-rerank.ts"
51
- import { REGION_CLASS_PLACETYPES, regionQualifierProbeKeys } from "./region-keys.ts"
52
- import { allRows, hasColumn, hasTable } from "./sqlite-utils.ts"
53
- import { type NameKey, normalizeLocalityForKey, stripLocalityQualifier } from "./street-normalize.ts"
54
- import type { FindPlaceQuery, PlaceCandidate, PlaceLookup, WOFPlacetype } from "./types.ts"
55
-
56
- export { rankByPrimaryPreference } from "./primary-preference.ts"
57
- export type { RankedRow } from "./primary-preference.ts"
43
+ } from "#candidate-ancestors-schema"
44
+ import { CANDIDATE_FTS_TABLE } from "#candidate-fts"
45
+ import type { CandidateDatabase, CandidateTable, CountryCodeTable, PlacetypeCodeTable } from "#candidate-schema"
46
+ import { readGazetteerCoverageManifest } from "#coverage-manifest-schema"
47
+ import { referentialFromPopulation } from "#place-importance-schema"
48
+ import { POSTAL_CITY_CANDIDATE_TABLE, type PostalCityCandidateTable } from "#postal/city-candidate-schema"
49
+ import { rankByPrimaryPreference, type RankedRow, RERANK_FETCH } from "#primary-preference"
50
+ import { applyProximityRerank } from "#proximity-rerank"
51
+ import { REGION_CLASS_PLACETYPES, regionQualifierProbeKeys } from "#region-keys"
52
+ import { allRows, hasColumn, hasTable } from "#sqlite-utils"
53
+ import { type NameKey, normalizeLocalityForKey, stripLocalityQualifier } from "#street/normalize"
54
+ import type { FindPlaceQuery, PlaceCandidate, PlaceLookup, WOFPlacetype } from "#types"
55
+
56
+ export { rankByPrimaryPreference } from "#primary-preference"
57
+ export type { RankedRow } from "#primary-preference"
58
58
 
59
59
  export interface WOFCandidateTableLookupOpts {
60
60
  /**
61
61
  * Path to a `candidate.db` built by `build-candidate.ts`. Opened read-only.
62
62
  */
63
- databasePath?: string
63
+ databasePath?: PathBuilderLike
64
64
  /**
65
65
  * Pre-opened handle (tests / shared connections). Mutually exclusive with `databasePath`.
66
66
  */
67
- database?: DatabaseSync
67
+ database?: DatabaseClient<CandidateDatabase>
68
68
  /**
69
69
  * #1882 opt-in: exempt `name_role = 'variant'` aliases — the holder's own primary name in another orthography,
70
70
  * stamped by the build's own-name detector — from the cross-country primary-preference penalty. No-ops on an artifact
@@ -126,12 +126,12 @@ function wordFuzzySimilarity(a: string, b: string): number {
126
126
  }
127
127
 
128
128
  /**
129
- * Postcode-containment re-rank gate radius (km) — the SAME value the resolver's country pass measures at
130
- * (`POSTCODE_COUNTRY_COHERENCE_GATE_KM`, resolver/postcode-country-coherence.ts): a locality within this distance of
131
- * the postcode's own centroid counts as "containing" it. One number, two passes — a divergence here would make the two
132
- * mechanisms disagree about what is proximal.
129
+ * Postcode-containment re-rank check radius (km) — the SAME value the resolver's country pass measures at
130
+ * (`POSTCODE_COUNTRY_COHERENCE_THRESHOLD_KM`, resolver/postcode-country-coherence.ts): a locality within this distance
131
+ * of the postcode's own centroid counts as "containing" it. One number, two passes — a divergence here would make the
132
+ * two mechanisms disagree about what is proximal.
133
133
  */
134
- const POSTCODE_CONTAINMENT_GATE_KM = 25
134
+ const POSTCODE_CONTAINMENT_THRESHOLD_KM = 25
135
135
 
136
136
  /**
137
137
  * Unpadded character-trigrams of `s`, OR'd into an FTS5 trigram MATCH query (each quoted so FTS treats it as a literal
@@ -156,9 +156,13 @@ function ftsTrigramQuery(s: string): string {
156
156
  * Node {@link PlaceLookup} over `candidate.db`. Drop-in for {@link WOFSQLitePlaceLookup} in `createWOFResolver(backend)`
157
157
  * — same `findPlace` contract, population-first ranking.
158
158
  */
159
- export class WOFCandidateTableLookup implements PlaceLookup {
160
- #db: DatabaseSync
161
- #ownsDB: boolean
159
+ export class WOFCandidateTableLookup implements PlaceLookup, Disposable {
160
+ #db: DatabaseClient<CandidateDatabase>
161
+ /**
162
+ * Resources this instance opened. A connection handed in by a caller is NOT in here, so disposal cannot reach it —
163
+ * ownership is membership rather than a flag a later branch has to check.
164
+ */
165
+ readonly #resources = new DisposableStack()
162
166
  readonly #countryToID = new Map<string, number>()
163
167
  readonly #idToCountry = new Map<number, string>()
164
168
  readonly #placetypeToID = new Map<string, number>()
@@ -167,29 +171,29 @@ export class WOFCandidateTableLookup implements PlaceLookup {
167
171
  * Prepared `(name_key, postcode)` probe for the #741 postal-city side-index — `undefined` when the
168
172
  * `postal_city_candidate` table isn't present, so a candidate.db built without it is byte-stable.
169
173
  */
170
- readonly #postalCityProbe: ReturnType<DatabaseSync["prepare"]> | undefined
174
+ readonly #postalCityProbe: ReturnType<DatabaseClient["prepare"]> | undefined
171
175
  /**
172
176
  * Prepared FTS5-trigram MATCH probe for the typo-tolerant fallback — `undefined` when the `candidate_fts` index isn't
173
177
  * present, so a candidate.db built without it is byte-stable (the fuzzy path is skipped, exactly like today).
174
178
  */
175
- readonly #ftsProbe: ReturnType<DatabaseSync["prepare"]> | undefined
179
+ readonly #ftsProbe: ReturnType<DatabaseClient["prepare"]> | undefined
176
180
  /**
177
- * Prepared UNFILTERED existence probe (`name_key` present anywhere, ignoring country/placetype/bbox). Gates the fuzzy
178
- * fallback: fuzzy is a TYPO corrector, so it engages only when the name doesn't exist in the gazetteer at all. A name
179
- * that DOES exist but missed under the active filter is a filter miss (e.g. a placer misroute "Vienna, Austria"→IT),
180
- * not a spelling miss — fuzzing it would scrape an unrelated same-country place and defeat the cascade's
181
- * country-agnostic retry. Prepared only alongside `#ftsProbe`.
181
+ * Prepared UNFILTERED existence probe (`name_key` present anywhere, ignoring country/placetype/bbox). Checks the
182
+ * fuzzy fallback: fuzzy is a TYPO corrector, so it engages only when the name doesn't exist in the gazetteer at all.
183
+ * A name that DOES exist but missed under the active filter is a filter miss (e.g. a placer misroute "Vienna,
184
+ * Austria"→IT), not a spelling miss — fuzzing it would scrape an unrelated same-country place and defeat the
185
+ * cascade's country-agnostic retry. Prepared only alongside `#ftsProbe`.
182
186
  */
183
- readonly #nameKeyExistsProbe: ReturnType<DatabaseSync["prepare"]> | undefined
187
+ readonly #nameKeyExistsProbe: ReturnType<DatabaseClient["prepare"]> | undefined
184
188
  /**
185
189
  * Facts this candidate DB declares about itself — the coverage manifest (`country_coverage` + `country_bbox`) the
186
190
  * gazetteer build emits, read once at open. `undefined` when the artifact predates the manifest, so every consumer
187
- * (the hard-country coverage gate, guard-B plausibility) falls back to its code constants byte-identically.
191
+ * (the hard-country coverage check, guard-B plausibility) falls back to its code constants byte-identically.
188
192
  */
189
193
  readonly artifactCoverage: GazetteerArtifactCoverage | undefined
190
194
  /**
191
195
  * `", importance"` when this artifact carries the #28 fame column, `""` when it does not — spliced into the probe's
192
- * SELECT list. Existence-gated exactly like `#ftsProbe` and `#postalCityProbe` above, and for the same reason: a
196
+ * SELECT list. Existence-restricted exactly like `#ftsProbe` and `#postalCityProbe` above, and for the same reason: a
193
197
  * candidate.db built before the column is a valid artifact, and naming a column it lacks would turn a stale gazetteer
194
198
  * into `no such column` on the first keystroke rather than into "no fame signal", which is what it is.
195
199
  */
@@ -208,22 +212,22 @@ export class WOFCandidateTableLookup implements PlaceLookup {
208
212
  /**
209
213
  * Prepared chain probe over the `candidate_ancestor` sidecar — `undefined` when the artifact predates it.
210
214
  */
211
- readonly #ancestorsProbe: ReturnType<DatabaseSync["prepare"]> | undefined
215
+ readonly #ancestorsProbe: ReturnType<DatabaseClient["prepare"]> | undefined
212
216
  readonly #ancestorsCache = new Map<number, Ancestor[]>()
213
217
  /**
214
218
  * Prepared interval-label probe over `candidate_interval` — `undefined` when the artifact predates the sidecar, which
215
- * is what makes the admin-containment re-rank (#1717 stage 2) capability-gated: without it,
219
+ * is what makes the admin-containment re-rank (#1717 stage 2) capability-restricted: without it,
216
220
  * `FindPlaceQuery.regionQualifier` is ignored, no candidate carries a `containedByQualifier` stamp, and the resolver
217
- * walk reports the lever `unavailable` instead of silently dead.
221
+ * walk reports the change `unavailable` instead of silently dead.
218
222
  */
219
- readonly #intervalProbe: ReturnType<DatabaseSync["prepare"]> | undefined
223
+ readonly #intervalProbe: ReturnType<DatabaseClient["prepare"]> | undefined
220
224
  readonly #intervalCache = new Map<number, IntervalLabel | null>()
221
225
  /**
222
226
  * Prepared qualifier probe: the region-band rows (plus `country` — the region SLOT can hold a mislabeled country
223
227
  * name, "Moscow, Russia" parses region="Russia") for one folded qualifier key. `undefined` when the artifact lacks
224
228
  * the sidecar or the placetype dictionary lacks the band entirely.
225
229
  */
226
- readonly #qualifierProbe: ReturnType<DatabaseSync["prepare"]> | undefined
230
+ readonly #qualifierProbe: ReturnType<DatabaseClient["prepare"]> | undefined
227
231
  /**
228
232
  * The ancestor lineage of a resolved place — nearest-first (locality-tier → county → region → … → country), the same
229
233
  * order the FTS backend's `ancestorLineage` serves, read from the `candidate_ancestor` sidecar in one clustered
@@ -240,10 +244,8 @@ export class WOFCandidateTableLookup implements PlaceLookup {
240
244
  constructor(opts: WOFCandidateTableLookupOpts) {
241
245
  if (opts.database) {
242
246
  this.#db = opts.database
243
- this.#ownsDB = false
244
247
  } else if (opts.databasePath) {
245
- this.#db = new DatabaseSync(opts.databasePath, { readOnly: true })
246
- this.#ownsDB = true
248
+ this.#db = this.#resources.use(new DatabaseClient<CandidateDatabase>(opts.databasePath, { readOnly: true }))
247
249
  } else {
248
250
  throw new Error("WOFCandidateTableLookup needs `databasePath` or `database`")
249
251
  }
@@ -285,7 +287,7 @@ export class WOFCandidateTableLookup implements PlaceLookup {
285
287
  this.#variantAliasExemption = opts.variantAliasExemption === true
286
288
  this.#roleSelect = this.#hasNameRole ? ", name_role" : ""
287
289
 
288
- // Ancestors sidecar (#1717): existence-gated like the probes above, and the CAPABILITY gates with
290
+ // Ancestors sidecar (#1717): existence-restricted like the probes above, and the CAPABILITY checks with
289
291
  // it — see the `ancestors` property doc for why an older artifact must read as "no ancestors()"
290
292
  // rather than as a method that answers [] everywhere.
291
293
  if (hasTable(this.#db, CANDIDATE_ANCESTOR_TABLE)) {
@@ -297,7 +299,7 @@ export class WOFCandidateTableLookup implements PlaceLookup {
297
299
  this.ancestors = (id) => this.#ancestorLineage(id)
298
300
  }
299
301
 
300
- // Admin-containment re-rank (#1717 stage 2): gated on the interval half of the sidecar (built in
302
+ // Admin-containment re-rank (#1717 stage 2): conditioned on the interval half of the sidecar (built in
301
303
  // the same pass as the closure rows; probed separately so a hand-degraded artifact degrades
302
304
  // truthfully) AND on the placetype dictionary carrying the qualifier band at all.
303
305
  if (this.#ancestorsProbe && hasTable(this.#db, CANDIDATE_INTERVAL_TABLE)) {
@@ -314,7 +316,7 @@ export class WOFCandidateTableLookup implements PlaceLookup {
314
316
  }
315
317
  }
316
318
 
317
- // Coverage manifest (survey candidate #2): the artifact's own coverage facts, existence-gated like
319
+ // Coverage manifest (survey candidate #2): the artifact's own coverage facts, existence-restricted like
318
320
  // the probes above — a candidate.db built before the manifest reads `undefined` and consumers keep
319
321
  // their code-constant fallbacks byte-identically.
320
322
  this.artifactCoverage = readGazetteerCoverageManifest(this.#db)
@@ -396,7 +398,7 @@ export class WOFCandidateTableLookup implements PlaceLookup {
396
398
  * Is `sprID` contained by ANY of the qualifier's rows? Interval first — {@link intervalContains}, O(1), reflexive —
397
399
  * then the closure rows where intervals abstain: the interval forest encodes only the CANONICAL parent per place, so
398
400
  * a `false` there means "not contained along the canonical hierarchy", and the chain probe (one clustered read of
399
- * ≤{@link MAX_ANCESTOR_DEPTH} rows) is the complete record that settles it.
401
+ * ≤{@link MAX_ANCESTOR_DEPTH} rows) is the complete record that determines the result.
400
402
  */
401
403
  #containedByQualifier(sprID: number, qualifierIDs: ReadonlySet<number>, qualifierLabels: IntervalLabel[]): boolean {
402
404
  if (qualifierIDs.has(sprID)) return true
@@ -491,7 +493,7 @@ export class WOFCandidateTableLookup implements PlaceLookup {
491
493
  // cannot reach a neighbourhood-tier namesake, so a CONTAINED one is structurally invisible no matter
492
494
  // how the list reorders — the Astoria class: Queens' Astoria is a WOF neighbourhood, and the walk
493
495
  // answered the Oregon locality under `qualifier="NY"` because nothing in the pool sat under NY. The
494
- // widening is injection-only and triple-gated: the band is explicit (neighbourhood/macrohood/microhood
496
+ // widening is injection-only and triple-conditioned: the band is explicit (neighbourhood/macrohood/microhood
495
497
  // — never region or country tiers), admission still requires the sidecar's containment proof, and only
496
498
  // primary-keyed rows enter (an alias-keyed neighbourhood is the #1626 scrape class). Recall can only
497
499
  // widen, and only toward rows the qualifier vouches for. `opts.shapeFilters`' bbox clause is
@@ -601,7 +603,7 @@ export class WOFCandidateTableLookup implements PlaceLookup {
601
603
 
602
604
  // #741: postcode-keyed postal-city alias. An exact `(name_key, postcode)` hit resolves a
603
605
  // user-typed POSTAL city ("Antioch", 37013) to the geographic locality the postcode sits in
604
- // ("Nashville"), bypassing the population/region ranking that can't see the postcode. Gated on
606
+ // ("Nashville"), bypassing the population/region ranking that can't see the postcode. Conditioned on
605
607
  // the side-index being present, a postcode in the query, and a locality-tier request — so the
606
608
  // common (no-postcode / non-locality) path is untouched. A hit short-circuits: the postcode is
607
609
  // an exact, high-confidence disambiguator, so we return the single geographic locality.
@@ -632,7 +634,7 @@ export class WOFCandidateTableLookup implements PlaceLookup {
632
634
  // SHAPE subset (placetype/bbox/primary — everything but the country scope) is kept separately
633
635
  // because the admin-containment injection probe (#1717 stage 2) runs under the shape conds
634
636
  // WITHOUT the country: bypassing a locale-inferred country scope for a qualifier-vouched
635
- // candidate is the lever's whole point, and it is the one filter injection may cross.
637
+ // candidate is the change's whole point and the one filter injection may cross.
636
638
  const filters: string[] = []
637
639
  const filterParams: Array<string | number> = []
638
640
  const shapeFilters: string[] = []
@@ -667,7 +669,7 @@ export class WOFCandidateTableLookup implements PlaceLookup {
667
669
  }
668
670
 
669
671
  // The re-reading guard (#1632, the #1626 rationale generalized to the caller): a probe whose surface
670
- // is a token cut out of a longer classified span never NAMED an alias, so alias-keyed rows must not
672
+ // is a token taken out of a longer classified span never NAMED an alias, so alias-keyed rows must not
671
673
  // answer it — 'Savile Row''s token 'Row' resolved Rhu, Scotland (585 km) through the village's
672
674
  // historical-name alias key. Whole-input bare probes never set this, keeping the exonym recall the
673
675
  // #1546 note protects (Москва's alias rows answer 'Moscow').
@@ -763,7 +765,7 @@ export class WOFCandidateTableLookup implements PlaceLookup {
763
765
  // the same on either backend. The country/placetype/bbox/region filters still apply via `probe`.
764
766
  // Skipped when the index is absent (byte-stable for an older candidate.db).
765
767
  //
766
- // Gate: only when the name doesn't exist in the gazetteer AT ALL (unfiltered). A name that exists
768
+ // Condition: only when the name doesn't exist in the gazetteer AT ALL (unfiltered). A name that exists
767
769
  // but missed under the active country/placetype/bbox filter is a FILTER miss, not a spelling miss
768
770
  // — fuzzing it scrapes an unrelated same-filter place ("Vienna, Austria" misrouted to IT would
769
771
  // pull a tiny Italian name_key near Siena) and masks the cascade's country-agnostic retry that
@@ -821,7 +823,7 @@ export class WOFCandidateTableLookup implements PlaceLookup {
821
823
 
822
824
  let rows = cascade(regionParentID)
823
825
  // #1731: whether the rows the caller receives came from the UNSCOPED fallback below — the backend's
824
- // interior gate the resolver-side trace (#1721) cannot otherwise see. Stamped onto every returned
826
+ // interior check the resolver-side trace (#1721) cannot otherwise see. Stamped onto every returned
825
827
  // place, because the re-admission path is exactly where a wrong-instance namesake enters.
826
828
  let regionScopeMiss = false
827
829
 
@@ -838,8 +840,8 @@ export class WOFCandidateTableLookup implements PlaceLookup {
838
840
  // holds 75001, not the one that holds a 75001-free namesake). The resolver sends this flag on locality
839
841
  // lookups when `ResolveOpts.postcodeContainmentCoherence` is on. Strictly beneath the #741 postal-city
840
842
  // short-circuit above — an exact (name, postcode) hit IS the answer and outranks any re-rank — and after
841
- // the region-scope fallback, so it sees the final row set. Rows within the gate sort by distance first;
842
- // the out-gate tail keeps its original population-first order. No in-gate row, or no postcode row in
843
+ // the region-scope fallback, so it sees the final row set. Rows within the radius sort by distance first;
844
+ // the out-of-radius tail keeps its original population-first order. No in-radius row, or no postcode row in
843
845
  // the candidate table → unchanged (byte-identical to the flag-off path).
844
846
  if (
845
847
  query.postcode &&
@@ -850,32 +852,32 @@ export class WOFCandidateTableLookup implements PlaceLookup {
850
852
  const anchor = this.#postcodeAnchor(query.postcode, query.country)
851
853
 
852
854
  if (anchor) {
853
- const inGate: Array<{ row: RankedRow<CandidateRow>; distanceKm: number }> = []
854
- const outGate: RankedRow<CandidateRow>[] = []
855
+ const insideThreshold: Array<{ row: RankedRow<CandidateRow>; distanceKm: number }> = []
856
+ const outsideThreshold: RankedRow<CandidateRow>[] = []
855
857
 
856
858
  for (const row of rows) {
857
859
  const distanceKm = haversineKm(anchor.lat, anchor.lon, Number(row.latitude), Number(row.longitude))
858
860
 
859
- if (distanceKm <= POSTCODE_CONTAINMENT_GATE_KM) {
860
- inGate.push({ row, distanceKm })
861
+ if (distanceKm <= POSTCODE_CONTAINMENT_THRESHOLD_KM) {
862
+ insideThreshold.push({ row, distanceKm })
861
863
  } else {
862
- outGate.push(row)
864
+ outsideThreshold.push(row)
863
865
  }
864
866
  }
865
867
 
866
- if (inGate.length) {
868
+ if (insideThreshold.length) {
867
869
  // oxlint-disable-next-line unicorn/no-array-sort -- sorts a freshly-built array; toSorted would double-allocate on a hot path
868
- inGate.sort((a, b) => a.distanceKm - b.distanceKm)
869
- rows = [...inGate.map(({ row }) => row), ...outGate]
870
+ insideThreshold.sort((a, b) => a.distanceKm - b.distanceKm)
871
+ rows = [...insideThreshold.map(({ row }) => row), ...outsideThreshold]
870
872
  }
871
873
  }
872
874
  }
873
875
 
874
876
  // Admin-containment re-rank (#1717 stage 2): LAST, on the final row set — the qualifier is the
875
877
  // address's outermost explicit statement, so its partition outranks the postcode-proximity order
876
- // above (contained rows keep that order among themselves). Capability-gated on the sidecar
878
+ // above (contained rows keep that order among themselves). Capability-conditioned on the sidecar
877
879
  // (`#qualifierProbe`); when the artifact predates it, `regionQualifier` is ignored, no stamp is
878
- // written, and the resolver walk reports the lever `unavailable`.
880
+ // written, and the resolver walk reports the change `unavailable`.
879
881
  if (query.regionQualifier?.trim() && this.#qualifierProbe && this.#wantsLocality(query.placetype)) {
880
882
  rows = this.#applyAdminContainment(rows, query.regionQualifier.trim(), query.country, {
881
883
  nameKey,
@@ -893,13 +895,13 @@ export class WOFCandidateTableLookup implements PlaceLookup {
893
895
  id: Number(row.spr_id),
894
896
  name: String(row.name ?? ""),
895
897
  placetype: (this.#idToPlacetype.get(Number(row.placetype_id)) ?? "") as WOFPlacetype,
896
- // Surfaced so the cascade can country-gate a postcode by the resolved locality (an ambiguous
898
+ // Surfaced so the cascade can country-restrict a postcode by the resolved locality (an ambiguous
897
899
  // international postcode like 10115 = Berlin DE AND New York US must not out-resolve the city).
898
900
  country: this.#idToCountry.get(Number(row.country_id)) ?? "",
899
901
  lat: Number(row.latitude),
900
902
  lon: Number(row.longitude),
901
903
  // `score` stays the RAW population rank (`-neg_rank`) — it feeds the resolver walk's absolute
902
- // `minWinningScore` gate (`resolve.ts`), which must see real prominence, never a penalized value.
904
+ // `minWinningScore` floor (`resolve.ts`), which must see real prominence, never a penalized value.
903
905
  score: -Number(row.neg_rank),
904
906
  // `prominence` carries the bounded cross-country primary preference (the effective, penalty-adjusted
905
907
  // rank). The walk ORDERS candidates by `prominence ?? score` (`resolve.ts`), so this is what makes the
@@ -921,6 +923,9 @@ export class WOFCandidateTableLookup implements PlaceLookup {
921
923
  // asked (a `regionQualifier` query over a sidecar-bearing artifact); its absence is what
922
924
  // the resolver walk reports as `unavailable` (meaning-of-zero).
923
925
  ...(row.containedByQualifier === undefined ? {} : { containedByQualifier: row.containedByQualifier }),
926
+ // #1893 — the exemption's firing mark, carried only when the ranker actually spared this row
927
+ // the cross-country penalty (see RankedRow.variantExempted).
928
+ ...(row.variantExempted ? { variantAliasExempted: true as const } : {}),
924
929
  // The two-score split's carry (ROAD_TO_V9 §2). `referential` names the prominence this
925
930
  // backend has always ordered by — `neg_rank` IS `-log10(population + 1)`, so the score and
926
931
  // the sort key are two readings of the same number.
@@ -965,9 +970,7 @@ export class WOFCandidateTableLookup implements PlaceLookup {
965
970
  return candidates
966
971
  }
967
972
 
968
- close(): void {
969
- if (this.#ownsDB) {
970
- this.#db.close()
971
- }
973
+ [Symbol.dispose](): void {
974
+ this.#resources[Symbol.dispose]()
972
975
  }
973
976
  }
@@ -17,14 +17,14 @@
17
17
 
18
18
  import { sql, type Kysely } from "kysely"
19
19
 
20
- import type { CandidateAncestorsDatabase } from "./candidate-ancestors-schema.ts"
21
- import type { CapitalTable } from "./capital-schema.ts"
22
- import type { NameKey } from "./street-normalize.ts"
20
+ import type { CandidateAncestorsDatabase } from "#candidate-ancestors-schema"
21
+ import type { CapitalTable } from "#capital-schema"
22
+ import type { NameKey } from "#street/normalize"
23
23
 
24
24
  /**
25
25
  * One candidate row. `name_key` + the four small int keys + `neg_rank` + `spr_id` form the clustered primary key; the
26
26
  * rest is denormalized so a resolve is one probe (no join to `spr`). Coordinates + bbox + name are nullable at the SQL
27
- * level (a postcode shard row may lack a bbox).
27
+ * level (a postcode extract row may lack a bbox).
28
28
  */
29
29
  export interface CandidateTable {
30
30
  /**
@@ -99,7 +99,7 @@ export interface CandidateTable {
99
99
  * core.
100
100
  *
101
101
  * NULL = no role detected. The column is WRITE-ONLY in this build generation: no ranking consumer reads it — a rank
102
- * penalty is its own future, D-rule-gated step with the `gloss_key` board as tripwire.
102
+ * penalty is its own future, D-rule-conditional step with the `gloss_key` board as regression check.
103
103
  */
104
104
  name_role: string | null
105
105
  }
@@ -7,15 +7,15 @@
7
7
  * ordered — the weighted-sum score and the exact-match tiering that ranks over it.
8
8
  */
9
9
 
10
- import type { DatabaseSync } from "node:sqlite"
11
-
12
10
  import { haversineKm } from "@mailwoman/spatial"
11
+ import type { DatabaseClient } from "@mailwoman/sqlite/client"
13
12
 
14
- import { exactMatchIDs, officialNameIDs } from "./exact-match.ts"
15
- import { compareReferential, referentialFromPopulation } from "./place-importance-schema.ts"
16
- import type { RankingWeights } from "./ranking-weights.ts"
17
- import type { RawSearchRow } from "./search-fetch.ts"
18
- import type { FindPlaceQuery, PlaceCandidate, WOFPlacetype } from "./types.ts"
13
+ import { exactMatchIDs, officialNameIDs } from "#exact-match"
14
+ import { foldQueryText } from "#fts/index"
15
+ import { compareReferential, referentialFromPopulation } from "#place-importance-schema"
16
+ import { populationBoostTerm, type RankingWeights } from "#ranking-weights"
17
+ import type { RawSearchRow } from "#search-fetch"
18
+ import type { FindPlaceQuery, PlaceCandidate, WOFPlacetype } from "#types"
19
19
 
20
20
  /**
21
21
  * Score one raw FTS row into a `PlaceCandidate`: the weighted sum over the negated BM25 baseline, the placetype /
@@ -95,14 +95,8 @@ export function candidateFromSearchRow(
95
95
 
96
96
  // Population boost: capped at `populationBoost` magnitude at `10^populationScaleLog10`
97
97
  // people. Missing population → no contribution. Never penalizes.
98
- let popTerm = 0
99
-
100
- if (row.population !== null && row.population > 0 && weights.populationScaleLog10 > 0) {
101
- const popLog = Math.log10(1 + row.population)
102
- const popFraction = Math.min(1, popLog / weights.populationScaleLog10)
103
- popTerm = weights.populationBoost * popFraction
104
- score += popTerm
105
- }
98
+ const popTerm = populationBoostTerm(row.population, weights)
99
+ score += popTerm
106
100
 
107
101
  // Combined prominence for the exact-tier sort when proximity hints are present: population
108
102
  // and nearness in the SAME additive units, so the map view / the user's location can win a
@@ -154,13 +148,13 @@ export function candidateFromSearchRow(
154
148
  }
155
149
 
156
150
  /**
157
- * Order `candidates` IN PLACE — the exact-match tier first when the shard can answer the name probes, otherwise plain
151
+ * Order `candidates` IN PLACE — the exact-match tier first when the extract can answer the name probes, otherwise plain
158
152
  * weighted-score order. Every candidate is stamped with its `exactMatch` flag on the way through.
159
153
  */
160
- export function rankCandidates(
154
+ export function rankCandidates<DB>(
161
155
  candidates: PlaceCandidate[],
162
156
  options: {
163
- db: DatabaseSync
157
+ db: DatabaseClient<DB>
164
158
  schemaName: string
165
159
  query: FindPlaceQuery
166
160
  weights: RankingWeights
@@ -204,12 +198,11 @@ export function rankCandidates(
204
198
  // widen recall, not to tie primaries. ME→Maine is untouched: 'ME' name-exact-matches
205
199
  // nothing, so the alias sub-tier still decides there. Population orders within each
206
200
  // sub-tier as before.
207
- const norm = (v: string): string => v.toLowerCase().trim().replaceAll(/\s+/g, " ")
208
- const needle = norm(query.text)
201
+ const needle = foldQueryText(query.text)
209
202
 
210
203
  // #936 option 3: an OFFICIAL name (preferred form in an official language of the place's
211
204
  // country, `names.official = 1`) counts as the place's own name for the sub-tier — "Åbo" is
212
- // Turku's name, not merely its alias. Floor-gated on the holder's population (see the
205
+ // Turku's name, not merely its alias. Floor-conditioned on the holder's population (see the
213
206
  // RankingWeights docstring for the measured 100k boundary). officialIDs ⊆ exactIDs by
214
207
  // construction (official rows are names rows), so only the sub-tier KIND changes.
215
208
  const officialIDs = weights.officialNameExact
@@ -226,7 +219,7 @@ export function rankCandidates(
226
219
  const kind = (c: PlaceCandidate): number => {
227
220
  if (!exactIDs.has(c.id as number)) return 0
228
221
 
229
- if (norm(String(c.name ?? "")) === needle) return 2
222
+ if (foldQueryText(String(c.name ?? "")) === needle) return 2
230
223
 
231
224
  return officialIDs?.has(c.id as number) ? 2 : 1
232
225
  }
@@ -14,13 +14,12 @@
14
14
  * keeps the coordinate radius from promoting a capital's same-name neighbours (`capitals.ts`).
15
15
  */
16
16
 
17
- import type { DatabaseSync } from "node:sqlite"
18
-
19
- import { tryParsingJSON } from "@mailwoman/core/objects"
17
+ import { tryParsingJSON } from "@mailwoman/core/json"
18
+ import type { DatabaseClient } from "@mailwoman/sqlite/client"
20
19
  import type { Kysely } from "kysely"
21
20
 
22
- import type { CapitalPoint } from "./capitals.ts"
23
- import { hasTable } from "./sqlite-utils.ts"
21
+ import type { CapitalPoint } from "#capitals"
22
+ import { hasTable } from "#sqlite-utils"
24
23
 
25
24
  /**
26
25
  * The table name the builder writes and the reader probes — one word, singular, matching the artifact's other reference
@@ -63,7 +62,7 @@ export async function createCapitalTable<DB extends { capital: CapitalTable }>(d
63
62
  * back to its next source rather than treating an old artifact as "no capitals" (the meaning-of-zero rule: a missing
64
63
  * table is UNMEASURED, an empty one is a finding).
65
64
  */
66
- export function readCapitalPoints(db: DatabaseSync): CapitalPoint[] | null {
65
+ export function readCapitalPoints<DB>(db: DatabaseClient<DB>): CapitalPoint[] | null {
67
66
  if (!hasTable(db, CAPITAL_TABLE)) return null
68
67
 
69
68
  const points: CapitalPoint[] = []
@@ -12,7 +12,7 @@
12
12
  * Matching is an IDENTITY test with three conjuncts: same country, within
13
13
  * {@link CAPITAL_MATCH_RADIUS_KM} of the reference point, and the candidate's own folded name a
14
14
  * member of the reference entry's folded name set (name + romanization + the source's alternate
15
- * names, so exonym rows — "Vienna" for Wien — still match). All three are load-bearing. The
15
+ * names, so exonym rows — "Vienna" for Wien — still match). All three are required. The
16
16
  * iteration-1 board run matched on country + coordinate alone, and the 25 km radius promoted
17
17
  * capital-ADJACENT namesakes instead of capitals: North Salt Lake beside the Utah seat, a Gujarat
18
18
  * Indiranagar beside Gandhinagar, Via delle Parti beside Perugia. The name set is what makes the
@@ -21,7 +21,7 @@
21
21
 
22
22
  import { haversineKm } from "@mailwoman/spatial"
23
23
 
24
- import { normalizeLocalityForKey } from "./street-normalize.ts"
24
+ import { normalizeLocalityForKey } from "#street/normalize"
25
25
 
26
26
  /**
27
27
  * Capital status of one candidate: national capital, admin-1 seat, or neither. Numeric so the resolver's promotion can
@@ -38,12 +38,13 @@
38
38
  * be wired as a post-step of the main `scripts/build-unified-wof.ts`.
39
39
  */
40
40
 
41
- import type { DatabaseSync } from "node:sqlite"
42
-
43
41
  import type { CoincidentLocality } from "@mailwoman/resolver"
44
42
  import { haversineKm } from "@mailwoman/spatial"
43
+ import type { DatabaseClient } from "@mailwoman/sqlite/client"
44
+ import { tableExists } from "@mailwoman/sqlite/introspection"
45
45
 
46
- import { allRows } from "./sqlite-utils.ts"
46
+ import type { WOFDatabase } from "#schema"
47
+ import { allRows } from "#sqlite-utils"
47
48
 
48
49
  /**
49
50
  * Table of places that hold more than one admin role — a locality that is also its county seat. Written by the
@@ -105,16 +106,12 @@ interface CandidateRow {
105
106
  pop: number
106
107
  }
107
108
 
108
- function tableExists(db: DatabaseSync, name: string): boolean {
109
- return !!db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name = ?").get(name)
110
- }
111
-
112
109
  /**
113
110
  * Derive the coincident-roles relation into `db`. Additive — only creates/replaces the `coincident_roles` table; never
114
111
  * touches `spr`/`names`/`ancestors`. Idempotent.
115
112
  */
116
113
  export function buildCoincidentRoles(
117
- db: DatabaseSync,
114
+ db: DatabaseClient<WOFDatabase>,
118
115
  opts: BuildCoincidentRolesOpts = {}
119
116
  ): BuildCoincidentRolesResult {
120
117
  const start = Date.now()
@@ -215,7 +212,7 @@ export function buildCoincidentRoles(
215
212
  /**
216
213
  * True iff the relation table exists. Used by the resolver to decide whether completion can run.
217
214
  */
218
- export function coincidentRolesExists(db: DatabaseSync): boolean {
215
+ export function coincidentRolesExists<DB>(db: DatabaseClient<DB>): boolean {
219
216
  return tableExists(db, COINCIDENT_ROLES_TABLE)
220
217
  }
221
218
 
@@ -224,7 +221,7 @@ export function coincidentRolesExists(db: DatabaseSync): boolean {
224
221
  * MULTIPLE same-name descendants; the consumer disambiguates (min distance → population → abstain). Returns an empty
225
222
  * map when the table is absent.
226
223
  */
227
- export function loadCoincidentRoles(db: DatabaseSync): Map<number, CoincidentRole[]> {
224
+ export function loadCoincidentRoles<DB>(db: DatabaseClient<DB>): Map<number, CoincidentRole[]> {
228
225
  const map = new Map<number, CoincidentRole[]>()
229
226
 
230
227
  if (!coincidentRolesExists(db)) return map
@@ -269,7 +266,7 @@ export function loadCoincidentRoles(db: DatabaseSync): Map<number, CoincidentRol
269
266
  * {@link loadCoincidentRoles}, carrying the canonical name and coordinates each coincident locality resolves to.
270
267
  * Returns an empty map when the relation table is absent.
271
268
  */
272
- export function loadCoincidentLocalities(db: DatabaseSync): Map<number, CoincidentLocality[]> {
269
+ export function loadCoincidentLocalities<DB>(db: DatabaseClient<DB>): Map<number, CoincidentLocality[]> {
273
270
  const map = new Map<number, CoincidentLocality[]>()
274
271
 
275
272
  if (coincidentRolesExists(db)) {
@@ -21,7 +21,7 @@
21
21
  * source).
22
22
  */
23
23
 
24
- import type { FindPlaceQuery, PlaceCandidate } from "./types.ts"
24
+ import type { FindPlaceQuery, PlaceCandidate } from "#types"
25
25
 
26
26
  /**
27
27
  * Soft-scoring weights for the `postcode_area_resolution` strategy: `pc·S_pc + name·S_name + pop·S_pop`.
@@ -76,13 +76,13 @@ export const WORLD_DEFAULT: ResolvedConvention = {
76
76
  export const BUILTIN_STRATEGY_NAMES = ["postcode_area_resolution", "fallback_fuzzy_name_match"] as const
77
77
 
78
78
  /**
79
- * Table name for the convention asset (#290). Carried here so the build script, the runtime source, and the shard
79
+ * Table name for the convention asset (#290). Carried here so the build script, the runtime source, and the extract
80
80
  * auto-detect all agree.
81
81
  */
82
82
  export const ADDRESS_CONVENTION_TABLE = "address_convention"
83
83
 
84
84
  /**
85
- * A named resolution primitive. Returns `null` to abstain (gate unmet / no data) → the dispatcher tries the next
85
+ * A named resolution primitive. Returns `null` to abstain (condition unmet / no data) → the dispatcher tries the next
86
86
  * strategy; returns an array (possibly empty) to claim the result.
87
87
  */
88
88
  export type Strategy = (query: FindPlaceQuery, convention: ResolvedConvention) => Promise<PlaceCandidate[] | null>
@@ -11,7 +11,7 @@
11
11
 
12
12
  import type { Kysely } from "kysely"
13
13
 
14
- import { ADDRESS_CONVENTION_TABLE } from "./convention.ts"
14
+ import { ADDRESS_CONVENTION_TABLE } from "#convention/index"
15
15
 
16
16
  /**
17
17
  * One convention profile, keyed by the WOF admin polygon it attaches to.
@@ -49,7 +49,7 @@ export type ConventionSchemaHandle = Pick<Kysely<ConventionDatabase>, "schema">
49
49
 
50
50
  /**
51
51
  * Create `address_convention`. The table name comes from {@link ADDRESS_CONVENTION_TABLE} so the build script, the
52
- * runtime source, and the shard auto-detect cannot drift apart.
52
+ * runtime source, and the extract auto-detect cannot drift apart.
53
53
  */
54
54
  export async function createAddressConventionTable(db: ConventionSchemaHandle): Promise<void> {
55
55
  await db.schema