@harperfast/harper 5.3.0 → 5.3.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.
Files changed (231) hide show
  1. package/bin/copyDb.ts +5 -1
  2. package/bin/deployRenderer.ts +3 -0
  3. package/components/Application.ts +66 -22
  4. package/components/DESIGN.md +89 -36
  5. package/components/componentLoader.ts +2 -0
  6. package/components/deploymentRecorder.ts +18 -1
  7. package/components/installFingerprint.ts +123 -0
  8. package/components/mcp/DESIGN.md +4 -4
  9. package/components/operations.js +29 -0
  10. package/config/DESIGN.md +5 -5
  11. package/dataLayer/DESIGN.md +37 -22
  12. package/dataLayer/backupRepository.ts +248 -0
  13. package/dataLayer/restoreMarker.ts +30 -75
  14. package/dataLayer/rocksdbBackup.ts +253 -110
  15. package/dist/bin/copyDb.js +3 -0
  16. package/dist/bin/copyDb.js.map +1 -1
  17. package/dist/bin/deployRenderer.js +3 -0
  18. package/dist/bin/deployRenderer.js.map +1 -1
  19. package/dist/components/Application.d.ts +5 -0
  20. package/dist/components/Application.js +51 -19
  21. package/dist/components/Application.js.map +1 -1
  22. package/dist/components/componentLoader.js +2 -0
  23. package/dist/components/componentLoader.js.map +1 -1
  24. package/dist/components/deploymentRecorder.js +18 -1
  25. package/dist/components/deploymentRecorder.js.map +1 -1
  26. package/dist/components/installFingerprint.d.ts +39 -0
  27. package/dist/components/installFingerprint.js +113 -0
  28. package/dist/components/installFingerprint.js.map +1 -0
  29. package/dist/components/operations.d.ts +2 -0
  30. package/dist/components/operations.js +31 -0
  31. package/dist/components/operations.js.map +1 -1
  32. package/dist/dataLayer/backupRepository.d.ts +33 -0
  33. package/dist/dataLayer/backupRepository.js +232 -0
  34. package/dist/dataLayer/backupRepository.js.map +1 -0
  35. package/dist/dataLayer/restoreMarker.d.ts +4 -1
  36. package/dist/dataLayer/restoreMarker.js +29 -68
  37. package/dist/dataLayer/restoreMarker.js.map +1 -1
  38. package/dist/dataLayer/rocksdbBackup.js +221 -112
  39. package/dist/dataLayer/rocksdbBackup.js.map +1 -1
  40. package/dist/index.d.ts +1 -0
  41. package/dist/index.js.map +1 -1
  42. package/dist/json/systemSchema.json +14 -0
  43. package/dist/resources/DatabaseTransaction.d.ts +140 -11
  44. package/dist/resources/DatabaseTransaction.js +1055 -464
  45. package/dist/resources/DatabaseTransaction.js.map +1 -1
  46. package/dist/resources/IterableEventQueue.d.ts +2 -1
  47. package/dist/resources/IterableEventQueue.js +16 -8
  48. package/dist/resources/IterableEventQueue.js.map +1 -1
  49. package/dist/resources/LMDBTransaction.d.ts +13 -2
  50. package/dist/resources/LMDBTransaction.js +219 -93
  51. package/dist/resources/LMDBTransaction.js.map +1 -1
  52. package/dist/resources/RecordEncoder.js +2 -3
  53. package/dist/resources/RecordEncoder.js.map +1 -1
  54. package/dist/resources/Resource.js +5 -6
  55. package/dist/resources/Resource.js.map +1 -1
  56. package/dist/resources/ResourceInterface.d.ts +3 -1
  57. package/dist/resources/ResourceInterface.js.map +1 -1
  58. package/dist/resources/RocksIndexStore.d.ts +2 -1
  59. package/dist/resources/RocksIndexStore.js +3 -0
  60. package/dist/resources/RocksIndexStore.js.map +1 -1
  61. package/dist/resources/Table.js +116 -12
  62. package/dist/resources/Table.js.map +1 -1
  63. package/dist/resources/analytics/write.js +6 -2
  64. package/dist/resources/analytics/write.js.map +1 -1
  65. package/dist/resources/auditStore.d.ts +71 -17
  66. package/dist/resources/auditStore.js +248 -64
  67. package/dist/resources/auditStore.js.map +1 -1
  68. package/dist/resources/branchDatabase.js +2 -0
  69. package/dist/resources/branchDatabase.js.map +1 -1
  70. package/dist/resources/databases.js +8 -2
  71. package/dist/resources/databases.js.map +1 -1
  72. package/dist/resources/indexes/fullTextNativeBinding.d.ts +6 -2
  73. package/dist/resources/indexes/fullTextNativeBinding.js +12 -2
  74. package/dist/resources/indexes/fullTextNativeBinding.js.map +1 -1
  75. package/dist/resources/indexes/fullTextQueryIndex.d.ts +4 -0
  76. package/dist/resources/indexes/fullTextQueryIndex.js +207 -10
  77. package/dist/resources/indexes/fullTextQueryIndex.js.map +1 -1
  78. package/dist/resources/models/Models.d.ts +11 -0
  79. package/dist/resources/models/Models.js +95 -4
  80. package/dist/resources/models/Models.js.map +1 -1
  81. package/dist/resources/models/backendRegistry.d.ts +8 -0
  82. package/dist/resources/models/backendRegistry.js +15 -1
  83. package/dist/resources/models/backendRegistry.js.map +1 -1
  84. package/dist/resources/models/bootstrap.d.ts +2 -0
  85. package/dist/resources/models/bootstrap.js +6 -0
  86. package/dist/resources/models/bootstrap.js.map +1 -1
  87. package/dist/resources/models/calibration.d.ts +88 -0
  88. package/dist/resources/models/calibration.js +244 -0
  89. package/dist/resources/models/calibration.js.map +1 -0
  90. package/dist/resources/models/calibrationStore.d.ts +163 -0
  91. package/dist/resources/models/calibrationStore.js +986 -0
  92. package/dist/resources/models/calibrationStore.js.map +1 -0
  93. package/dist/resources/models/decisionStore.d.ts +24 -0
  94. package/dist/resources/models/decisionStore.js +45 -0
  95. package/dist/resources/models/decisionStore.js.map +1 -1
  96. package/dist/resources/models/generativeDecision.js +44 -15
  97. package/dist/resources/models/generativeDecision.js.map +1 -1
  98. package/dist/resources/models/types.d.ts +7 -0
  99. package/dist/resources/recordLock.d.ts +8 -5
  100. package/dist/resources/recordLock.js +6 -4
  101. package/dist/resources/recordLock.js.map +1 -1
  102. package/dist/resources/replayLogs.js +8 -1
  103. package/dist/resources/replayLogs.js.map +1 -1
  104. package/dist/resources/scheduler/engine.d.ts +4 -0
  105. package/dist/resources/scheduler/engine.js +30 -2
  106. package/dist/resources/scheduler/engine.js.map +1 -1
  107. package/dist/resources/search.d.ts +16 -4
  108. package/dist/resources/search.js +117 -13
  109. package/dist/resources/search.js.map +1 -1
  110. package/dist/resources/transaction.js +85 -5
  111. package/dist/resources/transaction.js.map +1 -1
  112. package/dist/resources/transactionBroadcast.d.ts +8 -0
  113. package/dist/resources/transactionBroadcast.js +65 -0
  114. package/dist/resources/transactionBroadcast.js.map +1 -1
  115. package/dist/security/keys.d.ts +1 -1
  116. package/dist/security/keys.js +170 -120
  117. package/dist/security/keys.js.map +1 -1
  118. package/dist/server/http.js +10 -0
  119. package/dist/server/http.js.map +1 -1
  120. package/dist/server/serverHelpers/Request.js +11 -2
  121. package/dist/server/serverHelpers/Request.js.map +1 -1
  122. package/dist/server/serverHelpers/contentTypes.js +8 -3
  123. package/dist/server/serverHelpers/contentTypes.js.map +1 -1
  124. package/dist/server/serverHelpers/uwsServer.js +38 -7
  125. package/dist/server/serverHelpers/uwsServer.js.map +1 -1
  126. package/dist/server/threads/manageThreads.d.ts +3 -3
  127. package/dist/server/threads/manageThreads.js +15 -13
  128. package/dist/server/threads/manageThreads.js.map +1 -1
  129. package/dist/server/threads/threadServer.d.ts +3 -0
  130. package/dist/server/threads/threadServer.js +24 -6
  131. package/dist/server/threads/threadServer.js.map +1 -1
  132. package/dist/upgrade/directives/5-3-0.js +9 -3
  133. package/dist/upgrade/directives/5-3-0.js.map +1 -1
  134. package/dist/utility/durableFile.d.ts +36 -0
  135. package/dist/utility/durableFile.js +106 -0
  136. package/dist/utility/durableFile.js.map +1 -0
  137. package/dist/utility/errors/hdbError.d.ts +4 -0
  138. package/dist/utility/errors/hdbError.js +10 -1
  139. package/dist/utility/errors/hdbError.js.map +1 -1
  140. package/dist/utility/globalSchema.d.ts +9 -0
  141. package/dist/utility/hdbTerms.d.ts +1 -0
  142. package/dist/utility/hdbTerms.js +1 -0
  143. package/dist/utility/hdbTerms.js.map +1 -1
  144. package/dist/validation/configValidator.js +29 -0
  145. package/dist/validation/configValidator.js.map +1 -1
  146. package/index.ts +7 -0
  147. package/json/systemSchema.json +14 -0
  148. package/npm-shrinkwrap.json +22 -22
  149. package/package.json +2 -2
  150. package/resources/DESIGN.md +57 -272
  151. package/resources/DatabaseTransaction.ts +708 -87
  152. package/resources/FULL_TEXT.md +6 -2
  153. package/resources/IterableEventQueue.ts +14 -7
  154. package/resources/LMDBTransaction.ts +212 -84
  155. package/resources/RecordEncoder.ts +2 -3
  156. package/resources/Resource.ts +5 -6
  157. package/resources/ResourceInterface.ts +3 -1
  158. package/resources/RocksIndexStore.ts +5 -0
  159. package/resources/Table.ts +118 -15
  160. package/resources/analytics/write.ts +6 -2
  161. package/resources/audit-retention.md +203 -0
  162. package/resources/auditStore.ts +306 -84
  163. package/resources/branchDatabase.ts +2 -0
  164. package/resources/databases.ts +6 -2
  165. package/resources/indexes/DESIGN.md +120 -177
  166. package/resources/indexes/fullTextNativeBinding.ts +22 -3
  167. package/resources/indexes/fullTextQueryIndex.ts +274 -11
  168. package/resources/models/DESIGN.md +11 -3
  169. package/resources/models/Models.ts +127 -4
  170. package/resources/models/backendRegistry.ts +17 -0
  171. package/resources/models/bootstrap.ts +9 -1
  172. package/resources/models/calibration.ts +298 -0
  173. package/resources/models/calibrationStore.ts +1167 -0
  174. package/resources/models/decisionStore.ts +57 -0
  175. package/resources/models/generativeDecision.ts +54 -16
  176. package/resources/models/types.ts +6 -0
  177. package/resources/record-locks.md +155 -141
  178. package/resources/recordLock.ts +12 -6
  179. package/resources/replayLogs.ts +9 -2
  180. package/resources/scheduler/DESIGN.md +4 -3
  181. package/resources/scheduler/engine.ts +35 -2
  182. package/resources/search.ts +154 -16
  183. package/resources/transaction.ts +50 -5
  184. package/resources/transactionBroadcast.ts +69 -0
  185. package/security/DESIGN.md +9 -30
  186. package/security/keys.ts +175 -127
  187. package/server/DESIGN.md +70 -36
  188. package/server/http.ts +10 -0
  189. package/server/serverHelpers/Request.ts +10 -2
  190. package/server/serverHelpers/contentTypes.ts +5 -3
  191. package/server/serverHelpers/uwsServer.ts +34 -7
  192. package/server/threads/manageThreads.js +16 -14
  193. package/server/threads/threadServer.js +24 -6
  194. package/studio/web/assets/{Chat-CNEKMllJ.js → Chat-4LMxI0yB.js} +1 -1
  195. package/studio/web/assets/{FloatingChat-CEnWhHeR.js → FloatingChat-kWHApEtF.js} +3 -3
  196. package/studio/web/assets/{SearchDialog-CwhJdEdY.js → SearchDialog-B7ymna97.js} +1 -1
  197. package/studio/web/assets/{apiToken-DC5vsaaO.js → apiToken-CE3AAt9f.js} +1 -1
  198. package/studio/web/assets/{applications-DQZxDy0x.js → applications-DdN7CqsB.js} +1 -1
  199. package/studio/web/assets/{cssMode-Dz2DxF4e.js → cssMode-BpySZUSt.js} +1 -1
  200. package/studio/web/assets/{editor-B3mjd3tz.js → editor-myLCVv9C.js} +1 -1
  201. package/studio/web/assets/{html-BsRGM7tp.js → html-DGNYO55O.js} +1 -1
  202. package/studio/web/assets/{htmlMode-tUKJaA3o.js → htmlMode-BUgpQr41.js} +1 -1
  203. package/studio/web/assets/{index-BuqFjN5K.js → index-FN4KC9va.js} +39 -39
  204. package/studio/web/assets/index-QLZw6xrU.css +1 -0
  205. package/studio/web/assets/{index.lazy-CcpfQFY_.js → index.lazy-DZFuaumG.js} +1 -1
  206. package/studio/web/assets/{javascript-BZ_uRGHl.js → javascript-DiBzh4pj.js} +1 -1
  207. package/studio/web/assets/{jsonMode-DgB-aFMj.js → jsonMode-Bm312nmu.js} +1 -1
  208. package/studio/web/assets/{languageServices-BleuBw17.js → languageServices-Dz2K9rZN.js} +1 -1
  209. package/studio/web/assets/{lspLanguageFeatures-ByVYLSsQ.js → lspLanguageFeatures-CNu1L5xn.js} +1 -1
  210. package/studio/web/assets/{notifications-TuzN0IMi.js → notifications--nwFLGmM.js} +1 -1
  211. package/studio/web/assets/{notifications-D1Nf-Edn.js → notifications-BelKw5bR.js} +1 -1
  212. package/studio/web/assets/{profile-D7C7Lupz.js → profile-AU5FjOBx.js} +1 -1
  213. package/studio/web/assets/{regions-nGQCm-v8.js → regions-C0sTSEHH.js} +1 -1
  214. package/studio/web/assets/{register-C3x9Ze6P.js → register-DyNR2rGk.js} +2 -2
  215. package/studio/web/assets/{setComponentFile-DpjrRqeG.js → setComponentFile-BkWx8AN3.js} +1 -1
  216. package/studio/web/assets/{setup-CGiKLZ9e.js → setup-D6LZS78d.js} +2 -2
  217. package/studio/web/assets/{status-CGJwrNPH.js → status-BCWnn70o.js} +1 -1
  218. package/studio/web/assets/{toggleHighContrast-C-Ne6P7T.js → toggleHighContrast-pyeGJ6W1.js} +1 -1
  219. package/studio/web/assets/{tsMode-CSreYTys.js → tsMode-CGV3iaWC.js} +1 -1
  220. package/studio/web/assets/{typescript-MnxBk89W.js → typescript-Ci7Khvwo.js} +1 -1
  221. package/studio/web/assets/{useEntityRestURL-TNrh77-s.js → useEntityRestURL-DNiz3aZ0.js} +1 -1
  222. package/studio/web/assets/{workers-BfZlUNVI.js → workers-byzxjbqy.js} +1 -1
  223. package/studio/web/assets/{xml-BHd6qGH7.js → xml-DGnHQ3CX.js} +1 -1
  224. package/studio/web/assets/{yaml-C53R8OQq.js → yaml-BUoTnPWb.js} +1 -1
  225. package/studio/web/index.html +2 -2
  226. package/upgrade/directives/5-3-0.ts +10 -3
  227. package/utility/durableFile.ts +96 -0
  228. package/utility/errors/hdbError.ts +9 -0
  229. package/utility/hdbTerms.ts +1 -0
  230. package/validation/configValidator.ts +31 -0
  231. package/studio/web/assets/index-72cEH474.css +0 -1
