@linxiraos/pi-utils 1.4.7 → 1.4.10
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 +6 -8
- package/dist/types/acp/schema.d.ts +1 -1
- package/dist/types/ar/codecs/xz.d.ts +4 -0
- package/dist/types/ar/lzh.d.ts +2 -0
- package/dist/types/async.d.ts +5 -0
- package/dist/types/bytes.d.ts +7 -0
- package/dist/types/color.d.ts +2 -0
- package/dist/types/env.d.ts +1 -0
- package/dist/types/file-lock.d.ts +6 -0
- package/dist/types/held-file.d.ts +5 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/pid.d.ts +8 -0
- package/dist/types/postmortem.d.ts +3 -2
- package/dist/types/sqlite.d.ts +12 -0
- package/package.json +3 -2
- package/src/acp/schema.ts +53 -107
- package/src/ar/arj.ts +13 -32
- package/src/ar/asar.ts +5 -8
- package/src/ar/codecs/xz.ts +7 -8
- package/src/ar/lzh.ts +21 -27
- package/src/ar/sevenzip/decode.ts +1 -56
- package/src/ar/tar.ts +1 -8
- package/src/async.ts +13 -0
- package/src/bytes.ts +14 -0
- package/src/color.ts +14 -2
- package/src/env.ts +46 -2
- package/src/file-lock.ts +9 -0
- package/src/held-file.ts +22 -0
- package/src/index.ts +2 -0
- package/src/logger.ts +2 -10
- package/src/pid.ts +16 -0
- package/src/postmortem.ts +61 -33
- package/src/runtime-install.ts +1 -4
- package/src/sqlite.ts +32 -2
package/src/runtime-install.ts
CHANGED
|
@@ -4,6 +4,7 @@ import * as Module from "node:module";
|
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { withFileLock } from "./file-lock";
|
|
6
6
|
import { isEexist, isEnoent } from "./fs-error";
|
|
7
|
+
import { isRecord } from "./type-guards";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* On-demand runtime dependency support for native-heavy optional packages
|
|
@@ -32,10 +33,6 @@ const RUNTIME_CONDITIONS: Record<string, true> = { node: true, require: true, de
|
|
|
32
33
|
/** Extension probes appended to a `main`/`exports` target that lacks one. */
|
|
33
34
|
const RUNTIME_EXTENSIONS: readonly string[] = [".js", ".cjs", ".mjs", ".json", ".node"];
|
|
34
35
|
|
|
35
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
36
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
36
|
/**
|
|
40
37
|
* Walk a conditional `exports` target (string, array of fallbacks, or a
|
|
41
38
|
* condition object) and return the first relative path that matches a runtime
|
package/src/sqlite.ts
CHANGED
|
@@ -2,15 +2,43 @@
|
|
|
2
2
|
import { Database } from "bun:sqlite";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import * as path from "node:path";
|
|
5
|
+
import { installSqliteLockShim } from "@linxiraos/pi-natives/sqlite-locks";
|
|
5
6
|
import { getDbBusyTimeoutMs } from "./env";
|
|
6
7
|
import { withFileLockSync } from "./file-lock";
|
|
7
8
|
import { isEnoent } from "./fs-error";
|
|
9
|
+
import { toError } from "./type-guards";
|
|
8
10
|
import * as logger from "./logger";
|
|
9
11
|
|
|
10
12
|
const BUSY_MAX_ATTEMPTS = 4;
|
|
11
13
|
const BUSY_BASE_DELAY_MS = 100;
|
|
12
14
|
const SQLITE_STORE_SUFFIXES = ["-wal", "-shm", "-journal", ""];
|
|
13
15
|
|
|
16
|
+
let sqliteLockShimInstalled: boolean | undefined;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Moves this process's SQLite locks onto open-file-description locks (Linux), once.
|
|
20
|
+
*
|
|
21
|
+
* SQLite's POSIX record locks belong to the process, so any close of another
|
|
22
|
+
* descriptor of a database or its `-shm` released them, including Bun's own file
|
|
23
|
+
* APIs and the bash tool's builtins; a peer omp then unlinked the WAL under the live
|
|
24
|
+
* connection (issue #15586). Call before the process opens its first database: a
|
|
25
|
+
* connection opened earlier keeps POSIX locks. Returns whether the shim is active; a
|
|
26
|
+
* Linux build where it cannot be installed (Bun's SQLite layout changed) logs a warning
|
|
27
|
+
* once, and callers with a UI surface it.
|
|
28
|
+
*/
|
|
29
|
+
export function ensureSqliteLockShim(): boolean {
|
|
30
|
+
if (sqliteLockShimInstalled === undefined) {
|
|
31
|
+
sqliteLockShimInstalled = installSqliteLockShim();
|
|
32
|
+
if (!sqliteLockShimInstalled && process.platform === "linux") {
|
|
33
|
+
logger.warn("SQLite OFD lock shim unavailable; in-process reads of a live store can release its locks", {
|
|
34
|
+
bun: Bun.version,
|
|
35
|
+
issue: "https://github.com/can1357/oh-my-pi/issues/15586",
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return sqliteLockShimInstalled;
|
|
40
|
+
}
|
|
41
|
+
|
|
14
42
|
/**
|
|
15
43
|
* A store's identity as `dev:ino:birthtimeMs`, `null` when the path holds no
|
|
16
44
|
* file, or `undefined` when the stat itself failed and no conclusion is safe.
|
|
@@ -100,7 +128,7 @@ function closeFailedDatabase(db: Database | undefined, error: unknown, identity:
|
|
|
100
128
|
try {
|
|
101
129
|
db?.close();
|
|
102
130
|
} catch (closeError) {
|
|
103
|
-
const original =
|
|
131
|
+
const original = toError(error);
|
|
104
132
|
const detail = closeError instanceof Error ? closeError.message : String(closeError);
|
|
105
133
|
original.message += `; failed to close the SQLite handle: ${detail}`;
|
|
106
134
|
throw new SqliteAttemptFailure(original, identity, { canRecover: false });
|
|
@@ -152,6 +180,7 @@ async function openWithBusyRetries<T>(
|
|
|
152
180
|
let db: Database | undefined;
|
|
153
181
|
const identity = sqliteFileIdentity(dbPath);
|
|
154
182
|
try {
|
|
183
|
+
ensureSqliteLockShim();
|
|
155
184
|
db = new Database(dbPath);
|
|
156
185
|
// WAL recovery can bypass the busy handler; both it and retries are needed (#2421).
|
|
157
186
|
db.run(`PRAGMA busy_timeout = ${getDbBusyTimeoutMs()}`);
|
|
@@ -175,6 +204,7 @@ function openOnce<T>(dbPath: string, initialize: (db: Database) => T, options: S
|
|
|
175
204
|
let db: Database | undefined;
|
|
176
205
|
const identity = sqliteFileIdentity(dbPath);
|
|
177
206
|
try {
|
|
207
|
+
ensureSqliteLockShim();
|
|
178
208
|
db = new Database(dbPath);
|
|
179
209
|
db.run(`PRAGMA busy_timeout = ${getDbBusyTimeoutMs()}`);
|
|
180
210
|
return initialize(db);
|
|
@@ -333,7 +363,7 @@ export function openSqliteDatabaseSync<T>(
|
|
|
333
363
|
|
|
334
364
|
/** Adds the failing store's path to an error without losing SQLite result codes or its original stack. */
|
|
335
365
|
export function annotateSqliteError(error: unknown, dbPath: string): Error {
|
|
336
|
-
const annotated =
|
|
366
|
+
const annotated = toError(error);
|
|
337
367
|
annotated.message = `Database "${dbPath}": ${annotated.message}`;
|
|
338
368
|
return annotated;
|
|
339
369
|
}
|