@mailwoman/resolver-wof-sqlite 10.0.0 → 10.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (477) hide show
  1. package/README.md +9 -8
  2. package/lib/address/point/interpolation.ts +45 -39
  3. package/lib/address/point/schema.ts +17 -40
  4. package/lib/address/point.ts +316 -0
  5. package/lib/{address/index.ts → address.ts} +1 -1
  6. package/lib/ancestry/backfill.ts +20 -86
  7. package/lib/{ancestry/index.ts → ancestry.ts} +19 -15
  8. package/lib/build/candidate.ts +122 -174
  9. package/lib/build/population-corrections.ts +64 -0
  10. package/lib/build/slim.ts +44 -114
  11. package/lib/candidate/alias-bags.ts +16 -17
  12. package/lib/candidate/ancestors/schema.ts +77 -61
  13. package/lib/candidate/ancestors/sidecar.ts +15 -22
  14. package/lib/candidate/country-display-names.ts +6 -20
  15. package/lib/candidate/extract-fold.ts +10 -55
  16. package/lib/candidate/fts.ts +5 -23
  17. package/lib/candidate/importance.ts +65 -68
  18. package/lib/candidate/lookup.ts +124 -415
  19. package/lib/candidate/name-roles.ts +15 -33
  20. package/lib/candidate/own-name.ts +35 -32
  21. package/lib/candidate/place-attrs.ts +20 -13
  22. package/lib/candidate/schema.ts +29 -65
  23. package/lib/candidate/scoring.ts +54 -93
  24. package/lib/capital-schema.ts +21 -17
  25. package/lib/capitals.ts +29 -27
  26. package/lib/coincident-roles.ts +85 -55
  27. package/lib/convention/schema.ts +15 -16
  28. package/lib/convention.ts +144 -0
  29. package/lib/coverage-manifest-schema.ts +40 -45
  30. package/lib/currency-backfill.ts +34 -79
  31. package/lib/env.ts +1 -1
  32. package/lib/exact-match.ts +32 -21
  33. package/lib/extracts.ts +97 -74
  34. package/lib/fst/autocomplete.ts +54 -37
  35. package/lib/fst/builder.ts +37 -41
  36. package/lib/fst/deserialize-web.ts +16 -17
  37. package/lib/fst/format.ts +41 -23
  38. package/lib/fst/freshness.ts +43 -120
  39. package/lib/fst/matcher.ts +7 -5
  40. package/lib/fst/serialize.ts +54 -74
  41. package/lib/fst/types.ts +78 -75
  42. package/lib/{fst/index.ts → fst.ts} +1 -0
  43. package/lib/fts/query.ts +5 -36
  44. package/lib/fts.ts +280 -0
  45. package/lib/geonames/aliases.ts +73 -144
  46. package/lib/geonames/postal.ts +162 -71
  47. package/lib/index.ts +9 -8
  48. package/lib/interpolation.ts +48 -100
  49. package/lib/lookup.ts +155 -270
  50. package/lib/name-score.ts +9 -7
  51. package/lib/nsul/lookup.ts +37 -54
  52. package/lib/nsul/schema.ts +16 -43
  53. package/lib/paths.ts +159 -0
  54. package/lib/place-importance-schema.ts +62 -169
  55. package/lib/poi/lookup.ts +104 -121
  56. package/lib/poi/schema.ts +42 -26
  57. package/lib/polygon-schema.ts +10 -6
  58. package/lib/postal/city/alias/lookup.ts +22 -40
  59. package/lib/postal/city/alias/schema.ts +14 -10
  60. package/lib/postal/city/candidate-schema.ts +26 -20
  61. package/lib/postcode-point-lookup.ts +8 -27
  62. package/lib/primary-preference.ts +46 -126
  63. package/lib/proximity-rerank.ts +44 -33
  64. package/lib/ranking-weights.ts +105 -78
  65. package/lib/region-keys.ts +70 -42
  66. package/lib/reverse.ts +149 -86
  67. package/lib/schema.ts +73 -50
  68. package/lib/search-fetch.ts +90 -68
  69. package/lib/sqlite/convention-source.ts +15 -23
  70. package/lib/sqlite/utils.ts +19 -22
  71. package/lib/street/centroid/schema.ts +37 -42
  72. package/lib/street/{centroid/index.ts → centroid.ts} +16 -25
  73. package/lib/street/morphology/fst/builder.ts +60 -42
  74. package/lib/street/morphology/fst/loader.ts +40 -32
  75. package/lib/street/name-lookup.ts +45 -41
  76. package/lib/street/normalize.ts +88 -219
  77. package/lib/street/segment-schema.ts +116 -43
  78. package/lib/{street/index.ts → street.ts} +1 -1
  79. package/lib/types.ts +109 -150
  80. package/lib/unified-schema.ts +29 -29
  81. package/lib/uprn/existence.ts +30 -19
  82. package/lib/uprn/lookup.ts +29 -68
  83. package/lib/uprn/schema.ts +18 -40
  84. package/lib/weights-overlay-linker.ts +236 -252
  85. package/out/address/point/interpolation.d.ts +20 -23
  86. package/out/address/point/interpolation.d.ts.map +1 -1
  87. package/out/address/point/interpolation.js +42 -39
  88. package/out/address/point/interpolation.js.map +1 -1
  89. package/out/address/point/schema.d.ts +12 -35
  90. package/out/address/point/schema.d.ts.map +1 -1
  91. package/out/address/point/schema.js +3 -19
  92. package/out/address/point/schema.js.map +1 -1
  93. package/out/address/point.d.ts +57 -0
  94. package/out/address/point.d.ts.map +1 -0
  95. package/out/address/point.js +206 -0
  96. package/out/address/point.js.map +1 -0
  97. package/out/{address/index.js → address.d.ts} +2 -2
  98. package/out/address.d.ts.map +1 -0
  99. package/out/{address/index.d.ts → address.js} +2 -2
  100. package/out/address.js.map +1 -0
  101. package/out/ancestry/backfill.d.ts +11 -64
  102. package/out/ancestry/backfill.d.ts.map +1 -1
  103. package/out/ancestry/backfill.js +14 -74
  104. package/out/ancestry/backfill.js.map +1 -1
  105. package/out/ancestry.d.ts +49 -0
  106. package/out/ancestry.d.ts.map +1 -0
  107. package/out/ancestry.js +59 -0
  108. package/out/ancestry.js.map +1 -0
  109. package/out/build/candidate.d.ts +82 -112
  110. package/out/build/candidate.d.ts.map +1 -1
  111. package/out/build/candidate.js +17 -100
  112. package/out/build/candidate.js.map +1 -1
  113. package/out/build/population-corrections.d.ts +52 -0
  114. package/out/build/population-corrections.d.ts.map +1 -0
  115. package/out/build/population-corrections.js +40 -0
  116. package/out/build/population-corrections.js.map +1 -0
  117. package/out/build/slim.d.ts +8 -44
  118. package/out/build/slim.d.ts.map +1 -1
  119. package/out/build/slim.js +33 -94
  120. package/out/build/slim.js.map +1 -1
  121. package/out/candidate/alias-bags.d.ts +6 -6
  122. package/out/candidate/alias-bags.d.ts.map +1 -1
  123. package/out/candidate/alias-bags.js +16 -17
  124. package/out/candidate/alias-bags.js.map +1 -1
  125. package/out/candidate/ancestors/schema.d.ts +73 -57
  126. package/out/candidate/ancestors/schema.d.ts.map +1 -1
  127. package/out/candidate/ancestors/schema.js +56 -48
  128. package/out/candidate/ancestors/schema.js.map +1 -1
  129. package/out/candidate/ancestors/sidecar.d.ts +3 -8
  130. package/out/candidate/ancestors/sidecar.d.ts.map +1 -1
  131. package/out/candidate/ancestors/sidecar.js +15 -22
  132. package/out/candidate/ancestors/sidecar.js.map +1 -1
  133. package/out/candidate/country-display-names.d.ts +5 -15
  134. package/out/candidate/country-display-names.d.ts.map +1 -1
  135. package/out/candidate/country-display-names.js +6 -20
  136. package/out/candidate/country-display-names.js.map +1 -1
  137. package/out/candidate/extract-fold.d.ts +7 -15
  138. package/out/candidate/extract-fold.d.ts.map +1 -1
  139. package/out/candidate/extract-fold.js +5 -47
  140. package/out/candidate/extract-fold.js.map +1 -1
  141. package/out/candidate/fts.d.ts +5 -23
  142. package/out/candidate/fts.d.ts.map +1 -1
  143. package/out/candidate/fts.js +5 -23
  144. package/out/candidate/fts.js.map +1 -1
  145. package/out/candidate/importance.d.ts +60 -65
  146. package/out/candidate/importance.d.ts.map +1 -1
  147. package/out/candidate/importance.js +56 -63
  148. package/out/candidate/importance.js.map +1 -1
  149. package/out/candidate/lookup.d.ts +18 -55
  150. package/out/candidate/lookup.d.ts.map +1 -1
  151. package/out/candidate/lookup.js +82 -385
  152. package/out/candidate/lookup.js.map +1 -1
  153. package/out/candidate/name-roles.d.ts +9 -21
  154. package/out/candidate/name-roles.d.ts.map +1 -1
  155. package/out/candidate/name-roles.js +15 -33
  156. package/out/candidate/name-roles.js.map +1 -1
  157. package/out/candidate/own-name.d.ts +23 -25
  158. package/out/candidate/own-name.d.ts.map +1 -1
  159. package/out/candidate/own-name.js +35 -32
  160. package/out/candidate/own-name.js.map +1 -1
  161. package/out/candidate/place-attrs.d.ts +20 -13
  162. package/out/candidate/place-attrs.d.ts.map +1 -1
  163. package/out/candidate/place-attrs.js +4 -5
  164. package/out/candidate/place-attrs.js.map +1 -1
  165. package/out/candidate/schema.d.ts +27 -62
  166. package/out/candidate/schema.d.ts.map +1 -1
  167. package/out/candidate/schema.js +10 -22
  168. package/out/candidate/schema.js.map +1 -1
  169. package/out/candidate/scoring.d.ts +7 -8
  170. package/out/candidate/scoring.d.ts.map +1 -1
  171. package/out/candidate/scoring.js +52 -89
  172. package/out/candidate/scoring.js.map +1 -1
  173. package/out/capital-schema.d.ts +21 -17
  174. package/out/capital-schema.d.ts.map +1 -1
  175. package/out/capital-schema.js +17 -15
  176. package/out/capital-schema.js.map +1 -1
  177. package/out/capitals.d.ts +27 -25
  178. package/out/capitals.d.ts.map +1 -1
  179. package/out/capitals.js +23 -21
  180. package/out/capitals.js.map +1 -1
  181. package/out/coincident-roles.d.ts +60 -43
  182. package/out/coincident-roles.d.ts.map +1 -1
  183. package/out/coincident-roles.js +72 -50
  184. package/out/coincident-roles.js.map +1 -1
  185. package/out/convention/schema.d.ts +14 -14
  186. package/out/convention/schema.d.ts.map +1 -1
  187. package/out/convention/schema.js +6 -4
  188. package/out/convention/schema.js.map +1 -1
  189. package/out/convention.d.ts +97 -0
  190. package/out/convention.d.ts.map +1 -0
  191. package/out/convention.js +81 -0
  192. package/out/convention.js.map +1 -0
  193. package/out/coverage-manifest-schema.d.ts +34 -39
  194. package/out/coverage-manifest-schema.d.ts.map +1 -1
  195. package/out/coverage-manifest-schema.js +25 -34
  196. package/out/coverage-manifest-schema.js.map +1 -1
  197. package/out/currency-backfill.d.ts +16 -38
  198. package/out/currency-backfill.d.ts.map +1 -1
  199. package/out/currency-backfill.js +19 -46
  200. package/out/currency-backfill.js.map +1 -1
  201. package/out/env.d.ts +1 -1
  202. package/out/env.js +1 -1
  203. package/out/exact-match.d.ts +19 -10
  204. package/out/exact-match.d.ts.map +1 -1
  205. package/out/exact-match.js +32 -21
  206. package/out/exact-match.js.map +1 -1
  207. package/out/extracts.d.ts +66 -55
  208. package/out/extracts.d.ts.map +1 -1
  209. package/out/extracts.js +63 -55
  210. package/out/extracts.js.map +1 -1
  211. package/out/fst/autocomplete.d.ts +29 -21
  212. package/out/fst/autocomplete.d.ts.map +1 -1
  213. package/out/fst/autocomplete.js +39 -28
  214. package/out/fst/autocomplete.js.map +1 -1
  215. package/out/fst/builder.d.ts.map +1 -1
  216. package/out/fst/builder.js +37 -41
  217. package/out/fst/builder.js.map +1 -1
  218. package/out/fst/deserialize-web.d.ts +4 -4
  219. package/out/fst/deserialize-web.d.ts.map +1 -1
  220. package/out/fst/deserialize-web.js +15 -16
  221. package/out/fst/deserialize-web.js.map +1 -1
  222. package/out/fst/format.d.ts +41 -23
  223. package/out/fst/format.d.ts.map +1 -1
  224. package/out/fst/format.js +41 -23
  225. package/out/fst/format.js.map +1 -1
  226. package/out/fst/freshness.d.ts +19 -81
  227. package/out/fst/freshness.d.ts.map +1 -1
  228. package/out/fst/freshness.js +31 -94
  229. package/out/fst/freshness.js.map +1 -1
  230. package/out/fst/matcher.d.ts +5 -4
  231. package/out/fst/matcher.d.ts.map +1 -1
  232. package/out/fst/matcher.js +2 -2
  233. package/out/fst/matcher.js.map +1 -1
  234. package/out/fst/serialize.d.ts +28 -28
  235. package/out/fst/serialize.d.ts.map +1 -1
  236. package/out/fst/serialize.js +53 -71
  237. package/out/fst/serialize.js.map +1 -1
  238. package/out/fst/types.d.ts +78 -74
  239. package/out/fst/types.d.ts.map +1 -1
  240. package/out/fst/types.js +1 -4
  241. package/out/fst/types.js.map +1 -1
  242. package/out/{fst/index.js → fst.d.ts} +2 -1
  243. package/out/fst.d.ts.map +1 -0
  244. package/out/{fst/index.d.ts → fst.js} +2 -1
  245. package/out/fst.js.map +1 -0
  246. package/out/fts/query.d.ts +2 -27
  247. package/out/fts/query.d.ts.map +1 -1
  248. package/out/fts/query.js +5 -36
  249. package/out/fts/query.js.map +1 -1
  250. package/out/fts.d.ts +126 -0
  251. package/out/fts.d.ts.map +1 -0
  252. package/out/fts.js +188 -0
  253. package/out/fts.js.map +1 -0
  254. package/out/geonames/aliases.d.ts +26 -62
  255. package/out/geonames/aliases.d.ts.map +1 -1
  256. package/out/geonames/aliases.js +45 -117
  257. package/out/geonames/aliases.js.map +1 -1
  258. package/out/geonames/postal.d.ts +84 -44
  259. package/out/geonames/postal.d.ts.map +1 -1
  260. package/out/geonames/postal.js +115 -73
  261. package/out/geonames/postal.js.map +1 -1
  262. package/out/{geonames/index.js → geonames.d.ts} +1 -1
  263. package/out/geonames.d.ts.map +1 -0
  264. package/out/{geonames/index.d.ts → geonames.js} +1 -1
  265. package/out/geonames.js.map +1 -0
  266. package/out/index.d.ts +9 -8
  267. package/out/index.d.ts.map +1 -1
  268. package/out/index.js +6 -5
  269. package/out/index.js.map +1 -1
  270. package/out/interpolation.d.ts +18 -55
  271. package/out/interpolation.d.ts.map +1 -1
  272. package/out/interpolation.js +27 -69
  273. package/out/interpolation.js.map +1 -1
  274. package/out/lookup.d.ts +23 -51
  275. package/out/lookup.d.ts.map +1 -1
  276. package/out/lookup.js +136 -234
  277. package/out/lookup.js.map +1 -1
  278. package/out/name-score.d.ts +2 -2
  279. package/out/name-score.d.ts.map +1 -1
  280. package/out/name-score.js +9 -7
  281. package/out/name-score.js.map +1 -1
  282. package/out/nsul/lookup.d.ts +33 -34
  283. package/out/nsul/lookup.d.ts.map +1 -1
  284. package/out/nsul/lookup.js +26 -40
  285. package/out/nsul/lookup.js.map +1 -1
  286. package/out/nsul/schema.d.ts +16 -43
  287. package/out/nsul/schema.d.ts.map +1 -1
  288. package/out/nsul/schema.js +9 -35
  289. package/out/nsul/schema.js.map +1 -1
  290. package/out/{nsul/index.d.ts → nsul.d.ts} +1 -1
  291. package/out/nsul.d.ts.map +1 -0
  292. package/out/{nsul/index.js → nsul.js} +1 -1
  293. package/out/nsul.js.map +1 -0
  294. package/out/paths.d.ts +124 -0
  295. package/out/paths.d.ts.map +1 -0
  296. package/out/paths.js +104 -0
  297. package/out/paths.js.map +1 -0
  298. package/out/place-importance-schema.d.ts +51 -143
  299. package/out/place-importance-schema.d.ts.map +1 -1
  300. package/out/place-importance-schema.js +28 -143
  301. package/out/place-importance-schema.js.map +1 -1
  302. package/out/poi/lookup.d.ts +40 -47
  303. package/out/poi/lookup.d.ts.map +1 -1
  304. package/out/poi/lookup.js +69 -96
  305. package/out/poi/lookup.js.map +1 -1
  306. package/out/poi/schema.d.ts +41 -25
  307. package/out/poi/schema.d.ts.map +1 -1
  308. package/out/poi/schema.js +25 -17
  309. package/out/poi/schema.js.map +1 -1
  310. package/out/{poi/index.js → poi.d.ts} +1 -1
  311. package/out/poi.d.ts.map +1 -0
  312. package/out/{poi/index.d.ts → poi.js} +1 -1
  313. package/out/poi.js.map +1 -0
  314. package/out/polygon-schema.d.ts +10 -6
  315. package/out/polygon-schema.d.ts.map +1 -1
  316. package/out/polygon-schema.js +2 -2
  317. package/out/polygon-schema.js.map +1 -1
  318. package/out/postal/city/alias/lookup.d.ts +20 -23
  319. package/out/postal/city/alias/lookup.d.ts.map +1 -1
  320. package/out/postal/city/alias/lookup.js +17 -30
  321. package/out/postal/city/alias/lookup.js.map +1 -1
  322. package/out/postal/city/alias/schema.d.ts +14 -10
  323. package/out/postal/city/alias/schema.d.ts.map +1 -1
  324. package/out/postal/city/alias/schema.js +10 -8
  325. package/out/postal/city/alias/schema.js.map +1 -1
  326. package/out/postal/city/candidate-schema.d.ts +25 -19
  327. package/out/postal/city/candidate-schema.d.ts.map +1 -1
  328. package/out/postal/city/candidate-schema.js +21 -17
  329. package/out/postal/city/candidate-schema.js.map +1 -1
  330. package/out/{postal/index.d.ts → postal.d.ts} +1 -1
  331. package/out/postal.d.ts.map +1 -0
  332. package/out/{postal/index.js → postal.js} +1 -1
  333. package/out/postal.js.map +1 -0
  334. package/out/postcode-point-lookup.d.ts +6 -24
  335. package/out/postcode-point-lookup.d.ts.map +1 -1
  336. package/out/postcode-point-lookup.js +5 -17
  337. package/out/postcode-point-lookup.js.map +1 -1
  338. package/out/primary-preference.d.ts +38 -92
  339. package/out/primary-preference.d.ts.map +1 -1
  340. package/out/primary-preference.js +15 -99
  341. package/out/primary-preference.js.map +1 -1
  342. package/out/proximity-rerank.d.ts +41 -30
  343. package/out/proximity-rerank.d.ts.map +1 -1
  344. package/out/proximity-rerank.js +38 -29
  345. package/out/proximity-rerank.js.map +1 -1
  346. package/out/ranking-weights.d.ts +98 -64
  347. package/out/ranking-weights.d.ts.map +1 -1
  348. package/out/ranking-weights.js +26 -25
  349. package/out/ranking-weights.js.map +1 -1
  350. package/out/region-keys.d.ts +50 -31
  351. package/out/region-keys.d.ts.map +1 -1
  352. package/out/region-keys.js +68 -40
  353. package/out/region-keys.js.map +1 -1
  354. package/out/reverse.d.ts +78 -50
  355. package/out/reverse.d.ts.map +1 -1
  356. package/out/reverse.js +98 -61
  357. package/out/reverse.js.map +1 -1
  358. package/out/schema.d.ts +72 -49
  359. package/out/schema.d.ts.map +1 -1
  360. package/out/schema.js +4 -5
  361. package/out/schema.js.map +1 -1
  362. package/out/search-fetch.d.ts +16 -12
  363. package/out/search-fetch.d.ts.map +1 -1
  364. package/out/search-fetch.js +83 -63
  365. package/out/search-fetch.js.map +1 -1
  366. package/out/sqlite/convention-source.d.ts +12 -16
  367. package/out/sqlite/convention-source.d.ts.map +1 -1
  368. package/out/sqlite/convention-source.js +13 -22
  369. package/out/sqlite/convention-source.js.map +1 -1
  370. package/out/sqlite/utils.d.ts +19 -19
  371. package/out/sqlite/utils.d.ts.map +1 -1
  372. package/out/sqlite/utils.js +14 -15
  373. package/out/sqlite/utils.js.map +1 -1
  374. package/out/street/centroid/schema.d.ts +37 -42
  375. package/out/street/centroid/schema.d.ts.map +1 -1
  376. package/out/street/centroid/schema.js +9 -21
  377. package/out/street/centroid/schema.js.map +1 -1
  378. package/out/street/centroid.d.ts +30 -0
  379. package/out/street/centroid.d.ts.map +1 -0
  380. package/out/street/{centroid/index.js → centroid.js} +13 -24
  381. package/out/street/centroid.js.map +1 -0
  382. package/out/street/morphology/fst/builder.d.ts +20 -10
  383. package/out/street/morphology/fst/builder.d.ts.map +1 -1
  384. package/out/street/morphology/fst/builder.js +44 -34
  385. package/out/street/morphology/fst/builder.js.map +1 -1
  386. package/out/street/morphology/fst/loader.d.ts +33 -26
  387. package/out/street/morphology/fst/loader.d.ts.map +1 -1
  388. package/out/street/morphology/fst/loader.js +23 -22
  389. package/out/street/morphology/fst/loader.js.map +1 -1
  390. package/out/street/name-lookup.d.ts +24 -18
  391. package/out/street/name-lookup.d.ts.map +1 -1
  392. package/out/street/name-lookup.js +34 -35
  393. package/out/street/name-lookup.js.map +1 -1
  394. package/out/street/normalize.d.ts +35 -136
  395. package/out/street/normalize.d.ts.map +1 -1
  396. package/out/street/normalize.js +77 -194
  397. package/out/street/normalize.js.map +1 -1
  398. package/out/street/segment-schema.d.ts +79 -39
  399. package/out/street/segment-schema.d.ts.map +1 -1
  400. package/out/street/segment-schema.js +71 -21
  401. package/out/street/segment-schema.js.map +1 -1
  402. package/out/{street/index.js → street.d.ts} +2 -2
  403. package/out/street.d.ts.map +1 -0
  404. package/out/{street/index.d.ts → street.js} +2 -2
  405. package/out/street.js.map +1 -0
  406. package/out/types.d.ts +84 -149
  407. package/out/types.d.ts.map +1 -1
  408. package/out/types.js +0 -6
  409. package/out/types.js.map +1 -1
  410. package/out/unified-schema.d.ts +8 -12
  411. package/out/unified-schema.d.ts.map +1 -1
  412. package/out/unified-schema.js +29 -29
  413. package/out/unified-schema.js.map +1 -1
  414. package/out/uprn/existence.d.ts +28 -17
  415. package/out/uprn/existence.d.ts.map +1 -1
  416. package/out/uprn/existence.js +26 -16
  417. package/out/uprn/existence.js.map +1 -1
  418. package/out/uprn/lookup.d.ts +14 -44
  419. package/out/uprn/lookup.d.ts.map +1 -1
  420. package/out/uprn/lookup.js +21 -57
  421. package/out/uprn/lookup.js.map +1 -1
  422. package/out/uprn/schema.d.ts +18 -40
  423. package/out/uprn/schema.d.ts.map +1 -1
  424. package/out/uprn/schema.js +10 -32
  425. package/out/uprn/schema.js.map +1 -1
  426. package/out/{uprn/index.d.ts → uprn.d.ts} +1 -1
  427. package/out/uprn.d.ts.map +1 -0
  428. package/out/{uprn/index.js → uprn.js} +1 -1
  429. package/out/uprn.js.map +1 -0
  430. package/out/weights-overlay-linker.d.ts +138 -144
  431. package/out/weights-overlay-linker.d.ts.map +1 -1
  432. package/out/weights-overlay-linker.js +105 -159
  433. package/out/weights-overlay-linker.js.map +1 -1
  434. package/package.json +91 -596
  435. package/lib/address/point/index.ts +0 -328
  436. package/lib/convention/index.ts +0 -154
  437. package/lib/fts/index.ts +0 -361
  438. package/out/address/index.d.ts.map +0 -1
  439. package/out/address/index.js.map +0 -1
  440. package/out/address/point/index.d.ts +0 -53
  441. package/out/address/point/index.d.ts.map +0 -1
  442. package/out/address/point/index.js +0 -222
  443. package/out/address/point/index.js.map +0 -1
  444. package/out/ancestry/index.d.ts +0 -45
  445. package/out/ancestry/index.d.ts.map +0 -1
  446. package/out/ancestry/index.js +0 -55
  447. package/out/ancestry/index.js.map +0 -1
  448. package/out/convention/index.d.ts +0 -106
  449. package/out/convention/index.d.ts.map +0 -1
  450. package/out/convention/index.js +0 -93
  451. package/out/convention/index.js.map +0 -1
  452. package/out/fst/index.d.ts.map +0 -1
  453. package/out/fst/index.js.map +0 -1
  454. package/out/fts/index.d.ts +0 -184
  455. package/out/fts/index.d.ts.map +0 -1
  456. package/out/fts/index.js +0 -277
  457. package/out/fts/index.js.map +0 -1
  458. package/out/geonames/index.d.ts.map +0 -1
  459. package/out/geonames/index.js.map +0 -1
  460. package/out/nsul/index.d.ts.map +0 -1
  461. package/out/nsul/index.js.map +0 -1
  462. package/out/poi/index.d.ts.map +0 -1
  463. package/out/poi/index.js.map +0 -1
  464. package/out/postal/index.d.ts.map +0 -1
  465. package/out/postal/index.js.map +0 -1
  466. package/out/street/centroid/index.d.ts +0 -40
  467. package/out/street/centroid/index.d.ts.map +0 -1
  468. package/out/street/centroid/index.js.map +0 -1
  469. package/out/street/index.d.ts.map +0 -1
  470. package/out/street/index.js.map +0 -1
  471. package/out/uprn/index.d.ts.map +0 -1
  472. package/out/uprn/index.js.map +0 -1
  473. /package/lib/{geonames/index.ts → geonames.ts} +0 -0
  474. /package/lib/{nsul/index.ts → nsul.ts} +0 -0
  475. /package/lib/{poi/index.ts → poi.ts} +0 -0
  476. /package/lib/{postal/index.ts → postal.ts} +0 -0
  477. /package/lib/{uprn/index.ts → uprn.ts} +0 -0
