@dolthub/doltlite 0.10.0 → 0.10.6

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 CHANGED
@@ -147,6 +147,19 @@ db.exec("SELECT dolt_commit('-Am', 'my message')")
147
147
  | `doltCherryPick(hash)` | `void` | Cherry-pick a commit onto HEAD |
148
148
  | `doltRevert(ref?)` | `void` | Revert a commit (default: HEAD) |
149
149
 
150
+ ### `binPath()`
151
+
152
+ Returns the absolute path to the bundled `doltlite` CLI binary for the current platform. Useful when a consumer wants to spawn the shell directly — e.g. for an interactive `db` subcommand — rather than driving everything through the Node bindings.
153
+
154
+ ```javascript
155
+ import { binPath } from "@dolthub/doltlite"
156
+ import { spawn } from "child_process"
157
+
158
+ const child = spawn(binPath(), ["mydata.db"], { stdio: "inherit" })
159
+ ```
160
+
161
+ Throws if no CLI build is bundled for the current platform/arch. (Upstream currently ships CLI tools for `linux-x64`, `darwin-arm64`, and `win32-x64`; the `.node` addon covers more platforms than the shell.)
162
+
150
163
  ## Building from source
151
164
 
152
165
  ```bash
package/binding.gyp CHANGED
@@ -5,15 +5,18 @@
5
5
  "sources": [
6
6
  "amalgamation/doltlite_orig.c",
7
7
  "amalgamation/doltlite.c",
8
+ "amalgamation/blake3_sse2_impl.c",
9
+ "amalgamation/blake3_sse41_impl.c",
10
+ "amalgamation/blake3_avx2_impl.c",
11
+ "amalgamation/blake3_avx512_impl.c",
12
+ "amalgamation/blake3_neon_impl.c",
8
13
  "src/addon.cpp",
14
+ "src/bun_compat.cpp",
9
15
  "src/database.cpp",
10
16
  "src/statement.cpp"
11
17
  ],
12
18
  "include_dirs": [
13
19
  "amalgamation",
14
- "doltlite-src",
15
- "doltlite-src/src",
16
- "doltlite-src/ext/blake3",
17
20
  "<!@(node -p \"require('node-addon-api').include\")"
18
21
  ],
19
22
  "defines": [
package/index.d.ts CHANGED
@@ -6,6 +6,14 @@
6
6
  * changing their import. Dolt-specific methods are added under `dolt*` names.
7
7
  */
8
8
 
9
+ /**
10
+ * Absolute path to the platform's `doltlite` CLI binary bundled in this
11
+ * package. Use it to spawn the shell (interactive or with a script piped
12
+ * via stdio). Throws if the binary isn't bundled for the current
13
+ * platform/arch.
14
+ */
15
+ export function binPath(): string
16
+
9
17
  export interface ColumnInfo {
10
18
  name: string | null
11
19
  column: string | null
package/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict"
2
2
 
3
3
  const path = require("path")
4
+ const fs = require("fs")
4
5
 
5
6
  // Try a prebuilt binary first (shipped with published packages),
6
7
  // then fall back to a locally compiled build.
@@ -23,5 +24,24 @@ function loadAddon() {
23
24
  )
24
25
  }
25
26
 
27
+ // Absolute path to the platform's `doltlite` CLI binary, shipped in the
28
+ // package's prebuilds/ alongside the .node addon. Used by consumers (e.g.
29
+ // opencode) that want to spawn an interactive shell or pipe SQL through
30
+ // the doltlite shell. Throws if the binary isn't bundled for this platform.
31
+ function binPath() {
32
+ const platform = process.platform
33
+ const arch = process.arch
34
+ const ext = platform === "win32" ? ".exe" : ""
35
+ const candidate = path.join(__dirname, "prebuilds", `${platform}-${arch}`, `doltlite${ext}`)
36
+ if (!fs.existsSync(candidate)) {
37
+ throw new Error(
38
+ `@dolthub/doltlite: no doltlite CLI binary bundled for ${platform}-${arch}.\n` +
39
+ `Expected at ${candidate}. File an issue at ` +
40
+ `https://github.com/dolthub/doltlite-node/issues`
41
+ )
42
+ }
43
+ return candidate
44
+ }
45
+
26
46
  const { DatabaseSync, StatementSync } = loadAddon()
