@balq/node 0.1.1
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/README.md +80 -0
- package/index.d.ts +165 -0
- package/index.js +704 -0
- package/lib.d.ts +36 -0
- package/lib.js +119 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @balq/node
|
|
2
|
+
|
|
3
|
+
Node.js bindings for [balq](../../README.md): a local, verified archive of
|
|
4
|
+
contract storage built from EIP-7928 Block-Level Access Lists. In-process
|
|
5
|
+
(napi-rs), no HTTP hop; reads stay available while `sync()` runs.
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
const { Archive, Layout, NotAvailableError } = require("@balq/node");
|
|
9
|
+
|
|
10
|
+
const ar = Archive.open("./balq.redb", { proofWindow: 0 });
|
|
11
|
+
ar.watch("0x3582…53ce", 114563); // from >= head + 1
|
|
12
|
+
await ar.sync("http://localhost:8545"); // fetch → verify → apply; returns a SyncReport
|
|
13
|
+
|
|
14
|
+
const v = ar.storageAt("0x3582…53ce", "0", 114591);
|
|
15
|
+
// { value: "0x…0c", provenance: "bal", setAt: 114590, index: 125 }
|
|
16
|
+
|
|
17
|
+
const layout = Layout.fromFile("./out/Playground.sol/Playground.json"); // forge artifact or bare storageLayout
|
|
18
|
+
const loc = layout.locate("balances[0x61Cc…ca80]");
|
|
19
|
+
layout.decode(loc, ar.storageAt("0x3582…53ce", loc.slot, 114591).value); // "37585"
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
ar.storageAt("0x3582…53ce", "0", 114500);
|
|
23
|
+
} catch (e) {
|
|
24
|
+
if (e instanceof NotAvailableError) console.log(e.code); // "BeforeStart" — never null
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Every miss is a `NotAvailableError` with `code` ∈ `NotWatched | BeforeStart |
|
|
29
|
+
AfterHead | NotSynced | NotBootstrapped | BootstrapPending | BootstrapLost |
|
|
30
|
+
Internal`. Numbers are JS numbers (block heights fit); words, slots and
|
|
31
|
+
addresses are 0x-hex strings.
|
|
32
|
+
|
|
33
|
+
## API
|
|
34
|
+
|
|
35
|
+
| | |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `Archive.open(path, {proofWindow?, fullDetail?, allowUnverified?})` | open or create |
|
|
38
|
+
| `watch(addr, fromBlock)` / `unwatch(addr)` / `watchlist()` / `head()` | watchlist and head |
|
|
39
|
+
| `sync(rpcUrl, bootstrap = true, backupRpc?): Promise<SyncReport>` | one pass to the node's head; `backupRpc` (any archive provider) is asked only when `rpcUrl` lacks a BAL or cannot prove a slot, and is verified the same way |
|
|
40
|
+
| `storageAt(addr, slot, block): StorageValue` | one ordered seek |
|
|
41
|
+
| `history(addr, slot, from, to): HistoryEntry[]` | changes in `[from, to)` |
|
|
42
|
+
| `changedSlots(addr, block): string[]` | from the block index |
|
|
43
|
+
| `bootstrapSlot(rpcUrl, addr, slot, backupRpc?): Promise<void>` | prove a never-changed slot at head |
|
|
44
|
+
| `Layout.fromFile(path)` / `Layout.fromJson(s)` | solc storageLayout |
|
|
45
|
+
| `locate(path)` / `decode(loc, word)` / `describeSlot(slot)` / `fields()` | names ↔ slots |
|
|
46
|
+
|
|
47
|
+
## Build locally
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
npm ci
|
|
51
|
+
npx napi build --platform # needs Node >= 20.12 for the CLI; the module itself runs on >= 18
|
|
52
|
+
node test/smoke.mjs # against ../../testbed/balq.redb
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Zero logic lives in this crate — see `src/lib.rs`: argument conversion,
|
|
56
|
+
one call into `bal-archive` / `bal-layout`, result conversion.
|
|
57
|
+
|
|
58
|
+
## Reading by name: `view`
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
const view = ar.view(proxy, layout).at(114591); // storage as of the end of block 114591
|
|
62
|
+
|
|
63
|
+
view.counter // 12n
|
|
64
|
+
view.balances[addr] // 37585n
|
|
65
|
+
view.nested[addr][7] // 0x… (raw word if the layout cannot decode it)
|
|
66
|
+
view.totals.index // 5000000000000000146n
|
|
67
|
+
view.items[3] // …
|
|
68
|
+
view.items.length // 8n
|
|
69
|
+
view.c // true
|
|
70
|
+
view.lastPoker // "0x61Cc…"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Integers are `bigint`, bools `boolean`, addresses / bytes / undecodable
|
|
74
|
+
words `string`. A missing value throws `NotAvailableError` (never
|
|
75
|
+
`undefined`); an unknown field throws at access time.
|
|
76
|
+
|
|
77
|
+
Types: `balq typegen out/Playground.sol/Playground.json > Playground.d.ts`
|
|
78
|
+
(or `layout.typescript("PlaygroundView")`), then
|
|
79
|
+
`ar.view(proxy, layout).at<PlaygroundView>(block)` — misspelled fields
|
|
80
|
+
fail at compile time.
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/* auto-generated by NAPI-RS */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/** The archive. Safe to read from while `sync()` is in flight. */
|
|
4
|
+
export declare class Archive {
|
|
5
|
+
/** Open (or create) an archive file. */
|
|
6
|
+
static open(path: string, options?: ArchiveOptions | undefined | null): Archive
|
|
7
|
+
/** Start accumulating `address` from `fromBlock` (must be > current head). */
|
|
8
|
+
watch(address: string, fromBlock: number): void
|
|
9
|
+
/** Stop watching and delete the address's data. */
|
|
10
|
+
unwatch(address: string): void
|
|
11
|
+
/** Watched addresses with their start blocks. */
|
|
12
|
+
watchlist(): Array<WatchEntry>
|
|
13
|
+
/** Last applied block, or null if nothing was synced yet. */
|
|
14
|
+
head(): Head | null
|
|
15
|
+
/**
|
|
16
|
+
* Fetch, verify and apply blocks from `rpcUrl` up to its head. Bootstraps
|
|
17
|
+
* first-seen slots via eth_getProof unless `bootstrap === false`.
|
|
18
|
+
* `backupRpc` (an archive endpoint, any provider) is asked only when the
|
|
19
|
+
* primary lacks a block's BAL or cannot prove a slot; its answers are
|
|
20
|
+
* verified exactly like the primary's.
|
|
21
|
+
*/
|
|
22
|
+
sync(rpcUrl: string, bootstrap?: boolean | undefined | null, backupRpc?: string | undefined | null): Promise<SyncReport>
|
|
23
|
+
/** Value of `slot` at the end of `block`. Throws NotAvailableError, never returns null. */
|
|
24
|
+
storageAt(address: string, slot: string, block: number): StorageValue
|
|
25
|
+
/** Changes of `slot` in `[from, to)`. */
|
|
26
|
+
history(address: string, slot: string, from: number, to: number): Array<HistoryEntry>
|
|
27
|
+
/** Slots of `address` written in `block`. */
|
|
28
|
+
changedSlots(address: string, block: number): Array<string>
|
|
29
|
+
/** Prove a never-changed slot at the archive head (lazy bootstrap). */
|
|
30
|
+
bootstrapSlot(rpcUrl: string, address: string, slot: string, backupRpc?: string | undefined | null): Promise<void>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** A parsed solc storage layout. */
|
|
34
|
+
export declare class Layout {
|
|
35
|
+
/** From a solc storageLayout JSON string or a whole forge/hardhat artifact. */
|
|
36
|
+
static fromJson(json: string): Layout
|
|
37
|
+
/** From a file containing either of the above. */
|
|
38
|
+
static fromFile(path: string): Layout
|
|
39
|
+
/** Resolve `totals.index`, `balances[0xabc…]`, `items[2]`, `items.length`. */
|
|
40
|
+
locate(path: string): Location
|
|
41
|
+
/**
|
|
42
|
+
* Decode a 32-byte word at a location. Returns the value as a string
|
|
43
|
+
* (decimal for integers, "true"/"false", 0x-address, or the raw word).
|
|
44
|
+
*/
|
|
45
|
+
decode(location: Location, wordHex: string): string
|
|
46
|
+
/** Every named field living in a raw slot (mapping entries excluded — keccak is one-way). */
|
|
47
|
+
describeSlot(slot: string): Array<NamedLocation>
|
|
48
|
+
/** Top-level variable names in declaration order. */
|
|
49
|
+
fields(): Array<string>
|
|
50
|
+
/**
|
|
51
|
+
* What a path names: "value:<uint|int|bool|address|bytes|raw>", "struct",
|
|
52
|
+
* "mapping", "array" or "fixedArray". Drives the `view` proxy in lib.js.
|
|
53
|
+
*/
|
|
54
|
+
kindOf(path: string): string
|
|
55
|
+
/**
|
|
56
|
+
* Decode a word and say what the text is, so JS can turn it into
|
|
57
|
+
* `bigint` / `boolean` / `string` without guessing.
|
|
58
|
+
*/
|
|
59
|
+
decodeValue(location: Location, wordHex: string): DecodedValue
|
|
60
|
+
/** TypeScript interface for this layout as the `view` proxy exposes it. */
|
|
61
|
+
typescript(name: string): string
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Options for `Archive.open`. */
|
|
65
|
+
export interface ArchiveOptions {
|
|
66
|
+
/**
|
|
67
|
+
* Blocks behind head the node still serves eth_getProof
|
|
68
|
+
* (reth: `--rpc.eth-proof-window`). Default 120.
|
|
69
|
+
*/
|
|
70
|
+
proofWindow?: number
|
|
71
|
+
/** Store every intra-block change instead of the last one. Fixed at creation. */
|
|
72
|
+
fullDetail?: boolean
|
|
73
|
+
/** Apply blocks without a BAL hash in the header. Debug only. */
|
|
74
|
+
allowUnverified?: boolean
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** A decoded word with its kind. */
|
|
78
|
+
export interface DecodedValue {
|
|
79
|
+
/** "uint" | "int" | "bool" | "address" | "bytes" | "raw" */
|
|
80
|
+
kind: string
|
|
81
|
+
/** Decimal for integers, "true"/"false", 0x-hex for addresses/bytes/raw. */
|
|
82
|
+
text: string
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Archive head. */
|
|
86
|
+
export interface Head {
|
|
87
|
+
/** Last applied block. */
|
|
88
|
+
number: number
|
|
89
|
+
/** Its hash. */
|
|
90
|
+
hash: string
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** One recorded change. */
|
|
94
|
+
export interface HistoryEntry {
|
|
95
|
+
/** Block of the change. */
|
|
96
|
+
block: number
|
|
97
|
+
/** Position within the block. */
|
|
98
|
+
index: number
|
|
99
|
+
/** 0x-prefixed 32-byte post-value. */
|
|
100
|
+
value: string
|
|
101
|
+
/** "bal" for entries inside a valid range. */
|
|
102
|
+
provenance: string
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Where a value lives. */
|
|
106
|
+
export interface Location {
|
|
107
|
+
/** 0x-prefixed storage slot. */
|
|
108
|
+
slot: string
|
|
109
|
+
/** Byte offset from the low-order end of the word. */
|
|
110
|
+
offset: number
|
|
111
|
+
/** Size in bytes. */
|
|
112
|
+
size: number
|
|
113
|
+
/** solc type id, e.g. `t_uint128`. */
|
|
114
|
+
typeId: string
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** A field name with its location. */
|
|
118
|
+
export interface NamedLocation {
|
|
119
|
+
/** Path such as `totals.index` or `items[3]`. */
|
|
120
|
+
name: string
|
|
121
|
+
/** Where it lives. */
|
|
122
|
+
location: Location
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** A stored word with its provenance. */
|
|
126
|
+
export interface StorageValue {
|
|
127
|
+
/** 0x-prefixed 32-byte word. */
|
|
128
|
+
value: string
|
|
129
|
+
/** "bal" | "proof" | "imported" | "unverified" */
|
|
130
|
+
provenance: string
|
|
131
|
+
/** Block at which this value was set (watch start - 1 for proven pre-values). */
|
|
132
|
+
setAt: number
|
|
133
|
+
/** Position within `setAt`. */
|
|
134
|
+
index: number
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** What one `sync()` did. */
|
|
138
|
+
export interface SyncReport {
|
|
139
|
+
/** First block this pass tried to apply. */
|
|
140
|
+
from?: number
|
|
141
|
+
/** Last block applied. */
|
|
142
|
+
to?: number
|
|
143
|
+
/** Blocks applied. */
|
|
144
|
+
blocksApplied: number
|
|
145
|
+
/** Fork point, if a reorg was rolled back. */
|
|
146
|
+
reorgedTo?: number
|
|
147
|
+
/** Slot records written. */
|
|
148
|
+
slotsWritten: number
|
|
149
|
+
/** Pre-values proven in this pass. */
|
|
150
|
+
bootstrapped: number
|
|
151
|
+
/** Slots still awaiting a proof. */
|
|
152
|
+
bootstrapPending: number
|
|
153
|
+
/** Slots whose pre-value became unobtainable. */
|
|
154
|
+
bootstrapLost: number
|
|
155
|
+
/** Blocks applied without a BAL hash (debug only). */
|
|
156
|
+
unverifiedBlocks: number
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** One watchlist entry. */
|
|
160
|
+
export interface WatchEntry {
|
|
161
|
+
/** Watched address. */
|
|
162
|
+
address: string
|
|
163
|
+
/** First block covered. */
|
|
164
|
+
from: number
|
|
165
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
// prettier-ignore
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
// @ts-nocheck
|
|
4
|
+
/* auto-generated by NAPI-RS */
|
|
5
|
+
|
|
6
|
+
const { readFileSync } = require('fs')
|
|
7
|
+
let nativeBinding = null
|
|
8
|
+
const loadErrors = []
|
|
9
|
+
|
|
10
|
+
const isMusl = () => {
|
|
11
|
+
let musl = false
|
|
12
|
+
if (process.platform === 'linux') {
|
|
13
|
+
musl = isMuslFromFilesystem()
|
|
14
|
+
if (musl === null) {
|
|
15
|
+
musl = isMuslFromReport()
|
|
16
|
+
}
|
|
17
|
+
if (musl === null) {
|
|
18
|
+
musl = isMuslFromChildProcess()
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return musl
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-')
|
|
25
|
+
|
|
26
|
+
const isMuslFromFilesystem = () => {
|
|
27
|
+
try {
|
|
28
|
+
return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl')
|
|
29
|
+
} catch {
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const isMuslFromReport = () => {
|
|
35
|
+
let report = null
|
|
36
|
+
if (process.report && typeof process.report.getReport === 'function') {
|
|
37
|
+
process.report.excludeNetwork = true
|
|
38
|
+
report = process.report.getReport()
|
|
39
|
+
}
|
|
40
|
+
if (!report) {
|
|
41
|
+
return null
|
|
42
|
+
}
|
|
43
|
+
if (report.header && report.header.glibcVersionRuntime) {
|
|
44
|
+
return false
|
|
45
|
+
}
|
|
46
|
+
if (Array.isArray(report.sharedObjects)) {
|
|
47
|
+
if (report.sharedObjects.some(isFileMusl)) {
|
|
48
|
+
return true
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return false
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const isMuslFromChildProcess = () => {
|
|
55
|
+
try {
|
|
56
|
+
return require('child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl')
|
|
57
|
+
} catch (e) {
|
|
58
|
+
// If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false
|
|
59
|
+
return false
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function requireNative() {
|
|
64
|
+
if (process.env.NAPI_RS_NATIVE_LIBRARY_PATH) {
|
|
65
|
+
try {
|
|
66
|
+
return require(process.env.NAPI_RS_NATIVE_LIBRARY_PATH);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
loadErrors.push(err)
|
|
69
|
+
}
|
|
70
|
+
} else if (process.platform === 'android') {
|
|
71
|
+
if (process.arch === 'arm64') {
|
|
72
|
+
try {
|
|
73
|
+
return require('./bal-node.android-arm64.node')
|
|
74
|
+
} catch (e) {
|
|
75
|
+
loadErrors.push(e)
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const binding = require('balq-android-arm64')
|
|
79
|
+
const bindingPackageVersion = require('balq-android-arm64/package.json').version
|
|
80
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
81
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
82
|
+
}
|
|
83
|
+
return binding
|
|
84
|
+
} catch (e) {
|
|
85
|
+
loadErrors.push(e)
|
|
86
|
+
}
|
|
87
|
+
} else if (process.arch === 'arm') {
|
|
88
|
+
try {
|
|
89
|
+
return require('./bal-node.android-arm-eabi.node')
|
|
90
|
+
} catch (e) {
|
|
91
|
+
loadErrors.push(e)
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const binding = require('balq-android-arm-eabi')
|
|
95
|
+
const bindingPackageVersion = require('balq-android-arm-eabi/package.json').version
|
|
96
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
97
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
98
|
+
}
|
|
99
|
+
return binding
|
|
100
|
+
} catch (e) {
|
|
101
|
+
loadErrors.push(e)
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
loadErrors.push(new Error(`Unsupported architecture on Android ${process.arch}`))
|
|
105
|
+
}
|
|
106
|
+
} else if (process.platform === 'win32') {
|
|
107
|
+
if (process.arch === 'x64') {
|
|
108
|
+
if ((process.config && process.config.variables && process.config.variables.shlib_suffix === 'dll.a') || (process.config && process.config.variables && process.config.variables.node_target_type === 'shared_library')) {
|
|
109
|
+
try {
|
|
110
|
+
return require('./bal-node.win32-x64-gnu.node')
|
|
111
|
+
} catch (e) {
|
|
112
|
+
loadErrors.push(e)
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const binding = require('balq-win32-x64-gnu')
|
|
116
|
+
const bindingPackageVersion = require('balq-win32-x64-gnu/package.json').version
|
|
117
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
118
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
119
|
+
}
|
|
120
|
+
return binding
|
|
121
|
+
} catch (e) {
|
|
122
|
+
loadErrors.push(e)
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
try {
|
|
126
|
+
return require('./bal-node.win32-x64-msvc.node')
|
|
127
|
+
} catch (e) {
|
|
128
|
+
loadErrors.push(e)
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const binding = require('balq-win32-x64-msvc')
|
|
132
|
+
const bindingPackageVersion = require('balq-win32-x64-msvc/package.json').version
|
|
133
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
134
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
135
|
+
}
|
|
136
|
+
return binding
|
|
137
|
+
} catch (e) {
|
|
138
|
+
loadErrors.push(e)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
} else if (process.arch === 'ia32') {
|
|
142
|
+
try {
|
|
143
|
+
return require('./bal-node.win32-ia32-msvc.node')
|
|
144
|
+
} catch (e) {
|
|
145
|
+
loadErrors.push(e)
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
const binding = require('balq-win32-ia32-msvc')
|
|
149
|
+
const bindingPackageVersion = require('balq-win32-ia32-msvc/package.json').version
|
|
150
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
151
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
152
|
+
}
|
|
153
|
+
return binding
|
|
154
|
+
} catch (e) {
|
|
155
|
+
loadErrors.push(e)
|
|
156
|
+
}
|
|
157
|
+
} else if (process.arch === 'arm64') {
|
|
158
|
+
try {
|
|
159
|
+
return require('./bal-node.win32-arm64-msvc.node')
|
|
160
|
+
} catch (e) {
|
|
161
|
+
loadErrors.push(e)
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const binding = require('balq-win32-arm64-msvc')
|
|
165
|
+
const bindingPackageVersion = require('balq-win32-arm64-msvc/package.json').version
|
|
166
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
167
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
168
|
+
}
|
|
169
|
+
return binding
|
|
170
|
+
} catch (e) {
|
|
171
|
+
loadErrors.push(e)
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
loadErrors.push(new Error(`Unsupported architecture on Windows: ${process.arch}`))
|
|
175
|
+
}
|
|
176
|
+
} else if (process.platform === 'darwin') {
|
|
177
|
+
try {
|
|
178
|
+
return require('./bal-node.darwin-universal.node')
|
|
179
|
+
} catch (e) {
|
|
180
|
+
loadErrors.push(e)
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
const binding = require('balq-darwin-universal')
|
|
184
|
+
const bindingPackageVersion = require('balq-darwin-universal/package.json').version
|
|
185
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
186
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
187
|
+
}
|
|
188
|
+
return binding
|
|
189
|
+
} catch (e) {
|
|
190
|
+
loadErrors.push(e)
|
|
191
|
+
}
|
|
192
|
+
if (process.arch === 'x64') {
|
|
193
|
+
try {
|
|
194
|
+
return require('./bal-node.darwin-x64.node')
|
|
195
|
+
} catch (e) {
|
|
196
|
+
loadErrors.push(e)
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
const binding = require('balq-darwin-x64')
|
|
200
|
+
const bindingPackageVersion = require('balq-darwin-x64/package.json').version
|
|
201
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
202
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
203
|
+
}
|
|
204
|
+
return binding
|
|
205
|
+
} catch (e) {
|
|
206
|
+
loadErrors.push(e)
|
|
207
|
+
}
|
|
208
|
+
} else if (process.arch === 'arm64') {
|
|
209
|
+
try {
|
|
210
|
+
return require('./bal-node.darwin-arm64.node')
|
|
211
|
+
} catch (e) {
|
|
212
|
+
loadErrors.push(e)
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
const binding = require('balq-darwin-arm64')
|
|
216
|
+
const bindingPackageVersion = require('balq-darwin-arm64/package.json').version
|
|
217
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
218
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
219
|
+
}
|
|
220
|
+
return binding
|
|
221
|
+
} catch (e) {
|
|
222
|
+
loadErrors.push(e)
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
loadErrors.push(new Error(`Unsupported architecture on macOS: ${process.arch}`))
|
|
226
|
+
}
|
|
227
|
+
} else if (process.platform === 'freebsd') {
|
|
228
|
+
if (process.arch === 'x64') {
|
|
229
|
+
try {
|
|
230
|
+
return require('./bal-node.freebsd-x64.node')
|
|
231
|
+
} catch (e) {
|
|
232
|
+
loadErrors.push(e)
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
const binding = require('balq-freebsd-x64')
|
|
236
|
+
const bindingPackageVersion = require('balq-freebsd-x64/package.json').version
|
|
237
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
238
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
239
|
+
}
|
|
240
|
+
return binding
|
|
241
|
+
} catch (e) {
|
|
242
|
+
loadErrors.push(e)
|
|
243
|
+
}
|
|
244
|
+
} else if (process.arch === 'arm64') {
|
|
245
|
+
try {
|
|
246
|
+
return require('./bal-node.freebsd-arm64.node')
|
|
247
|
+
} catch (e) {
|
|
248
|
+
loadErrors.push(e)
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
const binding = require('balq-freebsd-arm64')
|
|
252
|
+
const bindingPackageVersion = require('balq-freebsd-arm64/package.json').version
|
|
253
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
254
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
255
|
+
}
|
|
256
|
+
return binding
|
|
257
|
+
} catch (e) {
|
|
258
|
+
loadErrors.push(e)
|
|
259
|
+
}
|
|
260
|
+
} else {
|
|
261
|
+
loadErrors.push(new Error(`Unsupported architecture on FreeBSD: ${process.arch}`))
|
|
262
|
+
}
|
|
263
|
+
} else if (process.platform === 'linux') {
|
|
264
|
+
if (process.arch === 'x64') {
|
|
265
|
+
if (isMusl()) {
|
|
266
|
+
try {
|
|
267
|
+
return require('./bal-node.linux-x64-musl.node')
|
|
268
|
+
} catch (e) {
|
|
269
|
+
loadErrors.push(e)
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
const binding = require('balq-linux-x64-musl')
|
|
273
|
+
const bindingPackageVersion = require('balq-linux-x64-musl/package.json').version
|
|
274
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
275
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
276
|
+
}
|
|
277
|
+
return binding
|
|
278
|
+
} catch (e) {
|
|
279
|
+
loadErrors.push(e)
|
|
280
|
+
}
|
|
281
|
+
} else {
|
|
282
|
+
try {
|
|
283
|
+
return require('./bal-node.linux-x64-gnu.node')
|
|
284
|
+
} catch (e) {
|
|
285
|
+
loadErrors.push(e)
|
|
286
|
+
}
|
|
287
|
+
try {
|
|
288
|
+
const binding = require('balq-linux-x64-gnu')
|
|
289
|
+
const bindingPackageVersion = require('balq-linux-x64-gnu/package.json').version
|
|
290
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
291
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
292
|
+
}
|
|
293
|
+
return binding
|
|
294
|
+
} catch (e) {
|
|
295
|
+
loadErrors.push(e)
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
} else if (process.arch === 'arm64') {
|
|
299
|
+
if (isMusl()) {
|
|
300
|
+
try {
|
|
301
|
+
return require('./bal-node.linux-arm64-musl.node')
|
|
302
|
+
} catch (e) {
|
|
303
|
+
loadErrors.push(e)
|
|
304
|
+
}
|
|
305
|
+
try {
|
|
306
|
+
const binding = require('balq-linux-arm64-musl')
|
|
307
|
+
const bindingPackageVersion = require('balq-linux-arm64-musl/package.json').version
|
|
308
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
309
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
310
|
+
}
|
|
311
|
+
return binding
|
|
312
|
+
} catch (e) {
|
|
313
|
+
loadErrors.push(e)
|
|
314
|
+
}
|
|
315
|
+
} else {
|
|
316
|
+
try {
|
|
317
|
+
return require('./bal-node.linux-arm64-gnu.node')
|
|
318
|
+
} catch (e) {
|
|
319
|
+
loadErrors.push(e)
|
|
320
|
+
}
|
|
321
|
+
try {
|
|
322
|
+
const binding = require('balq-linux-arm64-gnu')
|
|
323
|
+
const bindingPackageVersion = require('balq-linux-arm64-gnu/package.json').version
|
|
324
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
325
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
326
|
+
}
|
|
327
|
+
return binding
|
|
328
|
+
} catch (e) {
|
|
329
|
+
loadErrors.push(e)
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
} else if (process.arch === 'arm') {
|
|
333
|
+
if (isMusl()) {
|
|
334
|
+
try {
|
|
335
|
+
return require('./bal-node.linux-arm-musleabihf.node')
|
|
336
|
+
} catch (e) {
|
|
337
|
+
loadErrors.push(e)
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
const binding = require('balq-linux-arm-musleabihf')
|
|
341
|
+
const bindingPackageVersion = require('balq-linux-arm-musleabihf/package.json').version
|
|
342
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
343
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
344
|
+
}
|
|
345
|
+
return binding
|
|
346
|
+
} catch (e) {
|
|
347
|
+
loadErrors.push(e)
|
|
348
|
+
}
|
|
349
|
+
} else {
|
|
350
|
+
try {
|
|
351
|
+
return require('./bal-node.linux-arm-gnueabihf.node')
|
|
352
|
+
} catch (e) {
|
|
353
|
+
loadErrors.push(e)
|
|
354
|
+
}
|
|
355
|
+
try {
|
|
356
|
+
const binding = require('balq-linux-arm-gnueabihf')
|
|
357
|
+
const bindingPackageVersion = require('balq-linux-arm-gnueabihf/package.json').version
|
|
358
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
359
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
360
|
+
}
|
|
361
|
+
return binding
|
|
362
|
+
} catch (e) {
|
|
363
|
+
loadErrors.push(e)
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
} else if (process.arch === 'loong64') {
|
|
367
|
+
if (isMusl()) {
|
|
368
|
+
try {
|
|
369
|
+
return require('./bal-node.linux-loong64-musl.node')
|
|
370
|
+
} catch (e) {
|
|
371
|
+
loadErrors.push(e)
|
|
372
|
+
}
|
|
373
|
+
try {
|
|
374
|
+
const binding = require('balq-linux-loong64-musl')
|
|
375
|
+
const bindingPackageVersion = require('balq-linux-loong64-musl/package.json').version
|
|
376
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
377
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
378
|
+
}
|
|
379
|
+
return binding
|
|
380
|
+
} catch (e) {
|
|
381
|
+
loadErrors.push(e)
|
|
382
|
+
}
|
|
383
|
+
} else {
|
|
384
|
+
try {
|
|
385
|
+
return require('./bal-node.linux-loong64-gnu.node')
|
|
386
|
+
} catch (e) {
|
|
387
|
+
loadErrors.push(e)
|
|
388
|
+
}
|
|
389
|
+
try {
|
|
390
|
+
const binding = require('balq-linux-loong64-gnu')
|
|
391
|
+
const bindingPackageVersion = require('balq-linux-loong64-gnu/package.json').version
|
|
392
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
393
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
394
|
+
}
|
|
395
|
+
return binding
|
|
396
|
+
} catch (e) {
|
|
397
|
+
loadErrors.push(e)
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
} else if (process.arch === 'riscv64') {
|
|
401
|
+
if (isMusl()) {
|
|
402
|
+
try {
|
|
403
|
+
return require('./bal-node.linux-riscv64-musl.node')
|
|
404
|
+
} catch (e) {
|
|
405
|
+
loadErrors.push(e)
|
|
406
|
+
}
|
|
407
|
+
try {
|
|
408
|
+
const binding = require('balq-linux-riscv64-musl')
|
|
409
|
+
const bindingPackageVersion = require('balq-linux-riscv64-musl/package.json').version
|
|
410
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
411
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
412
|
+
}
|
|
413
|
+
return binding
|
|
414
|
+
} catch (e) {
|
|
415
|
+
loadErrors.push(e)
|
|
416
|
+
}
|
|
417
|
+
} else {
|
|
418
|
+
try {
|
|
419
|
+
return require('./bal-node.linux-riscv64-gnu.node')
|
|
420
|
+
} catch (e) {
|
|
421
|
+
loadErrors.push(e)
|
|
422
|
+
}
|
|
423
|
+
try {
|
|
424
|
+
const binding = require('balq-linux-riscv64-gnu')
|
|
425
|
+
const bindingPackageVersion = require('balq-linux-riscv64-gnu/package.json').version
|
|
426
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
427
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
428
|
+
}
|
|
429
|
+
return binding
|
|
430
|
+
} catch (e) {
|
|
431
|
+
loadErrors.push(e)
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
} else if (process.arch === 'ppc64') {
|
|
435
|
+
try {
|
|
436
|
+
return require('./bal-node.linux-ppc64-gnu.node')
|
|
437
|
+
} catch (e) {
|
|
438
|
+
loadErrors.push(e)
|
|
439
|
+
}
|
|
440
|
+
try {
|
|
441
|
+
const binding = require('balq-linux-ppc64-gnu')
|
|
442
|
+
const bindingPackageVersion = require('balq-linux-ppc64-gnu/package.json').version
|
|
443
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
444
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
445
|
+
}
|
|
446
|
+
return binding
|
|
447
|
+
} catch (e) {
|
|
448
|
+
loadErrors.push(e)
|
|
449
|
+
}
|
|
450
|
+
} else if (process.arch === 's390x') {
|
|
451
|
+
try {
|
|
452
|
+
return require('./bal-node.linux-s390x-gnu.node')
|
|
453
|
+
} catch (e) {
|
|
454
|
+
loadErrors.push(e)
|
|
455
|
+
}
|
|
456
|
+
try {
|
|
457
|
+
const binding = require('balq-linux-s390x-gnu')
|
|
458
|
+
const bindingPackageVersion = require('balq-linux-s390x-gnu/package.json').version
|
|
459
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
460
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
461
|
+
}
|
|
462
|
+
return binding
|
|
463
|
+
} catch (e) {
|
|
464
|
+
loadErrors.push(e)
|
|
465
|
+
}
|
|
466
|
+
} else {
|
|
467
|
+
loadErrors.push(new Error(`Unsupported architecture on Linux: ${process.arch}`))
|
|
468
|
+
}
|
|
469
|
+
} else if (process.platform === 'openharmony') {
|
|
470
|
+
if (process.arch === 'arm64') {
|
|
471
|
+
try {
|
|
472
|
+
return require('./bal-node.openharmony-arm64.node')
|
|
473
|
+
} catch (e) {
|
|
474
|
+
loadErrors.push(e)
|
|
475
|
+
}
|
|
476
|
+
try {
|
|
477
|
+
const binding = require('balq-openharmony-arm64')
|
|
478
|
+
const bindingPackageVersion = require('balq-openharmony-arm64/package.json').version
|
|
479
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
480
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
481
|
+
}
|
|
482
|
+
return binding
|
|
483
|
+
} catch (e) {
|
|
484
|
+
loadErrors.push(e)
|
|
485
|
+
}
|
|
486
|
+
} else if (process.arch === 'x64') {
|
|
487
|
+
try {
|
|
488
|
+
return require('./bal-node.openharmony-x64.node')
|
|
489
|
+
} catch (e) {
|
|
490
|
+
loadErrors.push(e)
|
|
491
|
+
}
|
|
492
|
+
try {
|
|
493
|
+
const binding = require('balq-openharmony-x64')
|
|
494
|
+
const bindingPackageVersion = require('balq-openharmony-x64/package.json').version
|
|
495
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
496
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
497
|
+
}
|
|
498
|
+
return binding
|
|
499
|
+
} catch (e) {
|
|
500
|
+
loadErrors.push(e)
|
|
501
|
+
}
|
|
502
|
+
} else if (process.arch === 'arm') {
|
|
503
|
+
try {
|
|
504
|
+
return require('./bal-node.openharmony-arm.node')
|
|
505
|
+
} catch (e) {
|
|
506
|
+
loadErrors.push(e)
|
|
507
|
+
}
|
|
508
|
+
try {
|
|
509
|
+
const binding = require('balq-openharmony-arm')
|
|
510
|
+
const bindingPackageVersion = require('balq-openharmony-arm/package.json').version
|
|
511
|
+
if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
512
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
513
|
+
}
|
|
514
|
+
return binding
|
|
515
|
+
} catch (e) {
|
|
516
|
+
loadErrors.push(e)
|
|
517
|
+
}
|
|
518
|
+
} else {
|
|
519
|
+
loadErrors.push(new Error(`Unsupported architecture on OpenHarmony: ${process.arch}`))
|
|
520
|
+
}
|
|
521
|
+
} else {
|
|
522
|
+
loadErrors.push(new Error(`Unsupported OS: ${process.platform}, architecture: ${process.arch}`))
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function createLoadErrorChain(errors) {
|
|
527
|
+
return errors.reduce((previous, current) => {
|
|
528
|
+
let message
|
|
529
|
+
try {
|
|
530
|
+
message =
|
|
531
|
+
current && typeof current.message === 'string'
|
|
532
|
+
? current.message
|
|
533
|
+
: String(current)
|
|
534
|
+
} catch {
|
|
535
|
+
message = 'Unknown error'
|
|
536
|
+
}
|
|
537
|
+
const error = new Error(message)
|
|
538
|
+
error.cause = previous
|
|
539
|
+
return error
|
|
540
|
+
}, null)
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// NAPI_RS_FORCE_WASI is a tri-state flag:
|
|
544
|
+
// unset / any other value → native binding preferred, WASI is only a fallback
|
|
545
|
+
// 'true' → prefer WASI, but retain native as a lazy fallback
|
|
546
|
+
// 'error' → require WASI without initializing a native fallback
|
|
547
|
+
// Treating any non-empty string as truthy (the historical behavior) meant
|
|
548
|
+
// NAPI_RS_FORCE_WASI=false, NAPI_RS_FORCE_WASI=0, etc. inadvertently triggered
|
|
549
|
+
// the WASI path, causing ENOENT for packages shipped without a .wasi.cjs file.
|
|
550
|
+
//
|
|
551
|
+
// NAPI_RS_WASI_FLAVOR selects one exact generated flavor and implies strict
|
|
552
|
+
// WASI loading. It never crosses into another flavor or falls back to native.
|
|
553
|
+
const __napiWasiFlavors = ["wasm32-wasi"]
|
|
554
|
+
const __napiWasiFlavor = process.env.NAPI_RS_WASI_FLAVOR
|
|
555
|
+
const __napiWasiFlavorRequested =
|
|
556
|
+
typeof __napiWasiFlavor === 'string' && __napiWasiFlavor.length > 0
|
|
557
|
+
if (
|
|
558
|
+
__napiWasiFlavorRequested &&
|
|
559
|
+
__napiWasiFlavors.indexOf(__napiWasiFlavor) === -1
|
|
560
|
+
) {
|
|
561
|
+
throw new Error(
|
|
562
|
+
'Unsupported WASI flavor "' +
|
|
563
|
+
__napiWasiFlavor +
|
|
564
|
+
'". Available flavors: ' +
|
|
565
|
+
__napiWasiFlavors.join(', '),
|
|
566
|
+
)
|
|
567
|
+
}
|
|
568
|
+
const forceWasiError = process.env.NAPI_RS_FORCE_WASI === 'error'
|
|
569
|
+
const forceWasi =
|
|
570
|
+
process.env.NAPI_RS_FORCE_WASI === 'true' ||
|
|
571
|
+
forceWasiError ||
|
|
572
|
+
__napiWasiFlavorRequested
|
|
573
|
+
|
|
574
|
+
if (!forceWasi) {
|
|
575
|
+
nativeBinding = requireNative()
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
if (!nativeBinding || forceWasi) {
|
|
579
|
+
let wasiBinding = null
|
|
580
|
+
let wasiBindingLoaded = false
|
|
581
|
+
const wasiBindingErrors = []
|
|
582
|
+
const __napiWasiResolveCandidate = (specifier, isPackage, localArtifacts) => {
|
|
583
|
+
try {
|
|
584
|
+
require.resolve(specifier)
|
|
585
|
+
} catch (resolveError) {
|
|
586
|
+
if (!resolveError || resolveError.code !== 'MODULE_NOT_FOUND') {
|
|
587
|
+
throw resolveError
|
|
588
|
+
}
|
|
589
|
+
if (isPackage) {
|
|
590
|
+
try {
|
|
591
|
+
require.resolve(specifier + '/package.json')
|
|
592
|
+
} catch (packageError) {
|
|
593
|
+
if (packageError && packageError.code === 'MODULE_NOT_FOUND') {
|
|
594
|
+
return resolveError
|
|
595
|
+
}
|
|
596
|
+
// An exports restriction proves the package exists even when its
|
|
597
|
+
// package.json is not public. Preserve the root resolution failure.
|
|
598
|
+
throw resolveError
|
|
599
|
+
}
|
|
600
|
+
// The package exists but its main/export target is broken.
|
|
601
|
+
throw resolveError
|
|
602
|
+
}
|
|
603
|
+
return resolveError
|
|
604
|
+
}
|
|
605
|
+
if (localArtifacts) {
|
|
606
|
+
let artifactError = null
|
|
607
|
+
for (let i = 0; i < localArtifacts.length; i++) {
|
|
608
|
+
try {
|
|
609
|
+
require.resolve(localArtifacts[i])
|
|
610
|
+
return null
|
|
611
|
+
} catch (resolveError) {
|
|
612
|
+
if (!resolveError || resolveError.code !== 'MODULE_NOT_FOUND') {
|
|
613
|
+
throw resolveError
|
|
614
|
+
}
|
|
615
|
+
artifactError = resolveError
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return artifactError
|
|
619
|
+
}
|
|
620
|
+
return null
|
|
621
|
+
}
|
|
622
|
+
if (!wasiBindingLoaded && (!__napiWasiFlavorRequested || __napiWasiFlavor === "wasm32-wasi")) {
|
|
623
|
+
let candidateError = null
|
|
624
|
+
let candidateFailed = false
|
|
625
|
+
try {
|
|
626
|
+
candidateError = __napiWasiResolveCandidate('./bal-node.wasi.cjs', false, ["./bal-node.wasm32-wasi.debug.wasm","./bal-node.wasm32-wasi.wasm"])
|
|
627
|
+
candidateFailed = candidateError !== null
|
|
628
|
+
if (!candidateFailed) {
|
|
629
|
+
wasiBinding = require('./bal-node.wasi.cjs')
|
|
630
|
+
nativeBinding = wasiBinding
|
|
631
|
+
wasiBindingLoaded = true
|
|
632
|
+
}
|
|
633
|
+
} catch (err) {
|
|
634
|
+
candidateError = err
|
|
635
|
+
candidateFailed = true
|
|
636
|
+
}
|
|
637
|
+
if (candidateFailed) {
|
|
638
|
+
wasiBindingErrors.push(candidateError)
|
|
639
|
+
loadErrors.push(candidateError)
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
if (!wasiBindingLoaded && (!__napiWasiFlavorRequested || __napiWasiFlavor === "wasm32-wasi")) {
|
|
643
|
+
let candidateError = null
|
|
644
|
+
let candidateFailed = false
|
|
645
|
+
try {
|
|
646
|
+
candidateError = __napiWasiResolveCandidate('balq-wasm32-wasi', true, undefined)
|
|
647
|
+
candidateFailed = candidateError !== null
|
|
648
|
+
if (!candidateFailed) {
|
|
649
|
+
if (process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
650
|
+
const bindingPackageVersion = require('balq-wasm32-wasi/package.json').version
|
|
651
|
+
if (bindingPackageVersion !== '0.1.1') {
|
|
652
|
+
throw new Error(`WASI binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
wasiBinding = require('balq-wasm32-wasi')
|
|
656
|
+
nativeBinding = wasiBinding
|
|
657
|
+
wasiBindingLoaded = true
|
|
658
|
+
}
|
|
659
|
+
} catch (err) {
|
|
660
|
+
candidateError = err
|
|
661
|
+
candidateFailed = true
|
|
662
|
+
}
|
|
663
|
+
if (candidateFailed) {
|
|
664
|
+
wasiBindingErrors.push(candidateError)
|
|
665
|
+
loadErrors.push(candidateError)
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
if (
|
|
669
|
+
!wasiBindingLoaded &&
|
|
670
|
+
forceWasi &&
|
|
671
|
+
!forceWasiError &&
|
|
672
|
+
!__napiWasiFlavorRequested
|
|
673
|
+
) {
|
|
674
|
+
nativeBinding = requireNative()
|
|
675
|
+
}
|
|
676
|
+
if ((forceWasiError || __napiWasiFlavorRequested) && !wasiBindingLoaded) {
|
|
677
|
+
const error = new Error(
|
|
678
|
+
__napiWasiFlavorRequested
|
|
679
|
+
? 'WASI binding for flavor "' + __napiWasiFlavor + '" not found'
|
|
680
|
+
: 'WASI binding not found and NAPI_RS_FORCE_WASI is set to error',
|
|
681
|
+
)
|
|
682
|
+
error.cause = createLoadErrorChain(wasiBindingErrors)
|
|
683
|
+
throw error
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if (!nativeBinding) {
|
|
688
|
+
if (loadErrors.length > 0) {
|
|
689
|
+
const error = new Error(
|
|
690
|
+
`Cannot find native binding. ` +
|
|
691
|
+
`npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). ` +
|
|
692
|
+
'Please try `npm i` again after removing both package-lock.json and node_modules directory.',
|
|
693
|
+
)
|
|
694
|
+
// assign instead of the `new Error(message, { cause })` options form,
|
|
695
|
+
// which Node < 16.9 silently ignores
|
|
696
|
+
error.cause = createLoadErrorChain(loadErrors)
|
|
697
|
+
throw error
|
|
698
|
+
}
|
|
699
|
+
throw new Error(`Failed to load native binding`)
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
module.exports = nativeBinding
|
|
703
|
+
module.exports.Archive = nativeBinding.Archive
|
|
704
|
+
module.exports.Layout = nativeBinding.Layout
|
package/lib.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export * from "./index";
|
|
2
|
+
import { Archive as NativeArchive, Layout } from "./index";
|
|
3
|
+
|
|
4
|
+
/** Thrown by reads when there is no value — never `null`. */
|
|
5
|
+
export class NotAvailableError extends Error {
|
|
6
|
+
name: "NotAvailableError";
|
|
7
|
+
code:
|
|
8
|
+
| "NotWatched"
|
|
9
|
+
| "BeforeStart"
|
|
10
|
+
| "AfterHead"
|
|
11
|
+
| "NotSynced"
|
|
12
|
+
| "InvalidRange"
|
|
13
|
+
| "NotBootstrapped"
|
|
14
|
+
| "BootstrapPending"
|
|
15
|
+
| "BootstrapLost"
|
|
16
|
+
| "Internal";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Storage of one contract at one block, read by variable name.
|
|
21
|
+
* Generate a precise type with `balq typegen <layout> --name MyContractView`
|
|
22
|
+
* (or `layout.typescript("MyContractView")`) and pass it as `T`.
|
|
23
|
+
*/
|
|
24
|
+
export type StorageView<T = any> = T;
|
|
25
|
+
|
|
26
|
+
export interface ContractView {
|
|
27
|
+
/** Variables of the contract at the end of `block`. */
|
|
28
|
+
at<T = any>(block: number): StorageView<T>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
declare module "./index" {
|
|
32
|
+
interface Archive {
|
|
33
|
+
/** Read storage by name through a solc layout; see `at()`. */
|
|
34
|
+
view(address: string, layout: Layout): ContractView;
|
|
35
|
+
}
|
|
36
|
+
}
|
package/lib.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// Thin wrapper over the generated `index.js`:
|
|
2
|
+
// - turns `[NotAvailable:Code] …` errors from Rust into `NotAvailableError`
|
|
3
|
+
// with a `.code`;
|
|
4
|
+
// - adds `archive.view(address, layout).at(block)`, a proxy that reads the
|
|
5
|
+
// contract's variables by name, the way they are written in Solidity.
|
|
6
|
+
// No archive or layout logic lives here; every read goes through the native
|
|
7
|
+
// `locate` / `kindOf` / `storageAt` / `decodeValue`.
|
|
8
|
+
|
|
9
|
+
const native = require("./index.js");
|
|
10
|
+
|
|
11
|
+
class NotAvailableError extends Error {
|
|
12
|
+
constructor(code, message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = "NotAvailableError";
|
|
15
|
+
this.code = code;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const RE = /^\[NotAvailable:([A-Za-z]+)\] (.*)$/s;
|
|
20
|
+
|
|
21
|
+
function convert(e) {
|
|
22
|
+
const m = typeof e?.message === "string" && RE.exec(e.message);
|
|
23
|
+
return m ? new NotAvailableError(m[1], m[2]) : e;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function wrap(obj, names) {
|
|
27
|
+
for (const n of names) {
|
|
28
|
+
const orig = obj[n];
|
|
29
|
+
obj[n] = function (...args) {
|
|
30
|
+
try {
|
|
31
|
+
const r = orig.apply(this, args);
|
|
32
|
+
return r instanceof Promise ? r.catch((e) => { throw convert(e); }) : r;
|
|
33
|
+
} catch (e) {
|
|
34
|
+
throw convert(e);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
wrap(native.Archive.prototype, ["storageAt", "history", "changedSlots", "sync", "bootstrapSlot"]);
|
|
41
|
+
|
|
42
|
+
// ---- view -----------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
function toJs(decoded) {
|
|
45
|
+
switch (decoded.kind) {
|
|
46
|
+
case "uint":
|
|
47
|
+
case "int":
|
|
48
|
+
return BigInt(decoded.text);
|
|
49
|
+
case "bool":
|
|
50
|
+
return decoded.text === "true";
|
|
51
|
+
default:
|
|
52
|
+
return decoded.text; // address, bytes, raw: 0x-hex
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Properties JS itself probes on any object; never storage fields.
|
|
57
|
+
const PASSTHROUGH = new Set(["then", "toJSON", "constructor", "valueOf", "toString", "inspect"]);
|
|
58
|
+
|
|
59
|
+
function readLeaf(archive, address, layout, block, path) {
|
|
60
|
+
const loc = layout.locate(path);
|
|
61
|
+
const v = archive.storageAt(address, loc.slot, block);
|
|
62
|
+
return toJs(layout.decodeValue(loc, v.value));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* A proxy for the container at `path` ("" = the contract itself).
|
|
67
|
+
* Property access extends the path according to the container's kind and
|
|
68
|
+
* either descends (struct / mapping / array) or reads a leaf value.
|
|
69
|
+
*/
|
|
70
|
+
function container(archive, address, layout, block, path, kind) {
|
|
71
|
+
const extend = (prop) => {
|
|
72
|
+
if (kind === "struct" || kind === "") return path ? `${path}.${prop}` : prop;
|
|
73
|
+
if (kind === "array" && prop === "length") return `${path}.length`;
|
|
74
|
+
return `${path}[${prop}]`; // mapping, array, fixedArray
|
|
75
|
+
};
|
|
76
|
+
return new Proxy(Object.create(null), {
|
|
77
|
+
get(_, prop) {
|
|
78
|
+
if (typeof prop === "symbol" || PASSTHROUGH.has(prop)) return undefined;
|
|
79
|
+
const next = extend(String(prop));
|
|
80
|
+
const k = layout.kindOf(next); // throws for unknown fields
|
|
81
|
+
if (k.startsWith("value:")) return readLeaf(archive, address, layout, block, next);
|
|
82
|
+
return container(archive, address, layout, block, next, k);
|
|
83
|
+
},
|
|
84
|
+
has(_, prop) {
|
|
85
|
+
if (typeof prop === "symbol") return false;
|
|
86
|
+
try {
|
|
87
|
+
layout.kindOf(extend(String(prop)));
|
|
88
|
+
return true;
|
|
89
|
+
} catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
ownKeys() {
|
|
94
|
+
return kind === "" || !path ? layout.fields() : [];
|
|
95
|
+
},
|
|
96
|
+
getOwnPropertyDescriptor(_, prop) {
|
|
97
|
+
return { enumerable: true, configurable: true, value: undefined };
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* `archive.view(address, layout)` → `{ at(block) }`.
|
|
104
|
+
* `at(block)` returns an object whose properties are the contract's storage
|
|
105
|
+
* variables at the end of `block`: `view.counter`, `view.balances[addr]`,
|
|
106
|
+
* `view.totals.index`, `view.items[3]`, `view.items.length`.
|
|
107
|
+
* Integers are `bigint`, bools `boolean`, addresses/bytes/raw words `string`.
|
|
108
|
+
* A missing value throws `NotAvailableError` — never `undefined`.
|
|
109
|
+
*/
|
|
110
|
+
native.Archive.prototype.view = function (address, layout) {
|
|
111
|
+
const archive = this;
|
|
112
|
+
return {
|
|
113
|
+
at(block) {
|
|
114
|
+
return container(archive, address, layout, block, "", "");
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
module.exports = { ...native, NotAvailableError };
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@balq/node",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Local, verified archive of contract storage built from EIP-7928 BALs — Node.js bindings",
|
|
5
|
+
"main": "lib.js",
|
|
6
|
+
"types": "lib.d.ts",
|
|
7
|
+
"license": "MIT OR Apache-2.0",
|
|
8
|
+
"files": [
|
|
9
|
+
"lib.js",
|
|
10
|
+
"lib.d.ts",
|
|
11
|
+
"index.js",
|
|
12
|
+
"index.d.ts"
|
|
13
|
+
],
|
|
14
|
+
"napi": {
|
|
15
|
+
"binaryName": "bal-node",
|
|
16
|
+
"targets": [
|
|
17
|
+
"x86_64-pc-windows-msvc",
|
|
18
|
+
"x86_64-unknown-linux-gnu",
|
|
19
|
+
"aarch64-unknown-linux-gnu",
|
|
20
|
+
"x86_64-apple-darwin",
|
|
21
|
+
"aarch64-apple-darwin"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">= 18"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "napi build --release --platform",
|
|
29
|
+
"build:debug": "napi build --platform",
|
|
30
|
+
"test": "node test/smoke.mjs"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@napi-rs/cli": "^3"
|
|
34
|
+
},
|
|
35
|
+
"optionalDependencies": {
|
|
36
|
+
"@balq/node-win32-x64-msvc": "0.1.1",
|
|
37
|
+
"@balq/node-linux-x64-gnu": "0.1.1",
|
|
38
|
+
"@balq/node-linux-arm64-gnu": "0.1.1",
|
|
39
|
+
"@balq/node-darwin-x64": "0.1.1",
|
|
40
|
+
"@balq/node-darwin-arm64": "0.1.1"
|
|
41
|
+
}
|
|
42
|
+
}
|