@wrongstack/persistence 0.309.0 → 0.310.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/dist/atomic-write.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +67 -6
- package/dist/sqlite-runtime.d.ts +13 -0
- package/package.json +2 -2
package/dist/atomic-write.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export declare class PersistenceFsError extends Error {
|
|
|
40
40
|
*/
|
|
41
41
|
export declare function createPersistencePrimitives(options?: PersistencePrimitiveOptions): PersistencePrimitives;
|
|
42
42
|
export declare const atomicWrite: (targetPath: string, content: string | Uint8Array, opts?: AtomicWriteOptions) => Promise<void>;
|
|
43
|
+
export declare const atomicReplaceWithWriter: <T>(targetPath: string, write: (handle: fs.FileHandle) => Promise<T>, opts?: AtomicWriteOptions) => Promise<T>;
|
|
43
44
|
export declare const ensureDir: (dir: string) => Promise<void>;
|
|
44
45
|
export declare const withFileLock: <T>(targetPath: string, fn: () => Promise<T>, opts?: FileLockOptions) => Promise<T>;
|
|
45
46
|
//# sourceMappingURL=atomic-write.d.ts.map
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -61,10 +61,18 @@ function createPersistencePrimitives(options = {}) {
|
|
|
61
61
|
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
|
62
62
|
const tmp = tempPathFor(targetPath);
|
|
63
63
|
try {
|
|
64
|
+
const createMode = opts.mode;
|
|
64
65
|
if (typeof content === "string") {
|
|
65
|
-
await fs.writeFile(tmp, content, {
|
|
66
|
+
await fs.writeFile(tmp, content, {
|
|
67
|
+
flag: "wx",
|
|
68
|
+
encoding: opts.encoding ?? "utf8",
|
|
69
|
+
...createMode !== void 0 ? { mode: createMode } : {}
|
|
70
|
+
});
|
|
66
71
|
} else {
|
|
67
|
-
await fs.writeFile(tmp, content, {
|
|
72
|
+
await fs.writeFile(tmp, content, {
|
|
73
|
+
flag: "wx",
|
|
74
|
+
...createMode !== void 0 ? { mode: createMode } : {}
|
|
75
|
+
});
|
|
68
76
|
}
|
|
69
77
|
await commitTemp(tmp, targetPath, opts);
|
|
70
78
|
} catch (error) {
|
|
@@ -72,11 +80,11 @@ function createPersistencePrimitives(options = {}) {
|
|
|
72
80
|
throw error;
|
|
73
81
|
}
|
|
74
82
|
}
|
|
75
|
-
async function
|
|
83
|
+
async function atomicReplaceWithWriter2(targetPath, write, opts = {}) {
|
|
76
84
|
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
|
77
85
|
const tmp = tempPathFor(targetPath);
|
|
78
86
|
try {
|
|
79
|
-
const handle = await fs.open(tmp, "wx");
|
|
87
|
+
const handle = await fs.open(tmp, "wx", opts.mode);
|
|
80
88
|
let result;
|
|
81
89
|
try {
|
|
82
90
|
result = await write(handle);
|
|
@@ -127,7 +135,9 @@ function createPersistencePrimitives(options = {}) {
|
|
|
127
135
|
await retryAfterBackoff();
|
|
128
136
|
continue;
|
|
129
137
|
}
|
|
130
|
-
if (code !== "EEXIST" && code !== "EPERM")
|
|
138
|
+
if (code !== "EEXIST" && code !== "EPERM" && code !== "EACCES" && code !== "EBUSY") {
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
131
141
|
try {
|
|
132
142
|
const stat2 = await fs.stat(lockPath);
|
|
133
143
|
if (Date.now() - stat2.mtimeMs > staleMs) {
|
|
@@ -163,7 +173,7 @@ function createPersistencePrimitives(options = {}) {
|
|
|
163
173
|
await fs.unlink(lockPath).catch(() => void 0);
|
|
164
174
|
}
|
|
165
175
|
}
|
|
166
|
-
return { atomicWrite: atomicWrite2, atomicReplaceWithWriter, ensureDir: ensureDir2, withFileLock: withFileLock2 };
|
|
176
|
+
return { atomicWrite: atomicWrite2, atomicReplaceWithWriter: atomicReplaceWithWriter2, ensureDir: ensureDir2, withFileLock: withFileLock2 };
|
|
167
177
|
}
|
|
168
178
|
async function waitForLockRelease(lockPath, remainingMs) {
|
|
169
179
|
const parentDir = path.dirname(lockPath);
|
|
@@ -243,6 +253,7 @@ async function renameWithRetry(from, to) {
|
|
|
243
253
|
}
|
|
244
254
|
var defaultPrimitives = createPersistencePrimitives();
|
|
245
255
|
var atomicWrite = defaultPrimitives.atomicWrite;
|
|
256
|
+
var atomicReplaceWithWriter = defaultPrimitives.atomicReplaceWithWriter;
|
|
246
257
|
var ensureDir = defaultPrimitives.ensureDir;
|
|
247
258
|
var withFileLock = defaultPrimitives.withFileLock;
|
|
248
259
|
|
|
@@ -424,17 +435,67 @@ async function bindProjectEndpoint(options) {
|
|
|
424
435
|
)
|
|
425
436
|
};
|
|
426
437
|
}
|
|
438
|
+
|
|
439
|
+
// src/sqlite-runtime.ts
|
|
440
|
+
import { createRequire } from "node:module";
|
|
441
|
+
function databaseSyncFromNode(module) {
|
|
442
|
+
if (typeof module !== "object" || module === null || !("DatabaseSync" in module)) return null;
|
|
443
|
+
return typeof module.DatabaseSync === "function" ? module.DatabaseSync : null;
|
|
444
|
+
}
|
|
445
|
+
function databaseSyncFromBun(module) {
|
|
446
|
+
if (typeof module !== "object" || module === null || !("Database" in module)) return null;
|
|
447
|
+
if (typeof module.Database !== "function") return null;
|
|
448
|
+
const BunDatabase = module.Database;
|
|
449
|
+
function BunDatabaseSync(filename, options) {
|
|
450
|
+
const bunOptions = options?.readOnly ? { readonly: true, create: false, readwrite: false } : void 0;
|
|
451
|
+
return new BunDatabase(filename, bunOptions);
|
|
452
|
+
}
|
|
453
|
+
return BunDatabaseSync;
|
|
454
|
+
}
|
|
455
|
+
function loadRuntimeDatabaseSync(loadModule = createRequire(import.meta.url)) {
|
|
456
|
+
let nodeError;
|
|
457
|
+
try {
|
|
458
|
+
const Database = databaseSyncFromNode(loadModule("node:sqlite"));
|
|
459
|
+
if (Database) return Database;
|
|
460
|
+
nodeError = new Error("node:sqlite did not export DatabaseSync");
|
|
461
|
+
} catch (error) {
|
|
462
|
+
nodeError = error;
|
|
463
|
+
}
|
|
464
|
+
let bunError;
|
|
465
|
+
try {
|
|
466
|
+
const Database = databaseSyncFromBun(loadModule("bun:sqlite"));
|
|
467
|
+
if (Database) return Database;
|
|
468
|
+
bunError = new Error("bun:sqlite did not export Database");
|
|
469
|
+
} catch (error) {
|
|
470
|
+
bunError = error;
|
|
471
|
+
}
|
|
472
|
+
const describe = (error) => error instanceof Error ? error.message : String(error);
|
|
473
|
+
throw new Error(
|
|
474
|
+
`No supported synchronous SQLite runtime is available (node:sqlite: ${describe(nodeError)}; bun:sqlite: ${describe(bunError)}).`
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
function isRuntimeSqliteAvailable(loadModule) {
|
|
478
|
+
try {
|
|
479
|
+
loadRuntimeDatabaseSync(loadModule);
|
|
480
|
+
return true;
|
|
481
|
+
} catch {
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
427
485
|
export {
|
|
428
486
|
PersistenceFsError,
|
|
429
487
|
SECRET_DIR_MODE,
|
|
430
488
|
SECRET_FILE_MODE,
|
|
431
489
|
assertUnixSocketPathWithinLimit,
|
|
490
|
+
atomicReplaceWithWriter,
|
|
432
491
|
atomicWrite,
|
|
433
492
|
bindProjectEndpoint,
|
|
434
493
|
checkUnixSocketPath,
|
|
435
494
|
createPersistencePrimitives,
|
|
436
495
|
ensureDir,
|
|
437
496
|
isProjectEndpointLive,
|
|
497
|
+
isRuntimeSqliteAvailable,
|
|
498
|
+
loadRuntimeDatabaseSync,
|
|
438
499
|
restrictDirPermissions,
|
|
439
500
|
restrictFilePermissions,
|
|
440
501
|
unixSocketPathLimit,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
type DatabaseSyncConstructor = typeof DatabaseSync;
|
|
3
|
+
type ModuleLoader = (specifier: string) => unknown;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the synchronous SQLite constructor for the active JavaScript runtime.
|
|
6
|
+
* Node uses `node:sqlite`; Bun uses a small constructor adapter over `bun:sqlite`.
|
|
7
|
+
* The SQL surface WrongStack relies on (`exec`, `prepare`, `get`, `all`, `run`,
|
|
8
|
+
* and `close`) is shared by both implementations.
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadRuntimeDatabaseSync(loadModule?: ModuleLoader): DatabaseSyncConstructor;
|
|
11
|
+
export declare function isRuntimeSqliteAvailable(loadModule?: ModuleLoader): boolean;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=sqlite-runtime.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/persistence",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.310.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Dependency-free filesystem persistence primitives shared across WrongStack packages.",
|
|
6
6
|
"repository": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "node ../../scripts/build-package.mjs",
|
|
38
|
-
"typecheck": "tsc --noEmit",
|
|
38
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
|
|
39
39
|
"test": "vitest run --config vitest.config.ts",
|
|
40
40
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\""
|
|
41
41
|
}
|