@mailwoman/tiger 9.0.0 → 9.1.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mailwoman/tiger",
3
- "version": "9.0.0",
3
+ "version": "9.1.0",
4
4
  "description": "US Census TIGER/Line data processing and analysis.",
5
5
  "keywords": [
6
6
  "census",
@@ -73,12 +73,12 @@
73
73
  "test": "node ./out/sdk/TIGERService.test.js"
74
74
  },
75
75
  "dependencies": {
76
- "@mailwoman/core": "9.0.0",
77
- "@mailwoman/spatial": "9.0.0",
76
+ "@mailwoman/core": "9.1.0",
77
+ "@mailwoman/spatial": "9.1.0",
78
78
  "@turf/boolean-contains": "^7.3.5",
79
79
  "kysely": "^0.29.4",
80
80
  "shapefile-parser": "^1.0.3",
81
- "spliterator": "^6.0.1",
81
+ "spliterator": "^6.1.0",
82
82
  "type-fest": "^5.8.0"
83
83
  },
84
84
  "devDependencies": {
package/sdk/download.ts CHANGED
@@ -20,6 +20,8 @@ import { rename } from "node:fs/promises"
20
20
  import { Readable } from "node:stream"
21
21
  import { pipeline } from "node:stream/promises"
22
22
 
23
+ import { verifyZipIntegrity } from "@mailwoman/core/fs/zip"
24
+
23
25
  /**
24
26
  * Run a command and resolve its stdout, rejecting with the captured stderr on a non-zero exit.
25
27
  *
@@ -45,14 +47,14 @@ export function runCapture(cmd: string, args: string[]): Promise<string> {
45
47
  * Download `url` to `dest` unless a VALID copy is already there. Returns `true` when the cache was reused, `false` when
46
48
  * a download happened.
47
49
  *
48
- * "Valid" means `unzip -tq` passes — an existence check alone is not enough, because an interrupted download leaves a
49
- * plausible-looking file that fails only much later, inside ogr2ogr. Writes to a `.tmp` sibling and renames, so `dest`
50
- * is never a partial archive.
50
+ * "Valid" means every member's CRC-32 checks out — an existence check alone is not enough, because an interrupted
51
+ * download leaves a plausible-looking file that fails only much later, inside ogr2ogr. Writes to a `.tmp` sibling and
52
+ * renames, so `dest` is never a partial archive.
51
53
  */
52
54
  export async function downloadIfNeeded(url: string, dest: string): Promise<boolean> {
53
55
  if (existsSync(dest)) {
54
56
  try {
55
- await runCapture("unzip", ["-tq", dest])
57
+ await verifyZipIntegrity(dest)
56
58
 
57
59
  return true
58
60
  } catch {
package/sdk/fetch.ts CHANGED
@@ -32,12 +32,13 @@ import { DatabaseSync } from "node:sqlite"
32
32
  import { Readable } from "node:stream"
33
33
  import { pipeline } from "node:stream/promises"
34
34
 
35
+ import { extractZipEntries } from "@mailwoman/core/fs/zip"
35
36
  import { DatabaseClient } from "@mailwoman/core/kysley/client"
36
37
  import { tryParsingJSON } from "@mailwoman/core/objects"
37
38
  import { mailwomanDataRoot } from "@mailwoman/core/utils"
38
39
  import { TextSpliterator } from "spliterator"
39
40
 
40
- import { downloadIfNeeded, runCapture } from "./download.ts"
41
+ import { downloadIfNeeded } from "./download.ts"
41
42
  import type { TIGERBlockTable, TIGERDatabase, TIGERPlaceTable, TIGERStreetTable } from "./schema.ts"
42
43
  import { initializeTIGERSchema, TIGER_PRAGMAS } from "./schema.ts"
43
44
 
@@ -270,7 +271,7 @@ export async function* fetchTIGER(options: FetchTIGEROptions): AsyncGenerator<Fe
270
271
  const cached = await downloadIfNeeded(url, zipPath)
271
272
  yield { phase: "download", file: zipName, cached }
272
273
 
273
- await runCapture("unzip", ["-o", "-q", zipPath, "-d", cacheDir])
274
+ await extractZipEntries(zipPath, cacheDir)
274
275
  const layer = `tl_${vintage}_${unit}_${level}`
275
276
  const shpPath = join(cacheDir, layer + ".shp")
276
277
  yield { phase: "extract", file: layer + ".shp" }
@@ -24,12 +24,13 @@ import { DatabaseSync } from "node:sqlite"
24
24
  import { Readable } from "node:stream"
25
25
  import { pipeline } from "node:stream/promises"
26
26
 
27
+ import { extractZipEntries } from "@mailwoman/core/fs/zip"
27
28
  import { DatabaseClient } from "@mailwoman/core/kysley/client"
28
29
  import { mailwomanDataRoot } from "@mailwoman/core/utils"
29
30
  import { TextSpliterator } from "spliterator"
30
31
 
31
32
  import { AdminLevel1CodeToAbbreviation, StateName, type AdminLevel1Code } from "../state.ts"
32
- import { downloadIfNeeded, runCapture } from "./download.ts"
33
+ import { downloadIfNeeded } from "./download.ts"
33
34
  import { initializeTIGERSchema, TIGER_PRAGMAS, type PLBlockTable, type TIGERDatabase } from "./schema.ts"
34
35
 
35
36
  const REDISTRICTING_BASE =
@@ -148,7 +149,7 @@ export async function* fetchRedistricting(
148
149
  const cached = await downloadIfNeeded(url, zipPath)
149
150
  yield { phase: "download", file: zipName, cached }
150
151
 
151
- await runCapture("unzip", ["-o", "-q", zipPath, "-d", cacheDir])
152
+ await extractZipEntries(zipPath, cacheDir)
152
153
  const geoPath = join(cacheDir, `${fileAbbr}geo${vintage}.pl`)
153
154
  const seg1Path = join(cacheDir, `${fileAbbr}00001${vintage}.pl`)
154
155
  yield { phase: "extract", file: `${fileAbbr}geo${vintage}.pl` }