@mailwoman/resolver-wof-sqlite 9.1.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 (501) hide show
  1. package/README.md +36 -20
  2. package/lib/address/index.ts +9 -0
  3. package/{address-point-interpolation.ts → lib/address/point-interpolation.ts} +40 -28
  4. package/{address-point-schema.ts → lib/address/point-schema.ts} +34 -8
  5. package/lib/address/point.ts +280 -0
  6. package/{ancestry-backfill.ts → lib/ancestry/backfill.ts} +14 -19
  7. package/{ancestry.ts → lib/ancestry/index.ts} +13 -8
  8. package/{build-candidate.ts → lib/build-candidate.ts} +243 -199
  9. package/{build-slim.ts → lib/build-slim.ts} +153 -168
  10. package/lib/candidate/alias-bags.ts +56 -0
  11. package/lib/candidate/ancestors-sidecar.ts +204 -0
  12. package/lib/candidate/country-display-names.ts +79 -0
  13. package/lib/candidate/extract-fold.ts +138 -0
  14. package/lib/candidate/name-roles.ts +238 -0
  15. package/lib/candidate/own-name.ts +146 -0
  16. package/lib/candidate/place-attrs.ts +44 -0
  17. package/lib/candidate-ancestors-schema.ts +195 -0
  18. package/{candidate-fts.ts → lib/candidate-fts.ts} +7 -5
  19. package/{candidate-importance.ts → lib/candidate-importance.ts} +54 -57
  20. package/lib/candidate-lookup.ts +976 -0
  21. package/{candidate-schema.ts → lib/candidate-schema.ts} +34 -6
  22. package/lib/candidate-scoring.ts +261 -0
  23. package/lib/capital-schema.ts +89 -0
  24. package/lib/capitals.ts +148 -0
  25. package/{coincident-roles.ts → lib/coincident-roles.ts} +75 -19
  26. package/{convention.ts → lib/convention/index.ts} +5 -5
  27. package/lib/convention/schema.ts +72 -0
  28. package/{coverage-manifest-schema.ts → lib/coverage-manifest-schema.ts} +15 -16
  29. package/lib/currency-backfill.ts +334 -0
  30. package/lib/env.ts +50 -0
  31. package/lib/exact-match.ts +113 -0
  32. package/{sharding.ts → lib/extracts.ts} +63 -60
  33. package/lib/fst/autocomplete.ts +176 -0
  34. package/{fst-builder.ts → lib/fst/builder.ts} +30 -27
  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} +42 -75
  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} +28 -23
  43. package/{fts-query.ts → lib/fts/query.ts} +2 -2
  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} +16 -15
  47. package/{index.ts → lib/index.ts} +52 -48
  48. package/{interpolation.ts → lib/interpolation.ts} +137 -41
  49. package/lib/lookup.ts +861 -0
  50. package/{name-score.ts → lib/name-score.ts} +6 -4
  51. package/lib/nsul/index.ts +8 -0
  52. package/lib/nsul/lookup.ts +144 -0
  53. package/lib/nsul/schema.ts +130 -0
  54. package/{place-importance-schema.ts → lib/place-importance-schema.ts} +70 -22
  55. package/lib/poi/index.ts +8 -0
  56. package/{poi-lookup.ts → lib/poi/lookup.ts} +32 -39
  57. package/{poi-schema.ts → lib/poi/schema.ts} +10 -6
  58. package/lib/polygon-schema.ts +47 -0
  59. package/{postal-city-alias-lookup.ts → lib/postal/city-alias-lookup.ts} +15 -21
  60. package/{postal-city-candidate-schema.ts → lib/postal/city-candidate-schema.ts} +4 -2
  61. package/lib/postal/index.ts +9 -0
  62. package/{postcode-point-lookup.ts → lib/postcode-point-lookup.ts} +17 -15
  63. package/lib/primary-preference.ts +226 -0
  64. package/lib/proximity-rerank.ts +120 -0
  65. package/{ranking-weights.ts → lib/ranking-weights.ts} +30 -4
  66. package/lib/region-keys.ts +144 -0
  67. package/{reverse.ts → lib/reverse.ts} +45 -56
  68. package/{schema.ts → lib/schema.ts} +11 -1
  69. package/lib/search-fetch.ts +257 -0
  70. package/{sqlite-convention-source.ts → lib/sqlite-convention-source.ts} +9 -10
  71. package/lib/sqlite-utils.ts +83 -0
  72. package/{street-centroid-schema.ts → lib/street/centroid-schema.ts} +12 -6
  73. package/{street-centroid.ts → lib/street/centroid.ts} +26 -28
  74. package/lib/street/index.ts +13 -0
  75. package/{street-morphology-fst-builder.ts → lib/street/morphology-fst-builder.ts} +24 -14
  76. package/{street-morphology-fst-loader.ts → lib/street/morphology-fst-loader.ts} +14 -12
  77. package/{street-name-lookup.ts → lib/street/name-lookup.ts} +14 -30
  78. package/lib/street/normalize.ts +572 -0
  79. package/{street-segment-schema.ts → lib/street/segment-schema.ts} +13 -8
  80. package/{types.ts → lib/types.ts} +49 -9
  81. package/{unified-schema.ts → lib/unified-schema.ts} +21 -25
  82. package/lib/uprn/existence.ts +84 -0
  83. package/lib/uprn/index.ts +9 -0
  84. package/lib/uprn/lookup.ts +206 -0
  85. package/lib/uprn/schema.ts +124 -0
  86. package/lib/weights-overlay-linker.ts +878 -0
  87. package/out/address/index.d.ts +9 -0
  88. package/out/address/index.d.ts.map +1 -0
  89. package/out/address/index.js +9 -0
  90. package/out/address/index.js.map +1 -0
  91. package/out/{address-point-interpolation.d.ts → address/point-interpolation.d.ts} +11 -10
  92. package/out/address/point-interpolation.d.ts.map +1 -0
  93. package/out/{address-point-interpolation.js → address/point-interpolation.js} +29 -23
  94. package/out/address/point-interpolation.js.map +1 -0
  95. package/out/{address-point-schema.d.ts → address/point-schema.d.ts} +30 -10
  96. package/out/address/point-schema.d.ts.map +1 -0
  97. package/out/{address-point-schema.js → address/point-schema.js} +7 -3
  98. package/out/address/point-schema.js.map +1 -0
  99. package/out/{address-point.d.ts → address/point.d.ts} +16 -8
  100. package/out/address/point.d.ts.map +1 -0
  101. package/out/address/point.js +191 -0
  102. package/out/address/point.js.map +1 -0
  103. package/out/{ancestry-backfill.d.ts → ancestry/backfill.d.ts} +7 -5
  104. package/out/ancestry/backfill.d.ts.map +1 -0
  105. package/out/{ancestry-backfill.js → ancestry/backfill.js} +12 -16
  106. package/out/ancestry/backfill.js.map +1 -0
  107. package/out/{ancestry.d.ts → ancestry/index.d.ts} +6 -5
  108. package/out/ancestry/index.d.ts.map +1 -0
  109. package/out/{ancestry.js → ancestry/index.js} +7 -7
  110. package/out/ancestry/index.js.map +1 -0
  111. package/out/build-candidate.d.ts +88 -7
  112. package/out/build-candidate.d.ts.map +1 -1
  113. package/out/build-candidate.js +145 -149
  114. package/out/build-candidate.js.map +1 -1
  115. package/out/build-slim.d.ts +5 -5
  116. package/out/build-slim.d.ts.map +1 -1
  117. package/out/build-slim.js +127 -142
  118. package/out/build-slim.js.map +1 -1
  119. package/out/candidate/alias-bags.d.ts +19 -0
  120. package/out/candidate/alias-bags.d.ts.map +1 -0
  121. package/out/candidate/alias-bags.js +39 -0
  122. package/out/candidate/alias-bags.js.map +1 -0
  123. package/out/candidate/ancestors-sidecar.d.ts +32 -0
  124. package/out/candidate/ancestors-sidecar.d.ts.map +1 -0
  125. package/out/candidate/ancestors-sidecar.js +140 -0
  126. package/out/candidate/ancestors-sidecar.js.map +1 -0
  127. package/out/candidate/country-display-names.d.ts +35 -0
  128. package/out/candidate/country-display-names.d.ts.map +1 -0
  129. package/out/candidate/country-display-names.js +59 -0
  130. package/out/candidate/country-display-names.js.map +1 -0
  131. package/out/candidate/extract-fold.d.ts +32 -0
  132. package/out/candidate/extract-fold.d.ts.map +1 -0
  133. package/out/candidate/extract-fold.js +104 -0
  134. package/out/candidate/extract-fold.js.map +1 -0
  135. package/out/candidate/name-roles.d.ts +57 -0
  136. package/out/candidate/name-roles.d.ts.map +1 -0
  137. package/out/candidate/name-roles.js +166 -0
  138. package/out/candidate/name-roles.js.map +1 -0
  139. package/out/candidate/own-name.d.ts +50 -0
  140. package/out/candidate/own-name.d.ts.map +1 -0
  141. package/out/candidate/own-name.js +132 -0
  142. package/out/candidate/own-name.js.map +1 -0
  143. package/out/candidate/place-attrs.d.ts +43 -0
  144. package/out/candidate/place-attrs.d.ts.map +1 -0
  145. package/out/candidate/place-attrs.js +15 -0
  146. package/out/candidate/place-attrs.js.map +1 -0
  147. package/out/candidate-ancestors-schema.d.ts +150 -0
  148. package/out/candidate-ancestors-schema.d.ts.map +1 -0
  149. package/out/candidate-ancestors-schema.js +123 -0
  150. package/out/candidate-ancestors-schema.js.map +1 -0
  151. package/out/candidate-fts.d.ts +7 -5
  152. package/out/candidate-fts.d.ts.map +1 -1
  153. package/out/candidate-fts.js +5 -3
  154. package/out/candidate-fts.js.map +1 -1
  155. package/out/candidate-importance.d.ts +16 -16
  156. package/out/candidate-importance.d.ts.map +1 -1
  157. package/out/candidate-importance.js +47 -52
  158. package/out/candidate-importance.js.map +1 -1
  159. package/out/candidate-lookup.d.ts +31 -52
  160. package/out/candidate-lookup.d.ts.map +1 -1
  161. package/out/candidate-lookup.js +380 -172
  162. package/out/candidate-lookup.js.map +1 -1
  163. package/out/candidate-schema.d.ts +31 -7
  164. package/out/candidate-schema.d.ts.map +1 -1
  165. package/out/candidate-schema.js +3 -0
  166. package/out/candidate-schema.js.map +1 -1
  167. package/out/candidate-scoring.d.ts +34 -0
  168. package/out/candidate-scoring.d.ts.map +1 -0
  169. package/out/candidate-scoring.js +196 -0
  170. package/out/candidate-scoring.js.map +1 -0
  171. package/out/capital-schema.d.ts +51 -0
  172. package/out/capital-schema.d.ts.map +1 -0
  173. package/out/capital-schema.js +63 -0
  174. package/out/capital-schema.js.map +1 -0
  175. package/out/capitals.d.ts +69 -0
  176. package/out/capitals.d.ts.map +1 -0
  177. package/out/capitals.js +98 -0
  178. package/out/capitals.js.map +1 -0
  179. package/out/coincident-roles.d.ts +12 -4
  180. package/out/coincident-roles.d.ts.map +1 -1
  181. package/out/coincident-roles.js +43 -11
  182. package/out/coincident-roles.js.map +1 -1
  183. package/out/{convention.d.ts → convention/index.d.ts} +5 -5
  184. package/out/convention/index.d.ts.map +1 -0
  185. package/out/{convention.js → convention/index.js} +4 -4
  186. package/out/convention/index.js.map +1 -0
  187. package/out/convention/schema.d.ts +51 -0
  188. package/out/convention/schema.d.ts.map +1 -0
  189. package/out/convention/schema.js +34 -0
  190. package/out/convention/schema.js.map +1 -0
  191. package/out/coverage-manifest-schema.d.ts +8 -8
  192. package/out/coverage-manifest-schema.d.ts.map +1 -1
  193. package/out/coverage-manifest-schema.js +6 -10
  194. package/out/coverage-manifest-schema.js.map +1 -1
  195. package/out/currency-backfill.d.ts +90 -0
  196. package/out/currency-backfill.d.ts.map +1 -0
  197. package/out/currency-backfill.js +196 -0
  198. package/out/currency-backfill.js.map +1 -0
  199. package/out/env.d.ts +43 -0
  200. package/out/env.d.ts.map +1 -0
  201. package/out/env.js +48 -0
  202. package/out/env.js.map +1 -0
  203. package/out/exact-match.d.ts +25 -0
  204. package/out/exact-match.d.ts.map +1 -0
  205. package/out/exact-match.js +88 -0
  206. package/out/exact-match.js.map +1 -0
  207. package/out/extracts.d.ts +114 -0
  208. package/out/extracts.d.ts.map +1 -0
  209. package/out/{sharding.js → extracts.js} +38 -38
  210. package/out/extracts.js.map +1 -0
  211. package/out/{fst-autocomplete.d.ts → fst/autocomplete.d.ts} +13 -13
  212. package/out/fst/autocomplete.d.ts.map +1 -0
  213. package/out/fst/autocomplete.js +113 -0
  214. package/out/fst/autocomplete.js.map +1 -0
  215. package/out/{fst-builder.d.ts → fst/builder.d.ts} +5 -5
  216. package/out/fst/builder.d.ts.map +1 -0
  217. package/out/{fst-builder.js → fst/builder.js} +24 -24
  218. package/out/fst/builder.js.map +1 -0
  219. package/out/{fst-deserialize-web.d.ts → fst/deserialize-web.d.ts} +3 -3
  220. package/out/fst/deserialize-web.d.ts.map +1 -0
  221. package/out/{fst-deserialize-web.js → fst/deserialize-web.js} +10 -74
  222. package/out/fst/deserialize-web.js.map +1 -0
  223. package/out/fst/format.d.ts +80 -0
  224. package/out/fst/format.d.ts.map +1 -0
  225. package/out/fst/format.js +91 -0
  226. package/out/fst/format.js.map +1 -0
  227. package/out/{fst-freshness.d.ts → fst/freshness.d.ts} +11 -14
  228. package/out/fst/freshness.d.ts.map +1 -0
  229. package/out/{fst-freshness.js → fst/freshness.js} +42 -74
  230. package/out/fst/freshness.js.map +1 -0
  231. package/out/fst/index.d.ts +14 -0
  232. package/out/fst/index.d.ts.map +1 -0
  233. package/out/fst/index.js +14 -0
  234. package/out/fst/index.js.map +1 -0
  235. package/out/{fst-matcher.d.ts → fst/matcher.d.ts} +2 -2
  236. package/out/fst/matcher.d.ts.map +1 -0
  237. package/out/{fst-matcher.js → fst/matcher.js} +1 -1
  238. package/out/fst/matcher.js.map +1 -0
  239. package/out/{fst-serialize.d.ts → fst/serialize.d.ts} +5 -10
  240. package/out/fst/serialize.d.ts.map +1 -0
  241. package/out/{fst-serialize.js → fst/serialize.js} +18 -98
  242. package/out/fst/serialize.js.map +1 -0
  243. package/out/{fst-types.d.ts → fst/types.d.ts} +4 -3
  244. package/out/fst/types.d.ts.map +1 -0
  245. package/out/{fst-types.js → fst/types.js} +1 -1
  246. package/out/fst/types.js.map +1 -0
  247. package/out/{fts.d.ts → fts/index.d.ts} +20 -13
  248. package/out/fts/index.d.ts.map +1 -0
  249. package/out/{fts.js → fts/index.js} +20 -15
  250. package/out/fts/index.js.map +1 -0
  251. package/out/{fts-query.d.ts → fts/query.d.ts} +2 -2
  252. package/out/fts/query.d.ts.map +1 -0
  253. package/out/{fts-query.js → fts/query.js} +2 -2
  254. package/out/fts/query.js.map +1 -0
  255. package/out/{geonames-aliases.d.ts → geonames/aliases.d.ts} +8 -6
  256. package/out/geonames/aliases.d.ts.map +1 -0
  257. package/out/{geonames-aliases.js → geonames/aliases.js} +7 -7
  258. package/out/geonames/aliases.js.map +1 -0
  259. package/out/geonames/index.d.ts +8 -0
  260. package/out/geonames/index.d.ts.map +1 -0
  261. package/out/geonames/index.js +8 -0
  262. package/out/geonames/index.js.map +1 -0
  263. package/out/{geonames-postal.d.ts → geonames/postal.d.ts} +12 -10
  264. package/out/geonames/postal.d.ts.map +1 -0
  265. package/out/{geonames-postal.js → geonames/postal.js} +11 -11
  266. package/out/geonames/postal.js.map +1 -0
  267. package/out/index.d.ts +32 -31
  268. package/out/index.d.ts.map +1 -1
  269. package/out/index.js +24 -24
  270. package/out/index.js.map +1 -1
  271. package/out/interpolation.d.ts +18 -9
  272. package/out/interpolation.d.ts.map +1 -1
  273. package/out/interpolation.js +108 -36
  274. package/out/interpolation.js.map +1 -1
  275. package/out/lookup.d.ts +25 -25
  276. package/out/lookup.d.ts.map +1 -1
  277. package/out/lookup.js +174 -558
  278. package/out/lookup.js.map +1 -1
  279. package/out/name-score.d.ts +0 -10
  280. package/out/name-score.d.ts.map +1 -1
  281. package/out/name-score.js +6 -4
  282. package/out/name-score.js.map +1 -1
  283. package/out/nsul/index.d.ts +8 -0
  284. package/out/nsul/index.d.ts.map +1 -0
  285. package/out/nsul/index.js +8 -0
  286. package/out/nsul/index.js.map +1 -0
  287. package/out/nsul/lookup.d.ts +83 -0
  288. package/out/nsul/lookup.d.ts.map +1 -0
  289. package/out/nsul/lookup.js +80 -0
  290. package/out/nsul/lookup.js.map +1 -0
  291. package/out/nsul/schema.d.ts +100 -0
  292. package/out/nsul/schema.d.ts.map +1 -0
  293. package/out/nsul/schema.js +78 -0
  294. package/out/nsul/schema.js.map +1 -0
  295. package/out/place-importance-schema.d.ts +47 -10
  296. package/out/place-importance-schema.d.ts.map +1 -1
  297. package/out/place-importance-schema.js +56 -10
  298. package/out/place-importance-schema.js.map +1 -1
  299. package/out/poi/index.d.ts +8 -0
  300. package/out/poi/index.d.ts.map +1 -0
  301. package/out/poi/index.js +8 -0
  302. package/out/poi/index.js.map +1 -0
  303. package/out/{poi-lookup.d.ts → poi/lookup.d.ts} +8 -10
  304. package/out/poi/lookup.d.ts.map +1 -0
  305. package/out/{poi-lookup.js → poi/lookup.js} +24 -29
  306. package/out/poi/lookup.js.map +1 -0
  307. package/out/{poi-schema.d.ts → poi/schema.d.ts} +10 -6
  308. package/out/poi/schema.d.ts.map +1 -0
  309. package/out/{poi-schema.js → poi/schema.js} +1 -1
  310. package/out/poi/schema.js.map +1 -0
  311. package/out/polygon-schema.d.ts +37 -0
  312. package/out/polygon-schema.d.ts.map +1 -0
  313. package/out/polygon-schema.js +23 -0
  314. package/out/polygon-schema.js.map +1 -0
  315. package/out/{postal-city-alias-lookup.d.ts → postal/city-alias-lookup.d.ts} +7 -6
  316. package/out/postal/city-alias-lookup.d.ts.map +1 -0
  317. package/out/{postal-city-alias-lookup.js → postal/city-alias-lookup.js} +12 -16
  318. package/out/postal/city-alias-lookup.js.map +1 -0
  319. package/out/{postal-city-alias-schema.d.ts → postal/city-alias-schema.d.ts} +1 -1
  320. package/out/{postal-city-alias-schema.d.ts.map → postal/city-alias-schema.d.ts.map} +1 -1
  321. package/out/{postal-city-alias-schema.js → postal/city-alias-schema.js} +1 -1
  322. package/out/{postal-city-alias-schema.js.map → postal/city-alias-schema.js.map} +1 -1
  323. package/out/{postal-city-candidate-schema.d.ts → postal/city-candidate-schema.d.ts} +4 -3
  324. package/out/postal/city-candidate-schema.d.ts.map +1 -0
  325. package/out/{postal-city-candidate-schema.js → postal/city-candidate-schema.js} +2 -2
  326. package/out/{postal-city-candidate-schema.js.map → postal/city-candidate-schema.js.map} +1 -1
  327. package/out/postal/index.d.ts +9 -0
  328. package/out/postal/index.d.ts.map +1 -0
  329. package/out/postal/index.js +9 -0
  330. package/out/postal/index.js.map +1 -0
  331. package/out/postcode-point-lookup.d.ts +10 -10
  332. package/out/postcode-point-lookup.d.ts.map +1 -1
  333. package/out/postcode-point-lookup.js +13 -13
  334. package/out/postcode-point-lookup.js.map +1 -1
  335. package/out/primary-preference.d.ts +133 -0
  336. package/out/primary-preference.d.ts.map +1 -0
  337. package/out/primary-preference.js +146 -0
  338. package/out/primary-preference.js.map +1 -0
  339. package/out/proximity-rerank.d.ts +77 -0
  340. package/out/proximity-rerank.d.ts.map +1 -0
  341. package/out/proximity-rerank.js +86 -0
  342. package/out/proximity-rerank.js.map +1 -0
  343. package/out/ranking-weights.d.ts +15 -3
  344. package/out/ranking-weights.d.ts.map +1 -1
  345. package/out/ranking-weights.js +21 -3
  346. package/out/ranking-weights.js.map +1 -1
  347. package/out/region-keys.d.ts +47 -0
  348. package/out/region-keys.d.ts.map +1 -0
  349. package/out/region-keys.js +121 -0
  350. package/out/region-keys.js.map +1 -0
  351. package/out/reverse.d.ts +6 -6
  352. package/out/reverse.d.ts.map +1 -1
  353. package/out/reverse.js +23 -35
  354. package/out/reverse.js.map +1 -1
  355. package/out/schema.d.ts +10 -1
  356. package/out/schema.d.ts.map +1 -1
  357. package/out/schema.js.map +1 -1
  358. package/out/search-fetch.d.ts +59 -0
  359. package/out/search-fetch.d.ts.map +1 -0
  360. package/out/search-fetch.js +184 -0
  361. package/out/search-fetch.js.map +1 -0
  362. package/out/sqlite-convention-source.d.ts +7 -7
  363. package/out/sqlite-convention-source.d.ts.map +1 -1
  364. package/out/sqlite-convention-source.js +5 -5
  365. package/out/sqlite-convention-source.js.map +1 -1
  366. package/out/sqlite-utils.d.ts +24 -6
  367. package/out/sqlite-utils.d.ts.map +1 -1
  368. package/out/sqlite-utils.js +24 -7
  369. package/out/sqlite-utils.js.map +1 -1
  370. package/out/{street-centroid-schema.d.ts → street/centroid-schema.d.ts} +12 -7
  371. package/out/street/centroid-schema.d.ts.map +1 -0
  372. package/out/{street-centroid-schema.js → street/centroid-schema.js} +5 -5
  373. package/out/{street-centroid-schema.js.map → street/centroid-schema.js.map} +1 -1
  374. package/out/{street-centroid.d.ts → street/centroid.d.ts} +6 -6
  375. package/out/street/centroid.d.ts.map +1 -0
  376. package/out/{street-centroid.js → street/centroid.js} +18 -24
  377. package/out/street/centroid.js.map +1 -0
  378. package/out/street/index.d.ts +13 -0
  379. package/out/street/index.d.ts.map +1 -0
  380. package/out/street/index.js +13 -0
  381. package/out/street/index.js.map +1 -0
  382. package/out/{street-morphology-fst-builder.d.ts → street/morphology-fst-builder.d.ts} +4 -4
  383. package/out/street/morphology-fst-builder.d.ts.map +1 -0
  384. package/out/{street-morphology-fst-builder.js → street/morphology-fst-builder.js} +18 -13
  385. package/out/street/morphology-fst-builder.js.map +1 -0
  386. package/out/{street-morphology-fst-loader.d.ts → street/morphology-fst-loader.d.ts} +5 -5
  387. package/out/street/morphology-fst-loader.d.ts.map +1 -0
  388. package/out/{street-morphology-fst-loader.js → street/morphology-fst-loader.js} +11 -10
  389. package/out/street/morphology-fst-loader.js.map +1 -0
  390. package/out/{street-name-lookup.d.ts → street/name-lookup.d.ts} +4 -7
  391. package/out/street/name-lookup.d.ts.map +1 -0
  392. package/out/{street-name-lookup.js → street/name-lookup.js} +9 -23
  393. package/out/street/name-lookup.js.map +1 -0
  394. package/out/street/normalize.d.ts +179 -0
  395. package/out/street/normalize.d.ts.map +1 -0
  396. package/out/street/normalize.js +457 -0
  397. package/out/street/normalize.js.map +1 -0
  398. package/out/{street-segment-schema.d.ts → street/segment-schema.d.ts} +13 -9
  399. package/out/street/segment-schema.d.ts.map +1 -0
  400. package/out/{street-segment-schema.js → street/segment-schema.js} +4 -4
  401. package/out/{street-segment-schema.js.map → street/segment-schema.js.map} +1 -1
  402. package/out/types.d.ts +49 -9
  403. package/out/types.d.ts.map +1 -1
  404. package/out/types.js.map +1 -1
  405. package/out/unified-schema.d.ts +6 -5
  406. package/out/unified-schema.d.ts.map +1 -1
  407. package/out/unified-schema.js +16 -19
  408. package/out/unified-schema.js.map +1 -1
  409. package/out/uprn/existence.d.ts +53 -0
  410. package/out/uprn/existence.d.ts.map +1 -0
  411. package/out/uprn/existence.js +61 -0
  412. package/out/uprn/existence.js.map +1 -0
  413. package/out/uprn/index.d.ts +9 -0
  414. package/out/uprn/index.d.ts.map +1 -0
  415. package/out/uprn/index.js +9 -0
  416. package/out/uprn/index.js.map +1 -0
  417. package/out/uprn/lookup.d.ts +85 -0
  418. package/out/uprn/lookup.d.ts.map +1 -0
  419. package/out/uprn/lookup.js +149 -0
  420. package/out/uprn/lookup.js.map +1 -0
  421. package/out/uprn/schema.d.ts +93 -0
  422. package/out/uprn/schema.d.ts.map +1 -0
  423. package/out/uprn/schema.js +78 -0
  424. package/out/uprn/schema.js.map +1 -0
  425. package/out/weights-overlay-linker.d.ts +299 -0
  426. package/out/weights-overlay-linker.d.ts.map +1 -0
  427. package/out/weights-overlay-linker.js +511 -0
  428. package/out/weights-overlay-linker.js.map +1 -0
  429. package/package.json +622 -154
  430. package/address-point.ts +0 -125
  431. package/candidate-lookup.ts +0 -720
  432. package/fst-autocomplete.ts +0 -204
  433. package/geo.ts +0 -121
  434. package/lookup.ts +0 -1354
  435. package/out/address-point-interpolation.d.ts.map +0 -1
  436. package/out/address-point-interpolation.js.map +0 -1
  437. package/out/address-point-schema.d.ts.map +0 -1
  438. package/out/address-point-schema.js.map +0 -1
  439. package/out/address-point.d.ts.map +0 -1
  440. package/out/address-point.js +0 -84
  441. package/out/address-point.js.map +0 -1
  442. package/out/ancestry-backfill.d.ts.map +0 -1
  443. package/out/ancestry-backfill.js.map +0 -1
  444. package/out/ancestry.d.ts.map +0 -1
  445. package/out/ancestry.js.map +0 -1
  446. package/out/convention.d.ts.map +0 -1
  447. package/out/convention.js.map +0 -1
  448. package/out/fst-autocomplete.d.ts.map +0 -1
  449. package/out/fst-autocomplete.js +0 -130
  450. package/out/fst-autocomplete.js.map +0 -1
  451. package/out/fst-builder.d.ts.map +0 -1
  452. package/out/fst-builder.js.map +0 -1
  453. package/out/fst-deserialize-web.d.ts.map +0 -1
  454. package/out/fst-deserialize-web.js.map +0 -1
  455. package/out/fst-freshness.d.ts.map +0 -1
  456. package/out/fst-freshness.js.map +0 -1
  457. package/out/fst-matcher.d.ts.map +0 -1
  458. package/out/fst-matcher.js.map +0 -1
  459. package/out/fst-serialize.d.ts.map +0 -1
  460. package/out/fst-serialize.js.map +0 -1
  461. package/out/fst-types.d.ts.map +0 -1
  462. package/out/fst-types.js.map +0 -1
  463. package/out/fts-query.d.ts.map +0 -1
  464. package/out/fts-query.js.map +0 -1
  465. package/out/fts.d.ts.map +0 -1
  466. package/out/fts.js.map +0 -1
  467. package/out/geo.d.ts +0 -74
  468. package/out/geo.d.ts.map +0 -1
  469. package/out/geo.js +0 -71
  470. package/out/geo.js.map +0 -1
  471. package/out/geonames-aliases.d.ts.map +0 -1
  472. package/out/geonames-aliases.js.map +0 -1
  473. package/out/geonames-postal.d.ts.map +0 -1
  474. package/out/geonames-postal.js.map +0 -1
  475. package/out/poi-lookup.d.ts.map +0 -1
  476. package/out/poi-lookup.js.map +0 -1
  477. package/out/poi-schema.d.ts.map +0 -1
  478. package/out/poi-schema.js.map +0 -1
  479. package/out/postal-city-alias-lookup.d.ts.map +0 -1
  480. package/out/postal-city-alias-lookup.js.map +0 -1
  481. package/out/postal-city-candidate-schema.d.ts.map +0 -1
  482. package/out/sharding.d.ts +0 -114
  483. package/out/sharding.d.ts.map +0 -1
  484. package/out/sharding.js.map +0 -1
  485. package/out/street-centroid-schema.d.ts.map +0 -1
  486. package/out/street-centroid.d.ts.map +0 -1
  487. package/out/street-centroid.js.map +0 -1
  488. package/out/street-morphology-fst-builder.d.ts.map +0 -1
  489. package/out/street-morphology-fst-builder.js.map +0 -1
  490. package/out/street-morphology-fst-loader.d.ts.map +0 -1
  491. package/out/street-morphology-fst-loader.js.map +0 -1
  492. package/out/street-name-lookup.d.ts.map +0 -1
  493. package/out/street-name-lookup.js.map +0 -1
  494. package/out/street-normalize.d.ts +0 -95
  495. package/out/street-normalize.d.ts.map +0 -1
  496. package/out/street-normalize.js +0 -272
  497. package/out/street-normalize.js.map +0 -1
  498. package/out/street-segment-schema.d.ts.map +0 -1
  499. package/sqlite-utils.ts +0 -46
  500. package/street-normalize.ts +0 -318
  501. /package/{postal-city-alias-schema.ts → lib/postal/city-alias-schema.ts} +0 -0
