Explorar el Código

fix(web): satisfy contracts-ready lint and dedup the stable-file read

Rescope nothing new: drop the needless async from the inherited readRaw
default (reject explicitly on abort), fix the void arrow shorthand in
downloadBlob, and share one revision-stable file-read loop between readRaw
and readPrefix in the JSONL backend.
_Kerman hace 1 mes
padre
commit
3a6112f641

+ 1 - 1
packages/client/ui-trajectory/src/client/export-log.ts

@@ -38,5 +38,5 @@ export function downloadBlob(blob: Blob, filename: string): void {
   anchor.download = filename
   anchor.click()
   // Revoke one tick later: some browsers read the blob URL after click().
-  setTimeout(() => URL.revokeObjectURL(url), 0)
+  setTimeout(() => { URL.revokeObjectURL(url) }, 0)
 }

+ 23 - 23
packages/session/session-persistence-jsonl/src/index.ts

@@ -253,17 +253,7 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi
     signal?.throwIfAborted()
     const path = await this.findLog(id, signal)
     if (path === undefined) return undefined
-    let buffer: Buffer
-    // Revision-stable read: a writer appending between stat and readFile
-    // would yield a torn physical file (see readPrefix).
-    for (;;) {
-      signal?.throwIfAborted()
-      const before = fileRevision(await stat(path, { bigint: true }))
-      buffer = await readFile(path, { signal })
-      signal?.throwIfAborted()
-      const after = fileRevision(await stat(path, { bigint: true }))
-      if (before === after) break
-    }
+    const { buffer } = await this.readStableFile(path, signal)
     let content: string
     if (this.compression === 'zstd') {
       const { frames } = scanZstdFrames(buffer)
@@ -290,27 +280,37 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi
   }
 
   /**
-   * Read a stored prefix and convert torn-tail state to the opaque marker the
-   * coordinator can round-trip without knowing the physical encoding.
+   * Read a file's bytes under a revision-stable loop: a writer appending
+   * between stat and readFile would yield a torn physical file, so retry
+   * while the stat revision changes.
+   * @param path - the artifact file to read.
+   * @param signal - optional cancellation for the stat/read work.
+   * @returns the stable bytes and the revision that matched both stats.
    */
-  private async readPrefix(
+  private async readStableFile(
     path: string,
-    expectedId?: SessionId,
     signal?: AbortSignal,
-  ): Promise<StoredPrefix<JsonlTornMarker>> {
-    let buffer: Buffer
-    let revision: PersistenceRevision
+  ): Promise<{ buffer: Buffer; revision: PersistenceRevision }> {
     for (;;) {
       signal?.throwIfAborted()
       const before = fileRevision(await stat(path, { bigint: true }))
-      buffer = await readFile(path, { signal })
+      const buffer = await readFile(path, { signal })
       signal?.throwIfAborted()
       const after = fileRevision(await stat(path, { bigint: true }))
-      if (before === after) {
-        revision = after
-        break
-      }
+      if (before === after) return { buffer, revision: after }
     }
+  }
+
+  /**
+   * Read a stored prefix and convert torn-tail state to the opaque marker the
+   * coordinator can round-trip without knowing the physical encoding.
+   */
+  private async readPrefix(
+    path: string,
+    expectedId?: SessionId,
+    signal?: AbortSignal,
+  ): Promise<StoredPrefix<JsonlTornMarker>> {
+    const { buffer, revision } = await this.readStableFile(path, signal)
     let prefix: Omit<StoredPrefix<JsonlTornMarker>, 'revision'>
     try {
       if (this.compression === 'zstd') {

+ 3 - 3
packages/session/session-persistence/src/index.ts

@@ -108,9 +108,9 @@ export abstract class SessionPersistence extends Service {
    * @returns the raw artifact plus its parsed header, or `undefined` when the
    * session is absent or the backend owns no per-session artifact.
    */
-  async readRaw(_id: SessionId, signal?: AbortSignal): Promise<SessionRawArtifact | undefined> {
-    signal?.throwIfAborted()
-    return undefined
+  readRaw(_id: SessionId, signal?: AbortSignal): Promise<SessionRawArtifact | undefined> {
+    if (signal?.aborted === true) return Promise.reject(signal.reason)
+    return Promise.resolve(undefined)
   }
 
   /**