@mailwoman/corpus 9.0.0 → 9.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (524) hide show
  1. package/README.md +3 -3
  2. package/data/PROVENANCE.md +227 -0
  3. package/data/reviewed-ve-postcode-tuples.json +74 -0
  4. package/data/sub-venue-lexicon.json +18269 -0
  5. package/out/src/adapters/ban/adapter.d.ts +1 -1
  6. package/out/src/adapters/ban/adapter.d.ts.map +1 -1
  7. package/out/src/adapters/ban/adapter.js +5 -4
  8. package/out/src/adapters/ban/adapter.js.map +1 -1
  9. package/out/src/adapters/fcc-bdc/adapter.d.ts +1 -1
  10. package/out/src/adapters/fcc-bdc/adapter.d.ts.map +1 -1
  11. package/out/src/adapters/fcc-bdc/adapter.js +3 -3
  12. package/out/src/adapters/fcc-bdc/adapter.js.map +1 -1
  13. package/out/src/adapters/geonames/adapter.d.ts +1 -1
  14. package/out/src/adapters/geonames/adapter.d.ts.map +1 -1
  15. package/out/src/adapters/geonames/adapter.js +2 -2
  16. package/out/src/adapters/geonames/adapter.js.map +1 -1
  17. package/out/src/adapters/geonames-postal/adapter.d.ts +1 -1
  18. package/out/src/adapters/geonames-postal/adapter.d.ts.map +1 -1
  19. package/out/src/adapters/geonames-postal/adapter.js +3 -3
  20. package/out/src/adapters/geonames-postal/adapter.js.map +1 -1
  21. package/out/src/adapters/gnaf/adapter.d.ts +1 -1
  22. package/out/src/adapters/gnaf/adapter.d.ts.map +1 -1
  23. package/out/src/adapters/gnaf/adapter.js +2 -2
  24. package/out/src/adapters/gnaf/adapter.js.map +1 -1
  25. package/out/src/adapters/gnaf/assemble.js +1 -1
  26. package/out/src/adapters/gnaf/assemble.js.map +1 -1
  27. package/out/src/adapters/index.d.ts +1 -1
  28. package/out/src/adapters/index.d.ts.map +1 -1
  29. package/out/src/adapters/index.js +1 -1
  30. package/out/src/adapters/index.js.map +1 -1
  31. package/out/src/adapters/openaddresses/adapter.d.ts +1 -1
  32. package/out/src/adapters/openaddresses/adapter.d.ts.map +1 -1
  33. package/out/src/adapters/openaddresses/adapter.js +3 -3
  34. package/out/src/adapters/openaddresses/adapter.js.map +1 -1
  35. package/out/src/adapters/overture/adapter.d.ts +1 -1
  36. package/out/src/adapters/overture/adapter.d.ts.map +1 -1
  37. package/out/src/adapters/overture/adapter.js +2 -2
  38. package/out/src/adapters/overture/adapter.js.map +1 -1
  39. package/out/src/adapters/state-hi-schools/adapter.d.ts +1 -1
  40. package/out/src/adapters/state-hi-schools/adapter.d.ts.map +1 -1
  41. package/out/src/adapters/state-hi-schools/adapter.js +7 -6
  42. package/out/src/adapters/state-hi-schools/adapter.js.map +1 -1
  43. package/out/src/adapters/state-ia-contractors/adapter.d.ts +1 -1
  44. package/out/src/adapters/state-ia-contractors/adapter.d.ts.map +1 -1
  45. package/out/src/adapters/state-ia-contractors/adapter.js +12 -7
  46. package/out/src/adapters/state-ia-contractors/adapter.js.map +1 -1
  47. package/out/src/adapters/state-ny-notaries/adapter.d.ts +1 -1
  48. package/out/src/adapters/state-ny-notaries/adapter.d.ts.map +1 -1
  49. package/out/src/adapters/state-ny-notaries/adapter.js +12 -18
  50. package/out/src/adapters/state-ny-notaries/adapter.js.map +1 -1
  51. package/out/src/adapters/state-tx-notaries/adapter.d.ts +1 -1
  52. package/out/src/adapters/state-tx-notaries/adapter.d.ts.map +1 -1
  53. package/out/src/adapters/state-tx-notaries/adapter.js +12 -7
  54. package/out/src/adapters/state-tx-notaries/adapter.js.map +1 -1
  55. package/out/src/adapters/synth-po-box/adapter.d.ts +3 -3
  56. package/out/src/adapters/synth-po-box/adapter.d.ts.map +1 -1
  57. package/out/src/adapters/synth-po-box/adapter.js +3 -3
  58. package/out/src/adapters/synth-po-box/adapter.js.map +1 -1
  59. package/out/src/adapters/tiger/adapter.d.ts +1 -1
  60. package/out/src/adapters/tiger/adapter.d.ts.map +1 -1
  61. package/out/src/adapters/tiger/adapter.js +2 -2
  62. package/out/src/adapters/tiger/adapter.js.map +1 -1
  63. package/out/src/adapters/usgov-hrsa-fqhc/adapter.d.ts +1 -1
  64. package/out/src/adapters/usgov-hrsa-fqhc/adapter.d.ts.map +1 -1
  65. package/out/src/adapters/usgov-hrsa-fqhc/adapter.js +7 -6
  66. package/out/src/adapters/usgov-hrsa-fqhc/adapter.js.map +1 -1
  67. package/out/src/adapters/usgov-imls-pls/adapter.d.ts +1 -1
  68. package/out/src/adapters/usgov-imls-pls/adapter.d.ts.map +1 -1
  69. package/out/src/adapters/usgov-imls-pls/adapter.js +11 -7
  70. package/out/src/adapters/usgov-imls-pls/adapter.js.map +1 -1
  71. package/out/src/adapters/usgov-irs-bmf/adapter.d.ts +1 -1
  72. package/out/src/adapters/usgov-irs-bmf/adapter.d.ts.map +1 -1
  73. package/out/src/adapters/usgov-irs-bmf/adapter.js +6 -5
  74. package/out/src/adapters/usgov-irs-bmf/adapter.js.map +1 -1
  75. package/out/src/adapters/usgov-nad/adapter.d.ts +1 -1
  76. package/out/src/adapters/usgov-nad/adapter.d.ts.map +1 -1
  77. package/out/src/adapters/usgov-nad/adapter.js +8 -8
  78. package/out/src/adapters/usgov-nad/adapter.js.map +1 -1
  79. package/out/src/adapters/usgov-nppes/adapter.d.ts +1 -1
  80. package/out/src/adapters/usgov-nppes/adapter.d.ts.map +1 -1
  81. package/out/src/adapters/usgov-nppes/adapter.js +10 -10
  82. package/out/src/adapters/usgov-nppes/adapter.js.map +1 -1
  83. package/out/src/adapters/usgov-samhsa-treatment-locator/adapter.d.ts +1 -1
  84. package/out/src/adapters/usgov-samhsa-treatment-locator/adapter.d.ts.map +1 -1
  85. package/out/src/adapters/usgov-samhsa-treatment-locator/adapter.js +7 -6
  86. package/out/src/adapters/usgov-samhsa-treatment-locator/adapter.js.map +1 -1
  87. package/out/src/{adapter.d.ts → adapters/utils/index.d.ts} +8 -2
  88. package/out/src/adapters/utils/index.d.ts.map +1 -0
  89. package/out/src/{adapter.js → adapters/utils/index.js} +11 -3
  90. package/out/src/adapters/utils/index.js.map +1 -0
  91. package/out/src/adapters/wof-admin-jp/adapter.d.ts +1 -1
  92. package/out/src/adapters/wof-admin-jp/adapter.d.ts.map +1 -1
  93. package/out/src/adapters/wof-admin-jp/adapter.js +5 -5
  94. package/out/src/adapters/wof-admin-jp/adapter.js.map +1 -1
  95. package/out/src/adapters/wof-admin-json/adapter.d.ts +4 -15
  96. package/out/src/adapters/wof-admin-json/adapter.d.ts.map +1 -1
  97. package/out/src/adapters/wof-admin-json/adapter.js +11 -35
  98. package/out/src/adapters/wof-admin-json/adapter.js.map +1 -1
  99. package/out/src/adapters/wof-json-rows.d.ts +32 -0
  100. package/out/src/adapters/wof-json-rows.d.ts.map +1 -0
  101. package/out/src/adapters/wof-json-rows.js +45 -0
  102. package/out/src/adapters/wof-json-rows.js.map +1 -0
  103. package/out/src/adapters/wof-postalcode-json/adapter.d.ts +4 -9
  104. package/out/src/adapters/wof-postalcode-json/adapter.d.ts.map +1 -1
  105. package/out/src/adapters/wof-postalcode-json/adapter.js +12 -37
  106. package/out/src/adapters/wof-postalcode-json/adapter.js.map +1 -1
  107. package/out/src/build.d.ts +4 -4
  108. package/out/src/build.d.ts.map +1 -1
  109. package/out/src/build.js +7 -7
  110. package/out/src/build.js.map +1 -1
  111. package/out/src/index.d.ts +3 -17
  112. package/out/src/index.d.ts.map +1 -1
  113. package/out/src/index.js +3 -17
  114. package/out/src/index.js.map +1 -1
  115. package/out/src/name-prone-us-suffixes.d.ts +12 -0
  116. package/out/src/name-prone-us-suffixes.d.ts.map +1 -0
  117. package/out/src/name-prone-us-suffixes.js +12 -0
  118. package/out/src/name-prone-us-suffixes.js.map +1 -0
  119. package/out/src/parquet-wrapper/reader.d.ts.map +1 -1
  120. package/out/src/parquet-wrapper/reader.js +5 -0
  121. package/out/src/parquet-wrapper/reader.js.map +1 -1
  122. package/out/src/runner.d.ts +2 -2
  123. package/out/src/runner.d.ts.map +1 -1
  124. package/out/src/runner.js +1 -1
  125. package/out/src/runner.js.map +1 -1
  126. package/out/src/shard-recipes/anchor-absorption.d.ts.map +1 -1
  127. package/out/src/shard-recipes/anchor-absorption.js +4 -5
  128. package/out/src/shard-recipes/anchor-absorption.js.map +1 -1
  129. package/out/src/shard-recipes/bare-country.d.ts +25 -0
  130. package/out/src/shard-recipes/bare-country.d.ts.map +1 -0
  131. package/out/src/shard-recipes/bare-country.js +87 -0
  132. package/out/src/shard-recipes/bare-country.js.map +1 -0
  133. package/out/src/shard-recipes/boundary-stress.d.ts.map +1 -1
  134. package/out/src/shard-recipes/boundary-stress.js +2 -2
  135. package/out/src/shard-recipes/boundary-stress.js.map +1 -1
  136. package/out/src/shard-recipes/country-balanced.d.ts.map +1 -1
  137. package/out/src/shard-recipes/country-balanced.js +14 -21
  138. package/out/src/shard-recipes/country-balanced.js.map +1 -1
  139. package/out/src/shard-recipes/cz-pcfirst-preposition.d.ts.map +1 -1
  140. package/out/src/shard-recipes/cz-pcfirst-preposition.js +28 -10
  141. package/out/src/shard-recipes/cz-pcfirst-preposition.js.map +1 -1
  142. package/out/src/shard-recipes/fr-admin-split.d.ts.map +1 -1
  143. package/out/src/shard-recipes/fr-admin-split.js +4 -3
  144. package/out/src/shard-recipes/fr-admin-split.js.map +1 -1
  145. package/out/src/shard-recipes/fr-bare-street.d.ts.map +1 -1
  146. package/out/src/shard-recipes/fr-bare-street.js +72 -11
  147. package/out/src/shard-recipes/fr-bare-street.js.map +1 -1
  148. package/out/src/shard-recipes/fr-lieudit.d.ts.map +1 -1
  149. package/out/src/shard-recipes/fr-lieudit.js +4 -3
  150. package/out/src/shard-recipes/fr-lieudit.js.map +1 -1
  151. package/out/src/shard-recipes/fr-order.d.ts.map +1 -1
  152. package/out/src/shard-recipes/fr-order.js +11 -20
  153. package/out/src/shard-recipes/fr-order.js.map +1 -1
  154. package/out/src/shard-recipes/german.d.ts.map +1 -1
  155. package/out/src/shard-recipes/german.js +8 -14
  156. package/out/src/shard-recipes/german.js.map +1 -1
  157. package/out/src/shard-recipes/house-venue.d.ts.map +1 -1
  158. package/out/src/shard-recipes/house-venue.js +1 -1
  159. package/out/src/shard-recipes/house-venue.js.map +1 -1
  160. package/out/src/shard-recipes/index.d.ts.map +1 -1
  161. package/out/src/shard-recipes/index.js +8 -1
  162. package/out/src/shard-recipes/index.js.map +1 -1
  163. package/out/src/shard-recipes/intersection.d.ts.map +1 -1
  164. package/out/src/shard-recipes/intersection.js +7 -13
  165. package/out/src/shard-recipes/intersection.js.map +1 -1
  166. package/out/src/shard-recipes/locale.d.ts +5 -5
  167. package/out/src/shard-recipes/locale.d.ts.map +1 -1
  168. package/out/src/shard-recipes/locale.js +13 -20
  169. package/out/src/shard-recipes/locale.js.map +1 -1
  170. package/out/src/shard-recipes/no-street.d.ts.map +1 -1
  171. package/out/src/shard-recipes/no-street.js +1 -1
  172. package/out/src/shard-recipes/no-street.js.map +1 -1
  173. package/out/src/shard-recipes/po-box-cedex.d.ts.map +1 -1
  174. package/out/src/shard-recipes/po-box-cedex.js +60 -43
  175. package/out/src/shard-recipes/po-box-cedex.js.map +1 -1
  176. package/out/src/shard-recipes/po-box.d.ts.map +1 -1
  177. package/out/src/shard-recipes/po-box.js +1 -1
  178. package/out/src/shard-recipes/po-box.js.map +1 -1
  179. package/out/src/shard-recipes/reviewed-postcode-tail.d.ts +47 -0
  180. package/out/src/shard-recipes/reviewed-postcode-tail.d.ts.map +1 -0
  181. package/out/src/shard-recipes/reviewed-postcode-tail.js +125 -0
  182. package/out/src/shard-recipes/reviewed-postcode-tail.js.map +1 -0
  183. package/out/src/shard-recipes/scaffold.d.ts +51 -23
  184. package/out/src/shard-recipes/scaffold.d.ts.map +1 -1
  185. package/out/src/shard-recipes/scaffold.js +59 -23
  186. package/out/src/shard-recipes/scaffold.js.map +1 -1
  187. package/out/src/shard-recipes/street-affix.d.ts +54 -0
  188. package/out/src/shard-recipes/street-affix.d.ts.map +1 -1
  189. package/out/src/shard-recipes/street-affix.js +203 -35
  190. package/out/src/shard-recipes/street-affix.js.map +1 -1
  191. package/out/src/shard-recipes/street-bare.d.ts.map +1 -1
  192. package/out/src/shard-recipes/street-bare.js +3 -3
  193. package/out/src/shard-recipes/street-bare.js.map +1 -1
  194. package/out/src/shard-recipes/street.d.ts.map +1 -1
  195. package/out/src/shard-recipes/street.js +2 -2
  196. package/out/src/shard-recipes/street.js.map +1 -1
  197. package/out/src/shard-recipes/sub-venue-sources.d.ts +3 -6
  198. package/out/src/shard-recipes/sub-venue-sources.d.ts.map +1 -1
  199. package/out/src/shard-recipes/sub-venue-sources.js +4 -9
  200. package/out/src/shard-recipes/sub-venue-sources.js.map +1 -1
  201. package/out/src/shard-recipes/sub-venue.d.ts +2 -2
  202. package/out/src/shard-recipes/sub-venue.d.ts.map +1 -1
  203. package/out/src/shard-recipes/sub-venue.js +7 -6
  204. package/out/src/shard-recipes/sub-venue.js.map +1 -1
  205. package/out/src/shard-recipes/trailing-region.d.ts +74 -0
  206. package/out/src/shard-recipes/trailing-region.d.ts.map +1 -0
  207. package/out/src/shard-recipes/trailing-region.js +157 -0
  208. package/out/src/shard-recipes/trailing-region.js.map +1 -0
  209. package/out/src/shard-recipes/unit.d.ts.map +1 -1
  210. package/out/src/shard-recipes/unit.js +6 -12
  211. package/out/src/shard-recipes/unit.js.map +1 -1
  212. package/out/src/{synthesize-anchor-absorption.d.ts → synthesizers/anchor-absorption.d.ts} +1 -1
  213. package/out/src/synthesizers/anchor-absorption.d.ts.map +1 -0
  214. package/out/src/{synthesize-anchor-absorption.js → synthesizers/anchor-absorption.js} +1 -1
  215. package/out/src/synthesizers/anchor-absorption.js.map +1 -0
  216. package/out/src/{synthesize-boundary-stress.d.ts → synthesizers/boundary-stress.d.ts} +3 -3
  217. package/out/src/synthesizers/boundary-stress.d.ts.map +1 -0
  218. package/out/src/{synthesize-boundary-stress.js → synthesizers/boundary-stress.js} +2 -2
  219. package/out/src/synthesizers/boundary-stress.js.map +1 -0
  220. package/out/src/{synthesize-german.d.ts → synthesizers/german.d.ts} +2 -2
  221. package/out/src/synthesizers/german.d.ts.map +1 -0
  222. package/out/src/{synthesize-german.js → synthesizers/german.js} +2 -2
  223. package/out/src/synthesizers/german.js.map +1 -0
  224. package/out/src/{synthesize-house-venue.d.ts → synthesizers/house-venue.d.ts} +4 -4
  225. package/out/src/synthesizers/house-venue.d.ts.map +1 -0
  226. package/out/src/{synthesize-house-venue.js → synthesizers/house-venue.js} +20 -6
  227. package/out/src/synthesizers/house-venue.js.map +1 -0
  228. package/out/src/{synthesize-intersection.d.ts → synthesizers/intersection.d.ts} +2 -2
  229. package/out/src/synthesizers/intersection.d.ts.map +1 -0
  230. package/out/src/{synthesize-intersection.js → synthesizers/intersection.js} +1 -1
  231. package/out/src/synthesizers/intersection.js.map +1 -0
  232. package/out/src/{synthesize-no-street.d.ts → synthesizers/no-street.d.ts} +3 -3
  233. package/out/src/synthesizers/no-street.d.ts.map +1 -0
  234. package/out/src/{synthesize-no-street.js → synthesizers/no-street.js} +2 -2
  235. package/out/src/synthesizers/no-street.js.map +1 -0
  236. package/out/src/{synthesize-po-box.d.ts → synthesizers/po-box.d.ts} +2 -2
  237. package/out/src/synthesizers/po-box.d.ts.map +1 -0
  238. package/out/src/{synthesize-po-box.js → synthesizers/po-box.js} +1 -1
  239. package/out/src/synthesizers/po-box.js.map +1 -0
  240. package/out/src/{synthesize-street.d.ts → synthesizers/street.d.ts} +2 -2
  241. package/out/src/synthesizers/street.d.ts.map +1 -0
  242. package/out/src/{synthesize-street.js → synthesizers/street.js} +4 -3
  243. package/out/src/synthesizers/street.js.map +1 -0
  244. package/out/src/{synthesize.d.ts → synthesizers/utils.d.ts} +3 -3
  245. package/out/src/synthesizers/utils.d.ts.map +1 -0
  246. package/out/src/{synthesize.js → synthesizers/utils.js} +5 -4
  247. package/out/src/synthesizers/utils.js.map +1 -0
  248. package/out/src/tools/align-shard.d.ts.map +1 -1
  249. package/out/src/tools/align-shard.js +2 -2
  250. package/out/src/tools/align-shard.js.map +1 -1
  251. package/out/src/tools/fetch/ban.d.ts.map +1 -1
  252. package/out/src/tools/fetch/ban.js +2 -18
  253. package/out/src/tools/fetch/ban.js.map +1 -1
  254. package/out/src/tools/fetch/download.d.ts +12 -3
  255. package/out/src/tools/fetch/download.d.ts.map +1 -1
  256. package/out/src/tools/fetch/download.js +20 -4
  257. package/out/src/tools/fetch/download.js.map +1 -1
  258. package/out/src/tools/fetch/geonames-dump.d.ts +87 -0
  259. package/out/src/tools/fetch/geonames-dump.d.ts.map +1 -0
  260. package/out/src/tools/fetch/geonames-dump.js +178 -0
  261. package/out/src/tools/fetch/geonames-dump.js.map +1 -0
  262. package/out/src/tools/fetch/geonames-postal.d.ts +76 -0
  263. package/out/src/tools/fetch/geonames-postal.d.ts.map +1 -0
  264. package/out/src/tools/fetch/geonames-postal.js +125 -0
  265. package/out/src/tools/fetch/geonames-postal.js.map +1 -0
  266. package/out/src/tools/fetch/imls-pls.d.ts.map +1 -1
  267. package/out/src/tools/fetch/imls-pls.js +5 -17
  268. package/out/src/tools/fetch/imls-pls.js.map +1 -1
  269. package/out/src/tools/fetch/index.d.ts +11 -0
  270. package/out/src/tools/fetch/index.d.ts.map +1 -1
  271. package/out/src/tools/fetch/index.js +11 -0
  272. package/out/src/tools/fetch/index.js.map +1 -1
  273. package/out/src/tools/fetch/nad.d.ts.map +1 -1
  274. package/out/src/tools/fetch/nad.js +20 -11
  275. package/out/src/tools/fetch/nad.js.map +1 -1
  276. package/out/src/tools/fetch/nppes.d.ts.map +1 -1
  277. package/out/src/tools/fetch/nppes.js +17 -22
  278. package/out/src/tools/fetch/nppes.js.map +1 -1
  279. package/out/src/tools/fetch/openaddresses.d.ts.map +1 -1
  280. package/out/src/tools/fetch/openaddresses.js +18 -17
  281. package/out/src/tools/fetch/openaddresses.js.map +1 -1
  282. package/out/src/tools/fetch/ourairports.d.ts.map +1 -1
  283. package/out/src/tools/fetch/ourairports.js +7 -2
  284. package/out/src/tools/fetch/ourairports.js.map +1 -1
  285. package/out/src/tools/fetch/ppd.d.ts +0 -4
  286. package/out/src/tools/fetch/ppd.d.ts.map +1 -1
  287. package/out/src/tools/fetch/ppd.js +1 -1
  288. package/out/src/tools/fetch/ppd.js.map +1 -1
  289. package/out/src/tools/fetch/state-hi-schools.d.ts.map +1 -1
  290. package/out/src/tools/fetch/state-hi-schools.js +3 -19
  291. package/out/src/tools/fetch/state-hi-schools.js.map +1 -1
  292. package/out/src/tools/fetch/state-sources.d.ts +4 -0
  293. package/out/src/tools/fetch/state-sources.d.ts.map +1 -1
  294. package/out/src/tools/fetch/state-sources.js +1 -5
  295. package/out/src/tools/fetch/state-sources.js.map +1 -1
  296. package/out/src/tools/fetch/tiger-full.d.ts.map +1 -1
  297. package/out/src/tools/fetch/tiger-full.js +15 -21
  298. package/out/src/tools/fetch/tiger-full.js.map +1 -1
  299. package/out/src/tools/golden-expand.d.ts.map +1 -1
  300. package/out/src/tools/golden-expand.js +34 -25
  301. package/out/src/tools/golden-expand.js.map +1 -1
  302. package/out/src/tools/golden-relabel-street.d.ts.map +1 -1
  303. package/out/src/tools/golden-relabel-street.js +4 -77
  304. package/out/src/tools/golden-relabel-street.js.map +1 -1
  305. package/out/src/tools/index.d.ts +2 -2
  306. package/out/src/tools/index.d.ts.map +1 -1
  307. package/out/src/tools/index.js +2 -2
  308. package/out/src/tools/index.js.map +1 -1
  309. package/out/src/tools/ingest-csv.d.ts.map +1 -1
  310. package/out/src/tools/ingest-csv.js +0 -11
  311. package/out/src/tools/ingest-csv.js.map +1 -1
  312. package/out/src/tools/overlay-manifest.d.ts +4 -0
  313. package/out/src/tools/overlay-manifest.d.ts.map +1 -1
  314. package/out/src/tools/overlay-manifest.js +16 -6
  315. package/out/src/tools/overlay-manifest.js.map +1 -1
  316. package/out/src/tools/postcode-triples.d.ts +175 -0
  317. package/out/src/tools/postcode-triples.d.ts.map +1 -0
  318. package/out/src/tools/postcode-triples.js +304 -0
  319. package/out/src/tools/postcode-triples.js.map +1 -0
  320. package/out/src/tools/shard-kryptonite.d.ts.map +1 -1
  321. package/out/src/tools/shard-kryptonite.js +1 -3
  322. package/out/src/tools/shard-kryptonite.js.map +1 -1
  323. package/out/src/tools/shard-translit.d.ts.map +1 -1
  324. package/out/src/tools/shard-translit.js +4 -27
  325. package/out/src/tools/shard-translit.js.map +1 -1
  326. package/out/src/tools/sub-venue/harvest.d.ts +100 -0
  327. package/out/src/tools/sub-venue/harvest.d.ts.map +1 -0
  328. package/out/src/tools/sub-venue/harvest.js +168 -0
  329. package/out/src/tools/sub-venue/harvest.js.map +1 -0
  330. package/out/src/tools/sub-venue/head-nouns.d.ts +50 -0
  331. package/out/src/tools/sub-venue/head-nouns.d.ts.map +1 -0
  332. package/out/src/tools/sub-venue/head-nouns.js +210 -0
  333. package/out/src/tools/sub-venue/head-nouns.js.map +1 -0
  334. package/out/src/tools/sub-venue/surfaces.d.ts +45 -0
  335. package/out/src/tools/sub-venue/surfaces.d.ts.map +1 -0
  336. package/out/src/tools/sub-venue/surfaces.js +77 -0
  337. package/out/src/tools/sub-venue/surfaces.js.map +1 -0
  338. package/out/src/tools/sub-venue/table.d.ts +229 -0
  339. package/out/src/tools/sub-venue/table.d.ts.map +1 -0
  340. package/out/src/tools/sub-venue/table.js +108 -0
  341. package/out/src/tools/sub-venue/table.js.map +1 -0
  342. package/out/src/tools/sub-venue/wikidata.d.ts +26 -0
  343. package/out/src/tools/sub-venue/wikidata.d.ts.map +1 -0
  344. package/out/src/tools/sub-venue/wikidata.js +62 -0
  345. package/out/src/tools/sub-venue/wikidata.js.map +1 -0
  346. package/out/src/tools/sub-venue-lexicon.d.ts +27 -378
  347. package/out/src/tools/sub-venue-lexicon.d.ts.map +1 -1
  348. package/out/src/tools/sub-venue-lexicon.js +30 -565
  349. package/out/src/tools/sub-venue-lexicon.js.map +1 -1
  350. package/out/src/{align.d.ts → utils/align.d.ts} +1 -1
  351. package/out/src/utils/align.d.ts.map +1 -0
  352. package/out/src/utils/align.js.map +1 -0
  353. package/out/src/utils/golden.d.ts.map +1 -0
  354. package/out/src/{golden.js → utils/golden.js} +2 -2
  355. package/out/src/utils/golden.js.map +1 -0
  356. package/out/src/utils/index.d.ts +14 -0
  357. package/out/src/utils/index.d.ts.map +1 -0
  358. package/out/src/utils/index.js +14 -0
  359. package/out/src/utils/index.js.map +1 -0
  360. package/out/src/utils/license.d.ts.map +1 -0
  361. package/out/src/{license.js → utils/license.js} +1 -1
  362. package/out/src/utils/license.js.map +1 -0
  363. package/out/src/{parquet.d.ts → utils/parquet.d.ts} +24 -5
  364. package/out/src/utils/parquet.d.ts.map +1 -0
  365. package/out/src/{parquet.js → utils/parquet.js} +6 -3
  366. package/out/src/utils/parquet.js.map +1 -0
  367. package/out/src/{split.d.ts → utils/split.d.ts} +1 -1
  368. package/out/src/utils/split.d.ts.map +1 -0
  369. package/out/src/{split.js → utils/split.js} +2 -2
  370. package/out/src/utils/split.js.map +1 -0
  371. package/out/src/utils/tokenize.d.ts.map +1 -0
  372. package/out/src/utils/tokenize.js.map +1 -0
  373. package/out/src/utils/wof-json.d.ts.map +1 -0
  374. package/out/src/utils/wof-json.js.map +1 -0
  375. package/package.json +287 -21
  376. package/src/adapters/ban/adapter.ts +7 -5
  377. package/src/adapters/fcc-bdc/adapter.ts +5 -4
  378. package/src/adapters/geonames/adapter.ts +3 -3
  379. package/src/adapters/geonames-postal/adapter.ts +4 -4
  380. package/src/adapters/gnaf/adapter.ts +3 -3
  381. package/src/adapters/gnaf/assemble.ts +1 -1
  382. package/src/adapters/index.ts +3 -2
  383. package/src/adapters/openaddresses/adapter.ts +4 -4
  384. package/src/adapters/overture/adapter.ts +3 -3
  385. package/src/adapters/state-hi-schools/adapter.ts +8 -7
  386. package/src/adapters/state-ia-contractors/adapter.ts +13 -8
  387. package/src/adapters/state-ny-notaries/adapter.ts +13 -32
  388. package/src/adapters/state-tx-notaries/adapter.ts +13 -8
  389. package/src/adapters/synth-po-box/adapter.ts +4 -4
  390. package/src/adapters/tiger/adapter.ts +5 -3
  391. package/src/adapters/usgov-hrsa-fqhc/adapter.ts +8 -7
  392. package/src/adapters/usgov-imls-pls/adapter.ts +12 -8
  393. package/src/adapters/usgov-irs-bmf/adapter.ts +7 -6
  394. package/src/adapters/usgov-nad/adapter.ts +9 -9
  395. package/src/adapters/usgov-nppes/adapter.ts +13 -12
  396. package/src/adapters/usgov-samhsa-treatment-locator/adapter.ts +8 -7
  397. package/src/{adapter.ts → adapters/utils/index.ts} +15 -3
  398. package/src/adapters/wof-admin-jp/adapter.ts +9 -12
  399. package/src/adapters/wof-admin-json/adapter.ts +15 -54
  400. package/src/adapters/wof-json-rows.ts +79 -0
  401. package/src/adapters/wof-postalcode-json/adapter.ts +16 -50
  402. package/src/build.ts +8 -8
  403. package/src/index.ts +3 -17
  404. package/src/name-prone-us-suffixes.ts +12 -0
  405. package/src/parquet-wrapper/reader.ts +9 -0
  406. package/src/runner.ts +2 -2
  407. package/src/shard-recipes/anchor-absorption.ts +5 -5
  408. package/src/shard-recipes/bare-country.ts +95 -0
  409. package/src/shard-recipes/boundary-stress.ts +3 -2
  410. package/src/shard-recipes/country-balanced.ts +16 -27
  411. package/src/shard-recipes/cz-pcfirst-preposition.ts +29 -10
  412. package/src/shard-recipes/fr-admin-split.ts +6 -4
  413. package/src/shard-recipes/fr-bare-street.ts +85 -10
  414. package/src/shard-recipes/fr-lieudit.ts +6 -4
  415. package/src/shard-recipes/fr-order.ts +13 -26
  416. package/src/shard-recipes/german.ts +9 -18
  417. package/src/shard-recipes/house-venue.ts +2 -1
  418. package/src/shard-recipes/index.ts +8 -1
  419. package/src/shard-recipes/intersection.ts +9 -17
  420. package/src/shard-recipes/locale.ts +16 -24
  421. package/src/shard-recipes/no-street.ts +2 -1
  422. package/src/shard-recipes/po-box-cedex.ts +76 -58
  423. package/src/shard-recipes/po-box.ts +2 -1
  424. package/src/shard-recipes/reviewed-postcode-tail.ts +189 -0
  425. package/src/shard-recipes/scaffold.ts +99 -24
  426. package/src/shard-recipes/street-affix.ts +284 -45
  427. package/src/shard-recipes/street-bare.ts +4 -3
  428. package/src/shard-recipes/street.ts +3 -2
  429. package/src/shard-recipes/sub-venue-sources.ts +13 -23
  430. package/src/shard-recipes/sub-venue.ts +11 -9
  431. package/src/shard-recipes/trailing-region.ts +183 -0
  432. package/src/shard-recipes/unit.ts +8 -17
  433. package/src/{synthesize-boundary-stress.ts → synthesizers/boundary-stress.ts} +2 -2
  434. package/src/{synthesize-german.ts → synthesizers/german.ts} +3 -2
  435. package/src/{synthesize-house-venue.ts → synthesizers/house-venue.ts} +20 -6
  436. package/src/{synthesize-intersection.ts → synthesizers/intersection.ts} +1 -1
  437. package/src/{synthesize-no-street.ts → synthesizers/no-street.ts} +2 -2
  438. package/src/{synthesize-po-box.ts → synthesizers/po-box.ts} +1 -1
  439. package/src/{synthesize-street.ts → synthesizers/street.ts} +5 -3
  440. package/src/{synthesize.ts → synthesizers/utils.ts} +6 -4
  441. package/src/tools/align-shard.ts +3 -2
  442. package/src/tools/fetch/ban.ts +2 -22
  443. package/src/tools/fetch/download.ts +22 -4
  444. package/src/tools/fetch/geonames-dump.ts +267 -0
  445. package/src/tools/fetch/geonames-postal.ts +180 -0
  446. package/src/tools/fetch/imls-pls.ts +6 -20
  447. package/src/tools/fetch/index.ts +11 -0
  448. package/src/tools/fetch/nad.ts +21 -10
  449. package/src/tools/fetch/nppes.ts +17 -23
  450. package/src/tools/fetch/openaddresses.ts +18 -22
  451. package/src/tools/fetch/ourairports.ts +7 -2
  452. package/src/tools/fetch/ppd.ts +1 -1
  453. package/src/tools/fetch/state-hi-schools.ts +3 -23
  454. package/src/tools/fetch/state-sources.ts +1 -1
  455. package/src/tools/fetch/tiger-full.ts +17 -24
  456. package/src/tools/golden-expand.ts +44 -33
  457. package/src/tools/golden-relabel-street.ts +5 -68
  458. package/src/tools/index.ts +2 -2
  459. package/src/tools/ingest-csv.ts +0 -13
  460. package/src/tools/overlay-manifest.ts +20 -8
  461. package/src/tools/postcode-triples.ts +375 -0
  462. package/src/tools/shard-kryptonite.ts +4 -5
  463. package/src/tools/shard-translit.ts +16 -35
  464. package/src/tools/sub-venue/harvest.ts +235 -0
  465. package/src/tools/sub-venue/head-nouns.ts +242 -0
  466. package/src/tools/sub-venue/surfaces.ts +95 -0
  467. package/src/tools/sub-venue/table.ts +281 -0
  468. package/src/tools/sub-venue/wikidata.ts +85 -0
  469. package/src/tools/sub-venue-lexicon.ts +67 -886
  470. package/src/{align.ts → utils/align.ts} +2 -1
  471. package/src/{golden.ts → utils/golden.ts} +2 -3
  472. package/src/utils/index.ts +14 -0
  473. package/src/{license.ts → utils/license.ts} +1 -1
  474. package/src/{parquet.ts → utils/parquet.ts} +22 -9
  475. package/src/{split.ts → utils/split.ts} +3 -3
  476. package/out/src/adapter.d.ts.map +0 -1
  477. package/out/src/adapter.js.map +0 -1
  478. package/out/src/align.d.ts.map +0 -1
  479. package/out/src/align.js.map +0 -1
  480. package/out/src/format.d.ts +0 -14
  481. package/out/src/format.d.ts.map +0 -1
  482. package/out/src/format.js +0 -14
  483. package/out/src/format.js.map +0 -1
  484. package/out/src/golden.d.ts.map +0 -1
  485. package/out/src/golden.js.map +0 -1
  486. package/out/src/license.d.ts.map +0 -1
  487. package/out/src/license.js.map +0 -1
  488. package/out/src/parquet.d.ts.map +0 -1
  489. package/out/src/parquet.js.map +0 -1
  490. package/out/src/split.d.ts.map +0 -1
  491. package/out/src/split.js.map +0 -1
  492. package/out/src/synthesize-anchor-absorption.d.ts.map +0 -1
  493. package/out/src/synthesize-anchor-absorption.js.map +0 -1
  494. package/out/src/synthesize-boundary-stress.d.ts.map +0 -1
  495. package/out/src/synthesize-boundary-stress.js.map +0 -1
  496. package/out/src/synthesize-german.d.ts.map +0 -1
  497. package/out/src/synthesize-german.js.map +0 -1
  498. package/out/src/synthesize-house-venue.d.ts.map +0 -1
  499. package/out/src/synthesize-house-venue.js.map +0 -1
  500. package/out/src/synthesize-intersection.d.ts.map +0 -1
  501. package/out/src/synthesize-intersection.js.map +0 -1
  502. package/out/src/synthesize-no-street.d.ts.map +0 -1
  503. package/out/src/synthesize-no-street.js.map +0 -1
  504. package/out/src/synthesize-po-box.d.ts.map +0 -1
  505. package/out/src/synthesize-po-box.js.map +0 -1
  506. package/out/src/synthesize-street.d.ts.map +0 -1
  507. package/out/src/synthesize-street.js.map +0 -1
  508. package/out/src/synthesize.d.ts.map +0 -1
  509. package/out/src/synthesize.js.map +0 -1
  510. package/out/src/tokenize.d.ts.map +0 -1
  511. package/out/src/tokenize.js.map +0 -1
  512. package/out/src/wof-json.d.ts.map +0 -1
  513. package/out/src/wof-json.js.map +0 -1
  514. package/src/format.ts +0 -14
  515. /package/out/src/{align.js → utils/align.js} +0 -0
  516. /package/out/src/{golden.d.ts → utils/golden.d.ts} +0 -0
  517. /package/out/src/{license.d.ts → utils/license.d.ts} +0 -0
  518. /package/out/src/{tokenize.d.ts → utils/tokenize.d.ts} +0 -0
  519. /package/out/src/{tokenize.js → utils/tokenize.js} +0 -0
  520. /package/out/src/{wof-json.d.ts → utils/wof-json.d.ts} +0 -0
  521. /package/out/src/{wof-json.js → utils/wof-json.js} +0 -0
  522. /package/src/{synthesize-anchor-absorption.ts → synthesizers/anchor-absorption.ts} +0 -0
  523. /package/src/{tokenize.ts → utils/tokenize.ts} +0 -0
  524. /package/src/{wof-json.ts → utils/wof-json.ts} +0 -0