@@ -1,21 +1,10 @@
1
1
  'use strict';
2
2
 
3
- import {
4
- closeSync,
5
- existsSync,
6
- mkdirSync,
7
- openSync,
8
- readdirSync,
9
- readFileSync,
10
- renameSync,
11
- fsyncSync,
12
- unlinkSync,
13
- writeSync,
14
- } from 'node:fs';
3
+ import { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync } from 'node:fs';
15
4
  import { basename, dirname, isAbsolute, join, resolve } from 'node:path';
16
5
  import { createHash } from 'node:crypto';
17
6
  import { tryFileLock, fileLockRelease } from '@harperfast/rocksdb-js';
18
- import { fsyncTolerantSync, isUnsupportedSyncError } from '../utility/fsync.ts';
7
+ import { fsyncDirectory, pathPresent, writeFileDurably } from '../utility/durableFile.ts';
19
8
 
20
9
  /**
21
10
  * Restore lock + marker protocol for RocksDB database restores (online operation and offline CLI),
@@ -112,11 +101,11 @@ export type RestoreState = 'in-progress' | 'incomplete' | 'clear';
112
101
  * distinguish debris from a crashed restore.
113
102
  */
114
103
  export function restoreMarkerPresent(dbPath: string): boolean {
115
- return existsSync(restoringMarkerPath(dbPath));
104
+ return pathPresent(restoringMarkerPath(dbPath));
116
105
  }
