@fudrouter/fsrouter 0.6.94 → 0.6.95

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.
@@ -72,13 +72,51 @@ export async function POST_handler(req, res) {
72
72
  if (db && typeof db.close === "function")
73
73
  db.close();
74
74
  }
75
- // 2. Remove active -wal and -shm files to prevent corruption/mismatch
75
+ // 2. Remove active -wal and -shm files to prevent corruption/mismatch.
76
+ // On Windows these files can be locked by the OS/AV/SQLite even after
77
+ // db.close() (EBUSY). Use a retry + rename fallback so restore never
78
+ // hard-fails on a transient lock.
76
79
  const walFile = path.join(DATA_DIR, "db", "data.sqlite-wal");
77
80
  const shmFile = path.join(DATA_DIR, "db", "data.sqlite-shm");
78
- if (fs.existsSync(walFile))
79
- fs.unlinkSync(walFile);
80
- if (fs.existsSync(shmFile))
81
- fs.unlinkSync(shmFile);
81
+ const safeUnlink = (file) => {
82
+ if (!fs.existsSync(file))
83
+ return;
84
+ // Give the DB a moment to fully release the file handle.
85
+ const attempts = process.platform === "win32" ? 12 : 3;
86
+ for (let i = 0; i < attempts; i++) {
87
+ try {
88
+ fs.unlinkSync(file);
89
+ return;
90
+ }
91
+ catch (e) {
92
+ if (e.code === "EBUSY" || e.code === "EPERM" || e.code === "ETXTBSY") {
93
+ // Fallback: rename out of the way (atomic on NTFS) then retry unlink.
94
+ try {
95
+ const tmp = `${file}.old-${Date.now()}`;
96
+ fs.renameSync(file, tmp);
97
+ try {
98
+ fs.unlinkSync(tmp);
99
+ }
100
+ catch { /* ignore */ }
101
+ return;
102
+ }
103
+ catch {
104
+ // Wait and retry — the lock may be released shortly.
105
+ try {
106
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 250);
107
+ }
108
+ catch { /* noop */ }
109
+ continue;
110
+ }
111
+ }
112
+ throw e;
113
+ }
114
+ }
115
+ // Last resort: leave the file; SQLite rebuilds -wal/-shm on next open.
116
+ console.warn(`[Restore] Could not remove ${file} (locked) — continuing.`);
117
+ };
118
+ safeUnlink(walFile);
119
+ safeUnlink(shmFile);
82
120
  // 3. Restore secrets/raw DB only for legacy backups. Do not overwrite the
83
121
  // logical import with a stale/incompatible SQLite file.
84
122
  const filesToRestore = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fudrouter/fsrouter",
3
- "version": "0.6.94",
3
+ "version": "0.6.95",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "9Router v2 — Express Backend (API, SSE, DB, Auth, MITM)",