@mailwoman/resolver-wof-sqlite 9.2.0 → 9.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (488) hide show
  1. package/README.md +16 -19
  2. package/lib/address/index.ts +9 -0
  3. package/{address-point-interpolation.ts → lib/address/point-interpolation.ts} +24 -22
  4. package/{address-point-schema.ts → lib/address/point-schema.ts} +18 -4
  5. package/{address-point.ts → lib/address/point.ts} +89 -27
  6. package/{ancestry-backfill.ts → lib/ancestry/backfill.ts} +14 -19
  7. package/{ancestry.ts → lib/ancestry/index.ts} +5 -3
  8. package/{build-candidate.ts → lib/build-candidate.ts} +84 -77
  9. package/{build-slim.ts → lib/build-slim.ts} +150 -165
  10. package/{candidate → lib/candidate}/alias-bags.ts +8 -6
  11. package/{candidate → lib/candidate}/ancestors-sidecar.ts +13 -15
  12. package/{candidate → lib/candidate}/country-display-names.ts +2 -2
  13. package/{candidate/shard-fold.ts → lib/candidate/extract-fold.ts} +26 -25
  14. package/{candidate → lib/candidate}/name-roles.ts +17 -16
  15. package/{candidate → lib/candidate}/own-name.ts +1 -1
  16. package/{candidate → lib/candidate}/place-attrs.ts +3 -3
  17. package/{candidate-ancestors-schema.ts → lib/candidate-ancestors-schema.ts} +4 -4
  18. package/{candidate-fts.ts → lib/candidate-fts.ts} +3 -3
  19. package/{candidate-importance.ts → lib/candidate-importance.ts} +53 -57
  20. package/{candidate-lookup.ts → lib/candidate-lookup.ts} +76 -73
  21. package/{candidate-schema.ts → lib/candidate-schema.ts} +5 -5
  22. package/{candidate-scoring.ts → lib/candidate-scoring.ts} +15 -22
  23. package/{capital-schema.ts → lib/capital-schema.ts} +5 -6
  24. package/{capitals.ts → lib/capitals.ts} +2 -2
  25. package/{coincident-roles.ts → lib/coincident-roles.ts} +8 -11
  26. package/{convention.ts → lib/convention/index.ts} +3 -3
  27. package/{convention-schema.ts → lib/convention/schema.ts} +2 -2
  28. package/{coverage-manifest-schema.ts → lib/coverage-manifest-schema.ts} +9 -10
  29. package/{currency-backfill.ts → lib/currency-backfill.ts} +126 -41
  30. package/lib/env.ts +50 -0
  31. package/{exact-match.ts → lib/exact-match.ts} +23 -14
  32. package/{sharding.ts → lib/extracts.ts} +61 -58
  33. package/{fst-autocomplete.ts → lib/fst/autocomplete.ts} +4 -4
  34. package/{fst-builder.ts → lib/fst/builder.ts} +17 -16
  35. package/{fst-deserialize-web.ts → lib/fst/deserialize-web.ts} +27 -87
  36. package/lib/fst/format.ts +106 -0
  37. package/{fst-freshness.ts → lib/fst/freshness.ts} +41 -74
  38. package/lib/fst/index.ts +14 -0
  39. package/{fst-matcher.ts → lib/fst/matcher.ts} +1 -1
  40. package/{fst-serialize.ts → lib/fst/serialize.ts} +37 -115
  41. package/{fst-types.ts → lib/fst/types.ts} +4 -2
  42. package/{fts.ts → lib/fts/index.ts} +24 -19
  43. package/{fts-query.ts → lib/fts/query.ts} +1 -1
  44. package/{geonames-aliases.ts → lib/geonames/aliases.ts} +13 -13
  45. package/lib/geonames/index.ts +8 -0
  46. package/{geonames-postal.ts → lib/geonames/postal.ts} +14 -13
  47. package/{index.ts → lib/index.ts} +37 -37
  48. package/{interpolation.ts → lib/interpolation.ts} +27 -25
  49. package/{lookup.ts → lib/lookup.ts} +129 -141
  50. package/lib/nsul/index.ts +8 -0
  51. package/lib/nsul/lookup.ts +144 -0
  52. package/lib/nsul/schema.ts +130 -0
  53. package/{place-importance-schema.ts → lib/place-importance-schema.ts} +7 -8
  54. package/lib/poi/index.ts +8 -0
  55. package/{poi-lookup.ts → lib/poi/lookup.ts} +22 -28
  56. package/{poi-schema.ts → lib/poi/schema.ts} +3 -4
  57. package/{postal-city-alias-lookup.ts → lib/postal/city-alias-lookup.ts} +14 -20
  58. package/{postal-city-candidate-schema.ts → lib/postal/city-candidate-schema.ts} +2 -2
  59. package/lib/postal/index.ts +9 -0
  60. package/{postcode-point-lookup.ts → lib/postcode-point-lookup.ts} +17 -15
  61. package/{primary-preference.ts → lib/primary-preference.ts} +29 -10
  62. package/{proximity-rerank.ts → lib/proximity-rerank.ts} +2 -2
  63. package/{ranking-weights.ts → lib/ranking-weights.ts} +30 -4
  64. package/{region-keys.ts → lib/region-keys.ts} +9 -9
  65. package/{reverse.ts → lib/reverse.ts} +34 -46
  66. package/{schema.ts → lib/schema.ts} +10 -0
  67. package/{search-fetch.ts → lib/search-fetch.ts} +29 -28
  68. package/{sqlite-convention-source.ts → lib/sqlite-convention-source.ts} +9 -10
  69. package/{sqlite-utils.ts → lib/sqlite-utils.ts} +14 -18
  70. package/{street-centroid-schema.ts → lib/street/centroid-schema.ts} +5 -5
  71. package/{street-centroid.ts → lib/street/centroid.ts} +14 -21
  72. package/lib/street/index.ts +13 -0
  73. package/{street-morphology-fst-builder.ts → lib/street/morphology-fst-builder.ts} +24 -14
  74. package/{street-morphology-fst-loader.ts → lib/street/morphology-fst-loader.ts} +14 -12
  75. package/{street-name-lookup.ts → lib/street/name-lookup.ts} +14 -30
  76. package/{street-normalize.ts → lib/street/normalize.ts} +44 -19
  77. package/{street-segment-schema.ts → lib/street/segment-schema.ts} +7 -7
  78. package/{types.ts → lib/types.ts} +18 -12
  79. package/{unified-schema.ts → lib/unified-schema.ts} +20 -24
  80. package/lib/uprn/existence.ts +84 -0
  81. package/lib/uprn/index.ts +9 -0
  82. package/{uprn-lookup.ts → lib/uprn/lookup.ts} +14 -18
  83. package/{uprn-schema.ts → lib/uprn/schema.ts} +3 -3
  84. package/lib/weights-overlay-linker.ts +878 -0
  85. package/out/address/index.d.ts +9 -0
  86. package/out/address/index.d.ts.map +1 -0
  87. package/out/address/index.js +9 -0
  88. package/out/address/index.js.map +1 -0
  89. package/out/{address-point-interpolation.d.ts → address/point-interpolation.d.ts} +11 -10
  90. package/out/address/point-interpolation.d.ts.map +1 -0
  91. package/out/{address-point-interpolation.js → address/point-interpolation.js} +18 -18
  92. package/out/address/point-interpolation.js.map +1 -0
  93. package/out/{address-point-schema.d.ts → address/point-schema.d.ts} +16 -6
  94. package/out/address/point-schema.d.ts.map +1 -0
  95. package/out/{address-point-schema.js → address/point-schema.js} +7 -3
  96. package/out/address/point-schema.js.map +1 -0
  97. package/out/{address-point.d.ts → address/point.d.ts} +16 -8
  98. package/out/address/point.d.ts.map +1 -0
  99. package/out/{address-point.js → address/point.js} +71 -20
  100. package/out/address/point.js.map +1 -0
  101. package/out/{ancestry-backfill.d.ts → ancestry/backfill.d.ts} +7 -5
  102. package/out/ancestry/backfill.d.ts.map +1 -0
  103. package/out/{ancestry-backfill.js → ancestry/backfill.js} +12 -16
  104. package/out/ancestry/backfill.js.map +1 -0
  105. package/out/{ancestry.d.ts → ancestry/index.d.ts} +4 -3
  106. package/out/ancestry/index.d.ts.map +1 -0
  107. package/out/{ancestry.js → ancestry/index.js} +3 -2
  108. package/out/ancestry/index.js.map +1 -0
  109. package/out/build-candidate.d.ts +30 -24
  110. package/out/build-candidate.d.ts.map +1 -1
  111. package/out/build-candidate.js +50 -52
  112. package/out/build-candidate.js.map +1 -1
  113. package/out/build-slim.d.ts +4 -4
  114. package/out/build-slim.d.ts.map +1 -1
  115. package/out/build-slim.js +124 -139
  116. package/out/build-slim.js.map +1 -1
  117. package/out/candidate/alias-bags.d.ts +5 -3
  118. package/out/candidate/alias-bags.d.ts.map +1 -1
  119. package/out/candidate/alias-bags.js +2 -2
  120. package/out/candidate/alias-bags.js.map +1 -1
  121. package/out/candidate/ancestors-sidecar.d.ts +9 -10
  122. package/out/candidate/ancestors-sidecar.d.ts.map +1 -1
  123. package/out/candidate/ancestors-sidecar.js +7 -7
  124. package/out/candidate/ancestors-sidecar.js.map +1 -1
  125. package/out/candidate/country-display-names.d.ts +1 -1
  126. package/out/candidate/country-display-names.d.ts.map +1 -1
  127. package/out/candidate/country-display-names.js +1 -1
  128. package/out/candidate/country-display-names.js.map +1 -1
  129. package/out/candidate/extract-fold.d.ts +32 -0
  130. package/out/candidate/extract-fold.d.ts.map +1 -0
  131. package/out/candidate/{shard-fold.js → extract-fold.js} +20 -20
  132. package/out/candidate/extract-fold.js.map +1 -0
  133. package/out/candidate/name-roles.d.ts +13 -11
  134. package/out/candidate/name-roles.d.ts.map +1 -1
  135. package/out/candidate/name-roles.js +11 -10
  136. package/out/candidate/name-roles.js.map +1 -1
  137. package/out/candidate/own-name.d.ts +1 -1
  138. package/out/candidate/own-name.d.ts.map +1 -1
  139. package/out/candidate/own-name.js +1 -1
  140. package/out/candidate/own-name.js.map +1 -1
  141. package/out/candidate/place-attrs.d.ts +3 -3
  142. package/out/candidate/place-attrs.d.ts.map +1 -1
  143. package/out/candidate/place-attrs.js +1 -1
  144. package/out/candidate/place-attrs.js.map +1 -1
  145. package/out/candidate-ancestors-schema.d.ts +4 -4
  146. package/out/candidate-ancestors-schema.d.ts.map +1 -1
  147. package/out/candidate-ancestors-schema.js +2 -2
  148. package/out/candidate-ancestors-schema.js.map +1 -1
  149. package/out/candidate-fts.d.ts +3 -3
  150. package/out/candidate-fts.d.ts.map +1 -1
  151. package/out/candidate-fts.js +1 -1
  152. package/out/candidate-fts.js.map +1 -1
  153. package/out/candidate-importance.d.ts +16 -16
  154. package/out/candidate-importance.d.ts.map +1 -1
  155. package/out/candidate-importance.js +46 -51
  156. package/out/candidate-importance.js.map +1 -1
  157. package/out/candidate-lookup.d.ts +11 -9
  158. package/out/candidate-lookup.d.ts.map +1 -1
  159. package/out/candidate-lookup.js +61 -58
  160. package/out/candidate-lookup.js.map +1 -1
  161. package/out/candidate-schema.d.ts +5 -5
  162. package/out/candidate-schema.d.ts.map +1 -1
  163. package/out/candidate-schema.js.map +1 -1
  164. package/out/candidate-scoring.d.ts +7 -7
  165. package/out/candidate-scoring.d.ts.map +1 -1
  166. package/out/candidate-scoring.js +10 -14
  167. package/out/candidate-scoring.js.map +1 -1
  168. package/out/capital-schema.d.ts +3 -3
  169. package/out/capital-schema.d.ts.map +1 -1
  170. package/out/capital-schema.js +2 -2
  171. package/out/capital-schema.js.map +1 -1
  172. package/out/capitals.d.ts +1 -1
  173. package/out/capitals.d.ts.map +1 -1
  174. package/out/capitals.js +2 -2
  175. package/out/capitals.js.map +1 -1
  176. package/out/coincident-roles.d.ts +6 -5
  177. package/out/coincident-roles.d.ts.map +1 -1
  178. package/out/coincident-roles.js +2 -4
  179. package/out/coincident-roles.js.map +1 -1
  180. package/out/{convention.d.ts → convention/index.d.ts} +4 -4
  181. package/out/convention/index.d.ts.map +1 -0
  182. package/out/{convention.js → convention/index.js} +2 -2
  183. package/out/convention/index.js.map +1 -0
  184. package/out/{convention-schema.d.ts → convention/schema.d.ts} +2 -2
  185. package/out/convention/schema.d.ts.map +1 -0
  186. package/out/{convention-schema.js → convention/schema.js} +3 -3
  187. package/out/convention/schema.js.map +1 -0
  188. package/out/coverage-manifest-schema.d.ts +8 -8
  189. package/out/coverage-manifest-schema.d.ts.map +1 -1
  190. package/out/coverage-manifest-schema.js +4 -4
  191. package/out/coverage-manifest-schema.js.map +1 -1
  192. package/out/currency-backfill.d.ts +51 -7
  193. package/out/currency-backfill.d.ts.map +1 -1
  194. package/out/currency-backfill.js +65 -49
  195. package/out/currency-backfill.js.map +1 -1
  196. package/out/env.d.ts +43 -0
  197. package/out/env.d.ts.map +1 -0
  198. package/out/env.js +48 -0
  199. package/out/env.js.map +1 -0
  200. package/out/exact-match.d.ts +5 -5
  201. package/out/exact-match.d.ts.map +1 -1
  202. package/out/exact-match.js +10 -11
  203. package/out/exact-match.js.map +1 -1
  204. package/out/extracts.d.ts +114 -0
  205. package/out/extracts.d.ts.map +1 -0
  206. package/out/{sharding.js → extracts.js} +38 -38
  207. package/out/extracts.js.map +1 -0
  208. package/out/{fst-autocomplete.d.ts → fst/autocomplete.d.ts} +2 -2
  209. package/out/fst/autocomplete.d.ts.map +1 -0
  210. package/out/{fst-autocomplete.js → fst/autocomplete.js} +3 -3
  211. package/out/fst/autocomplete.js.map +1 -0
  212. package/out/{fst-builder.d.ts → fst/builder.d.ts} +5 -5
  213. package/out/fst/builder.d.ts.map +1 -0
  214. package/out/{fst-builder.js → fst/builder.js} +14 -13
  215. package/out/fst/builder.js.map +1 -0
  216. package/out/{fst-deserialize-web.d.ts → fst/deserialize-web.d.ts} +3 -3
  217. package/out/fst/deserialize-web.d.ts.map +1 -0
  218. package/out/{fst-deserialize-web.js → fst/deserialize-web.js} +10 -74
  219. package/out/fst/deserialize-web.js.map +1 -0
  220. package/out/fst/format.d.ts +80 -0
  221. package/out/fst/format.d.ts.map +1 -0
  222. package/out/fst/format.js +91 -0
  223. package/out/fst/format.js.map +1 -0
  224. package/out/{fst-freshness.d.ts → fst/freshness.d.ts} +10 -13
  225. package/out/fst/freshness.d.ts.map +1 -0
  226. package/out/{fst-freshness.js → fst/freshness.js} +41 -73
  227. package/out/fst/freshness.js.map +1 -0
  228. package/out/fst/index.d.ts +14 -0
  229. package/out/fst/index.d.ts.map +1 -0
  230. package/out/fst/index.js +14 -0
  231. package/out/fst/index.js.map +1 -0
  232. package/out/{fst-matcher.d.ts → fst/matcher.d.ts} +2 -2
  233. package/out/fst/matcher.d.ts.map +1 -0
  234. package/out/{fst-matcher.js → fst/matcher.js} +1 -1
  235. package/out/fst/matcher.js.map +1 -0
  236. package/out/{fst-serialize.d.ts → fst/serialize.d.ts} +5 -10
  237. package/out/fst/serialize.d.ts.map +1 -0
  238. package/out/{fst-serialize.js → fst/serialize.js} +18 -98
  239. package/out/fst/serialize.js.map +1 -0
  240. package/out/{fst-types.d.ts → fst/types.d.ts} +4 -3
  241. package/out/fst/types.d.ts.map +1 -0
  242. package/out/{fst-types.js → fst/types.js} +1 -1
  243. package/out/fst/types.js.map +1 -0
  244. package/out/{fts.d.ts → fts/index.d.ts} +16 -9
  245. package/out/fts/index.d.ts.map +1 -0
  246. package/out/{fts.js → fts/index.js} +16 -11
  247. package/out/fts/index.js.map +1 -0
  248. package/out/{fts-query.d.ts → fts/query.d.ts} +2 -2
  249. package/out/fts/query.d.ts.map +1 -0
  250. package/out/{fts-query.js → fts/query.js} +1 -1
  251. package/out/fts/query.js.map +1 -0
  252. package/out/{geonames-aliases.d.ts → geonames/aliases.d.ts} +8 -6
  253. package/out/geonames/aliases.d.ts.map +1 -0
  254. package/out/{geonames-aliases.js → geonames/aliases.js} +7 -7
  255. package/out/geonames/aliases.js.map +1 -0
  256. package/out/geonames/index.d.ts +8 -0
  257. package/out/geonames/index.d.ts.map +1 -0
  258. package/out/geonames/index.js +8 -0
  259. package/out/geonames/index.js.map +1 -0
  260. package/out/{geonames-postal.d.ts → geonames/postal.d.ts} +10 -8
  261. package/out/geonames/postal.d.ts.map +1 -0
  262. package/out/{geonames-postal.js → geonames/postal.js} +9 -9
  263. package/out/geonames/postal.js.map +1 -0
  264. package/out/index.d.ts +32 -32
  265. package/out/index.d.ts.map +1 -1
  266. package/out/index.js +24 -24
  267. package/out/index.js.map +1 -1
  268. package/out/interpolation.d.ts +10 -9
  269. package/out/interpolation.d.ts.map +1 -1
  270. package/out/interpolation.js +20 -20
  271. package/out/interpolation.js.map +1 -1
  272. package/out/lookup.d.ts +21 -20
  273. package/out/lookup.d.ts.map +1 -1
  274. package/out/lookup.js +102 -112
  275. package/out/lookup.js.map +1 -1
  276. package/out/name-score.d.ts.map +1 -1
  277. package/out/name-score.js.map +1 -1
  278. package/out/nsul/index.d.ts +8 -0
  279. package/out/nsul/index.d.ts.map +1 -0
  280. package/out/nsul/index.js +8 -0
  281. package/out/nsul/index.js.map +1 -0
  282. package/out/nsul/lookup.d.ts +83 -0
  283. package/out/nsul/lookup.d.ts.map +1 -0
  284. package/out/nsul/lookup.js +80 -0
  285. package/out/nsul/lookup.js.map +1 -0
  286. package/out/nsul/schema.d.ts +100 -0
  287. package/out/nsul/schema.d.ts.map +1 -0
  288. package/out/nsul/schema.js +78 -0
  289. package/out/nsul/schema.js.map +1 -0
  290. package/out/place-importance-schema.d.ts +5 -5
  291. package/out/place-importance-schema.d.ts.map +1 -1
  292. package/out/place-importance-schema.js +3 -3
  293. package/out/place-importance-schema.js.map +1 -1
  294. package/out/poi/index.d.ts +8 -0
  295. package/out/poi/index.d.ts.map +1 -0
  296. package/out/poi/index.js +8 -0
  297. package/out/poi/index.js.map +1 -0
  298. package/out/{poi-lookup.d.ts → poi/lookup.d.ts} +8 -10
  299. package/out/poi/lookup.d.ts.map +1 -0
  300. package/out/{poi-lookup.js → poi/lookup.js} +14 -18
  301. package/out/poi/lookup.js.map +1 -0
  302. package/out/{poi-schema.d.ts → poi/schema.d.ts} +4 -4
  303. package/out/poi/schema.d.ts.map +1 -0
  304. package/out/{poi-schema.js → poi/schema.js} +1 -1
  305. package/out/poi/schema.js.map +1 -0
  306. package/out/polygon-schema.d.ts.map +1 -1
  307. package/out/polygon-schema.js.map +1 -1
  308. package/out/{postal-city-alias-lookup.d.ts → postal/city-alias-lookup.d.ts} +6 -5
  309. package/out/postal/city-alias-lookup.d.ts.map +1 -0
  310. package/out/{postal-city-alias-lookup.js → postal/city-alias-lookup.js} +11 -15
  311. package/out/postal/city-alias-lookup.js.map +1 -0
  312. package/out/{postal-city-alias-schema.d.ts → postal/city-alias-schema.d.ts} +1 -1
  313. package/out/{postal-city-alias-schema.d.ts.map → postal/city-alias-schema.d.ts.map} +1 -1
  314. package/out/{postal-city-alias-schema.js → postal/city-alias-schema.js} +1 -1
  315. package/out/{postal-city-alias-schema.js.map → postal/city-alias-schema.js.map} +1 -1
  316. package/out/{postal-city-candidate-schema.d.ts → postal/city-candidate-schema.d.ts} +3 -3
  317. package/out/{postal-city-candidate-schema.d.ts.map → postal/city-candidate-schema.d.ts.map} +1 -1
  318. package/out/{postal-city-candidate-schema.js → postal/city-candidate-schema.js} +2 -2
  319. package/out/{postal-city-candidate-schema.js.map → postal/city-candidate-schema.js.map} +1 -1
  320. package/out/postal/index.d.ts +9 -0
  321. package/out/postal/index.d.ts.map +1 -0
  322. package/out/postal/index.js +9 -0
  323. package/out/postal/index.js.map +1 -0
  324. package/out/postcode-point-lookup.d.ts +10 -10
  325. package/out/postcode-point-lookup.d.ts.map +1 -1
  326. package/out/postcode-point-lookup.js +13 -13
  327. package/out/postcode-point-lookup.js.map +1 -1
  328. package/out/primary-preference.d.ts +13 -5
  329. package/out/primary-preference.d.ts.map +1 -1
  330. package/out/primary-preference.js +16 -8
  331. package/out/primary-preference.js.map +1 -1
  332. package/out/proximity-rerank.d.ts +2 -2
  333. package/out/proximity-rerank.d.ts.map +1 -1
  334. package/out/proximity-rerank.js +2 -2
  335. package/out/proximity-rerank.js.map +1 -1
  336. package/out/ranking-weights.d.ts +15 -3
  337. package/out/ranking-weights.d.ts.map +1 -1
  338. package/out/ranking-weights.js +21 -3
  339. package/out/ranking-weights.js.map +1 -1
  340. package/out/region-keys.d.ts +8 -8
  341. package/out/region-keys.d.ts.map +1 -1
  342. package/out/region-keys.js +9 -9
  343. package/out/region-keys.js.map +1 -1
  344. package/out/reverse.d.ts +6 -6
  345. package/out/reverse.d.ts.map +1 -1
  346. package/out/reverse.js +20 -29
  347. package/out/reverse.js.map +1 -1
  348. package/out/schema.d.ts +9 -0
  349. package/out/schema.d.ts.map +1 -1
  350. package/out/schema.js.map +1 -1
  351. package/out/search-fetch.d.ts +12 -10
  352. package/out/search-fetch.d.ts.map +1 -1
  353. package/out/search-fetch.js +21 -20
  354. package/out/search-fetch.js.map +1 -1
  355. package/out/sqlite-convention-source.d.ts +7 -7
  356. package/out/sqlite-convention-source.d.ts.map +1 -1
  357. package/out/sqlite-convention-source.js +5 -5
  358. package/out/sqlite-convention-source.js.map +1 -1
  359. package/out/sqlite-utils.d.ts +8 -8
  360. package/out/sqlite-utils.d.ts.map +1 -1
  361. package/out/sqlite-utils.js +7 -8
  362. package/out/sqlite-utils.js.map +1 -1
  363. package/out/{street-centroid-schema.d.ts → street/centroid-schema.d.ts} +6 -6
  364. package/out/{street-centroid-schema.d.ts.map → street/centroid-schema.d.ts.map} +1 -1
  365. package/out/{street-centroid-schema.js → street/centroid-schema.js} +5 -5
  366. package/out/{street-centroid-schema.js.map → street/centroid-schema.js.map} +1 -1
  367. package/out/{street-centroid.d.ts → street/centroid.d.ts} +6 -6
  368. package/out/street/centroid.d.ts.map +1 -0
  369. package/out/{street-centroid.js → street/centroid.js} +13 -19
  370. package/out/street/centroid.js.map +1 -0
  371. package/out/street/index.d.ts +13 -0
  372. package/out/street/index.d.ts.map +1 -0
  373. package/out/street/index.js +13 -0
  374. package/out/street/index.js.map +1 -0
  375. package/out/{street-morphology-fst-builder.d.ts → street/morphology-fst-builder.d.ts} +4 -4
  376. package/out/street/morphology-fst-builder.d.ts.map +1 -0
  377. package/out/{street-morphology-fst-builder.js → street/morphology-fst-builder.js} +18 -13
  378. package/out/street/morphology-fst-builder.js.map +1 -0
  379. package/out/{street-morphology-fst-loader.d.ts → street/morphology-fst-loader.d.ts} +5 -5
  380. package/out/street/morphology-fst-loader.d.ts.map +1 -0
  381. package/out/{street-morphology-fst-loader.js → street/morphology-fst-loader.js} +11 -10
  382. package/out/street/morphology-fst-loader.js.map +1 -0
  383. package/out/{street-name-lookup.d.ts → street/name-lookup.d.ts} +4 -7
  384. package/out/street/name-lookup.d.ts.map +1 -0
  385. package/out/{street-name-lookup.js → street/name-lookup.js} +9 -23
  386. package/out/street/name-lookup.js.map +1 -0
  387. package/out/{street-normalize.d.ts → street/normalize.d.ts} +25 -14
  388. package/out/street/normalize.d.ts.map +1 -0
  389. package/out/{street-normalize.js → street/normalize.js} +36 -17
  390. package/out/street/normalize.js.map +1 -0
  391. package/out/{street-segment-schema.d.ts → street/segment-schema.d.ts} +8 -8
  392. package/out/{street-segment-schema.d.ts.map → street/segment-schema.d.ts.map} +1 -1
  393. package/out/{street-segment-schema.js → street/segment-schema.js} +4 -4
  394. package/out/{street-segment-schema.js.map → street/segment-schema.js.map} +1 -1
  395. package/out/types.d.ts +18 -12
  396. package/out/types.d.ts.map +1 -1
  397. package/out/types.js.map +1 -1
  398. package/out/unified-schema.d.ts +5 -4
  399. package/out/unified-schema.d.ts.map +1 -1
  400. package/out/unified-schema.js +15 -18
  401. package/out/unified-schema.js.map +1 -1
  402. package/out/uprn/existence.d.ts +53 -0
  403. package/out/uprn/existence.d.ts.map +1 -0
  404. package/out/uprn/existence.js +61 -0
  405. package/out/uprn/existence.js.map +1 -0
  406. package/out/uprn/index.d.ts +9 -0
  407. package/out/uprn/index.d.ts.map +1 -0
  408. package/out/uprn/index.js +9 -0
  409. package/out/uprn/index.js.map +1 -0
  410. package/out/{uprn-lookup.d.ts → uprn/lookup.d.ts} +4 -4
  411. package/out/uprn/lookup.d.ts.map +1 -0
  412. package/out/{uprn-lookup.js → uprn/lookup.js} +11 -14
  413. package/out/uprn/lookup.js.map +1 -0
  414. package/out/{uprn-schema.d.ts → uprn/schema.d.ts} +4 -4
  415. package/out/uprn/schema.d.ts.map +1 -0
  416. package/out/{uprn-schema.js → uprn/schema.js} +4 -4
  417. package/out/uprn/schema.js.map +1 -0
  418. package/out/weights-overlay-linker.d.ts +184 -26
  419. package/out/weights-overlay-linker.d.ts.map +1 -1
  420. package/out/weights-overlay-linker.js +338 -86
  421. package/out/weights-overlay-linker.js.map +1 -1
  422. package/package.json +465 -269
  423. package/out/address-point-interpolation.d.ts.map +0 -1
  424. package/out/address-point-interpolation.js.map +0 -1
  425. package/out/address-point-schema.d.ts.map +0 -1
  426. package/out/address-point-schema.js.map +0 -1
  427. package/out/address-point.d.ts.map +0 -1
  428. package/out/address-point.js.map +0 -1
  429. package/out/ancestry-backfill.d.ts.map +0 -1
  430. package/out/ancestry-backfill.js.map +0 -1
  431. package/out/ancestry.d.ts.map +0 -1
  432. package/out/ancestry.js.map +0 -1
  433. package/out/candidate/shard-fold.d.ts +0 -31
  434. package/out/candidate/shard-fold.d.ts.map +0 -1
  435. package/out/candidate/shard-fold.js.map +0 -1
  436. package/out/convention-schema.d.ts.map +0 -1
  437. package/out/convention-schema.js.map +0 -1
  438. package/out/convention.d.ts.map +0 -1
  439. package/out/convention.js.map +0 -1
  440. package/out/fst-autocomplete.d.ts.map +0 -1
  441. package/out/fst-autocomplete.js.map +0 -1
  442. package/out/fst-builder.d.ts.map +0 -1
  443. package/out/fst-builder.js.map +0 -1
  444. package/out/fst-deserialize-web.d.ts.map +0 -1
  445. package/out/fst-deserialize-web.js.map +0 -1
  446. package/out/fst-freshness.d.ts.map +0 -1
  447. package/out/fst-freshness.js.map +0 -1
  448. package/out/fst-matcher.d.ts.map +0 -1
  449. package/out/fst-matcher.js.map +0 -1
  450. package/out/fst-serialize.d.ts.map +0 -1
  451. package/out/fst-serialize.js.map +0 -1
  452. package/out/fst-types.d.ts.map +0 -1
  453. package/out/fst-types.js.map +0 -1
  454. package/out/fts-query.d.ts.map +0 -1
  455. package/out/fts-query.js.map +0 -1
  456. package/out/fts.d.ts.map +0 -1
  457. package/out/fts.js.map +0 -1
  458. package/out/geonames-aliases.d.ts.map +0 -1
  459. package/out/geonames-aliases.js.map +0 -1
  460. package/out/geonames-postal.d.ts.map +0 -1
  461. package/out/geonames-postal.js.map +0 -1
  462. package/out/poi-lookup.d.ts.map +0 -1
  463. package/out/poi-lookup.js.map +0 -1
  464. package/out/poi-schema.d.ts.map +0 -1
  465. package/out/poi-schema.js.map +0 -1
  466. package/out/postal-city-alias-lookup.d.ts.map +0 -1
  467. package/out/postal-city-alias-lookup.js.map +0 -1
  468. package/out/sharding.d.ts +0 -114
  469. package/out/sharding.d.ts.map +0 -1
  470. package/out/sharding.js.map +0 -1
  471. package/out/street-centroid.d.ts.map +0 -1
  472. package/out/street-centroid.js.map +0 -1
  473. package/out/street-morphology-fst-builder.d.ts.map +0 -1
  474. package/out/street-morphology-fst-builder.js.map +0 -1
  475. package/out/street-morphology-fst-loader.d.ts.map +0 -1
  476. package/out/street-morphology-fst-loader.js.map +0 -1
  477. package/out/street-name-lookup.d.ts.map +0 -1
  478. package/out/street-name-lookup.js.map +0 -1
  479. package/out/street-normalize.d.ts.map +0 -1
  480. package/out/street-normalize.js.map +0 -1
  481. package/out/uprn-lookup.d.ts.map +0 -1
  482. package/out/uprn-lookup.js.map +0 -1
  483. package/out/uprn-schema.d.ts.map +0 -1
  484. package/out/uprn-schema.js.map +0 -1
  485. package/weights-overlay-linker.ts +0 -377
  486. /package/{name-score.ts → lib/name-score.ts} +0 -0
  487. /package/{polygon-schema.ts → lib/polygon-schema.ts} +0 -0
  488. /package/{postal-city-alias-schema.ts → lib/postal/city-alias-schema.ts} +0 -0
