@mailwoman/soil 9.4.0 → 10.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.
Files changed (115) hide show
  1. package/README.md +118 -116
  2. package/lib/index.ts +66 -98
  3. package/lib/paths.ts +24 -0
  4. package/lib/schema.ts +188 -120
  5. package/lib/vocabulary.ts +40 -107
  6. package/out/index.d.ts +52 -70
  7. package/out/index.d.ts.map +1 -1
  8. package/out/index.js +24 -72
  9. package/out/index.js.map +1 -1
  10. package/out/paths.d.ts +19 -0
  11. package/out/paths.d.ts.map +1 -0
  12. package/out/paths.js +21 -0
  13. package/out/paths.js.map +1 -0
  14. package/out/schema.d.ts +187 -119
  15. package/out/schema.d.ts.map +1 -1
  16. package/out/schema.js +31 -31
  17. package/out/schema.js.map +1 -1
  18. package/out/sdk/acquire.d.ts +15 -24
  19. package/out/sdk/acquire.d.ts.map +1 -1
  20. package/out/sdk/acquire.js +5 -20
  21. package/out/sdk/acquire.js.map +1 -1
  22. package/out/sdk/build-soil.d.ts +67 -70
  23. package/out/sdk/build-soil.d.ts.map +1 -1
  24. package/out/sdk/build-soil.js +65 -95
  25. package/out/sdk/build-soil.js.map +1 -1
  26. package/out/sdk/cell-tiers.d.ts +7 -19
  27. package/out/sdk/cell-tiers.d.ts.map +1 -1
  28. package/out/sdk/cell-tiers.js +19 -38
  29. package/out/sdk/cell-tiers.js.map +1 -1
  30. package/out/sdk/cells.d.ts +15 -41
  31. package/out/sdk/cells.d.ts.map +1 -1
  32. package/out/sdk/cells.js +11 -38
  33. package/out/sdk/cells.js.map +1 -1
  34. package/out/sdk/client.d.ts +23 -48
  35. package/out/sdk/client.d.ts.map +1 -1
  36. package/out/sdk/client.js +19 -63
  37. package/out/sdk/client.js.map +1 -1
  38. package/out/sdk/download.d.ts +24 -47
  39. package/out/sdk/download.d.ts.map +1 -1
  40. package/out/sdk/download.js +14 -54
  41. package/out/sdk/download.js.map +1 -1
  42. package/out/sdk/ingest/chunk.d.ts +77 -0
  43. package/out/sdk/ingest/chunk.d.ts.map +1 -0
  44. package/out/sdk/{ingest-chunk.js → ingest/chunk.js} +19 -17
  45. package/out/sdk/ingest/chunk.js.map +1 -0
  46. package/out/sdk/ingest/worker.d.ts +9 -0
  47. package/out/sdk/ingest/worker.d.ts.map +1 -0
  48. package/out/{scripts/ingest-chunk.js → sdk/ingest/worker.js} +11 -10
  49. package/out/sdk/ingest/worker.js.map +1 -0
  50. package/out/sdk/ingest.d.ts +40 -52
  51. package/out/sdk/ingest.d.ts.map +1 -1
  52. package/out/sdk/ingest.js +18 -61
  53. package/out/sdk/ingest.js.map +1 -1
  54. package/out/sdk/measure-resolutions.d.ts +5 -16
  55. package/out/sdk/measure-resolutions.d.ts.map +1 -1
  56. package/out/sdk/measure-resolutions.js +3 -15
  57. package/out/sdk/measure-resolutions.js.map +1 -1
  58. package/out/sdk/reduce.d.ts +33 -59
  59. package/out/sdk/reduce.d.ts.map +1 -1
  60. package/out/sdk/reduce.js +47 -78
  61. package/out/sdk/reduce.js.map +1 -1
  62. package/out/sdk/survey-area.d.ts +16 -48
  63. package/out/sdk/survey-area.d.ts.map +1 -1
  64. package/out/sdk/survey-area.js +33 -77
  65. package/out/sdk/survey-area.js.map +1 -1
  66. package/out/sdk/tabular.d.ts +32 -31
  67. package/out/sdk/tabular.d.ts.map +1 -1
  68. package/out/sdk/tabular.js +58 -56
  69. package/out/sdk/tabular.js.map +1 -1
  70. package/out/sdk/test-kit.d.ts +57 -0
  71. package/out/sdk/test-kit.d.ts.map +1 -0
  72. package/out/{test-kit.js → sdk/test-kit.js} +18 -39
  73. package/out/sdk/test-kit.js.map +1 -0
  74. package/out/sdk/verify.d.ts +15 -51
  75. package/out/sdk/verify.d.ts.map +1 -1
  76. package/out/sdk/verify.js +19 -77
  77. package/out/sdk/verify.js.map +1 -1
  78. package/out/vocabulary.d.ts +37 -103
  79. package/out/vocabulary.d.ts.map +1 -1
  80. package/out/vocabulary.js +34 -107
  81. package/out/vocabulary.js.map +1 -1
  82. package/package.json +36 -190
  83. package/{lib/sdk → sdk}/acquire.ts +17 -27
  84. package/{lib/sdk → sdk}/build-soil.ts +114 -128
  85. package/{lib/sdk → sdk}/cell-tiers.ts +20 -39
  86. package/{lib/sdk → sdk}/cells.ts +17 -43
  87. package/sdk/client.ts +147 -0
  88. package/sdk/download.ts +131 -0
  89. package/{lib/sdk/ingest-chunk.ts → sdk/ingest/chunk.ts} +34 -26
  90. package/{lib/scripts/ingest-chunk.ts → sdk/ingest/worker.ts} +10 -9
  91. package/sdk/ingest.ts +253 -0
  92. package/{lib/sdk → sdk}/measure-resolutions.ts +5 -16
  93. package/sdk/reduce.ts +344 -0
  94. package/{lib/sdk → sdk}/survey-area.ts +39 -83
  95. package/{lib/sdk → sdk}/tabular.ts +62 -59
  96. package/{lib → sdk}/test-kit.ts +18 -40
  97. package/{lib/sdk → sdk}/verify.ts +29 -85
  98. package/lib/sdk/client.ts +0 -184
  99. package/lib/sdk/download.ts +0 -161
  100. package/lib/sdk/index.ts +0 -20
  101. package/lib/sdk/ingest.ts +0 -278
  102. package/lib/sdk/reduce.ts +0 -375
  103. package/out/scripts/ingest-chunk.d.ts +0 -11
  104. package/out/scripts/ingest-chunk.d.ts.map +0 -1
  105. package/out/scripts/ingest-chunk.js.map +0 -1
  106. package/out/sdk/index.d.ts +0 -20
  107. package/out/sdk/index.d.ts.map +0 -1
  108. package/out/sdk/index.js +0 -20
  109. package/out/sdk/index.js.map +0 -1
  110. package/out/sdk/ingest-chunk.d.ts +0 -73
  111. package/out/sdk/ingest-chunk.d.ts.map +0 -1
  112. package/out/sdk/ingest-chunk.js.map +0 -1
  113. package/out/test-kit.d.ts +0 -79
  114. package/out/test-kit.d.ts.map +0 -1
  115. package/out/test-kit.js.map +0 -1