@@ -2,26 +2,13 @@
2
2
  * @copyright Sister Software
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
- *
6
- * SQLite implementation of core's `StreetCentroidLookup` (#1042): the street-level tier BELOW the
7
- * exact address-point tier and ABOVE admin-centroid resolution. Given a street name (no house
8
- * number) plus a postcode/commune scope, it returns the street's CENTROID + an honest extent-derived
9
- * uncertainty from the derived `street-centroids-<cc>.db` roll-up.
10
- *
11
- * Query-side normalization is THE shared normalizer (`street-normalize.ts`), selected per the extract's
12
- * `streetLocale`, so build-side and probe-side keys agree by construction. The commune scope folds
13
- * through `normalizeLocalityForKey` + `stripArrondissement` (BAN names Paris/Lyon/Marseille per
14
- * arrondissement; a query names the base commune).
15
- *
16
- * Scope order is most-selective first: `postcode`, then the base commune. Each scope WEIGHTED-
17
- * aggregates (by `point_count`) across the matched rows in SQL, so a commune-scope probe returns the
18
- * street's grand centroid over every postcode/arrondissement it spans — one row, one hit. Matching is
19
- * exact-after-normalization only (no fuzzy street matching in this tier).
5
+ * @file SQLite implementation of core's `StreetCentroidLookup`.
20
6
  */