117
106
 
118
107
  export function databaseDropMarkerPresent(dbPath: string): boolean {
119
- return existsSync(droppingMarkerPath(dbPath));
108
+ return pathPresent(droppingMarkerPath(dbPath));
120
109
  }
121
110
 
122
111
  /** The lock and (optional) marker held by a begin/acquire call, threaded back to complete/abandon. */
@@ -151,9 +140,9 @@ export type RestoreLock = {
151
140
  * before any destructive step, so a database without a marker has nothing to protect yet.
152
141
  */
153
142
  export function checkRestoreState(dbPath: string): RestoreState {
154
- if (!existsSync(restoringMarkerPath(dbPath))) return 'clear';
143
+ if (!pathPresent(restoringMarkerPath(dbPath))) return 'clear';
155
144
  const lockPath = restoreLockPath(dbPath);
156
- if (existsSync(lockPath)) {
145
+ if (pathPresent(lockPath)) {
157
146
  const token = tryFileLock(lockPath);
158
147
  if (token === 0) return 'in-progress';
159
148
  fileLockRelease(token);
@@ -161,26 +150,6 @@ export function checkRestoreState(dbPath: string): RestoreState {
161
150
  return 'incomplete';
162
151
  }
163
152
 
164
- /**
165
- * fsync a directory so a create/unlink of an entry within it is durable. Best-effort: Windows (and
166
- * some filesystems) reject opening a directory for fsync with EPERM/EISDIR/ENOTSUP — the durability
167
- * flush is a POSIX nicety, so treat those as a no-op rather than failing the restore.
168
- */
169
- function fsyncDir(dir: string): void {
170
- let dirFd: number;
171
- try {
172
- dirFd = openSync(dir, 'r');
173
- } catch (error: any) {
174
- if (isUnsupportedSyncError(error)) return;
175
- throw error;
176
- }
177
- try {
178
- fsyncTolerantSync(dirFd);
179
- } finally {
180
- closeSync(dirFd);
181
- }
182
- }
183
-
184
153
  /**
185
154
  * Take the per-database restore lock without writing a marker. Restore and drop build their durable
186
155
  * protocols on this shared exclusion primitive. Throws (statusCode 409) if the lock is already held.
@@ -189,7 +158,7 @@ export function acquireRestoreLock(dbPath: string): RestoreLock {
189
158
  const metaDir = restoreMetaDir(dbPath);
190
159
  const createMetaDir = !existsSync(metaDir);
191
160
  mkdirSync(metaDir, { recursive: true });
192
- if (createMetaDir) fsyncDir(dirname(metaDir));
161
+ if (createMetaDir) fsyncDirectory(dirname(metaDir));
193
162
  const token = tryFileLock(restoreLockPath(dbPath));
194
163
  if (token === 0) {
195
164
  const error: any = new Error(`Restore already in progress for database at ${dbPath}`);
@@ -226,28 +195,7 @@ function markerIsIntact(markerPath: string, dbPath: string): boolean {
226
195
  * left by an earlier crash is this database's own debris and is simply overwritten.
227
196
  */
228
197
  function publishMarker(dbPath: string, markerPath: string, content: string): void {
229
- const metaDir = restoreMetaDir(dbPath);
230
- const tempPath = join(metaDir, restoreMetaKey(dbPath) + MARKER_TEMP_SUFFIX);
231
- try {
232
- const fd = openSync(tempPath, 'w');
233
- try {
234
- writeSync(fd, content);
235
- fsyncSync(fd);
236
- } finally {
237
- closeSync(fd);
238
- }
239
- renameSync(tempPath, markerPath);
240
- } catch (error) {
241
- try {
242
- unlinkSync(tempPath);
243
- } catch {
244
- // debris either way; the write failure is the error worth reporting
245
- }
246
- throw error;
247
- }
248
- // fsync the metadata directory so the marker's directory entry is durable — without this a
249
- // power loss can lose the entry, and a half-purged database would load as healthy
250
- fsyncDir(metaDir);
198
+ writeFileDurably(markerPath, content, restoreMetaKey(dbPath) + MARKER_TEMP_SUFFIX);
251
199
  }
252
200
 
253
201
  function publishRestoringMarker(dbPath: string): void {
@@ -263,48 +211,55 @@ function publishRestoringMarker(dbPath: string): void {
263
211
  * destructive step. Returns the lock (with `preexisting` set when a marker was already present, so
264
212
  * a failed recovery attempt knows not to clear it). Throws (statusCode 409) if another restore
265
213
  * already holds the lock.
214
+ * `beforePublishMarker` runs synchronously under the lock, after admission but before publication,
215
+ * so a caller can durably claim its source before a crash can leave a restoring marker behind.
266
216
  *
267
217
  * An intact marker is left exactly as it is. A recovery attempt runs over a directory an earlier
268
218
  * restore may have half-purged, so the marker it finds is the only thing keeping that directory
269
219
  * from loading as healthy; rewriting it buys nothing (the content it would write is the content
270
220
  * already there) and risks everything.
271
221
  */
272
- export function beginRestore(dbPath: string): RestoreLock {
222
+ export function beginRestore(dbPath: string, beforePublishMarker?: () => void): RestoreLock {
273
223
  const markerPath = restoringMarkerPath(dbPath);
274
224
  const lock = acquireRestoreLock(dbPath);
275
225
  // Sampled while holding the lock, not before it: a restore that waited out an earlier one would
276
226
  // otherwise carry the earlier run's "no marker" reading, and on its own pre-destruction failure
277
227
  // clear the marker protecting a directory that run had already half-purged.
278
- const preexisting = existsSync(markerPath);
279
228
  try {
229
+ lock.preexisting = pathPresent(markerPath);
280
230
  if (databaseDropMarkerPresent(dbPath)) {
281
231
  const error: any = new Error(`Database at ${dbPath} has an incomplete drop; retry drop_database first`);
282
232
  error.statusCode = 409;
283
233
  throw error;
284
234
  }
285
- if (!preexisting || !markerIsIntact(markerPath, dbPath)) publishRestoringMarker(dbPath);
235
+ beforePublishMarker?.();
236
+ if (!lock.preexisting || !markerIsIntact(markerPath, dbPath)) publishRestoringMarker(dbPath);
286
237
  // An intact marker is kept, but its durability is not assumed: the publisher that wrote it may
287
238
  // have been interrupted between the rename and this flush, which would leave the directory
288
239
  // entry — the thing the startup scan reads — still only in the page cache.
289
- else fsyncDir(restoreMetaDir(dbPath));
240
+ else fsyncDirectory(restoreMetaDir(dbPath));
290
241
  } catch (error) {
291
242
  fileLockRelease(lock.token);
292
243
  throw error;
293
244
  }
294
- return { ...lock, preexisting };
245
+ return lock;
295
246
  }
296
247
 
297
248
  /**
298
249
  * Mark the restore successful: delete the marker (while still holding the lock), then release
299
250
  * the lock.
300
251
  */
252
+ export function clearRestoringMarker(lock: RestoreLock): void {
253
+ unlinkSync(restoringMarkerPath(lock.dbPath));
254
+ // fsync the metadata directory so the marker's *removal* is durable — symmetric with the
255
+ // creation fsync in beginRestore. Without it, a power loss could resurrect the marker's
256
+ // directory entry and misclassify a fully-restored database as incomplete.
257
+ fsyncDirectory(restoreMetaDir(lock.dbPath));
258
+ }
259
+
301
260
  export function completeRestore(lock: RestoreLock): void {
302
261
  try {
303
- unlinkSync(restoringMarkerPath(lock.dbPath));
304
- // fsync the metadata directory so the marker's *removal* is durable — symmetric with the
305
- // creation fsync in beginRestore. Without it, a power loss could resurrect the marker's
306
- // directory entry and misclassify a fully-restored database as incomplete.
307
- fsyncDir(restoreMetaDir(lock.dbPath));
262
+ clearRestoringMarker(lock);
308
263
  } finally {
309
264
  fileLockRelease(lock.token);
310
265
  }
@@ -328,7 +283,7 @@ export function clearRestoreMarker(lock: RestoreLock): void {
328
283
  const markerPath = restoringMarkerPath(lock.dbPath);
329
284
  if (existsSync(markerPath)) {
330
285
  unlinkSync(markerPath);
331
- fsyncDir(restoreMetaDir(lock.dbPath));
286
+ fsyncDirectory(restoreMetaDir(lock.dbPath));
332
287
  }
333
288
  } finally {
334
289
  fileLockRelease(lock.token);
@@ -459,7 +414,7 @@ export function beginDatabaseDrop(
459
414
  }
460
415
  blobDatabaseName = marker.blobDatabaseName;
461
416
  blobPaths = marker.blobPaths;
462
- fsyncDir(restoreMetaDir(dbPath));
417
+ fsyncDirectory(restoreMetaDir(dbPath));
463
418
  } else {
464
419
  const encodedBlobPaths = encodeBlobPaths(blobPaths);
465
420
  publishMarker(
@@ -479,16 +434,16 @@ function removeDatabaseDropMarker(lock: DatabaseDropLock): void {
479
434
  const markerPath = droppingMarkerPath(lock.dbPath);
480
435
  if (existsSync(markerPath)) {
481
436
  unlinkSync(markerPath);
482
- fsyncDir(restoreMetaDir(lock.dbPath));
437
+ fsyncDirectory(restoreMetaDir(lock.dbPath));
483
438
  }
484
439
  }
485
440
 
486
441
  export function completeDatabaseDrop(lock: DatabaseDropLock): void {
487
442
  try {
488
- fsyncDir(dirname(lock.dbPath));
443
+ fsyncDirectory(dirname(lock.dbPath));
489
444
  for (const blobPath of lock.blobPaths) {
490
445
  const parent = dirname(blobPath);
491
- if (existsSync(parent)) fsyncDir(parent);
446
+ if (existsSync(parent)) fsyncDirectory(parent);
492
447
  }
493
448
  removeDatabaseDropMarker(lock);
494
449
  } finally {