@aigne/sqlite 0.3.1 → 0.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.1](https://github.com/AIGNE-io/aigne-framework/compare/sqlite-v0.4.0...sqlite-v0.4.1) (2025-08-26)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **cli:** reduce memory usage of AIGNE CLI ([#411](https://github.com/AIGNE-io/aigne-framework/issues/411)) ([9c36969](https://github.com/AIGNE-io/aigne-framework/commit/9c369699d966d37abf2d6a1624eac3d2fda4123b))
9
+
10
+ ## [0.4.0](https://github.com/AIGNE-io/aigne-framework/compare/sqlite-v0.3.1...sqlite-v0.4.0) (2025-07-15)
11
+
12
+
13
+ ### Features
14
+
15
+ * **memory:** support did space memory adapter ([#229](https://github.com/AIGNE-io/aigne-framework/issues/229)) ([6f69b64](https://github.com/AIGNE-io/aigne-framework/commit/6f69b64e98b963db9d6ab5357306b445385eaa68))
16
+
3
17
  ## [0.3.1](https://github.com/AIGNE-io/aigne-framework/compare/sqlite-v0.3.0...sqlite-v0.3.1) (2025-07-14)
4
18
 
5
19
 
@@ -3,11 +3,30 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.initDatabase = initDatabase;
4
4
  const client_1 = require("@libsql/client");
5
5
  const libsql_1 = require("drizzle-orm/libsql");
6
+ const retry_js_1 = require("./retry.js");
6
7
  async function initDatabase({ url = ":memory:", wal = false, } = {}) {
8
+ let db;
7
9
  if (wal) {
8
10
  const client = (0, client_1.createClient)({ url });
9
- await client.execute("PRAGMA journal_mode=WAL;");
10
- return (0, libsql_1.drizzle)(client);
11
+ await client.execute(`\
12
+ PRAGMA journal_mode = WAL;
13
+ PRAGMA synchronous = normal;
14
+ PRAGMA wal_autocheckpoint = 5000;
15
+ PRAGMA busy_timeout = 5000;
16
+ `);
17
+ db = (0, libsql_1.drizzle)(client);
11
18
  }
12
- return (0, libsql_1.drizzle)(url);
19
+ else {
20
+ db = (0, libsql_1.drizzle)(url);
21
+ }
22
+ if ("session" in db && db.session && typeof db.session === "object") {
23
+ db.session = (0, retry_js_1.withRetry)(db.session, [
24
+ "all",
25
+ "get",
26
+ "run",
27
+ "values",
28
+ "count",
29
+ ]);
30
+ }
31
+ return db;
13
32
  }
@@ -1 +1,3 @@
1
- {"type": "commonjs"}
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,8 @@
1
+ export interface WithRetryOptions {
2
+ max?: number;
3
+ backoffBase?: number;
4
+ backoffExponent?: number;
5
+ backoffJitter?: number;
6
+ shouldRetry?: (err: any) => boolean;
7
+ }
8
+ export declare function withRetry<T extends object>(db: T, methods: (keyof T)[], { max, backoffBase, backoffExponent, backoffJitter, shouldRetry, }?: WithRetryOptions): T;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withRetry = withRetry;
4
+ function isDBLockedError(error) {
5
+ let err = error;
6
+ while (err) {
7
+ if (!(err instanceof Error))
8
+ return false;
9
+ if (typeof err.message !== "string")
10
+ return false;
11
+ const isLock = err.message.includes("SQLITE_BUSY");
12
+ if (isLock)
13
+ return true;
14
+ err = err.cause;
15
+ }
16
+ return false;
17
+ }
18
+ function withRetry(db, methods, { max = 20, backoffBase = 300, backoffExponent = 1.2, backoffJitter = 100, shouldRetry = isDBLockedError, } = {}) {
19
+ return new Proxy(db, {
20
+ get(target, prop) {
21
+ const val = target?.[prop];
22
+ if (methods.includes(prop) && typeof val === "function") {
23
+ return async (...args) => {
24
+ let attempt = 1;
25
+ while (true) {
26
+ try {
27
+ return await val.apply(target, args);
28
+ }
29
+ catch (err) {
30
+ if (!shouldRetry(err) || ++attempt > max) {
31
+ throw err;
32
+ }
33
+ const exp = backoffExponent ** (attempt - 1);
34
+ const expDelay = backoffBase * exp;
35
+ const jitter = Math.random() * backoffJitter;
36
+ const waitTime = Math.floor(expDelay + jitter);
37
+ await new Promise((resolve) => setTimeout(resolve, waitTime));
38
+ }
39
+ }
40
+ };
41
+ }
42
+ return val;
43
+ },
44
+ });
45
+ }
@@ -1,10 +1,29 @@
1
1
  import { createClient } from "@libsql/client";
2
2
  import { drizzle } from "drizzle-orm/libsql";
3
+ import { withRetry } from "./retry.js";
3
4
  export async function initDatabase({ url = ":memory:", wal = false, } = {}) {
5
+ let db;
4
6
  if (wal) {
5
7
  const client = createClient({ url });
6
- await client.execute("PRAGMA journal_mode=WAL;");
7
- return drizzle(client);
8
+ await client.execute(`\
9
+ PRAGMA journal_mode = WAL;
10
+ PRAGMA synchronous = normal;
11
+ PRAGMA wal_autocheckpoint = 5000;
12
+ PRAGMA busy_timeout = 5000;
13
+ `);
14
+ db = drizzle(client);
8
15
  }
9
- return drizzle(url);
16
+ else {
17
+ db = drizzle(url);
18
+ }
19
+ if ("session" in db && db.session && typeof db.session === "object") {
20
+ db.session = withRetry(db.session, [
21
+ "all",
22
+ "get",
23
+ "run",
24
+ "values",
25
+ "count",
26
+ ]);
27
+ }
28
+ return db;
10
29
  }
@@ -1 +1,3 @@
1
- {"type": "module"}
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,8 @@
1
+ export interface WithRetryOptions {
2
+ max?: number;
3
+ backoffBase?: number;
4
+ backoffExponent?: number;
5
+ backoffJitter?: number;
6
+ shouldRetry?: (err: any) => boolean;
7
+ }
8
+ export declare function withRetry<T extends object>(db: T, methods: (keyof T)[], { max, backoffBase, backoffExponent, backoffJitter, shouldRetry, }?: WithRetryOptions): T;
@@ -0,0 +1,42 @@
1
+ function isDBLockedError(error) {
2
+ let err = error;
3
+ while (err) {
4
+ if (!(err instanceof Error))
5
+ return false;
6
+ if (typeof err.message !== "string")
7
+ return false;
8
+ const isLock = err.message.includes("SQLITE_BUSY");
9
+ if (isLock)
10
+ return true;
11
+ err = err.cause;
12
+ }
13
+ return false;
14
+ }
15
+ export function withRetry(db, methods, { max = 20, backoffBase = 300, backoffExponent = 1.2, backoffJitter = 100, shouldRetry = isDBLockedError, } = {}) {
16
+ return new Proxy(db, {
17
+ get(target, prop) {
18
+ const val = target?.[prop];
19
+ if (methods.includes(prop) && typeof val === "function") {
20
+ return async (...args) => {
21
+ let attempt = 1;
22
+ while (true) {
23
+ try {
24
+ return await val.apply(target, args);
25
+ }
26
+ catch (err) {
27
+ if (!shouldRetry(err) || ++attempt > max) {
28
+ throw err;
29
+ }
30
+ const exp = backoffExponent ** (attempt - 1);
31
+ const expDelay = backoffBase * exp;
32
+ const jitter = Math.random() * backoffJitter;
33
+ const waitTime = Math.floor(expDelay + jitter);
34
+ await new Promise((resolve) => setTimeout(resolve, waitTime));
35
+ }
36
+ }
37
+ };
38
+ }
39
+ return val;
40
+ },
41
+ });
42
+ }
package/package.json CHANGED
@@ -1,17 +1,20 @@
1
1
  {
2
2
  "name": "@aigne/sqlite",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "description": "AIGNE SQLite database library for building AI-powered applications",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
8
  "author": "Arcblock <blocklet@arcblock.io> https://github.com/blocklet",
9
- "homepage": "https://github.com/AIGNE-io/aigne-framework",
9
+ "homepage": "https://www.aigne.io/framework",
10
10
  "license": "Elastic-2.0",
11
11
  "repository": {
12
12
  "type": "git",
13
13
  "url": "git+https://github.com/AIGNE-io/aigne-framework"
14
14
  },
15
+ "bugs": {
16
+ "url": "https://github.com/AIGNE-io/aigne-framework/issues"
17
+ },
15
18
  "files": [
16
19
  "lib/cjs",
17
20
  "lib/esm",
@@ -62,6 +65,6 @@
62
65
  "clean": "rimraf lib test/coverage",
63
66
  "test": "bun test",
64
67
  "test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-reporter=text",
65
- "postbuild": "echo '{\"type\": \"module\"}' > lib/esm/package.json && echo '{\"type\": \"commonjs\"}' > lib/cjs/package.json"
68
+ "postbuild": "node ../../scripts/post-build-lib.mjs"
66
69
  }
67
70
  }