@@ -29,23 +29,23 @@
29
29
  * (both derive purely from `spr` + `names` — see `fts.ts`). That means `WOFSQLitePlaceLookup`
30
30
  * opens the slim DB without any code change — it sees a smaller universe, nothing more.
31
31
  *
32
- * Multi-shard inputs (e.g. admin + postcode) are processed in sequence; selected rows accumulate
33
- * into the single output DB. The postcode shard contributes only postcodes; admin contributes
34
- * everything else. Empty / missing input paths are skipped (callers pass `""` when a shard, such
32
+ * Multi-extract inputs (e.g. admin + postcode) are processed in sequence; selected rows accumulate
33
+ * into the single output DB. The postcode extract contributes only postcodes; admin contributes
34
+ * everything else. Empty / missing input paths are skipped (callers pass `""` when a extract, such
35
35
  * as a custom postcode DB, isn't built yet).
36
36
  */
37
37
 
38
- import { copyFileSync, existsSync, mkdtempSync, rmSync, statSync } from "node:fs"
39
- import { tmpdir } from "node:os"
40
- import { join } from "node:path"
41
- import { DatabaseSync } from "node:sqlite"
38
+ import { statPath, pathExists } from "@mailwoman/core/fs/readers"
39
+ import { temporaryDirectory } from "@mailwoman/core/fs/temporary"
40
+ import { copyFileTo, removePath } from "@mailwoman/core/fs/writers"
41
+ import { countRows } from "@mailwoman/sqlite"
42
+ import { DatabaseClient } from "@mailwoman/sqlite/client"
43
+ import { sealDatabase } from "@mailwoman/sqlite/sealed-db"
44
+ import { sql } from "kysely"
45
+ import type { Kysely } from "kysely"
42
46
 
43
- import { SqliteDialect } from "@mailwoman/core/kysley/dialect"
44
- import { sealDatabase } from "@mailwoman/core/utils"
45
- import { Kysely, sql } from "kysely"
46
-
47
- import { buildPlaceSearchFTS, PLACE_BBOX_TABLE, PLACE_POPULATION_TABLE, PLACE_SEARCH_TABLE } from "./fts.ts"
48
- import type { NamesTable, SprTable } from "./schema.ts"
47
+ import { buildPlaceSearchFTS, PLACE_BBOX_TABLE, PLACE_POPULATION_TABLE, PLACE_SEARCH_TABLE } from "#fts/index"
48
+ import type { NamesTable, SprTable, WOFDatabase } from "#schema"
49
49
 
50
50
  export interface BuildSlimOptions {
51
51
  /**
@@ -69,7 +69,7 @@ export interface BuildSlimOptions {
69
69
  * external `content=`), so once it's built `names` is only the build-time source — the resolver queries
70
70
  * `place_search` + `spr` + `place_population` + `coincident_roles` and never reads `names` at runtime. Dropping it is
71
71
  * the single biggest size win (~2/3 of the file for a multi-locale build; see #359). A future consumer that needs raw
72
- * alt-names at runtime should ship a SEPARATE shard rather than re-bloat the hot DB.
72
+ * alt-names at runtime should ship a SEPARATE extract rather than re-bloat the hot DB.
73
73
  */
74
74
  dropNames?: boolean
75
75
  /**
@@ -149,65 +149,59 @@ export async function buildSlimWOFDatabase(opts: BuildSlimOptions): Promise<Buil
149
149
  const topLocalities = opts.topLocalitiesPerCountry ?? 1000
150
150
  const progress = opts.onProgress ?? (() => {})
151
151
 
152
- // Callers pass `""` for shards that don't exist yet (e.g. a not-yet-built custom postcode DB).
152
+ // Callers pass `""` for extracts that don't exist yet (e.g. a not-yet-built custom postcode DB).
153
153
  // Skip empties up front; require every remaining path to exist.
154
154
  const inputs = opts.inputs.filter((p) => p.length > 0)
155
155
 
156
156
  if (!inputs.length) throw new Error("no input WOF dbs provided")
157
157
 
158
158
  for (const input of inputs) {
159
- if (!existsSync(input)) throw new Error(`input WOF db not found: ${input}`)
159
+ if (!(await pathExists(input))) throw new Error(`input WOF db not found: ${input}`)
160
160
  }
161
161
 
162
162
  progress("init", `${inputs.length} input(s) → ${opts.output}`)
163
163
 
164
- if (existsSync(opts.output)) {
165
- rmSync(opts.output)
164
+ if (await pathExists(opts.output)) {
165
+ await removePath(opts.output)
166
166
  }
167
167
 
168
168
  // Open the output DB and create the empty schema. We discover the schema from the FIRST input
169
169
  // (raw sqlite_master read — Kysely doesn't model that) so the output mirrors source column
170
170
  // ordering / types. `CREATE TABLE AS SELECT` flattens types to dynamic, which would break
171
171
  // callers that rely on column-affinity behavior.
172
- const out = new DatabaseSync(opts.output)
172
+ const out = new DatabaseClient<BuildSchema>(opts.output)
173
173
  let result: BuildSlimResult
174
174
 
175
175
  try {
176
- const firstSource = new DatabaseSync(inputs[0]!, { readOnly: true })
177
-
178
- try {
179
- progress("schema", "copying spr / names / place_population schemas from first input")
180
-
181
- for (const table of COPIED_TABLES) {
182
- const createSQL = firstSource
183
- .prepare(`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?`)
184
- .get(table) as { sql?: string } | undefined
185
-
186
- if (createSQL?.sql) {
187
- // Raw DDL by design (introspect-and-replay): we exec the SOURCE DB's own CREATE TABLE
188
- // string read from sqlite_master, so a static Kysely builder can't express it. See AGENTS.md.
189
- out.exec(createSQL.sql)
190
- } else if (table === PLACE_POPULATION_TABLE) {
191
- // Older source builds may predate the aux table — create it empty so the per-source
192
- // copy + ranking have somewhere to land. Sparse-by-design; missing rows are fine.
193
- out.exec(PLACE_POPULATION_DDL)
194
- } else {
195
- throw new Error(`source DB ${inputs[0]} is missing required table '${table}'`)
196
- }
176
+ using firstSource = new DatabaseClient<WOFDatabase>(inputs[0]!, { readOnly: true })
177
+
178
+ progress("schema", "copying spr / names / place_population schemas from first input")
179
+
180
+ for (const table of COPIED_TABLES) {
181
+ const createSQL = firstSource
182
+ .prepare(`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?`)
183
+ .get(table) as { sql?: string } | undefined
184
+
185
+ if (createSQL?.sql) {
186
+ // Raw DDL by design (introspect-and-replay): we exec the SOURCE DB's own CREATE TABLE
187
+ // string read from sqlite_master, so a static Kysely builder can't express it. See AGENTS.md.
188
+ out.exec(createSQL.sql)
189
+ } else if (table === PLACE_POPULATION_TABLE) {
190
+ // Older source builds may predate the aux table — create it empty so the per-source
191
+ // copy + ranking have somewhere to land. Sparse-by-design; missing rows are fine.
192
+ out.exec(PLACE_POPULATION_DDL)
193
+ } else {
194
+ throw new Error(`source DB ${inputs[0]} is missing required table '${table}'`)
197
195
  }
198
-
199
- // PRIMARY KEY on spr.id + place_population.id come from the schemas we copied; an explicit
200
- // index on names.id helps the per-id INSERT SELECT later.
201
- out.exec(`CREATE INDEX IF NOT EXISTS names_id_idx ON names(id);`)
202
- } finally {
203
- firstSource.close()
204
196
  }
205
197
 
206
- const kysely = new Kysely<BuildSchema>({ dialect: new SqliteDialect({ database: out }) })
198
+ // PRIMARY KEY on spr.id + place_population.id come from the schemas we copied; an explicit
199
+ // index on names.id helps the per-id INSERT SELECT later.
200
+ out.exec(`CREATE INDEX IF NOT EXISTS names_id_idx ON names(id);`)
207
201
 
208
202
  // Pull rows from each input.
209
203
  for (const inputPath of inputs) {
210
- await copyFromSource(out, kysely, inputPath, countries, topLocalities, progress)
204
+ await copyFromSource(out, out, inputPath, countries, topLocalities, progress)
211
205
  }
212
206
 
213
207
  // Build the resolver virtual tables on the trimmed row set. Both place_search (FTS5) and
@@ -264,21 +258,21 @@ export async function buildSlimWOFDatabase(opts: BuildSlimOptions): Promise<Buil
264
258
 
265
259
  result = {
266
260
  outputPath: opts.output,
267
- outputBytes: statSync(opts.output).size,
261
+ outputBytes: (await statPath(opts.output)).size,
268
262
  rowCounts,
269
263
  }
270
264
  } finally {
271
- out.close()
265
+ await out.destroy()
272
266
  }
273
267
 
274
268
  // The sealed-artifact invariant: a built DB is a read-only asset from the moment it exists.
275
- sealDatabase(opts.output)
269
+ await sealDatabase(opts.output)
276
270
 
277
271
  return result
278
272
  }
279
273
 
280
274
  async function copyFromSource(
281
- out: DatabaseSync,
275
+ out: DatabaseClient<BuildSchema>,
282
276
  kysely: Kysely<BuildSchema>,
283
277
  inputPath: string,
284
278
  countries: string[],
@@ -290,134 +284,125 @@ async function copyFromSource(
290
284
  // ATTACH will still want a writable journal on the side; copying to /tmp dodges that without
291
285
  // mutating the canonical files in /mnt/playpen/mailwoman-data/wof/. ATTACH / DETACH stay raw
292
286
  // — Kysely doesn't model them.
293
- const tmpScratch = mkdtempSync(join(tmpdir(), "mailwoman-slim-src-"))
294
- const scratchPath = join(tmpScratch, "src.db")
295
- copyFileSync(inputPath, scratchPath)
287
+ await using tmpScratch = await temporaryDirectory("mailwoman-slim-src-")
288
+ const scratchPath = tmpScratch.resolve("src.db")
296
289
 
297
- try {
298
- out.exec(`ATTACH DATABASE '${scratchPath.replaceAll("'", "''")}' AS src;`)
299
-
300
- try {
301
- // Does this shard carry the pre-built population aux table? The admin source does; a bare
302
- // postcode shard might not. The locality ranking + population copy below adapt accordingly.
303
- const srcHasPopulation = Boolean(
304
- out.prepare(`SELECT 1 FROM src.sqlite_master WHERE type = 'table' AND name = '${PLACE_POPULATION_TABLE}'`).get()
305
- )
290
+ await copyFileTo(inputPath, scratchPath)
306
291
 
307
- // The SELECT-INSERT queries below go through Kysely. The cross-schema FROM is the only
308
- // "interesting" bit: by declaring `src.spr` / `src.names` / `src.place_population` in
309
- // `BuildSchema`, Kysely lets us write `selectFrom("src.spr")` with the same column-type
310
- // checking as the regular schema. SQLite parses the dotted identifier as a schema-name
311
- // qualifier, so this works directly without any aliasing trick.
292
+ out.exec(`ATTACH DATABASE '${scratchPath.replaceAll("'", "''")}' AS src;`)
312
293
 
313
- // 1. Ancestor placetypes (country / region / county / etc.) — always-kept.
314
- progress("country", `${inputPath}: ancestor placetypes in (${countries.join(",")})`)
315
-
316
- await kysely
317
- .insertInto("spr")
318
- .expression((eb) =>
319
- eb
320
- .selectFrom("src.spr")
321
- .selectAll()
322
- .where("is_current", "!=", 0)
323
- .where("is_deprecated", "=", 0)
324
- .where("country", "in", countries)
325
- .where("placetype", "in", [...ANCESTOR_PLACETYPES])
326
- )
327
- .onConflict((oc) => oc.doNothing())
328
- .execute()
294
+ try {
295
+ // Does this extract carry the pre-built population aux table? The admin source does; a bare
296
+ // postcode extract might not. The locality ranking + population copy below adapt accordingly.
297
+ const srcHasPopulation = Boolean(
298
+ out.prepare(`SELECT 1 FROM src.sqlite_master WHERE type = 'table' AND name = '${PLACE_POPULATION_TABLE}'`).get()
299
+ )
300
+
301
+ // The SELECT-INSERT queries below go through Kysely. The cross-schema FROM is the only
302
+ // "interesting" bit: by declaring `src.spr` / `src.names` / `src.place_population` in
303
+ // `BuildSchema`, Kysely lets us write `selectFrom("src.spr")` with the same column-type
304
+ // checking as the regular schema. SQLite parses the dotted identifier as a schema-name
305
+ // qualifier, so this works directly without any aliasing trick.
306
+
307
+ // 1. Ancestor placetypes (country / region / county / etc.) — always-kept.
308
+ progress("country", `${inputPath}: ancestor placetypes in (${countries.join(",")})`)
309
+
310
+ await kysely
311
+ .insertInto("spr")
312
+ .expression((eb) =>
313
+ eb
314
+ .selectFrom("src.spr")
315
+ .selectAll()
316
+ .where("is_current", "!=", 0)
317
+ .where("is_deprecated", "=", 0)
318
+ .where("country", "in", countries)
319
+ .where("placetype", "in", [...ANCESTOR_PLACETYPES])
320
+ )
321
+ .onConflict((oc) => oc.doNothing())
322
+ .execute()
323
+
324
+ // 2. Top-K localities by population. Population lives in the pre-built `place_population`
325
+ // aux table — left-join it so localities without a population row still qualify (sorted
326
+ // last). If the extract has no population table, fall back to a deterministic id ordering.
327
+ progress("locality", `${inputPath}: top-${topLocalities} localities by population`)
328
+
329
+ await kysely
330
+ .insertInto("spr")
331
+ .expression((eb) =>
332
+ eb
333
+ .selectFrom("src.spr as s")
334
+ .$if(srcHasPopulation, (qb) => qb.leftJoin("src.place_population as p", "p.id", "s.id"))
335
+ .selectAll("s")
336
+ .where("s.is_current", "!=", 0)
337
+ .where("s.is_deprecated", "=", 0)
338
+ .where("s.country", "in", countries)
339
+ .where("s.placetype", "=", "locality")
340
+ .orderBy(srcHasPopulation ? sql<number>`COALESCE(p.population, 0)` : sql<number>`s.id`, "desc")
341
+ .limit(topLocalities)
342
+ )
343
+ .onConflict((oc) => oc.doNothing())
344
+ .execute()
345
+
346
+ // 3. All postcodes in scope.
347
+ progress("postcode", `${inputPath}: all postcodes`)
348
+
349
+ await kysely
350
+ .insertInto("spr")
351
+ .expression((eb) =>
352
+ eb
353
+ .selectFrom("src.spr")
354
+ .selectAll()
355
+ .where("is_current", "!=", 0)
356
+ .where("is_deprecated", "=", 0)
357
+ .where("country", "in", countries)
358
+ .where("placetype", "=", "postalcode")
359
+ )
360
+ .onConflict((oc) => oc.doNothing())
361
+ .execute()
329
362
 
330
- // 2. Top-K localities by population. Population lives in the pre-built `place_population`
331
- // aux table — left-join it so localities without a population row still qualify (sorted
332
- // last). If the shard has no population table, fall back to a deterministic id ordering.
333
- progress("locality", `${inputPath}: top-${topLocalities} localities by population`)
363
+ // 4. Pull names for the IDs we just selected.
364
+ progress("names", `${inputPath}: names rows for selected IDs`)
334
365
 
335
- await kysely
336
- .insertInto("spr")
337
- .expression((eb) =>
338
- eb
339
- .selectFrom("src.spr as s")
340
- .$if(srcHasPopulation, (qb) => qb.leftJoin("src.place_population as p", "p.id", "s.id"))
341
- .selectAll("s")
342
- .where("s.is_current", "!=", 0)
343
- .where("s.is_deprecated", "=", 0)
344
- .where("s.country", "in", countries)
345
- .where("s.placetype", "=", "locality")
346
- .orderBy(srcHasPopulation ? sql<number>`COALESCE(p.population, 0)` : sql<number>`s.id`, "desc")
347
- .limit(topLocalities)
348
- )
349
- .onConflict((oc) => oc.doNothing())
350
- .execute()
366
+ await kysely
367
+ .insertInto("names")
368
+ .expression((eb) => eb.selectFrom("src.names").selectAll().where("id", "in", eb.selectFrom("spr").select("id")))
369
+ .onConflict((oc) => oc.doNothing())
370
+ .execute()
351
371
 
352
- // 3. All postcodes in scope.
353
- progress("postcode", `${inputPath}: all postcodes`)
372
+ // 5. Pull population rows for the selected IDs (sparse — only the places WOF has a count for).
373
+ if (srcHasPopulation) {
374
+ progress("place_population", `${inputPath}: population rows for selected IDs`)
354
375
 
355
376
  await kysely
356
- .insertInto("spr")
377
+ .insertInto("place_population")
357
378
  .expression((eb) =>
358
- eb
359
- .selectFrom("src.spr")
360
- .selectAll()
361
- .where("is_current", "!=", 0)
362
- .where("is_deprecated", "=", 0)
363
- .where("country", "in", countries)
364
- .where("placetype", "=", "postalcode")
379
+ eb.selectFrom("src.place_population").selectAll().where("id", "in", eb.selectFrom("spr").select("id"))
365
380
  )
366
381
  .onConflict((oc) => oc.doNothing())
367
382
  .execute()
383
+ }
368
384
 
369
- // 4. Pull names for the IDs we just selected.
370
- progress("names", `${inputPath}: names rows for selected IDs`)
371
-
372
- await kysely
373
- .insertInto("names")
374
- .expression((eb) => eb.selectFrom("src.names").selectAll().where("id", "in", eb.selectFrom("spr").select("id")))
375
- .onConflict((oc) => oc.doNothing())
376
- .execute()
377
-
378
- // 5. Pull population rows for the selected IDs (sparse — only the places WOF has a count for).
379
- if (srcHasPopulation) {
380
- progress("place_population", `${inputPath}: population rows for selected IDs`)
381
-
382
- await kysely
383
- .insertInto("place_population")
384
- .expression((eb) =>
385
- eb.selectFrom("src.place_population").selectAll().where("id", "in", eb.selectFrom("spr").select("id"))
386
- )
387
- .onConflict((oc) => oc.doNothing())
388
- .execute()
389
- }
390
-
391
- // 6. Carry the coincident_roles relation (#402) when this source has it (the admin DB), so the
392
- // slim/demo DB supports dual-role hierarchy completion (on by default). Filtered to surviving
393
- // spr ids → no orphans. Tiny (~hundreds of rows). `ancestors` is intentionally NOT copied (huge
394
- // + build-only), so we copy the derived table rather than rebuild it. Raw SQL — conditional +
395
- // not in the Kysely build schema.
396
- const relationSchema = out
397
- .prepare(`SELECT sql FROM src.sqlite_master WHERE type = 'table' AND name = 'coincident_roles'`)
398
- .get() as { sql?: string } | undefined
399
-
400
- if (relationSchema?.sql) {
401
- progress("coincident_roles", `${inputPath}: copying dual-role relation`)
402
- out.exec(relationSchema.sql.replace(/CREATE TABLE/i, "CREATE TABLE IF NOT EXISTS"))
403
-
404
- out.exec(
405
- `INSERT OR IGNORE INTO coincident_roles SELECT * FROM src.coincident_roles
406
- WHERE admin_id IN (SELECT id FROM spr) AND locality_id IN (SELECT id FROM spr)`
407
- )
385
+ // 6. Carry the coincident_roles relation (#402) when this source has it (the admin DB), so the
386
+ // slim/demo DB supports dual-role hierarchy completion (on by default). Filtered to surviving
387
+ // spr ids → no orphans. Tiny (~hundreds of rows). `ancestors` is intentionally NOT copied (huge
388
+ // + build-only), so we copy the derived table rather than rebuild it. Raw SQL — conditional +
389
+ // not in the Kysely build schema.
390
+ const relationSchema = out
391
+ .prepare(`SELECT sql FROM src.sqlite_master WHERE type = 'table' AND name = 'coincident_roles'`)
392
+ .get() as { sql?: string } | undefined
393
+
394
+ if (relationSchema?.sql) {
395
+ progress("coincident_roles", `${inputPath}: copying dual-role relation`)
396
+ out.exec(relationSchema.sql.replace(/CREATE TABLE/i, "CREATE TABLE IF NOT EXISTS"))
397
+
398
+ out.exec(
399
+ `INSERT OR IGNORE INTO coincident_roles SELECT * FROM src.coincident_roles
400
+ WHERE admin_id IN (SELECT id FROM spr) AND locality_id IN (SELECT id FROM spr)`
401
+ )
408
402
 
409
- out.exec(`CREATE INDEX IF NOT EXISTS coincident_roles_by_admin ON coincident_roles (admin_id)`)
410
- }
411
- } finally {
412
- out.exec(`DETACH DATABASE src;`)
403
+ out.exec(`CREATE INDEX IF NOT EXISTS coincident_roles_by_admin ON coincident_roles (admin_id)`)
413
404
  }
414
405
  } finally {
415
- rmSync(tmpScratch, { recursive: true, force: true })
406
+ out.exec(`DETACH DATABASE src;`)
416
407
  }
417
408
  }
418
-
419
- function countRows(db: DatabaseSync, table: string): number {
420
- const row = db.prepare(`SELECT COUNT(*) AS n FROM ${table}`).get() as { n?: number } | undefined
421
-
422
- return Number(row?.n ?? 0)
423
- }
@@ -5,19 +5,21 @@
5
5
  * @file Pass 2 of the candidate build — explode `place_search.alt_names` into distinct alias rows.
6
6
  */
7
7
 
8
- import type { DatabaseSync } from "node:sqlite"
8
+ import type { DatabaseClient } from "@mailwoman/sqlite/client"
9
9
 
10
- import { ALIAS_SEPARATOR } from "../fts.ts"
11
- import { normalizeLocalityForKey } from "../street-normalize.ts"
12
- import type { PlaceAttrs, StageRow } from "./place-attrs.ts"
10
+ import type { CandidateDatabase } from "#candidate-schema"
11
+ import type { PlaceAttrs, StageRow } from "#candidate/place-attrs"
12
+ import { ALIAS_SEPARATOR } from "#fts/index"
13
+ import type { WOFDatabase } from "#schema"
14
+ import { normalizeLocalityForKey } from "#street/normalize"
13
15
 
14
16
  /**
15
17
  * Pass 2 — explode each place's `place_search.alt_names` bag into distinct-key alias rows (`is_primary = 0`), and count
16
18
  * each place's distinct staged keys (primary included) — the gloss detector's key-count signal (#1730).
17
19
  */
18
20
  export function explodeAliasBags(
19
- src: DatabaseSync,
20
- out: DatabaseSync,
21
+ src: DatabaseClient<WOFDatabase>,
22
+ out: DatabaseClient<CandidateDatabase>,
21
23
  attrs: Map<number, PlaceAttrs>,
22
24
  stageRow: StageRow
23
25
  ): { nAlias: number; keyCounts: Map<number, number> } {
@@ -5,11 +5,9 @@
5
5
  * @file Pass 3b of the candidate build — the containment sidecar (closure rows + interval labels).
6
6
  */
7
7
 
8
- import type { DatabaseSync } from "node:sqlite"
8
+ import type { DatabaseClient } from "@mailwoman/sqlite/client"
9
9
 
10
- import type { DatabaseClient } from "@mailwoman/core/kysley/client"
11
-
12
- import { placetypeDepth } from "../ancestry.ts"
10
+ import { placetypeDepth } from "#ancestry/index"
13
11
  import {
14
12
  CANDIDATE_ANCESTOR_COLUMNS,
15
13
  CANDIDATE_ANCESTOR_TABLE,
@@ -17,9 +15,10 @@ import {
17
15
  createCandidateAncestorTable,
18
16
  createCandidateIntervalTable,
19
17
  MAX_ANCESTOR_DEPTH,
20
- } from "../candidate-ancestors-schema.ts"
21
- import type { CandidateDatabase } from "../candidate-schema.ts"
22
- import type { PlaceAttrs } from "./place-attrs.ts"
18
+ } from "#candidate-ancestors-schema"
19
+ import type { CandidateDatabase } from "#candidate-schema"
20
+ import type { PlaceAttrs } from "#candidate/place-attrs"
21
+ import type { WOFDatabase } from "#schema"
23
22
 
24
23
  /**
25
24
  * Pass 3b — the ancestors sidecar: closure rows + interval labels (candidate-ancestors-schema.ts owns the encoding
@@ -27,14 +26,13 @@ import type { PlaceAttrs } from "./place-attrs.ts"
27
26
  * denormalizing each edge with the parent's name/key from `attrs`, streamed `ORDER BY id` so the clustered `(spr_id,
28
27
  * depth)` insert is sorted — the contiguous-leaves discipline of the candidate table itself.
29
28
  *
30
- * Excluded by policy: self rows, and placetypes outside the containment ladder (continent, empire, …: `placetypeDepth`
31
- * 0) — they discriminate nothing a consumer of this sidecar checks. An edge to a parent with no current `spr` row has
32
- * no name to denormalize; it is dropped and counted rather than stored blind.
29
+ * Excluded by policy: self rows, and placetypes outside the containment ladder (continent, empire, …: `placetypeDepth` 0)
30
+ * — they discriminate nothing a consumer of this sidecar checks. An edge to a parent with no current `spr` row has no
31
+ * name to denormalize; it is dropped and counted rather than stored blind.
33
32
  */
34
33
  export async function buildAncestorsSidecar(ctx: {
35
- src: DatabaseSync
36
- out: DatabaseSync
37
- kdb: DatabaseClient<CandidateDatabase>
34
+ src: DatabaseClient<WOFDatabase>
35
+ out: DatabaseClient<CandidateDatabase>
38
36
  attrs: Map<number, PlaceAttrs>
39
37
  ptID: (pt: string | null) => number
40
38
  progress: (phase: string, message: string) => void
@@ -42,8 +40,8 @@ export async function buildAncestorsSidecar(ctx: {
42
40
  const { src, out, attrs, ptID, progress } = ctx
43
41
 
44
42
  progress("ancestors", "building containment sidecar (closure rows + interval labels)")
45
- await createCandidateAncestorTable(ctx.kdb)
46
- await createCandidateIntervalTable(ctx.kdb)
43
+ await createCandidateAncestorTable(ctx.out)
44
+ await createCandidateIntervalTable(ctx.out)
47
45
 
48
46
  const insAncestor = out.prepare(
49
47
  `INSERT INTO ${CANDIDATE_ANCESTOR_TABLE} VALUES (${CANDIDATE_ANCESTOR_COLUMNS.map(() => "?").join(", ")})`
@@ -7,8 +7,8 @@
7
7
 
8
8
  import { enumerateCountryDisplayNames } from "@mailwoman/codex/country"
9
9
 
10
- import { normalizeLocalityForKey } from "../street-normalize.ts"
11
- import type { PlaceAttrs, StageRow } from "./place-attrs.ts"
10
+ import type { PlaceAttrs, StageRow } from "#candidate/place-attrs"
11
+ import { normalizeLocalityForKey } from "#street/normalize"
12
12
 
13
13
  /**
14
14
  * Fold every country surface ICU knows onto that country's candidate row (#1678 thread 1).
@@ -2,40 +2,43 @@
2
2
  * @copyright Sister Software
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
- * @file Pass 4 of the candidate build — fold a postcode or locality shard into the staging table.
5
+ * @file Pass 4 of the candidate build — fold a postcode or locality extract into the staging table.
6
6
  */
7
7
 
8
- import { DatabaseSync } from "node:sqlite"
8
+ import { DatabaseClient } from "@mailwoman/sqlite/client"
9
+ import { tableExists } from "@mailwoman/sqlite/introspection"
9
10
 
10
- import { normalizeLocalityForKey } from "../street-normalize.ts"
11
- import type { PlaceAttrs, StageRow } from "./place-attrs.ts"
11
+ import type { CandidateDatabase } from "#candidate-schema"
12
+ import type { PlaceAttrs, StageRow } from "#candidate/place-attrs"
13
+ import type { WOFDatabase } from "#schema"
14
+ import { normalizeLocalityForKey } from "#street/normalize"
12
15
 
13
16
  /**
14
- * Fold ONE shard (`spr` rows at `shardPlacetype` carrying real coordinates) in, then pass 4b: the alias names hanging
15
- * off that same shard's `names` table.
17
+ * Fold ONE extract (`spr` rows at `extractPlacetype` carrying real coordinates) in, then pass 4b: the alias names
18
+ * hanging off that same extract's `names` table.
16
19
  *
17
20
  * Self-contained by construction — it shares only the staging statement and the code dictionaries with the admin passes
18
21
  * above it, and nothing downstream reads anything it produces except the two counters it returns.
19
22
  */
20
- export function foldShard(ctx: {
23
+ export function foldExtract(ctx: {
21
24
  /**
22
- * The staging connection. The shard itself is opened read-only here and closed before returning.
25
+ * The staging connection. The extract itself is opened read-only here and closed before returning.
23
26
  */
24
- out: DatabaseSync
25
- shardPath: string
26
- shardPlacetype: "postalcode" | "locality"
27
+ out: DatabaseClient<CandidateDatabase>
28
+ extractPath: string
29
+ extractPlacetype: "postalcode" | "locality"
27
30
  ccID: (code: string | null) => number
28
31
  ptID: (pt: string | null) => number
29
32
  stageRow: StageRow
30
33
  progress: (phase: string, message: string) => void
31
34
  }): { primaries: number; aliases: number } {
32
- const { out, shardPath, shardPlacetype, ccID, ptID, stageRow, progress } = ctx
35
+ const { out, extractPath, extractPlacetype, ccID, ptID, stageRow, progress } = ctx
33
36
 
34
- progress(shardPlacetype === "postalcode" ? "postcodes" : "localities", `reading ${shardPath}`)
37
+ progress(extractPlacetype === "postalcode" ? "postcodes" : "localities", `reading ${extractPath}`)
35
38
 
36
- const pc = new DatabaseSync(shardPath, { readOnly: true })
37
- const pcPtid = ptID(shardPlacetype)
38
- // Per-shard, not the admin `attrs` map: pass 1 only ever sees the admin DB, so the alias pass
39
+ using pc = new DatabaseClient<WOFDatabase>(extractPath, { readOnly: true })
40
+ const pcPtid = ptID(extractPlacetype)
41
+ // Per-extract, not the admin `attrs` map: pass 1 only ever sees the admin DB, so the alias pass
39
42
  // below has nothing to join against unless this primary loop records what it staged.
40
43
  const pcAttrs = new Map<number, PlaceAttrs>()
41
44
  let primaries = 0
@@ -49,7 +52,7 @@ export function foldShard(ctx: {
49
52
  min_latitude AS mnlat, min_longitude AS mnlon, max_latitude AS mxlat, max_longitude AS mxlon
50
53
  FROM spr WHERE placetype = ? AND latitude != 0 AND longitude != 0`
51
54
  )
52
- .iterate(shardPlacetype)) {
55
+ .iterate(extractPlacetype)) {
53
56
  const name = String(r.name ?? "")
54
57
  const key = normalizeLocalityForKey(name)
55
58
 
@@ -91,18 +94,18 @@ export function foldShard(ctx: {
91
94
  // --- pass 4b: postcode ALIAS names (#1495) ---
92
95
  //
93
96
  // The delivery-city names GeoNames supplies for a ZIP ("Brooklyn" for 11201) are written into
94
- // the shard's `names` table by `postcode/centroid-fills.ts`'s `geonamesNameFill`. Everything
97
+ // the extract's `names` table by `postcode/centroid-fills.ts`'s `geonamesNameFill`. Everything
95
98
  // downstream of `names` picked them up EXCEPT this build: `fts.ts` unions `spr.name` with every
96
99
  // `names` row into `place_search.alt_names`, so the FTS backend resolved "Brooklyn" → 11201
97
100
  // while the candidate backend — whose every row IS an exact-tier row — had no key for it at
98
101
  // all. Pass 2 does the equivalent fold for admin places, but reads the ADMIN `place_search`,
99
- // and `attrs` holds admin ids only, so a postcode shard could never reach it.
102
+ // and `attrs` holds admin ids only, so a postcode extract could never reach it.
100
103
  //
101
104
  // Same discipline as pass 2: `is_primary = 0` (so `rankByPrimaryPreference` treats it as an
102
105
  // alias, not a canonical postcode name), the row stays denormalized onto the POSTCODE's own
103
106
  // spr_id/coords/bbox, and the display `name` stays the postcode — resolving "brooklyn" answers
104
107
  // with place 11201, it does not rename the place to its delivery city.
105
- const hasNames = pc.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='names'").get() !== undefined
108
+ const hasNames = tableExists(pc, "names")
106
109
 
107
110
  if (hasNames) {
108
111
  out.exec("BEGIN")
@@ -125,13 +128,11 @@ export function foldShard(ctx: {
125
128
 
126
129
  out.exec("COMMIT")
127
130
  } else {
128
- // Never a silent zero: real shards come from `createUnifiedSchema`, which always creates
129
- // `names`. A shard without it has no alias surface to lose, but say so rather than reporting
131
+ // Never a silent zero: real extracts come from `createUnifiedSchema`, which always creates
132
+ // `names`. A extract without it has no alias surface to lose, but say so rather than reporting
130
133
  // "0 aliases" from a table that was never read.
131
- progress("postcode-aliases", `${shardPath} has no \`names\` table — no delivery-city aliases to fold`)
134
+ progress("postcode-aliases", `${extractPath} has no \`names\` table — no delivery-city aliases to fold`)
132
135
  }
133
136
 
134
- pc.close()
135
-
136
137
  return { primaries, aliases }
137
138
  }