@bendyline/docblocks 2.0.0 → 2.1.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 (278) hide show
  1. package/README.md +2 -2
  2. package/dist/{chunk-2D7Y4IR3.js → chunk-4437YWLE.js} +123 -67
  3. package/dist/{chunk-5MYAICRE.js → chunk-45T5AFCN.js} +44 -57
  4. package/dist/{chunk-PGR7LK6D.js → chunk-6L3JRDE7.js} +14 -6
  5. package/dist/{chunk-RVQHY3XU.js → chunk-6XHOOBYF.js} +0 -1
  6. package/dist/chunk-73OOROXH.js +8 -0
  7. package/dist/{chunk-SI2LU2RP.js → chunk-AYWKIZLD.js} +1 -1
  8. package/dist/{chunk-GCPBEMMH.js → chunk-BVY7GGNV.js} +10 -21
  9. package/dist/{chunk-AEHCVWU5.js → chunk-DZB666V7.js} +0 -1
  10. package/dist/{chunk-75UUF6C4.js → chunk-HI7QEWL6.js} +18 -10
  11. package/dist/chunk-KQ6756AJ.js +28 -0
  12. package/dist/chunk-LMMOFRGQ.js +148 -0
  13. package/dist/{chunk-FNW556FN.js → chunk-M2PUNKHS.js} +0 -1
  14. package/dist/chunk-M5ZNQGR5.js +19 -0
  15. package/dist/chunk-M62ZGJ5I.js +51 -0
  16. package/dist/chunk-OQCPBOQA.js +168 -0
  17. package/dist/{chunk-EGNDADXB.js → chunk-QI6YKTQV.js} +2 -3
  18. package/dist/chunk-SJBB5OD7.js +227 -0
  19. package/dist/{chunk-EZKJZUNJ.js → chunk-XAMILHQP.js} +0 -1
  20. package/dist/{chunk-J32GU3F3.js → chunk-YM7O3PWO.js} +249 -222
  21. package/dist/{chunk-RQJRQF46.js → chunk-ZO7G53QP.js} +41 -49
  22. package/dist/document/index.d.ts +358 -6
  23. package/dist/document/index.js +24 -4
  24. package/dist/filesystem/electron.d.ts +73 -4
  25. package/dist/filesystem/electron.js +16 -4
  26. package/dist/filesystem/index.d.ts +228 -22
  27. package/dist/filesystem/index.js +133 -20
  28. package/dist/filesystem/indexeddb.d.ts +284 -5
  29. package/dist/filesystem/indexeddb.js +22 -5
  30. package/dist/filesystem/memory.d.ts +152 -4
  31. package/dist/filesystem/memory.js +12 -4
  32. package/dist/filesystem/native.d.ts +136 -4
  33. package/dist/filesystem/native.js +27 -4
  34. package/dist/host/index.d.ts +32 -9
  35. package/dist/host/index.js +26 -30
  36. package/dist/index.d.ts +14 -10
  37. package/dist/index.js +204 -10
  38. package/dist/mcp/index.d.ts +33 -4
  39. package/dist/mcp/index.js +31 -4
  40. package/dist/mcp/zod.d.ts +645 -643
  41. package/dist/mcp/zod.js +700 -885
  42. package/dist/share/index.d.ts +43 -0
  43. package/dist/share/index.js +12 -0
  44. package/dist/{types-CsX6EN2t.d.ts → types-BEg5SQ1_.d.ts} +1 -1
  45. package/dist/{types-eOlt9J7n.d.ts → types-CueK0tvU.d.ts} +34 -11
  46. package/dist/vscode/index.d.ts +225 -3
  47. package/dist/vscode/index.js +389 -3
  48. package/dist/workspace/index.d.ts +141 -4
  49. package/dist/workspace/index.js +28 -3
  50. package/package.json +10 -5
  51. package/dist/chunk-2D7Y4IR3.js.map +0 -1
  52. package/dist/chunk-5MYAICRE.js.map +0 -1
  53. package/dist/chunk-75UUF6C4.js.map +0 -1
  54. package/dist/chunk-AEHCVWU5.js.map +0 -1
  55. package/dist/chunk-AYZ4HN5M.js +0 -20
  56. package/dist/chunk-AYZ4HN5M.js.map +0 -1
  57. package/dist/chunk-EGNDADXB.js.map +0 -1
  58. package/dist/chunk-EZKJZUNJ.js.map +0 -1
  59. package/dist/chunk-FNW556FN.js.map +0 -1
  60. package/dist/chunk-GCPBEMMH.js.map +0 -1
  61. package/dist/chunk-J32GU3F3.js.map +0 -1
  62. package/dist/chunk-PGR7LK6D.js.map +0 -1
  63. package/dist/chunk-RQJRQF46.js.map +0 -1
  64. package/dist/chunk-RVQHY3XU.js.map +0 -1
  65. package/dist/chunk-SI2LU2RP.js.map +0 -1
  66. package/dist/chunk-W5UUUII5.js +0 -142
  67. package/dist/chunk-W5UUUII5.js.map +0 -1
  68. package/dist/document/document-session.d.ts +0 -127
  69. package/dist/document/document-session.d.ts.map +0 -1
  70. package/dist/document/document-session.js +0 -749
  71. package/dist/document/document-session.js.map +0 -1
  72. package/dist/document/filesystem-target.d.ts +0 -17
  73. package/dist/document/filesystem-target.d.ts.map +0 -1
  74. package/dist/document/filesystem-target.js +0 -70
  75. package/dist/document/filesystem-target.js.map +0 -1
  76. package/dist/document/index.d.ts.map +0 -1
  77. package/dist/document/index.js.map +0 -1
  78. package/dist/document/recovery-journal.d.ts +0 -125
  79. package/dist/document/recovery-journal.d.ts.map +0 -1
  80. package/dist/document/recovery-journal.js +0 -385
  81. package/dist/document/recovery-journal.js.map +0 -1
  82. package/dist/document/types.d.ts +0 -89
  83. package/dist/document/types.d.ts.map +0 -1
  84. package/dist/document/types.js +0 -9
  85. package/dist/document/types.js.map +0 -1
  86. package/dist/filesystem/commit-lock.d.ts +0 -3
  87. package/dist/filesystem/commit-lock.d.ts.map +0 -1
  88. package/dist/filesystem/commit-lock.js +0 -20
  89. package/dist/filesystem/commit-lock.js.map +0 -1
  90. package/dist/filesystem/dbk-workspace.d.ts +0 -34
  91. package/dist/filesystem/dbk-workspace.d.ts.map +0 -1
  92. package/dist/filesystem/dbk-workspace.js +0 -85
  93. package/dist/filesystem/dbk-workspace.js.map +0 -1
  94. package/dist/filesystem/electron-provider-v2.d.ts +0 -36
  95. package/dist/filesystem/electron-provider-v2.d.ts.map +0 -1
  96. package/dist/filesystem/electron-provider-v2.js +0 -503
  97. package/dist/filesystem/electron-provider-v2.js.map +0 -1
  98. package/dist/filesystem/electron-provider.d.ts +0 -35
  99. package/dist/filesystem/electron-provider.d.ts.map +0 -1
  100. package/dist/filesystem/electron-provider.js +0 -69
  101. package/dist/filesystem/electron-provider.js.map +0 -1
  102. package/dist/filesystem/electron.d.ts.map +0 -1
  103. package/dist/filesystem/electron.js.map +0 -1
  104. package/dist/filesystem/file-media-provider.d.ts +0 -23
  105. package/dist/filesystem/file-media-provider.d.ts.map +0 -1
  106. package/dist/filesystem/file-media-provider.js +0 -85
  107. package/dist/filesystem/file-media-provider.js.map +0 -1
  108. package/dist/filesystem/filesystem-content-container.d.ts +0 -24
  109. package/dist/filesystem/filesystem-content-container.d.ts.map +0 -1
  110. package/dist/filesystem/filesystem-content-container.js +0 -153
  111. package/dist/filesystem/filesystem-content-container.js.map +0 -1
  112. package/dist/filesystem/fs-error.d.ts +0 -46
  113. package/dist/filesystem/fs-error.d.ts.map +0 -1
  114. package/dist/filesystem/fs-error.js +0 -170
  115. package/dist/filesystem/fs-error.js.map +0 -1
  116. package/dist/filesystem/index.d.ts.map +0 -1
  117. package/dist/filesystem/index.js.map +0 -1
  118. package/dist/filesystem/indexeddb-content-container.d.ts +0 -22
  119. package/dist/filesystem/indexeddb-content-container.d.ts.map +0 -1
  120. package/dist/filesystem/indexeddb-content-container.js +0 -100
  121. package/dist/filesystem/indexeddb-content-container.js.map +0 -1
  122. package/dist/filesystem/indexeddb-provider-v2.d.ts +0 -96
  123. package/dist/filesystem/indexeddb-provider-v2.d.ts.map +0 -1
  124. package/dist/filesystem/indexeddb-provider-v2.js +0 -1241
  125. package/dist/filesystem/indexeddb-provider-v2.js.map +0 -1
  126. package/dist/filesystem/indexeddb-provider.d.ts +0 -39
  127. package/dist/filesystem/indexeddb-provider.d.ts.map +0 -1
  128. package/dist/filesystem/indexeddb-provider.js +0 -145
  129. package/dist/filesystem/indexeddb-provider.js.map +0 -1
  130. package/dist/filesystem/indexeddb-store.d.ts +0 -34
  131. package/dist/filesystem/indexeddb-store.d.ts.map +0 -1
  132. package/dist/filesystem/indexeddb-store.js +0 -165
  133. package/dist/filesystem/indexeddb-store.js.map +0 -1
  134. package/dist/filesystem/indexeddb.d.ts.map +0 -1
  135. package/dist/filesystem/indexeddb.js.map +0 -1
  136. package/dist/filesystem/legacy-v2-adapter.d.ts +0 -62
  137. package/dist/filesystem/legacy-v2-adapter.d.ts.map +0 -1
  138. package/dist/filesystem/legacy-v2-adapter.js +0 -499
  139. package/dist/filesystem/legacy-v2-adapter.js.map +0 -1
  140. package/dist/filesystem/memory-provider-v2.d.ts +0 -92
  141. package/dist/filesystem/memory-provider-v2.d.ts.map +0 -1
  142. package/dist/filesystem/memory-provider-v2.js +0 -615
  143. package/dist/filesystem/memory-provider-v2.js.map +0 -1
  144. package/dist/filesystem/memory-provider.d.ts +0 -54
  145. package/dist/filesystem/memory-provider.d.ts.map +0 -1
  146. package/dist/filesystem/memory-provider.js +0 -132
  147. package/dist/filesystem/memory-provider.js.map +0 -1
  148. package/dist/filesystem/memory.d.ts.map +0 -1
  149. package/dist/filesystem/memory.js.map +0 -1
  150. package/dist/filesystem/move-entry.d.ts +0 -9
  151. package/dist/filesystem/move-entry.d.ts.map +0 -1
  152. package/dist/filesystem/move-entry.js +0 -103
  153. package/dist/filesystem/move-entry.js.map +0 -1
  154. package/dist/filesystem/move-error.d.ts +0 -53
  155. package/dist/filesystem/move-error.d.ts.map +0 -1
  156. package/dist/filesystem/move-error.js +0 -99
  157. package/dist/filesystem/move-error.js.map +0 -1
  158. package/dist/filesystem/native-provider-v2.d.ts +0 -75
  159. package/dist/filesystem/native-provider-v2.d.ts.map +0 -1
  160. package/dist/filesystem/native-provider-v2.js +0 -849
  161. package/dist/filesystem/native-provider-v2.js.map +0 -1
  162. package/dist/filesystem/native-provider.d.ts +0 -53
  163. package/dist/filesystem/native-provider.d.ts.map +0 -1
  164. package/dist/filesystem/native-provider.js +0 -471
  165. package/dist/filesystem/native-provider.js.map +0 -1
  166. package/dist/filesystem/native.d.ts.map +0 -1
  167. package/dist/filesystem/native.js.map +0 -1
  168. package/dist/filesystem/types.d.ts +0 -83
  169. package/dist/filesystem/types.d.ts.map +0 -1
  170. package/dist/filesystem/types.js +0 -16
  171. package/dist/filesystem/types.js.map +0 -1
  172. package/dist/filesystem/v2.d.ts +0 -172
  173. package/dist/filesystem/v2.d.ts.map +0 -1
  174. package/dist/filesystem/v2.js +0 -16
  175. package/dist/filesystem/v2.js.map +0 -1
  176. package/dist/filesystem/workspace-path.d.ts +0 -21
  177. package/dist/filesystem/workspace-path.d.ts.map +0 -1
  178. package/dist/filesystem/workspace-path.js +0 -80
  179. package/dist/filesystem/workspace-path.js.map +0 -1
  180. package/dist/host/filesystem-v2.d.ts +0 -45
  181. package/dist/host/filesystem-v2.d.ts.map +0 -1
  182. package/dist/host/filesystem-v2.js +0 -13
  183. package/dist/host/filesystem-v2.js.map +0 -1
  184. package/dist/host/git.d.ts +0 -200
  185. package/dist/host/git.d.ts.map +0 -1
  186. package/dist/host/git.js +0 -15
  187. package/dist/host/git.js.map +0 -1
  188. package/dist/host/index.d.ts.map +0 -1
  189. package/dist/host/index.js.map +0 -1
  190. package/dist/host/types.d.ts +0 -232
  191. package/dist/host/types.d.ts.map +0 -1
  192. package/dist/host/types.js +0 -10
  193. package/dist/host/types.js.map +0 -1
  194. package/dist/host/wire-policy.d.ts +0 -22
  195. package/dist/host/wire-policy.d.ts.map +0 -1
  196. package/dist/host/wire-policy.js +0 -92
  197. package/dist/host/wire-policy.js.map +0 -1
  198. package/dist/index.d.ts.map +0 -1
  199. package/dist/index.js.map +0 -1
  200. package/dist/mcp/index.d.ts.map +0 -1
  201. package/dist/mcp/index.js.map +0 -1
  202. package/dist/mcp/types.d.ts +0 -466
  203. package/dist/mcp/types.d.ts.map +0 -1
  204. package/dist/mcp/types.js +0 -25
  205. package/dist/mcp/types.js.map +0 -1
  206. package/dist/mcp/wire.d.ts +0 -29
  207. package/dist/mcp/wire.d.ts.map +0 -1
  208. package/dist/mcp/wire.js +0 -1046
  209. package/dist/mcp/wire.js.map +0 -1
  210. package/dist/mcp/zod.d.ts.map +0 -1
  211. package/dist/mcp/zod.js.map +0 -1
  212. package/dist/vscode/index.d.ts.map +0 -1
  213. package/dist/vscode/index.js.map +0 -1
  214. package/dist/vscode/messages.d.ts +0 -204
  215. package/dist/vscode/messages.d.ts.map +0 -1
  216. package/dist/vscode/messages.js +0 -494
  217. package/dist/vscode/messages.js.map +0 -1
  218. package/dist/workspace/index.d.ts.map +0 -1
  219. package/dist/workspace/index.js.map +0 -1
  220. package/dist/workspace/reconcile-electron.d.ts +0 -19
  221. package/dist/workspace/reconcile-electron.d.ts.map +0 -1
  222. package/dist/workspace/reconcile-electron.js +0 -42
  223. package/dist/workspace/reconcile-electron.js.map +0 -1
  224. package/dist/workspace/types.d.ts +0 -69
  225. package/dist/workspace/types.d.ts.map +0 -1
  226. package/dist/workspace/types.js +0 -2
  227. package/dist/workspace/types.js.map +0 -1
  228. package/dist/workspace/workspace-manager.d.ts +0 -47
  229. package/dist/workspace/workspace-manager.d.ts.map +0 -1
  230. package/dist/workspace/workspace-manager.js +0 -126
  231. package/dist/workspace/workspace-manager.js.map +0 -1
  232. package/src/document/document-session.ts +0 -834
  233. package/src/document/filesystem-target.ts +0 -109
  234. package/src/document/index.ts +0 -41
  235. package/src/document/recovery-journal.ts +0 -536
  236. package/src/document/types.ts +0 -116
  237. package/src/filesystem/commit-lock.ts +0 -29
  238. package/src/filesystem/dbk-workspace.ts +0 -135
  239. package/src/filesystem/electron-provider-v2.ts +0 -630
  240. package/src/filesystem/electron-provider.ts +0 -99
  241. package/src/filesystem/electron.ts +0 -3
  242. package/src/filesystem/file-media-provider.ts +0 -103
  243. package/src/filesystem/filesystem-content-container.ts +0 -164
  244. package/src/filesystem/fs-error.ts +0 -234
  245. package/src/filesystem/index.ts +0 -143
  246. package/src/filesystem/indexeddb-content-container.ts +0 -112
  247. package/src/filesystem/indexeddb-provider-v2.ts +0 -1740
  248. package/src/filesystem/indexeddb-provider.ts +0 -171
  249. package/src/filesystem/indexeddb-store.ts +0 -207
  250. package/src/filesystem/indexeddb.ts +0 -12
  251. package/src/filesystem/legacy-v2-adapter.ts +0 -779
  252. package/src/filesystem/memory-provider-v2.ts +0 -896
  253. package/src/filesystem/memory-provider.ts +0 -180
  254. package/src/filesystem/memory.ts +0 -15
  255. package/src/filesystem/move-entry.ts +0 -142
  256. package/src/filesystem/move-error.ts +0 -159
  257. package/src/filesystem/native-provider-v2.ts +0 -1165
  258. package/src/filesystem/native-provider.ts +0 -537
  259. package/src/filesystem/native.ts +0 -16
  260. package/src/filesystem/types.ts +0 -114
  261. package/src/filesystem/v2.ts +0 -231
  262. package/src/filesystem/workspace-path.ts +0 -92
  263. package/src/host/filesystem-v2.ts +0 -104
  264. package/src/host/git.ts +0 -246
  265. package/src/host/index.ts +0 -93
  266. package/src/host/types.ts +0 -274
  267. package/src/host/wire-policy.ts +0 -103
  268. package/src/index.ts +0 -10
  269. package/src/mcp/index.ts +0 -3
  270. package/src/mcp/types.ts +0 -594
  271. package/src/mcp/wire.ts +0 -1280
  272. package/src/mcp/zod.ts +0 -1000
  273. package/src/vscode/index.ts +0 -2
  274. package/src/vscode/messages.ts +0 -704
  275. package/src/workspace/index.ts +0 -17
  276. package/src/workspace/reconcile-electron.ts +0 -65
  277. package/src/workspace/types.ts +0 -67
  278. package/src/workspace/workspace-manager.ts +0 -151
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/document/document-session.ts","../src/document/filesystem-target.ts","../src/document/recovery-journal.ts"],"sourcesContent":["import type {\n DocumentCommitTarget,\n DocumentConflictStrategy,\n DocumentExternalChangeResult,\n DocumentExternalSnapshot,\n DocumentSaveReason,\n DocumentSessionConflict,\n DocumentSessionEditScope,\n DocumentSessionLifecycle,\n DocumentSessionOptions,\n DocumentSessionSnapshot,\n DocumentSessionStatus,\n DocumentSessionTransition,\n} from './types.js';\nimport { isFileSystemMoveStateError } from '../filesystem/move-error.js';\nimport type { DocumentRecoveryJournal } from './recovery-journal.js';\n\ntype SessionListener = () => void;\n\nconst DEFAULT_AUTO_SAVE_RETRY_DELAYS_MS = [1_000, 3_000, 10_000] as const;\n\n/**\n * Raised by a commit target when optimistic external-change verification\n * fails. The session converts it into durable conflict state.\n */\nexport class DocumentCommitConflictError extends Error {\n public readonly externalContent: string | null;\n public readonly externalVersion: string | number | null;\n\n public constructor(\n message: string,\n externalContent: string | null,\n externalVersion: string | number | null = null,\n ) {\n super(message);\n this.name = 'DocumentCommitConflictError';\n this.externalContent = externalContent;\n this.externalVersion = externalVersion;\n }\n}\n\nexport class DocumentSessionConflictError extends Error {\n public readonly conflict: DocumentSessionConflict;\n\n public constructor(conflict: DocumentSessionConflict) {\n super('The document changed outside DocBlocks while local edits were pending.');\n this.name = 'DocumentSessionConflictError';\n this.conflict = conflict;\n }\n}\n\n/**\n * A revisioned, serialized persistence boundary for one active document.\n *\n * Invariants:\n * - only drain() calls target.commit();\n * - at most one commit is in flight;\n * - revisions never decrease, including across target transitions;\n * - destructive operations wait for an in-flight commit and run last;\n * - a target is never changed by a React effect cleanup.\n */\nexport class DocumentSession {\n private readonly autoSaveDelayMs: number;\n private readonly autoSaveRetryDelaysMs: readonly number[];\n private readonly recoveryJournal: DocumentRecoveryJournal | null;\n private readonly listeners = new Set<SessionListener>();\n private autoSaveEnabled: boolean;\n\n private target: DocumentCommitTarget | null = null;\n private content = '';\n private persistedContent: string | null = null;\n private revision = 0;\n private persistedRevision = 0;\n private savingRevision: number | null = null;\n private savingContent: string | null = null;\n private generation = 0;\n private externalSequence = -1;\n private lifecycle: DocumentSessionLifecycle = 'open';\n private frozen = false;\n private error: Error | null = null;\n private conflict: DocumentSessionConflict | null = null;\n\n private autoSaveTimer: ReturnType<typeof setTimeout> | null = null;\n private autoSaveRetryAttempt = 0;\n private drainPromise: Promise<void> | null = null;\n private haltDrain = false;\n private operationTail: Promise<void> = Promise.resolve();\n private snapshot: DocumentSessionSnapshot;\n\n public constructor(options: DocumentSessionOptions = {}) {\n this.autoSaveDelayMs = Math.max(0, options.autoSaveDelayMs ?? 500);\n this.autoSaveEnabled = options.autoSaveEnabled ?? true;\n this.autoSaveRetryDelaysMs = normalizeRetryDelays(\n options.autoSaveRetryDelaysMs ?? DEFAULT_AUTO_SAVE_RETRY_DELAYS_MS,\n );\n this.recoveryJournal = options.recoveryJournal ?? null;\n this.snapshot = this.createSnapshot();\n }\n\n public readonly subscribe = (listener: SessionListener): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n public readonly getSnapshot = (): DocumentSessionSnapshot => this.snapshot;\n\n /** Enable or disable automatic persistence without weakening explicit or lifecycle flushes. */\n public setAutoSaveEnabled(enabled: boolean): void {\n if (this.autoSaveEnabled === enabled) return;\n this.autoSaveEnabled = enabled;\n if (!enabled) {\n this.clearAutoSaveTimer();\n return;\n }\n if (\n this.target &&\n this.lifecycle === 'open' &&\n !this.frozen &&\n !this.conflict &&\n this.persistedRevision < this.revision\n ) {\n this.scheduleAutoSave();\n }\n }\n\n /**\n * Record a complete local snapshot and schedule its persistence.\n * Returns the assigned monotonic revision.\n */\n public edit(content: string, scope: DocumentSessionEditScope): number {\n if (!this.target || this.lifecycle !== 'open' || this.frozen) {\n throw new Error('Cannot edit a document session that is not open.');\n }\n if (scope.targetKey !== this.target.key || scope.generation !== this.generation) {\n throw new Error('Cannot apply an edit from an obsolete document instance.');\n }\n if (content === this.content) return this.revision;\n\n this.content = content;\n this.revision += 1;\n this.error = null;\n this.autoSaveRetryAttempt = 0;\n if (this.conflict) {\n this.conflict = {\n ...this.conflict,\n localContent: content,\n localRevision: this.revision,\n };\n }\n this.writeRecoverySnapshot();\n if (!this.conflict) this.scheduleAutoSave();\n this.emit();\n return this.revision;\n }\n\n /**\n * Persist the revision current when flush() is called. A later edit may\n * advance the session again, but commits remain strictly serialized.\n */\n public async flush(reason: DocumentSaveReason = 'manual'): Promise<DocumentSessionSnapshot> {\n this.clearAutoSaveTimer();\n if (!this.target) return this.snapshot;\n if (this.conflict) throw new DocumentSessionConflictError(this.conflict);\n\n const requiredRevision = this.revision;\n while (this.target && this.persistedRevision < requiredRevision) {\n if (this.conflict) throw new DocumentSessionConflictError(this.conflict);\n if (this.haltDrain) {\n throw new Error('Document persistence was cancelled before the requested revision saved.');\n }\n try {\n await this.ensureDrain(reason);\n } catch (error: unknown) {\n if (this.conflict) throw new DocumentSessionConflictError(this.conflict);\n throw error;\n }\n }\n\n if (this.conflict) throw new DocumentSessionConflictError(this.conflict);\n if (this.persistedRevision < requiredRevision) {\n throw new Error('The document target closed before the requested revision saved.');\n }\n return this.snapshot;\n }\n\n /**\n * Flush the old document, then replace it with a new clean baseline.\n * UI state should change only after this promise resolves.\n */\n public transitionTo(\n target: DocumentCommitTarget | null,\n content: string,\n ): Promise<DocumentSessionSnapshot> {\n return this.enqueueOperation(() =>\n this.performTransition(async () => ({ target, content })).then((snapshot) => {\n if (!snapshot) throw new Error('A fixed document transition cannot be cancelled.');\n return snapshot;\n }),\n );\n }\n\n /**\n * Freeze and flush the current document before reading the next one. The\n * loader may return null when a navigation request was superseded, leaving\n * the current target active and clean.\n */\n public transitionWithLoad(\n load: () => Promise<DocumentSessionTransition | null>,\n ): Promise<DocumentSessionSnapshot | null> {\n return this.enqueueOperation(() => this.performTransition(load));\n }\n\n /**\n * Flush the current path, run the storage move, and only then swap the\n * commit target. No edit can enter between those steps.\n */\n public retarget(\n nextTarget: DocumentCommitTarget,\n moveStorage: () => Promise<void>,\n ): Promise<DocumentSessionSnapshot> {\n return this.enqueueOperation(async () => {\n this.assertNotPreparingClose();\n if (!this.target) throw new Error('Cannot retarget a session without a document.');\n\n this.lifecycle = 'transitioning';\n this.frozen = true;\n this.emit();\n try {\n this.haltDrain = false;\n await this.flush('transition');\n await moveStorage();\n this.generation += 1;\n this.externalSequence = -1;\n this.target = nextTarget;\n this.error = null;\n this.conflict = null;\n this.lifecycle = 'open';\n this.frozen = false;\n this.emit();\n return this.snapshot;\n } catch (error: unknown) {\n if (isFileSystemMoveStateError(error)) {\n if (error.documentLocation === 'destination') {\n this.generation += 1;\n this.externalSequence = -1;\n this.target = nextTarget;\n }\n this.haltDrain = true;\n this.error = error;\n this.lifecycle = 'open';\n // The provider could not establish one authoritative compound move.\n // Keep editing frozen until navigation/recovery chooses a real path.\n this.frozen = true;\n this.emit();\n throw error;\n }\n this.lifecycle = 'open';\n this.frozen = false;\n this.emit();\n throw error;\n }\n });\n }\n\n /**\n * Cancel queued writes, wait for an already-running write, then delete.\n * The deletion is therefore the final storage operation for this target.\n */\n public delete(deleteStorage: () => Promise<void>): Promise<DocumentSessionSnapshot> {\n return this.enqueueOperation(async () => {\n this.assertNotPreparingClose();\n this.lifecycle = 'transitioning';\n this.frozen = true;\n this.haltDrain = true;\n this.clearAutoSaveTimer();\n this.emit();\n\n await this.awaitActiveDrain();\n try {\n await deleteStorage();\n } catch (error: unknown) {\n this.haltDrain = false;\n this.lifecycle = 'open';\n this.frozen = false;\n if (this.target && this.persistedRevision < this.revision && !this.conflict) {\n this.scheduleAutoSave();\n }\n this.emit();\n throw error;\n }\n\n this.discardRecoverySnapshot();\n this.detach();\n return this.snapshot;\n });\n }\n\n /**\n * Discard queued changes and detach without mutating storage. This is used\n * for explicitly abandoned sessions, never as an implicit effect cleanup.\n */\n public cancel(): Promise<DocumentSessionSnapshot> {\n return this.enqueueOperation(async () => {\n this.lifecycle = 'transitioning';\n this.frozen = true;\n this.haltDrain = true;\n this.clearAutoSaveTimer();\n this.emit();\n await this.awaitActiveDrain();\n this.discardRecoverySnapshot();\n this.detach();\n return this.snapshot;\n });\n }\n\n /**\n * Observe a filesystem/host change captured for targetKey. Clean sessions\n * adopt it. Dirty or saving sessions preserve local text and enter conflict.\n */\n public observeExternal(change: DocumentExternalSnapshot): DocumentExternalChangeResult {\n if (!this.target || change.targetKey !== this.target.key || this.lifecycle === 'closed') {\n return 'ignored';\n }\n if (change.sequence !== undefined) {\n if (!Number.isSafeInteger(change.sequence) || change.sequence <= this.externalSequence) {\n return 'ignored';\n }\n this.externalSequence = change.sequence;\n }\n\n // While conflicted, a current observation equal to the latest local\n // snapshot proves that revision durable without requiring another write.\n // Never acknowledge while a commit is still running; its eventual result\n // remains authoritative for the serialized drain.\n if (\n this.conflict &&\n change.content === this.content &&\n this.savingRevision === null &&\n this.lifecycle === 'open'\n ) {\n this.clearAutoSaveTimer();\n this.autoSaveRetryAttempt = 0;\n this.persistedRevision = this.revision;\n this.persistedContent = this.content;\n this.haltDrain = false;\n this.error = null;\n this.conflict = null;\n this.discardRecoverySnapshot();\n this.emit();\n return 'applied';\n }\n\n // Once a conflict exists, every later accepted observation refreshes its\n // external branch before ordinary duplicate suppression. In particular,\n // A -> local C -> external B -> external A must offer A, not stale B, when\n // the user chooses Reload external.\n if (this.conflict) {\n const externalVersion = change.version ?? null;\n if (\n this.conflict.localContent === this.content &&\n this.conflict.localRevision === this.revision &&\n this.conflict.externalContent === change.content &&\n this.conflict.externalVersion === externalVersion\n ) {\n return 'ignored';\n }\n\n this.clearAutoSaveTimer();\n this.haltDrain = true;\n this.conflict = {\n targetKey: change.targetKey,\n localContent: this.content,\n localRevision: this.revision,\n externalContent: change.content,\n externalVersion,\n };\n this.error = null;\n this.writeRecoverySnapshot();\n this.emit();\n return 'conflict';\n }\n\n if (\n change.content === this.content ||\n change.content === this.persistedContent ||\n (this.savingRevision !== null && change.content === this.savingContent)\n ) {\n return 'ignored';\n }\n\n const isClean =\n this.persistedRevision === this.revision &&\n this.savingRevision === null &&\n this.error === null &&\n this.conflict === null;\n\n if (isClean && change.content !== null) {\n this.content = change.content;\n this.revision += 1;\n this.persistedRevision = this.revision;\n this.persistedContent = change.content;\n this.generation += 1;\n this.discardRecoverySnapshot();\n this.emit();\n return 'applied';\n }\n\n this.clearAutoSaveTimer();\n this.haltDrain = true;\n this.conflict = {\n targetKey: change.targetKey,\n localContent: this.content,\n localRevision: this.revision,\n externalContent: change.content,\n externalVersion: change.version ?? null,\n };\n this.error = null;\n this.writeRecoverySnapshot();\n this.emit();\n return 'conflict';\n }\n\n public resolveConflict(strategy: DocumentConflictStrategy): Promise<DocumentSessionSnapshot> {\n return this.enqueueOperation(async () => {\n if (!this.conflict) return this.snapshot;\n\n this.clearAutoSaveTimer();\n this.haltDrain = true;\n await this.awaitActiveDrain();\n // A watcher may refresh or converge the conflict while an in-flight\n // commit settles. Resolve the branch that is current now, never the\n // snapshot captured before the await.\n const currentConflict = this.conflict;\n if (!currentConflict) return this.snapshot;\n\n if (strategy === 'use-external') {\n this.discardRecoverySnapshot();\n this.generation += 1;\n this.revision += 1;\n this.conflict = null;\n this.error = null;\n this.haltDrain = false;\n\n if (currentConflict.externalContent === null) {\n this.target = null;\n this.content = '';\n this.persistedContent = null;\n this.persistedRevision = this.revision;\n this.lifecycle = 'closed';\n this.frozen = true;\n } else {\n this.content = currentConflict.externalContent;\n this.persistedContent = currentConflict.externalContent;\n this.persistedRevision = this.revision;\n this.lifecycle = 'open';\n this.frozen = false;\n }\n this.emit();\n return this.snapshot;\n }\n\n // Keep the local branch, but make the observed external snapshot the\n // optimistic baseline for the next conditional commit.\n this.persistedContent = currentConflict.externalContent;\n // A clean external deletion/conflict has no unsaved local revision.\n // Keeping local still requires a fresh commit that recreates/overwrites\n // the target, so make that intent explicit with a new revision.\n this.revision += 1;\n this.conflict = null;\n this.error = null;\n this.haltDrain = false;\n this.lifecycle = 'open';\n this.frozen = false;\n this.writeRecoverySnapshot();\n this.emit();\n return this.flush('conflict');\n });\n }\n\n /**\n * Freeze edits and flush through the latest revision. A successful call\n * remains frozen until cancelClose(); the owning host may now destroy it.\n */\n public prepareClose(): Promise<DocumentSessionSnapshot> {\n return this.enqueueOperation(async () => {\n if (this.lifecycle === 'closing') return this.snapshot;\n this.lifecycle = 'closing';\n this.frozen = true;\n this.haltDrain = false;\n this.emit();\n try {\n await this.flush('close');\n return this.snapshot;\n } catch (error: unknown) {\n this.lifecycle = 'open';\n this.frozen = false;\n this.emit();\n throw error;\n }\n });\n }\n\n /** Resume editing when a host cancels a prepared close. */\n public cancelClose(): void {\n if (this.lifecycle !== 'closing') return;\n this.lifecycle = 'open';\n this.frozen = false;\n this.haltDrain = false;\n if (this.target && this.persistedRevision < this.revision && !this.conflict) {\n this.scheduleAutoSave();\n }\n this.emit();\n }\n\n private async performTransition(\n load: () => Promise<DocumentSessionTransition | null>,\n ): Promise<DocumentSessionSnapshot | null> {\n this.assertNotPreparingClose();\n this.lifecycle = 'transitioning';\n this.frozen = true;\n this.emit();\n\n try {\n this.haltDrain = false;\n await this.flush('transition');\n this.clearAutoSaveTimer();\n const next = await load();\n if (!next) {\n this.lifecycle = 'open';\n this.frozen = false;\n this.emit();\n return null;\n }\n\n this.generation += 1;\n this.externalSequence = -1;\n this.target = next.target;\n this.content = next.content;\n this.revision += 1;\n this.persistedRevision = this.revision;\n this.persistedContent = next.target ? next.content : null;\n this.savingRevision = null;\n this.savingContent = null;\n this.error = null;\n this.conflict = null;\n this.haltDrain = false;\n this.lifecycle = 'open';\n this.frozen = false;\n const recoveryState = this.restoreRecoverySnapshot();\n if (recoveryState === 'dirty') this.scheduleAutoSave();\n this.emit();\n return this.snapshot;\n } catch (error: unknown) {\n this.lifecycle = 'open';\n this.frozen = false;\n this.emit();\n throw error;\n }\n }\n\n private scheduleAutoSave(delayMs = this.autoSaveDelayMs): void {\n this.clearAutoSaveTimer();\n if (!this.autoSaveEnabled) return;\n this.autoSaveTimer = setTimeout(() => {\n this.autoSaveTimer = null;\n const target = this.target;\n const generation = this.generation;\n void this.flush('autosave').then(\n () => {\n this.autoSaveRetryAttempt = 0;\n },\n () => {\n // Preserve honest error/conflict state while making ordinary I/O\n // failures recoverable. A newer edit already owns a fresh debounce\n // timer, and lifecycle operations cancel this retry path.\n if (\n this.autoSaveTimer !== null ||\n !target ||\n target !== this.target ||\n generation !== this.generation ||\n this.lifecycle !== 'open' ||\n this.frozen ||\n this.haltDrain ||\n this.conflict ||\n this.persistedRevision >= this.revision\n ) {\n return;\n }\n const retryDelay = this.autoSaveRetryDelaysMs[this.autoSaveRetryAttempt];\n if (retryDelay === undefined) return;\n this.autoSaveRetryAttempt += 1;\n this.scheduleAutoSave(retryDelay);\n },\n );\n }, delayMs);\n }\n\n private clearAutoSaveTimer(): void {\n if (this.autoSaveTimer === null) return;\n clearTimeout(this.autoSaveTimer);\n this.autoSaveTimer = null;\n }\n\n private ensureDrain(reason: DocumentSaveReason): Promise<void> {\n if (this.drainPromise) return this.drainPromise;\n const running = this.drain(reason);\n this.drainPromise = running;\n const clear = () => {\n if (this.drainPromise === running) this.drainPromise = null;\n };\n void running.then(clear, clear);\n return running;\n }\n\n private async drain(reason: DocumentSaveReason): Promise<void> {\n while (\n this.target &&\n !this.haltDrain &&\n !this.conflict &&\n this.persistedRevision < this.revision\n ) {\n const target = this.target;\n const generation = this.generation;\n const saveRevision = this.revision;\n const saveContent = this.content;\n const previousPersistedRevision = this.persistedRevision;\n const previousPersistedContent = this.persistedContent;\n\n this.savingRevision = saveRevision;\n this.savingContent = saveContent;\n this.error = null;\n this.emit();\n\n try {\n await target.commit({\n targetKey: target.key,\n content: saveContent,\n revision: saveRevision,\n persistedRevision: previousPersistedRevision,\n persistedContent: previousPersistedContent,\n reason,\n });\n } catch (error: unknown) {\n this.savingRevision = null;\n this.savingContent = null;\n if (error instanceof DocumentCommitConflictError) {\n this.haltDrain = true;\n this.conflict = {\n targetKey: target.key,\n localContent: this.content,\n localRevision: this.revision,\n externalContent: error.externalContent,\n externalVersion: error.externalVersion,\n };\n this.error = null;\n } else {\n this.error = toError(error);\n }\n this.emit();\n throw error;\n }\n\n if (generation !== this.generation || target !== this.target) return;\n this.persistedRevision = Math.max(this.persistedRevision, saveRevision);\n this.persistedContent = saveContent;\n this.autoSaveRetryAttempt = 0;\n this.savingRevision = null;\n this.savingContent = null;\n this.error = null;\n const activeConflict = this.getSnapshot().conflict;\n if (activeConflict?.externalContent === saveContent && this.content === saveContent) {\n // An observation that matched the in-flight local snapshot could not\n // be acknowledged until the commit settled. Its successful return now\n // proves both branches converged on the same durable revision.\n this.conflict = null;\n this.haltDrain = false;\n }\n this.recoveryJournal?.acknowledge({\n targetKey: target.key,\n generation,\n persistedRevision: this.persistedRevision,\n });\n this.emit();\n }\n }\n\n private async awaitActiveDrain(): Promise<void> {\n const active = this.drainPromise;\n if (!active) return;\n try {\n await active;\n } catch {\n // A destructive cancellation still waits for the operation to settle,\n // but a failed obsolete write must not prevent the requested deletion.\n }\n }\n\n /**\n * Rehydrate a synchronous crash snapshot after the durable baseline has\n * been read. A matching baseline is safe to resume as dirty; a changed\n * baseline becomes an explicit conflict and is never auto-overwritten.\n */\n private restoreRecoverySnapshot(): 'none' | 'dirty' | 'conflict' {\n if (!this.target || !this.recoveryJournal) return 'none';\n const recovered = this.recoveryJournal.lookup(this.target.key);\n if (!recovered) return 'none';\n\n if (recovered.content === this.content) {\n this.recoveryJournal.acknowledge({\n targetKey: recovered.targetKey,\n generation: recovered.generation,\n persistedRevision: recovered.revision,\n });\n return 'none';\n }\n\n const externalContent = this.content;\n this.generation = Math.max(this.generation, recovered.generation) + 1;\n this.revision = Math.max(this.revision, recovered.revision) + 1;\n this.content = recovered.content;\n\n if (recovered.persistedContent === externalContent) {\n this.writeRecoverySnapshot();\n return 'dirty';\n }\n\n // Preserve the journal's prior baseline so a second crash continues to\n // reopen as a conflict until the user explicitly chooses a branch.\n this.persistedContent = recovered.persistedContent;\n this.haltDrain = true;\n this.conflict = {\n targetKey: this.target.key,\n localContent: recovered.content,\n localRevision: this.revision,\n externalContent,\n externalVersion: null,\n };\n this.writeRecoverySnapshot();\n return 'conflict';\n }\n\n private writeRecoverySnapshot(): void {\n if (!this.target || !this.recoveryJournal) return;\n if (this.persistedRevision >= this.revision && !this.conflict) return;\n this.recoveryJournal.write({\n targetKey: this.target.key,\n generation: this.generation,\n revision: this.revision,\n content: this.content,\n persistedContent: this.persistedContent,\n });\n }\n\n private discardRecoverySnapshot(): void {\n if (!this.target) return;\n this.recoveryJournal?.discard(this.target.key);\n }\n\n private detach(): void {\n this.clearAutoSaveTimer();\n this.autoSaveRetryAttempt = 0;\n this.generation += 1;\n this.externalSequence = -1;\n this.target = null;\n this.persistedContent = null;\n this.savingRevision = null;\n this.savingContent = null;\n this.error = null;\n this.conflict = null;\n this.haltDrain = false;\n this.lifecycle = 'closed';\n this.frozen = true;\n this.emit();\n }\n\n private assertNotPreparingClose(): void {\n if (this.lifecycle === 'closing') {\n throw new Error('The document is already prepared for close.');\n }\n }\n\n private enqueueOperation<T>(operation: () => Promise<T>): Promise<T> {\n const run = this.operationTail.then(operation, operation);\n this.operationTail = run.then(\n () => undefined,\n () => undefined,\n );\n return run;\n }\n\n private createSnapshot(): DocumentSessionSnapshot {\n return Object.freeze({\n targetKey: this.target?.key ?? null,\n content: this.content,\n revision: this.revision,\n persistedRevision: this.persistedRevision,\n persistedContent: this.persistedContent,\n savingRevision: this.savingRevision,\n generation: this.generation,\n status: this.computeStatus(),\n lifecycle: this.lifecycle,\n frozen: this.frozen,\n error: this.error,\n conflict: this.conflict,\n });\n }\n\n private computeStatus(): DocumentSessionStatus {\n if (this.lifecycle === 'closed') return 'closed';\n if (!this.target) return 'idle';\n if (this.conflict) return 'conflict';\n if (this.error) return 'error';\n if (this.savingRevision !== null) return 'saving';\n return this.persistedRevision < this.revision ? 'dirty' : 'saved';\n }\n\n private emit(): void {\n this.snapshot = this.createSnapshot();\n for (const listener of [...this.listeners]) listener();\n }\n}\n\nfunction toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\nfunction normalizeRetryDelays(delays: readonly number[]): readonly number[] {\n return delays.map((delay) => {\n if (!Number.isFinite(delay) || delay < 0) {\n throw new TypeError('Autosave retry delays must be finite, non-negative numbers.');\n }\n return Math.floor(delay);\n });\n}\n","import { getFileSystemProviderV2, type FileSystemProvider } from '../filesystem/types.js';\nimport { FsError } from '../filesystem/fs-error.js';\nimport { parseWorkspacePath } from '../filesystem/workspace-path.js';\nimport { DocumentCommitConflictError } from './document-session.js';\nimport type { DocumentCommitTarget, DocumentExternalVersion } from './types.js';\n\nexport interface FileSystemDocumentTargetOptions {\n /**\n * Compare the current file with the session's persisted baseline before\n * replacing it. Enabled by default.\n */\n verifyExternalChanges?: boolean;\n onCommitted?: (content: string, revision: number) => void;\n}\n\n/**\n * Adapt a FileSystemProvider path to the commit protocol used by\n * DocumentSession. The optimistic read catches external edits/deletions\n * before a local write recreates or silently replaces them.\n */\nexport function createFileSystemDocumentTarget(\n provider: FileSystemProvider,\n path: string,\n options: FileSystemDocumentTargetOptions = {},\n): DocumentCommitTarget {\n const verifyExternalChanges = options.verifyExternalChanges ?? true;\n const canonicalPath = parseWorkspacePath(path);\n const providerV2 = getFileSystemProviderV2(provider);\n return {\n key: provider.id + ':' + canonicalPath,\n async commit(request) {\n if (providerV2 && providerV2.capabilities.conditionalWrite !== 'none') {\n const current = await providerV2.readFile(canonicalPath);\n const currentContent = current ? new TextDecoder().decode(current.data) : null;\n if (currentContent !== request.persistedContent && currentContent !== request.content) {\n throw new DocumentCommitConflictError(\n 'The document changed outside DocBlocks: ' + path,\n currentContent,\n current?.entry.version ?? null,\n );\n }\n if (currentContent === request.content) {\n options.onCommitted?.(request.content, request.revision);\n return { version: current?.entry.version ?? null };\n }\n\n try {\n const committed = await providerV2.writeFile(\n canonicalPath,\n new TextEncoder().encode(request.content),\n {\n mode: current ? 'replace' : 'create',\n createParents: true,\n expectedVersion: current?.entry.version ?? null,\n },\n );\n options.onCommitted?.(request.content, request.revision);\n return { version: committed.version };\n } catch (error: unknown) {\n if (\n error instanceof FsError &&\n (error.code === 'conflict' ||\n error.code === 'already-exists' ||\n error.code === 'not-found')\n ) {\n const external = await providerV2.readFile(canonicalPath);\n throw new DocumentCommitConflictError(\n 'The document changed outside DocBlocks: ' + path,\n external ? new TextDecoder().decode(external.data) : null,\n external?.entry.version ?? null,\n );\n }\n throw error;\n }\n }\n\n if (provider.commitFile) {\n const result = await provider.commitFile(path, request.content, request.persistedContent);\n if (result.status === 'conflict') {\n throw new DocumentCommitConflictError(\n 'The document changed outside DocBlocks: ' + path,\n result.content,\n result.version,\n );\n }\n options.onCommitted?.(request.content, request.revision);\n return { version: result.version };\n }\n\n if (verifyExternalChanges) {\n const current = await provider.readFile(path);\n if (current !== request.persistedContent && current !== request.content) {\n const meta = await provider.stat(path).catch(() => null);\n const version: DocumentExternalVersion = meta?.lastModified ?? null;\n throw new DocumentCommitConflictError(\n 'The document changed outside DocBlocks: ' + path,\n current,\n version,\n );\n }\n }\n\n await provider.writeFile(path, request.content);\n options.onCommitted?.(request.content, request.revision);\n const meta = await provider.stat(path).catch(() => null);\n return { version: meta?.lastModified ?? null };\n },\n };\n}\n","/**\n * Synchronous crash-recovery journal for dirty document snapshots.\n *\n * The journal deliberately depends on a tiny injected Storage-like contract\n * instead of reading `window.localStorage` at module load time. This keeps the\n * document package usable in Node, Electron main, VS Code extension hosts, and\n * tests while allowing browser renderers to use localStorage for a best-effort\n * write that completes before the current JavaScript turn ends.\n */\n\nexport const DOCUMENT_RECOVERY_JOURNAL_STORAGE_KEY = 'docblocks:document-recovery:v1';\nexport const DOCUMENT_RECOVERY_JOURNAL_SCHEMA_VERSION = 1;\n\nexport interface DocumentRecoveryStorage {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\nexport interface DocumentRecoveryRecord {\n /** Stable commit-target key, including the workspace/provider scope. */\n targetKey: string;\n /** DocumentSession generation that produced this snapshot. */\n generation: number;\n /** Monotonic DocumentSession revision represented by `content`. */\n revision: number;\n /** Complete markdown snapshot. */\n content: string;\n /**\n * Content last acknowledged by the commit target when this draft was made.\n * Recovery may be applied automatically only when storage still matches this\n * baseline; otherwise the caller must surface an external-change conflict.\n */\n persistedContent: string | null;\n /** Time the dirty record for this target was first created. */\n createdAt: number;\n /** Time the record was most recently replaced. */\n updatedAt: number;\n}\n\nexport interface DocumentRecoveryWrite {\n targetKey: string;\n generation: number;\n revision: number;\n content: string;\n persistedContent: string | null;\n}\n\nexport interface DocumentRecoveryAcknowledgement {\n targetKey: string;\n generation: number;\n /** Highest revision durably acknowledged by the commit target. */\n persistedRevision: number;\n}\n\nexport type DocumentRecoveryWriteFailure =\n | 'invalid-record'\n | 'record-too-large'\n | 'storage-unavailable'\n | 'quota-exceeded';\n\nexport type DocumentRecoveryWriteResult =\n | { status: 'stored'; evicted: number }\n | { status: 'unchanged'; evicted: 0 }\n | { status: 'ignored-stale'; evicted: 0 }\n | { status: 'rejected'; reason: DocumentRecoveryWriteFailure; evicted: number };\n\nexport interface DocumentRecoveryJournalOptions {\n storageKey?: string;\n /** Maximum number of document records retained. Defaults to 20. */\n maxEntries?: number;\n /** Conservative UTF-16 estimate for the whole serialized journal. */\n maxStorageBytes?: number;\n /** Conservative UTF-16 estimate for one serialized record. */\n maxRecordBytes?: number;\n /** Records older than this are discarded while reading. Defaults to 7 days. */\n maxAgeMs?: number;\n /** Tolerated clock skew for records dated in the future. Defaults to 5 minutes. */\n maxFutureSkewMs?: number;\n /** Injected for deterministic tests. */\n now?: () => number;\n}\n\ninterface DocumentRecoveryEnvelope {\n schemaVersion: typeof DOCUMENT_RECOVERY_JOURNAL_SCHEMA_VERSION;\n records: DocumentRecoveryRecord[];\n}\n\ninterface LoadedRecords {\n records: DocumentRecoveryRecord[];\n needsRepair: boolean;\n}\n\ninterface PersistResult {\n stored: boolean;\n evicted: number;\n reason?: 'storage-unavailable' | 'quota-exceeded';\n}\n\nconst DEFAULT_MAX_ENTRIES = 20;\nconst DEFAULT_MAX_STORAGE_BYTES = 2_000_000;\nconst DEFAULT_MAX_RECORD_BYTES = 1_000_000;\nconst DEFAULT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;\nconst DEFAULT_MAX_FUTURE_SKEW_MS = 5 * 60 * 1000;\nconst MAX_TARGET_KEY_LENGTH = 4096;\n\n/**\n * Best-effort, synchronous recovery storage.\n *\n * Normal save acknowledgement is the only automatic path that removes the\n * current record. Explicit discard, age expiry, corruption repair, and bounded\n * eviction are intentional exceptions: callers can discard after the user\n * rejects recovery, and the journal must never grow without limit.\n */\nexport class DocumentRecoveryJournal {\n private readonly storage: DocumentRecoveryStorage | null;\n private readonly storageKey: string;\n private readonly maxEntries: number;\n private readonly maxStorageBytes: number;\n private readonly maxRecordBytes: number;\n private readonly maxAgeMs: number;\n private readonly maxFutureSkewMs: number;\n private readonly now: () => number;\n\n public constructor(\n storage: DocumentRecoveryStorage | null,\n options: DocumentRecoveryJournalOptions = {},\n ) {\n this.storage = storage;\n this.storageKey = options.storageKey?.trim() || DOCUMENT_RECOVERY_JOURNAL_STORAGE_KEY;\n this.maxEntries = positiveInteger(options.maxEntries, DEFAULT_MAX_ENTRIES);\n this.maxStorageBytes = positiveInteger(options.maxStorageBytes, DEFAULT_MAX_STORAGE_BYTES);\n this.maxRecordBytes = Math.min(\n positiveInteger(options.maxRecordBytes, DEFAULT_MAX_RECORD_BYTES),\n this.maxStorageBytes,\n );\n this.maxAgeMs = nonNegativeFinite(options.maxAgeMs, DEFAULT_MAX_AGE_MS);\n this.maxFutureSkewMs = nonNegativeFinite(options.maxFutureSkewMs, DEFAULT_MAX_FUTURE_SKEW_MS);\n this.now = options.now ?? Date.now;\n }\n\n /**\n * Synchronously persist the latest dirty snapshot for a target.\n * Storage/quota failures are returned, never thrown into an editor onChange.\n */\n public write(input: DocumentRecoveryWrite): DocumentRecoveryWriteResult {\n const timestamp = this.now();\n if (!isValidWrite(input) || !Number.isFinite(timestamp) || timestamp < 0) {\n return { status: 'rejected', reason: 'invalid-record', evicted: 0 };\n }\n if (!this.storage) {\n return { status: 'rejected', reason: 'storage-unavailable', evicted: 0 };\n }\n if (\n estimatedBytes(input.content) > this.maxRecordBytes ||\n (input.persistedContent !== null &&\n estimatedBytes(input.persistedContent) > this.maxRecordBytes)\n ) {\n return { status: 'rejected', reason: 'record-too-large', evicted: 0 };\n }\n\n const loaded = this.load(timestamp);\n const existing = loaded.records.find((record) => record.targetKey === input.targetKey);\n if (existing) {\n const ordering = compareGenerationRevision(input, existing);\n if (ordering < 0) return { status: 'ignored-stale', evicted: 0 };\n if (ordering === 0) {\n if (\n existing.content === input.content &&\n existing.persistedContent === input.persistedContent\n ) {\n return { status: 'unchanged', evicted: 0 };\n }\n // A revision is an immutable content snapshot. Reusing it for different\n // content would make acknowledgement and recovery ambiguous.\n return { status: 'rejected', reason: 'invalid-record', evicted: 0 };\n }\n }\n\n const candidate: DocumentRecoveryRecord = {\n targetKey: input.targetKey,\n generation: input.generation,\n revision: input.revision,\n content: input.content,\n persistedContent: input.persistedContent,\n createdAt: existing?.createdAt ?? timestamp,\n updatedAt: timestamp,\n };\n if (estimatedBytes(JSON.stringify(candidate)) > this.maxRecordBytes) {\n return { status: 'rejected', reason: 'record-too-large', evicted: 0 };\n }\n if (estimatedBytes(serializeEnvelope([candidate])) > this.maxStorageBytes) {\n return { status: 'rejected', reason: 'record-too-large', evicted: 0 };\n }\n\n const next = loaded.records.filter((record) => record.targetKey !== input.targetKey);\n next.push(candidate);\n const persisted = this.persistBounded(next, input.targetKey);\n if (!persisted.stored) {\n return {\n status: 'rejected',\n reason: persisted.reason ?? 'quota-exceeded',\n evicted: persisted.evicted,\n };\n }\n return { status: 'stored', evicted: persisted.evicted };\n }\n\n /** Return the recoverable snapshot for one target, if present and valid. */\n public lookup(targetKey: string, generation?: number): DocumentRecoveryRecord | null {\n if (!isValidTargetKey(targetKey) || !isOptionalGeneration(generation)) return null;\n const record = this.load(this.now()).records.find(\n (candidate) =>\n candidate.targetKey === targetKey &&\n (generation === undefined || candidate.generation === generation),\n );\n return record ? cloneRecord(record) : null;\n }\n\n /** List valid records, newest first. Optionally restrict to one target. */\n public list(targetKey?: string): DocumentRecoveryRecord[] {\n if (targetKey !== undefined && !isValidTargetKey(targetKey)) return [];\n return this.load(this.now())\n .records.filter((record) => targetKey === undefined || record.targetKey === targetKey)\n .sort(compareNewestFirst)\n .map(cloneRecord);\n }\n\n /**\n * Clear a record only when the same generation has durably acknowledged at\n * least the journaled revision. A stale acknowledgement cannot erase a newer\n * crash-recovery snapshot.\n */\n public acknowledge(input: DocumentRecoveryAcknowledgement): boolean {\n if (!isValidAcknowledgement(input) || !this.storage) return false;\n const records = this.load(this.now()).records;\n const record = records.find((candidate) => candidate.targetKey === input.targetKey);\n if (\n !record ||\n record.generation !== input.generation ||\n record.revision > input.persistedRevision\n ) {\n return false;\n }\n\n return this.persistExact(records.filter((candidate) => candidate !== record));\n }\n\n /** Explicitly discard recovery data after a user or lifecycle decision. */\n public discard(targetKey: string, generation?: number): boolean {\n if (!isValidTargetKey(targetKey) || !isOptionalGeneration(generation) || !this.storage) {\n return false;\n }\n const records = this.load(this.now()).records;\n const next = records.filter(\n (record) =>\n record.targetKey !== targetKey ||\n (generation !== undefined && record.generation !== generation),\n );\n if (next.length === records.length) return false;\n return this.persistExact(next);\n }\n\n private load(timestamp: number): LoadedRecords {\n if (!this.storage) return { records: [], needsRepair: false };\n\n let raw: string | null;\n try {\n raw = this.storage.getItem(this.storageKey);\n } catch {\n return { records: [], needsRepair: false };\n }\n if (raw === null) return { records: [], needsRepair: false };\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw) as unknown;\n } catch {\n this.tryRemove();\n return { records: [], needsRepair: true };\n }\n if (!isEnvelope(parsed)) {\n this.tryRemove();\n return { records: [], needsRepair: true };\n }\n\n const byTarget = new Map<string, DocumentRecoveryRecord>();\n let needsRepair = estimatedBytes(raw) > this.maxStorageBytes;\n for (const candidate of parsed.records) {\n if (!isValidStoredRecord(candidate, timestamp, this.maxAgeMs, this.maxFutureSkewMs)) {\n needsRepair = true;\n continue;\n }\n if (estimatedBytes(JSON.stringify(candidate)) > this.maxRecordBytes) {\n needsRepair = true;\n continue;\n }\n const current = byTarget.get(candidate.targetKey);\n if (!current || compareStoredRecords(candidate, current) > 0) {\n if (current) needsRepair = true;\n byTarget.set(candidate.targetKey, cloneRecord(candidate));\n } else {\n needsRepair = true;\n }\n }\n\n const records = [...byTarget.values()].sort(compareNewestFirst);\n while (records.length > this.maxEntries) {\n records.pop();\n needsRepair = true;\n }\n while (\n records.length > 0 &&\n estimatedBytes(serializeEnvelope(records)) > this.maxStorageBytes\n ) {\n records.pop();\n needsRepair = true;\n }\n if (needsRepair) {\n // Best effort only. Read APIs must still return the validated in-memory\n // records even when storage is temporarily unavailable.\n this.persistBounded(records);\n }\n return { records, needsRepair };\n }\n\n private persistBounded(\n records: DocumentRecoveryRecord[],\n protectedTarget?: string,\n ): PersistResult {\n if (!this.storage) {\n return { stored: false, evicted: 0, reason: 'storage-unavailable' };\n }\n\n const next = [...records].sort(compareNewestFirst);\n let evicted = 0;\n while (next.length > this.maxEntries) {\n if (!evictOldest(next, protectedTarget)) break;\n evicted += 1;\n }\n\n let serialized = serializeEnvelope(next);\n while (estimatedBytes(serialized) > this.maxStorageBytes) {\n if (!evictOldest(next, protectedTarget)) {\n return { stored: false, evicted, reason: 'quota-exceeded' };\n }\n evicted += 1;\n serialized = serializeEnvelope(next);\n }\n\n for (;;) {\n try {\n this.storage.setItem(this.storageKey, serialized);\n return { stored: true, evicted };\n } catch {\n if (!evictOldest(next, protectedTarget)) {\n return { stored: false, evicted, reason: 'quota-exceeded' };\n }\n evicted += 1;\n serialized = serializeEnvelope(next);\n }\n }\n }\n\n private persistExact(records: DocumentRecoveryRecord[]): boolean {\n if (!this.storage) return false;\n if (records.length === 0) {\n try {\n this.storage.removeItem(this.storageKey);\n return true;\n } catch {\n return false;\n }\n }\n try {\n this.storage.setItem(this.storageKey, serializeEnvelope(records));\n return true;\n } catch {\n return false;\n }\n }\n\n private tryRemove(): void {\n try {\n this.storage?.removeItem(this.storageKey);\n } catch {\n // Recovery is best effort; a denied cleanup must not fail application startup.\n }\n }\n}\n\n/**\n * Resolve browser localStorage on demand. Importing this module never touches\n * browser globals, and access errors (sandboxing/security settings) yield null.\n */\nexport function getDefaultDocumentRecoveryStorage(): DocumentRecoveryStorage | null {\n try {\n const candidate = Reflect.get(globalThis, 'localStorage') as unknown;\n if (!isStorage(candidate)) return null;\n return candidate;\n } catch {\n return null;\n }\n}\n\nfunction serializeEnvelope(records: DocumentRecoveryRecord[]): string {\n const envelope: DocumentRecoveryEnvelope = {\n schemaVersion: DOCUMENT_RECOVERY_JOURNAL_SCHEMA_VERSION,\n records,\n };\n return JSON.stringify(envelope);\n}\n\n/** localStorage quotas are commonly measured from UTF-16 storage usage. */\nfunction estimatedBytes(value: string): number {\n return value.length * 2;\n}\n\nfunction positiveInteger(value: number | undefined, fallback: number): number {\n return Number.isSafeInteger(value) && (value ?? 0) > 0 ? (value as number) : fallback;\n}\n\nfunction nonNegativeFinite(value: number | undefined, fallback: number): number {\n return Number.isFinite(value) && (value ?? -1) >= 0 ? (value as number) : fallback;\n}\n\nfunction isEnvelope(value: unknown): value is DocumentRecoveryEnvelope {\n if (!isObject(value)) return false;\n return (\n value.schemaVersion === DOCUMENT_RECOVERY_JOURNAL_SCHEMA_VERSION && Array.isArray(value.records)\n );\n}\n\nfunction isValidStoredRecord(\n value: unknown,\n timestamp: number,\n maxAgeMs: number,\n maxFutureSkewMs: number,\n): value is DocumentRecoveryRecord {\n if (!isObject(value)) return false;\n if (\n !isValidTargetKey(value.targetKey) ||\n !isNonNegativeSafeInteger(value.generation) ||\n !isNonNegativeSafeInteger(value.revision) ||\n typeof value.content !== 'string' ||\n (value.persistedContent !== null && typeof value.persistedContent !== 'string') ||\n !isNonNegativeFiniteNumber(value.createdAt) ||\n !isNonNegativeFiniteNumber(value.updatedAt) ||\n value.createdAt > value.updatedAt\n ) {\n return false;\n }\n if (!Number.isFinite(timestamp) || timestamp < 0) return false;\n if (value.updatedAt > timestamp + maxFutureSkewMs) return false;\n return timestamp - value.updatedAt <= maxAgeMs;\n}\n\nfunction isValidWrite(value: DocumentRecoveryWrite): boolean {\n return (\n isValidTargetKey(value.targetKey) &&\n isNonNegativeSafeInteger(value.generation) &&\n isNonNegativeSafeInteger(value.revision) &&\n typeof value.content === 'string' &&\n (value.persistedContent === null || typeof value.persistedContent === 'string')\n );\n}\n\nfunction isValidAcknowledgement(value: DocumentRecoveryAcknowledgement): boolean {\n return (\n isValidTargetKey(value.targetKey) &&\n isNonNegativeSafeInteger(value.generation) &&\n isNonNegativeSafeInteger(value.persistedRevision)\n );\n}\n\nfunction isValidTargetKey(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0 && value.length <= MAX_TARGET_KEY_LENGTH;\n}\n\nfunction isOptionalGeneration(value: number | undefined): boolean {\n return value === undefined || isNonNegativeSafeInteger(value);\n}\n\nfunction isNonNegativeSafeInteger(value: unknown): value is number {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction isNonNegativeFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isStorage(value: unknown): value is DocumentRecoveryStorage {\n if (!isObject(value)) return false;\n return (\n typeof value.getItem === 'function' &&\n typeof value.setItem === 'function' &&\n typeof value.removeItem === 'function'\n );\n}\n\nfunction compareGenerationRevision(\n left: Pick<DocumentRecoveryRecord, 'generation' | 'revision'>,\n right: Pick<DocumentRecoveryRecord, 'generation' | 'revision'>,\n): number {\n if (left.generation !== right.generation) return left.generation - right.generation;\n return left.revision - right.revision;\n}\n\nfunction compareStoredRecords(left: DocumentRecoveryRecord, right: DocumentRecoveryRecord): number {\n return compareGenerationRevision(left, right) || left.updatedAt - right.updatedAt;\n}\n\nfunction compareNewestFirst(left: DocumentRecoveryRecord, right: DocumentRecoveryRecord): number {\n return right.updatedAt - left.updatedAt || right.revision - left.revision;\n}\n\nfunction cloneRecord(record: DocumentRecoveryRecord): DocumentRecoveryRecord {\n return { ...record };\n}\n\nfunction evictOldest(records: DocumentRecoveryRecord[], protectedTarget?: string): boolean {\n let oldestIndex = -1;\n for (let index = 0; index < records.length; index += 1) {\n if (records[index].targetKey === protectedTarget) continue;\n if (oldestIndex < 0 || compareNewestFirst(records[index], records[oldestIndex]) > 0) {\n oldestIndex = index;\n }\n }\n if (oldestIndex < 0) return false;\n records.splice(oldestIndex, 1);\n return true;\n}\n"],"mappings":"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","names":["meta"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/filesystem/memory-provider-v2.ts","../src/filesystem/memory-provider.ts"],"sourcesContent":["import { FsError, type FsOperation } from './fs-error.js';\nimport type { FileCommitResult } from './types.js';\nimport {\n parseFileSystemVersion,\n type FileSystemCreateDirectoryOptions,\n type FileSystemDirectorySnapshot,\n type FileSystemEntrySnapshot,\n type FileSystemFileRead,\n type FileSystemFileSnapshot,\n type FileSystemMoveOptions,\n type FileSystemProviderCapabilities,\n type FileSystemProviderV2,\n type FileSystemRemoveOptions,\n type FileSystemRemoveResult,\n type FileSystemSnapshot,\n type FileSystemSnapshotEntry,\n type FileSystemVersion,\n type FileSystemWatchEvent,\n type FileSystemWatchListener,\n type FileSystemWatchOptions,\n type FileSystemWatchSubscription,\n type FileSystemWriteOptions,\n} from './v2.js';\nimport {\n WORKSPACE_ROOT,\n parseWorkspacePath,\n workspacePathBasename,\n workspacePathContains,\n workspacePathDirname,\n type WorkspacePath,\n} from './workspace-path.js';\n\ninterface MemoryEntryBase {\n readonly version: FileSystemVersion;\n readonly lastModified: string;\n}\n\ninterface MemoryFileEntry extends MemoryEntryBase {\n readonly kind: 'file';\n readonly data: ArrayBuffer;\n /** Compatibility metadata only; v2 always treats the payload as bytes. */\n readonly payloadKind: MemoryFilePayloadKind;\n}\n\ninterface MemoryDirectoryEntry extends MemoryEntryBase {\n readonly kind: 'directory';\n}\n\ntype MemoryEntry = MemoryFileEntry | MemoryDirectoryEntry;\n\nexport type MemoryFilePayloadKind = 'text' | 'binary';\n\nexport interface MemoryFileSystemV2StateFile {\n readonly path: WorkspacePath;\n readonly data: ArrayBuffer;\n readonly payloadKind: MemoryFilePayloadKind;\n}\n\nexport interface MemoryFileSystemV2CompatibilityFile {\n readonly data: ArrayBuffer;\n readonly payloadKind: MemoryFilePayloadKind;\n}\n\nexport interface MemoryFileSystemV2State {\n readonly revision: number;\n readonly files: readonly MemoryFileSystemV2StateFile[];\n readonly directories: readonly WorkspacePath[];\n}\n\nexport interface MemoryFileSystemV2ReplacementFile {\n readonly path: WorkspacePath;\n readonly data: ArrayBuffer | Uint8Array;\n readonly payloadKind: MemoryFilePayloadKind;\n}\n\nexport interface MemoryFileSystemV2Replacement {\n readonly files: readonly MemoryFileSystemV2ReplacementFile[];\n readonly directories?: readonly WorkspacePath[];\n}\n\ninterface MemoryWatcher {\n readonly listener: FileSystemWatchListener;\n readonly onError: FileSystemWatchOptions['onError'];\n}\n\ntype MemoryWatchEventInput = FileSystemWatchEvent extends infer Event\n ? Event extends FileSystemWatchEvent\n ? Omit<Event, 'sequence' | 'origin'>\n : never\n : never;\n\nconst MEMORY_CAPABILITIES: FileSystemProviderCapabilities = Object.freeze({\n writeAtomicity: 'process',\n moveAtomicity: 'process',\n snapshotAtomicity: 'process',\n conditionalWrite: 'process',\n recursiveRemove: true,\n watch: true,\n caseSensitivity: 'sensitive',\n symlinkPolicy: 'unsupported',\n durability: 'volatile',\n});\n\n/**\n * Correctness reference for FileSystemProviderV2.\n *\n * Every mutation validates first, stages a fresh map, swaps it once, and only\n * then emits notifications. File buffers are owned by the provider and every\n * read/snapshot returns a defensive copy.\n */\nexport class MemoryFileSystemProviderV2 implements FileSystemProviderV2 {\n public readonly id: string;\n public readonly label: string;\n public readonly capabilities = MEMORY_CAPABILITIES;\n\n private entries: Map<WorkspacePath, MemoryEntry>;\n private readonly watchers = new Set<MemoryWatcher>();\n private readonly subscriptions = new Set<FileSystemWatchSubscription>();\n private readonly pendingEvents: FileSystemWatchEvent[] = [];\n private emittingEvents = false;\n private mutationCounter = 0;\n private eventSequence = 0;\n private treeVersion: FileSystemVersion;\n private disposed = false;\n private disposePromise: Promise<void> | null = null;\n\n public constructor(id: string, label: string) {\n this.id = id;\n this.label = label;\n this.treeVersion = parseFileSystemVersion(`${id}:0`);\n const now = new Date().toISOString();\n this.entries = new Map([\n [WORKSPACE_ROOT, { kind: 'directory', version: this.treeVersion, lastModified: now }],\n ]);\n }\n\n /** Monotonic in-process revision used by synchronous transient-workspace staging. */\n public get mutationRevision(): number {\n return this.mutationCounter;\n }\n\n /** @internal Atomically couple owned bytes to their v1 compatibility kind. */\n public readCompatibilityFile(path: WorkspacePath): MemoryFileSystemV2CompatibilityFile | null {\n this.assertOpen('read');\n const canonical = this.canonical(path);\n const entry = this.entries.get(canonical);\n if (!entry) return null;\n if (entry.kind !== 'file') {\n throw this.error(\n 'type-mismatch',\n 'read',\n canonical,\n 'Expected a file but found a directory.',\n );\n }\n return Object.freeze({ data: entry.data.slice(0), payloadKind: entry.payloadKind });\n }\n\n /** @internal Capture an owned synchronous copy for DBK whole-tree staging. */\n public captureState(): MemoryFileSystemV2State {\n this.assertOpen('snapshot');\n const files: MemoryFileSystemV2StateFile[] = [];\n const directories: WorkspacePath[] = [];\n for (const [path, entry] of [...this.entries].sort(([left], [right]) =>\n compareText(left, right),\n )) {\n if (!path) continue;\n if (entry.kind === 'directory') directories.push(path);\n else {\n files.push(\n Object.freeze({ path, data: entry.data.slice(0), payloadKind: entry.payloadKind }),\n );\n }\n }\n return Object.freeze({\n revision: this.mutationCounter,\n files: Object.freeze(files),\n directories: Object.freeze(directories),\n });\n }\n\n /** @internal Atomically replace a transient workspace after complete validation. */\n public replaceState(replacement: MemoryFileSystemV2Replacement, expectedRevision?: number): void {\n this.assertOpen('write');\n const stagedFiles = new Map<\n WorkspacePath,\n { readonly data: ArrayBuffer; readonly payloadKind: MemoryFilePayloadKind }\n >();\n const stagedDirectories = new Set<WorkspacePath>();\n const explicitDirectories = new Set<WorkspacePath>();\n\n for (const rawDirectory of replacement.directories ?? []) {\n const directory = this.canonicalNonRoot(rawDirectory, 'create-directory');\n if (explicitDirectories.has(directory)) {\n throw this.error(\n 'already-exists',\n 'create-directory',\n directory,\n 'Duplicate replacement directory.',\n );\n }\n explicitDirectories.add(directory);\n stagedDirectories.add(directory);\n addParentPaths(stagedDirectories, directory);\n }\n for (const rawFile of replacement.files) {\n const path = this.canonicalNonRoot(rawFile.path, 'write');\n if (stagedFiles.has(path)) {\n throw this.error('already-exists', 'write', path, 'Duplicate replacement file.');\n }\n if (!isMemoryFilePayloadKind(rawFile.payloadKind)) {\n throw this.error('type-mismatch', 'write', path, 'Invalid replacement payload kind.');\n }\n stagedFiles.set(path, {\n data: copyBytes(rawFile.data),\n payloadKind: rawFile.payloadKind,\n });\n addParentPaths(stagedDirectories, path);\n }\n for (const path of stagedFiles.keys()) {\n if (stagedDirectories.has(path)) {\n throw this.error(\n 'type-mismatch',\n 'write',\n path,\n 'Replacement path has conflicting file and directory kinds.',\n );\n }\n for (const parent of parentChain(path)) {\n if (parent && stagedFiles.has(parent)) {\n throw this.error('type-mismatch', 'write', parent, 'A replacement parent is a file.');\n }\n }\n }\n if (expectedRevision !== undefined && expectedRevision !== this.mutationCounter) {\n throw this.error(\n 'conflict',\n 'write',\n WORKSPACE_ROOT,\n 'Memory filesystem changed while replacement contents were staged.',\n );\n }\n\n const version = this.nextVersion();\n const now = new Date().toISOString();\n const next = new Map<WorkspacePath, MemoryEntry>([\n [WORKSPACE_ROOT, { kind: 'directory', version, lastModified: now }],\n ]);\n this.addDirectories(next, [...stagedDirectories], version, now);\n for (const [path, file] of stagedFiles) {\n next.set(path, {\n kind: 'file',\n data: file.data,\n payloadKind: file.payloadKind,\n version,\n lastModified: now,\n });\n }\n this.entries = next;\n this.emit({\n type: 'overflow',\n kind: null,\n path: WORKSPACE_ROOT,\n destinationPath: null,\n version: null,\n previousVersion: null,\n });\n }\n\n /** @internal Synchronous setup hook used before a transient provider is published. */\n public seedText(path: WorkspacePath, content: string): void {\n this.writeFileNow(path, new TextEncoder().encode(content), { createParents: true }, 'text');\n }\n\n /** @internal Legacy text write that preserves text/binary compatibility metadata. */\n public async writeText(\n path: WorkspacePath,\n content: string,\n options: FileSystemWriteOptions = {},\n ): Promise<FileSystemFileSnapshot> {\n return this.writeFileNow(path, new TextEncoder().encode(content), options, 'text');\n }\n\n /** @internal Legacy binary write that explicitly changes compatibility payload kind. */\n public async writeBinary(\n path: WorkspacePath,\n data: ArrayBuffer | Uint8Array,\n options: FileSystemWriteOptions = {},\n ): Promise<FileSystemFileSnapshot> {\n return this.writeFileNow(path, data, options, 'binary');\n }\n\n /** @internal Atomic legacy compare-and-write over the authoritative v2 entry. */\n public async commitText(\n path: WorkspacePath,\n content: string,\n expectedContent: string | null,\n ): Promise<FileCommitResult> {\n this.assertOpen('write');\n const canonical = this.canonicalNonRoot(path, 'write');\n const existing = this.entries.get(canonical);\n if (existing?.kind === 'directory') {\n throw this.error('type-mismatch', 'write', canonical, 'Cannot replace a directory.');\n }\n const currentContent =\n existing?.kind === 'file' && existing.payloadKind === 'text'\n ? new TextDecoder().decode(existing.data)\n : null;\n if (\n (existing?.kind === 'file' && existing.payloadKind === 'binary') ||\n (currentContent !== expectedContent && currentContent !== content)\n ) {\n return {\n status: 'conflict',\n content: currentContent,\n version: existing?.version ?? null,\n };\n }\n const written = this.writeFileNow(\n canonical,\n new TextEncoder().encode(content),\n { createParents: true, expectedVersion: existing?.version ?? null },\n 'text',\n );\n return { status: 'committed', version: written.version };\n }\n\n public async stat(path: WorkspacePath): Promise<FileSystemEntrySnapshot | null> {\n this.assertOpen('stat');\n const canonical = this.canonical(path);\n const entry = this.entries.get(canonical);\n return entry ? this.toEntrySnapshot(canonical, entry) : null;\n }\n\n public async readFile(path: WorkspacePath): Promise<FileSystemFileRead | null> {\n this.assertOpen('read');\n const canonical = this.canonical(path);\n const entry = this.entries.get(canonical);\n if (!entry) return null;\n if (entry.kind !== 'file') {\n throw this.error(\n 'type-mismatch',\n 'read',\n canonical,\n 'Expected a file but found a directory.',\n );\n }\n return Object.freeze({\n entry: this.toFileSnapshot(canonical, entry),\n data: entry.data.slice(0),\n });\n }\n\n public async readDirectory(path: WorkspacePath): Promise<readonly FileSystemEntrySnapshot[]> {\n this.assertOpen('list');\n const canonical = this.canonical(path);\n const directory = this.entries.get(canonical);\n if (!directory) {\n throw this.error('not-found', 'list', canonical, 'Directory does not exist.');\n }\n if (directory.kind !== 'directory') {\n throw this.error(\n 'type-mismatch',\n 'list',\n canonical,\n 'Expected a directory but found a file.',\n );\n }\n\n const children: FileSystemEntrySnapshot[] = [];\n for (const [entryPath, entry] of this.entries) {\n if (entryPath && workspacePathDirname(entryPath) === canonical) {\n children.push(this.toEntrySnapshot(entryPath, entry));\n }\n }\n children.sort(compareSnapshots);\n return Object.freeze(children);\n }\n\n public async writeFile(\n path: WorkspacePath,\n data: ArrayBuffer | Uint8Array,\n options: FileSystemWriteOptions = {},\n ): Promise<FileSystemFileSnapshot> {\n return this.writeFileNow(path, data, options);\n }\n\n private writeFileNow(\n path: WorkspacePath,\n data: ArrayBuffer | Uint8Array,\n options: FileSystemWriteOptions,\n payloadKind?: MemoryFilePayloadKind,\n ): FileSystemFileSnapshot {\n this.assertOpen('write');\n const canonical = this.canonicalNonRoot(path, 'write');\n const existing = this.entries.get(canonical);\n if (existing?.kind === 'directory') {\n throw this.error(\n 'type-mismatch',\n 'write',\n canonical,\n 'Cannot replace a directory with a file.',\n );\n }\n\n const mode = options.mode ?? 'upsert';\n if (mode === 'create' && existing) {\n throw this.error('already-exists', 'write', canonical, 'File already exists.');\n }\n if (mode === 'replace' && !existing) {\n throw this.error('not-found', 'write', canonical, 'File does not exist.');\n }\n this.assertExpectedVersion(existing, options.expectedVersion, 'write', canonical);\n\n const missingParents = this.planParents(canonical, options.createParents ?? false, 'write');\n const ownedData = copyBytes(data);\n const version = this.nextVersion();\n const now = new Date().toISOString();\n const next = new Map(this.entries);\n this.addDirectories(next, missingParents, version, now);\n next.set(canonical, {\n kind: 'file',\n data: ownedData,\n payloadKind: payloadKind ?? (existing?.kind === 'file' ? existing.payloadKind : 'binary'),\n version,\n lastModified: now,\n });\n this.touchParents(next, canonical, version, now);\n this.entries = next;\n\n for (const directoryPath of missingParents) {\n this.emit({\n type: 'created',\n kind: 'directory',\n path: directoryPath,\n destinationPath: null,\n version,\n previousVersion: null,\n });\n }\n this.emit({\n type: existing ? 'modified' : 'created',\n kind: 'file',\n path: canonical,\n destinationPath: null,\n version,\n previousVersion: existing?.version ?? null,\n });\n return this.toFileSnapshot(canonical, next.get(canonical) as MemoryFileEntry);\n }\n\n public async createDirectory(\n path: WorkspacePath,\n options: FileSystemCreateDirectoryOptions = {},\n ): Promise<FileSystemDirectorySnapshot> {\n this.assertOpen('create-directory');\n const canonical = this.canonical(path);\n const existing = this.entries.get(canonical);\n if (existing) {\n if (existing.kind !== 'directory') {\n throw this.error(\n 'type-mismatch',\n 'create-directory',\n canonical,\n 'Cannot replace a file with a directory.',\n );\n }\n if ((options.mode ?? 'ensure') === 'create') {\n throw this.error(\n 'already-exists',\n 'create-directory',\n canonical,\n 'Directory already exists.',\n );\n }\n return this.toDirectorySnapshot(canonical, existing);\n }\n\n const missingParents = this.planParents(\n canonical,\n options.createParents ?? false,\n 'create-directory',\n );\n const version = this.nextVersion();\n const now = new Date().toISOString();\n const next = new Map(this.entries);\n const created = [...missingParents, canonical];\n this.addDirectories(next, created, version, now);\n this.touchParents(next, canonical, version, now);\n this.entries = next;\n\n for (const directoryPath of created) {\n this.emit({\n type: 'created',\n kind: 'directory',\n path: directoryPath,\n destinationPath: null,\n version,\n previousVersion: null,\n });\n }\n return this.toDirectorySnapshot(canonical, next.get(canonical) as MemoryDirectoryEntry);\n }\n\n public async remove(\n path: WorkspacePath,\n options: FileSystemRemoveOptions = {},\n ): Promise<FileSystemRemoveResult> {\n this.assertOpen('remove');\n const canonical = this.canonicalNonRoot(path, 'remove');\n const existing = this.entries.get(canonical);\n if (!existing) {\n if ((options.missing ?? 'error') === 'ignore') {\n return Object.freeze({ removed: false, version: this.treeVersion });\n }\n throw this.error('not-found', 'remove', canonical, 'Entry does not exist.');\n }\n this.assertExpectedVersion(existing, options.expectedVersion, 'remove', canonical);\n\n const descendants = [...this.entries.keys()].filter((candidate) =>\n workspacePathContains(canonical, candidate, false),\n );\n if (existing.kind === 'directory' && descendants.length > 0 && !options.recursive) {\n throw this.error('not-empty', 'remove', canonical, 'Directory is not empty.');\n }\n\n const version = this.nextVersion();\n const now = new Date().toISOString();\n const next = new Map(this.entries);\n next.delete(canonical);\n if (existing.kind === 'directory') {\n for (const descendant of descendants) next.delete(descendant);\n }\n this.touchParents(next, canonical, version, now);\n this.entries = next;\n\n this.emit({\n type: 'removed',\n kind: existing.kind,\n path: canonical,\n destinationPath: null,\n version: null,\n previousVersion: existing.version,\n });\n return Object.freeze({ removed: true, version });\n }\n\n public async move(\n oldPath: WorkspacePath,\n newPath: WorkspacePath,\n options: FileSystemMoveOptions = {},\n ): Promise<FileSystemEntrySnapshot> {\n this.assertOpen('move');\n const sourcePath = this.canonicalNonRoot(oldPath, 'move');\n const destinationPath = this.canonicalNonRoot(newPath, 'move');\n const source = this.entries.get(sourcePath);\n if (!source) throw this.error('not-found', 'move', sourcePath, 'Source does not exist.');\n this.assertExpectedVersion(source, options.expectedVersion, 'move', sourcePath);\n if (sourcePath === destinationPath) return this.toEntrySnapshot(sourcePath, source);\n if (this.entries.has(destinationPath)) {\n throw new FsError('already-exists', 'Destination already exists.', {\n operation: 'move',\n path: sourcePath,\n destinationPath,\n });\n }\n if (source.kind === 'directory' && workspacePathContains(sourcePath, destinationPath, false)) {\n throw new FsError('invalid-path', 'Cannot move a directory into itself.', {\n operation: 'move',\n path: sourcePath,\n destinationPath,\n });\n }\n\n const missingParents = this.planParents(\n destinationPath,\n options.createParents ?? false,\n 'move',\n );\n const sourcePaths = [...this.entries.keys()].filter((candidate) =>\n workspacePathContains(sourcePath, candidate),\n );\n const sourceSet = new Set(sourcePaths);\n const remapped = sourcePaths.map((currentPath) => {\n const suffix = currentPath.slice(sourcePath.length);\n const target = parseWorkspacePath(`${destinationPath}${suffix}`);\n if (this.entries.has(target) && !sourceSet.has(target)) {\n throw new FsError('already-exists', 'A destination descendant already exists.', {\n operation: 'move',\n path: currentPath,\n destinationPath: target,\n });\n }\n return [currentPath, target] as const;\n });\n\n const version = this.nextVersion();\n const now = new Date().toISOString();\n const next = new Map(this.entries);\n for (const currentPath of sourcePaths) next.delete(currentPath);\n this.addDirectories(next, missingParents, version, now);\n for (const [currentPath, targetPath] of remapped) {\n const current = this.entries.get(currentPath)!;\n next.set(targetPath, this.withVersion(current, version, now));\n }\n this.touchParents(next, sourcePath, version, now);\n this.touchParents(next, destinationPath, version, now);\n this.entries = next;\n\n for (const directoryPath of missingParents) {\n this.emit({\n type: 'created',\n kind: 'directory',\n path: directoryPath,\n destinationPath: null,\n version,\n previousVersion: null,\n });\n }\n this.emit({\n type: 'moved',\n kind: source.kind,\n path: sourcePath,\n destinationPath,\n version,\n previousVersion: source.version,\n });\n return this.toEntrySnapshot(destinationPath, next.get(destinationPath)!);\n }\n\n public async snapshot(): Promise<FileSystemSnapshot> {\n this.assertOpen('snapshot');\n const entries: FileSystemSnapshotEntry[] = [...this.entries.entries()]\n .sort(([left], [right]) => compareText(left, right))\n .map(([path, entry]) => {\n if (entry.kind === 'file') {\n return Object.freeze({ ...this.toFileSnapshot(path, entry), data: entry.data.slice(0) });\n }\n return this.toDirectorySnapshot(path, entry);\n });\n return Object.freeze({ version: this.treeVersion, entries: Object.freeze(entries) });\n }\n\n public watch(\n listener: FileSystemWatchListener,\n options: FileSystemWatchOptions = {},\n ): FileSystemWatchSubscription {\n this.assertOpen('watch');\n const watcher: MemoryWatcher = { listener, onError: options.onError };\n this.watchers.add(watcher);\n let closed = false;\n let disposePromise: Promise<void> | null = null;\n const subscription: FileSystemWatchSubscription = {\n get closed() {\n return closed;\n },\n ready: Promise.resolve(),\n dispose: () => {\n if (disposePromise) return disposePromise;\n closed = true;\n this.watchers.delete(watcher);\n this.subscriptions.delete(subscription);\n disposePromise = Promise.resolve();\n return disposePromise;\n },\n };\n this.subscriptions.add(subscription);\n return subscription;\n }\n\n public dispose(): Promise<void> {\n if (this.disposePromise) return this.disposePromise;\n this.disposed = true;\n this.disposePromise = Promise.all(\n [...this.subscriptions].map((subscription) => subscription.dispose()),\n ).then(() => undefined);\n return this.disposePromise;\n }\n\n private canonical(path: WorkspacePath): WorkspacePath {\n return parseWorkspacePath(path);\n }\n\n private canonicalNonRoot(path: WorkspacePath, operation: FsOperation): WorkspacePath {\n const canonical = this.canonical(path);\n if (!canonical) {\n throw this.error(\n 'invalid-path',\n operation,\n canonical,\n 'The workspace root is not a file entry.',\n );\n }\n return canonical;\n }\n\n private assertOpen(operation: FsOperation): void {\n if (!this.disposed) return;\n throw new FsError('disposed', 'Filesystem provider is disposed.', { operation });\n }\n\n private assertExpectedVersion(\n entry: MemoryEntry | undefined,\n expected: FileSystemVersion | null | undefined,\n operation: FsOperation,\n path: WorkspacePath,\n ): void {\n if (expected === undefined) return;\n if (expected === null ? !entry : entry?.version === expected) return;\n throw this.error(\n 'conflict',\n operation,\n path,\n 'Entry version does not match the expected version.',\n );\n }\n\n private planParents(\n path: WorkspacePath,\n createParents: boolean,\n operation: FsOperation,\n ): WorkspacePath[] {\n const missing: WorkspacePath[] = [];\n for (const parent of parentChain(path)) {\n if (!parent) continue;\n const entry = this.entries.get(parent);\n if (entry?.kind === 'file') {\n throw this.error(\n 'type-mismatch',\n operation,\n parent,\n 'A parent path is a file, not a directory.',\n );\n }\n if (!entry) {\n if (!createParents) {\n throw this.error('not-found', operation, parent, 'Parent directory does not exist.');\n }\n missing.push(parent);\n }\n }\n return missing;\n }\n\n private addDirectories(\n target: Map<WorkspacePath, MemoryEntry>,\n paths: readonly WorkspacePath[],\n version: FileSystemVersion,\n lastModified: string,\n ): void {\n for (const path of paths) {\n target.set(path, { kind: 'directory', version, lastModified });\n }\n }\n\n private touchParents(\n target: Map<WorkspacePath, MemoryEntry>,\n path: WorkspacePath,\n version: FileSystemVersion,\n lastModified: string,\n ): void {\n for (const parent of parentChain(path)) {\n const entry = target.get(parent);\n if (entry?.kind === 'directory') {\n target.set(parent, { kind: 'directory', version, lastModified });\n }\n }\n }\n\n private withVersion(\n entry: MemoryEntry,\n version: FileSystemVersion,\n lastModified: string,\n ): MemoryEntry {\n return entry.kind === 'file'\n ? {\n kind: 'file',\n data: entry.data,\n payloadKind: entry.payloadKind,\n version,\n lastModified,\n }\n : { kind: 'directory', version, lastModified };\n }\n\n private nextVersion(): FileSystemVersion {\n this.mutationCounter += 1;\n this.treeVersion = parseFileSystemVersion(`${this.id}:${this.mutationCounter}`);\n return this.treeVersion;\n }\n\n private toEntrySnapshot(path: WorkspacePath, entry: MemoryEntry): FileSystemEntrySnapshot {\n return entry.kind === 'file'\n ? this.toFileSnapshot(path, entry)\n : this.toDirectorySnapshot(path, entry);\n }\n\n private toFileSnapshot(path: WorkspacePath, entry: MemoryFileEntry): FileSystemFileSnapshot {\n return Object.freeze({\n kind: 'file',\n path,\n name: workspacePathBasename(path),\n size: entry.data.byteLength,\n version: entry.version,\n lastModified: entry.lastModified,\n });\n }\n\n private toDirectorySnapshot(\n path: WorkspacePath,\n entry: MemoryDirectoryEntry,\n ): FileSystemDirectorySnapshot {\n return Object.freeze({\n kind: 'directory',\n path,\n name: workspacePathBasename(path),\n size: null,\n version: entry.version,\n lastModified: entry.lastModified,\n });\n }\n\n private emit(event: MemoryWatchEventInput): void {\n const complete: FileSystemWatchEvent = Object.freeze({\n ...event,\n sequence: ++this.eventSequence,\n origin: 'local',\n });\n this.pendingEvents.push(complete);\n if (this.emittingEvents) return;\n\n this.emittingEvents = true;\n try {\n while (this.pendingEvents.length > 0) {\n const pending = this.pendingEvents.shift();\n if (!pending) continue;\n for (const watcher of [...this.watchers]) {\n try {\n watcher.listener(pending);\n } catch {\n // A watcher is observational; it cannot roll back a completed mutation.\n }\n }\n }\n } finally {\n this.emittingEvents = false;\n }\n }\n\n private error(\n code: ConstructorParameters<typeof FsError>[0],\n operation: FsOperation,\n path: WorkspacePath,\n message: string,\n ): FsError {\n return new FsError(code, message, { operation, path });\n }\n}\n\nfunction parentChain(path: WorkspacePath): WorkspacePath[] {\n const parents: WorkspacePath[] = [];\n let current = workspacePathDirname(path);\n while (true) {\n parents.unshift(current);\n if (!current) return parents;\n current = workspacePathDirname(current);\n }\n}\n\nfunction addParentPaths(target: Set<WorkspacePath>, path: WorkspacePath): void {\n for (const parent of parentChain(path)) {\n if (parent) target.add(parent);\n }\n}\n\nfunction isMemoryFilePayloadKind(value: unknown): value is MemoryFilePayloadKind {\n return value === 'text' || value === 'binary';\n}\n\nfunction copyBytes(data: ArrayBuffer | Uint8Array): ArrayBuffer {\n const source = ArrayBuffer.isView(data)\n ? new Uint8Array(data.buffer, data.byteOffset, data.byteLength)\n : new Uint8Array(data);\n const copy = new Uint8Array(source.byteLength);\n copy.set(source);\n return copy.buffer as ArrayBuffer;\n}\n\nfunction compareSnapshots(left: FileSystemEntrySnapshot, right: FileSystemEntrySnapshot): number {\n if (left.kind !== right.kind) return left.kind === 'directory' ? -1 : 1;\n return compareText(left.name, right.name);\n}\n\nfunction compareText(left: string, right: string): number {\n return left < right ? -1 : left > right ? 1 : 0;\n}\n","/**\n * In-memory filesystem used by transient loose-file and DBK workspaces.\n *\n * MemoryFileSystemProviderV2 is authoritative. This class is the temporary\n * text-oriented v1 facade retained while callers migrate to the byte contract.\n */\n\nimport { FsError, type FsOperation } from './fs-error.js';\nimport {\n MemoryFileSystemProviderV2,\n type MemoryFileSystemV2ReplacementFile,\n} from './memory-provider-v2.js';\nimport type { FileCommitResult, FileSystemEntry, FileSystemProvider, FileMeta } from './types.js';\nimport { parseWorkspacePath, type WorkspacePath } from './workspace-path.js';\n\nexport type MemoryFileSystemSnapshotFile =\n | {\n readonly kind: 'text';\n readonly path: string;\n readonly content: string;\n }\n | {\n readonly kind: 'binary';\n readonly path: string;\n readonly data: ArrayBuffer | Uint8Array;\n };\n\n/** Complete provider-relative state for a transient memory workspace. */\nexport interface MemoryFileSystemSnapshot {\n readonly files: readonly MemoryFileSystemSnapshotFile[];\n readonly directories?: readonly string[];\n}\n\nfunction canonicalPath(path: string): WorkspacePath {\n return parseWorkspacePath(path);\n}\n\nfunction entryPath(path: string, operation: FsOperation): WorkspacePath {\n const canonical = canonicalPath(path);\n if (!canonical) {\n throw new FsError('invalid-path', 'The workspace root is not a file entry.', {\n operation,\n path,\n });\n }\n return canonical;\n}\n\nfunction decode(data: ArrayBuffer): string {\n return new TextDecoder().decode(data);\n}\n\n/**\n * Legacy facade over the correctness-first memory provider.\n *\n * Synchronous seed/snapshot replacement methods remain because DBK import\n * fully stages external bytes before publishing one atomic in-memory swap.\n */\nexport class MemoryFileSystemProvider implements FileSystemProvider {\n public readonly id: string;\n public readonly label: string;\n public readonly v2: MemoryFileSystemProviderV2;\n\n public constructor(id: string, label: string) {\n this.id = id;\n this.label = label;\n this.v2 = new MemoryFileSystemProviderV2(id, label);\n }\n\n /** Monotonic version of the complete in-memory tree. */\n public get treeVersion(): number {\n return this.v2.mutationRevision;\n }\n\n /** Capture an owned deterministic copy of the complete transient tree. */\n public captureContents(): MemoryFileSystemSnapshot {\n const state = this.v2.captureState();\n return {\n files: state.files.map((file) =>\n file.payloadKind === 'text'\n ? { kind: 'text' as const, path: file.path, content: decode(file.data) }\n : { kind: 'binary' as const, path: file.path, data: file.data.slice(0) },\n ),\n directories: [...state.directories],\n };\n }\n\n /** Atomically replace the complete tree after validating and owning all input. */\n public replaceContents(snapshot: MemoryFileSystemSnapshot, expectedTreeVersion?: number): void {\n const files: MemoryFileSystemV2ReplacementFile[] = snapshot.files.map((file) => ({\n path: entryPath(file.path, 'write'),\n payloadKind: file.kind,\n data: file.kind === 'text' ? new TextEncoder().encode(file.content) : file.data,\n }));\n const directories = (snapshot.directories ?? []).map((path) =>\n entryPath(path, 'create-directory'),\n );\n this.v2.replaceState({ files, directories }, expectedTreeVersion);\n }\n\n /** Seed synchronously before publishing a transient provider to consumers. */\n public seedText(path: string, content: string): void {\n this.v2.seedText(entryPath(path, 'write'), content);\n }\n\n public async readFile(path: string): Promise<string | null> {\n const file = await this.v2.readFile(entryPath(path, 'read'));\n return file ? decode(file.data) : null;\n }\n\n public async writeFile(path: string, content: string): Promise<void> {\n await this.v2.writeText(entryPath(path, 'write'), content, { createParents: true });\n }\n\n public commitFile(\n path: string,\n content: string,\n expectedContent: string | null,\n ): Promise<FileCommitResult> {\n return this.v2.commitText(entryPath(path, 'write'), content, expectedContent);\n }\n\n public async delete(path: string): Promise<void> {\n await this.v2.remove(entryPath(path, 'remove'), { recursive: true, missing: 'ignore' });\n }\n\n public async rename(oldPath: string, newPath: string): Promise<void> {\n await this.v2.move(entryPath(oldPath, 'move'), entryPath(newPath, 'move'), {\n createParents: true,\n });\n }\n\n public async readDirectory(path: string): Promise<FileSystemEntry[]> {\n const canonical = canonicalPath(path);\n try {\n const entries = await this.v2.readDirectory(canonical);\n return entries.map((entry) => ({\n kind: entry.kind,\n name: entry.name,\n path: entry.path,\n }));\n } catch (error: unknown) {\n // Preserve the v1 missing-directory behavior only on the compatibility facade.\n if (error instanceof FsError && error.code === 'not-found') return [];\n throw error;\n }\n }\n\n public async exists(path: string): Promise<boolean> {\n return (await this.v2.stat(canonicalPath(path))) !== null;\n }\n\n public async createDirectory(path: string): Promise<void> {\n await this.v2.createDirectory(canonicalPath(path), { createParents: true });\n }\n\n public async stat(path: string): Promise<FileMeta | null> {\n const canonical = canonicalPath(path);\n if (!canonical) return null;\n const entry = await this.v2.stat(canonical);\n if (!entry || entry.kind !== 'file') return null;\n return {\n name: entry.name,\n path: entry.path,\n size: entry.size,\n lastModified: entry.lastModified,\n };\n }\n\n public async readBinary(path: string): Promise<ArrayBuffer | null> {\n const canonical = entryPath(path, 'read');\n const file = this.v2.readCompatibilityFile(canonical);\n if (!file || file.payloadKind !== 'binary') return null;\n return file.data;\n }\n\n public async writeBinary(path: string, data: ArrayBuffer | Uint8Array): Promise<void> {\n await this.v2.writeBinary(entryPath(path, 'write'), data, { createParents: true });\n }\n}\n"],"mappings":"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","names":["entryPath"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/host/filesystem-v2.ts","../src/host/index.ts"],"sourcesContent":["import type {\n FileSystemCreateDirectoryOptions,\n FileSystemDirectorySnapshot,\n FileSystemEntrySnapshot,\n FileSystemFileRead,\n FileSystemFileSnapshot,\n FileSystemMoveOptions,\n FileSystemProviderCapabilities,\n FileSystemRemoveOptions,\n FileSystemRemoveResult,\n FileSystemSnapshot,\n FileSystemWatchEvent,\n FileSystemWriteOptions,\n SerializedFsError,\n WorkspacePath,\n} from '../filesystem/index.js';\n\n/** Stable capabilities shared by the Electron v2 client and native backend. */\nexport const ELECTRON_FILE_SYSTEM_V2_CAPABILITIES: FileSystemProviderCapabilities = Object.freeze({\n writeAtomicity: 'process',\n moveAtomicity: 'process',\n snapshotAtomicity: 'process',\n conditionalWrite: 'process',\n recursiveRemove: true,\n watch: true,\n caseSensitivity: 'platform',\n symlinkPolicy: 'follow-contained',\n durability: 'best-effort',\n});\n\n/** Explicit result envelope; Electron does not preserve custom Error fields. */\nexport type HostFileSystemV2Result<T> =\n | { readonly ok: true; readonly value: T }\n | { readonly ok: false; readonly error: SerializedFsError };\n\nexport interface HostFileSystemV2OpenRequest {\n readonly instanceId: string;\n /** Main-owned persisted workspace authority, never an absolute path. */\n readonly providerId: string;\n readonly label: string;\n}\n\nexport type HostFileSystemV2WatchMessage =\n | {\n readonly instanceId: string;\n readonly subscriptionId: string;\n readonly kind: 'event';\n readonly event: FileSystemWatchEvent;\n }\n | {\n readonly instanceId: string;\n readonly subscriptionId: string;\n readonly kind: 'error';\n readonly error: SerializedFsError;\n };\n\n/** Wire-level filesystem v2 API exposed by preload. */\nexport interface DocBlocksHostFsV2API {\n open(\n request: HostFileSystemV2OpenRequest,\n ): Promise<HostFileSystemV2Result<FileSystemProviderCapabilities>>;\n stat(\n instanceId: string,\n path: WorkspacePath,\n ): Promise<HostFileSystemV2Result<FileSystemEntrySnapshot | null>>;\n readFile(\n instanceId: string,\n path: WorkspacePath,\n ): Promise<HostFileSystemV2Result<FileSystemFileRead | null>>;\n readDirectory(\n instanceId: string,\n path: WorkspacePath,\n ): Promise<HostFileSystemV2Result<readonly FileSystemEntrySnapshot[]>>;\n writeFile(\n instanceId: string,\n path: WorkspacePath,\n data: ArrayBuffer | Uint8Array,\n options?: FileSystemWriteOptions,\n ): Promise<HostFileSystemV2Result<FileSystemFileSnapshot>>;\n createDirectory(\n instanceId: string,\n path: WorkspacePath,\n options?: FileSystemCreateDirectoryOptions,\n ): Promise<HostFileSystemV2Result<FileSystemDirectorySnapshot>>;\n remove(\n instanceId: string,\n path: WorkspacePath,\n options?: FileSystemRemoveOptions,\n ): Promise<HostFileSystemV2Result<FileSystemRemoveResult>>;\n move(\n instanceId: string,\n oldPath: WorkspacePath,\n newPath: WorkspacePath,\n options?: FileSystemMoveOptions,\n ): Promise<HostFileSystemV2Result<FileSystemEntrySnapshot>>;\n snapshot(instanceId: string): Promise<HostFileSystemV2Result<FileSystemSnapshot>>;\n watchSubscribe(instanceId: string, subscriptionId: string): Promise<HostFileSystemV2Result<null>>;\n watchUnsubscribe(\n instanceId: string,\n subscriptionId: string,\n ): Promise<HostFileSystemV2Result<null>>;\n dispose(instanceId: string): Promise<HostFileSystemV2Result<null>>;\n onWatchMessage(listener: (message: HostFileSystemV2WatchMessage) => void): () => void;\n}\n","/**\n * Host bridge — shared types + runtime access for the Electron desktop\n * host. The renderer calls `getDocBlocksHost()` to reach the preload\n * contextBridge; `isElectronHost()` gates desktop-only UI branches.\n */\n\nexport type {\n DocBlocksHostAPI,\n DocBlocksHostFsAPI,\n DocBlocksHostExternalAPI,\n DocBlocksHostWorkspacesAPI,\n DocBlocksHostShellAPI,\n DocBlocksHostExportAPI,\n DocBlocksHostFfmpegAPI,\n DocBlocksHostUpdaterAPI,\n DocBlocksHostLifecycleAPI,\n ElectronWorkspaceInfo,\n ExternalBinaryCommitResult,\n HostCloseReason,\n HostEnvironment,\n HostExportTargetGrant,\n HostPrepareCloseRequest,\n HostPrepareCloseResult,\n MenuCommand,\n OpenRequest,\n UpdateInstallResult,\n UpdaterStatus,\n} from './types.js';\n\nexport type {\n DocBlocksHostGitAPI,\n GitBranchInfo,\n GitCapabilities,\n GitCloneHandle,\n GitCloneProgress,\n GitError,\n GitErrorCode,\n GitFileAtRevision,\n GitFileChange,\n GitFileStatusCode,\n GitLogEntry,\n GitLogOptions,\n GitRemoteInfo,\n GitRepoDetection,\n GitResult,\n GitRevision,\n GitStatus,\n} from './git.js';\n\nexport {\n ELECTRON_FILE_SYSTEM_V2_CAPABILITIES,\n type DocBlocksHostFsV2API,\n type HostFileSystemV2OpenRequest,\n type HostFileSystemV2Result,\n type HostFileSystemV2WatchMessage,\n} from './filesystem-v2.js';\n\nexport {\n HOST_WIRE_LIMITS,\n isBoundedBytePayload,\n isBoundedString,\n isTrustedRendererUrl,\n parseExternalHttpUrl,\n parseOpenRequest,\n} from './wire-policy.js';\n\nimport type { DocBlocksHostAPI } from './types.js';\n\n/** True when running inside the Electron desktop shell. */\nexport function isElectronHost(): boolean {\n if (typeof globalThis === 'undefined') return false;\n const host = (globalThis as { docBlocksHost?: unknown }).docBlocksHost;\n return (\n typeof host === 'object' &&\n host !== null &&\n typeof (host as { fs?: unknown }).fs === 'object' &&\n (host as { fs?: unknown }).fs !== null\n );\n}\n\n/** Return the host API, or throw if not running under Electron. */\nexport function getDocBlocksHost(): DocBlocksHostAPI {\n const host = (globalThis as { docBlocksHost?: DocBlocksHostAPI }).docBlocksHost;\n if (!host) {\n throw new Error('docBlocksHost is not available — not running under Electron?');\n }\n return host;\n}\n\n/** Return the host API, or null if not running under Electron. */\nexport function maybeGetDocBlocksHost(): DocBlocksHostAPI | null {\n return (globalThis as { docBlocksHost?: DocBlocksHostAPI }).docBlocksHost ?? null;\n}\n"],"mappings":";AAkBO,IAAM,uCAAuE,OAAO,OAAO;AAAA,EAChG,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,OAAO;AAAA,EACP,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,YAAY;AACd,CAAC;;;ACyCM,SAAS,iBAA0B;AACxC,MAAI,OAAO,eAAe,YAAa,QAAO;AAC9C,QAAM,OAAQ,WAA2C;AACzD,SACE,OAAO,SAAS,YAChB,SAAS,QACT,OAAQ,KAA0B,OAAO,YACxC,KAA0B,OAAO;AAEtC;AAGO,SAAS,mBAAqC;AACnD,QAAM,OAAQ,WAAoD;AAClE,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,mEAA8D;AAAA,EAChF;AACA,SAAO;AACT;AAGO,SAAS,wBAAiD;AAC/D,SAAQ,WAAoD,iBAAiB;AAC/E;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/filesystem/fs-error.ts","../src/filesystem/workspace-path.ts"],"sourcesContent":["/** Stable error codes shared by every filesystem transport and backend. */\nexport type FsErrorCode =\n | 'invalid-path'\n | 'path-escape'\n | 'not-found'\n | 'already-exists'\n | 'type-mismatch'\n | 'not-empty'\n | 'permission-denied'\n | 'conflict'\n | 'quota-exceeded'\n | 'not-supported'\n | 'busy'\n | 'disposed'\n | 'closed'\n | 'aborted'\n | 'io';\n\nexport type FsOperation =\n | 'parse-path'\n | 'read'\n | 'stat'\n | 'list'\n | 'write'\n | 'create-directory'\n | 'remove'\n | 'move'\n | 'snapshot'\n | 'watch'\n | 'dispose';\n\n/** Plain-data form safe to send over IPC, postMessage, or JSON. */\nexport interface SerializedFsError {\n readonly name: 'FsError';\n readonly code: FsErrorCode;\n readonly message: string;\n readonly operation: FsOperation | null;\n readonly path: string | null;\n readonly destinationPath: string | null;\n readonly retryable: boolean;\n}\n\nexport interface FsErrorContext {\n readonly operation?: FsOperation;\n readonly path?: string;\n readonly destinationPath?: string;\n readonly retryable?: boolean;\n readonly defaultCode?: FsErrorCode;\n}\n\nconst FS_ERROR_CODES: ReadonlySet<string> = new Set<FsErrorCode>([\n 'invalid-path',\n 'path-escape',\n 'not-found',\n 'already-exists',\n 'type-mismatch',\n 'not-empty',\n 'permission-denied',\n 'conflict',\n 'quota-exceeded',\n 'not-supported',\n 'busy',\n 'disposed',\n 'closed',\n 'aborted',\n 'io',\n]);\n\nconst FS_OPERATIONS: ReadonlySet<string> = new Set<FsOperation>([\n 'parse-path',\n 'read',\n 'stat',\n 'list',\n 'write',\n 'create-directory',\n 'remove',\n 'move',\n 'snapshot',\n 'watch',\n 'dispose',\n]);\n\n/** Error with a stable code and a deliberately serializable public shape. */\nexport class FsError extends Error {\n public readonly code: FsErrorCode;\n public readonly operation: FsOperation | null;\n public readonly path: string | null;\n public readonly destinationPath: string | null;\n public readonly retryable: boolean;\n\n public constructor(code: FsErrorCode, message: string, context: FsErrorContext = {}) {\n super(message);\n this.name = 'FsError';\n this.code = code;\n this.operation = context.operation ?? null;\n this.path = context.path ?? null;\n this.destinationPath = context.destinationPath ?? null;\n this.retryable = context.retryable ?? (code === 'io' || code === 'aborted' || code === 'busy');\n }\n\n public toJSON(): SerializedFsError {\n return {\n name: 'FsError',\n code: this.code,\n message: this.message,\n operation: this.operation,\n path: this.path,\n destinationPath: this.destinationPath,\n retryable: this.retryable,\n };\n }\n}\n\nexport function mapDomExceptionToFsErrorCode(name: string): FsErrorCode {\n switch (name) {\n case 'NotFoundError':\n return 'not-found';\n case 'ConstraintError':\n return 'already-exists';\n case 'TypeMismatchError':\n return 'type-mismatch';\n case 'InvalidModificationError':\n return 'not-empty';\n case 'NotAllowedError':\n case 'SecurityError':\n case 'NoModificationAllowedError':\n return 'permission-denied';\n case 'QuotaExceededError':\n return 'quota-exceeded';\n case 'NotSupportedError':\n return 'not-supported';\n case 'InvalidStateError':\n return 'disposed';\n case 'AbortError':\n return 'aborted';\n default:\n return 'io';\n }\n}\n\nexport function mapNodeErrorCodeToFsErrorCode(code: string): FsErrorCode {\n switch (code) {\n case 'ENOENT':\n return 'not-found';\n case 'ENOTDIR':\n return 'type-mismatch';\n case 'EEXIST':\n return 'already-exists';\n case 'EISDIR':\n return 'type-mismatch';\n case 'ENOTEMPTY':\n return 'not-empty';\n case 'EACCES':\n case 'EPERM':\n return 'permission-denied';\n case 'ENOSPC':\n case 'EDQUOT':\n return 'quota-exceeded';\n case 'EBUSY':\n return 'busy';\n case 'EXDEV':\n case 'ENOTSUP':\n case 'EOPNOTSUPP':\n return 'not-supported';\n default:\n return 'io';\n }\n}\n\nexport function isSerializedFsError(value: unknown): value is SerializedFsError {\n if (!value || typeof value !== 'object') return false;\n const candidate = value as Partial<Record<keyof SerializedFsError, unknown>>;\n return (\n candidate.name === 'FsError' &&\n typeof candidate.code === 'string' &&\n FS_ERROR_CODES.has(candidate.code) &&\n typeof candidate.message === 'string' &&\n (candidate.operation === null ||\n (typeof candidate.operation === 'string' && FS_OPERATIONS.has(candidate.operation))) &&\n (candidate.path === null || typeof candidate.path === 'string') &&\n (candidate.destinationPath === null || typeof candidate.destinationPath === 'string') &&\n typeof candidate.retryable === 'boolean'\n );\n}\n\nexport function deserializeFsError(value: SerializedFsError): FsError {\n return new FsError(value.code, value.message, {\n operation: value.operation ?? undefined,\n path: value.path ?? undefined,\n destinationPath: value.destinationPath ?? undefined,\n retryable: value.retryable,\n });\n}\n\nexport function fsErrorFromUnknown(error: unknown, context: FsErrorContext = {}): FsError {\n if (error instanceof FsError) return error;\n if (isSerializedFsError(error)) return deserializeFsError(error);\n\n const name = getErrorStringField(error, 'name');\n const nodeCode = getErrorStringField(error, 'code');\n const message = getErrorStringField(error, 'message') ?? String(error);\n const code =\n context.defaultCode ??\n (nodeCode\n ? mapNodeErrorCodeToFsErrorCode(nodeCode)\n : name\n ? mapDomExceptionToFsErrorCode(name)\n : 'io');\n return new FsError(code, message, context);\n}\n\nexport function serializeFsError(error: unknown, context: FsErrorContext = {}): SerializedFsError {\n return fsErrorFromUnknown(error, context).toJSON();\n}\n\n/**\n * True when a storage backend rejected an operation because the origin or\n * device is out of space. Covers typed `FsError`s (`'quota-exceeded'`, from\n * DOMException `QuotaExceededError` or Node `ENOSPC`/`EDQUOT`), serialized\n * transport copies, and raw DOMExceptions from backends that do not wrap\n * their errors (e.g. the File System Access API) — including cross-realm\n * instances where `instanceof DOMException` would fail.\n */\nexport function isQuotaExceededError(error: unknown): boolean {\n if (error instanceof FsError) return error.code === 'quota-exceeded';\n if (isSerializedFsError(error)) return error.code === 'quota-exceeded';\n return getErrorStringField(error, 'name') === 'QuotaExceededError';\n}\n\nfunction getErrorStringField(error: unknown, key: 'name' | 'message' | 'code'): string | null {\n if (!error || typeof error !== 'object') return null;\n const value = (error as Record<string, unknown>)[key];\n return typeof value === 'string' ? value : null;\n}\n","import { FsError } from './fs-error.js';\n\ndeclare const workspacePathBrand: unique symbol;\n\n/** Canonical, root-relative, forward-slash path within one workspace. */\nexport type WorkspacePath = string & { readonly [workspacePathBrand]: 'WorkspacePath' };\n\nexport const WORKSPACE_ROOT = '' as WorkspacePath;\n\n/**\n * Parse a legacy/user path into its one canonical workspace representation.\n * Leading/trailing and repeated separators are normalized; traversal and NUL\n * segments are rejected rather than resolved.\n */\nexport function parseWorkspacePath(input: string): WorkspacePath {\n if (\n [...input].some((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n return codePoint <= 0x1f || codePoint === 0x7f;\n })\n ) {\n throw invalidPath(input, 'Workspace paths must not contain NUL or other control characters.');\n }\n if (/^[a-zA-Z]:/u.test(input)) {\n throw new FsError('path-escape', 'Workspace paths must not be OS drive-qualified paths.', {\n operation: 'parse-path',\n path: input,\n });\n }\n\n const normalized = input\n .replace(/\\\\/g, '/')\n .replace(/\\/+/g, '/')\n .replace(/^\\/|\\/$/g, '');\n if (!normalized) return WORKSPACE_ROOT;\n\n const segments = normalized.split('/');\n if (segments.some((segment) => segment === '.' || segment === '..')) {\n throw new FsError('path-escape', 'Workspace paths must not contain \".\" or \"..\" segments.', {\n operation: 'parse-path',\n path: input,\n });\n }\n return normalized as WorkspacePath;\n}\n\nexport function tryParseWorkspacePath(input: unknown): WorkspacePath | null {\n if (typeof input !== 'string') return null;\n try {\n return parseWorkspacePath(input);\n } catch {\n return null;\n }\n}\n\n/** Convert a canonical path to the slash-prefixed form accepted by v1 providers. */\nexport function workspacePathToLegacy(path: WorkspacePath): string {\n return path ? `/${path}` : '/';\n}\n\nexport function workspacePathJoin(parent: WorkspacePath, child: string): WorkspacePath {\n const childPath = parseWorkspacePath(child);\n if (!parent) return childPath;\n if (!childPath) return parent;\n return parseWorkspacePath(`${parent}/${childPath}`);\n}\n\nexport function workspacePathDirname(path: WorkspacePath): WorkspacePath {\n if (!path) return WORKSPACE_ROOT;\n const slash = path.lastIndexOf('/');\n return slash < 0 ? WORKSPACE_ROOT : (path.slice(0, slash) as WorkspacePath);\n}\n\nexport function workspacePathBasename(path: WorkspacePath): string {\n if (!path) return '';\n const slash = path.lastIndexOf('/');\n return slash < 0 ? path : path.slice(slash + 1);\n}\n\nexport function workspacePathContains(\n parent: WorkspacePath,\n candidate: WorkspacePath,\n inclusive = true,\n): boolean {\n if (parent === candidate) return inclusive;\n if (!parent) return candidate !== WORKSPACE_ROOT;\n return candidate.startsWith(`${parent}/`);\n}\n\nfunction invalidPath(path: string, message: string): FsError {\n return new FsError('invalid-path', message, { operation: 'parse-path', path });\n}\n"],"mappings":"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","names":[]}
@@ -1,142 +0,0 @@
1
- import {
2
- getFileSystemProviderV2
3
- } from "./chunk-EZKJZUNJ.js";
4
-
5
- // src/workspace/workspace-manager.ts
6
- import { LocalForageAdapter } from "@bendyline/squisq/storage";
7
- var DB_NAME = "docblocks-workspaces";
8
- var STORE_NAME = "workspaces";
9
- var LIST_KEY = "workspace-list";
10
- var DEFAULT_WORKSPACE_ID = "default";
11
- var store = new LocalForageAdapter({
12
- name: DB_NAME,
13
- storeName: STORE_NAME
14
- });
15
- var transientWorkspaces = /* @__PURE__ */ new Map();
16
- function registerTransientWorkspace(descriptor, provider) {
17
- const previous = transientWorkspaces.get(descriptor.id);
18
- if (previous && previous.provider !== provider) {
19
- void getFileSystemProviderV2(previous.provider)?.dispose();
20
- }
21
- transientWorkspaces.set(descriptor.id, { descriptor, provider });
22
- }
23
- function getTransientWorkspace(id) {
24
- return transientWorkspaces.get(id) ?? null;
25
- }
26
- async function unregisterTransientWorkspace(id) {
27
- const entry = transientWorkspaces.get(id);
28
- if (!entry) return;
29
- transientWorkspaces.delete(id);
30
- await getFileSystemProviderV2(entry.provider)?.dispose();
31
- }
32
- async function listPersisted() {
33
- const list = await store.get(LIST_KEY);
34
- return list ?? [];
35
- }
36
- async function listWorkspaces() {
37
- const persisted = await listPersisted();
38
- const transient = [...transientWorkspaces.values()].map((t) => t.descriptor);
39
- return [...persisted, ...transient];
40
- }
41
- async function getWorkspace(id) {
42
- const transient = transientWorkspaces.get(id);
43
- if (transient) return transient.descriptor;
44
- const list = await listPersisted();
45
- return list.find((w) => w.id === id) ?? null;
46
- }
47
- async function saveWorkspace(workspace) {
48
- if (workspace.type === "transient") return;
49
- const list = await listPersisted();
50
- const idx = list.findIndex((w) => w.id === workspace.id);
51
- if (idx >= 0) {
52
- list[idx] = workspace;
53
- } else {
54
- list.push(workspace);
55
- }
56
- await store.set(LIST_KEY, list);
57
- }
58
- async function removeWorkspace(id) {
59
- if (transientWorkspaces.has(id)) {
60
- await unregisterTransientWorkspace(id);
61
- return;
62
- }
63
- const list = await listPersisted();
64
- const filtered = list.filter((w) => w.id !== id);
65
- await store.set(LIST_KEY, filtered);
66
- }
67
- async function touchWorkspace(id) {
68
- const transient = transientWorkspaces.get(id);
69
- if (transient) {
70
- transient.descriptor.lastOpened = (/* @__PURE__ */ new Date()).toISOString();
71
- return;
72
- }
73
- const list = await listPersisted();
74
- const workspace = list.find((w) => w.id === id);
75
- if (workspace) {
76
- workspace.lastOpened = (/* @__PURE__ */ new Date()).toISOString();
77
- await store.set(LIST_KEY, list);
78
- }
79
- }
80
- async function ensureDefaultWorkspace() {
81
- const existing = await getWorkspace(DEFAULT_WORKSPACE_ID);
82
- if (existing) return existing;
83
- const descriptor = {
84
- id: DEFAULT_WORKSPACE_ID,
85
- name: "My Documents",
86
- type: "indexeddb",
87
- lastOpened: (/* @__PURE__ */ new Date()).toISOString()
88
- };
89
- await saveWorkspace(descriptor);
90
- return descriptor;
91
- }
92
-
93
- // src/workspace/reconcile-electron.ts
94
- function comparableRoot(rootPath, platform) {
95
- const normalized = rootPath.replace(/\\/gu, "/").replace(/\/+$/gu, "");
96
- return platform === "win32" ? normalized.toLowerCase() : normalized;
97
- }
98
- function reconcileElectronWorkspaceDescriptors(local, hostWorkspaces, platform, now) {
99
- const electron = local.filter((workspace) => workspace.type === "electron-native");
100
- const matchedLocalIds = /* @__PURE__ */ new Set();
101
- const idRemap = {};
102
- const upsert = hostWorkspaces.map((hostWorkspace) => {
103
- const root = comparableRoot(hostWorkspace.rootPath, platform);
104
- const candidates = electron.filter(
105
- (workspace) => workspace.rootPath && comparableRoot(workspace.rootPath, platform) === root
106
- );
107
- const matching = candidates.sort(
108
- (left, right) => right.lastOpened.localeCompare(left.lastOpened)
109
- )[0];
110
- if (matching) {
111
- matchedLocalIds.add(matching.id);
112
- if (matching.id !== hostWorkspace.id) idRemap[matching.id] = hostWorkspace.id;
113
- }
114
- return {
115
- id: hostWorkspace.id,
116
- name: matching?.name ?? hostWorkspace.name,
117
- type: "electron-native",
118
- rootPath: hostWorkspace.rootPath,
119
- lastOpened: matching?.lastOpened ?? now,
120
- ...matching?.versioningOverride ? { versioningOverride: matching.versioningOverride } : {}
121
- };
122
- });
123
- const canonicalIds = new Set(hostWorkspaces.map((workspace) => workspace.id));
124
- const removeIds = electron.filter(
125
- (workspace) => !canonicalIds.has(workspace.id) || matchedLocalIds.has(workspace.id) && !upsert.some((candidate) => candidate.id === workspace.id)
126
- ).map((workspace) => workspace.id);
127
- return { removeIds, upsert, idRemap };
128
- }
129
-
130
- export {
131
- registerTransientWorkspace,
132
- getTransientWorkspace,
133
- unregisterTransientWorkspace,
134
- listWorkspaces,
135
- getWorkspace,
136
- saveWorkspace,
137
- removeWorkspace,
138
- touchWorkspace,
139
- ensureDefaultWorkspace,
140
- reconcileElectronWorkspaceDescriptors
141
- };
142
- //# sourceMappingURL=chunk-W5UUUII5.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/workspace/workspace-manager.ts","../src/workspace/reconcile-electron.ts"],"sourcesContent":["/**\n * WorkspaceManager — manages the list of known workspaces in IndexedDB\n * and provides helpers for creating / switching / removing them.\n *\n * The actual FileSystemProvider instances are created by the caller\n * (since native providers need a DirectoryHandle from user interaction).\n */\n\nimport { LocalForageAdapter } from '@bendyline/squisq/storage';\nimport { getFileSystemProviderV2, type FileSystemProvider } from '../filesystem/types.js';\nimport type { WorkspaceDescriptor } from './types.js';\n\nconst DB_NAME = 'docblocks-workspaces';\nconst STORE_NAME = 'workspaces';\nconst LIST_KEY = 'workspace-list';\nconst DEFAULT_WORKSPACE_ID = 'default';\n\nconst store = new LocalForageAdapter({\n name: DB_NAME,\n storeName: STORE_NAME,\n});\n\n/**\n * Session-only transient workspaces (a loose file or `.dbk` opened from the\n * OS). Kept purely in memory — never written to the persisted list — with\n * their pre-built provider registered alongside the descriptor. Lost on\n * reload, which is the intended \"transient for the app session\" behaviour.\n */\ninterface TransientEntry {\n descriptor: WorkspaceDescriptor;\n provider: FileSystemProvider;\n}\nconst transientWorkspaces = new Map<string, TransientEntry>();\n\n/** Register a transient workspace and its (already-built) provider. */\nexport function registerTransientWorkspace(\n descriptor: WorkspaceDescriptor,\n provider: FileSystemProvider,\n): void {\n const previous = transientWorkspaces.get(descriptor.id);\n if (previous && previous.provider !== provider) {\n void getFileSystemProviderV2(previous.provider)?.dispose();\n }\n transientWorkspaces.set(descriptor.id, { descriptor, provider });\n}\n\n/** Look up a transient workspace (descriptor + provider) by id, if any. */\nexport function getTransientWorkspace(\n id: string,\n): { descriptor: WorkspaceDescriptor; provider: FileSystemProvider } | null {\n return transientWorkspaces.get(id) ?? null;\n}\n\n/** Forget a transient workspace (e.g. when it is closed). */\nexport async function unregisterTransientWorkspace(id: string): Promise<void> {\n const entry = transientWorkspaces.get(id);\n if (!entry) return;\n transientWorkspaces.delete(id);\n await getFileSystemProviderV2(entry.provider)?.dispose();\n}\n\n/** The persisted (on-disk) workspace list only — excludes transient ones. */\nasync function listPersisted(): Promise<WorkspaceDescriptor[]> {\n const list = await store.get<WorkspaceDescriptor[]>(LIST_KEY);\n return list ?? [];\n}\n\n/**\n * Get all known workspace descriptors — persisted plus any session-only\n * transient ones (so they show in the picker and resolve for the session).\n */\nexport async function listWorkspaces(): Promise<WorkspaceDescriptor[]> {\n const persisted = await listPersisted();\n const transient = [...transientWorkspaces.values()].map((t) => t.descriptor);\n return [...persisted, ...transient];\n}\n\n/**\n * Get a specific workspace descriptor by id (transient or persisted).\n */\nexport async function getWorkspace(id: string): Promise<WorkspaceDescriptor | null> {\n const transient = transientWorkspaces.get(id);\n if (transient) return transient.descriptor;\n const list = await listPersisted();\n return list.find((w) => w.id === id) ?? null;\n}\n\n/**\n * Add or update a workspace descriptor. If a workspace with the same id\n * already exists, it is replaced. Transient workspaces are never persisted.\n */\nexport async function saveWorkspace(workspace: WorkspaceDescriptor): Promise<void> {\n if (workspace.type === 'transient') return;\n const list = await listPersisted();\n const idx = list.findIndex((w) => w.id === workspace.id);\n if (idx >= 0) {\n list[idx] = workspace;\n } else {\n list.push(workspace);\n }\n await store.set(LIST_KEY, list);\n}\n\n/**\n * Remove a workspace descriptor by id (transient or persisted).\n */\nexport async function removeWorkspace(id: string): Promise<void> {\n if (transientWorkspaces.has(id)) {\n await unregisterTransientWorkspace(id);\n return;\n }\n const list = await listPersisted();\n const filtered = list.filter((w) => w.id !== id);\n await store.set(LIST_KEY, filtered);\n}\n\n/**\n * Touch the lastOpened timestamp on a workspace. For transient workspaces this\n * updates the in-memory descriptor only (nothing is persisted).\n */\nexport async function touchWorkspace(id: string): Promise<void> {\n const transient = transientWorkspaces.get(id);\n if (transient) {\n transient.descriptor.lastOpened = new Date().toISOString();\n return;\n }\n const list = await listPersisted();\n const workspace = list.find((w) => w.id === id);\n if (workspace) {\n workspace.lastOpened = new Date().toISOString();\n await store.set(LIST_KEY, list);\n }\n}\n\n/**\n * Ensure a default IndexedDB workspace exists. Called on app startup.\n * Returns the descriptor.\n */\nexport async function ensureDefaultWorkspace(): Promise<WorkspaceDescriptor> {\n const existing = await getWorkspace(DEFAULT_WORKSPACE_ID);\n if (existing) return existing;\n\n const descriptor: WorkspaceDescriptor = {\n id: DEFAULT_WORKSPACE_ID,\n name: 'My Documents',\n type: 'indexeddb',\n lastOpened: new Date().toISOString(),\n };\n await saveWorkspace(descriptor);\n return descriptor;\n}\n","import type { ElectronWorkspaceInfo, HostEnvironment } from '../host/types.js';\nimport type { WorkspaceDescriptor } from './types.js';\n\nexport interface ElectronWorkspaceReconciliation {\n /** Obsolete renderer descriptors to remove before attempting restoration. */\n readonly removeIds: readonly string[];\n /** Canonical main-authorized descriptors to insert or replace. */\n readonly upsert: readonly WorkspaceDescriptor[];\n /** Safe navigation migration for a local descriptor matched by root. */\n readonly idRemap: Readonly<Record<string, string>>;\n}\n\nfunction comparableRoot(rootPath: string, platform: HostEnvironment['platform']): string {\n const normalized = rootPath.replace(/\\\\/gu, '/').replace(/\\/+$/gu, '');\n return platform === 'win32' ? normalized.toLowerCase() : normalized;\n}\n\n/**\n * Reconcile renderer IndexedDB metadata with the main process authority list.\n * `hostWorkspaces` is authoritative: local Electron descriptors absent from\n * it cannot be opened safely and are removed. Root-path matching carries user\n * metadata across an id migration without treating that display path as\n * authority.\n */\nexport function reconcileElectronWorkspaceDescriptors(\n local: readonly WorkspaceDescriptor[],\n hostWorkspaces: readonly ElectronWorkspaceInfo[],\n platform: HostEnvironment['platform'],\n now: string,\n): ElectronWorkspaceReconciliation {\n const electron = local.filter((workspace) => workspace.type === 'electron-native');\n const matchedLocalIds = new Set<string>();\n const idRemap: Record<string, string> = {};\n const upsert = hostWorkspaces.map((hostWorkspace): WorkspaceDescriptor => {\n const root = comparableRoot(hostWorkspace.rootPath, platform);\n const candidates = electron.filter(\n (workspace) => workspace.rootPath && comparableRoot(workspace.rootPath, platform) === root,\n );\n const matching = candidates.sort((left, right) =>\n right.lastOpened.localeCompare(left.lastOpened),\n )[0];\n if (matching) {\n matchedLocalIds.add(matching.id);\n if (matching.id !== hostWorkspace.id) idRemap[matching.id] = hostWorkspace.id;\n }\n return {\n id: hostWorkspace.id,\n name: matching?.name ?? hostWorkspace.name,\n type: 'electron-native',\n rootPath: hostWorkspace.rootPath,\n lastOpened: matching?.lastOpened ?? now,\n ...(matching?.versioningOverride ? { versioningOverride: matching.versioningOverride } : {}),\n };\n });\n const canonicalIds = new Set(hostWorkspaces.map((workspace) => workspace.id));\n const removeIds = electron\n .filter(\n (workspace) =>\n !canonicalIds.has(workspace.id) ||\n (matchedLocalIds.has(workspace.id) &&\n !upsert.some((candidate) => candidate.id === workspace.id)),\n )\n .map((workspace) => workspace.id);\n return { removeIds, upsert, idRemap };\n}\n"],"mappings":";;;;;AAQA,SAAS,0BAA0B;AAInC,IAAM,UAAU;AAChB,IAAM,aAAa;AACnB,IAAM,WAAW;AACjB,IAAM,uBAAuB;AAE7B,IAAM,QAAQ,IAAI,mBAAmB;AAAA,EACnC,MAAM;AAAA,EACN,WAAW;AACb,CAAC;AAYD,IAAM,sBAAsB,oBAAI,IAA4B;AAGrD,SAAS,2BACd,YACA,UACM;AACN,QAAM,WAAW,oBAAoB,IAAI,WAAW,EAAE;AACtD,MAAI,YAAY,SAAS,aAAa,UAAU;AAC9C,SAAK,wBAAwB,SAAS,QAAQ,GAAG,QAAQ;AAAA,EAC3D;AACA,sBAAoB,IAAI,WAAW,IAAI,EAAE,YAAY,SAAS,CAAC;AACjE;AAGO,SAAS,sBACd,IAC0E;AAC1E,SAAO,oBAAoB,IAAI,EAAE,KAAK;AACxC;AAGA,eAAsB,6BAA6B,IAA2B;AAC5E,QAAM,QAAQ,oBAAoB,IAAI,EAAE;AACxC,MAAI,CAAC,MAAO;AACZ,sBAAoB,OAAO,EAAE;AAC7B,QAAM,wBAAwB,MAAM,QAAQ,GAAG,QAAQ;AACzD;AAGA,eAAe,gBAAgD;AAC7D,QAAM,OAAO,MAAM,MAAM,IAA2B,QAAQ;AAC5D,SAAO,QAAQ,CAAC;AAClB;AAMA,eAAsB,iBAAiD;AACrE,QAAM,YAAY,MAAM,cAAc;AACtC,QAAM,YAAY,CAAC,GAAG,oBAAoB,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU;AAC3E,SAAO,CAAC,GAAG,WAAW,GAAG,SAAS;AACpC;AAKA,eAAsB,aAAa,IAAiD;AAClF,QAAM,YAAY,oBAAoB,IAAI,EAAE;AAC5C,MAAI,UAAW,QAAO,UAAU;AAChC,QAAM,OAAO,MAAM,cAAc;AACjC,SAAO,KAAK,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK;AAC1C;AAMA,eAAsB,cAAc,WAA+C;AACjF,MAAI,UAAU,SAAS,YAAa;AACpC,QAAM,OAAO,MAAM,cAAc;AACjC,QAAM,MAAM,KAAK,UAAU,CAAC,MAAM,EAAE,OAAO,UAAU,EAAE;AACvD,MAAI,OAAO,GAAG;AACZ,SAAK,GAAG,IAAI;AAAA,EACd,OAAO;AACL,SAAK,KAAK,SAAS;AAAA,EACrB;AACA,QAAM,MAAM,IAAI,UAAU,IAAI;AAChC;AAKA,eAAsB,gBAAgB,IAA2B;AAC/D,MAAI,oBAAoB,IAAI,EAAE,GAAG;AAC/B,UAAM,6BAA6B,EAAE;AACrC;AAAA,EACF;AACA,QAAM,OAAO,MAAM,cAAc;AACjC,QAAM,WAAW,KAAK,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AAC/C,QAAM,MAAM,IAAI,UAAU,QAAQ;AACpC;AAMA,eAAsB,eAAe,IAA2B;AAC9D,QAAM,YAAY,oBAAoB,IAAI,EAAE;AAC5C,MAAI,WAAW;AACb,cAAU,WAAW,cAAa,oBAAI,KAAK,GAAE,YAAY;AACzD;AAAA,EACF;AACA,QAAM,OAAO,MAAM,cAAc;AACjC,QAAM,YAAY,KAAK,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC9C,MAAI,WAAW;AACb,cAAU,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC9C,UAAM,MAAM,IAAI,UAAU,IAAI;AAAA,EAChC;AACF;AAMA,eAAsB,yBAAuD;AAC3E,QAAM,WAAW,MAAM,aAAa,oBAAoB;AACxD,MAAI,SAAU,QAAO;AAErB,QAAM,aAAkC;AAAA,IACtC,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,EACrC;AACA,QAAM,cAAc,UAAU;AAC9B,SAAO;AACT;;;AC1IA,SAAS,eAAe,UAAkB,UAA+C;AACvF,QAAM,aAAa,SAAS,QAAQ,QAAQ,GAAG,EAAE,QAAQ,UAAU,EAAE;AACrE,SAAO,aAAa,UAAU,WAAW,YAAY,IAAI;AAC3D;AASO,SAAS,sCACd,OACA,gBACA,UACA,KACiC;AACjC,QAAM,WAAW,MAAM,OAAO,CAAC,cAAc,UAAU,SAAS,iBAAiB;AACjF,QAAM,kBAAkB,oBAAI,IAAY;AACxC,QAAM,UAAkC,CAAC;AACzC,QAAM,SAAS,eAAe,IAAI,CAAC,kBAAuC;AACxE,UAAM,OAAO,eAAe,cAAc,UAAU,QAAQ;AAC5D,UAAM,aAAa,SAAS;AAAA,MAC1B,CAAC,cAAc,UAAU,YAAY,eAAe,UAAU,UAAU,QAAQ,MAAM;AAAA,IACxF;AACA,UAAM,WAAW,WAAW;AAAA,MAAK,CAAC,MAAM,UACtC,MAAM,WAAW,cAAc,KAAK,UAAU;AAAA,IAChD,EAAE,CAAC;AACH,QAAI,UAAU;AACZ,sBAAgB,IAAI,SAAS,EAAE;AAC/B,UAAI,SAAS,OAAO,cAAc,GAAI,SAAQ,SAAS,EAAE,IAAI,cAAc;AAAA,IAC7E;AACA,WAAO;AAAA,MACL,IAAI,cAAc;AAAA,MAClB,MAAM,UAAU,QAAQ,cAAc;AAAA,MACtC,MAAM;AAAA,MACN,UAAU,cAAc;AAAA,MACxB,YAAY,UAAU,cAAc;AAAA,MACpC,GAAI,UAAU,qBAAqB,EAAE,oBAAoB,SAAS,mBAAmB,IAAI,CAAC;AAAA,IAC5F;AAAA,EACF,CAAC;AACD,QAAM,eAAe,IAAI,IAAI,eAAe,IAAI,CAAC,cAAc,UAAU,EAAE,CAAC;AAC5E,QAAM,YAAY,SACf;AAAA,IACC,CAAC,cACC,CAAC,aAAa,IAAI,UAAU,EAAE,KAC7B,gBAAgB,IAAI,UAAU,EAAE,KAC/B,CAAC,OAAO,KAAK,CAAC,cAAc,UAAU,OAAO,UAAU,EAAE;AAAA,EAC/D,EACC,IAAI,CAAC,cAAc,UAAU,EAAE;AAClC,SAAO,EAAE,WAAW,QAAQ,QAAQ;AACtC;","names":[]}