@@ -3,35 +3,11 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * The delineation-keyed cell index, and the two numbers the index resolution is chosen from.
7
- *
8
- * THE CLASSIFIER ITSELF LIVES IN `@mailwoman/spatial`, because the traps it guards are properties of
9
- * h3-js rather than of SSURGO: a centre-containment polyfill drops every polygon smaller than a cell, an
10
- * exhausted WASM allocator reports success and returns zeros, and the allocator is sized from the
11
- * bounding box. The layer contract states all three as requirements on every polygon builder. What is
12
- * soil-shaped is the ACCUMULATOR below, which keys on the delineation rather than on a hazard class,
13
- * because the reduction weights by the area a delineation covers.
14
- *
15
- * EXPECT THE `partial` SHARE TO INVERT AGAINST THE FLOOD LAYER, AND DO NOT READ THAT AS A DEFECT. Flood
16
- * polygons are large against their cells, so most cells fall wholly inside one zone and `compactCells`
17
- * collapses long uniform interiors. Soil delineations are the opposite: 85.4% of `IA153`'s 17,966 of them
18
- * are smaller than one resolution-9 cell, and the median is 24,863 m² against a 105,333 m² cell. Small
19
- * polygons against large cells means most cells are crossed by a boundary — so the `partial` share should
20
- * be HIGH, `compactCells` should yield close to nothing, and the index alone will rarely answer a point
21
- * probe. That is not an argument against storing the geometry; it is the argument for why this layer
22
- * carries the reduced `soil_capability_cell` alongside the index rather than relying on the index the way
23
- * the flood layer can.
24
- *
25
- * TWO NUMBERS GET REPORTED AT EACH CANDIDATE RESOLUTION, AND THEY MOVE IN OPPOSITE DIRECTIONS. The
26
- * `partial` cell share says whether the containment index answers most probes alone. The share of cells
27
- * whose top class holds less than half the cell says whether the layer is answering or hedging — the
28
- * cell-grain analogue of NRCS's own `niccdcdpct` distribution, which reads 3.3% below half nationally.
29
- * Going coarser improves the first and worsens the second, and picking between them is what the
30
- * measurement is for.
6
+ * The delineation-keyed cell index, plus the partial-cell and mixed-top-class shares that choose its resolution.
31
7
  */
32
8
  import { type FeatureCells, type MultiPolygonRings } from "@mailwoman/spatial";
33
9
  /**
34
- * The label this layer's classifier failures carry.
10
+ * The label assigned to this layer's classifier failures.
35
11
  */
36
12
  export declare const SOIL_CELL_LABEL = "soil cells";
37
13
  /**
@@ -56,12 +32,13 @@ export interface SoilCellIndexMeasurement {
56
32
  */
57
33
  partialCells: number;
58
34
  /**
59
- * `partialCells / touchedCells` — the share of in-layer probes that cannot be answered from the index alone.
35
+ * `partialCells / touchedCells`, the share of in-layer probes that cannot
36
+ * be answered using only the index.
60
37
  */
61
38
  partialShare: number;
62
39
  /**
63
- * Whole cells after `compactCells`. Expected to be close to `wholeCells` here rather than far below it: compaction
64
- * needs a uniform interior, and small delineations do not produce one.
40
+ * Whole cells after `compactCells`, expected to be close to `wholeCells` here
41
+ * because small delineations do not produce a uniform interior.
65
42
  */
66
43
  compactedWholeCells: number;
67
44
  /**
@@ -69,8 +46,8 @@ export interface SoilCellIndexMeasurement {
69
46
  */
70
47
  cellDelineationPairs: number;
71
48
  /**
72
- * The mean number of delineations reaching a cell — the direct measure of how mixed a cell is before any rating is
73
- * read, and the number that rises as the resolution coarsens.
49
+ * The mean number of delineations reaching a cell measures how mixed a cell is
50
+ * before any rating is read and rises as the resolution coarsens.
74
51
  */
75
52
  meanDelineationsPerCell: number;
76
53
  /**
@@ -83,10 +60,9 @@ export interface SoilCellIndexMeasurement {
83
60
  resolutions: number[];
84
61
  }
85
62
  /**
86
- * Accumulate one resolution's cell index over a stream of delineations.
87
- *
88
- * Held as short-cell STRINGS rather than the integers the tables store, because `compactCells` is an h3-js function
89
- * over full indexes and round-tripping through the integer form at every step would cost more than the strings do.
63
+ * Accumulates one resolution's cell index over a stream of delineations,
64
+ * held as short-cell strings because `compactCells` needs full h3-js indexes
65
+ * and round-tripping through the integer form would cost more.
90
66
  */