@@ -19,7 +19,7 @@
19
19
  * EDGE TABLE [edgeCount × 8 bytes] stringIdx u32 index into string table targetState u32
20
20
  *
21
21
  * PLACE TABLE [placeCount × 60 bytes at V5, 56 below] wofID u32 placetypeIdx u8 index into
22
- * PLACETYPE_ORDER chainLen u8 0..8 crossCountryBranches u8 (header flags bit0 gates the read)
22
+ * PLACETYPE_ORDER chainLen u8 0..8 crossCountryBranches u8 (header flags bit0 enables the read)
23
23
  * placeFlags u8 (V5; bit0 = encyclopedic present) nameIdx u32 index into string table referential f32
24
24
  * population-anchored likelihood [0,1] — was the conflated `importance` (V2–V4), was population u32
25
25
  * (V1) lat f32 lon f32 chain [u32; 8] parent chain (unused slots = 0) encyclopedic f32 (V5 only;
@@ -33,97 +33,34 @@
33
33
  * V4-and-below artifact as format-stale for exactly this reason: its single float is unattributable.
34
34
  */
35
35
 
36
- import { tryParsingJSON } from "@mailwoman/core/objects"
37
-
38
- import type { FSTNode } from "./fst-matcher.ts"
39
- import { FSTMatcher } from "./fst-matcher.ts"
40
- import type { FSTProvenance, PlaceEntry, PlacetypeID } from "./fst-types.ts"
41
-
42
- /**
43
- * Format version that widened the per-state edge and place counters from 16 to 32 bits, growing the state entry from 12
44
- * to 16 bytes. Readers branch on it to stay backward-compatible with v2/v3 files.
45
- */
46
- const VERSION_WIDE_STATE_COUNTERS = 4
47
-
48
- /**
49
- * State-table entry size in bytes at or above {@link VERSION_WIDE_STATE_COUNTERS}.
50
- */
51
- const WIDE_STATE_ENTRY_SIZE = 16
52
-
53
- /**
54
- * State-table entry size in bytes below {@link VERSION_WIDE_STATE_COUNTERS}.
55
- */
56
- const NARROW_STATE_ENTRY_SIZE = 12
57
-
58
- /**
59
- * First format version carrying the trailing metadata block; older files simply have none.
60
- */
61
- const VERSION_WITH_METADATA = 3
36
+ import { tryParsingJSON } from "@mailwoman/core/json"
37
+
38
+ import {
39
+ EDGE_ENTRY_SIZE,
40
+ ENCYCLOPEDIC_OFFSET,
41
+ FST_FORMAT_VERSION,
42
+ FST_MAGIC_BYTES,
43
+ HEADER_SIZE,
44
+ LEGACY_PLACE_ENTRY_SIZE,
45
+ NARROW_STATE_ENTRY_SIZE,
46
+ PLACE_FLAG_HAS_ENCYCLOPEDIC,
47
+ PLACETYPE_ORDER,
48
+ SPLIT_PLACE_ENTRY_SIZE,
49
+ VERSION_TWO_SCORE_SPLIT,
50
+ VERSION_WIDE_STATE_COUNTERS,
51
+ VERSION_WITH_METADATA,
52
+ WIDE_STATE_ENTRY_SIZE,
53
+ } from "#fst/format"
54
+ import type { FSTNode } from "#fst/matcher"
55
+ import { FSTMatcher } from "#fst/matcher"
56
+ import type { FSTProvenance, PlaceEntry } from "#fst/types"
57
+
58
+ export { FST_FORMAT_VERSION } from "#fst/format"
62
59
 
63
60
  /**
64
- * Format version that split the single `importance` float into `referential` + `encyclopedic`, growing the place entry
65
- * from 56 to 60 bytes and claiming the previously-reserved `pp+7` byte as {@link PLACE_FLAG_HAS_ENCYCLOPEDIC}.
61
+ * File magic as a Buffer, for the Node-side prefix comparison.
66
62
  */
67
- const VERSION_TWO_SCORE_SPLIT = 5
68
-
69
- /**
70
- * Place-entry size in bytes at or above {@link VERSION_TWO_SCORE_SPLIT}.
71
- */
72
- const SPLIT_PLACE_ENTRY_SIZE = 60
73
-
74
- /**
75
- * Place-entry size in bytes below {@link VERSION_TWO_SCORE_SPLIT}.
76
- */
77
- const LEGACY_PLACE_ENTRY_SIZE = 56
78
-
79
- /**
80
- * Byte offset of the encyclopedic float inside a v5 place entry — immediately after the 8-slot parent chain.
81
- */
82
- const ENCYCLOPEDIC_OFFSET = 56
83
-
84
- /**
85
- * `placeFlags` bit 0 (byte `pp+7`, v5+): this place carries an encyclopedic score. Per-PLACE rather than per-file
86
- * because absence is the common case — roughly 89% of the 2026-08-05 gazetteer has no Wikipedia article — and a
87
- * file-level flag would force every one of those rows to claim a 0 it never had.
88
- */
89
- const PLACE_FLAG_HAS_ENCYCLOPEDIC = 1
90
-
91
- /**
92
- * File magic. A reader rejects anything not starting with these four bytes before parsing further.
93
- */
94
- const MAGIC = Buffer.from("FST\0", "ascii")
95
-
96
- /**
97
- * Format version this serializer emits. See {@link VERSION_WIDE_STATE_COUNTERS} for what each bump changed.
98
- */
99
- const VERSION = 5
100
-
101
- /**
102
- * The format version this tree WRITES, published so a freshness guard can call an older artifact format-stale without
103
- * re-typing the number. Mirrors `REQUIRED_PAIR_INDEX_SCHEMA`'s role for PIX1: one constant, so a version bump cannot be
104
- * noticed by some checkers and not others. See `fst-freshness.ts`.
105
- */
106
- export const FST_FORMAT_VERSION = VERSION
107
-
108
- /**
109
- * Fixed header size in bytes: magic, version, and the section offsets that follow it.
110
- */
111
- const HEADER_SIZE = 32
112
-
113
- /**
114
- * State-table entry: edge offset, place offset, and the two 32-bit counters (v4 widths).
115
- */
116
- const STATE_ENTRY_SIZE = 16
117
-
118
- /**
119
- * Edge-table entry: the transition label and the target state index.
120
- */
121
- const EDGE_ENTRY_SIZE = 8
122
-
123
- /**
124
- * Place-table entry at the version this tree WRITES: the place id, its placetype, coordinates, and both scores.
125
- */
126
- const PLACE_ENTRY_SIZE = SPLIT_PLACE_ENTRY_SIZE
63
+ const MAGIC = Buffer.from(FST_MAGIC_BYTES)
127
64
 
128
65
  /**
129
66
  * Longest ancestry chain stored per place. Deeper hierarchies are truncated at the leaf end, since the specific end of
@@ -131,24 +68,6 @@ const PLACE_ENTRY_SIZE = SPLIT_PLACE_ENTRY_SIZE
131
68
  */
132
69
  const MAX_CHAIN_LEN = 8
133
70
 
134
- /**
135
- * Placetypes in hierarchy order, largest first. The index into this array is what gets written into a place entry, so
136
- * REORDERING IT BREAKS EVERY EXISTING FILE — append instead, and bump the version.
137
- */
138
- const PLACETYPE_ORDER: readonly PlacetypeID[] = [
139
- "country",
140
- "region",
141
- "county",
142
- "locality",
143
- "localadmin",
144
- "borough",
145
- "neighbourhood",
146
- "postalcode",
147
- "campus",
148
- "dependency",
149
- "street_affix",
150
- ]
151
-
152
71
  const placetypeToIdx = new Map<string, number>()
153
72
 
154
73
  for (let i = 0; i < PLACETYPE_ORDER.length; i++) {
@@ -198,9 +117,9 @@ export function serializeFST(matcher: FSTMatcher, provenance?: FSTProvenance): B
198
117
 
199
118
  // --- Allocate ---
200
119
  const stringTableSize = (strings.length + 1) * 4 + stringBytes
201
- const stateTableSize = nodes.length * STATE_ENTRY_SIZE
120
+ const stateTableSize = nodes.length * WIDE_STATE_ENTRY_SIZE
202
121
  const edgeTableSize = totalEdges * EDGE_ENTRY_SIZE
203
- const placeTableSize = totalPlaces * PLACE_ENTRY_SIZE
122
+ const placeTableSize = totalPlaces * SPLIT_PLACE_ENTRY_SIZE
204
123
  const provenanceJson = provenance ? Buffer.from(JSON.stringify(provenance), "utf8") : null
205
124
  const provenanceSize = provenanceJson ? 4 + provenanceJson.length : 0
206
125
  const binarySize = HEADER_SIZE + stringTableSize + stateTableSize + edgeTableSize + placeTableSize
@@ -215,7 +134,7 @@ export function serializeFST(matcher: FSTMatcher, provenance?: FSTProvenance): B
215
134
  const hasAmbiguity = nodes.some((n) => n.places.some((p) => p.crossCountryBranches !== undefined))
216
135
  MAGIC.copy(buf, pos)
217
136
  pos += 4
218
- buf.writeUInt16LE(VERSION, pos)
137
+ buf.writeUInt16LE(FST_FORMAT_VERSION, pos)
219
138
  pos += 2
220
139
  buf.writeUInt16LE(hasAmbiguity ? 1 : 0, pos)
221
140
  pos += 2
@@ -261,7 +180,7 @@ export function serializeFST(matcher: FSTMatcher, provenance?: FSTProvenance): B
261
180
 
262
181
  for (let si = 0; si < nodes.length; si++) {
263
182
  const node = nodes[si]!
264
- const sp = stateTableStart + si * STATE_ENTRY_SIZE
183
+ const sp = stateTableStart + si * WIDE_STATE_ENTRY_SIZE
265
184
 
266
185
  buf.writeUInt32LE(edgeIdx, sp)
267
186
  buf.writeUInt32LE(placeIdx, sp + 4)
@@ -277,14 +196,14 @@ export function serializeFST(matcher: FSTMatcher, provenance?: FSTProvenance): B
277
196
  }
278
197
 
279
198
  for (const place of node.places) {
280
- const pp = placeTableStart + placeIdx * PLACE_ENTRY_SIZE
199
+ const pp = placeTableStart + placeIdx * SPLIT_PLACE_ENTRY_SIZE
281
200
  // Filter out WOF sentinel parent IDs (negative values like -1, -4).
282
201
  const validChain = place.parentChain.filter((id) => id > 0)
283
202
  const chainLen = Math.min(validChain.length, MAX_CHAIN_LEN)
284
203
  buf.writeUInt32LE(place.wofID, pp)
285
204
  buf.writeUInt8(placetypeToIdx.get(place.placetype) ?? 0, pp + 4)
286
205
  buf.writeUInt8(chainLen, pp + 5)
287
- // Former _pad: byte 0 = crossCountryBranches (header flags bit0 gates the read), byte 1 = v5 placeFlags.
206
+ // Former _pad: byte 0 = crossCountryBranches (header flags bit0 enables the read), byte 1 = v5 placeFlags.
288
207
  buf.writeUInt8(hasAmbiguity ? Math.min(place.crossCountryBranches ?? 0, 255) : 0, pp + 6)
289
208
  // An absent encyclopedic score writes flag 0 AND a 0.0 float. The float is unread in that
290
209
  // state, so absence can never surface as a score — the meaning-of-zero rule, in bytes.
@@ -321,7 +240,10 @@ export function deserializeFST(buf: Buffer): FSTMatcher {
321
240
  if (!buf.subarray(0, 4).equals(MAGIC)) throw new Error("FST magic mismatch")
322
241
  const version = buf.readUInt16LE(4)
323
242
 
324
- if (version < 1 || version > VERSION) throw new Error(`FST version ${version} unsupported (expected 1..${VERSION})`)
243
+ if (version < 1 || version > FST_FORMAT_VERSION) {
244
+ throw new Error(`FST version ${version} unsupported (expected 1..${FST_FORMAT_VERSION})`)
245
+ }
246
+
325
247
  const isV2 = version >= 2
326
248
  const isSplit = version >= VERSION_TWO_SCORE_SPLIT
327
249
  // flags bit0 (survey #4): place rows carry surface-ambiguity data in the former _pad byte.
@@ -416,7 +338,7 @@ export function deserializeFST(buf: Buffer): FSTMatcher {
416
338
  lat: buf.readFloatLE(pp + 16),
417
339
  lon: buf.readFloatLE(pp + 20),
418
340
  parentChain,
419
- // Header flags bit0 gates the read (survey #4): pre-ambiguity artifacts expose undefined.
341
+ // Header flags bit0 enables the read (survey #4): pre-ambiguity artifacts expose undefined.
420
342
  ...(hasAmbiguity ? { crossCountryBranches: buf.readUInt8(pp + 6) } : {}),
421
343
  ...(hasEncyclopedic ? { encyclopedic: buf.readFloatLE(pp + ENCYCLOPEDIC_OFFSET) } : {}),
422
344
  }
@@ -8,6 +8,8 @@
8
8
  * prefix of every place name in the gazetteer.
9
9
  */
10
10
 
11
+ import type { PathBuilderLike } from "path-ts"
12
+
11
13
  export interface PlaceEntry {
12
14
  wofID: number
13
15
  placetype: PlacetypeID
@@ -129,7 +131,7 @@ export interface FSTProvenance {
129
131
  }
130
132
 
131
133
  export interface BuildFSTOpts {
132
- dbPath: string
134
+ dbPath: PathBuilderLike
133
135
  /**
134
136
  * Pre-computed identity of `dbPath` to stamp into provenance. Omit and the builder reads it via
135
137
  * `readWOFSourceIdentity` (sidecar-cached). Supply it when the digest is already in hand, or when the caller is
@@ -164,7 +166,7 @@ export interface BuildFSTOpts {
164
166
  * accessible under several surfaces records each surface's own count. Serialized into the place row's former `_pad`
165
167
  * byte with presence signaled by header flags bit0, so VERSION stays put and pre-ambiguity artifacts read as "no
166
168
  * data" (never "0 branches" — the meaning-of-zero rule). No decoder consumes it yet; consumers (FST-prior tempering,
167
- * the Option-A evidence channel) arrive behind their own measured gates.
169
+ * the Option-A evidence channel) arrive behind their own measured checks.
168
170
  */
169
171
  surfaceCountryCounts?: ReadonlyMap<string, number>
170
172
  onProgress?: (phase: string, detail?: string) => void
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * FTS5 index lifecycle for the WOF SQLite distribution.
7
7
  *
8
- * Shared by `WOFSqlitePlaceLookup` (lazy build via `buildFTS: true`) and the operator-side
8
+ * Shared by `WOFSQLitePlaceLookup` (lazy build via `buildFTS: true`) and the operator-side
9
9
  * `mailwoman gazetteer build fts` CLI (ahead-of-time build to avoid first-open latency in production).
10
10
  *
11
11
  * Upstream WOF SQLite distributions do NOT ship FTS5. The index lives in a `place_search` virtual
@@ -14,10 +14,11 @@
14
14
  * bag.
15
15
  */
16
16
 
17
- import type { DatabaseSync } from "node:sqlite"
17
+ import type { DatabaseClient } from "@mailwoman/sqlite/client"
18
+ import { tableExists } from "@mailwoman/sqlite/introspection"
18
19
 
19
20
  /**
20
- * Name of the FTS5 virtual table this module owns. Centralized so `WOFSqlitePlaceLookup` and the CLI can't drift apart.
21
+ * Name of the FTS5 virtual table this module owns. Centralized so `WOFSQLitePlaceLookup` and the CLI can't drift apart.
21
22
  */
22
23
  export const PLACE_SEARCH_TABLE = "place_search"
23
24
 
@@ -71,19 +72,29 @@ export const ALIAS_SEPARATOR = "\uE000"
71
72
  */
72
73
  const ALIAS_SEPARATOR_CODEPOINT = ALIAS_SEPARATOR.codePointAt(0) as number
73
74
 
75
+ /**
76
+ * The query/name fold every exact-tier comparison uses: lowercase, trim, collapse internal whitespace. The `alt_names`
77
+ * bag is compared alias-by-alias against a query folded THIS way, so the fold lives beside the bag parser — every
78
+ * consumer (the Node resolver's exact tier, the WASM resolver, the name-exact sub-tier sort) folds through this one
79
+ * function.
80
+ */
81
+ export function foldQueryText(input: string): string {
82
+ return input.toLowerCase().trim().replaceAll(/\s+/g, " ")
83
+ }
84
+
74
85
  /**
75
86
  * Does any alias in an `alt_names` bag exactly equal the (already-normalized) query? The single shared implementation
76
- * of the exact-tier alias check for every consumer of the bag — the Node resolver's `#exactMatchIds` fallback, the WASM
87
+ * of the exact-tier alias check for every consumer of the bag — the Node resolver's `#exactMatchIDs` fallback, the WASM
77
88
  * resolver, and the demo's httpvfs resolver — so the bag format and its parsers can't drift.
78
89
  *
79
90
  * Two formats exist in the wild:
80
91
  *
81
92
  * - **Separated bags** (built since #523): aliases joined with {@link ALIAS_SEPARATOR}, plus a trailing separator so even
82
93
  * a single-alias bag self-identifies as separator-formatted. Split + per-alias equality — a true exact-alias check,
83
- * matching the semantics of the full `names` table (`names.name = ? COLLATE NOCASE`), so it runs UNGATED: an alias
84
- * match is an exact match whether or not another candidate matched on its canonical name.
94
+ * matching the semantics of the full `names` table (`names.name = ? COLLATE NOCASE`), so it runs unrestricted: an
95
+ * alias match is an exact match whether or not another candidate matched on its canonical name.
85
96
  * - **Legacy bags** (pre-#523 artifacts, e.g. an already-deployed slim DB): aliases space-joined, boundaries lost. Falls
86
- * back to the historical padded-containment check, gated on `anyStrictExact` — ungated containment would
97
+ * back to the historical padded-containment check, conditioned on `anyStrictExact` — unrestricted containment would
87
98
  * false-promote interior fragments ("York" inside the alias "New York City") and cross-boundary fragments ("York New"
88
99
  * across "…York" + "New…"). Delete this branch once every shipped artifact carries the separator.
89
100
  *
@@ -95,15 +106,14 @@ const ALIAS_SEPARATOR_CODEPOINT = ALIAS_SEPARATOR.codePointAt(0) as number
95
106
  */
96
107
  export function aliasBagExactMatch(altNames: string | null, normalizedQuery: string, anyStrictExact: boolean): boolean {
97
108
  if (altNames === null || altNames === "" || !normalizedQuery) return false
98
- const norm = (s: string): string => s.toLowerCase().trim().replaceAll(/\s+/g, " ")
99
109
 
100
110
  if (altNames.includes(ALIAS_SEPARATOR)) {
101
- return altNames.split(ALIAS_SEPARATOR).some((alias) => norm(alias) === normalizedQuery)
111
+ return altNames.split(ALIAS_SEPARATOR).some((alias) => foldQueryText(alias) === normalizedQuery)
102
112
  }
103
113
 
104
114
  if (anyStrictExact) return false
105
115
 
106
- return ` ${norm(altNames)} `.includes(` ${normalizedQuery} `)
116
+ return ` ${foldQueryText(altNames)} `.includes(` ${normalizedQuery} `)
107
117
  }
108
118
 
109
119
  /**
@@ -189,7 +199,10 @@ export interface BuildPlaceSearchFTSOpts {
189
199
  * Returns a `BuildPlaceSearchFTSResult` summary. Idempotent when `drop: false` — re-running against an already-indexed
190
200
  * DB skips whichever indexes already exist.
191
201
  */
192
- export function buildPlaceSearchFTS(db: DatabaseSync, opts: BuildPlaceSearchFTSOpts = {}): BuildPlaceSearchFTSResult {
202
+ export function buildPlaceSearchFTS<DB>(
203
+ db: DatabaseClient<DB>,
204
+ opts: BuildPlaceSearchFTSOpts = {}
205
+ ): BuildPlaceSearchFTSResult {
193
206
  const start = Date.now()
194
207
  const onProgress = opts.onProgress ?? (() => {})
195
208
 
@@ -326,31 +339,23 @@ export function buildPlaceSearchFTS(db: DatabaseSync, opts: BuildPlaceSearchFTSO
326
339
  }
327
340
 
328
341
  /**
329
- * Returns true iff the `place_search` table exists in the connected DB. Used by `WOFSqlitePlaceLookup` for its "FTS
342
+ * Returns true iff the `place_search` table exists in the connected DB. Used by `WOFSQLitePlaceLookup` for its "FTS
330
343
  * missing — pass buildFTS:true or run the CLI" guard.
331
344
  */
332
- export function placeSearchFTSExists(db: DatabaseSync): boolean {
345
+ export function placeSearchFTSExists<DB>(db: DatabaseClient<DB>): boolean {
333
346
  return tableExists(db, PLACE_SEARCH_TABLE)
334
347
  }
335
348
 
336
349
  /**
337
350
  * Returns true iff the `place_bbox` R*Tree table exists. Used for opt-in proximity lookup checks.
338
351
  */
339
- export function placeBboxExists(db: DatabaseSync): boolean {
352
+ export function placeBboxExists<DB>(db: DatabaseClient<DB>): boolean {
340
353
  return tableExists(db, PLACE_BBOX_TABLE)
341
354
  }
342
355
 
343
356
  /**
344
357
  * Returns true iff the `place_population` table exists. Used for opt-in population-ranking checks.
345
358
  */
346
- export function placePopulationExists(db: DatabaseSync): boolean {
359
+ export function placePopulationExists<DB>(db: DatabaseClient<DB>): boolean {
347
360
  return tableExists(db, PLACE_POPULATION_TABLE)
348
361
  }
349
-
350
- function tableExists(db: DatabaseSync, name: string): boolean {
351
- const row = db.prepare(`SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?`).get(name) as
352
- | { name: string }
353
- | undefined
354
-
355
- return Boolean(row)
356
- }
@@ -8,7 +8,7 @@
8
8
  * an unescaped quote or a bare `*` is a syntax error, not an empty result.
9
9
  */
10
10
 
11
- import type { FindPlaceQuery, WOFPlacetype } from "./types.ts"
11
+ import type { FindPlaceQuery, WOFPlacetype } from "#types"
12
12
 
13
13
  export function normalizePlacetypes(p: FindPlaceQuery["placetype"]): WOFPlacetype[] | null {
14
14
  if (!p) return null
@@ -67,7 +67,7 @@ export function sanitizeFTSQuery(text: string, opts?: { fuseTokens?: boolean }):
67
67
  // fusing "Thiron-Gardais" into the unmatchable single term `ThironGardais` while the FTS
68
68
  // doc holds two terms (#945 — the entire hyphenated-name class missed at the raw lookup;
69
69
  // masked for years because pre-splice tokenizers never emitted hyphen-preserved values).
70
- const parts = trimmed.split(/[^\p{L}\p{N}]+/u).filter(Boolean)
70
+ const parts = trimmed.split(/[^\p{L}\p{N}]+/u).filter((part) => part.length > 0)
71
71
 
72
72
  if (!parts.length) continue
73
73
 
@@ -24,14 +24,14 @@
24
24
  * (TSV).
25
25
  */
26
26
 
27
- import { existsSync } from "node:fs"
28
- import type { DatabaseSync } from "node:sqlite"
29
-
30
27
  import { isOfficialLanguage } from "@mailwoman/codex/country"
31
- import { join } from "path-ts"
28
+ import { pathExists } from "@mailwoman/core/fs/readers"
29
+ import type { DatabaseClient } from "@mailwoman/sqlite/client"
30
+ import { join, type PathBuilderLike } from "path-ts"
32
31
  import { TSVSpliterator } from "spliterator"
33
32
 
34
- import { GEONAMES_POSTAL_ID_BASE } from "./geonames-postal.ts"
33
+ import { GEONAMES_POSTAL_ID_BASE } from "#geonames/postal"
34
+ import type { WOFDatabase } from "#schema"
35
35
 
36
36
  /**
37
37
  * Synthetic id base for GeoNames-sourced rows (#743/#193) — above Overture's 8e12 so the three sources (WOF real ids,
@@ -62,11 +62,11 @@ const FOLD_OWNED_TABLES = ["spr", "names", "place_population", "ancestors"] as c
62
62
  * country. Gaborone/BW at id 9000000121151 became Aichegg/AT and kept all 26 of its names; Kinshasa's 16,000,000
63
63
  * population landed on a Lithuanian hamlet.
64
64
  *
65
- * The upper bound is NOT the end of the id space. Each later shard owns a range above this one — GeoNames-postal @
65
+ * The upper bound is NOT the end of the id space. Each later extract owns a range above this one — GeoNames-postal @
66
66
  * 9.5e12, NL-PC6 @ 9.6e12, Code-Point @ 9.7e12, NI @ 9.8e12 — and a purge that ran past {@link GEONAMES_POSTAL_ID_BASE}
67
67
  * would delete them.
68
68
  */
69
- export function purgeGeonamesAliasRange(db: DatabaseSync): Record<string, number> {
69
+ export function purgeGeonamesAliasRange<DB>(db: DatabaseClient<DB>): Record<string, number> {
70
70
  const removed: Record<string, number> = {}
71
71
 
72
72
  for (const table of FOLD_OWNED_TABLES) {
@@ -125,7 +125,7 @@ async function parseAlternateNamesV2(
125
125
  // spelling across rows — Malabo carries "Santa Isabel" as (es, unflagged) AND as (no-language,
126
126
  // isHistoric=1, to=1973). Officialness must see the flags from EVERY row for the spelling, or the
127
127
  // colonial-era name sails through on the language-tagged row (the #936 review's Malabo finding).
128
- // Do NOT gate on isPreferredName instead — it's sparse annotation, not a signal (Turku's sv "Åbo"
128
+ // Do NOT condition on isPreferredName instead — it's sparse annotation, not a signal (Turku's sv "Åbo"
129
129
  // is unflagged; FI has 1,746 flags across the whole dump).
130
130
  //
131
131
  // Both passes STREAM the file rather than sharing one materialized array: NO's V2 dump is 33 MB,
@@ -190,9 +190,9 @@ async function parseAlternateNamesV2(
190
190
  * the candidate build's alias pass.
191
191
  */
192
192
  export async function ingestGeonamesAliases(
193
- db: DatabaseSync,
193
+ db: DatabaseClient<WOFDatabase>,
194
194
  countries: string[],
195
- geonamesDir: string,
195
+ geonamesDir: PathBuilderLike,
196
196
  onProgress?: (event: GeonamesIngestProgress) => void,
197
197
  opts?: {
198
198
  /**
@@ -211,7 +211,7 @@ export async function ingestGeonamesAliases(
211
211
  * at 7 new name-exact collisions globally). The main dump's bare `alternatenames` list still decides WHICH rows
212
212
  * exist; V2 only decorates them. Missing file = the pre-#936 untagged behavior, not an error.
213
213
  */
214
- alternateDir?: string
214
+ alternateDir?: PathBuilderLike
215
215
  }
216
216
  ): Promise<number> {
217
217
  // Latin-only, no bracket/paren noise GeoNames packs into `alternatenames` ("(( Karis Landskommun ))",
@@ -265,7 +265,7 @@ export async function ingestGeonamesAliases(
265
265
  for (const cc of countries) {
266
266
  const file = join(geonamesDir, `${cc}.txt`)
267
267
 
268
- if (!existsSync(file)) {
268
+ if (!(await pathExists(file))) {
269
269
  report({ country: cc, places: 0, skipped: true }, file)
270
270
 
271
271
  continue
@@ -275,7 +275,7 @@ export async function ingestGeonamesAliases(
275
275
  // #267: add A-class admin + ancestry only for the gap countries this country is in (never the EU set).
276
276
  const addAdmin = opts?.adminForCountries?.has(cc) ?? false
277
277
  const v2File = opts?.alternateDir ? join(opts.alternateDir, `${cc}.txt`) : undefined
278
- const readV2 = Boolean(v2File && existsSync(v2File))
278
+ const readV2 = Boolean(v2File && (await pathExists(v2File)))
279
279
 
280
280
  // Survey pass. The dump is STREAMED — NO's is 71 MB and only the caller knows which country
281
281
  // comes next — so what a later pass needs has to be collected here rather than re-scanned off a
@@ -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 "#geonames/aliases"
8
+ export * from "#geonames/postal"
@@ -3,15 +3,15 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * #920 — fold GeoNames POSTAL codes into a WOF/unified postcode shard as first-class
6
+ * #920 — fold GeoNames POSTAL codes into a WOF/unified postcode extract as first-class
7
7
  * `postalcode` places, for the countries whose WOF postalcode repos don't exist (the
8
8
  * namesake-tail locales: FI/CZ/SK/SI/DK/NO/HR/PL and any future gap).
9
9
  *
10
10
  * Why: the night-31 taxonomy measured the cross-locale resolve tail as NAMESAKE COLLISION
11
- * (FI 300/1k … PL 75/1k offender rows), and the controlled experiment showed postcode-shard
11
+ * (FI 300/1k … PL 75/1k offender rows), and the controlled experiment showed postcode-extract
12
12
  * coverage alone collapses it (FI 300→1, CZ 131→4): a resolvable postcode node feeds the
13
13
  * resolver's coordinate-first sibling-postcode candidate injection, which binds the locality
14
- * pick to its postcode neighborhood. The machinery already ships; it was coverage-starved.
14
+ * pick to its postcode neighborhood. The implementation already ships; it was coverage-starved.
15
15
  *
16
16
  * Two hard-won laws from the experiment are enforced HERE, in code, not in a runbook:
17
17
  *
@@ -30,16 +30,17 @@
30
30
  * --geonames-postal-countries`, any standalone fold, and the `mailwoman gazetteer` commands
31
31
  * share ONE implementation. GeoNames postal dump = `download.geonames.org/export/zip/<CC>.zip`
32
32
  * → `<CC>.txt` (TSV: country, postcode, place, admin1, code1, admin2, code2, admin3, code3,
33
- * lat, lon, accuracy). License CC BY 4.0 — attribution rides the shard's `meta` provenance and
33
+ * lat, lon, accuracy). License CC BY 4.0 — attribution rides the extract's `meta` provenance and
34
34
  * the model card like the existing GeoNames alias fold.
35
35
  */
36
36
 
37
- import { existsSync } from "node:fs"
38
- import type { DatabaseSync } from "node:sqlite"
39
-
40
- import { join } from "path-ts"
37
+ import { pathExists } from "@mailwoman/core/fs/readers"
38
+ import type { DatabaseClient } from "@mailwoman/sqlite/client"
39
+ import { join, type PathBuilderLike } from "path-ts"
41
40
  import { TSVSpliterator } from "spliterator"
42
41
 
42
+ import type { WOFDatabase } from "#schema"
43
+
43
44
  /**
44
45
  * Column count of a GeoNames postal-code TSV row. Short rows are truncated or blank and are skipped. See the
45
46
  * allCountries.zip readme for the field list.
@@ -54,7 +55,7 @@ const GEONAMES_POSTAL_COLUMNS = 11
54
55
  export const GEONAMES_POSTAL_ID_BASE = 9_500_000_000_000
55
56
 
56
57
  /**
57
- * The #920 name law: reduce a postal code to the sanitized-query token shape — strip every non-letter/number — so the
58
+ * The #920 name law: reduce a postcode to the sanitized-query token shape — strip every non-letter/number — so the
58
59
  * stored name matches what `sanitizeFTSQuery` produces from the parsed postcode token. `"110 00"` → `"11000"`,
59
60
  * `"11-041"` → `"11041"`, `"AD500"` → `"AD500"`.
60
61
  */
@@ -77,7 +78,7 @@ export type PostcodePoint = readonly [number, number]
77
78
  *
78
79
  * Distance is squared-Euclidean in DEGREES, not haversine. At the scale a postcode spans, the ranking the two produce
79
80
  * is the same, and this one carries no trig into a per-group inner loop. Ties go to the earliest member, which makes
80
- * the result a pure function of the input order — the property a rebuilt shard's ids depend on.
81
+ * the result a pure function of the input order — the property a rebuilt extract's ids depend on.
81
82
  *
82
83
  * Exported (rather than inlined at each ingest) because it is the second half of the #920 pair: every postcode source
83
84
  * that groups member points — GeoNames postal, OSM `addr:postcode` — owes the same law, and a second hand-rolled copy
@@ -132,15 +133,15 @@ export interface GeonamesPostalIngestResult {
132
133
  }
133
134
 
134
135
  /**
135
- * Fold GeoNames postal codes for `countries` into an open unified/postcode ingest DB: one `spr` row per distinct
136
+ * Fold GeoNames postcodes for `countries` into an open unified/postcode ingest DB: one `spr` row per distinct
136
137
  * normalized postcode (placetype `postalcode`, medoid centroid, degenerate bbox), the normalized form as `name`, and
137
138
  * the display form as an extra `names` row when it differs. The caller owns the FTS rebuild (rows ride the standard
138
139
  * freeze phase).
139
140
  */
140
141
  export async function ingestGeonamesPostal(
141
- db: DatabaseSync,
142
+ db: DatabaseClient<WOFDatabase>,
142
143
  countries: readonly string[],
143
- postalDir: string
144
+ postalDir: PathBuilderLike
144
145
  ): Promise<GeonamesPostalIngestResult> {
145
146
  const sprInsert = db.prepare(
146
147
  `INSERT OR REPLACE INTO spr (id, parent_id, name, placetype, country, latitude, longitude, min_latitude, min_longitude, max_latitude, max_longitude, is_current, is_deprecated, is_ceased, is_superseded, is_superseding, lastmodified) VALUES (?, -1, ?, 'postalcode', ?, ?, ?, ?, ?, ?, ?, 1, 0, 0, 0, 0, 0)`
@@ -159,7 +160,7 @@ export async function ingestGeonamesPostal(
159
160
  const cc = country.toUpperCase()
160
161
  const file = join(postalDir, `${cc}.txt`)
161
162
 
162
- if (!existsSync(file)) {
163
+ if (!(await pathExists(file))) {
163
164
  missing.push(cc)
164
165
 
165
166
  console.error(
@@ -173,7 +174,7 @@ export async function ingestGeonamesPostal(
173
174
  const members = new Map<string, { display: string; pts: Array<[number, number]> }>()
174
175
 
175
176
  // Streamed: a national dump is a caller-supplied size — GB's is 177 MB, and only the caller
176
- // knows which country is next. `header: false` is load-bearing; the GeoNames postal dump is
177
+ // knows which country is next. `header: false` is required; the GeoNames postal dump is
177
178
  // headerless, so row 1 would be consumed as column names and its postcode lost.
178
179
  for await (const cols of TSVSpliterator.fromAsync(file, { header: false })) {
179
180
  if (cols.length < GEONAMES_POSTAL_COLUMNS) continue