@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
@@ -0,0 +1,144 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * Node reader for `nsul.db` — the GB UPRN → unit-postcode register (`nsul/schema.ts`). Two probes,
7
+ * both synchronous `.prepare()` hits in the `uprn/lookup.ts` style:
8
+ *
9
+ * - **`postcodeForUPRN(uprn)`**: primary-key hit on the `WITHOUT ROWID` table.
10
+ * - **`uprnsForPostcode(postcode)`**: the `pcds_compact` index, answering every UPRN the register
11
+ * assigns to one unit postcode with the point OS publishes for each — the "assigned points and
12
+ * their bound" the physical-constraint design record names as the prior's soft structure.
13
+ *
14
+ * ## `null` and `[]` are claims, scoped by coverage
15
+ *
16
+ * The register designates GB complete (every UPRN in AddressBase with a Code-Point Open postcode),
17
+ * and the builder writes `layer_coverage` with basis `designated` for every cell the register
18
+ * touches. Inside a covered cell an empty answer is evidence of absence: no GB UPRN by that number
19
+ * carries a Code-Point postcode, or no UPRN carries that postcode. Two absences the reader cannot
20
+ * tell from those are recorded in `nsul_meta` as counts rather than as rows — a UPRN whose `PCDS` is
21
+ * null (its postcode is not in Code-Point Open) and one Open UPRN publishes no coordinate for — so a
22
+ * caller building negative evidence reads the coverage table and those counts, not this reader
23
+ * alone. Outside coverage (Northern Ireland, the Isle of Man, the Channel Islands) the answer is
24
+ * UNKNOWN, per the meaning-of-zero rule.
25
+ */
26
+
27
+ import { DatabaseClient } from "@mailwoman/sqlite/client"
28
+
29
+ import { compactPostcode, type NSULDatabase } from "#nsul/schema"
30
+ import { prepareAll, prepareGet } from "#sqlite-utils"
31
+
32
+ /**
33
+ * The unit postcode the register assigns to a UPRN, in both stored forms.
34
+ */
35
+ export interface NSULPostcode {
36
+ /**
37
+ * As NSUL writes it — `RG40 4HR`.
38
+ */
39
+ pcds: string
40
+ /**
41
+ * Space removed — `RG404HR`, Code-Point Open's `spr.name` form.
42
+ */
43
+ pcdsCompact: string
44
+ }
45
+
46
+ /**
47
+ * One UPRN assigned to a unit postcode, with the point `uprn.db` holds for it.
48
+ */
49
+ export interface NSULAssignedPoint {
50
+ uprn: number
51
+ latitude: number
52
+ longitude: number
53
+ /**
54
+ * 48-bit short res-9 H3 cell, as `uprn.db` stores it.
55
+ */
56
+ h3Cell: number
57
+ }
58
+
59
+ export interface NSULLookupOpts {
60
+ /**
61
+ * Path to a `nsul.db` built by `mailwoman`'s gazetteer pipeline. Opened read-only.
62
+ */
63
+ databasePath?: string
64
+ /**
65
+ * Pre-opened handle (tests / shared connections). Mutually exclusive with `databasePath`.
66
+ */
67
+ database?: DatabaseClient<NSULDatabase>
68
+ }
69
+
70
+ interface PostcodeRow {
71
+ pcds: string
72
+ pcds_compact: string
73
+ }
74
+
75
+ interface PointRow {
76
+ uprn: number
77
+ lat: number
78
+ lon: number
79
+ h3_cell: number
80
+ }
81
+
82
+ /**
83
+ * Node reader over `nsul.db`. `implements Disposable` so callers can `using lookup = new NSULLookup(...)` — the same
84
+ * precedent as `UPRNLookup`.
85
+ */
86
+ export class NSULLookup implements Disposable {
87
+ #db: DatabaseClient<NSULDatabase>
88
+ /**
89
+ * Resources this instance opened. A connection handed in by a caller is NOT in here, so disposal cannot reach it —
90
+ * ownership is membership rather than a flag a later branch has to check.
91
+ */
92
+ readonly #resources = new DisposableStack()
93
+
94
+ readonly #postcodeProbe: (uprn: number) => PostcodeRow | undefined
95
+ readonly #pointsProbe: (pcdsCompact: string) => PointRow[]
96
+
97
+ constructor(opts: NSULLookupOpts) {
98
+ if (opts.database) {
99
+ this.#db = opts.database
100
+ } else if (opts.databasePath) {
101
+ this.#db = this.#resources.use(new DatabaseClient<NSULDatabase>(opts.databasePath, { readOnly: true }))
102
+ } else {
103
+ throw new Error("NSULLookup needs `databasePath` or `database`")
104
+ }
105
+
106
+ this.#postcodeProbe = prepareGet<[number], PostcodeRow, NSULDatabase>(
107
+ this.#db,
108
+ "SELECT pcds, pcds_compact FROM uprn_postcode WHERE uprn = ?"
109
+ )
110
+
111
+ this.#pointsProbe = prepareAll<[string], PointRow, NSULDatabase>(
112
+ this.#db,
113
+ "SELECT uprn, lat, lon, h3_cell FROM uprn_postcode WHERE pcds_compact = ? ORDER BY uprn"
114
+ )
115
+ }
116
+
117
+ /**
118
+ * The unit postcode the register assigns to `uprn`, or `null` when the register holds no row for it (see the module
119
+ * docstring for what that `null` claims).
120
+ */
121
+ postcodeForUPRN(uprn: number): NSULPostcode | null {
122
+ const row = this.#postcodeProbe(uprn)
123
+
124
+ return row ? { pcds: row.pcds, pcdsCompact: row.pcds_compact } : null
125
+ }
126
+
127
+ /**
128
+ * Every UPRN the register assigns to one unit postcode, with its published point, in ascending UPRN order. The key is
129
+ * compacted through {@link compactPostcode} first, so `PO21 1HR` and `PO211HR` answer identically. An empty array is
130
+ * the register's answer, scoped as the module docstring says.
131
+ */
132
+ uprnsForPostcode(postcode: string): NSULAssignedPoint[] {
133
+ return this.#pointsProbe(compactPostcode(postcode)).map((row) => ({
134
+ uprn: row.uprn,
135
+ latitude: row.lat,
136
+ longitude: row.lon,
137
+ h3Cell: row.h3_cell,
138
+ }))
139
+ }
140
+
141
+ [Symbol.dispose](): void {
142
+ this.#resources[Symbol.dispose]()
143
+ }
144
+ }
@@ -0,0 +1,130 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * Typed schema for `nsul.db` — the GB UPRN → unit-postcode register: the ONS **National Statistics
7
+ * UPRN Lookup** (NSUL) joined to the WGS84 point OS Open UPRN publishes for the same UPRN. One row per
8
+ * GB UPRN that carries a unit postcode AND has a published coordinate; the postcode is Code-Point
9
+ * Open's, so this table and `postcode-gb.bin` agree by construction on the universe of unit postcodes.
10
+ *
11
+ * ## Why this table exists
12
+ *
13
+ * Code-Point Open gives one coordinate per unit postcode; Open UPRN gives one coordinate per
14
+ * addressable object; neither says which object carries which postcode. NSUL does, as field `PCDS`,
15
+ * under OGL-UK-3.0. The `PO`-area measurement that produced this design (recorded on #1975) showed a
16
+ * nearest-centroid reconstruction of the register is exact on 69.6% of 531,266 UPRNs and a building
17
+ * footprint adds nothing, so the register is stored rather than inferred.
18
+ *
19
+ * ## Shape
20
+ *
21
+ * `uprn_postcode` is `WITHOUT ROWID` keyed on the UPRN: small fixed rows, probed by primary key, with
22
+ * one secondary index on `pcds_compact`. The postcode is stored twice on purpose — `pcds` exactly as
23
+ * NSUL writes it (`RG40 4HR`, one space) and `pcds_compact` with the space removed (`RG404HR`), which
24
+ * is the form Code-Point Open's `spr.name` uses, so the two artifacts join on a column rather than an
25
+ * expression. `lat`/`lon`/`h3_cell` are COPIED from `uprn.db` at build time by UPRN join — OS's own
26
+ * WGS84 columns, never a reprojection of NSUL's `GRIDGB1E`/`GRIDGB1N` — so a coordinate here is
27
+ * byte-identical to the one `uprn.db` holds for the same UPRN.
28
+ *
29
+ * The DB also embeds the layer-contract tables from `@mailwoman/core/layers`; the builder
30
+ * (`packages/mailwoman/lib/gazetteer-pipeline/nsul-layer.ts`) writes the manifest and coverage.
31
+ */
32
+
33
+ import type { LayerContractDatabase } from "@mailwoman/core/layers"
34
+ import { sql, type Kysely } from "kysely"
35
+
36
+ /**
37
+ * Resolution of the `h3_cell` column — the same res-9 spine `uprn.db` keys on, because the value is copied from it.
38
+ */
39
+ export const NSUL_H3_RESOLUTION = 9
40
+
41
+ /**
42
+ * Resolution of the layer's `layer_coverage` cells — coarse, per the contract, and the same as `uprn.db`'s so the two
43
+ * layers' coverage tables describe the same cells.
44
+ */
45
+ export const NSUL_COVERAGE_H3_RESOLUTION = 6
46
+
47
+ /**
48
+ * One UPRN with its unit postcode and the point OS publishes for it.
49
+ */
50
+ export interface UPRNPostcodeTable {
51
+ /**
52
+ * The Unique Property Reference Number — up to 12 digits, so always within `Number.MAX_SAFE_INTEGER`.
53
+ */
54
+ uprn: number
55
+ /**
56
+ * The unit postcode as NSUL writes it — outward code, one space, inward code (`RG40 4HR`).
57
+ */
58
+ pcds: string
59
+ /**
60
+ * {@link pcds} with the space removed (`RG404HR`) — the form Code-Point Open's `spr.name` carries, and the column
61
+ * `uprnsForPostcode` probes.
62
+ */
63
+ pcds_compact: string
64
+ /**
65
+ * WGS84 latitude, copied from `uprn.db` for the same UPRN.
66
+ */
67
+ lat: number
68
+ /**
69
+ * WGS84 longitude, copied from `uprn.db` for the same UPRN.
70
+ */
71
+ lon: number
72
+ /**
73
+ * 48-bit short H3 cell at {@link NSUL_H3_RESOLUTION}, copied from `uprn.db` for the same UPRN.
74
+ */
75
+ h3_cell: number
76
+ }
77
+
78
+ /**
79
+ * Build-provenance key/value pairs the fixed `layer_manifest` columns have no room for: the accounting counts, the
80
+ * header as found, the per-region row counts, the four attribution lines.
81
+ */
82
+ export interface NSULMetaTable {
83
+ key: string
84
+ value: string
85
+ }
86
+
87
+ export interface NSULDatabase extends LayerContractDatabase {
88
+ uprn_postcode: UPRNPostcodeTable
89
+ nsul_meta: NSULMetaTable
90
+ }
91
+
92
+ /**
93
+ * The compact form of a unit postcode: every space removed, upper-cased. `RG40 4HR` → `RG404HR`. The ONE derivation
94
+ * both the builder and every consumer share, so a caller holding NSUL's spaced form and one holding Code-Point's
95
+ * compact form reach the same key.
96
+ */
97
+ export function compactPostcode(pcds: string): string {
98
+ return pcds.replaceAll(/\s+/g, "").toUpperCase()
99
+ }
100
+
101
+ export async function createUPRNPostcodeTable(db: Kysely<NSULDatabase>): Promise<void> {
102
+ await db.schema
103
+ .createTable("uprn_postcode")
104
+ .addColumn("uprn", "integer", (c) => c.primaryKey())
105
+ .addColumn("pcds", "text", (c) => c.notNull())
106
+ .addColumn("pcds_compact", "text", (c) => c.notNull())
107
+ .addColumn("lat", "real", (c) => c.notNull())
108
+ .addColumn("lon", "real", (c) => c.notNull())
109
+ .addColumn("h3_cell", "integer", (c) => c.notNull())
110
+ .modifyEnd(sql`without rowid`)
111
+ .execute()
112
+ }
113
+
114
+ export async function createNSULMetaTable(db: Kysely<NSULDatabase>): Promise<void> {
115
+ await db.schema
116
+ .createTable("nsul_meta")
117
+ .addColumn("key", "text", (c) => c.primaryKey())
118
+ .addColumn("value", "text", (c) => c.notNull())
119
+ .execute()
120
+ }
121
+
122
+ /**
123
+ * The `pcds_compact` index the `uprnsForPostcode` probe reads. Builders call this AFTER the bulk load
124
+ * (index-after-load). There is no index on the spaced `pcds`: it is derivable from `pcds_compact` through
125
+ * {@link compactPostcode}, and a second index over 40 million rows would buy nothing a caller cannot get by compacting
126
+ * its key first.
127
+ */
128
+ export async function createNSULIndexes(db: Kysely<NSULDatabase>): Promise<void> {
129
+ await db.schema.createIndex("uprn_postcode_pcds_compact").on("uprn_postcode").column("pcds_compact").execute()
130
+ }
@@ -31,12 +31,11 @@
31
31
  * should read it; new code reads the split columns.
32
32
  */
33
33
 
34
- import type { DatabaseSync } from "node:sqlite"
35
-
36
34
  import { referentialFromPopulation } from "@mailwoman/core/resolver"
35
+ import type { DatabaseClient } from "@mailwoman/sqlite/client"
37
36
  import type { Kysely } from "kysely"
38
37
 
39
- import { allRows } from "./sqlite-utils.ts"
38
+ import { allRows } from "#sqlite-utils"
40
39
 
41
40
  //#region Schema
42
41
 
@@ -205,12 +204,12 @@ export type ImportanceSplitSource = (typeof IMPORTANCE_SPLIT_SOURCES)[keyof type
205
204
  *
206
205
  * There is deliberately no ORDER BY counterpart, and there should never be one: §2's policy is that this score is
207
206
  * carried and never ranked on. Without the column the select degrades to a literal `NULL` and the join is the empty
208
- * string, so a pre-split shard's query plan is byte-identical to what it was before the split. No shipped gazetteer
207
+ * string, so a pre-split extract's query plan is byte-identical to what it was before the split. No shipped gazetteer
209
208
  * carries the column yet, so today that degraded form is the only one anything builds.
210
209
  *
211
- * Call it ONCE per shard and cache the result — it runs a `PRAGMA`, and the callers are per-keystroke hot.
210
+ * Call it ONCE per extract and cache the result — it runs a `PRAGMA`, and the callers are per-keystroke hot.
212
211
  */
213
- export function encyclopedicClauses(db: DatabaseSync, schemaName: string): { select: string; join: string } {
212
+ export function encyclopedicClauses<DB>(db: DatabaseClient<DB>, schemaName: string): { select: string; join: string } {
214
213
  let present: boolean
215
214
 
216
215
  try {
@@ -300,7 +299,7 @@ export interface ImportanceSplit {
300
299
  /**
301
300
  * Does `table` exist in `db`, and if so which of `columns` does it have?
302
301
  */
303
- function tableColumns(db: DatabaseSync, table: string): Set<string> {
302
+ function tableColumns<DB>(db: DatabaseClient<DB>, table: string): Set<string> {
304
303
  try {
305
304
  const rows = allRows<{ name: string }>(db.prepare(`PRAGMA table_info(${table})`))
306
305
 
@@ -317,7 +316,7 @@ function tableColumns(db: DatabaseSync, table: string): Set<string> {
317
316
  * builder in particular must read the shipped population-only databases, the read-only 2026-08-05 staging database
318
317
  * (legacy conflated column), and post-split builds with one code path.
319
318
  */
320
- export function loadImportanceSplit(db: DatabaseSync): ImportanceSplit {
319
+ export function loadImportanceSplit<DB>(db: DatabaseClient<DB>): ImportanceSplit {
321
320
  const referential = new Map<number, number>()
322
321
  const encyclopedic = new Map<number, number>()
323
322
  const population = new Map<number, number>()
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+
7
+ export * from "#poi/lookup"
8
+ export * from "#poi/schema"
@@ -25,13 +25,12 @@
25
25
  * it).
26
26
  */
27
27
 
28
- import { DatabaseSync } from "node:sqlite"
29
-
30
28
  import { haversineKm, shortCellToInt, type H3Cell } from "@mailwoman/spatial"
29
+ import { DatabaseClient } from "@mailwoman/sqlite/client"
31
30
  import { gridDisk, latLngToCell } from "h3-js"
32
31
 
33
- import type { POICategoryCodeTable, POITable } from "./poi-schema.ts"
34
- import { allRows } from "./sqlite-utils.ts"
32
+ import type { POICategoryCodeTable, POIDatabase, POITable } from "#poi/schema"
33
+ import { allRows } from "#sqlite-utils"
35
34
 
36
35
  /**
37
36
  * Resolution the `poi` table's `h3_cell` column is keyed at — matches the builder (spec §3.4).
@@ -48,8 +47,9 @@ export const POI_H3_RESOLUTION = 9
48
47
  * unaffected: the loop breaks the ring it accumulates `limit` rows (cafe@Paris fills 20 by ring 2), so this ceiling
49
48
  * never enters their probe budget. Only sparse-but-present categories that never reach `limit` scan the fuller budget —
50
49
  * a cold, one-shot `mailwoman poi` path, not per-keystroke. 16 (not the bare threshold 14) leaves ~2 rings of margin so
51
- * the gate is stable against small db rebuilds, while staying ~4x tighter than the board's 25 km "roughly right place"
52
- * window (no wrong-city false positives). The browser reader passes its own smaller `maxRings` and is untouched.
50
+ * the radius is stable against small db rebuilds, while staying ~4x tighter than the board's 25 km "roughly right
51
+ * place" window (no wrong-city false positives). The browser reader passes its own smaller `maxRings` and is
52
+ * untouched.
53
53
  */
54
54
  const DEFAULT_MAX_RINGS = 16
55
55
 
@@ -112,7 +112,7 @@ export interface POISearchHit {
112
112
  distanceM?: number
113
113
  }
114
114
 
115
- export interface POILookupOpts {
115
+ export interface POILookupOpts<DB extends POIDatabase = POIDatabase> {
116
116
  /**
117
117
  * Path to a `poi.db` built by the (future) POI builder. Opened read-only.
118
118
  */
@@ -120,7 +120,7 @@ export interface POILookupOpts {
120
120
  /**
121
121
  * Pre-opened handle (tests / shared connections). Mutually exclusive with `databasePath`.
122
122
  */
123
- database?: DatabaseSync
123
+ database?: DatabaseClient<DB>
124
124
  }
125
125
 
126
126
  /**
@@ -140,36 +140,36 @@ type POIRow = Pick<
140
140
  >
141
141
 
142
142
  /**
143
- * Node reader over `poi.db`. `implements Disposable` so callers can `using lookup = new POILookup(...)` (or call
144
- * `[Symbol.dispose]()` explicitly), the same precedent as {@link WOFCandidateTableLookup} /
145
- * {@link WOFSQLitePlaceLookup}.
143
+ * Node reader over `poi.db`.
146
144
  */
147
- export class POILookup implements Disposable {
148
- #db: DatabaseSync
149
- #ownsDB: boolean
145
+ export class POILookup<DB extends POIDatabase = POIDatabase> implements Disposable {
146
+ #db: DatabaseClient<DB>
147
+ /**
148
+ * Resources this instance opened. A connection handed in by a caller is NOT in here, so disposal cannot reach it —
149
+ * ownership is membership rather than a flag a later branch has to check.
150
+ */
151
+ readonly #resources = new DisposableStack()
150
152
  readonly #categoryToID = new Map<string, number>()
151
153
  readonly #idToCategory = new Map<number, string>()
152
154
 
153
155
  /**
154
156
  * `(h3_cell, category_id)` → the cell's category-clustered range, most-confident-first.
155
157
  */
156
- readonly #categoryCellProbe: ReturnType<DatabaseSync["prepare"]>
158
+ readonly #categoryCellProbe: ReturnType<DatabaseClient["prepare"]>
157
159
  /**
158
160
  * `brand_wikidata` → ALL of a brand's rows globally (partial-index range-scan); distance-sorted in JS, not SQL.
159
161
  */
160
- readonly #brandProbe: ReturnType<DatabaseSync["prepare"]>
162
+ readonly #brandProbe: ReturnType<DatabaseClient["prepare"]>
161
163
  /**
162
164
  * FTS5 `MATCH` over `poi_search`, returning candidate `name_key`s to hydrate.
163
165
  */
164
- readonly #nameFTSProbe: ReturnType<DatabaseSync["prepare"]>
166
+ readonly #nameFTSProbe: ReturnType<DatabaseClient["prepare"]>
165
167
 
166
- constructor(opts: POILookupOpts) {
168
+ constructor(opts: POILookupOpts<DB>) {
167
169
  if (opts.database) {
168
170
  this.#db = opts.database
169
- this.#ownsDB = false
170
171
  } else if (opts.databasePath) {
171
- this.#db = new DatabaseSync(opts.databasePath, { readOnly: true })
172
- this.#ownsDB = true
172
+ this.#db = this.#resources.use(new DatabaseClient<DB>(opts.databasePath, { readOnly: true }))
173
173
  } else {
174
174
  throw new Error("POILookup needs `databasePath` or `database`")
175
175
  }
@@ -352,14 +352,8 @@ export class POILookup implements Disposable {
352
352
  return allRows<POIRow>(stmt, ...nameKeys)
353
353
  }
354
354
 
355
- close(): void {
356
- if (this.#ownsDB) {
357
- this.#db.close()
358
- }
359
- }
360
-
361
355
  [Symbol.dispose](): void {
362
- this.close()
356
+ this.#resources[Symbol.dispose]()
363
357
  }
364
358
  }
365
359
 
@@ -12,12 +12,11 @@
12
12
  * manifest (tier `shipped`, spine `h3` res 9) and per-res-6-cell coverage.
13
13
  */
14
14
 
15
- import type { DatabaseSync } from "node:sqlite"
16
-
17
15
  import type { LayerContractDatabase } from "@mailwoman/core/layers"
16
+ import type { DatabaseClient } from "@mailwoman/sqlite/client"
18
17
  import { sql, type Kysely } from "kysely"
19
18
 
20
- import type { NameKey } from "./street-normalize.ts"
19
+ import type { NameKey } from "#street/normalize"
21
20
 
22
21
  /**
23
22
  * One POI row. Clustered PK: h3_cell → category_id → neg_rank → rowid_key.
@@ -192,7 +191,7 @@ export const POI_FTS_TABLE = "poi_search"
192
191
  /**
193
192
  * FTS5 stays raw SQL by project rule (Kysely can't express virtual tables). Content-keyed by name_key.
194
193
  */
195
- export function createPOISearchFTS(db: DatabaseSync): void {
194
+ export function createPOISearchFTS<DB>(db: DatabaseClient<DB>): void {
196
195
  db.exec(
197
196
  `CREATE VIRTUAL TABLE ${POI_FTS_TABLE} USING fts5(name, name_key UNINDEXED, h3_cell UNINDEXED, tokenize = 'unicode61')`
198
197
  )
@@ -16,11 +16,9 @@
16
16
  * uses), keeping one normalizer in one place.
17
17
  */
18
18
 
19
- import { DatabaseSync } from "node:sqlite"
19
+ import { DatabaseClient } from "@mailwoman/sqlite/client"
20
20
 
21
- import { DatabaseClient } from "@mailwoman/core/kysley/client"
22
-
23
- import type { PostalCityAliasDatabase } from "./postal-city-alias-schema.ts"
21
+ import type { PostalCityAliasDatabase } from "#postal/city-alias-schema"
24
22
 
25
23
  export interface WOFPostalCityAliasLookupOpts {
26
24
  /**
@@ -30,7 +28,7 @@ export interface WOFPostalCityAliasLookupOpts {
30
28
  /**
31
29
  * Pre-opened handle (tests / shared connections). Mutually exclusive with `databasePath`.
32
30
  */
33
- database?: DatabaseSync
31
+ database?: DatabaseClient<PostalCityAliasDatabase>
34
32
  }
35
33
 
36
34
  /**
@@ -56,24 +54,22 @@ export interface PostalCityAlias {
56
54
  * differs from the geographic name — the rows that carry alias signal), issued via the typed Kysely query builder
57
55
  * against {@link PostalCityAliasDatabase}.
58
56
  */
59
- export class WOFPostalCityAliasLookup {
60
- #db: DatabaseSync
61
- #kdb: DatabaseClient<PostalCityAliasDatabase>
62
- #ownsDB: boolean
57
+ export class WOFPostalCityAliasLookup implements Disposable {
58
+ #db: DatabaseClient<PostalCityAliasDatabase>
59
+ /**
60
+ * Resources this instance opened. A connection handed in by a caller is NOT in here, so disposal cannot reach it —
61
+ * ownership is membership rather than a flag a later branch has to check.
62
+ */
63
+ readonly #resources = new DisposableStack()
63
64
 
64
65
  constructor(opts: WOFPostalCityAliasLookupOpts) {
65
66
  if (opts.database) {
66
67
  this.#db = opts.database
67
- this.#ownsDB = false
68
68
  } else if (opts.databasePath) {
69
- this.#db = new DatabaseSync(opts.databasePath, { readOnly: true })
70
- this.#ownsDB = true
69
+ this.#db = this.#resources.use(new DatabaseClient<PostalCityAliasDatabase>(opts.databasePath, { readOnly: true }))
71
70
  } else {
72
71
  throw new Error("WOFPostalCityAliasLookup needs `databasePath` or `database`")
73
72
  }
74
-
75
- // `#kdb` wraps `#db` for the typed query; close() owns the raw handle directly (sync).
76
- this.#kdb = new DatabaseClient<PostalCityAliasDatabase>({ database: this.#db })
77
73
  }
78
74
 
79
75
  /**
@@ -85,7 +81,7 @@ export class WOFPostalCityAliasLookup {
85
81
 
86
82
  if (!pc) return []
87
83
 
88
- const rows = await this.#kdb
84
+ const rows = await this.#db
89
85
  .selectFrom("postal_city_alias")
90
86
  .select(["postal_city", "geo_locality", "n"])
91
87
  .where("postcode", "=", pc)
@@ -95,9 +91,7 @@ export class WOFPostalCityAliasLookup {
95
91
  return rows.map((r) => ({ postalCity: String(r.postal_city), geoLocality: String(r.geo_locality), n: Number(r.n) }))
96
92
  }
97
93
 
98
- close(): void {
99
- if (this.#ownsDB) {
100
- this.#db.close()
101
- }
94
+ [Symbol.dispose](): void {
95
+ this.#resources[Symbol.dispose]()
102
96
  }
103
97
  }
@@ -20,7 +20,7 @@
20
20
 
21
21
  import { sql, type Kysely } from "kysely"
22
22
 
23
- import type { NameKey } from "./street-normalize.ts"
23
+ import type { NameKey } from "#street/normalize"
24
24
 
25
25
  /**
26
26
  * One postal-city → geo-locality edge, keyed exactly by `(name_key, postcode)`. The probe returns the geographic
@@ -55,7 +55,7 @@ export interface PostalCityCandidateDatabase {
55
55
  }
56
56
 
57
57
  /**
58
- * The table name the lookup probes (existence-gated, so an old candidate.db without it is byte-stable).
58
+ * The table name the lookup probes (existence-restricted, so an old candidate.db without it is byte-stable).
59
59
  */
60
60
  export const POSTAL_CITY_CANDIDATE_TABLE = "postal_city_candidate"
61
61
 
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+
7
+ export * from "#postal/city-alias-lookup"
8
+ export * from "#postal/city-alias-schema"
9
+ export * from "#postal/city-candidate-schema"
@@ -4,22 +4,24 @@
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
6
  * SQLite-backed postcode lookup for the postcode anchor (#240). A thin exact-match resolver over
7
- * one or more `postalcode-*.db` shards (the `spr` schema built by `build-unified-wof --placetypes
7
+ * one or more `postalcode-*.db` extracts (the `spr` schema built by `build-unified-wof --placetypes
8
8
  * postalcode`, then centroid-backfilled by `scripts/backfill-postcode-centroids.ts`).
9
9
  *
10
10
  * This is the production implementation of the `PostcodeResolver` interface consumed by
11
11
  * `@mailwoman/neural`'s `extractPostcodeAnchors`. It is deliberately dumb: an indexed exact-match
12
- * on the postcode string across every shard, unioned. No FTS, no ranking, no proximity — the
12
+ * on the postcode string across every extract, unioned. No FTS, no ranking, no proximity — the
13
13
  * anchor only needs "does this string exist as a postcode, in which countries, near where". A
14
- * future WASM build swaps this for an FST-backed resolver behind the same `lookup()` seam.
14
+ * future WASM build swaps this for an FST-backed resolver behind the same `lookup()` interface.
15
15
  *
16
- * Why multiple shards instead of the multi-shard `WOFSQLitePlaceLookup`: that resolver routes a
17
- * query to ONE shard by placetype, but every postcode shard shares `placetype='postalcode'`, so a
18
- * single query could only ever hit one country's shard. The anchor needs the union across
19
- * countries to build its country posterior, so it queries each shard directly.
16
+ * Why multiple extracts instead of the multi-extract `WOFSQLitePlaceLookup`: that resolver routes a
17
+ * query to ONE extract by placetype, but every postcode extract shares `placetype='postalcode'`, so a
18
+ * single query could only ever hit one country's extract. The anchor needs the union across
19
+ * countries to build its country posterior, so it queries each extract directly.
20
20
  */
21
21
 
22
- import { DatabaseSync } from "node:sqlite"
22
+ import { DatabaseClient } from "@mailwoman/sqlite/client"
23
+
24
+ import type { WOFDatabase } from "#schema"
23
25
 
24
26
  /**
25
27
  * A gazetteer hit. `lat`/`lon` of 0 means the postcode is known but has no centroid (no admin parent).
@@ -34,19 +36,19 @@ const LOOKUP_SQL =
34
36
  "SELECT country, latitude AS lat, longitude AS lon FROM spr WHERE name = ? AND placetype = 'postalcode' AND is_current != 0"
35
37
 
36
38
  export class WOFPostcodeLookup {
37
- readonly #dbs: DatabaseSync[]
38
- readonly #stmts: ReturnType<DatabaseSync["prepare"]>[]
39
+ readonly #dbs: DatabaseClient<WOFDatabase>[]
40
+ readonly #stmts: ReturnType<DatabaseClient["prepare"]>[]
39
41
 
40
42
  /**
41
- * Open each shard read-only and prepare its exact-match statement.
43
+ * Open each extract read-only and prepare its exact-match statement.
42
44
  */
43
45
  constructor(dbPaths: readonly string[]) {
44
- this.#dbs = dbPaths.map((p) => new DatabaseSync(p, { readOnly: true }))
46
+ this.#dbs = dbPaths.map((p) => new DatabaseClient<WOFDatabase>(p, { readOnly: true }))
45
47
  this.#stmts = this.#dbs.map((db) => db.prepare(LOOKUP_SQL))
46
48
  }
47
49
 
48
50
  /**
49
- * Exact-match the postcode across every shard and union the rows.
51
+ * Exact-match the postcode across every extract and union the rows.
50
52
  */
51
53
  lookup(postcode: string): PostcodePlace[] {
52
54
  const out: PostcodePlace[] = []
@@ -60,9 +62,9 @@ export class WOFPostcodeLookup {
60
62
  return out
61
63
  }
62
64
 
63
- close(): void {
65
+ [Symbol.dispose](): void {
64
66
  for (const db of this.#dbs) {
65
- db.close()
67
+ db.destroy()
66
68
  }
67
69
  }
68
70
  }