@gitsheets/core-napi 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/README.md +115 -0
- package/binding.cjs +178 -0
- package/index.d.ts +422 -0
- package/index.js +347 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# @gitsheets/core-napi
|
|
2
|
+
|
|
3
|
+
Node.js native binding for [`gitsheets-core`](../gitsheets-core) — the FFI
|
|
4
|
+
marshalling boundary between the published `gitsheets` npm package (a thin
|
|
5
|
+
TypeScript shell) and the Rust engine that owns the bytes: TOML parse/serialize,
|
|
6
|
+
canonical normalization, path templates, JSON-Schema validation, the embedded
|
|
7
|
+
JS engine, ICU collation, record CRUD / query / index, diff/patch, attachments,
|
|
8
|
+
and the `Sheet`/`Transaction`/`Store` state machine. Tree/blob/commit ops run on
|
|
9
|
+
`holo-tree` (gitoxide) inside the core.
|
|
10
|
+
|
|
11
|
+
This package exists so that a consumer can `npm install gitsheets` and get a
|
|
12
|
+
working native addon **without a Rust toolchain** — the matching prebuilt binary
|
|
13
|
+
is pulled in as an `optionalDependency` platform package.
|
|
14
|
+
|
|
15
|
+
## Building (in-repo development)
|
|
16
|
+
|
|
17
|
+
Requires a Rust toolchain and `@napi-rs/cli` (a devDependency):
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm install
|
|
21
|
+
npm run build:debug # or: npm run build (release)
|
|
22
|
+
npm test # node --test against scratch git repos
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`napi build` emits `gitsheets-core.<triple>.node`. The generated `index.js`
|
|
26
|
+
loader, `index.d.ts` types, and `binding.cjs` wrapper **are committed**; only the
|
|
27
|
+
`.node` binaries are git-ignored (built per-platform in CI). The `npm/<triple>/`
|
|
28
|
+
platform-package manifests are committed too; their `.node` payloads are dropped
|
|
29
|
+
in at publish time.
|
|
30
|
+
|
|
31
|
+
In-repo, the JS package resolves this binding through the npm-workspace symlink
|
|
32
|
+
(`node_modules/@gitsheets/core-napi → rust/gitsheets-napi`) and loads the locally
|
|
33
|
+
built `.node` next to `index.js`; the `optionalDependencies` platform packages
|
|
34
|
+
are only used by external consumers.
|
|
35
|
+
|
|
36
|
+
## Publishing / prebuilds
|
|
37
|
+
|
|
38
|
+
Published as the scoped package **`@gitsheets/core-napi`** with per-platform
|
|
39
|
+
prebuilt binaries shipped as `optionalDependencies`:
|
|
40
|
+
|
|
41
|
+
| Platform package | Triple | Built on | Smoke-tested |
|
|
42
|
+
| --- | --- | --- | --- |
|
|
43
|
+
| `@gitsheets/core-napi-linux-x64-gnu` | `x86_64-unknown-linux-gnu` | ubuntu-latest | ✓ native |
|
|
44
|
+
| `@gitsheets/core-napi-linux-arm64-gnu` | `aarch64-unknown-linux-gnu` | ubuntu-24.04-arm | ✓ native |
|
|
45
|
+
| `@gitsheets/core-napi-linux-x64-musl` | `x86_64-unknown-linux-musl` | ubuntu-latest (zig cross) | build-only |
|
|
46
|
+
| `@gitsheets/core-napi-darwin-arm64` | `aarch64-apple-darwin` | macos-latest | ✓ native |
|
|
47
|
+
| `@gitsheets/core-napi-darwin-x64` | `x86_64-apple-darwin` | macos-latest (cross) | build-only |
|
|
48
|
+
| `@gitsheets/core-napi-win32-x64-msvc` | `x86_64-pc-windows-msvc` | windows-latest | ✓ native |
|
|
49
|
+
|
|
50
|
+
Native targets build + smoke-test on a matching runner; cross targets (musl,
|
|
51
|
+
darwin-x64) build only, since their `.node` can't run on the host arch/libc (the
|
|
52
|
+
logic is covered by the native runs). The `.github/workflows/core-napi.yml`
|
|
53
|
+
workflow builds all six on every PR touching `rust/**`, and on a `core-napi-v*`
|
|
54
|
+
tag it builds then publishes.
|
|
55
|
+
|
|
56
|
+
Auth is **npm trusted publishing (OIDC)** — no tokens, matching the repo's
|
|
57
|
+
`publish-npm.yml`. Trusted publishing is configured *per package*, and a package
|
|
58
|
+
can't get a trusted publisher until it exists — so the seven packages
|
|
59
|
+
(the main package + six platform packages) need a **one-time manual bootstrap**
|
|
60
|
+
before automated releases work.
|
|
61
|
+
|
|
62
|
+
### Prerequisite: the `@gitsheets` npm scope
|
|
63
|
+
|
|
64
|
+
The `@gitsheets` org/scope must exist on npmjs.com and the person running the
|
|
65
|
+
bootstrap must be a member with publish rights. (One-time human setup.)
|
|
66
|
+
|
|
67
|
+
### One-time bootstrap (manual first publish, then configure trusted publishing)
|
|
68
|
+
|
|
69
|
+
The seven packages all start at an early version (currently `0.1.0`). They must
|
|
70
|
+
exist on npm before trusted publishing can be turned on.
|
|
71
|
+
|
|
72
|
+
1. **Get the prebuilt binaries.** Run the `core-napi` workflow (open a PR
|
|
73
|
+
touching `rust/**`, or trigger `workflow_dispatch`) and download its six
|
|
74
|
+
`bindings-*` artifacts — they hold the `.node` for each platform. A single
|
|
75
|
+
machine can't build all six natively, so use the CI artifacts.
|
|
76
|
+
|
|
77
|
+
2. **Publish all seven manually**, logged in as a `@gitsheets` org member
|
|
78
|
+
(`npm login`):
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
cd rust/gitsheets-napi
|
|
82
|
+
npm install
|
|
83
|
+
npx napi artifacts --dir <downloaded-artifacts-dir> # → npm/<triple>/*.node
|
|
84
|
+
# platform packages first, then the main package:
|
|
85
|
+
for d in npm/*/ ; do ( cd "$d" && npm publish --access public ); done
|
|
86
|
+
npm publish --access public --ignore-scripts # main; skip the napi
|
|
87
|
+
# prepublish hook
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
3. **Turn on trusted publishing** on npmjs.com for **each** of the seven packages
|
|
91
|
+
→ package Settings → Trusted Publisher → GitHub Actions, repo
|
|
92
|
+
`JarvusInnovations/gitsheets`, workflow `core-napi.yml`.
|
|
93
|
+
|
|
94
|
+
### Releases (after bootstrap — fully automated, tokenless)
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
git tag core-napi-v0.1.1 && git push origin core-napi-v0.1.1
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The tag drives the published version; CI builds all six platforms, then publishes
|
|
101
|
+
via OIDC (provenance). No secret needed. The `core-napi-v*` tag is the release
|
|
102
|
+
marker — napi runs with `--skip-gh-release` so it does **not** create a bare
|
|
103
|
+
`v<version>` GitHub release/tag (which would collide with the `gitsheets`
|
|
104
|
+
JS-package `v*` release namespace owned by `publish-npm.yml`).
|
|
105
|
+
|
|
106
|
+
**Version scheme.** `@gitsheets/core-napi` carries its own semver in its own
|
|
107
|
+
`core-napi-v*` tag namespace, decoupled from the `gitsheets` package's `v*` tags.
|
|
108
|
+
`packages/gitsheets` depends on it via a caret range (`^0.1.0`) so a compatible
|
|
109
|
+
addon release is picked up without a lockstep bump; widen the range deliberately
|
|
110
|
+
when the addon takes a breaking major.
|
|
111
|
+
|
|
112
|
+
To add or drop a platform later, edit `napi.triples.additional` +
|
|
113
|
+
`optionalDependencies` in `package.json`, run `npx napi create-npm-dir -t .`,
|
|
114
|
+
add the matching matrix entry in the workflow, and (since it's a new package)
|
|
115
|
+
bootstrap + trust that one package too.
|
package/binding.cjs
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Thin JS surface over the napi addon. The addon (./index.js) marshals records
|
|
4
|
+
// with full type fidelity and throws *structured* errors (own `code`, `status`,
|
|
5
|
+
// `gitsheetsClass`, and `issues`/`conflictingPaths` payloads). This wrapper owns
|
|
6
|
+
// the one genuinely host-specific concern the Rust side can't: constructing real
|
|
7
|
+
// instances of the typed `GitsheetsError` subclasses from `specs/api/errors.md`
|
|
8
|
+
// so consumers can `instanceof` and switch on `err.code`.
|
|
9
|
+
|
|
10
|
+
const addon = require('./index.js');
|
|
11
|
+
|
|
12
|
+
class GitsheetsError extends Error {
|
|
13
|
+
constructor(message, { code, status, cause } = {}) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'GitsheetsError';
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.status = status;
|
|
18
|
+
if (cause !== undefined) this.cause = cause;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class ConfigError extends GitsheetsError {
|
|
23
|
+
constructor(message, opts) {
|
|
24
|
+
super(message, opts);
|
|
25
|
+
this.name = 'ConfigError';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
class ValidationError extends GitsheetsError {
|
|
30
|
+
constructor(message, opts = {}) {
|
|
31
|
+
super(message, opts);
|
|
32
|
+
this.name = 'ValidationError';
|
|
33
|
+
this.issues = opts.issues ?? [];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class TransactionError extends GitsheetsError {
|
|
38
|
+
constructor(message, opts) {
|
|
39
|
+
super(message, opts);
|
|
40
|
+
this.name = 'TransactionError';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class IndexError extends GitsheetsError {
|
|
45
|
+
constructor(message, opts = {}) {
|
|
46
|
+
super(message, opts);
|
|
47
|
+
this.name = 'IndexError';
|
|
48
|
+
if (opts.conflictingPaths !== undefined) this.conflictingPaths = opts.conflictingPaths;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
class RefError extends GitsheetsError {
|
|
53
|
+
constructor(message, opts) {
|
|
54
|
+
super(message, opts);
|
|
55
|
+
this.name = 'RefError';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
class PathTemplateError extends GitsheetsError {
|
|
60
|
+
constructor(message, opts) {
|
|
61
|
+
super(message, opts);
|
|
62
|
+
this.name = 'PathTemplateError';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
class NotFoundError extends GitsheetsError {
|
|
67
|
+
constructor(message, opts) {
|
|
68
|
+
super(message, opts);
|
|
69
|
+
this.name = 'NotFoundError';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const CLASS_BY_NAME = {
|
|
74
|
+
ConfigError,
|
|
75
|
+
ValidationError,
|
|
76
|
+
TransactionError,
|
|
77
|
+
IndexError,
|
|
78
|
+
RefError,
|
|
79
|
+
PathTemplateError,
|
|
80
|
+
NotFoundError,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// Map a structured error raised by the addon onto its typed class. The mapping
|
|
84
|
+
// keys off the `gitsheetsClass` discriminant the core sets — never the message.
|
|
85
|
+
function mapCoreError(raw) {
|
|
86
|
+
const Cls = CLASS_BY_NAME[raw && raw.gitsheetsClass] ?? GitsheetsError;
|
|
87
|
+
const opts = { code: raw.code, status: raw.status, cause: raw };
|
|
88
|
+
if (raw.issues !== undefined) opts.issues = raw.issues;
|
|
89
|
+
if (raw.conflictingPaths !== undefined) opts.conflictingPaths = raw.conflictingPaths;
|
|
90
|
+
return new Cls(raw.message, opts);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Wrap an addon call so any structured core error surfaces as its typed class.
|
|
94
|
+
function wrap(fn) {
|
|
95
|
+
return (...args) => {
|
|
96
|
+
try {
|
|
97
|
+
return fn(...args);
|
|
98
|
+
} catch (raw) {
|
|
99
|
+
if (raw && typeof raw.gitsheetsClass === 'string') throw mapCoreError(raw);
|
|
100
|
+
throw raw;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module.exports = {
|
|
106
|
+
// Marshalling entry points (batch-first).
|
|
107
|
+
roundtrip: addon.roundtrip,
|
|
108
|
+
// Canonical TOML bytes-authority (batch-first). Parse/serialize can raise a
|
|
109
|
+
// structured core error (`config_invalid`), surfaced as its typed class.
|
|
110
|
+
parseRecords: wrap(addon.parseRecords),
|
|
111
|
+
serializeRecords: wrap(addon.serializeRecords),
|
|
112
|
+
// Definition logic (batch-first). Path rendering raises a typed
|
|
113
|
+
// PathTemplateError; schema compilation raises a typed ConfigError.
|
|
114
|
+
renderPathsBatch: wrap(addon.renderPathsBatch),
|
|
115
|
+
validateBatch: wrap(addon.validateBatch),
|
|
116
|
+
runComparator: wrap(addon.runComparator),
|
|
117
|
+
// Native locale array sort (declarative `sort = true`) — the ICU collator
|
|
118
|
+
// matching V8 `localeCompare`. Pure (no structured errors), so unwrapped.
|
|
119
|
+
collatorSort: addon.collatorSort,
|
|
120
|
+
// Stateful compiled definition (compile-once / reuse). Raw class — its
|
|
121
|
+
// structured errors carry `gitsheetsClass`; map with `mapCoreError` if needed.
|
|
122
|
+
CompiledDefinition: addon.CompiledDefinition,
|
|
123
|
+
// Record CRUD over the holo-tree substrate (batch-first). Substrate / record
|
|
124
|
+
// parse failures surface as typed core errors.
|
|
125
|
+
recordRead: wrap(addon.recordRead),
|
|
126
|
+
recordWrite: wrap(addon.recordWrite),
|
|
127
|
+
recordDelete: wrap(addon.recordDelete),
|
|
128
|
+
recordList: wrap(addon.recordList),
|
|
129
|
+
diffRecords: wrap(addon.diffRecords),
|
|
130
|
+
// Blob-write primitive: hash raw attachment bytes into the ODB. A substrate
|
|
131
|
+
// failure surfaces as a typed core error.
|
|
132
|
+
writeBlob: wrap(addon.writeBlob),
|
|
133
|
+
// Query traversal + filtering (batch-first): the template prunes the walk and
|
|
134
|
+
// the filter (equality / nested / `$pred` engine snippets) runs in the core.
|
|
135
|
+
recordQuery: wrap(addon.recordQuery),
|
|
136
|
+
recordQueryCandidates: wrap(addon.recordQueryCandidates),
|
|
137
|
+
templateFieldNames: wrap(addon.templateFieldNames),
|
|
138
|
+
// Secondary indexing (lazy, in-memory). A unique conflict surfaces as a typed
|
|
139
|
+
// IndexError(index_unique_conflict).
|
|
140
|
+
recordIndexUnique: wrap(addon.recordIndexUnique),
|
|
141
|
+
recordIndexMulti: wrap(addon.recordIndexMulti),
|
|
142
|
+
// Substrate (holo-tree) read/write counters — bulk benchmark instrumentation.
|
|
143
|
+
substrateStats: addon.substrateStats,
|
|
144
|
+
substrateReset: addon.substrateReset,
|
|
145
|
+
// Diff / patch primitives (RFC 6902 createPatch, RFC 7396 mergePatch).
|
|
146
|
+
createPatch: wrap(addon.createPatch),
|
|
147
|
+
applyMergePatch: wrap(addon.applyMergePatch),
|
|
148
|
+
// Orchestration: Sheet / Transaction / Store state machine (sheet-store-core).
|
|
149
|
+
// CoreTransaction is the stateful two-phase-protocol driver. Raw class — its
|
|
150
|
+
// methods throw structured errors carrying `gitsheetsClass`/`code`; map with
|
|
151
|
+
// `mapCoreError` where a typed instance is wanted.
|
|
152
|
+
CoreTransaction: addon.CoreTransaction,
|
|
153
|
+
coreDiscoverSheets: wrap(addon.coreDiscoverSheets),
|
|
154
|
+
coreCheckValidators: wrap(addon.coreCheckValidators),
|
|
155
|
+
// Markdown / mdx content-type codec. serialize/parse can raise a typed
|
|
156
|
+
// ValidationError/ConfigError; the H1 + normalize helpers are pure. Body
|
|
157
|
+
// NORMALIZATION is native — `markdownSerialize` runs the embedded
|
|
158
|
+
// `dprint-plugin-markdown` formatter (unless `normalize: false` is passed), and
|
|
159
|
+
// `markdownNormalizeBody` exposes it directly (see gitsheets_core::codec docs).
|
|
160
|
+
markdownSerialize: wrap(addon.markdownSerialize),
|
|
161
|
+
markdownParse: wrap(addon.markdownParse),
|
|
162
|
+
markdownParseHeaderOnly: wrap(addon.markdownParseHeaderOnly),
|
|
163
|
+
markdownExtractH1: addon.markdownExtractH1,
|
|
164
|
+
markdownRewriteH1: addon.markdownRewriteH1,
|
|
165
|
+
markdownNormalizeBody: addon.markdownNormalizeBody,
|
|
166
|
+
// Boundary-test entry: throws the typed class for a given stable code.
|
|
167
|
+
simulateCoreError: wrap(addon.simulateCoreError),
|
|
168
|
+
// Error machinery.
|
|
169
|
+
mapCoreError,
|
|
170
|
+
GitsheetsError,
|
|
171
|
+
ConfigError,
|
|
172
|
+
ValidationError,
|
|
173
|
+
TransactionError,
|
|
174
|
+
IndexError,
|
|
175
|
+
RefError,
|
|
176
|
+
PathTemplateError,
|
|
177
|
+
NotFoundError,
|
|
178
|
+
};
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/* auto-generated by NAPI-RS */
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Round-trip a **batch** of records through the core, preserving full type
|
|
8
|
+
* fidelity. The whole array crosses the FFI once. This is the foundation's
|
|
9
|
+
* stand-in for the real batch engine entry points (`upsertMany`, `queryAll`,
|
|
10
|
+
* …), which keep this same batch-first signature.
|
|
11
|
+
*/
|
|
12
|
+
export declare function roundtrip(records: Array<JsValue>): Array<JsValue>
|
|
13
|
+
/**
|
|
14
|
+
* Parse a **batch** of TOML documents into records, marshalled to JS with full
|
|
15
|
+
* type fidelity. The whole array crosses the FFI once (batch-first). A
|
|
16
|
+
* malformed document surfaces as a structured, typed core error (`config_invalid`).
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseRecords(documents: Array<string>): Array<JsValue>
|
|
19
|
+
/**
|
|
20
|
+
* Serialize a **batch** of records to their canonical TOML bytes in one call
|
|
21
|
+
* (deep key sort + `toml`-crate default formatting; see `gitsheets_core::canonical`).
|
|
22
|
+
* A value TOML can't represent surfaces as a structured, typed core error.
|
|
23
|
+
*/
|
|
24
|
+
export declare function serializeRecords(records: Array<JsValue>): Array<string>
|
|
25
|
+
/**
|
|
26
|
+
* One JSON-Schema validation failure, marshalled to the `ValidationIssue`
|
|
27
|
+
* shape the host surface uses (`source`/`schemaPath`/`code`, with snake fields
|
|
28
|
+
* rendered camelCase by napi). Returned by [`validate_batch`].
|
|
29
|
+
*/
|
|
30
|
+
export interface JsValidationIssue {
|
|
31
|
+
path: Array<string>
|
|
32
|
+
message: string
|
|
33
|
+
source: string
|
|
34
|
+
schemaPath?: string
|
|
35
|
+
code?: string
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Render a path template against a **batch** of records, returning one path per
|
|
39
|
+
* record (no file extension; the caller appends `.toml`/`.md`). The template is
|
|
40
|
+
* parsed and its expression components compiled into the embedded engine
|
|
41
|
+
* **once**, then reused across the whole batch — the bulk path crosses the FFI
|
|
42
|
+
* a single time. A render failure surfaces as a structured, typed
|
|
43
|
+
* `PathTemplateError` (`path_render_failed` / `path_invalid_chars`). This is the
|
|
44
|
+
* path-template half of the `node:vm` parity gate.
|
|
45
|
+
*/
|
|
46
|
+
export declare function renderPathsBatch(template: string, records: Array<JsValue>): Array<string>
|
|
47
|
+
/**
|
|
48
|
+
* Validate a **batch** of records against a JSON Schema, returning the issues
|
|
49
|
+
* for each record (an empty inner array ⇒ that record is valid). The schema is
|
|
50
|
+
* compiled **once**, then reused across the batch. Unlike the host's throwing
|
|
51
|
+
* `validateRecord`, this returns issues per record so a parity harness can diff
|
|
52
|
+
* the full pass/fail + path/keyword picture against `ajv`. A schema that won't
|
|
53
|
+
* compile surfaces as a structured, typed `ConfigError` (`config_invalid`).
|
|
54
|
+
*/
|
|
55
|
+
export declare function validateBatch(schema: JsValue, records: Array<JsValue>): Array<Array<JsValidationIssue>>
|
|
56
|
+
/**
|
|
57
|
+
* Compile a raw-JS sort comparator (`rule`, the body of `(a, b) => { … }`) and
|
|
58
|
+
* run it once against `a`/`b`, returning its numeric result. The direct
|
|
59
|
+
* comparator-parity entry point: a harness asserts this equals the same rule
|
|
60
|
+
* run through `node:vm` for identical inputs.
|
|
61
|
+
*/
|
|
62
|
+
export declare function runComparator(rule: string, a: JsValue, b: JsValue): number
|
|
63
|
+
/**
|
|
64
|
+
* Native locale array sort — the declarative `sort = true` path. Sorts the
|
|
65
|
+
* strings with the ICU collator that matches V8's `localeCompare(b, undefined,
|
|
66
|
+
* { sensitivity: 'base', ignorePunctuation: true, numeric: true })`. This is the
|
|
67
|
+
* exact function `Sheet::normalize_record` applies for a `sort = true` field, and
|
|
68
|
+
* it does **NOT** route through the boa engine (boa lacks `Intl`, so its
|
|
69
|
+
* `localeCompare` falls back to code-unit order and diverges from `node:vm` on
|
|
70
|
+
* non-ASCII / mixed-case input). Exposed so a `node --test` harness asserts
|
|
71
|
+
* byte-exact parity against `node`'s `localeCompare` — see
|
|
72
|
+
* `test/collator-parity.mjs`.
|
|
73
|
+
*/
|
|
74
|
+
export declare function collatorSort(strings: Array<string>): Array<string>
|
|
75
|
+
/**
|
|
76
|
+
* Read a batch of records by path. Each result is the record (a plain object
|
|
77
|
+
* with full TOML type fidelity) or `null` when no blob lives at that path.
|
|
78
|
+
*/
|
|
79
|
+
export declare function recordRead(gitDir: string, treeRef: string, base: string, paths: Array<string>, extension?: string | undefined | null): Array<JsValue | undefined | null>
|
|
80
|
+
/**
|
|
81
|
+
* The result of a `record_write`/`record_delete`: the new root tree hash plus
|
|
82
|
+
* per-record output (`blobHashes` for writes, `existed` for deletes).
|
|
83
|
+
*/
|
|
84
|
+
export interface JsWriteOutcome {
|
|
85
|
+
treeHash: string
|
|
86
|
+
blobHashes: Array<string>
|
|
87
|
+
}
|
|
88
|
+
/** The result of a `record_delete`. */
|
|
89
|
+
export interface JsDeleteOutcome {
|
|
90
|
+
treeHash: string
|
|
91
|
+
existed: Array<boolean>
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Write a batch of records (canonical TOML) under `base`, starting from the
|
|
95
|
+
* tree `baseRef`. `paths[i]` is written from `records[i]`. Returns the new root
|
|
96
|
+
* tree hash + each written blob hash. The bytes are produced by the core's
|
|
97
|
+
* bytes-authority, so two bindings writing the same record agree byte-for-byte.
|
|
98
|
+
*/
|
|
99
|
+
export declare function recordWrite(gitDir: string, baseRef: string, base: string, paths: Array<string>, records: Array<JsValue>, extension?: string | undefined | null): JsWriteOutcome
|
|
100
|
+
/**
|
|
101
|
+
* Delete a batch of records by path under `base`, starting from `baseRef`.
|
|
102
|
+
* `existed[i]` reports whether `paths[i]` was actually present.
|
|
103
|
+
*/
|
|
104
|
+
export declare function recordDelete(gitDir: string, baseRef: string, base: string, paths: Array<string>, extension?: string | undefined | null): JsDeleteOutcome
|
|
105
|
+
/**
|
|
106
|
+
* One record from `record_list`: its path (relative to `base`, no extension)
|
|
107
|
+
* and parsed value.
|
|
108
|
+
*/
|
|
109
|
+
export interface JsRecordEntry {
|
|
110
|
+
path: string
|
|
111
|
+
record: JsValue
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* List every record under `base` in the tree `treeRef`, in sorted
|
|
115
|
+
* (git-canonical) path order.
|
|
116
|
+
*/
|
|
117
|
+
export declare function recordList(gitDir: string, treeRef: string, base: string, extension?: string | undefined | null): Array<JsRecordEntry>
|
|
118
|
+
/**
|
|
119
|
+
* Hash raw bytes into the object database as a loose blob, returning its git
|
|
120
|
+
* blob hash — the core's blob-write primitive (replaces the JS package's direct
|
|
121
|
+
* `@hologit/holo-tree` `writeBlob`). Used by the CLI/host to hash a binary
|
|
122
|
+
* attachment before staging it into a record's attachment tree with
|
|
123
|
+
* `CoreTransaction.setAttachment(s)`. The hash is a pure function of the bytes,
|
|
124
|
+
* so Node and Python hashing the same content produce the same object.
|
|
125
|
+
*/
|
|
126
|
+
export declare function writeBlob(gitDir: string, content: Buffer): string
|
|
127
|
+
/**
|
|
128
|
+
* A snapshot of holo-tree's process-wide tree/blob counters — read-side
|
|
129
|
+
* instrumentation for the bulk benchmark and the hologit#464 perf finding.
|
|
130
|
+
*/
|
|
131
|
+
export interface JsSubstrateStats {
|
|
132
|
+
treesRead: number
|
|
133
|
+
treesWritten: number
|
|
134
|
+
treesSkippedClean: number
|
|
135
|
+
cacheHits: number
|
|
136
|
+
cacheMisses: number
|
|
137
|
+
blobsRead: number
|
|
138
|
+
}
|
|
139
|
+
/** Snapshot the substrate (holo-tree) counters. */
|
|
140
|
+
export declare function substrateStats(): JsSubstrateStats
|
|
141
|
+
/** Reset the substrate counters + the thread-local tree cache. */
|
|
142
|
+
export declare function substrateReset(): void
|
|
143
|
+
/**
|
|
144
|
+
* Query records under `base` in the tree `treeRef`, returning each matched
|
|
145
|
+
* `{ path, record }` in sorted path order. The template prunes the walk; the
|
|
146
|
+
* filter (equality / nested / `$pred` snippets) is applied to each candidate.
|
|
147
|
+
* Batch-first: the whole query crosses the FFI once.
|
|
148
|
+
*/
|
|
149
|
+
export declare function recordQuery(gitDir: string, treeRef: string, base: string, template: string, filter: object, extension?: string | undefined | null): Array<JsRecordEntry>
|
|
150
|
+
/**
|
|
151
|
+
* The pruning candidate set alone (no content filter applied) — the direct
|
|
152
|
+
* parity target for the host `Template.queryTree`. `query` is a (partial)
|
|
153
|
+
* record of the path-template input fields. Returns candidate record paths
|
|
154
|
+
* (relative to `base`, no extension) in sorted order.
|
|
155
|
+
*/
|
|
156
|
+
export declare function recordQueryCandidates(gitDir: string, treeRef: string, base: string, template: string, query: JsValue, extension?: string | undefined | null): Array<string>
|
|
157
|
+
/**
|
|
158
|
+
* The record fields that contribute to rendering `template` — the query
|
|
159
|
+
* auto-derivation set (`Template.getFieldNames` parity). Insertion-ordered,
|
|
160
|
+
* de-duplicated; expression components contribute a best-effort identifier
|
|
161
|
+
* scan minus JS keywords/globals.
|
|
162
|
+
*/
|
|
163
|
+
export declare function templateFieldNames(template: string): Array<string>
|
|
164
|
+
/**
|
|
165
|
+
* Build a **unique** index over the records under `base` and look up each key.
|
|
166
|
+
* `results[i]` is the record for `keys[i]`, or `null` when no record carries
|
|
167
|
+
* it. A duplicate key throws `IndexError(index_unique_conflict)` naming both
|
|
168
|
+
* paths.
|
|
169
|
+
*/
|
|
170
|
+
export declare function recordIndexUnique(gitDir: string, treeRef: string, base: string, keySnippet: string, keys: Array<string>, extension?: string | undefined | null): Array<JsValue | undefined | null>
|
|
171
|
+
/**
|
|
172
|
+
* Build a **non-unique** index over the records under `base` and look up each
|
|
173
|
+
* key. `results[i]` is every record carrying `keys[i]` (an empty array when
|
|
174
|
+
* none).
|
|
175
|
+
*/
|
|
176
|
+
export declare function recordIndexMulti(gitDir: string, treeRef: string, base: string, keySnippet: string, keys: Array<string>, extension?: string | undefined | null): Array<Array<JsValue>>
|
|
177
|
+
/**
|
|
178
|
+
* Generate an RFC 6902 JSON Patch transforming `src` into `dst` — the core's
|
|
179
|
+
* `createPatch`, matching the `rfc6902` package op-for-op. `null`/`undefined`
|
|
180
|
+
* on either side is the JSON null `Sheet.diffFrom` passes for an added
|
|
181
|
+
* (`src=null`) or deleted (`dst=null`) record.
|
|
182
|
+
*/
|
|
183
|
+
export declare function createPatch(src?: JsValue | undefined | null, dst?: JsValue | undefined | null): object
|
|
184
|
+
/**
|
|
185
|
+
* Apply an RFC 7396 JSON Merge Patch to `target` (`null` ⇒ absent), returning
|
|
186
|
+
* the merged record — the core's `mergePatch` behind `Sheet.patch`. A `null`
|
|
187
|
+
* in the patch deletes that key; an object merges recursively; anything else
|
|
188
|
+
* replaces wholesale. Returns `null` only when the patch deletes the record
|
|
189
|
+
* outright.
|
|
190
|
+
*/
|
|
191
|
+
export declare function applyMergePatch(target: JsValue | undefined | null, patch: JsMergePatch): JsValue | null
|
|
192
|
+
/**
|
|
193
|
+
* Diff records between two trees (`srcRef` → `dstRef`) under `base`, returning
|
|
194
|
+
* one entry per change with status, src/dst blob hashes, the parsed src/dst
|
|
195
|
+
* records, and the RFC 6902 patch — the full `Sheet.diffFrom({records,
|
|
196
|
+
* patches})` payload, computed in the core. `srcRef` may be the empty-tree hash
|
|
197
|
+
* for a from-scratch diff.
|
|
198
|
+
*/
|
|
199
|
+
export declare function diffRecords(gitDir: string, srcRef: string, dstRef: string, base: string, extension?: string | undefined | null): object
|
|
200
|
+
/**
|
|
201
|
+
* Throw the core error for a given stable `code`, surfaced as a **structured,
|
|
202
|
+
* matchable** JS error (own `code`, `status`, `gitsheetsClass`, and any
|
|
203
|
+
* `issues`/`conflictingPaths`). Boundary-test entry point: it exercises the
|
|
204
|
+
* error-variant → typed-class mapping without standing up real engine paths.
|
|
205
|
+
*/
|
|
206
|
+
export declare function simulateCoreError(code: string): void
|
|
207
|
+
/** Commit identity for the JS surface. */
|
|
208
|
+
export interface JsAuthor {
|
|
209
|
+
name: string
|
|
210
|
+
email: string
|
|
211
|
+
}
|
|
212
|
+
/** One ordered commit trailer (`Key: value`). */
|
|
213
|
+
export interface JsTrailer {
|
|
214
|
+
key: string
|
|
215
|
+
value: string
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Options for opening a [`CoreTransaction`]. `timeSeconds` / `offsetMinutes`
|
|
219
|
+
* carry the host clock + local-timezone offset (a host concern), exactly as the
|
|
220
|
+
* JS `commitTreeWithRepo` computes them today.
|
|
221
|
+
*/
|
|
222
|
+
export interface JsTransactionOptions {
|
|
223
|
+
parent?: string
|
|
224
|
+
branch?: string
|
|
225
|
+
author?: JsAuthor
|
|
226
|
+
committer?: JsAuthor
|
|
227
|
+
message: string
|
|
228
|
+
trailers?: Array<JsTrailer>
|
|
229
|
+
timeSeconds: number
|
|
230
|
+
offsetMinutes: number
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* The outcome of [`CoreTransaction::finalize`]. A no-op (no mutation, or the
|
|
234
|
+
* resulting tree equals the parent's) returns `commitHash = null`.
|
|
235
|
+
*/
|
|
236
|
+
export interface JsTransactionResult {
|
|
237
|
+
commitHash?: string
|
|
238
|
+
treeHash?: string
|
|
239
|
+
refName?: string
|
|
240
|
+
parentCommitHash?: string
|
|
241
|
+
}
|
|
242
|
+
/** The outcome of [`CoreTransaction::stage_upsert`]. */
|
|
243
|
+
export interface JsStageOutcome {
|
|
244
|
+
blobHash: string
|
|
245
|
+
path: string
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* One attachment entry from `CoreTransaction.getAttachments`: its filename and
|
|
249
|
+
* blob hash (name → hash).
|
|
250
|
+
*/
|
|
251
|
+
export interface JsAttachmentEntry {
|
|
252
|
+
name: string
|
|
253
|
+
hash: string
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Discover every sheet declared in `<openRoot>/.gitsheets/*.toml` in the tree
|
|
257
|
+
* `treeRef`. Sorted bare names. The `Store` discovery half (`openStore`).
|
|
258
|
+
*/
|
|
259
|
+
export declare function coreDiscoverSheets(gitDir: string, treeRef: string, openRoot: string): Array<string>
|
|
260
|
+
/**
|
|
261
|
+
* The `openStore` `config_missing` check: every validator must name a declared
|
|
262
|
+
* sheet. Throws `ConfigError(config_missing)` otherwise.
|
|
263
|
+
*/
|
|
264
|
+
export declare function coreCheckValidators(declared: Array<string>, validatorNames: Array<string>): void
|
|
265
|
+
/**
|
|
266
|
+
* Serialize a record to its on-disk markdown bytes (`+++` frontmatter + body),
|
|
267
|
+
* enforcing the title-from-H1 invariant when `titleField` is set. The body is
|
|
268
|
+
* normalized natively by the embedded `dprint-plugin-markdown` formatter unless
|
|
269
|
+
* `normalize` is `false` (then it is framed verbatim). A non-string body or a
|
|
270
|
+
* title that disagrees with the body's (normalized) H1 throws a typed
|
|
271
|
+
* `ValidationError`.
|
|
272
|
+
*/
|
|
273
|
+
export declare function markdownSerialize(record: JsValue, bodyField: string, titleField?: string | undefined | null, normalize?: boolean | undefined | null): string
|
|
274
|
+
/**
|
|
275
|
+
* Normalize a markdown body with the native `dprint-plugin-markdown` formatter
|
|
276
|
+
* (the pinned aggressive `textWrap: never` config). Deterministic + idempotent.
|
|
277
|
+
* Exposed so the boundary suite can assert the normalizer directly.
|
|
278
|
+
*/
|
|
279
|
+
export declare function markdownNormalizeBody(body: string): string
|
|
280
|
+
/**
|
|
281
|
+
* Parse on-disk markdown bytes into a full record (frontmatter fields + the
|
|
282
|
+
* body under `bodyField`). Mirrors `markdownFormat.parse`.
|
|
283
|
+
*/
|
|
284
|
+
export declare function markdownParse(text: string, bodyField: string, titleField?: string | undefined | null): JsValue
|
|
285
|
+
/**
|
|
286
|
+
* Parse only the frontmatter — the lazy-body path. The body field is absent in
|
|
287
|
+
* the returned record. Mirrors `markdownFormat.parseHeaderOnly`.
|
|
288
|
+
*/
|
|
289
|
+
export declare function markdownParseHeaderOnly(text: string, bodyField: string): JsValue
|
|
290
|
+
/**
|
|
291
|
+
* Extract the first ATX-style H1 from a markdown body, or `null` if absent.
|
|
292
|
+
* Mirrors `extractFirstH1`.
|
|
293
|
+
*/
|
|
294
|
+
export declare function markdownExtractH1(body: string): string | null
|
|
295
|
+
/**
|
|
296
|
+
* Rewrite (or prepend) the first ATX H1 of a markdown body to `title`. Mirrors
|
|
297
|
+
* `rewriteLeadingH1` — the `Sheet.patch` title-reconciliation helper.
|
|
298
|
+
*/
|
|
299
|
+
export declare function markdownRewriteH1(body: string, title: string): string
|
|
300
|
+
/**
|
|
301
|
+
* A compiled sheet definition: the embedded engine plus the definition's
|
|
302
|
+
* path template (and optional raw-JS sort comparator), **compiled once** at
|
|
303
|
+
* construction and reused across every method call. Holds a `!Send` boa
|
|
304
|
+
* context, so it is constructed and used on its owning JS thread — the
|
|
305
|
+
* thread-confinement the spec requires. Exists to demonstrate the
|
|
306
|
+
* compile-once-per-open / reuse-across-operations contract from JS.
|
|
307
|
+
*/
|
|
308
|
+
export declare class CompiledDefinition {
|
|
309
|
+
/**
|
|
310
|
+
* Compile a definition once: parse the path template (compiling its
|
|
311
|
+
* expression snippets into the engine) and, if given, compile a raw-JS sort
|
|
312
|
+
* comparator. All snippet compilation happens here — never per operation.
|
|
313
|
+
*/
|
|
314
|
+
constructor(pathTemplate: string, sortRule?: string | undefined | null)
|
|
315
|
+
/** Render one record's path using the already-compiled template. */
|
|
316
|
+
renderPath(record: JsValue): string
|
|
317
|
+
/**
|
|
318
|
+
* Run the compiled sort comparator on two values, returning its numeric
|
|
319
|
+
* result. Errors if the definition was built without a sort rule.
|
|
320
|
+
*/
|
|
321
|
+
compare(a: JsValue, b: JsValue): number
|
|
322
|
+
/**
|
|
323
|
+
* How many snippets were compiled into this definition's engine. Constant
|
|
324
|
+
* across operations — proof that compilation happened once at construction,
|
|
325
|
+
* not per `render_path` / `compare` call.
|
|
326
|
+
*/
|
|
327
|
+
snippetCount(): number
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* A live transaction the JS boundary suite drives. Holds a `!Send`
|
|
331
|
+
* `Transaction` (repo + private tree) and the opened `Sheet`s, so it is
|
|
332
|
+
* constructed and used on its owning JS thread — the thread-confinement the
|
|
333
|
+
* spec requires.
|
|
334
|
+
*/
|
|
335
|
+
export declare class CoreTransaction {
|
|
336
|
+
/**
|
|
337
|
+
* Open a transaction against `gitDir`. Resolves the parent/branch, builds
|
|
338
|
+
* the private tree, and acquires the single-writer slot. A concurrent open
|
|
339
|
+
* on the same repo throws `TransactionError(transaction_in_progress)`.
|
|
340
|
+
*/
|
|
341
|
+
static begin(gitDir: string, opts: JsTransactionOptions): CoreTransaction
|
|
342
|
+
/**
|
|
343
|
+
* Open a sheet against this transaction's tree (config read + template /
|
|
344
|
+
* schema / sort comparators compiled once).
|
|
345
|
+
*/
|
|
346
|
+
openSheet(name: string, configPath: string, openRoot: string, prefix: string): void
|
|
347
|
+
/**
|
|
348
|
+
* Phase 1 of the two-phase protocol *(non-mutating)*. Returns the candidate
|
|
349
|
+
* (`path`, `nextText`, and the normalized `record`) for the host validator;
|
|
350
|
+
* the candidate is stashed for a subsequent `stageUpsert`. A JSON-Schema
|
|
351
|
+
* rejection throws `ValidationError` here, before any bytes are written.
|
|
352
|
+
*/
|
|
353
|
+
prepareUpsert(name: string, record: JsValue, previousPath?: string | undefined | null, allowMissingBody?: boolean | undefined | null): object
|
|
354
|
+
/**
|
|
355
|
+
* Phase 3 *(mutating)*: write the stashed candidate from the last
|
|
356
|
+
* `prepareUpsert` for `name`. Marks the transaction mutated.
|
|
357
|
+
*/
|
|
358
|
+
stageUpsert(name: string): JsStageOutcome
|
|
359
|
+
/**
|
|
360
|
+
* Pre-flight idempotency check (`Sheet.willChange`) — same phase-1 pipeline,
|
|
361
|
+
* then a byte comparison to the existing blob. Non-mutating.
|
|
362
|
+
*/
|
|
363
|
+
willChange(name: string, record: JsValue, previousPath?: string | undefined | null, allowMissingBody?: boolean | undefined | null): object
|
|
364
|
+
/**
|
|
365
|
+
* Delete a record by its sheet-relative path *(mutating)*. Throws
|
|
366
|
+
* `NotFoundError(record_not_found)` when absent.
|
|
367
|
+
*/
|
|
368
|
+
delete(name: string, recordPath: string): void
|
|
369
|
+
/** `Sheet.clear` *(mutating)* — empties the sheet's data subtree. */
|
|
370
|
+
clear(name: string): void
|
|
371
|
+
/**
|
|
372
|
+
* Stage attachments for a record *(mutating)*: place each `name → blobHash`
|
|
373
|
+
* at `<recordPath>/<name>` in this transaction's live tree, so the record
|
|
374
|
+
* and its attachments commit atomically. Write the blob first with the
|
|
375
|
+
* top-level `writeBlob`. Marks the transaction mutated.
|
|
376
|
+
*/
|
|
377
|
+
setAttachments(name: string, recordPath: string, attachments: Record<string, string>): void
|
|
378
|
+
/** Stage a single attachment *(mutating)* — sugar over [`Self::set_attachments`]. */
|
|
379
|
+
setAttachment(name: string, recordPath: string, attachmentName: string, blobHash: string): void
|
|
380
|
+
/**
|
|
381
|
+
* Stage a raw text file at `path` in this transaction's private tree
|
|
382
|
+
* *(mutating)* — the generic file write the CLI uses to commit sheet-config
|
|
383
|
+
* edits (`init` / `infer` / `migrate-config`) atomically alongside nothing
|
|
384
|
+
* else. `path` is repo-root-relative. Returns the written blob hash.
|
|
385
|
+
*/
|
|
386
|
+
writeFile(path: string, content: string): string
|
|
387
|
+
/**
|
|
388
|
+
* The blob-hash map of a record's attachments (`name → hash`, sorted by
|
|
389
|
+
* name), or `null` when the record has no attachment directory. Read-only.
|
|
390
|
+
*/
|
|
391
|
+
getAttachments(name: string, recordPath: string): Array<JsAttachmentEntry> | null
|
|
392
|
+
/** The blob hash of a single named attachment, or `null` if absent. Read-only. */
|
|
393
|
+
getAttachment(name: string, recordPath: string, attachmentName: string): string | null
|
|
394
|
+
/**
|
|
395
|
+
* Remove a single named attachment *(mutating)*. Throws
|
|
396
|
+
* `NotFoundError(record_not_found)` when it doesn't exist. Marks mutated.
|
|
397
|
+
*/
|
|
398
|
+
deleteAttachment(name: string, recordPath: string, attachmentName: string): void
|
|
399
|
+
/**
|
|
400
|
+
* Remove all attachments for a record *(mutating)*. A no-op when the record
|
|
401
|
+
* has no attachment directory — in that case the transaction is NOT marked
|
|
402
|
+
* mutated (so an otherwise-empty transaction still finalizes to no commit).
|
|
403
|
+
* Returns whether anything was removed.
|
|
404
|
+
*/
|
|
405
|
+
deleteAttachments(name: string, recordPath: string): boolean
|
|
406
|
+
/**
|
|
407
|
+
* List every record under the sheet's base, decoded through the format
|
|
408
|
+
* codec, in sorted path order. `withBody` is the lazy-body switch for
|
|
409
|
+
* markdown sheets (`false` omits the body field); a no-op for TOML sheets.
|
|
410
|
+
* Read-only — does not mark the transaction mutated.
|
|
411
|
+
*/
|
|
412
|
+
list(name: string, withBody: boolean): Array<JsRecordEntry>
|
|
413
|
+
/** The parent commit hash captured at open (null on a fresh repo). */
|
|
414
|
+
parentCommitHash(): string | null
|
|
415
|
+
/**
|
|
416
|
+
* Finalize: commit-on-success-only with no-op detection + `parent_moved`
|
|
417
|
+
* re-check + CAS ref movement. Consumes the transaction.
|
|
418
|
+
*/
|
|
419
|
+
finalize(): JsTransactionResult
|
|
420
|
+
/** Discard without committing (handler threw). Releases the writer slot. */
|
|
421
|
+
discard(): void
|
|
422
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
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, 'gitsheets-core.android-arm64.node'))
|
|
36
|
+
try {
|
|
37
|
+
if (localFileExisted) {
|
|
38
|
+
nativeBinding = require('./gitsheets-core.android-arm64.node')
|
|
39
|
+
} else {
|
|
40
|
+
nativeBinding = require('@gitsheets/core-napi-android-arm64')
|
|
41
|
+
}
|
|
42
|
+
} catch (e) {
|
|
43
|
+
loadError = e
|
|
44
|
+
}
|
|
45
|
+
break
|
|
46
|
+
case 'arm':
|
|
47
|
+
localFileExisted = existsSync(join(__dirname, 'gitsheets-core.android-arm-eabi.node'))
|
|
48
|
+
try {
|
|
49
|
+
if (localFileExisted) {
|
|
50
|
+
nativeBinding = require('./gitsheets-core.android-arm-eabi.node')
|
|
51
|
+
} else {
|
|
52
|
+
nativeBinding = require('@gitsheets/core-napi-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, 'gitsheets-core.win32-x64-msvc.node')
|
|
67
|
+
)
|
|
68
|
+
try {
|
|
69
|
+
if (localFileExisted) {
|
|
70
|
+
nativeBinding = require('./gitsheets-core.win32-x64-msvc.node')
|
|
71
|
+
} else {
|
|
72
|
+
nativeBinding = require('@gitsheets/core-napi-win32-x64-msvc')
|
|
73
|
+
}
|
|
74
|
+
} catch (e) {
|
|
75
|
+
loadError = e
|
|
76
|
+
}
|
|
77
|
+
break
|
|
78
|
+
case 'ia32':
|
|
79
|
+
localFileExisted = existsSync(
|
|
80
|
+
join(__dirname, 'gitsheets-core.win32-ia32-msvc.node')
|
|
81
|
+
)
|
|
82
|
+
try {
|
|
83
|
+
if (localFileExisted) {
|
|
84
|
+
nativeBinding = require('./gitsheets-core.win32-ia32-msvc.node')
|
|
85
|
+
} else {
|
|
86
|
+
nativeBinding = require('@gitsheets/core-napi-win32-ia32-msvc')
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
loadError = e
|
|
90
|
+
}
|
|
91
|
+
break
|
|
92
|
+
case 'arm64':
|
|
93
|
+
localFileExisted = existsSync(
|
|
94
|
+
join(__dirname, 'gitsheets-core.win32-arm64-msvc.node')
|
|
95
|
+
)
|
|
96
|
+
try {
|
|
97
|
+
if (localFileExisted) {
|
|
98
|
+
nativeBinding = require('./gitsheets-core.win32-arm64-msvc.node')
|
|
99
|
+
} else {
|
|
100
|
+
nativeBinding = require('@gitsheets/core-napi-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, 'gitsheets-core.darwin-universal.node'))
|
|
112
|
+
try {
|
|
113
|
+
if (localFileExisted) {
|
|
114
|
+
nativeBinding = require('./gitsheets-core.darwin-universal.node')
|
|
115
|
+
} else {
|
|
116
|
+
nativeBinding = require('@gitsheets/core-napi-darwin-universal')
|
|
117
|
+
}
|
|
118
|
+
break
|
|
119
|
+
} catch {}
|
|
120
|
+
switch (arch) {
|
|
121
|
+
case 'x64':
|
|
122
|
+
localFileExisted = existsSync(join(__dirname, 'gitsheets-core.darwin-x64.node'))
|
|
123
|
+
try {
|
|
124
|
+
if (localFileExisted) {
|
|
125
|
+
nativeBinding = require('./gitsheets-core.darwin-x64.node')
|
|
126
|
+
} else {
|
|
127
|
+
nativeBinding = require('@gitsheets/core-napi-darwin-x64')
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {
|
|
130
|
+
loadError = e
|
|
131
|
+
}
|
|
132
|
+
break
|
|
133
|
+
case 'arm64':
|
|
134
|
+
localFileExisted = existsSync(
|
|
135
|
+
join(__dirname, 'gitsheets-core.darwin-arm64.node')
|
|
136
|
+
)
|
|
137
|
+
try {
|
|
138
|
+
if (localFileExisted) {
|
|
139
|
+
nativeBinding = require('./gitsheets-core.darwin-arm64.node')
|
|
140
|
+
} else {
|
|
141
|
+
nativeBinding = require('@gitsheets/core-napi-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, 'gitsheets-core.freebsd-x64.node'))
|
|
156
|
+
try {
|
|
157
|
+
if (localFileExisted) {
|
|
158
|
+
nativeBinding = require('./gitsheets-core.freebsd-x64.node')
|
|
159
|
+
} else {
|
|
160
|
+
nativeBinding = require('@gitsheets/core-napi-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, 'gitsheets-core.linux-x64-musl.node')
|
|
172
|
+
)
|
|
173
|
+
try {
|
|
174
|
+
if (localFileExisted) {
|
|
175
|
+
nativeBinding = require('./gitsheets-core.linux-x64-musl.node')
|
|
176
|
+
} else {
|
|
177
|
+
nativeBinding = require('@gitsheets/core-napi-linux-x64-musl')
|
|
178
|
+
}
|
|
179
|
+
} catch (e) {
|
|
180
|
+
loadError = e
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
localFileExisted = existsSync(
|
|
184
|
+
join(__dirname, 'gitsheets-core.linux-x64-gnu.node')
|
|
185
|
+
)
|
|
186
|
+
try {
|
|
187
|
+
if (localFileExisted) {
|
|
188
|
+
nativeBinding = require('./gitsheets-core.linux-x64-gnu.node')
|
|
189
|
+
} else {
|
|
190
|
+
nativeBinding = require('@gitsheets/core-napi-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, 'gitsheets-core.linux-arm64-musl.node')
|
|
201
|
+
)
|
|
202
|
+
try {
|
|
203
|
+
if (localFileExisted) {
|
|
204
|
+
nativeBinding = require('./gitsheets-core.linux-arm64-musl.node')
|
|
205
|
+
} else {
|
|
206
|
+
nativeBinding = require('@gitsheets/core-napi-linux-arm64-musl')
|
|
207
|
+
}
|
|
208
|
+
} catch (e) {
|
|
209
|
+
loadError = e
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
localFileExisted = existsSync(
|
|
213
|
+
join(__dirname, 'gitsheets-core.linux-arm64-gnu.node')
|
|
214
|
+
)
|
|
215
|
+
try {
|
|
216
|
+
if (localFileExisted) {
|
|
217
|
+
nativeBinding = require('./gitsheets-core.linux-arm64-gnu.node')
|
|
218
|
+
} else {
|
|
219
|
+
nativeBinding = require('@gitsheets/core-napi-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, 'gitsheets-core.linux-arm-musleabihf.node')
|
|
230
|
+
)
|
|
231
|
+
try {
|
|
232
|
+
if (localFileExisted) {
|
|
233
|
+
nativeBinding = require('./gitsheets-core.linux-arm-musleabihf.node')
|
|
234
|
+
} else {
|
|
235
|
+
nativeBinding = require('@gitsheets/core-napi-linux-arm-musleabihf')
|
|
236
|
+
}
|
|
237
|
+
} catch (e) {
|
|
238
|
+
loadError = e
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
localFileExisted = existsSync(
|
|
242
|
+
join(__dirname, 'gitsheets-core.linux-arm-gnueabihf.node')
|
|
243
|
+
)
|
|
244
|
+
try {
|
|
245
|
+
if (localFileExisted) {
|
|
246
|
+
nativeBinding = require('./gitsheets-core.linux-arm-gnueabihf.node')
|
|
247
|
+
} else {
|
|
248
|
+
nativeBinding = require('@gitsheets/core-napi-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, 'gitsheets-core.linux-riscv64-musl.node')
|
|
259
|
+
)
|
|
260
|
+
try {
|
|
261
|
+
if (localFileExisted) {
|
|
262
|
+
nativeBinding = require('./gitsheets-core.linux-riscv64-musl.node')
|
|
263
|
+
} else {
|
|
264
|
+
nativeBinding = require('@gitsheets/core-napi-linux-riscv64-musl')
|
|
265
|
+
}
|
|
266
|
+
} catch (e) {
|
|
267
|
+
loadError = e
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
localFileExisted = existsSync(
|
|
271
|
+
join(__dirname, 'gitsheets-core.linux-riscv64-gnu.node')
|
|
272
|
+
)
|
|
273
|
+
try {
|
|
274
|
+
if (localFileExisted) {
|
|
275
|
+
nativeBinding = require('./gitsheets-core.linux-riscv64-gnu.node')
|
|
276
|
+
} else {
|
|
277
|
+
nativeBinding = require('@gitsheets/core-napi-linux-riscv64-gnu')
|
|
278
|
+
}
|
|
279
|
+
} catch (e) {
|
|
280
|
+
loadError = e
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
break
|
|
284
|
+
case 's390x':
|
|
285
|
+
localFileExisted = existsSync(
|
|
286
|
+
join(__dirname, 'gitsheets-core.linux-s390x-gnu.node')
|
|
287
|
+
)
|
|
288
|
+
try {
|
|
289
|
+
if (localFileExisted) {
|
|
290
|
+
nativeBinding = require('./gitsheets-core.linux-s390x-gnu.node')
|
|
291
|
+
} else {
|
|
292
|
+
nativeBinding = require('@gitsheets/core-napi-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 { roundtrip, parseRecords, serializeRecords, renderPathsBatch, validateBatch, runComparator, collatorSort, CompiledDefinition, recordRead, recordWrite, recordDelete, recordList, writeBlob, substrateStats, substrateReset, recordQuery, recordQueryCandidates, templateFieldNames, recordIndexUnique, recordIndexMulti, createPatch, applyMergePatch, diffRecords, simulateCoreError, CoreTransaction, coreDiscoverSheets, coreCheckValidators, markdownSerialize, markdownNormalizeBody, markdownParse, markdownParseHeaderOnly, markdownExtractH1, markdownRewriteH1 } = nativeBinding
|
|
314
|
+
|
|
315
|
+
module.exports.roundtrip = roundtrip
|
|
316
|
+
module.exports.parseRecords = parseRecords
|
|
317
|
+
module.exports.serializeRecords = serializeRecords
|
|
318
|
+
module.exports.renderPathsBatch = renderPathsBatch
|
|
319
|
+
module.exports.validateBatch = validateBatch
|
|
320
|
+
module.exports.runComparator = runComparator
|
|
321
|
+
module.exports.collatorSort = collatorSort
|
|
322
|
+
module.exports.CompiledDefinition = CompiledDefinition
|
|
323
|
+
module.exports.recordRead = recordRead
|
|
324
|
+
module.exports.recordWrite = recordWrite
|
|
325
|
+
module.exports.recordDelete = recordDelete
|
|
326
|
+
module.exports.recordList = recordList
|
|
327
|
+
module.exports.writeBlob = writeBlob
|
|
328
|
+
module.exports.substrateStats = substrateStats
|
|
329
|
+
module.exports.substrateReset = substrateReset
|
|
330
|
+
module.exports.recordQuery = recordQuery
|
|
331
|
+
module.exports.recordQueryCandidates = recordQueryCandidates
|
|
332
|
+
module.exports.templateFieldNames = templateFieldNames
|
|
333
|
+
module.exports.recordIndexUnique = recordIndexUnique
|
|
334
|
+
module.exports.recordIndexMulti = recordIndexMulti
|
|
335
|
+
module.exports.createPatch = createPatch
|
|
336
|
+
module.exports.applyMergePatch = applyMergePatch
|
|
337
|
+
module.exports.diffRecords = diffRecords
|
|
338
|
+
module.exports.simulateCoreError = simulateCoreError
|
|
339
|
+
module.exports.CoreTransaction = CoreTransaction
|
|
340
|
+
module.exports.coreDiscoverSheets = coreDiscoverSheets
|
|
341
|
+
module.exports.coreCheckValidators = coreCheckValidators
|
|
342
|
+
module.exports.markdownSerialize = markdownSerialize
|
|
343
|
+
module.exports.markdownNormalizeBody = markdownNormalizeBody
|
|
344
|
+
module.exports.markdownParse = markdownParse
|
|
345
|
+
module.exports.markdownParseHeaderOnly = markdownParseHeaderOnly
|
|
346
|
+
module.exports.markdownExtractH1 = markdownExtractH1
|
|
347
|
+
module.exports.markdownRewriteH1 = markdownRewriteH1
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gitsheets/core-napi",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Node.js native binding for gitsheets-core — the FFI marshalling boundary.",
|
|
5
|
+
"main": "binding.cjs",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"license": "Apache-2.0",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/JarvusInnovations/gitsheets.git",
|
|
11
|
+
"directory": "rust/gitsheets-napi"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20"
|
|
15
|
+
},
|
|
16
|
+
"napi": {
|
|
17
|
+
"name": "gitsheets-core",
|
|
18
|
+
"triples": {
|
|
19
|
+
"defaults": false,
|
|
20
|
+
"additional": [
|
|
21
|
+
"x86_64-unknown-linux-gnu",
|
|
22
|
+
"aarch64-unknown-linux-gnu",
|
|
23
|
+
"x86_64-unknown-linux-musl",
|
|
24
|
+
"aarch64-apple-darwin",
|
|
25
|
+
"x86_64-apple-darwin",
|
|
26
|
+
"x86_64-pc-windows-msvc"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"binding.cjs",
|
|
32
|
+
"index.js",
|
|
33
|
+
"index.d.ts"
|
|
34
|
+
],
|
|
35
|
+
"optionalDependencies": {
|
|
36
|
+
"@gitsheets/core-napi-linux-x64-gnu": "0.1.0",
|
|
37
|
+
"@gitsheets/core-napi-linux-arm64-gnu": "0.1.0",
|
|
38
|
+
"@gitsheets/core-napi-linux-x64-musl": "0.1.0",
|
|
39
|
+
"@gitsheets/core-napi-darwin-arm64": "0.1.0",
|
|
40
|
+
"@gitsheets/core-napi-darwin-x64": "0.1.0",
|
|
41
|
+
"@gitsheets/core-napi-win32-x64-msvc": "0.1.0"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"artifacts": "napi artifacts",
|
|
45
|
+
"build": "napi build --platform --release",
|
|
46
|
+
"build:debug": "napi build --platform",
|
|
47
|
+
"prepublishOnly": "napi prepublish -t npm --skip-gh-release",
|
|
48
|
+
"test": "node --test test/roundtrip.mjs test/errors.mjs test/canonical.mjs test/path-template.mjs test/validation-parity.mjs test/engine-parity.mjs test/collator-parity.mjs test/record-crud.mjs test/record-query.mjs test/record-index.mjs test/sheet-store.mjs test/sheet-markdown.mjs test/sheet-attachments.mjs",
|
|
49
|
+
"bench": "node bench/query-bench.mjs",
|
|
50
|
+
"version": "napi version"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@napi-rs/cli": "^2.18.4",
|
|
54
|
+
"ajv": "^8.20.0",
|
|
55
|
+
"ajv-formats": "^3.0.1",
|
|
56
|
+
"rfc6902": "^5.2.0",
|
|
57
|
+
"smol-toml": "^1.7.0"
|
|
58
|
+
}
|
|
59
|
+
}
|