21
7
 
22
8
  import type { StreetCentroidHit, StreetCentroidLookup } from "@mailwoman/core/resolver"
23
9
  import { haversineKm } from "@mailwoman/spatial"
24
10
  import { DatabaseClient } from "@mailwoman/sqlite/client"
11
+ import type { PathBuilderLike } from "path-ts"
25
12
 
26
13
  import { hasTable, prepareGet, type PreparedGet } from "#sqlite-utils"
27
14
  import type { StreetCentroidDatabase } from "#street/centroid/schema"
@@ -36,7 +23,8 @@ import {
36
23
  } from "#street/normalize"
37
24
 
38
25
  /**
39
- * The weighted-centroid + extent + provenance an aggregate probe projects. `lat` is null when nothing matched.
26
+ * The weighted centroid, extent and provenance an aggregate probe returns;
27
+ * `lat` is null when no row matched.
40
28
  */
41
29
  interface AggRow {
42
30
  lat: number | null
@@ -50,7 +38,8 @@ interface AggRow {
50
38
  }
51
39
 
52
40
  /**
53
- * Weighted-centroid aggregate over a WHERE-filtered set. `SUM(coord*n)/SUM(n)` reconstructs the grand centroid.
41
+ * The aggregate columns that weight each row's centroid by `point_count` to
42
+ * reconstruct the combined centroid.
54
43
  */
55
44
  const AGG_SELECT =
56
45
  "SUM(lat * point_count) / SUM(point_count) AS lat, " +
@@ -59,12 +48,16 @@ const AGG_SELECT =
59
48
  "MAX(source) AS source, MAX(release) AS release"
60
49
 
61
50
  /**
62
- * Half the bbox diagonal, in METERS — an honest coarse radius for a street centroid.
51
+ * Half the bounding-box diagonal in meters, used as a coarse uncertainty radius for a street centroid.
63
52
  */
64
53
  function extentRadiusM(minLat: number, maxLat: number, minLon: number, maxLon: number): number {
65
54
  return Math.round(haversineKm(minLat, minLon, maxLat, maxLon) * 500)
66
55
  }
67
56
 
57
+ /**
58
+ * Finds a street's centroid and extent-based uncertainty by street name,
59
+ * scoped by postcode and then by base commune.
60
+ */
68
61
  export class StreetCentroidSqliteLookup implements StreetCentroidLookup {
69
62
  readonly #db: DatabaseClient<StreetCentroidDatabase>
70
63
  readonly #locale: StreetLocale
@@ -72,16 +65,14 @@ export class StreetCentroidSqliteLookup implements StreetCentroidLookup {
72
65
  readonly #byLocality: PreparedGet<[locality: NameKey, street: StreetKey], AggRow> | undefined
73
66
 
74
67
  /**
75
- * @param dbPath Extract path.
76
- * @param opts.streetLocale The street-normalization locale this extract was BUILT with — must match, or every key
77
- * misses. Defaults to `"fr"` (BAN is the French national register; the tier is FR-only today).
68
+ * The extract defaults to the `fr` street-normalization locale.
69
+ * A mismatch with the extract's locale makes every key miss.
78
70
  */
79
- constructor(dbPath: string, opts: { streetLocale?: StreetLocale } = {}) {
71
+ constructor(dbPath: PathBuilderLike, opts: { streetLocale?: StreetLocale } = {}) {
80
72
  this.#db = new DatabaseClient<StreetCentroidDatabase>(dbPath, { readOnly: true })
81
73
  this.#locale = opts.streetLocale ?? "fr"
82
74
 
83
- // Degrade gracefully on an empty/tableless extract (interrupted build, stray 0-byte file): with no
84
- // `street_centroid` table this lookup is a no-op miss, not a crash (mirrors the address-point reader).
75
+ // An extract without a `street_centroid` table makes every lookup miss.
85
76
  if (hasTable(this.#db, "street_centroid")) {
86
77
  this.#byPostcode = prepareGet(
87
78
  this.#db,
@@ -101,7 +92,7 @@ export class StreetCentroidSqliteLookup implements StreetCentroidLookup {
101
92
 
102
93
  if (!streetNorm) return null
103
94
 
104
- let row: AggRow | undefined
95
+ let row: AggRow | null = null
105
96
 
106
97
  if (query.postcode?.trim()) {
107
98
  row = this.#byPostcode(query.postcode.trim(), streetNorm)
@@ -5,13 +5,14 @@
5
5
  *
6
6
  * Build a street-morphology FST from libpostal's street_types dictionaries. The morphology FST maps
7
7
  * street-typing affixes (Street/Avenue/rue/Calle/Straße/...) to a single synthetic placetype
8
- * `"street_affix"` — distinct from the admin FST in source data, intent, and binary artifact.
8
+ * `"street_affix"`. Its source data and purpose differ from the admin FST.
9
+ * It also produces a separate binary artifact.
9
10
  *
10
11
  * The morphology FST closes the inference-time vacuum identified by the v0.6.1 postmortem: street
11
12
  * tokens have no admin-FST anchor, so synth-street training pushed the model toward over-emitting
12
13
  * `dependent_locality` on subcomponents. With the morphology FST, the neural decoder gets
13
14
  * positive evidence for street-typing affixes and the adjacent name tokens, plus negative
14
- * evidence away from `dependent_locality` on the same neighbours.
15
+ * evidence away from `dependent_locality` on the same neighbors.
15
16
  *
16
17
  * Design rationale + the four-layer street-supplement architecture lives in
17
18
  * `docs/articles/concepts/street-supplement-architecture.md`.
@@ -23,8 +24,9 @@
23
24
  * `fst-street-morphology.bin`.
24
25
  */
25
26
 
26
- import { isDirectory, readLocalTextFile, statPath } from "@mailwoman/core/fs/readers"
27
- import { join } from "path-ts"
27
+ import { readLocalTextFile } from "@mailwoman/core/fs/readers"
28
+ import { isDirectory, isFile } from "@mailwoman/core/fs/readers/stat"
29
+ import { PathBuilder, type PathBuilderLike } from "path-ts"
28
30
  import { TextSpliterator } from "spliterator"
29
31
  import { Globerator } from "spliterator/node/fs"
30
32
 
@@ -33,9 +35,11 @@ import { FSTMatcher, normalizeTokens } from "#fst/matcher"
33
35
  import type { FSTProvenance, PlaceEntry } from "#fst/types"
34
36
 
35
37
  /**
36
- * Reserved synthetic wofID base for street-morphology entries. 32-bit unsigned, well above any realistic WOF
37
- * allocation. Reusing the same base across rebuilds keeps IDs stable for any consumer that caches them. See
38
- * [[project-schema-storage-decision]] for the reserved range policy.
38
+ * Reserved synthetic wofID base for street-morphology entries. 32-bit unsigned,
39
+ * well above any realistic WOF allocation.
40
+ *
41
+ * The same base across rebuilds keeps IDs stable for consumers that cache them.
42
+ * See [[project-schema-storage-decision]] for the reserved range policy.
39
43
  */
40
44
  const STREET_AFFIX_WOFID_BASE = 1_900_000_000
41
45
 
@@ -45,19 +49,27 @@ export interface BuildStreetMorphologyFSTOpts {
45
49
  /**
46
50
  * Path to the `core/data/libpostal/dictionaries` directory containing per-locale subfolders.
47
51
  */
48
- dictionariesDir: string
52
+ dictionariesDir: PathBuilderLike
49
53
  /**
50
- * Optional locale filter — only ingest these locale subfolders. Defaults to all that have a `street_types.txt`.
54
+ * Optional locale filter — only ingest these locale subfolders.
55
+ *
56
+ * @defaultValue all that have a `street_types.txt`.
51
57
  */
52
58
  locales?: string[]
53
59
  /**
54
- * Minimum length (in characters, post-normalization) of variant surface forms to insert into the trie. Defaults to 3.
60
+ * Minimum length (in characters, post-normalization) of variant surface forms to insert into the trie.
61
+ *
62
+ * Rationale: libpostal's street_types dictionaries contain 1-2 character abbreviations
63
+ * (`a`, `b`, `av`, `bd`, `br`, ...) that collide with non-affix tokens at parse time,
64
+ * including US state abbreviations (`or`, `CA`, `ND`, `NY`).
65
+ * Single-letter unit designators and other short tokens also collide.
66
+ *
67
+ * Empirically these collisions push the morphology prior to mis-tag state
68
+ * abbreviations as `street_suffix`.
69
+ *
70
+ * A minimum length of 3 retains useful forms (`ave`, `blvd`, `rue`, `str`) while filtering out the noise.
55
71
  *
56
- * Rationale: libpostal's street_types dictionaries contain 1-2 character abbreviations (`a`, `b`, `av`, `bd`, `br`,
57
- * ...) that collide with non-affix tokens at parse time — notably US state abbreviations (`OR`, `CA`, `ND`, `NY`),
58
- * single-letter unit designators, and arbitrary short tokens. Empirically these collisions push the morphology prior
59
- * to mis-tag state abbreviations as `street_suffix`. A minimum length of 3 retains useful forms (`ave`, `blvd`,
60
- * `rue`, `str`) while filtering out the noise.
72
+ * @defaultValue `3`
61
73
  */
62
74
  minVariantLength?: number
63
75
  /**
@@ -76,20 +88,19 @@ export interface BuildStreetMorphologyFSTResult {
76
88
  }
77
89
 
78
90
  /**
79
- * Parse one `street_types.txt` line into `{ canonical, variants }`. Canonical is the first token (pre-`|`); variants
80
- * are all whitespace-stripped non-empty tokens including the canonical.
91
+ * Parse one `street_types.txt` line into `{ canonical, variants }`.
92
+ *
93
+ * Canonical is the first token (pre-`|`); variants are all whitespace-stripped
94
+ * non-empty tokens including the canonical.
81
95
  *
82
96
  * Lines with no `|` are treated as a single-form entry where canonical == variant.
83
97
  */
84
98
  function parseLine(line: string): { canonical: string; variants: string[] } | null {
85
99
  const trimmed = line.trim()
86
100
 
87
- if (!trimmed.length || trimmed.startsWith("#")) return null
101
+ if (!trimmed || trimmed.startsWith("#")) return null
88
102
 
89
- const parts = trimmed
90
- .split("|")
91
- .map((s) => s.trim())
92
- .filter((s) => s.length > 0)
103
+ const parts = TextSpliterator.from(trimmed, { delimiter: "|" }).toArray()
93
104
 
94
105
  if (!parts.length) return null
95
106
 
@@ -101,6 +112,7 @@ export async function buildStreetMorphologyFST(
101
112
  ): Promise<BuildStreetMorphologyFSTResult> {
102
113
  const progress = opts.onProgress ?? (() => {})
103
114
  const minVariantLength = opts.minVariantLength ?? 3
115
+ const dictionariesDir = PathBuilder.from(opts.dictionariesDir)
104
116
 
105
117
  // Discover locales — either provided explicitly, or all directories containing street_types.txt.
106
118
  let locales: string[]
@@ -110,7 +122,7 @@ export async function buildStreetMorphologyFST(
110
122
  locales = opts.locales
111
123
  } else {
112
124
  const entries = await Globerator.from("*", {
113
- cwd: opts.dictionariesDir,
125
+ cwd: dictionariesDir,
114
126
  absolute: false,
115
127
  onlyFiles: false,
116
128
  }).toArray()
@@ -118,7 +130,7 @@ export async function buildStreetMorphologyFST(
118
130
  const localeProbes: Array<[string, boolean]> = []
119
131
 
120
132
  for (const entry of entries) {
121
- const localePath = join(opts.dictionariesDir, entry)
133
+ const localePath = dictionariesDir(entry)
122
134
 
123
135
  if (!(await isDirectory(localePath))) {
124
136
  localeProbes.push([entry, false])
@@ -126,13 +138,7 @@ export async function buildStreetMorphologyFST(
126
138
  continue
127
139
  }
128
140
 
129
- try {
130
- await statPath(join(localePath, STREET_TYPES_FILENAME))
131
-
132
- localeProbes.push([entry, true])
133
- } catch {
134
- localeProbes.push([entry, false])
135
- }
141
+ localeProbes.push([entry, await isFile(localePath(STREET_TYPES_FILENAME))])
136
142
  }
137
143
 
138
144
  locales = localeProbes.filter(([, hasFile]) => hasFile).map(([entry]) => entry)
@@ -140,12 +146,12 @@ export async function buildStreetMorphologyFST(
140
146
 
141
147
  progress("discover", `Found ${locales.length} locales with ${STREET_TYPES_FILENAME}`)
142
148
 
143
- // Collect canonical → set-of-variants across all locales. Same canonical form may appear in
144
- // multiple locales (e.g. "avenue" in en/fr); we union the variant sets.
149
+ // Collect canonical → set-of-variants across all locales.
150
+ // Same canonical form may appear in multiple locales (e.g. "avenue" in en/fr); we union the variant sets.
145
151
  const canonicalToVariants = new Map<string, Set<string>>()
146
152
 
147
153
  for (const locale of locales) {
148
- const filePath = join(opts.dictionariesDir, locale, STREET_TYPES_FILENAME)
154
+ const filePath = dictionariesDir(locale, STREET_TYPES_FILENAME)
149
155
  const content = await readLocalTextFile(filePath)
150
156
 
151
157
  for (const line of TextSpliterator.from(content)) {
@@ -164,7 +170,8 @@ export async function buildStreetMorphologyFST(
164
170
 
165
171
  progress("collect", `Collected ${canonicalToVariants.size} canonical affixes`)
166
172
 
167
- // Assign stable synthetic wofIDs. Sort canonicals for determinism.
173
+ // Assign stable synthetic wofIDs.
174
+ // Sort canonicals for determinism.
168
175
  const sortedCanonicals = [...canonicalToVariants.keys()].toSorted()
169
176
  const canonicalToWOFID = new Map<string, number>()
170
177
 
@@ -172,8 +179,9 @@ export async function buildStreetMorphologyFST(
172
179
  canonicalToWOFID.set(sortedCanonicals[i]!, STREET_AFFIX_WOFID_BASE + i)
173
180
  }
174
181
 
175
- // Build the trie. Each variant is inserted as a token sequence pointing to its canonical's
176
- // PlaceEntry — so all variants of "avenue" (av/ave/aven/...) lead to the same terminal entry.
182
+ // Build the trie.
183
+ // Each variant is inserted as a token sequence pointing to its canonical's PlaceEntry —
184
+ // so all variants of "avenue" (av/ave/aven/...) lead to the same terminal entry.
177
185
  const nodes: FSTNode[] = [{ edges: new Map(), places: [] }]
178
186
 
179
187
  function insertName(tokens: string[], entry: PlaceEntry): void {
@@ -212,13 +220,16 @@ export async function buildStreetMorphologyFST(
212
220
  placetype: "street_affix",
213
221
  name: canonical,
214
222
  parentChain: [],
215
- // Fixed referential score: street affixes are structurally unambiguous (Avenue is almost
216
- // never anything but street-typing). The morphology prior caps bias separately; this value
217
- // just feeds the cap formula `referential * cap`. No encyclopedic field — a street affix is
218
- // not a place and has no article; absence here is the correct statement.
223
+ // Fixed referential score: street affixes are structurally unambiguous
224
+ // (Avenue is almost never anything but street-typing).
225
+ // The morphology prior caps bias separately.
226
+ // This value just feeds the cap formula `referential * cap`.
227
+ // No encyclopedic score — a street affix is not a place and has no article.
219
228
  referential: 1,
229
+ encyclopedic: null,
220
230
  lat: 0,
221
231
  lon: 0,
232
+ crossCountryBranches: null,
222
233
  }
223
234
 
224
235
  for (const variant of variants) {
@@ -251,7 +262,14 @@ export async function buildStreetMorphologyFST(
251
262
  edgeCount,
252
263
  nameInsertions: insertCount,
253
264
  importanceMatches: 0, // No importance scoring for morphology — fixed at 1.0.
254
- sourceDB: opts.dictionariesDir,
265
+ encyclopedicMatches: null,
266
+ importanceSource: null,
267
+ sourceDB: dictionariesDir.toString(),
268
+ sourceDBMD5: null,
269
+ sourceDBBytes: null,
270
+ modelCardVersion: null,
271
+ exclusionPolicy: null,
272
+ excludedInsertions: null,
255
273
  }
256
274
 
257
275
  return {
@@ -3,57 +3,64 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * Unified runtime loader for the street-morphology FST — the #1315 street-context check's signal
7
- * source, previously rebuilt from the libpostal dictionaries per process at three duplicate call
8
- * sites (runtime pipeline / parity eval / neural harness). The sealed artifact
9
- * (`fst-street-morphology.bin`, built by `mailwoman gazetteer build street-morphology`) replaces
10
- * those per-process builds; this loader is the ONE resolution ladder every node call site shares:
6
+ * Runtime loader for the street-morphology FST. The sealed artifact
7
+ * (`fst-street-morphology.bin`, built by `mailwoman gazetteer build street-morphology`) is the one
8
+ * resolution ladder every node call site shares.
11
9
  *
12
- * 1. An explicit `artifactPath` (e.g. the weights-package sibling surfaced by
13
- * `NeuralAddressClassifier.streetMorphologyPath`). When given, it is the only artifact probed.
14
- * 2. Otherwise the staged sealed artifact at `$MAILWOMAN_DATA_ROOT/wof/fst-street-morphology.bin`.
15
- * 3. Build-from-dictionaries fallback: `buildStreetMorphologyFST` over core's bundled libpostal
16
- * `street_types.txt` files — the pre-artifact behavior, kept so a missing artifact degrades to
17
- * a per-process build rather than a crash.
10
+ * 1. An explicit `artifactPath`, e.g. the weights-package sibling surfaced by
11
+ * `NeuralAddressClassifier.streetMorphologyPath`. When given, it is the only artifact probed.
12
+ * 2. Otherwise the staged sealed artifact at `$MAILWOMAN_DATA_ROOT/db/wof/fst-street-morphology.bin`.
13
+ * 3. A build-from-dictionaries fallback: `buildStreetMorphologyFST` over core's bundled libpostal
14
+ * `street_types.txt` files, kept so a missing artifact degrades to a per-process build instead
15
+ * of a crash.
18
16
  *
19
17
  * A present-but-unreadable artifact reports through `onWarn` and falls through to the build rung.
20
- * Browsers can't take the fallback (no fs) — they deserialize the same artifact via
21
- * `fst-deserialize-web.ts` (see the docs demo loader).
18
+ * Browsers cannot take the fallback because they have no filesystem API. They deserialize the same
19
+ * artifact through `fst-deserialize-web.ts` (see the docs demo loader).
22
20
  */
23
21
 
24
- import { dataRootPath } from "@mailwoman/core/data-root"
25
- import { pathExists, readLocalBuffer } from "@mailwoman/core/fs/readers"
22
+ import { readLocalBuffer } from "@mailwoman/core/fs/readers"
23
+ import { pathExists } from "@mailwoman/core/fs/readers/stat"
26
24
  import { resourceDictionaryPath } from "@mailwoman/core/paths"
25
+ import type { PathBuilder, PathBuilderLike } from "path-ts"
27
26
 
28
27
  import type { FSTMatcher } from "#fst/matcher"
29
28
  import { deserializeFST, readFSTProvenance } from "#fst/serialize"
30
29
  import type { FSTProvenance } from "#fst/types"
30
+ import { wofDatabasePath } from "#paths"
31
31
  import { buildStreetMorphologyFST } from "#street/morphology/fst/builder"
32
32
 
33
33
  /**
34
- * The sealed artifact's canonical filename — identical in the data-root staging dir and as a weights-package sibling.
34
+ * The sealed artifact's canonical filename, identical in the data-root staging dir
35
+ * and as a weights-package sibling.
35
36
  */
36
37
  export const STREET_MORPHOLOGY_ARTIFACT_FILENAME = "fst-street-morphology.bin"
37
38
 
38
39
  /**
39
- * The staged artifact's default location: `$MAILWOMAN_DATA_ROOT/wof/fst-street-morphology.bin`.
40
+ * The staged artifact's default location: `$MAILWOMAN_DATA_ROOT/db/wof/fst-street-morphology.bin`.
40
41
  */
41
- export function defaultStreetMorphologyArtifactPath(): string {
42
- return String(dataRootPath("wof", STREET_MORPHOLOGY_ARTIFACT_FILENAME))
42
+ export function defaultStreetMorphologyArtifactPath(): PathBuilder {
43
+ return wofDatabasePath(STREET_MORPHOLOGY_ARTIFACT_FILENAME)
43
44
  }
44
45
 
45
46
  export interface LoadStreetMorphologyFSTOpts {
46
47
  /**
47
- * Explicit artifact path (e.g. a weights-package sibling). When given it is the ONLY artifact probed — missing or
48
- * unreadable degrades straight to the dictionary build, never a throw.
48
+ * Explicit artifact path (e.g. A weights-package sibling).
49
+ *
50
+ * When given, it is the only artifact probed.
51
+ * A missing or unreadable artifact degrades straight to the dictionary build, never a throw.
49
52
  */
50
- artifactPath?: string
53
+ artifactPath?: PathBuilderLike
51
54
  /**
52
- * Dictionaries dir for the build fallback. Defaults to core's bundled libpostal dictionaries.
55
+ * Dictionaries dir for the build fallback.
56
+ *
57
+ * @defaultValue core's bundled libpostal dictionaries.
53
58
  */
54
- dictionariesDir?: string
59
+ dictionariesDir?: PathBuilderLike
55
60
  /**
56
- * Unreadable-artifact diagnostics. Defaults to silent (the caller owns its warn channel).
61
+ * Unreadable-artifact diagnostics.
62
+ *
63
+ * @defaultValue silent (the caller owns its warn channel).
57
64
  */
58
65
  onWarn?: (message: string) => void
59
66
  }
@@ -67,15 +74,16 @@ export interface LoadedStreetMorphologyFST {
67
74
  /**
68
75
  * The artifact path when `source === "artifact"`.
69
76
  */
70
- path?: string
77
+ path: PathBuilderLike | null
71
78
  /**
72
- * Build provenance — read from the artifact trailer, or carried fresh off the fallback build.
79
+ * Build provenance, read from the artifact trailer or copied from the fallback build.
73
80
  */
74
- provenance?: FSTProvenance
81
+ provenance: FSTProvenance | null
75
82
  }
76
83
 
77
84
  /**
78
- * Load the street-morphology matcher: sealed artifact first, per-process dictionary build as the degrade path.
85
+ * Load the street-morphology matcher: sealed artifact first, per-process
86
+ * dictionary build as the degrade path.
79
87
  */
80
88
  export async function loadStreetMorphologyFST(
81
89
  opts: LoadStreetMorphologyFSTOpts = {}
@@ -89,7 +97,7 @@ export async function loadStreetMorphologyFST(
89
97
  const matcher = deserializeFST(buf)
90
98
  const provenance = readFSTProvenance(buf)
91
99
 
92
- return { matcher, source: "artifact", path: artifactPath, ...(provenance ? { provenance } : {}) }
100
+ return { matcher, source: "artifact", path: artifactPath, provenance }
93
101
  } catch (error) {
94
102
  warn(
95
103
  `street-morphology artifact at ${artifactPath} unreadable (${(error as Error).message}) — falling back to the dictionary build`
@@ -98,8 +106,8 @@ export async function loadStreetMorphologyFST(
98
106
  }
99
107
 
100
108
  const built = await buildStreetMorphologyFST({
101
- dictionariesDir: opts.dictionariesDir ?? resourceDictionaryPath("libpostal"),
109
+ dictionariesDir: (opts.dictionariesDir ?? resourceDictionaryPath("libpostal")).toString(),
102
110
  })
103
111
 
104
- return { matcher: built.matcher, source: "built", provenance: built.provenance }
112
+ return { matcher: built.matcher, source: "built", path: null, provenance: built.provenance }
105
113
  }
@@ -3,68 +3,79 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * #727 stage-2 phase 4c — the SQLite backend for {@link StreetLocalityEvidence}.
6
+ * The SQLite backend for {@link StreetLocalityEvidence}.
7
7
  *
8
- * Reads a street-name index (the FR instance = BAN `street-centroids-fr.db`, a `street_centroid`
8
+ * Reads a street-name index (the FR instance is BAN `street-centroids-fr.db`, a `street_centroid`
9
9
  * table of `street_norm × locality_base × postcode` rows) and answers "does this street surface
10
- * exist as a name" for the k-best rerank. Sync-by-interface, `readOnly`, prepared statements,
11
- * graceful-degrade on a tableless extract — the same reader discipline as `AddressPointSqliteLookup`.
10
+ * exist as a name" for the k-best rerank. It is sync-by-interface and read-only, uses prepared
11
+ * statements. It also degrades gracefully on a tableless extract, following the same reader discipline as
12
+ * `AddressPointSqliteLookup`.
12
13
  *
13
- * THE FOLD CONTRACT: the surface is folded with {@link foldStreetSurface} (the shared function),
14
- * and the DB's `street_norm` column MUST have been built with that SAME fold or every hyphenated /
15
- * apostrophe'd street silently misses. The current `street-centroids-fr.db` predates the contract
16
- * fold (it folded without hyphen/apostrophe normalization); it must be REBUILT with
17
- * `foldStreetSurface` + a `street_norm` index before this backend is wired in production. Until
18
- * then this class is correct-by-construction against a fixture built with the contract fold, and
19
- * the production rebuild is a tracked BAN-sdk follow-up.
14
+ * The fold interface: the surface is folded with {@link foldStreetSurface} (the shared function),
15
+ * so the DB's `street_norm` column must have been built with that same fold or every hyphenated
16
+ * or apostrophe'd street silently misses. The column also needs a `street_norm` index before this
17
+ * backend is wired in production.
20
18
  */
21
19
 
22
20
  import { foldStreetSurface, type StreetEvidenceScope, type StreetLocalityEvidence } from "@mailwoman/resolver"
23
- import { DatabaseClient } from "@mailwoman/sqlite/client"
21
+ import type { DatabaseClient } from "@mailwoman/sqlite/client"
22
+ import { SQLiteLookup } from "@mailwoman/sqlite/lookup"
23
+ import type { PathBuilderLike } from "path-ts"
24
24
 
25
25
  import type { WOFDatabase } from "#schema"
26
26
  import { hasColumn, hasTable } from "#sqlite-utils"
27
27
 
28
28
  export interface SQLiteStreetNameLookupOpts {
29
29
  /**
30
- * ISO-2 (upper-case) countries this index answers for. Default `["FR"]` (the BAN street-centroids instance).
30
+ * ISO-2 (upper-case) countries this index answers for.
31
+ *
32
+ * @defaultValue `["FR"]` (the BAN street-centroids instance).
31
33
  */
32
34
  countries?: Iterable<string>
33
35
  /**
34
- * Table name. Default `street_centroid`.
36
+ * Table name.
37
+ *
38
+ * @defaultValue `street_centroid`
35
39
  */
36
40
  table?: string
37
41
  }
38
42
 
39
43
  /**
40
- * A {@link StreetLocalityEvidence} backed by a street-name SQLite index. Positive evidence only: any doubt (missing
41
- * table, read miss) returns `false`, so the rerank fails open to the model's ranking.
44
+ * A {@link StreetLocalityEvidence} backed by a street-name SQLite index.
45
+ *
46
+ * Positive evidence only: any doubt (missing table, read miss) returns `false`,
47
+ * so the rerank fails open to the model's ranking.
42
48
  */
43
- export class SQLiteStreetNameLookup implements StreetLocalityEvidence, Disposable {
49
+ export class SQLiteStreetNameLookup extends SQLiteLookup<WOFDatabase> implements StreetLocalityEvidence {
44
50
  readonly countries: ReadonlySet<string>
45
- readonly #db: DatabaseClient<WOFDatabase>
46
51
  readonly #byName: ReturnType<DatabaseClient["prepare"]> | undefined
47
52
  readonly #byNameLocality: ReturnType<DatabaseClient["prepare"]> | undefined
48
53
  readonly #byNamePostcode: ReturnType<DatabaseClient["prepare"]> | undefined
49
54
 
50
- constructor(dbPath: string, opts: SQLiteStreetNameLookupOpts = {}) {
55
+ constructor(dbPath: PathBuilderLike, opts: SQLiteStreetNameLookupOpts = {}) {
56
+ super({ databasePath: dbPath })
51
57
  this.countries = new Set([...(opts.countries ?? ["FR"])].map((c) => c.toUpperCase()))
52
- this.#db = new DatabaseClient<WOFDatabase>(dbPath, { readOnly: true })
53
58
  const table = opts.table ?? "street_centroid"
54
59
 
55
- // Degrade gracefully on an empty/tableless extract — a no-op miss, never a crash (#568 discipline).
56
- if (hasTable(this.#db, table)) {
57
- // Prefer the #727 phase-4c `name_key` column (foldStreetSurface, indexed by `idx_sc_name` for a direct seek);
58
- // fall back to `street_norm` on a pre-rebuild extract (a skip-scan, but correct). The fold used to build
59
- // `name_key` MUST match `foldStreetSurface` here (the fold-parity contract).
60
- const keyCol = hasColumn(this.#db, table, "name_key") ? "name_key" : "street_norm"
61
- this.#byName = this.#db.prepare(`SELECT 1 FROM ${table} WHERE ${keyCol} = ? LIMIT 1`)
60
+ // Degrade gracefully on an empty or tableless extract.
61
+ // A no-op miss, never a crash.
62
+ if (hasTable(this.database, table)) {
63
+ // Prefer the `name_key` column (built with `foldStreetSurface`
64
+ // and indexed by `idx_sc_name` for a direct seek).
65
+ // On a pre-rebuild extract, `street_norm` is a correct fallback.
66
+ // It uses a skip-scan.
67
+ // The fold that built `name_key` must match `foldStreetSurface` here.
68
+ // This is the fold-parity interface.
69
+ const keyCol = hasColumn(this.database, table, "name_key") ? "name_key" : "street_norm"
70
+ this.#byName = this.database.prepare(`SELECT 1 FROM ${table} WHERE ${keyCol} = ? LIMIT 1`)
62
71
 
63
- this.#byNameLocality = this.#db.prepare(
72
+ this.#byNameLocality = this.database.prepare(
64
73
  `SELECT 1 FROM ${table} WHERE ${keyCol} = ? AND locality_base = ? LIMIT 1`
65
74
  )
66
75
 
67
- this.#byNamePostcode = this.#db.prepare(`SELECT 1 FROM ${table} WHERE ${keyCol} = ? AND postcode = ? LIMIT 1`)
76
+ this.#byNamePostcode = this.database.prepare(
77
+ `SELECT 1 FROM ${table} WHERE ${keyCol} = ? AND postcode = ? LIMIT 1`
78
+ )
68
79
  }
69
80
  }
70
81
 
@@ -74,24 +85,17 @@ export class SQLiteStreetNameLookup implements StreetLocalityEvidence, Disposabl
74
85
 
75
86
  if (!norm) return false
76
87
 
77
- // Scoped lookups tighten precision when the hypothesis carries a locality/postcode; a scoped MISS falls back to the
78
- // unscoped probe (index incompleteness in the scope column is not evidence of absence — positive-evidence rule).
79
- if (
80
- scope?.locality &&
81
- this.#byNameLocality &&
82
- this.#byNameLocality.get(norm, foldStreetSurface(scope.locality)) !== undefined
83
- ) {
88
+ // Scoped lookups tighten precision when the hypothesis includes a locality/postcode.
89
+ // A scoped miss falls back to the unscoped probe.
90
+ // The scope column may be incomplete, so a miss there does not establish absence.
91
+ if (scope?.locality && this.#byNameLocality && this.#byNameLocality.get(norm, foldStreetSurface(scope.locality))) {
84
92
  return true
85
93
  }
86
94
 
87
- if (scope?.postcode && this.#byNamePostcode && this.#byNamePostcode.get(norm, scope.postcode) !== undefined) {
95
+ if (scope?.postcode && this.#byNamePostcode && this.#byNamePostcode.get(norm, scope.postcode)) {
88
96
  return true
89
97
  }
90
98
 
91
99
  return this.#byName.get(norm) !== undefined
92
100
  }
93
-
94
- [Symbol.dispose](): void {
95
- this.#db[Symbol.dispose]()
96
- }
97
101
  }