@rohirik/openltm-core 2.8.1 → 2.9.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/package.json
CHANGED
|
@@ -2,6 +2,7 @@ import { describe, it, expect, beforeEach } from "bun:test";
|
|
|
2
2
|
import { Database } from "bun:sqlite";
|
|
3
3
|
import {
|
|
4
4
|
locateSystemSqlite,
|
|
5
|
+
locateHonkerExt,
|
|
5
6
|
ensureCustomSqlite,
|
|
6
7
|
loadExtensions,
|
|
7
8
|
getCapabilities,
|
|
@@ -32,14 +33,27 @@ describe("extensions — capability probe", () => {
|
|
|
32
33
|
expect(typeof caps.honker).toBe("boolean");
|
|
33
34
|
});
|
|
34
35
|
|
|
35
|
-
it("honker is false when
|
|
36
|
-
const prev = process.env["
|
|
37
|
-
|
|
36
|
+
it("honker is false when force-disabled via LTM_DISABLE_HONKER", () => {
|
|
37
|
+
const prev = process.env["LTM_DISABLE_HONKER"];
|
|
38
|
+
process.env["LTM_DISABLE_HONKER"] = "1";
|
|
38
39
|
ensureCustomSqlite();
|
|
39
40
|
const db = new Database(":memory:");
|
|
40
41
|
const caps = loadExtensions(db);
|
|
41
42
|
expect(caps.honker).toBe(false);
|
|
42
|
-
if (prev) process.env["
|
|
43
|
+
if (prev === undefined) delete process.env["LTM_DISABLE_HONKER"];
|
|
44
|
+
else process.env["LTM_DISABLE_HONKER"] = prev;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("honker auto-loads when a vendored libhonker_ext binary is discoverable", () => {
|
|
48
|
+
// Mirrors the vec test: activation needs customSqlite (process-global, only
|
|
49
|
+
// before the first DB open) AND a discoverable binary. Skip when either is
|
|
50
|
+
// unavailable — that is the graceful-degradation path, not a failure.
|
|
51
|
+
if (locateHonkerExt() === null || process.env["LTM_DISABLE_HONKER"]) return;
|
|
52
|
+
ensureCustomSqlite();
|
|
53
|
+
const db = new Database(":memory:");
|
|
54
|
+
const caps = loadExtensions(db);
|
|
55
|
+
if (!caps.customSqlite) return;
|
|
56
|
+
expect(caps.honker).toBe(true);
|
|
43
57
|
});
|
|
44
58
|
|
|
45
59
|
it("respects LTM_DISABLE_VEC — vec capability is false when force-disabled", () => {
|
package/src/extensions.ts
CHANGED
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { Database } from "bun:sqlite";
|
|
15
15
|
import { existsSync } from "fs";
|
|
16
|
+
import { dirname, join } from "path";
|
|
17
|
+
import { fileURLToPath } from "url";
|
|
18
|
+
|
|
19
|
+
/** Directory of this module — used to resolve the vendored Honker binary. */
|
|
20
|
+
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
16
21
|
|
|
17
22
|
export interface Capabilities {
|
|
18
23
|
/** A system extension-enabled SQLite is active for this process. */
|
|
@@ -48,9 +53,9 @@ function envDisabled(name: string): boolean {
|
|
|
48
53
|
return v === "1" || v === "true";
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
for (const p of
|
|
56
|
+
/** First candidate path that exists on disk, or null. Never throws. */
|
|
57
|
+
function firstExisting(candidates: string[]): string | null {
|
|
58
|
+
for (const p of candidates) {
|
|
54
59
|
try {
|
|
55
60
|
if (existsSync(p)) return p;
|
|
56
61
|
} catch {
|
|
@@ -60,6 +65,32 @@ export function locateSystemSqlite(): string | null {
|
|
|
60
65
|
return null;
|
|
61
66
|
}
|
|
62
67
|
|
|
68
|
+
/** Locate a system extension-enabled libsqlite3, or null if none found. */
|
|
69
|
+
export function locateSystemSqlite(): string | null {
|
|
70
|
+
return firstExisting(systemSqliteCandidates());
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Probe order: explicit override first, then the vendored binary for this
|
|
74
|
+
// platform (packages/openltm-core/vendor/honker/<platform>/libhonker_ext.<ext>).
|
|
75
|
+
function honkerExtCandidates(): string[] {
|
|
76
|
+
const out: string[] = [];
|
|
77
|
+
const override = process.env["LTM_HONKER_EXT"];
|
|
78
|
+
if (override) out.push(override);
|
|
79
|
+
const platform = `${process.platform}-${process.arch}`;
|
|
80
|
+
const suffix = process.platform === "darwin" ? "dylib" : "so";
|
|
81
|
+
out.push(join(MODULE_DIR, "..", "vendor", "honker", platform, `libhonker_ext.${suffix}`));
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Locate the Honker loadable extension, or null if none is available for this
|
|
87
|
+
* platform. Mirrors locateSystemSqlite(): LTM_HONKER_EXT override wins, then the
|
|
88
|
+
* vendored per-platform binary. A null result means Honker stays dormant.
|
|
89
|
+
*/
|
|
90
|
+
export function locateHonkerExt(): string | null {
|
|
91
|
+
return firstExisting(honkerExtCandidates());
|
|
92
|
+
}
|
|
93
|
+
|
|
63
94
|
/**
|
|
64
95
|
* Switch the process to a system extension-enabled SQLite. Idempotent and
|
|
65
96
|
* never throws. Must run before the first Database is constructed to take
|
|
@@ -99,8 +130,8 @@ function loadVec(db: Database): boolean {
|
|
|
99
130
|
}
|
|
100
131
|
|
|
101
132
|
function loadHonker(db: Database): boolean {
|
|
102
|
-
const ext =
|
|
103
|
-
if (!ext
|
|
133
|
+
const ext = locateHonkerExt();
|
|
134
|
+
if (!ext) return false;
|
|
104
135
|
try {
|
|
105
136
|
db.loadExtension(ext);
|
|
106
137
|
return true;
|
|
@@ -114,12 +145,14 @@ function loadHonker(db: Database): boolean {
|
|
|
114
145
|
* capabilities for the process. Never throws.
|
|
115
146
|
*
|
|
116
147
|
* @param opts.vec attempt sqlite-vec (default true; env LTM_DISABLE_VEC wins)
|
|
117
|
-
* @param opts.honker attempt Honker (default
|
|
118
|
-
*
|
|
148
|
+
* @param opts.honker attempt Honker (default: auto-on when a libhonker_ext binary
|
|
149
|
+
* is discoverable via locateHonkerExt(); env LTM_DISABLE_HONKER
|
|
150
|
+
* force-disables, and LTM_HONKER_EXT overrides the binary path)
|
|
119
151
|
*/
|
|
120
152
|
export function loadExtensions(db: Database, opts?: { vec?: boolean; honker?: boolean }): Capabilities {
|
|
121
153
|
const wantVec = (opts?.vec ?? true) && !envDisabled("LTM_DISABLE_VEC");
|
|
122
|
-
const wantHonker =
|
|
154
|
+
const wantHonker =
|
|
155
|
+
(opts?.honker ?? locateHonkerExt() !== null) && !envDisabled("LTM_DISABLE_HONKER");
|
|
123
156
|
|
|
124
157
|
const customSqlite = ensureCustomSqlite();
|
|
125
158
|
const vec = customSqlite && wantVec ? loadVec(db) : false;
|
package/src/lib/honker.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* pre-Honker behaviour (inline embed, HTTP poll, file-watcher).
|
|
14
14
|
*/
|
|
15
15
|
import type { HonkerDb, HonkerModule } from "./honkerTypes.js";
|
|
16
|
-
import { getCapabilities, locateSystemSqlite } from "../extensions.js";
|
|
16
|
+
import { getCapabilities, locateSystemSqlite, locateHonkerExt } from "../extensions.js";
|
|
17
17
|
import { DB_PATH } from "../shared-db.js";
|
|
18
18
|
|
|
19
19
|
let _handle: HonkerDb | null | undefined = undefined;
|
|
@@ -31,7 +31,7 @@ export function getHonker(): HonkerDb | null {
|
|
|
31
31
|
|
|
32
32
|
function openHonker(): HonkerDb | null {
|
|
33
33
|
if (!getCapabilities().honker) return null;
|
|
34
|
-
const ext =
|
|
34
|
+
const ext = locateHonkerExt();
|
|
35
35
|
if (!ext) return null;
|
|
36
36
|
try {
|
|
37
37
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
Binary file
|