91
67
  export declare class SoilCellIndex {
92
68
  #private;
@@ -97,16 +73,14 @@ export declare class SoilCellIndex {
97
73
  */
98
74
  add(areaID: string, cells: FeatureCells): void;
99
75
  /**
100
- * Compact the whole-cell set and report the measurement.
101
- *
102
- * Compaction is applied to the WHOLE set only — a partial cell's parent is not partial in any useful sense, and
103
- * compacting it would claim the fringe covers ground it does not.
76
+ * Compacts the whole-cell set and reports the measurement, applying compaction to the
77
+ * whole set only because a partial cell's parent would claim fringe ground.
104
78
  */
105
79
  finish(): SoilCellIndexMeasurement;
106
80
  }
107
81
  /**
108
- * The measurement as markdown table ROWS — what a build receipt carries, one line per element so a caller printing them
109
- * never has to split a joined string back apart.
82
+ * The measurement as markdown table rows, one line per element so a caller never
83
+ * has to split a joined string back apart.
110
84
  */
111
85
  export declare function formatSoilResolutionRows(measurements: ReadonlyArray<SoilCellIndexMeasurement & {
112
86
  mixedCellShare?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"cells.d.ts","sourceRoot":"","sources":["../../lib/sdk/cells.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAIN,KAAK,YAAY,EAEjB,KAAK,iBAAiB,EACtB,MAAM,oBAAoB,CAAA;AAG3B;;GAEG;AACH,eAAO,MAAM,eAAe,eAAe,CAAA;AAE3C;;GAEG;AACH,wBAAgB,wBAAwB,CACvC,QAAQ,EAAE,iBAAiB,EAC3B,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE,MAAM,GACZ,YAAY,CAEd;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACxC,UAAU,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,mBAAmB,EAAE,MAAM,CAAA;IAC3B;;OAEG;IACH,oBAAoB,EAAE,MAAM,CAAA;IAC5B;;;OAGG;IACH,uBAAuB,EAAE,MAAM,CAAA;IAC/B;;OAEG;IACH,iBAAiB,EAAE,MAAM,CAAA;IACzB;;OAEG;IACH,WAAW,EAAE,MAAM,EAAE,CAAA;CACrB;AAED;;;;;GAKG;AACH,qBAAa,aAAa;;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;gBAYf,UAAU,EAAE,MAAM;IAI9B;;OAEG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI;IA6B9C;;;;;OAKG;IACH,MAAM,IAAI,wBAAwB;CA+BlC;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACvC,YAAY,EAAE,aAAa,CAAC,wBAAwB,GAAG;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GACjF,MAAM,EAAE,CAaV;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD"}
1
+ {"version":3,"file":"cells.d.ts","sourceRoot":"","sources":["../../sdk/cells.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAIN,KAAK,YAAY,EAEjB,KAAK,iBAAiB,EACtB,MAAM,oBAAoB,CAAA;AAG3B;;GAEG;AACH,eAAO,MAAM,eAAe,eAAe,CAAA;AAE3C;;GAEG;AACH,wBAAgB,wBAAwB,CACvC,QAAQ,EAAE,iBAAiB,EAC3B,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE,MAAM,GACZ,YAAY,CAEd;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACxC,UAAU,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,mBAAmB,EAAE,MAAM,CAAA;IAC3B;;OAEG;IACH,oBAAoB,EAAE,MAAM,CAAA;IAC5B;;;OAGG;IACH,uBAAuB,EAAE,MAAM,CAAA;IAC/B;;OAEG;IACH,iBAAiB,EAAE,MAAM,CAAA;IACzB;;OAEG;IACH,WAAW,EAAE,MAAM,EAAE,CAAA;CACrB;AAED;;;;GAIG;AACH,qBAAa,aAAa;;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAY3B,YAAY,UAAU,EAAE,MAAM,EAE7B;IAED;;OAEG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAa7C;IAgBD;;;OAGG;IACH,MAAM,IAAI,wBAAwB,CA8BjC;CACD;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACvC,YAAY,EAAE,aAAa,CAAC,wBAAwB,GAAG;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GACjF,MAAM,EAAE,CAaV;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD"}
package/out/sdk/cells.js CHANGED
@@ -3,36 +3,12 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * The delineation-keyed cell index, and the two numbers the index resolution is chosen from.
7
- *
8
- * THE CLASSIFIER ITSELF LIVES IN `@mailwoman/spatial`, because the traps it guards are properties of
9
- * h3-js rather than of SSURGO: a centre-containment polyfill drops every polygon smaller than a cell, an
10
- * exhausted WASM allocator reports success and returns zeros, and the allocator is sized from the
11
- * bounding box. The layer contract states all three as requirements on every polygon builder. What is
12
- * soil-shaped is the ACCUMULATOR below, which keys on the delineation rather than on a hazard class,
13
- * because the reduction weights by the area a delineation covers.
14
- *
15
- * EXPECT THE `partial` SHARE TO INVERT AGAINST THE FLOOD LAYER, AND DO NOT READ THAT AS A DEFECT. Flood
16
- * polygons are large against their cells, so most cells fall wholly inside one zone and `compactCells`
17
- * collapses long uniform interiors. Soil delineations are the opposite: 85.4% of `IA153`'s 17,966 of them
18
- * are smaller than one resolution-9 cell, and the median is 24,863 m² against a 105,333 m² cell. Small
19
- * polygons against large cells means most cells are crossed by a boundary — so the `partial` share should
20
- * be HIGH, `compactCells` should yield close to nothing, and the index alone will rarely answer a point
21
- * probe. That is not an argument against storing the geometry; it is the argument for why this layer
22
- * carries the reduced `soil_capability_cell` alongside the index rather than relying on the index the way
23
- * the flood layer can.
24
- *
25
- * TWO NUMBERS GET REPORTED AT EACH CANDIDATE RESOLUTION, AND THEY MOVE IN OPPOSITE DIRECTIONS. The
26
- * `partial` cell share says whether the containment index answers most probes alone. The share of cells
27
- * whose top class holds less than half the cell says whether the layer is answering or hedging — the
28
- * cell-grain analogue of NRCS's own `niccdcdpct` distribution, which reads 3.3% below half nationally.
29
- * Going coarser improves the first and worsens the second, and picking between them is what the
30
- * measurement is for.
6
+ * The delineation-keyed cell index, plus the partial-cell and mixed-top-class shares that choose its resolution.
31
7
  */
32
8
  import { classifyFeatureCells, compactAcrossResolutions, shortCellToInt, } from "@mailwoman/spatial";
33
9
  import { getResolution } from "h3-js";
34
10
  /**
35
- * The label this layer's classifier failures carry.
11
+ * The label assigned to this layer's classifier failures.
36
12
  */
37
13
  export const SOIL_CELL_LABEL = "soil cells";
38
14
  /**
@@ -42,18 +18,17 @@ export function classifyDelineationCells(polygons, targetResolution, areaID) {
42
18
  return classifyFeatureCells(polygons, targetResolution, areaID, SOIL_CELL_LABEL);
43
19
  }
44
20
  /**
45
- * Accumulate one resolution's cell index over a stream of delineations.
46
- *
47
- * Held as short-cell STRINGS rather than the integers the tables store, because `compactCells` is an h3-js function
48
- * over full indexes and round-tripping through the integer form at every step would cost more than the strings do.
21
+ * Accumulates one resolution's cell index over a stream of delineations,
22
+ * held as short-cell strings because `compactCells` needs full h3-js indexes
23
+ * and round-tripping through the integer form would cost more.
49
24
  */
50
25
  export class SoilCellIndex {
51
26
  resolution;
52
27
  #whole = new Set();
53
28
  #touched = new Set();
54
29
  /**
55
- * `cell → delineation ids`. Every touched cell, so the mean below is over the real population rather than over the
56
- * fringe alone.
30
+ * `cell → delineation ids` for every touched cell, so the mean is over the
31
+ * real population rather than only the fringe.
57
32
  */
58
33
  #byCell = new Map();
59
34
  #coarsened = 0;
@@ -85,10 +60,8 @@ export class SoilCellIndex {
85
60
  areas.add(areaID);
86
61
  }
87
62
  /**
88
- * Compact the whole-cell set and report the measurement.
89
- *
90
- * Compaction is applied to the WHOLE set only — a partial cell's parent is not partial in any useful sense, and
91
- * compacting it would claim the fringe covers ground it does not.
63
+ * Compacts the whole-cell set and reports the measurement, applying compaction to the
64
+ * whole set only because a partial cell's parent would claim fringe ground.
92
65
  */
93
66
  finish() {
94
67
  const compacted = compactAcrossResolutions(this.#whole);
@@ -117,8 +90,8 @@ export class SoilCellIndex {
117
90
  }
118
91
  }
119
92
  /**
120
- * The measurement as markdown table ROWS — what a build receipt carries, one line per element so a caller printing them
121
- * never has to split a joined string back apart.
93
+ * The measurement as markdown table rows, one line per element so a caller never
94
+ * has to split a joined string back apart.
122
95
  */
123
96
  export function formatSoilResolutionRows(measurements) {
124
97
  return [
@@ -1 +1 @@
1
- {"version":3,"file":"cells.js","sourceRoot":"","sources":["../../lib/sdk/cells.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cells.js","sourceRoot":"","sources":["../../sdk/cells.ts"],"names":[],"mappings":"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"}
@@ -2,46 +2,17 @@
2
2
  * @copyright Sister Software
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
- *
6
- * Soil Data Access — NRCS's live SQL service, and the two things this layer asks it: which survey areas
7
- * exist with what version date, and which map unit covers a point.
8
- *
9
- * THIS IS AN API REQUEST AND IT GOES THROUGH {@linkcode APIClient}. Small bodies, repeated calls, a
10
- * third-party host with a server-side query timeout and no published rate limit — the pacing, bounded
11
- * retry, response caching and `ResourceError` mapping are exactly what it needs. The survey-area
12
- * ARCHIVES are not: they are 13 to 41 MB file transfers, they stream to disk on raw `fetch`, and
13
- * `download.ts` says so in place.
14
- *
15
- * FAILURES COME BACK AS XML, INCLUDING ON A TIMEOUT, AND A JSON-ONLY PARSER MIS-READS THEM. A bad column,
16
- * a blocked query and a query that exceeded the server's own timeout all return an OGC
17
- * `ServiceExceptionReport` document. Measured messages: `Invalid query: Invalid column name
18
- * 'nosuchcolumn'.` (HTTP 400), `Invalid query - access denied.`, and `Your query timed out.` — and the
19
- * last one arrives on an HTTP 200. So every response is read as TEXT and checked for the report before
20
- * anything tries to parse it as JSON. A client that branched on the status code alone would read a
21
- * timeout as a successful empty answer, which is the exact shape of lie this program keeps writing down.
22
- *
23
- * SCHEMA INTROSPECTION IS REFUSED, SO THE COLUMN NAMES ARE THE PUBLISHED DATA DICTIONARY'S.
24
- * `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS` answers `Invalid query - access denied.` The
25
- * columns this file names were each verified by querying them successfully.
26
- *
27
- * FRESHNESS IS `sacatalog.saverest` AND NEVER A LENGTH PROBE. The download host answers `HEAD` with HTTP
28
- * 405 and IGNORES `Range` — a request with `Range: bytes=0-0` returned HTTP 200 and transferred the whole
29
- * 27,598,377 bytes — so "just check the size" starts a real download. The tabular service answers the
30
- * freshness question directly instead, and the version date it returns is what the archive's filename
31
- * embeds.
32
5
  */
33
6
  import { APIClient, type APIClientConfig, type ClockLike } from "@mailwoman/core/api";
7
+ import type { PathBuilderLike } from "path-ts";
34
8
  /**
35
- * The tabular endpoint. Anonymous: no key, no account, and no rate-limit header on any observed response.
9
+ * Sends anonymous requests to the Soil Data Access tabular query endpoint.
10
+ * Requests need no key or account.
36
11
  */
37
12
  export declare const SDA_POST_REST_URL = "https://sdmdataaccess.nrcs.usda.gov/Tabular/post.rest";
38
13
  /**
39
- * Minimum spacing between Soil Data Access requests, in milliseconds.
40
- *
41
- * NRCS publishes no rate limit for this service and returned no rate-limit header on any request, so this is courtesy
42
- * pacing rather than a published ceiling — stated as such rather than dressed up as a measured limit. It costs an
43
- * acquisition run nothing: a whole-state build makes one catalogue call, and the verification's per-point calls are
44
- * measured at 1.8 s each anyway.
14
+ * Sets the minimum spacing between Soil Data Access requests.
15
+ * NRCS publishes no rate limit for the service.
45
16
  */
46
17
  export declare const SDA_MIN_REQUEST_INTERVAL_MS = 500;
47
18
  /**
@@ -51,7 +22,8 @@ export interface SurveyAreaCatalogEntry {
51
22
  areasymbol: string;
52
23
  areaname: string;
53
24
  /**
54
- * The version-established date as an ISO date — what the archive's filename embeds.
25
+ * The version-established date as an ISO date.
26
+ * The survey area's archive filename embeds it.
55
27
  */
56
28
  saverest: string;
57
29
  saversion: number;
@@ -61,35 +33,38 @@ export interface SurveyAreaCatalogEntry {
61
33
  */
62
34
  export declare class SoilDataAccessClient extends APIClient<APIClientConfig> {
63
35
  /**
64
- * Run one query and return its rows.
36
+ * Runs one SQL query and returns its rows as strings, with NULL as an empty string.
65
37
  *
66
- * @throws {OGCServiceError} When the service answers with an exception report — including on an HTTP 200, which is
67
- * what a server-side timeout does.
38
+ * @throws {OGCServiceError} When the service answers with an exception report,
39
+ * including an HTTP 200 response.
40
+ * A server-side timeout uses that status.
68
41
  */
69
42
  query(sql: string): Promise<string[][]>;
70
43
  /**
71
- * The published survey areas whose symbol starts with `prefix` — a state code for a state-scoped build, or a whole
72
- * symbol for the single-area rung.
44
+ * Returns the published survey areas whose symbol starts with `prefix`,
45
+ * such as a state code or one whole area symbol.
73
46
  *
74
- * @throws {Error} When the catalogue returns nothing. An empty catalogue for a prefix a caller named is either a typo
75
- * or a service change, and building zero survey areas while reporting success is the shape this refuses.
47
+ * @throws {Error} When no survey area matches, because a build over an empty set
48
+ * would otherwise report success having written no rows.
76
49
  */
77
50
  readSurveyAreaCatalog(prefix: string): Promise<SurveyAreaCatalogEntry[]>;
78
51
  /**
79
- * Which map unit the service's OWN geometry assigns at a point, or `undefined` where it assigns none.
80
- *
81
- * This is the second path the built artifact is checked against: same authority, different distribution channel, and
82
- * geometry this package has never touched. Measured at 1.807 s per point, so a few hundred points is minutes.
52
+ * Returns the map unit key the service's own geometry assigns at a point, or `undefined`,
53
+ * as a cross-check against the authority through a channel this package never processed.
83
54
  */
84
55
  mukeyAtPoint(latitude: number, longitude: number): Promise<string | undefined>;
85
56
  }
57
+ /**
58
+ * Overrides the clock, the HTTP cache directory and the request spacing used
59
+ * by {@link createSoilDataAccessClient}.
60
+ */
86
61
  export interface CreateSoilDataAccessClientOptions {
87
62
  clock?: ClockLike;
88
- cacheDirectory?: string;
63
+ cacheDirectory?: PathBuilderLike;
89
64
  minRequestIntervalMs?: number;
90
65
  }
91
66
  /**
92
- * Build a {@link SoilDataAccessClient} with the disk cache and pacing this package's acquisition path expects.
67
+ * Creates a {@link SoilDataAccessClient} with retries, a 12-hour disk cache and the default request pacing.
93
68
  */
94
69
  export declare function createSoilDataAccessClient(options?: CreateSoilDataAccessClientOptions): SoilDataAccessClient;
95
70
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../lib/sdk/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,KAAK,SAAS,EAA+B,MAAM,qBAAqB,CAAA;AASlH;;GAEG;AACH,eAAO,MAAM,iBAAiB,0DAA0D,CAAA;AAExF;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAA;AAY9C;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,SAAS,CAAC,eAAe,CAAC;IACnE;;;;;OAKG;IACU,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;IA4BpD;;;;;;OAMG;IACU,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,EAAE,CAAC;IAqBrF;;;;;OAKG;IACU,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAO3F;AAED,MAAM,WAAW,iCAAiC;IACjD,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,GAAE,iCAAsC,GAAG,oBAAoB,CAahH"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../sdk/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,KAAK,SAAS,EAA+B,MAAM,qBAAqB,CAAA;AAGlH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAK9C;;;GAGG;AACH,eAAO,MAAM,iBAAiB,0DAA0D,CAAA;AAExF;;;GAGG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAA;AAI9C;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAEhB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,SAAS,CAAC,eAAe,CAAC;IACnE;;;;;;OAMG;IACU,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAuBnD;IAED;;;;;;OAMG;IACU,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAmBpF;IAED;;;OAGG;IACU,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAM1F;CACD;AAED;;;GAGG;AACH,MAAM,WAAW,iCAAiC;IACjD,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,cAAc,CAAC,EAAE,eAAe,CAAA;IAChC,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,GAAE,iCAAsC,GAAG,oBAAoB,CAahH"}
package/out/sdk/client.js CHANGED
@@ -2,86 +2,44 @@
2
2
  * @copyright Sister Software
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
- *
6
- * Soil Data Access — NRCS's live SQL service, and the two things this layer asks it: which survey areas
7
- * exist with what version date, and which map unit covers a point.
8
- *
9
- * THIS IS AN API REQUEST AND IT GOES THROUGH {@linkcode APIClient}. Small bodies, repeated calls, a
10
- * third-party host with a server-side query timeout and no published rate limit — the pacing, bounded
11
- * retry, response caching and `ResourceError` mapping are exactly what it needs. The survey-area
12
- * ARCHIVES are not: they are 13 to 41 MB file transfers, they stream to disk on raw `fetch`, and
13
- * `download.ts` says so in place.
14
- *
15
- * FAILURES COME BACK AS XML, INCLUDING ON A TIMEOUT, AND A JSON-ONLY PARSER MIS-READS THEM. A bad column,
16
- * a blocked query and a query that exceeded the server's own timeout all return an OGC
17
- * `ServiceExceptionReport` document. Measured messages: `Invalid query: Invalid column name
18
- * 'nosuchcolumn'.` (HTTP 400), `Invalid query - access denied.`, and `Your query timed out.` — and the
19
- * last one arrives on an HTTP 200. So every response is read as TEXT and checked for the report before
20
- * anything tries to parse it as JSON. A client that branched on the status code alone would read a
21
- * timeout as a successful empty answer, which is the exact shape of lie this program keeps writing down.
22
- *
23
- * SCHEMA INTROSPECTION IS REFUSED, SO THE COLUMN NAMES ARE THE PUBLISHED DATA DICTIONARY'S.
24
- * `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS` answers `Invalid query - access denied.` The
25
- * columns this file names were each verified by querying them successfully.
26
- *
27
- * FRESHNESS IS `sacatalog.saverest` AND NEVER A LENGTH PROBE. The download host answers `HEAD` with HTTP
28
- * 405 and IGNORES `Range` — a request with `Range: bytes=0-0` returned HTTP 200 and transferred the whole
29
- * 27,598,377 bytes — so "just check the size" starts a real download. The tabular service answers the
30
- * freshness question directly instead, and the version date it returns is what the archive's filename
31
- * embeds.
32
5
  */
33
6
  import { APIClient, assertNoOGCServiceException } from "@mailwoman/core/api";
34
7
  import { buildDiskStorage } from "@mailwoman/core/api/disk-storage";
35
- import { dataRootPath } from "@mailwoman/core/data-root";
36
- import { parseJSONStrict } from "@mailwoman/core/json";
8
+ import { parseJSONStrict, stringifyJSON } from "@mailwoman/core/json";
9
+ import { soilDatabasePath } from "#paths";
37
10
  import { saverestToISODate } from "#sdk/tabular";
38
- // Re-exported so a caller branching on this client's failures needs exactly one import.
39
11
  /**
40
- * The tabular endpoint. Anonymous: no key, no account, and no rate-limit header on any observed response.
12
+ * Sends anonymous requests to the Soil Data Access tabular query endpoint.
13
+ * Requests need no key or account.
41
14
  */
42
15
  export const SDA_POST_REST_URL = "https://sdmdataaccess.nrcs.usda.gov/Tabular/post.rest";
43
16
  /**
44
- * Minimum spacing between Soil Data Access requests, in milliseconds.
45
- *
46
- * NRCS publishes no rate limit for this service and returned no rate-limit header on any request, so this is courtesy
47
- * pacing rather than a published ceiling — stated as such rather than dressed up as a measured limit. It costs an
48
- * acquisition run nothing: a whole-state build makes one catalogue call, and the verification's per-point calls are
49
- * measured at 1.8 s each anyway.
17
+ * Sets the minimum spacing between Soil Data Access requests.
18
+ * NRCS publishes no rate limit for the service.
50
19
  */
51
20
  export const SDA_MIN_REQUEST_INTERVAL_MS = 500;
52
- /**
53
- * How long a cached Soil Data Access response stays fresh.
54
- *
55
- * Twelve hours, chosen against the product's cadence rather than a wall-clock intuition: NRCS performs ONE coordinated
56
- * Annual Soils Refresh, on October 1. Grouping `sacatalog` by year of `saverest` returns 2016: 1, 2025: 3,323, 2026: 56
57
- * — 98.3% of survey areas carry a single version date from one refresh rather than a per-area drift. A shorter TTL buys
58
- * nothing.
59
- */
60
21
  const SDA_CACHE_TTL_MS = 12 * 60 * 60 * 1000;
61
22
  /**
62
23
  * A client for Soil Data Access.
63
24
  */
64
25
  export class SoilDataAccessClient extends APIClient {
65
26
  /**
66
- * Run one query and return its rows.
27
+ * Runs one SQL query and returns its rows as strings, with NULL as an empty string.
67
28
  *
68
- * @throws {OGCServiceError} When the service answers with an exception report — including on an HTTP 200, which is
69
- * what a server-side timeout does.
29
+ * @throws {OGCServiceError} When the service answers with an exception report,
30
+ * including an HTTP 200 response.
31
+ * A server-side timeout uses that status.
70
32
  */
71
33
  async query(sql) {
72
34
  const { data } = await this.fetch({
73
35
  method: "POST",
74
36
  url: SDA_POST_REST_URL,
75
- // TEXT, not JSON, and that is the whole trap. A JSON response type hands a failure body to a JSON parser,
76
- // which either throws something unrelated to what went wrong or — on a 200 — yields nothing at all.
77
37
  responseType: "text",
78
38
  headers: { "Content-Type": "application/json" },
79
39
  data: { SERVICE: "query", FORMAT: "JSON", QUERY: sql },
80
40
  });
81
41
  assertNoOGCServiceException(data, `soil data access (query: ${sql.slice(0, 200)})`);
82
42
  const parsed = parseJSONStrict(data);
83
- // An answer with NO rows is `{}` rather than `{"Table":[]}`, so an absent `Table` is a real empty result and not a
84
- // read failure — the exception check above has already separated the two.
85
43
  if (parsed.Table === undefined)
86
44
  return [];
87
45
  if (!Array.isArray(parsed.Table)) {
@@ -90,17 +48,17 @@ export class SoilDataAccessClient extends APIClient {
90
48
  return parsed.Table.map((row) => row.map((value) => (value === null ? "" : String(value))));
91
49
  }
92
50
  /**
93
- * The published survey areas whose symbol starts with `prefix` — a state code for a state-scoped build, or a whole
94
- * symbol for the single-area rung.
51
+ * Returns the published survey areas whose symbol starts with `prefix`,
52
+ * such as a state code or one whole area symbol.
95
53
  *
96
- * @throws {Error} When the catalogue returns nothing. An empty catalogue for a prefix a caller named is either a typo
97
- * or a service change, and building zero survey areas while reporting success is the shape this refuses.
54
+ * @throws {Error} When no survey area matches, because a build over an empty set
55
+ * would otherwise report success having written no rows.
98
56
  */
99
57
  async readSurveyAreaCatalog(prefix) {
100
58
  const escaped = prefix.replaceAll("'", "''");
101
59
  const rows = await this.query(`SELECT areasymbol, areaname, saverest, saversion FROM sacatalog WHERE areasymbol LIKE '${escaped}%' ORDER BY areasymbol`);
102
60
  if (!rows.length) {
103
- throw new Error(`soil data access: the catalogue holds no survey area whose symbol starts with ${JSON.stringify(prefix)} — a build over an empty set would report success having written nothing`);
61
+ throw new Error(`soil data access: the catalogue holds no survey area whose symbol starts with ${stringifyJSON(prefix)} — a build over an empty set would report success having written nothing`);
104
62
  }
105
63
  return rows.map((row) => ({
106
64
  areasymbol: row[0],
@@ -110,10 +68,8 @@ export class SoilDataAccessClient extends APIClient {
110
68
  }));
111
69
  }
112
70
  /**
113
- * Which map unit the service's OWN geometry assigns at a point, or `undefined` where it assigns none.
114
- *
115
- * This is the second path the built artifact is checked against: same authority, different distribution channel, and
116
- * geometry this package has never touched. Measured at 1.807 s per point, so a few hundred points is minutes.
71
+ * Returns the map unit key the service's own geometry assigns at a point, or `undefined`,
72
+ * as a cross-check against the authority through a channel this package never processed.
117
73
  */
118
74
  async mukeyAtPoint(latitude, longitude) {
119
75
  const rows = await this.query(`SELECT mukey FROM SDA_Get_Mukey_from_intersection_with_WktWgs84('point(${longitude} ${latitude})')`);
@@ -121,7 +77,7 @@ export class SoilDataAccessClient extends APIClient {
121
77
  }
122
78
  }
123
79
  /**
124
- * Build a {@link SoilDataAccessClient} with the disk cache and pacing this package's acquisition path expects.
80
+ * Creates a {@link SoilDataAccessClient} with retries, a 12-hour disk cache and the default request pacing.
125
81
  */
126
82
  export function createSoilDataAccessClient(options = {}) {
127
83
  return new SoilDataAccessClient({
@@ -132,7 +88,7 @@ export function createSoilDataAccessClient(options = {}) {
132
88
  caching: {
133
89
  ttl: SDA_CACHE_TTL_MS,
134
90
  storage: buildDiskStorage({
135
- directory: options.cacheDirectory ?? String(dataRootPath("soil", "cache", "http")),
91
+ directory: (options.cacheDirectory ?? soilDatabasePath("cache", "http")).toString(),
136
92
  }),
137
93
  },
138
94
  });
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../lib/sdk/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../sdk/client.ts"],"names":[],"mappings":"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"}
@@ -2,56 +2,32 @@
2
2
  * @copyright Sister Software
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
- *
6
- * Acquire one survey area's published archive — 13 to 41 MB streamed to disk and unzipped.
7
- *
8
- * THE TRANSFER ITSELF LIVES IN `@mailwoman/core/utils`, and `streamToDisk` carries why a file transfer of
9
- * this size keeps raw `fetch` instead of going through `APIClient`, plus the `.part`-rename rule. What is
10
- * soil's, and stays here, is the URL shape, the cache key, and the two facts below that the shared
11
- * transfer is told rather than assumes: the progress stride and what a 400 means. The METADATA reads
12
- * around this one do go through `APIClient` — see `client.ts`.
13
- *
14
- * FRESHNESS IS `sacatalog.saverest`, NEVER A LENGTH PROBE, AND THE HOST LEAVES NO CHOICE. It answers `HEAD`
15
- * with HTTP 405 (`allow: GET`) and IGNORES `Range`: a request with `Range: bytes=0-0` returned HTTP 200 and
16
- * transferred the whole 27,598,377 bytes in 7.23 s. So "check the size first" starts a real download. The
17
- * cache is keyed on the version date the tabular service reports instead, and a vintage already on disk is
18
- * never re-fetched. The `Range` behaviour is PATH-SPECIFIC rather than host-wide — `/DataAvailability/`
19
- * does answer 206 — so a client must probe per path rather than conclude from one.
20
- *
21
- * THE FILENAME EMBEDS THE VERSION DATE AND A WRONG ONE IS AN HTTP 400. Not a 404: asking for a date the
22
- * host does not hold reads as a malformed request rather than a missing file, which is why the date comes
23
- * from the catalogue rather than from a guess. The square brackets must be sent literally, so the URL is
24
- * built with them percent-encoded.
25
- *
26
- * TWO CACHE VARIANTS EXIST AND THE BARE ONE IS WANTED. `wss_SSA_IA153_[2025-09-09].zip` is 25,474,922 bytes;
27
- * `wss_SSA_IA153_soildb_IA_2003_[2025-09-09].zip` is 27,598,377 and differs only by an EMPTY Microsoft Access
28
- * template container for a workflow this program does not use. Confirmed on a second area (`IA015`:
29
- * 38,981,269 against 41,104,724 bytes) and on a third that ships no template at all (`TX299`, 13,455,641
30
- * bytes, 97 files, no `.mdb`).
31
5
  */
6
+ import { PathBuilder, type PathBuilderLike } from "path-ts";
32
7
  /**
33
- * The download service's survey-area cache. Documented at `https://websoilsurvey.sc.egov.usda.gov/DSD/Download/help`,
34
- * which lists `GET /{CacheName}/{FileName}`.
8
+ * Points to the Web Soil Survey download cache that serves survey-area archives.
35
9
  */
36
10
  export declare const WSS_SSA_CACHE_URL = "https://websoilsurvey.sc.egov.usda.gov/DSD/Download/Cache/SSA";
37
11
  /**
38
- * The archive URL for one survey area at one version date.
39
- *
40
- * The brackets are percent-encoded rather than sent raw: they are not valid in a URL path, and a client that sends them
41
- * literally depends on the fetcher tolerating them.
12
+ * Returns the archive URL for one survey area at one version date, with the brackets
13
+ * around the date percent-encoded because they are not valid in a URL path.
42
14
  */
43
15
  export declare function surveyAreaArchiveURL(areaSymbol: string, versionDate: string): string;
16
+ /**
17
+ * Configures {@link downloadSurveyArea}, which caches the archive and its
18
+ * extracted tree under `cacheRoot/<versionDate>`.
19
+ */
44
20
  export interface DownloadSurveyAreaOptions {
45
21
  areaSymbol: string;
46
22
  /**
47
- * The version date from `sacatalog.saverest`, as `YYYY-MM-DD`.
23
+ * The survey area's version date from `sacatalog.saverest`, formatted as `YYYY-MM-DD`.
48
24
  */
49
25
  versionDate: string;
50
26
  /**
51
- * Where vintages are kept. Each version date gets its own directory, so a new refresh never overwrites the old one in
52
- * place and a re-run against the same vintage never re-transfers.
27
+ * The cache directory, where each version date gets its own subdirectory so a new
28
+ * vintage never overwrites an old one and a repeat run downloads no file.
53
29
  */
54
- cacheRoot: string;
30
+ cacheRoot: PathBuilderLike;
55
31
  onProgress?: (message: string) => void;
56
32
  }
57
33
  /**
@@ -61,24 +37,25 @@ export interface SurveyAreaArchive {
61
37
  areaSymbol: string;
62
38
  versionDate: string;
63
39
  /**
64
- * The extracted `<areasymbol>/` directory, holding `spatial/` and `tabular/`.
40
+ * The extracted `<areasymbol>/` directory.
41
+ * It contains `spatial/` and `tabular/`.
65
42
  */
66
- root: string;
67
- spatialDirectory: string;
68
- tabularDirectory: string;
43
+ root: PathBuilder;
44
+ spatialDirectory: PathBuilder;
45
+ tabularDirectory: PathBuilder;
69
46
  /**
70
- * The archive as transferred. Kept so a re-run costs nothing and so the bytes are re-checkable.
47
+ * The downloaded ZIP archive, kept so a repeat run skips the transfer and the bytes can be rechecked.
71
48
  */
72
- archivePath: string;
49
+ archivePath: PathBuilder;
73
50
  }
74
51
  /**
75
- * Download and unzip one survey area, returning where its pieces landed.
52
+ * Downloads and unzips one survey area into the cache, skipping completed steps.
53
+ * Returns the paths to its files.
76
54
  *
77
- * Downloads to a `.part` file and renames only on a clean finish, so an interrupted transfer never presents as a
78
- * complete archive — the same discipline the database build uses, for the same reason.
55
+ * The download goes through a `.part` file so an interrupted transfer never looks like a complete archive.
79
56
  *
80
- * @throws {Error} When the host answers anything but 200, or when the extracted tree does not hold the two directories
81
- * every survey area publishes.
57
+ * @throws {Error} When the host answers anything but 200, or when the extracted
58
+ * tree lacks the `spatial` or `tabular` directory.
82
59
  */
83
60
  export declare function downloadSurveyArea(options: DownloadSurveyAreaOptions): Promise<SurveyAreaArchive>;
84
61
  //# sourceMappingURL=download.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../lib/sdk/download.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAQH;;;GAGG;AACH,eAAO,MAAM,iBAAiB,kEAAkE,CAAA;AAEhG;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAEpF;AAED,MAAM,WAAW,yBAAyB;IACzC,UAAU,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACtC;AAcD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,MAAM,CAAA;IACxB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAqDvG"}
1
+ {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../sdk/download.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAA;AAE3D;;GAEG;AACH,eAAO,MAAM,iBAAiB,kEAAkE,CAAA;AAEhG;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAEpF;AAED;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACzC,UAAU,EAAE,MAAM,CAAA;IAElB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IAEnB;;;OAGG;IACH,SAAS,EAAE,eAAe,CAAA;IAC1B,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACtC;AAMD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IAEnB;;;OAGG;IACH,IAAI,EAAE,WAAW,CAAA;IACjB,gBAAgB,EAAE,WAAW,CAAA;IAC7B,gBAAgB,EAAE,WAAW,CAAA;IAE7B;;OAEG;IACH,WAAW,EAAE,WAAW,CAAA;CACxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAmDvG"}