27
- module.exports = { DatabaseSync, StatementSync }
47
+ module.exports = { DatabaseSync, StatementSync, binPath }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dolthub/doltlite",
3
- "version": "0.10.0",
3
+ "version": "0.10.6",
4
4
  "description": "Node.js bindings for DoltLite — a SQLite fork with Git-style version control",
5
5
  "license": "Apache-2.0",
6
6
  "main": "index.js",
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  // Downloads the doltlite autoconf source tarball from GitHub releases and
3
- // builds a complete amalgamation from it.
3
+ // builds a complete amalgamation from it, and bundles the matching doltlite
4
+ // CLI binary for the current platform into prebuilds/${platform}-${arch}/
5
+ // so that binPath() can return an absolute path.
4
6
  //
5
7
  // The autoconf tarball contains both sqlite3.c (the base SQLite amalgamation
6
8
  // with doltlite's storage patches) and the prolly tree + dolt SQL function
@@ -22,25 +24,23 @@ const outC = path.join(amalgDir, "doltlite.c")
22
24
  const outH = path.join(amalgDir, "doltlite.h")
23
25
  const srcRoot = path.join(__dirname, "../doltlite-src")
24
26
 
25
- // Skip if already built.
26
- if (fs.existsSync(outC) && fs.existsSync(outH)) {
27
- process.exit(0)
27
+ // Upstream dolthub/doltlite ships the CLI for these platform-arch pairs;
28
+ // place the binary next to the .node addon so binPath() can return it.
29
+ const CLI_TOOLS = {
30
+ "linux-x64": { upstream: "linux-x64", bin: "doltlite" },
31
+ "darwin-arm64": { upstream: "osx-arm64", bin: "doltlite" },
32
+ "win32-x64": { upstream: "win-x64", bin: "doltlite.exe" },
28
33
  }
29
34
 
30
- const tarballUrl = `https://github.com/dolthub/doltlite/releases/download/v${version}/doltlite-autoconf-${version}.tar.gz`
31
- const tarballPath = path.join(__dirname, `../doltlite-autoconf-${version}.tar.gz`)
32
-
33
- console.log(`Downloading doltlite source v${version}...`)
34
-
35
35
  function download(url, dest, cb) {
36
36
  const file = fs.createWriteStream(dest)
37
- function get(url) {
38
- https.get(url, (res) => {
37
+ function get(u) {
38
+ https.get(u, (res) => {
39
39
  if (res.statusCode === 301 || res.statusCode === 302) {
40
40
  return get(res.headers.location)
41
41
  }
42
42
  if (res.statusCode !== 200) {
43
- cb(new Error(`HTTP ${res.statusCode} downloading ${url}`))
43
+ cb(new Error(`HTTP ${res.statusCode} downloading ${u}`))
44
44
  return
45
45
  }
46
46
  res.pipe(file)
@@ -50,38 +50,79 @@ function download(url, dest, cb) {
50
50
  get(url)
51
51
  }
52
52
 
53
- download(tarballUrl, tarballPath, (err) => {
54
- if (err) {
55
- console.error("Failed to download doltlite source:", err.message)
56
- process.exit(1)
57
- }
53
+ function fetchSource(cb) {
54
+ if (fs.existsSync(outC) && fs.existsSync(outH)) return cb()
58
55
 
59
- try {
60
- fs.rmSync(srcRoot, { recursive: true, force: true })
61
- fs.mkdirSync(srcRoot, { recursive: true })
56
+ const tarballUrl = `https://github.com/dolthub/doltlite/releases/download/v${version}/doltlite-autoconf-${version}.tar.gz`
57
+ const tarballPath = path.join(__dirname, `../doltlite-autoconf-${version}.tar.gz`)
58
+ console.log(`Downloading doltlite source v${version}...`)
62
59
 
63
- // Extract tarball — tar is available on Linux, macOS, and Windows 10+.
64
- execSync(`tar xzf "${tarballPath}" -C "${srcRoot}"`, { stdio: "inherit" })
65
- fs.unlinkSync(tarballPath)
60
+ download(tarballUrl, tarballPath, (err) => {
61
+ if (err) return cb(new Error(`Failed to download source: ${err.message}`))
62
+ try {
63
+ fs.rmSync(srcRoot, { recursive: true, force: true })
64
+ fs.mkdirSync(srcRoot, { recursive: true })
65
+ execSync(`tar xzf "${tarballPath}" -C "${srcRoot}"`, { stdio: "inherit" })
66
+ fs.unlinkSync(tarballPath)
66
67
 
67
- // The tarball nests everything under doltlite-autoconf-${version}/.
68
- // Flatten it so doltlite-src/src/ and doltlite-src/sqlite3.c are the
69
- // canonical paths that build-amalgamation.js expects.
70
- const entries = fs.readdirSync(srcRoot)
71
- if (entries.length === 1 && fs.statSync(path.join(srcRoot, entries[0])).isDirectory()) {
72
- const subdir = path.join(srcRoot, entries[0])
73
- for (const f of fs.readdirSync(subdir)) {
74
- fs.renameSync(path.join(subdir, f), path.join(srcRoot, f))
68
+ // The tarball nests under doltlite-autoconf-${version}/. Flatten so
69
+ // doltlite-src/src/ and doltlite-src/sqlite3.c are canonical.
70
+ const entries = fs.readdirSync(srcRoot)
71
+ if (entries.length === 1 && fs.statSync(path.join(srcRoot, entries[0])).isDirectory()) {
72
+ const subdir = path.join(srcRoot, entries[0])
73
+ for (const f of fs.readdirSync(subdir)) {
74
+ fs.renameSync(path.join(subdir, f), path.join(srcRoot, f))
75
+ }
76
+ fs.rmdirSync(subdir)
75
77
  }
76
- fs.rmdirSync(subdir)
78
+ execSync(`node "${path.join(__dirname, "build-amalgamation.js")}"`, { stdio: "inherit" })
79
+ console.log("Source ready.")
80
+ cb()
81
+ } catch (e) {
82
+ cb(new Error(`Failed to prepare doltlite source: ${e.message}`))
77
83
  }
84
+ })
85
+ }
78
86
 
79
- // Build the complete amalgamation.
80
- execSync(`node "${path.join(__dirname, "build-amalgamation.js")}"`, { stdio: "inherit" })
87
+ function fetchCli(cb) {
88
+ const key = `${process.platform}-${process.arch}`
89
+ const meta = CLI_TOOLS[key]
90
+ if (!meta) {
91
+ console.log(`doltlite CLI: no upstream build for ${key}, skipping`)
92
+ return cb()
93
+ }
94
+ const prebuildDir = path.join(__dirname, "..", "prebuilds", key)
95
+ const binPath = path.join(prebuildDir, meta.bin)
96
+ if (fs.existsSync(binPath)) return cb()
97
+ fs.mkdirSync(prebuildDir, { recursive: true })
98
+
99
+ const url = `https://github.com/dolthub/doltlite/releases/download/v${version}/doltlite-tools-${meta.upstream}-${version}.zip`
100
+ const zipPath = path.join(__dirname, `../doltlite-tools-${meta.upstream}-${version}.zip`)
101
+ console.log(`Downloading doltlite CLI v${version} for ${key}...`)
102
+ download(url, zipPath, (err) => {
103
+ if (err) return cb(new Error(`Failed to download CLI: ${err.message}`))
104
+ try {
105
+ execSync(`unzip -jo "${zipPath}" "*/${meta.bin}" -d "${prebuildDir}"`, { stdio: "inherit" })
106
+ fs.unlinkSync(zipPath)
107
+ if (process.platform !== "win32") fs.chmodSync(binPath, 0o755)
108
+ cb()
109
+ } catch (e) {
110
+ cb(new Error(`Failed to extract CLI: ${e.message}`))
111
+ }
112
+ })
113
+ }
81
114
 
82
- console.log("Source ready.")
83
- } catch (e) {
84
- console.error("Failed to prepare doltlite source:", e.message)
115
+ fetchSource((err) => {
116
+ if (err) {
117
+ console.error(err.message)
85
118
  process.exit(1)
86
119
  }
120
+ fetchCli((cliErr) => {
121
+ if (cliErr) {
122
+ // Non-fatal: the addon still builds and works; binPath() will throw
123
+ // if a consumer invokes it without the CLI present.
124
+ console.error(`doltlite CLI: ${cliErr.message} (addon will still build)`)
125
+ }
126
+ process.exit(0)
127
+ })
87
128
  })
package/src/addon.cpp CHANGED
@@ -13,3 +13,8 @@ Napi::Object Init(Napi::Env env, Napi::Object exports) {
13
13
  }
14
14
 
15
15
  NODE_API_MODULE(doltlite, Init)
16
+
17
+ // C-linkage entry point used by src/bun_compat.cpp.
18
+ extern "C" napi_value _doltlite_init(napi_env env, napi_value exports) {
19
+ return Init(Napi::Env(env), Napi::Object(env, exports));
20
+ }
@@ -0,0 +1,16 @@
1
+ #include <node_api.h>
2
+
3
+ // Forward declaration of the init function defined in addon.cpp.
4
+ extern "C" napi_value _doltlite_init(napi_env env, napi_value exports);
5
+
6
+ // Provide napi_register_module_v1 for Bun's Worker loader on Node builds where
7
+ // NAPI_MODULE uses constructor registration and doesn't export this symbol
8
+ // (Node < ~22.12). On newer Node builds, NODE_API_MODULE in addon.cpp already
9
+ // emits a strong napi_register_module_v1, which the linker will prefer over
10
+ // this weak definition. MSVC doesn't support weak functions; skip it there
11
+ // since Windows builds target Node 22+ which supplies the symbol via NAPI_MODULE.
12
+ #if !defined(_MSC_VER)
13
+ extern "C" __attribute__((weak)) napi_value napi_register_module_v1(napi_env env, napi_value exports) {
14
+ return _doltlite_init(env, exports);
15
+ }
16
+ #endif
package/src/statement.cpp CHANGED
@@ -3,12 +3,21 @@
3
3
  #include "util.h"
4
4
  #include <vector>
5
5
 
6
- Napi::FunctionReference Statement::constructor_;
6
+ // Per-env storage for the Statement constructor so re-loading in a Worker
7
+ // thread doesn't overwrite the main thread's constructor reference.
8
+ struct StatementEnvData {
9
+ Napi::FunctionReference constructor;
10
+ };
11
+
12
+ Napi::FunctionReference& Statement::GetConstructor(Napi::Env env) {
13
+ auto* data = env.GetInstanceData<StatementEnvData>();
14
+ return data->constructor;
15
+ }
7
16
 
8
17
  // ── Factory (called from Database::Prepare) ──────────────────────────────────
9
18
 
10
19
  Napi::Object Statement::Create(Napi::Env env, Database* db, sqlite3_stmt* stmt) {
11
- auto obj = constructor_.New({});
20
+ auto obj = GetConstructor(env).New({});
12
21
  auto* self = Napi::ObjectWrap<Statement>::Unwrap(obj);
13
22
  self->db_ = db;
14
23
  self->stmt_ = stmt;
@@ -173,8 +182,10 @@ Napi::Object Statement::Init(Napi::Env env, Napi::Object exports) {
173
182
  InstanceAccessor("sourceSQL", &Statement::SourceSQLGetter, nullptr),
174
183
  InstanceAccessor("expandedSQL", &Statement::ExpandedSQLGetter, nullptr),
175
184
  });
176
- constructor_ = Napi::Persistent(ctor);
177
- constructor_.SuppressDestruct();
185
+ auto* data = new StatementEnvData();
186
+ data->constructor = Napi::Persistent(ctor);
187
+ data->constructor.SuppressDestruct();
188
+ env.SetInstanceData<StatementEnvData>(data);
178
189
  exports.Set("StatementSync", ctor);
179
190
  return exports;
180
191
  }
package/src/statement.h CHANGED
@@ -25,5 +25,5 @@ private:
25
25
  Napi::Value SourceSQLGetter(const Napi::CallbackInfo& info);
26
26
  Napi::Value ExpandedSQLGetter(const Napi::CallbackInfo& info);
27
27
 
28
- static Napi::FunctionReference constructor_;
28
+ static Napi::FunctionReference& GetConstructor(Napi::Env env);
29
29
  };