laterite 0.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/index.d.ts ADDED
@@ -0,0 +1,168 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /* auto-generated by NAPI-RS */
5
+
6
+ /**
7
+ * AGS spec type code → canonical category label (`"string"`, `"integer"`,
8
+ * `"decimal"`, `"datetime"`, `"date"`, `"time"`, `"bool"`, `"enum"`), or `null`
9
+ * for unknown codes (the TS wrapper re-raises as an error).
10
+ */
11
+ export declare function canonicalType(agsType: string): string | null
12
+ /**
13
+ * Presentation hint for a numeric AGS type: `"2DP"` → `"%.2f"`, `"3SF"` →
14
+ * `"%.3g"`, `"1SCI"` → `"%.1e"`; `null` for non-numeric / unknown codes.
15
+ */
16
+ export declare function displayHint(agsType: string): string | null
17
+ /**
18
+ * Parse an AGS4-shaped raw string into its canonical value — the same engine
19
+ * the read path uses. Permissive: empty / unparseable → `null`. Returns native
20
+ * JS: integer/decimal → number, bool → boolean, string/enum → string,
21
+ * **datetime/date/time → the canonical string** (`"YYYY-MM-DD HH:MM:SS"` /
22
+ * `"YYYY-MM-DD"` / `"HH:MM:SS"`), unknown code → the trimmed input.
23
+ */
24
+ export declare function parseValue(raw: string | undefined | null, agsType: string): any
25
+ /**
26
+ * Result of `transportPack` / `transportLock`: output size, ratio vs source,
27
+ * elapsed seconds.
28
+ */
29
+ export interface PackStats {
30
+ bytes: bigint
31
+ ratio: number
32
+ elapsedS: number
33
+ }
34
+ /** Result of `transportUnpack` / `transportUnlock`: output size, elapsed seconds. */
35
+ export interface UnpackStats {
36
+ bytes: bigint
37
+ elapsedS: number
38
+ }
39
+ /** zstd-compress `src` → `dest`. `level` is 1–22 (default 9, the AGS sweet spot). */
40
+ export declare function transportPack(src: string, dest: string, level?: number | undefined | null): PackStats
41
+ /** zstd-decompress `src` → `dest`. */
42
+ export declare function transportUnpack(src: string, dest: string): UnpackStats
43
+ /**
44
+ * zstd-compress, then age-encrypt with `password` → `dest`. Compress-then-
45
+ * encrypt is load-bearing: zstd needs low-entropy input; ciphertext is random.
46
+ */
47
+ export declare function transportLock(src: string, dest: string, password: string, level?: number | undefined | null): PackStats
48
+ /**
49
+ * age-decrypt with `password`, then zstd-decompress → `dest`. Wrong passphrase
50
+ * / non-passphrase envelopes surface as an error.
51
+ */
52
+ export declare function transportUnlock(src: string, dest: string, password: string): UnpackStats
53
+ /** The crate version. */
54
+ export declare function version(): string
55
+ /** Per-group schema — parallel arrays, one entry per heading. */
56
+ export interface GroupMeta {
57
+ headings: Array<string>
58
+ units: Array<string>
59
+ /** AGS TYPE codes from the file's TYPE row (e.g. "2DP", "DT", "ID"). */
60
+ types: Array<string>
61
+ /**
62
+ * The SQL/DuckDB column type each heading lands as ("DOUBLE", "BIGINT",
63
+ * "TIMESTAMP", "VARCHAR", …).
64
+ */
65
+ sqlTypes: Array<string>
66
+ /** 1-indexed source line of each DATA row (parallel to the group's rows). */
67
+ lineNumbers: Array<number>
68
+ }
69
+ /**
70
+ * Parse an AGS4 file (`path`) or in-memory `text` into a `Reading` handle.
71
+ * `encoding`: `"utf-8"` (default) / `"windows-1252"` / a label. Throws the
72
+ * classified `kind␟code␟message` (see the error-protocol note) on bad input.
73
+ */
74
+ export declare function parseArrow(path?: string | undefined | null, text?: string | undefined | null, encoding?: string | undefined | null): Reading
75
+ /** One rule violation (omitting `severity` ⇒ error, matching the engine). */
76
+ export interface Finding {
77
+ rule: string
78
+ line?: number
79
+ group: string
80
+ desc: string
81
+ severity?: string
82
+ }
83
+ /**
84
+ * The validation report — the Node mirror of laterite-py's `run_check` dict.
85
+ * `ok` is **false only for un-validatable input** (the TS `raiseFor` raises
86
+ * then); rule *violations* come back in `findings` with `ok:true`. `Report`'s
87
+ * `isValid` is the separate `count == 0`. `json`/`ndjson` are byte-identical
88
+ * to `ags4-check --json` / `--ndjson`.
89
+ */
90
+ export interface ValidationReport {
91
+ ok: boolean
92
+ /**
93
+ * Set (with `error`) only when `ok` is false — the failure kind the TS
94
+ * `raiseFor` maps to an exception (`not_ags4`, `unsupported_edition`, …).
95
+ */
96
+ errorKind?: string
97
+ error?: string
98
+ /**
99
+ * Mirrors the `ags4-check` binary: 0 valid / 1 findings on success;
100
+ * 3 not-found/io, 4 not-utf8/not-ags4/bad-edition, 5 bad-dict on failure.
101
+ */
102
+ exitCode: number
103
+ file: string
104
+ dictVersion: string
105
+ resolution: string
106
+ count: number
107
+ findings: Array<Finding>
108
+ json: string
109
+ ndjson: string
110
+ }
111
+ /**
112
+ * Validate an AGS4 file (`path`) or `text` against the AGS4 rules. `dict_version`
113
+ * `None`/`"auto"` auto-detects from `TRAN_AGS`, else forces an edition. Returns
114
+ * the `{ok:false}` failure report (not a throw) for un-validatable input.
115
+ */
116
+ export declare function runCheck(path?: string | undefined | null, text?: string | undefined | null, dictVersion?: string | undefined | null, includeWarnings?: boolean | undefined | null, includeFyi?: boolean | undefined | null, checkFiles?: boolean | undefined | null, encoding?: string | undefined | null): ValidationReport
117
+ /**
118
+ * One group of columnar input — its code + an Arrow IPC stream (`Buffer`)
119
+ * whose column names are the AGS headings.
120
+ */
121
+ export interface GroupIpc {
122
+ code: string
123
+ ipc: Buffer
124
+ }
125
+ /**
126
+ * The emit result. `bytes` is the AGS4 document; `findingsJson` is the
127
+ * validator's `{rule:[…]}` map on the output; `fixesApplied` counts safe fixes.
128
+ */
129
+ export interface EmitResult {
130
+ bytes: Buffer
131
+ findingsJson: string
132
+ fixesApplied: number
133
+ }
134
+ /**
135
+ * Build valid AGS4 from per-group **Arrow IPC** streams (the columnar
136
+ * producer; the read boundary reversed). = `ags4-wasm`'s `to_ags4_ipc`.
137
+ */
138
+ export declare function emitAgs4FromIpc(groups: Array<GroupIpc>, edition?: string | undefined | null, mode?: string | undefined | null): EmitResult
139
+ /**
140
+ * A parsed AGS4 file held native-side — the Node analog of laterite-py's
141
+ * `Reading` handle (and `ags4-wasm`'s `ParsedDataset`). Each group's typed
142
+ * `RecordBatch` is built lazily on `tableIpc(code)` and dropped after the
143
+ * bytes are returned, so peak residency is one batch.
144
+ */
145
+ export declare class Reading {
146
+ /** Group codes in file order (the order to load tables in). */
147
+ groupCodes(): Array<string>
148
+ /** The file's `TRAN_AGS` edition string, if present. */
149
+ get tranAgs(): string | null
150
+ /**
151
+ * `{headings, units, types, sqlTypes}` for one group, or `null` if the
152
+ * code isn't present. No Arrow built — cheap metadata only.
153
+ */
154
+ meta(code: string): GroupMeta | null
155
+ /**
156
+ * One group's rows as an Arrow **IPC stream** (`Buffer`), columns already
157
+ * correctly typed. The Node analog of the pyo3-arrow capsule: the typed
158
+ * columns come from the one shared emitter (`ags5_types::arrow_cols`), the
159
+ * SAME casting Python/wasm use — so a file types byte-identically across
160
+ * hosts. Returns `null` if the code isn't in the file.
161
+ */
162
+ tableIpc(code: string): Buffer | null
163
+ /**
164
+ * Re-emit byte-faithful AGS4 text from the retained parse (the raw DATA
165
+ * values, unchanged). = laterite-py's `Reading::emit`.
166
+ */
167
+ emit(): string
168
+ }
package/index.js ADDED
@@ -0,0 +1,326 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /* prettier-ignore */
4
+
5
+ /* auto-generated by NAPI-RS */
6
+
7
+ const { existsSync, readFileSync } = require('fs')
8
+ const { join } = require('path')
9
+
10
+ const { platform, arch } = process
11
+
12
+ let nativeBinding = null
13
+ let localFileExisted = false
14
+ let loadError = null
15
+
16
+ function isMusl() {
17
+ // For Node 10
18
+ if (!process.report || typeof process.report.getReport !== 'function') {
19
+ try {
20
+ const lddPath = require('child_process').execSync('which ldd').toString().trim()
21
+ return readFileSync(lddPath, 'utf8').includes('musl')
22
+ } catch (e) {
23
+ return true
24
+ }
25
+ } else {
26
+ const { glibcVersionRuntime } = process.report.getReport().header
27
+ return !glibcVersionRuntime
28
+ }
29
+ }
30
+
31
+ switch (platform) {
32
+ case 'android':
33
+ switch (arch) {
34
+ case 'arm64':
35
+ localFileExisted = existsSync(join(__dirname, 'laterite-node.android-arm64.node'))
36
+ try {
37
+ if (localFileExisted) {
38
+ nativeBinding = require('./laterite-node.android-arm64.node')
39
+ } else {
40
+ nativeBinding = require('@laterite/native-android-arm64')
41
+ }
42
+ } catch (e) {
43
+ loadError = e
44
+ }
45
+ break
46
+ case 'arm':
47
+ localFileExisted = existsSync(join(__dirname, 'laterite-node.android-arm-eabi.node'))
48
+ try {
49
+ if (localFileExisted) {
50
+ nativeBinding = require('./laterite-node.android-arm-eabi.node')
51
+ } else {
52
+ nativeBinding = require('@laterite/native-android-arm-eabi')
53
+ }
54
+ } catch (e) {
55
+ loadError = e
56
+ }
57
+ break
58
+ default:
59
+ throw new Error(`Unsupported architecture on Android ${arch}`)
60
+ }
61
+ break
62
+ case 'win32':
63
+ switch (arch) {
64
+ case 'x64':
65
+ localFileExisted = existsSync(
66
+ join(__dirname, 'laterite-node.win32-x64-msvc.node')
67
+ )
68
+ try {
69
+ if (localFileExisted) {
70
+ nativeBinding = require('./laterite-node.win32-x64-msvc.node')
71
+ } else {
72
+ nativeBinding = require('@laterite/native-win32-x64-msvc')
73
+ }
74
+ } catch (e) {
75
+ loadError = e
76
+ }
77
+ break
78
+ case 'ia32':
79
+ localFileExisted = existsSync(
80
+ join(__dirname, 'laterite-node.win32-ia32-msvc.node')
81
+ )
82
+ try {
83
+ if (localFileExisted) {
84
+ nativeBinding = require('./laterite-node.win32-ia32-msvc.node')
85
+ } else {
86
+ nativeBinding = require('@laterite/native-win32-ia32-msvc')
87
+ }
88
+ } catch (e) {
89
+ loadError = e
90
+ }
91
+ break
92
+ case 'arm64':
93
+ localFileExisted = existsSync(
94
+ join(__dirname, 'laterite-node.win32-arm64-msvc.node')
95
+ )
96
+ try {
97
+ if (localFileExisted) {
98
+ nativeBinding = require('./laterite-node.win32-arm64-msvc.node')
99
+ } else {
100
+ nativeBinding = require('@laterite/native-win32-arm64-msvc')
101
+ }
102
+ } catch (e) {
103
+ loadError = e
104
+ }
105
+ break
106
+ default:
107
+ throw new Error(`Unsupported architecture on Windows: ${arch}`)
108
+ }
109
+ break
110
+ case 'darwin':
111
+ localFileExisted = existsSync(join(__dirname, 'laterite-node.darwin-universal.node'))
112
+ try {
113
+ if (localFileExisted) {
114
+ nativeBinding = require('./laterite-node.darwin-universal.node')
115
+ } else {
116
+ nativeBinding = require('@laterite/native-darwin-universal')
117
+ }
118
+ break
119
+ } catch {}
120
+ switch (arch) {
121
+ case 'x64':
122
+ localFileExisted = existsSync(join(__dirname, 'laterite-node.darwin-x64.node'))
123
+ try {
124
+ if (localFileExisted) {
125
+ nativeBinding = require('./laterite-node.darwin-x64.node')
126
+ } else {
127
+ nativeBinding = require('@laterite/native-darwin-x64')
128
+ }
129
+ } catch (e) {
130
+ loadError = e
131
+ }
132
+ break
133
+ case 'arm64':
134
+ localFileExisted = existsSync(
135
+ join(__dirname, 'laterite-node.darwin-arm64.node')
136
+ )
137
+ try {
138
+ if (localFileExisted) {
139
+ nativeBinding = require('./laterite-node.darwin-arm64.node')
140
+ } else {
141
+ nativeBinding = require('@laterite/native-darwin-arm64')
142
+ }
143
+ } catch (e) {
144
+ loadError = e
145
+ }
146
+ break
147
+ default:
148
+ throw new Error(`Unsupported architecture on macOS: ${arch}`)
149
+ }
150
+ break
151
+ case 'freebsd':
152
+ if (arch !== 'x64') {
153
+ throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
154
+ }
155
+ localFileExisted = existsSync(join(__dirname, 'laterite-node.freebsd-x64.node'))
156
+ try {
157
+ if (localFileExisted) {
158
+ nativeBinding = require('./laterite-node.freebsd-x64.node')
159
+ } else {
160
+ nativeBinding = require('@laterite/native-freebsd-x64')
161
+ }
162
+ } catch (e) {
163
+ loadError = e
164
+ }
165
+ break
166
+ case 'linux':
167
+ switch (arch) {
168
+ case 'x64':
169
+ if (isMusl()) {
170
+ localFileExisted = existsSync(
171
+ join(__dirname, 'laterite-node.linux-x64-musl.node')
172
+ )
173
+ try {
174
+ if (localFileExisted) {
175
+ nativeBinding = require('./laterite-node.linux-x64-musl.node')
176
+ } else {
177
+ nativeBinding = require('@laterite/native-linux-x64-musl')
178
+ }
179
+ } catch (e) {
180
+ loadError = e
181
+ }
182
+ } else {
183
+ localFileExisted = existsSync(
184
+ join(__dirname, 'laterite-node.linux-x64-gnu.node')
185
+ )
186
+ try {
187
+ if (localFileExisted) {
188
+ nativeBinding = require('./laterite-node.linux-x64-gnu.node')
189
+ } else {
190
+ nativeBinding = require('@laterite/native-linux-x64-gnu')
191
+ }
192
+ } catch (e) {
193
+ loadError = e
194
+ }
195
+ }
196
+ break
197
+ case 'arm64':
198
+ if (isMusl()) {
199
+ localFileExisted = existsSync(
200
+ join(__dirname, 'laterite-node.linux-arm64-musl.node')
201
+ )
202
+ try {
203
+ if (localFileExisted) {
204
+ nativeBinding = require('./laterite-node.linux-arm64-musl.node')
205
+ } else {
206
+ nativeBinding = require('@laterite/native-linux-arm64-musl')
207
+ }
208
+ } catch (e) {
209
+ loadError = e
210
+ }
211
+ } else {
212
+ localFileExisted = existsSync(
213
+ join(__dirname, 'laterite-node.linux-arm64-gnu.node')
214
+ )
215
+ try {
216
+ if (localFileExisted) {
217
+ nativeBinding = require('./laterite-node.linux-arm64-gnu.node')
218
+ } else {
219
+ nativeBinding = require('@laterite/native-linux-arm64-gnu')
220
+ }
221
+ } catch (e) {
222
+ loadError = e
223
+ }
224
+ }
225
+ break
226
+ case 'arm':
227
+ if (isMusl()) {
228
+ localFileExisted = existsSync(
229
+ join(__dirname, 'laterite-node.linux-arm-musleabihf.node')
230
+ )
231
+ try {
232
+ if (localFileExisted) {
233
+ nativeBinding = require('./laterite-node.linux-arm-musleabihf.node')
234
+ } else {
235
+ nativeBinding = require('@laterite/native-linux-arm-musleabihf')
236
+ }
237
+ } catch (e) {
238
+ loadError = e
239
+ }
240
+ } else {
241
+ localFileExisted = existsSync(
242
+ join(__dirname, 'laterite-node.linux-arm-gnueabihf.node')
243
+ )
244
+ try {
245
+ if (localFileExisted) {
246
+ nativeBinding = require('./laterite-node.linux-arm-gnueabihf.node')
247
+ } else {
248
+ nativeBinding = require('@laterite/native-linux-arm-gnueabihf')
249
+ }
250
+ } catch (e) {
251
+ loadError = e
252
+ }
253
+ }
254
+ break
255
+ case 'riscv64':
256
+ if (isMusl()) {
257
+ localFileExisted = existsSync(
258
+ join(__dirname, 'laterite-node.linux-riscv64-musl.node')
259
+ )
260
+ try {
261
+ if (localFileExisted) {
262
+ nativeBinding = require('./laterite-node.linux-riscv64-musl.node')
263
+ } else {
264
+ nativeBinding = require('@laterite/native-linux-riscv64-musl')
265
+ }
266
+ } catch (e) {
267
+ loadError = e
268
+ }
269
+ } else {
270
+ localFileExisted = existsSync(
271
+ join(__dirname, 'laterite-node.linux-riscv64-gnu.node')
272
+ )
273
+ try {
274
+ if (localFileExisted) {
275
+ nativeBinding = require('./laterite-node.linux-riscv64-gnu.node')
276
+ } else {
277
+ nativeBinding = require('@laterite/native-linux-riscv64-gnu')
278
+ }
279
+ } catch (e) {
280
+ loadError = e
281
+ }
282
+ }
283
+ break
284
+ case 's390x':
285
+ localFileExisted = existsSync(
286
+ join(__dirname, 'laterite-node.linux-s390x-gnu.node')
287
+ )
288
+ try {
289
+ if (localFileExisted) {
290
+ nativeBinding = require('./laterite-node.linux-s390x-gnu.node')
291
+ } else {
292
+ nativeBinding = require('@laterite/native-linux-s390x-gnu')
293
+ }
294
+ } catch (e) {
295
+ loadError = e
296
+ }
297
+ break
298
+ default:
299
+ throw new Error(`Unsupported architecture on Linux: ${arch}`)
300
+ }
301
+ break
302
+ default:
303
+ throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
304
+ }
305
+
306
+ if (!nativeBinding) {
307
+ if (loadError) {
308
+ throw loadError
309
+ }
310
+ throw new Error(`Failed to load native binding`)
311
+ }
312
+
313
+ const { canonicalType, displayHint, parseValue, transportPack, transportUnpack, transportLock, transportUnlock, version, Reading, parseArrow, runCheck, emitAgs4FromIpc } = nativeBinding
314
+
315
+ module.exports.canonicalType = canonicalType
316
+ module.exports.displayHint = displayHint
317
+ module.exports.parseValue = parseValue
318
+ module.exports.transportPack = transportPack
319
+ module.exports.transportUnpack = transportUnpack
320
+ module.exports.transportLock = transportLock
321
+ module.exports.transportUnlock = transportUnlock
322
+ module.exports.version = version
323
+ module.exports.Reading = Reading
324
+ module.exports.parseArrow = parseArrow
325
+ module.exports.runCheck = runCheck
326
+ module.exports.emitAgs4FromIpc = emitAgs4FromIpc
package/package.json ADDED
@@ -0,0 +1,100 @@
1
+ {
2
+ "name": "laterite",
3
+ "version": "0.1.0",
4
+ "description": "AGS4 geotechnical data for Node.js — read, validate, produce, and query (the Node port of the laterite Python toolkit, Rust-backed).",
5
+ "license": "MIT",
6
+ "author": "niko86",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/niko86/laterite.git",
10
+ "directory": "rust-packages/laterite-node"
11
+ },
12
+ "homepage": "https://github.com/niko86/laterite#readme",
13
+ "keywords": [
14
+ "ags4",
15
+ "ags",
16
+ "geotechnical",
17
+ "validator",
18
+ "arrow",
19
+ "napi",
20
+ "rust"
21
+ ],
22
+ "type": "commonjs",
23
+ "main": "./dist/index.cjs",
24
+ "module": "./dist/index.mjs",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.mjs",
30
+ "require": "./dist/index.cjs"
31
+ },
32
+ "./package.json": "./package.json"
33
+ },
34
+ "imports": {
35
+ "#native": {
36
+ "types": "./index.d.ts",
37
+ "default": "./index.js"
38
+ }
39
+ },
40
+ "files": [
41
+ "dist",
42
+ "index.js",
43
+ "index.d.ts",
44
+ "README.md"
45
+ ],
46
+ "publishConfig": {
47
+ "access": "public"
48
+ },
49
+ "napi": {
50
+ "name": "laterite-node",
51
+ "package": {
52
+ "name": "@laterite/native"
53
+ },
54
+ "triples": {
55
+ "defaults": false,
56
+ "additional": [
57
+ "x86_64-unknown-linux-gnu",
58
+ "aarch64-apple-darwin",
59
+ "x86_64-pc-windows-msvc"
60
+ ]
61
+ }
62
+ },
63
+ "engines": {
64
+ "node": ">=18"
65
+ },
66
+ "scripts": {
67
+ "build": "napi build --platform --release && npm run build:ts",
68
+ "build:debug": "napi build --platform && npm run build:ts",
69
+ "build:ts": "tsup",
70
+ "artifacts": "napi artifacts",
71
+ "smoke:pack": "node tools/pack-smoke.mjs",
72
+ "prepublish:napi": "napi prepublish -t npm --skip-gh-release",
73
+ "test": "vitest run",
74
+ "typecheck": "tsc --noEmit"
75
+ },
76
+ "dependencies": {
77
+ "apache-arrow": "^21.1.0"
78
+ },
79
+ "optionalDependencies": {
80
+ "@laterite/native-linux-x64-gnu": "0.1.0",
81
+ "@laterite/native-darwin-arm64": "0.1.0",
82
+ "@laterite/native-win32-x64-msvc": "0.1.0"
83
+ },
84
+ "peerDependencies": {
85
+ "@duckdb/node-api": ">=1.5.0"
86
+ },
87
+ "peerDependenciesMeta": {
88
+ "@duckdb/node-api": {
89
+ "optional": true
90
+ }
91
+ },
92
+ "devDependencies": {
93
+ "@duckdb/node-api": "^1.5.3-r.3",
94
+ "@napi-rs/cli": "^2.18.4",
95
+ "@types/node": "^25.9.3",
96
+ "tsup": "^8.5.0",
97
+ "typescript": "^6.0.3",
98
+ "vitest": "^4.1.8"
99
+ }
100
+ }