@@ -24,20 +24,17 @@
24
24
  /* oxlint-disable sister-software/prefer-region-over-marks -- these markers label steps inside one
25
25
  procedure, not sections of declarations. A region there folds nothing a reader wants folded. */
26
26
 
27
- import { execFile } from "node:child_process"
28
27
  import { existsSync, mkdirSync, statSync } from "node:fs"
29
28
  import { rm } from "node:fs/promises"
30
- import { join } from "node:path"
31
- import { promisify } from "node:util"
29
+ import { basename, join } from "node:path"
32
30
 
31
+ import { APIClient, pluckResponseData } from "@mailwoman/core/api"
32
+ import { extractZipEntry, listZipEntries } from "@mailwoman/core/fs/zip"
33
33
  import { sha256File } from "@mailwoman/core/utils"
34
- import { TextSpliterator } from "spliterator"
35
34
 
36
35
  import type { BaseFetchOptions, FetchSummary } from "./download.ts"
37
36
  import { downloadToFile, readManifest, writeManifest } from "./download.ts"
38
37
 
39
- const execFileAsync = promisify(execFile)
40
-
41
38
  const INDEX_URL = "https://download.cms.gov/nppes/NPI_Files.html"
42
39
  const BASE_URL = "https://download.cms.gov/nppes"
43
40
  const SLUG = "usgov-nppes"
@@ -57,13 +54,14 @@ interface SourceManifest {
57
54
  * `NPPES_Data_Dissemination_<Month>_<Year>*.zip`; weekly files carry a `MMDDYY_MMDDYY` date range, which we exclude.
58
55
  */
59
56
  async function discoverLatestZip(): Promise<string | undefined> {
60
- const res = await fetch(INDEX_URL, {
61
- headers: { "Accept-Encoding": "gzip, br" },
62
- signal: AbortSignal.timeout(60_000),
57
+ // `responseType: "text"` the index is HTML, scraped by regex below.
58
+ const html = await new APIClient({
59
+ displayName: "nppes-index",
60
+ retry: true,
61
+ axios: { headers: { "Accept-Encoding": "gzip, br" } },
63
62
  })
64
-
65
- if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText} on ${INDEX_URL}`)
66
- const html = await res.text()
63
+ .fetch<string>({ url: INDEX_URL, responseType: "text", timeout: 60_000 })
64
+ .then(pluckResponseData)
67
65
 
68
66
  for (const match of html.matchAll(/NPPES_Data_Dissemination_[A-Za-z]+_\d{4}[^"]*\.zip/g)) {
69
67
  const name = match[0]
@@ -75,18 +73,13 @@ async function discoverLatestZip(): Promise<string | undefined> {
75
73
  }
76
74
 
77
75
  /**
78
- * Extract the main registry CSV name (npidata_pfile_*.csv) from a ZIP's `unzip -l` listing.
76
+ * The main registry CSV (npidata_pfile_*.csv), which the archive also carries alongside a header file and a per-month
77
+ * change file.
79
78
  */
80
79
  async function findNpidataCSV(zipPath: string): Promise<string | undefined> {
81
- const listing = await execFileAsync("unzip", ["-l", zipPath])
82
-
83
- for (const line of TextSpliterator.from(listing.stdout)) {
84
- const match = /npidata_pfile\S+\.csv/i.exec(line)
80
+ const entries = await listZipEntries(zipPath)
85
81
 
86
- if (match?.[0]) return match[0]
87
- }
88
-
89
- return undefined
82
+ return entries.find((entry) => /npidata_pfile\S+\.csv/i.test(entry.name))?.name
90
83
  }
91
84
 
92
85
  export async function fetchNPPES(options: FetchNPPESOptions, report?: (line: string) => void): Promise<FetchSummary> {
@@ -149,9 +142,10 @@ export async function fetchNPPES(options: FetchNPPESOptions, report?: (line: str
149
142
  }
150
143
 
151
144
  report?.(` Extracting: ${csvName}`)
152
- await execFileAsync("unzip", ["-o", "-j", zipDest, csvName, "-d", destDir])
153
145
 
154
- const csvDest = join(destDir, csvName)
146
+ const csvDest = join(destDir, basename(csvName))
147
+
148
+ await extractZipEntry(zipDest, csvName, csvDest)
155
149
  const csvSize = statSync(csvDest).size
156
150
  const csvSha = await sha256File(csvDest)
157
151
  report?.(` CSV size: ${(csvSize / 1024 / 1024).toFixed(1)} MB`)
@@ -62,7 +62,9 @@ import { pipeline } from "node:stream/promises"
62
62
  import { setTimeout as sleep } from "node:timers/promises"
63
63
  import { promisify } from "node:util"
64
64
 
65
+ import { APIClient, isSuccessStatus } from "@mailwoman/core/api"
65
66
  import { $private } from "@mailwoman/core/env"
67
+ import { ByteFormatter } from "@mailwoman/core/fs/utils"
66
68
  import { sha256File } from "@mailwoman/core/utils"
67
69
 
68
70
  import type { BaseFetchOptions, FetchSummary } from "./download.ts"
@@ -82,8 +84,6 @@ const HTTP_OK = 200
82
84
  */
83
85
  const MIN_PLAUSIBLE_SHARD_BYTES = 10_240
84
86
 
85
- const BYTES_PER_KIB = 1024
86
-
87
87
  const execFileAsync = promisify(execFile)
88
88
 
89
89
  const OA_BASE = "https://batch.openaddresses.io"
@@ -132,20 +132,6 @@ async function countLines(path: string): Promise<number> {
132
132
  return count
133
133
  }
134
134
 
135
- function humanBytes(bytes: number): string {
136
- const units = ["B", "KiB", "MiB", "GiB", "TiB"]
137
- let value = bytes
138
- let unit = 0
139
-
140
- while (value >= BYTES_PER_KIB && unit < units.length - 1) {
141
- value /= 1024
142
-
143
- unit++
144
- }
145
-
146
- return `${value.toFixed(unit === 0 ? 0 : 1)}${units[unit]}`
147
- }
148
-
149
135
  interface StreamDownloadOpts {
150
136
  headers?: Record<string, string>
151
137
  timeoutMs: number
@@ -263,18 +249,28 @@ The Canada collection (ca) is ~2 GiB compressed / ~7 GiB uncompressed
263
249
  if (collectionID === undefined) {
264
250
  report?.(`Unknown country code '${country}'. Fetching collection list to find ID...`)
265
251
 
266
- const res = await fetch(`${OA_BASE}/api/collections`, {
267
- headers: { Authorization: `Bearer ${token}`, "Accept-Encoding": "gzip, br" },
268
- signal: AbortSignal.timeout(30_000),
252
+ // The collections API only. The COLLECTION ARCHIVES stay on raw `fetch` — they stream multi-gigabyte
253
+ // bodies straight to disk, where response caching is nonsense and axios would buffer them in memory.
254
+ const res = await new APIClient({
255
+ displayName: "openaddresses-api",
256
+ retry: true,
257
+ axios: { headers: { Authorization: `Bearer ${token}`, "Accept-Encoding": "gzip, br" } },
269
258
  })
259
+ // `validateStatus` keeps a non-2xx as a RESPONSE rather than a throw: the caller reports the status and
260
+ // returns `fail(country)`, a graceful path this must not turn into an exception.
261
+ .fetch<OaCollection[]>({
262
+ url: `${OA_BASE}/api/collections`,
263
+ timeout: 30_000,
264
+ validateStatus: () => true,
265
+ })
270
266
 
271
- if (!res.ok) {
267
+ if (!isSuccessStatus(res.status)) {
272
268
  report?.(`ERROR: GET /api/collections returned HTTP ${res.status}.`)
273
269
 
274
270
  return fail(country)
275
271
  }
276
272
 
277
- const collections = (await res.json()) as OaCollection[]
273
+ const collections = res.data
278
274
  const match = collections.find((item) => item.name === country)
279
275
 
280
276
  if (match?.id === undefined) {
@@ -395,7 +391,7 @@ URL tried: ${OA_BASE}/api/collections/${collectionID}/download
395
391
 
396
392
  await writeManifest(manifestPath, manifest)
397
393
 
398
- report?.(` ✓ ${humanBytes(size)} rows=${rowCount} sha256=${sha}`)
394
+ report?.(` ✓ ${ByteFormatter.formatIEC(size)} rows=${rowCount} sha256=${sha}`)
399
395
  report?.(` MANIFEST written to ${manifestPath}`)
400
396
  report?.(`=== done`)
401
397
  report?.(`Feed to the adapter:`)
@@ -39,6 +39,7 @@
39
39
  import { mkdirSync } from "node:fs"
40
40
  import { join } from "node:path"
41
41
 
42
+ import { APIClient } from "@mailwoman/core/api"
42
43
  import { sha256File } from "@mailwoman/core/utils"
43
44
 
44
45
  import type { BaseFetchOptions, FetchSummary } from "./download.ts"
@@ -92,9 +93,13 @@ interface OurAirportsManifest {
92
93
  */
93
94
  async function readLastModified(url: string): Promise<string | null> {
94
95
  try {
95
- const res = await fetch(url, { method: "HEAD", signal: AbortSignal.timeout(30_000) })
96
+ const res = await new APIClient({ displayName: "ourairports", retry: true }).fetch({
97
+ url,
98
+ method: "head",
99
+ timeout: 30_000,
100
+ })
96
101
 
97
- return res.ok ? res.headers.get("last-modified") : null
102
+ return (res.headers["last-modified"] as string | undefined) ?? null
98
103
  } catch {
99
104
  return null
100
105
  }
@@ -104,7 +104,7 @@ export async function extractPPDTuples(
104
104
  /**
105
105
  * Stream `inputPath` (PPD CSV) → `outputPath` (OA-shaped tuples CSV), returning the row-count stats.
106
106
  */
107
- export async function runPPDExtract(inputPath: string, outputPath: string): Promise<PPDExtractStats> {
107
+ async function runPPDExtract(inputPath: string, outputPath: string): Promise<PPDExtractStats> {
108
108
  // No `encoding` — CSVSpliterator delimits raw bytes and decodes utf-8 itself (see readTuples in
109
109
  // shard-recipes/locale.ts). `header: false` yields every row as data — PPD ships no header row.
110
110
  const rows = CSVSpliterator.fromAsync<string[]>(createReadStream(inputPath), {
@@ -25,6 +25,7 @@ import { existsSync, mkdirSync, statSync } from "node:fs"
25
25
  import { unlink } from "node:fs/promises"
26
26
  import { join } from "node:path"
27
27
 
28
+ import { BYTES_PER_KIB, ByteFormatter } from "@mailwoman/core/fs/utils"
28
29
  import { sha256File } from "@mailwoman/core/utils"
29
30
 
30
31
  import type { BaseFetchOptions, FetchSummary } from "./download.ts"
@@ -34,7 +35,6 @@ import { downloadToFile, readManifest, writeManifest } from "./download.ts"
34
35
  * Bytes per KiB — the divisor for human-readable sizes, and the floor below which a "download" is an error page rather
35
36
  * than data.
36
37
  */
37
- const BYTES_PER_KIB = 1024
38
38
 
39
39
  const SOURCE_URL = "https://www.hawaiipublicschools.org/DOE%20Forms/SchoolList.xlsx"
40
40
  const SLUG = "state-hi-schools"
@@ -96,26 +96,6 @@ interface Manifest {
96
96
  notes: string
97
97
  }
98
98
 
99
- /**
100
- * Mimic `numfmt --to=iec` for a friendly byte-size log line.
101
- */
102
- function iec(bytes: number): string {
103
- if (bytes < BYTES_PER_KIB) return String(bytes)
104
- const units = ["K", "M", "G", "T", "P"]
105
- let value = bytes / 1024
106
- let i = 0
107
-
108
- while (value >= BYTES_PER_KIB && i < units.length - 1) {
109
- value /= 1024
110
-
111
- i++
112
- }
113
-
114
- const rounded = value < 10 ? value.toFixed(1) : Math.round(value).toString()
115
-
116
- return `${rounded}${units[i] ?? ""}`
117
- }
118
-
119
99
  /**
120
100
  * Run the openpyxl converter. Its stderr narration streams straight through to the process stderr (matching the old
121
101
  * `stdio: inherit` behavior) rather than routing through `report` — the python child owns those lines.
@@ -190,7 +170,7 @@ export async function fetchStateHISchools(
190
170
  }
191
171
 
192
172
  const xlsxSize = statSync(xlsxDest).size
193
- report?.(` Downloaded XLSX: ${iec(xlsxSize)}`)
173
+ report?.(` Downloaded XLSX: ${ByteFormatter.formatIEC(xlsxSize)}`)
194
174
 
195
175
  if (xlsxSize < BYTES_PER_KIB) {
196
176
  report?.(` ✗ Response too small (${xlsxSize} bytes) — probable error page`)
@@ -221,7 +201,7 @@ export async function fetchStateHISchools(
221
201
 
222
202
  await writeManifest(manifestPath, manifest)
223
203
 
224
- report?.(` ✓ ${iec(csvSize)} sha256=${csvSha}`)
204
+ report?.(` ✓ ${ByteFormatter.formatIEC(csvSize)} sha256=${csvSha}`)
225
205
  report?.(` MANIFEST written to ${manifestPath}`)
226
206
 
227
207
  return { fetched: 1, skipped: 0, failed: 0, failedCodes: [] }
@@ -20,6 +20,7 @@
20
20
  import { mkdirSync } from "node:fs"
21
21
  import { join } from "node:path"
22
22
 
23
+ import { BYTES_PER_KIB } from "@mailwoman/core/fs/utils"
23
24
  import { sha256File } from "@mailwoman/core/utils"
24
25
 
25
26
  import type { BaseFetchOptions, FetchSummary } from "./download.ts"
@@ -29,7 +30,6 @@ import { downloadToFile, writeManifest } from "./download.ts"
29
30
  * Bytes per KiB — the divisor for human-readable sizes, and the floor below which a "download" is an error page rather
30
31
  * than data.
31
32
  */
32
- const BYTES_PER_KIB = 1024
33
33
 
34
34
  export type FetchStateSourcesOptions = BaseFetchOptions
35
35
 
@@ -28,6 +28,8 @@ import { Readable } from "node:stream"
28
28
  import { pipeline } from "node:stream/promises"
29
29
  import { setTimeout as sleep } from "node:timers/promises"
30
30
 
31
+ import { APIClient, pluckResponseData } from "@mailwoman/core/api"
32
+ import { BYTES_PER_KIB, ByteFormatter } from "@mailwoman/core/fs/utils"
31
33
  import { sha256File } from "@mailwoman/core/utils"
32
34
 
33
35
  import type { BaseFetchOptions, FetchSummary } from "./download.ts"
@@ -47,8 +49,6 @@ const HTTP_OK = 200
47
49
  */
48
50
  const HTTP_REDIRECT = 300
49
51
 
50
- const BYTES_PER_KIB = 1024
51
-
52
52
  const TIGER_BASE_URL = "https://www2.census.gov/geo/tiger/TIGER2024/ADDRFEAT"
53
53
 
54
54
  export interface FetchTigerFullOptions extends BaseFetchOptions {
@@ -77,20 +77,6 @@ interface CountyEntry {
77
77
  bytes: number
78
78
  }
79
79
 
80
- function humanBytes(bytes: number): string {
81
- const units = ["B", "KiB", "MiB", "GiB", "TiB"]
82
- let value = bytes
83
- let unit = 0
84
-
85
- while (value >= BYTES_PER_KIB && unit < units.length - 1) {
86
- value /= 1024
87
-
88
- unit++
89
- }
90
-
91
- return `${value.toFixed(unit === 0 ? 0 : 1)}${units[unit]}`
92
- }
93
-
94
80
  /**
95
81
  * Stream an HTTP download to disk, returning the final HTTP status (0 on network error after retries).
96
82
  *
@@ -193,7 +179,7 @@ export async function fetchTigerFull(
193
179
  options: FetchTigerFullOptions,
194
180
  report?: (line: string) => void
195
181
  ): Promise<FetchSummary> {
196
- const skipStateFips = (options.skipStateFips ?? "50").split(/\s+/).filter(Boolean)
182
+ const skipStateFips = (options.skipStateFips ?? "50").split(/\s+/).filter((value) => value.length > 0)
197
183
  const rateSleepMs = Math.round((options.rateSleep ?? 0.2) * 1000)
198
184
  const maxParallel = options.maxParallel ?? 4
199
185
  const dryRun = options.dryRun ?? false
@@ -205,13 +191,17 @@ export async function fetchTigerFull(
205
191
 
206
192
  report?.(`=== Fetching TIGER 2024 ADDRFEAT directory listing...`)
207
193
 
208
- const listingRes = await fetch(`${TIGER_BASE_URL}/`, {
209
- headers: { "Accept-Encoding": "gzip, br" },
210
- signal: AbortSignal.timeout(60_000),
194
+ // `responseType: "text"` an Apache directory index, scraped below. The per-county ARCHIVE downloads
195
+ // stay on raw `fetch` (they stream to disk; see `downloadOne`).
196
+ const listingRes = await new APIClient({
197
+ displayName: "tiger-listing",
198
+ retry: true,
199
+ axios: { headers: { "Accept-Encoding": "gzip, br" } },
211
200
  })
201
+ .fetch<string>({ url: `${TIGER_BASE_URL}/`, responseType: "text", timeout: 60_000 })
202
+ .then(pluckResponseData)
212
203
 
213
- if (!listingRes.ok) throw new Error(`Failed to fetch TIGER directory listing: HTTP ${listingRes.status}`)
214
- const html = await listingRes.text()
204
+ const html = listingRes
215
205
  const allZips = [...new Set(html.match(/tl_2024_[0-9]{5}_addrfeat\.zip/g))].toSorted()
216
206
  const totalCounties = allZips.length
217
207
  report?.(` Found ${totalCounties} county ZIPs in the TIGER 2024 ADDRFEAT index.`)
@@ -314,7 +304,10 @@ export async function fetchTigerFull(
314
304
  // Collect results from this state.
315
305
  for (const result of results) {
316
306
  if (result.ok) {
317
- report?.(` ok ${result.filename} ${humanBytes(result.bytes)} sha256=${result.sha256.slice(0, 12)}...`)
307
+ report?.(
308
+ ` ok ${result.filename} ${ByteFormatter.formatIEC(result.bytes)} sha256=${result.sha256.slice(0, 12)}...`
309
+ )
310
+
318
311
  manifest.set(result.filename, { filename: result.filename, sha256: result.sha256, bytes: result.bytes })
319
312
 
320
313
  totalFetched++
@@ -350,7 +343,7 @@ export async function fetchTigerFull(
350
343
  report?.(` Counties failed : ${totalFailed}`)
351
344
 
352
345
  if (totalBytesFetched > 0) {
353
- report?.(` Bytes fetched this run : ${humanBytes(totalBytesFetched)} (${totalBytesFetched})`)
346
+ report?.(` Bytes fetched this run : ${ByteFormatter.formatIEC(totalBytesFetched)} (${totalBytesFetched})`)
354
347
  }
355
348
 
356
349
  if (totalFailed > 0) {
@@ -50,8 +50,9 @@ import { mkdir } from "node:fs/promises"
50
50
  import { dirname } from "node:path"
51
51
 
52
52
  import { ParquetReader } from "@dsnp/parquetjs"
53
+ import { APIClient, pluckResponseData } from "@mailwoman/core/api"
53
54
  import { $private } from "@mailwoman/core/env"
54
- import { tryParsingJSON } from "@mailwoman/core/objects"
55
+ import { isPresent, tryParsingJSON } from "@mailwoman/core/objects"
55
56
  import { dataRootPath } from "@mailwoman/core/utils"
56
57
  import { createNewlineWriter } from "spliterator"
57
58
 
@@ -195,7 +196,7 @@ async function loadSeeds(
195
196
  const paths = corpusPath
196
197
  .split(",")
197
198
  .map((p) => p.trim())
198
- .filter(Boolean)
199
+ .filter(isPresent)
199
200
 
200
201
  report?.(`reading seeds from ${paths.length} shard(s) (target: ${count}, stratified)`)
201
202
 
@@ -345,24 +346,28 @@ function makeDeepseekProvider(model: string): LlmProvider {
345
346
  name: "deepseek",
346
347
  model,
347
348
  async generateVariants(seed, n) {
348
- const res = await fetch("https://api.deepseek.com/chat/completions", {
349
- method: "POST",
350
- headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
351
- body: JSON.stringify({
352
- model,
353
- messages: [
354
- { role: "system", content: SYSTEM_PROMPT },
355
- { role: "user", content: buildUserPrompt(seed, n) },
356
- ],
357
- response_format: { type: "json_object" },
358
- max_tokens: 800,
359
- temperature: 0.7,
360
- }),
361
- signal: AbortSignal.timeout(60_000),
349
+ const data = await new APIClient({
350
+ displayName: "deepseek",
351
+ retry: true,
352
+ axios: { headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" } },
362
353
  })
354
+ .fetch<{ choices?: Array<{ message: { content: string } }> }>({
355
+ url: "https://api.deepseek.com/chat/completions",
356
+ method: "post",
357
+ timeout: 60_000,
358
+ data: {
359
+ model,
360
+ messages: [
361
+ { role: "system", content: SYSTEM_PROMPT },
362
+ { role: "user", content: buildUserPrompt(seed, n) },
363
+ ],
364
+ response_format: { type: "json_object" },
365
+ max_tokens: 800,
366
+ temperature: 0.7,
367
+ },
368
+ })
369
+ .then(pluckResponseData)
363
370
 
364
- if (!res.ok) throw new Error(`DeepSeek HTTP ${res.status}: ${await res.text()}`)
365
- const data = (await res.json()) as { choices?: Array<{ message: { content: string } }> }
366
371
  const content = data.choices?.[0]?.message.content ?? "{}"
367
372
 
368
373
  return parseCandidates(content)
@@ -379,24 +384,30 @@ function makeAnthropicProvider(model: string): LlmProvider {
379
384
  name: "anthropic",
380
385
  model,
381
386
  async generateVariants(seed, n) {
382
- const res = await fetch("https://api.anthropic.com/v1/messages", {
383
- method: "POST",
384
- headers: {
385
- "x-api-key": apiKey,
386
- "anthropic-version": "2023-06-01",
387
- "Content-Type": "application/json",
387
+ const data = await new APIClient({
388
+ displayName: "anthropic",
389
+ retry: true,
390
+ axios: {
391
+ headers: {
392
+ "x-api-key": apiKey,
393
+ "anthropic-version": "2023-06-01",
394
+ "Content-Type": "application/json",
395
+ },
388
396
  },
389
- body: JSON.stringify({
390
- model,
391
- max_tokens: 800,
392
- system: SYSTEM_PROMPT,
393
- messages: [{ role: "user", content: buildUserPrompt(seed, n) }],
394
- }),
395
- signal: AbortSignal.timeout(60_000),
396
397
  })
398
+ .fetch<{ content?: Array<{ type: string; text: string }> }>({
399
+ url: "https://api.anthropic.com/v1/messages",
400
+ method: "post",
401
+ timeout: 60_000,
402
+ data: {
403
+ model,
404
+ max_tokens: 800,
405
+ system: SYSTEM_PROMPT,
406
+ messages: [{ role: "user", content: buildUserPrompt(seed, n) }],
407
+ },
408
+ })
409
+ .then(pluckResponseData)
397
410
 
398
- if (!res.ok) throw new Error(`Anthropic HTTP ${res.status}: ${await res.text()}`)
399
- const data = (await res.json()) as { content?: Array<{ type: string; text: string }> }
400
411
  const text = data.content?.find((c) => c.type === "text")?.text ?? "[]"
401
412
 
402
413
  return parseCandidates(text)
@@ -60,10 +60,12 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from
60
60
  import { basename, join } from "node:path"
61
61
 
62
62
  import { isStreetDirectionalToken, matchTrailingSuffix, type USStreetSuffix } from "@mailwoman/codex/us"
63
- import { parseJSONStrict, tryParsingJSON } from "@mailwoman/core/objects"
63
+ import { isPresent, parseJSONStrict, tryParsingJSON } from "@mailwoman/core/objects"
64
64
  import { sha256File } from "@mailwoman/core/utils"
65
65
  import { TextSpliterator } from "spliterator"
66
66
 
67
+ import { NAME_PRONE_US_SUFFIXES } from "../name-prone-us-suffixes.ts"
68
+
67
69
  // ── Types ──────────────────────────────────────────────────────────────────
68
70
 
69
71
  /**
@@ -136,71 +138,6 @@ export interface GoldenRelabelResult {
136
138
  * pass 3 — the whole flagged class is 60 rows of 1,906), not from the whole 200-entry table: flagging every possible
137
139
  * name-head would mark a third of the corrections and stop being a review artifact.
138
140
  */
139
- const NAME_PRONE_SUFFIXES: ReadonlySet<USStreetSuffix> = new Set<USStreetSuffix>([
140
- "BEACH",
141
- "BROOK",
142
- "BROOKS",
143
- "CAMP",
144
- "CENTER",
145
- "CENTERS",
146
- "CLUB",
147
- "COMMON",
148
- "COMMONS",
149
- "CREEK",
150
- "CROSSING",
151
- "ESTATE",
152
- "ESTATES",
153
- "FIELD",
154
- "FIELDS",
155
- "FOREST",
156
- "GARDEN",
157
- "GARDENS",
158
- "GLEN",
159
- "GREEN",
160
- "GREENS",
161
- "GROVE",
162
- "GROVES",
163
- "HARBOR",
164
- "HEIGHTS",
165
- "HILL",
166
- "HILLS",
167
- "HOLLOW",
168
- "ISLAND",
169
- "ISLANDS",
170
- "ISLE",
171
- "JUNCTION",
172
- "LAKE",
173
- "LAKES",
174
- "LANDING",
175
- "MALL",
176
- "MANOR",
177
- "MEADOW",
178
- "MEADOWS",
179
- "MILL",
180
- "MILLS",
181
- "MISSION",
182
- "ORCHARD",
183
- "PARK",
184
- "PASS",
185
- "PLAZA",
186
- "POINT",
187
- "POINTS",
188
- "RANCH",
189
- "RIDGE",
190
- "SHORE",
191
- "SHORES",
192
- "SPRING",
193
- "SPRINGS",
194
- "SQUARE",
195
- "STATION",
196
- "SUMMIT",
197
- "VALLEY",
198
- "VIEW",
199
- "VIEWS",
200
- "VILLAGE",
201
- "VISTA",
202
- ])
203
-
204
141
  // ── Byte-exact tail split ──────────────────────────────────────────────────
205
142
 
206
143
  interface TailSplit {
@@ -381,7 +318,7 @@ export function relabelGoldenStreetRow(
381
318
  throw new Error(`golden-relabel: span reconstruction failed for ${JSON.stringify(street)}`)
382
319
  }
383
320
 
384
- if (canonical && NAME_PRONE_SUFFIXES.has(canonical)) {
321
+ if (canonical && NAME_PRONE_US_SUFFIXES.has(canonical)) {
385
322
  flags.push({
386
323
  kind: "name-prone-suffix",
387
324
  detail: `${canonical} heads proper names as often as street types`,
@@ -679,7 +616,7 @@ export async function relabelGoldenDirectory(
679
616
  function renderDeckMarkdown(deck: GoldenRelabelDeckEntry[], parent: string, version: string): string {
680
617
  const span = (components: Record<string, string>): string =>
681
618
  [components.street_prefix, components.street, components.street_suffix]
682
- .filter(Boolean)
619
+ .filter(isPresent)
683
620
  .map((s) => JSON.stringify(s))
684
621
  .join(" + ")
685
622
 
@@ -4,8 +4,7 @@
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
6
  * Corpus operator tools — the `run()`-style modules behind `mailwoman corpus …` commands. No argv,
7
- * no `process.exit`: commands own parsing, rendering, and exit codes (see the 2026-07-09
8
- * scripts→Pastel spec).
7
+ * no `process.exit`: commands own parsing, rendering, and exit codes.
9
8
  */
10
9
 
11
10
  export * from "./align-shard.ts"
@@ -23,6 +22,7 @@ export * from "./lint-shard.ts"
23
22
  export * from "./lint-shard-vocab.ts"
24
23
  export * from "./shard-kryptonite.ts"
25
24
  export * from "./overture-subvenue.ts"
25
+ export * from "./postcode-triples.ts"
26
26
  export * from "./sub-venue-lexicon.ts"
27
27
  export * from "./sub-venue-promotions.ts"
28
28
  export * from "./shard-translit.ts"
@@ -241,7 +241,6 @@ async function runIngest(opts: IngestOptions): Promise<void> {
241
241
  const createTableSQL = `CREATE TABLE IF NOT EXISTS "${opts.tableName}" (\n ${colDefs}\n);`
242
242
 
243
243
  const tempCols = columns.map((c) => `"${c.name}"`).join(", ")
244
- const insertSQL = `INSERT INTO "${opts.tableName}" (${tempCols})\nSELECT ${tempCols} FROM temp."${opts.tableName}_source";`
245
244
 
246
245
  process.stderr.write(`\nSchema inferred from ${sampleRows.length} sample rows:\n`)
247
246
  process.stderr.write(`${createTableSQL}\n\n`)
@@ -264,17 +263,6 @@ async function runIngest(opts: IngestOptions): Promise<void> {
264
263
 
265
264
  // Use the .import approach via a temp table, then INSERT INTO ... SELECT to handle
266
265
  // NULL normalization and type coercion.
267
- const csvBasename = basename(opts.inputPath)
268
-
269
- const importSQL = [
270
- `CREATE TEMP TABLE "${opts.tableName}_source" (${colDefs});`,
271
- `.mode csv`,
272
- `.separator "${opts.separator}"`,
273
- `.import "${csvBasename}" --skip ${opts.skipLines + (opts.hasHeader ? 1 : 0)} --schema temp ${opts.tableName}_source`,
274
- insertSQL,
275
- `DROP TABLE temp."${opts.tableName}_source";`,
276
- ]
277
-
278
266
  // better-sqlite3 doesn't support .import natively, so we use a different approach:
279
267
  // Read the CSV line-by-line and INSERT in a transaction.
280
268
  process.stderr.write(`Importing rows...\n`)
@@ -373,7 +361,6 @@ async function runIngest(opts: IngestOptions): Promise<void> {
373
361
  db.close()
374
362
 
375
363
  // Write MANIFEST
376
- const fileSize = (await import("node:fs/promises")).stat
377
364
  const stat = await (await import("node:fs/promises")).stat(opts.outputPath)
378
365
 
379
366
  const manifest = {