Browse Source

style(storage,workspace): satisfy the repository lint gate

eslint --fix formatting sweep plus the manual residue: sync method
bodies drop async behind Promise-returning signatures (the sqlite unit
routes primitives through a settle() guard preserving the never-throws-
synchronously contract), catch callbacks type their reason as unknown,
loadAll's global slot is plain unknown (null semantics stay in JSDoc),
a non-null assertion becomes a narrowing, and unsafe any assignments in
tests gain explicit types. One justified eslint-disable for
prefer-promise-reject-errors follows the core/session precedent —
wrapping would discard the original StorageError code.
imccyu 2 months ago
parent
commit
2e986ee1e3

+ 4 - 4
packages/storage/domain/src/domain.ts

@@ -164,9 +164,9 @@ export class DomainImpl {
     const host: TableHost = {
       domainName: spec.name,
       unit,
-      enqueue: (job) => this.enqueue(job),
-      assertReadable: () => this.assertReadable(),
-      emitChanged: (change) => this.ctx.emit('domain/changed', change),
+      enqueue: job => this.enqueue(job),
+      assertReadable: () => { this.assertReadable() },
+      emitChanged: (change) => { this.ctx.emit('domain/changed', change) },
     }
     for (const [table, tableRecords] of records) {
       this.tables.set(table, new KvTableImpl(host, table, tableRecords))
@@ -178,7 +178,7 @@ export class DomainImpl {
           this.assertReadable()
           return this.globalValue
         },
-        set: (value) => this.enqueue(async () => {
+        set: value => this.enqueue(async () => {
           await this.unit.setGlobal(value)
           this.globalValue = value
           host.emitChanged({ domain: this.name, table: '', key: '', operation: 'put', value })

+ 4 - 3
packages/storage/domain/src/index.ts

@@ -113,11 +113,12 @@ export class DomainFacility {
         }
         // A null stored global means "never written": serve `initial` without
         // materializing it — the first `set` writes.
-        const globalValue = spec.global === undefined
+        const globalSpec = spec.global
+        const globalValue = globalSpec === undefined
           ? undefined
           : snapshot.global === null
-            ? spec.global.initial
-            : parseRecord(spec.name, '', '', () => spec.global!.schema.parse(snapshot.global))
+            ? globalSpec.initial
+            : parseRecord(spec.name, '', '', () => globalSpec.schema.parse(snapshot.global))
         const domain = new DomainImpl(this.ctx, spec, unit, tables, globalValue)
         // The open-domain table entry is itself the effect: registration and
         // the drain-then-unlist teardown live in one closure.

+ 1 - 1
packages/storage/domain/src/spec.ts

@@ -45,7 +45,7 @@ export interface DomainSpec {
 
 /** Key type of one declared table, recovered from its phantom carrier. */
 export type TableKeyOf<S extends DomainSpec, N extends keyof S['tables']> =
-  S['tables'][N] extends DomainTableSpec<infer K, unknown> ? K : never
+  S['tables'][N] extends DomainTableSpec<infer K> ? K : never
 
 /** Value type of one declared table. */
 export type TableValueOf<S extends DomainSpec, N extends keyof S['tables']> =

+ 5 - 5
packages/storage/domain/tests/domain.spec.ts

@@ -174,14 +174,14 @@ describe('KvTable writes', () => {
     const table = (await facility.open(spec)).table('items')
     await table.put('counter', { label: 'c', count: 0 })
     await Promise.all(Array.from({ length: 50 }, () =>
-      table.update('counter', (current) => ({ ...current, count: current.count + 1 }))))
+      table.update('counter', current => ({ ...current, count: current.count + 1 }))))
     expect(table.get('counter')).toEqual({ label: 'c', count: 50 })
   })
 
   it('update rejects a missing key; delete reports prior existence', async () => {
     const { facility } = await harness()
     const table = (await facility.open(spec)).table('items')
-    await expect(table.update('ghost', (v) => v)).rejects.toMatchObject({ code: 'missing-key' })
+    await expect(table.update('ghost', v => v)).rejects.toMatchObject({ code: 'missing-key' })
     await table.put('a', { label: 'x', count: 1 })
     await expect(table.delete('a')).resolves.toBe(true)
     await expect(table.delete('a')).resolves.toBe(false)
@@ -192,7 +192,7 @@ describe('KvTable writes', () => {
     const domain = await facility.open(spec)
     const table = domain.table('items')
     await table.put('a', { label: 'x', count: 1 })
-    await table.update('a', (current) => ({ ...current, count: 2 }))
+    await table.update('a', current => ({ ...current, count: 2 }))
     await table.delete('a')
     await table.delete('a') // no event: already absent
     await domain.global.set({ theme: 'dark' })
@@ -216,7 +216,7 @@ describe('durability failure', () => {
 
     pool.failNextWrites = 3
     await expect(table.put('a', { label: 'x', count: 99 })).rejects.toThrow(/injected/)
-    await expect(table.update('a', (c) => ({ ...c, count: c.count + 1 }))).rejects.toThrow(/injected/)
+    await expect(table.update('a', c => ({ ...c, count: c.count + 1 }))).rejects.toThrow(/injected/)
     await expect(table.delete('a')).rejects.toThrow(/injected/)
 
     // Reads still serve the pre-failure record; no events leaked.
@@ -225,7 +225,7 @@ describe('durability failure', () => {
     expect(changes).toHaveLength(seen)
 
     // The chain survives rejections: the next write lands cleanly with no residue.
-    await table.update('a', (c) => ({ ...c, count: c.count + 1 }))
+    await table.update('a', c => ({ ...c, count: c.count + 1 }))
     expect(table.get('a')).toEqual({ label: 'x', count: 2 })
   })
 

+ 3 - 3
packages/storage/domain/tests/helpers/memory-backend.ts

@@ -18,10 +18,10 @@
 import { StorageError } from '@deepseek-ai/dsh-storage'
 import type { KvFacet, KvUnit, KvUnitDescriptor, StorageBackend } from '@deepseek-ai/dsh-storage'
 
-/** One unit's medium: tables of records plus the global slot. */
+/** One unit's medium: tables of records plus the global slot (`null` = never written). */
 export interface MemoryMedium {
   tables: Map<string, Map<string, unknown>>
-  global: unknown | null
+  global: unknown
 }
 
 /**
@@ -70,7 +70,7 @@ class MemoryKvUnit implements KvUnit {
     }
   }
 
-  async loadAll(): Promise<{ tables: Record<string, Record<string, unknown>>; global: unknown | null }> {
+  async loadAll(): Promise<{ tables: Record<string, Record<string, unknown>>; global: unknown }> {
     this.assertOpen()
     const tables: Record<string, Record<string, unknown>> = {}
     for (const table of this.descriptor.tables) {

+ 12 - 12
packages/storage/domain/tests/invariant.spec.ts

@@ -29,7 +29,7 @@ async function setup() {
   return { ctx, facility }
 }
 
-const invariantViolation = expect.objectContaining<Partial<InvariantError>>({
+const invariantViolation: unknown = expect.objectContaining<Partial<InvariantError>>({
   code: 'INVARIANT',
   packageName: '@deepseek-ai/dsh-domain',
 })
@@ -40,42 +40,42 @@ describe('domain change-event invariants', () => {
     const domain = await facility.open(spec)
     const rows = domain.table('rows')
     await rows.put('a', { n: 1 })
-    await rows.update('a', (current) => ({ n: current.n + 1 }))
+    await rows.update('a', current => ({ n: current.n + 1 }))
     await expect(rows.delete('a')).resolves.toBe(true)
     await domain.global.set({ n: 5 })
   })
 
   it('rejects an event for a domain that is not open', async () => {
     const { ctx } = await setup()
-    expect(() => ctx.emit('domain/changed', {
+    expect(() => { ctx.emit('domain/changed', {
       domain: 'ghost', table: 'rows', key: 'a', operation: 'put', value: { n: 1 },
-    })).toThrow(invariantViolation)
+    }) }).toThrow(invariantViolation)
   })
 
   it('rejects a put event whose value is not the in-memory record', async () => {
     const { ctx, facility } = await setup()
     const domain = await facility.open(spec)
     await domain.table('rows').put('a', { n: 1 })
-    expect(() => ctx.emit('domain/changed', {
+    expect(() => { ctx.emit('domain/changed', {
       domain: 'inv', table: 'rows', key: 'a', operation: 'put', value: { n: 999 },
-    })).toThrow(invariantViolation)
+    }) }).toThrow(invariantViolation)
   })
 
   it('rejects a deletion event while the record is still in memory', async () => {
     const { ctx, facility } = await setup()
     const domain = await facility.open(spec)
     await domain.table('rows').put('a', { n: 1 })
-    expect(() => ctx.emit('domain/changed', {
+    expect(() => { ctx.emit('domain/changed', {
       domain: 'inv', table: 'rows', key: 'a', operation: 'deleted',
-    })).toThrow(invariantViolation)
+    }) }).toThrow(invariantViolation)
   })
 
   it('rejects a global event whose value is not the in-memory global', async () => {
     const { ctx, facility } = await setup()
     await facility.open(spec)
-    expect(() => ctx.emit('domain/changed', {
+    expect(() => { ctx.emit('domain/changed', {
       domain: 'inv', table: '', key: '', operation: 'put', value: { n: 42 },
-    })).toThrow(invariantViolation)
+    }) }).toThrow(invariantViolation)
   })
 
   it('tolerates operations outside the closed union without failing falsely', async () => {
@@ -84,8 +84,8 @@ describe('domain change-event invariants', () => {
     await domain.table('rows').put('a', { n: 1 })
     // Merge-hostile input: the closed union's satisfies-never default arm is
     // unreachable in typed code; an untyped emit must not crash the check.
-    expect(() => ctx.emit('domain/changed', {
+    expect(() => { ctx.emit('domain/changed', {
       domain: 'inv', table: 'rows', key: 'a', operation: 'exotic',
-    } as unknown as DomainChanged)).not.toThrow()
+    } as unknown as DomainChanged) }).not.toThrow()
   })
 })

+ 2 - 2
packages/storage/storage-json/src/format.ts

@@ -8,10 +8,10 @@
 import { StorageError } from '@deepseek-ai/dsh-storage'
 import type { KvUnitDescriptor } from '@deepseek-ai/dsh-storage'
 
-/** In-memory authoritative state of one unit; the file is its projection. */
+/** In-memory authoritative state of one unit; the file is its projection. `global` is `null` until first written. */
 export interface UnitState {
   version: number
-  global: unknown | null
+  global: unknown
   tables: Map<string, Map<string, unknown>>
 }
 

+ 9 - 9
packages/storage/storage-json/src/unit.ts

@@ -36,10 +36,10 @@ export async function openJsonUnit(
   const state: UnitState =
     text === undefined
       ? {
-          version: descriptor.version,
-          global: null,
-          tables: new Map(descriptor.tables.map((table) => [table, new Map()])),
-        }
+        version: descriptor.version,
+        global: null,
+        tables: new Map(descriptor.tables.map(table => [table, new Map<string, unknown>()])),
+      }
       : parse(text, descriptor)
   return new JsonKvUnit(descriptor, path, state, onClose)
 }
@@ -56,13 +56,13 @@ class JsonKvUnit implements KvUnit {
     private readonly onClose: () => void,
   ) {}
 
-  async loadAll(): Promise<{ tables: Record<string, Record<string, unknown>>; global: unknown | null }> {
+  loadAll(): Promise<{ tables: Record<string, Record<string, unknown>>; global: unknown }> {
     this.assertOpen()
     const tables: Record<string, Record<string, unknown>> = {}
     for (const [table, records] of this.state.tables) {
       tables[table] = Object.fromEntries(records)
     }
-    return { tables, global: this.state.global }
+    return Promise.resolve({ tables, global: this.state.global })
   }
 
   async putRecord(table: string, key: string, value: unknown): Promise<void> {
@@ -73,7 +73,7 @@ class JsonKvUnit implements KvUnit {
     records.set(key, value)
     // Roll back on a failed publish: memory is authoritative, so a rejected
     // write must not survive in memory (or ride along with the next publish).
-    await this.publish().catch(async (error) => {
+    await this.publish().catch((error: unknown) => {
       if (hadKey) records.set(key, previous)
       else records.delete(key)
       throw error
@@ -86,7 +86,7 @@ class JsonKvUnit implements KvUnit {
     if (!records.has(key)) return
     const previous = records.get(key)
     records.delete(key)
-    await this.publish().catch(async (error) => {
+    await this.publish().catch((error: unknown) => {
       records.set(key, previous)
       throw error
     })
@@ -99,7 +99,7 @@ class JsonKvUnit implements KvUnit {
     }
     const previous = this.state.global
     this.state.global = value
-    await this.publish().catch(async (error) => {
+    await this.publish().catch((error: unknown) => {
       this.state.global = previous
       throw error
     })

+ 6 - 4
packages/storage/storage-json/tests/json-backend.spec.ts

@@ -78,7 +78,7 @@ describe('json backend specifics', () => {
     const root = await freshRoot()
     const backend = new JsonStorageBackend(root)
     await backend.kv.open(descriptor)
-    await expect(backend.kv.open(descriptor)).rejects.toThrowError(/already open/)
+    await expect(backend.kv.open(descriptor)).rejects.toThrow(/already open/)
     await backend.close()
   })
 
@@ -208,13 +208,15 @@ describe('json backend specifics', () => {
     const bigWrite = unit.putRecord('t', 'big', { blob: 'x'.repeat(4 * 1024 * 1024) })
     await unit.close()
     await expect(bigWrite).resolves.toBeUndefined()
-    const onDisk = JSON.parse(await readFile(join(root, 'shape.json'), 'utf8'))
-    expect(onDisk.tables.t.big).toBeDefined()
+    const onDisk = JSON.parse(await readFile(join(root, 'shape.json'), 'utf8')) as {
+      tables: Record<string, Record<string, unknown>>
+    }
+    expect(onDisk.tables['t']?.['big']).toBeDefined()
 
     const backend2 = new JsonStorageBackend(root)
     const opening = backend2.kv.open(descriptor)
     const closing = backend2.close()
-    await expect(opening.then((u) => u.putRecord('t', 'x', {}))).rejects.toMatchObject({ code: 'closed' })
+    await expect(opening.then(u => u.putRecord('t', 'x', {}))).rejects.toMatchObject({ code: 'closed' })
     await closing
   })
 })

+ 53 - 32
packages/storage/storage-sqlite/src/unit.ts

@@ -62,24 +62,25 @@ export class SqliteKvUnit implements KvUnit {
       : undefined
   }
 
-  async loadAll(): Promise<{ tables: Record<string, Record<string, unknown>>; global: unknown | null }> {
-    this.ensureOpen()
-    const tables: Record<string, Record<string, unknown>> = {}
-    for (const [name, statements] of this.tables) {
-      // Null prototype: record keys are arbitrary strings, so '__proto__'
-      // must land as an own property instead of mutating the prototype.
-      const records: Record<string, unknown> = Object.create(null) as Record<string, unknown>
-      for (const row of statements.selectAll.all() as unknown as Array<{ key: string; value: string }>) {
-        records[row.key] = this.parseValue(row.value, `table '${name}' key '${row.key}'`)
+  loadAll(): Promise<{ tables: Record<string, Record<string, unknown>>; global: unknown }> {
+    return this.settle(() => {
+      const tables: Record<string, Record<string, unknown>> = {}
+      for (const [name, statements] of this.tables) {
+        // Null prototype: record keys are arbitrary strings, so '__proto__'
+        // must land as an own property instead of mutating the prototype.
+        const records: Record<string, unknown> = Object.create(null) as Record<string, unknown>
+        for (const row of statements.selectAll.all() as unknown as Array<{ key: string; value: string }>) {
+          records[row.key] = this.parseValue(row.value, `table '${name}' key '${row.key}'`)
+        }
+        tables[name] = records
       }
-      tables[name] = records
-    }
-    let global: unknown = null
-    if (this.globalSelect !== undefined) {
-      const row = this.globalSelect.get(this.descriptor.name) as { value: string } | undefined
-      if (row !== undefined) global = this.parseValue(row.value, 'global slot')
-    }
-    return { tables, global }
+      let global: unknown = null
+      if (this.globalSelect !== undefined) {
+        const row = this.globalSelect.get(this.descriptor.name) as { value: string } | undefined
+        if (row !== undefined) global = this.parseValue(row.value, 'global slot')
+      }
+      return { tables, global }
+    })
   }
 
   /** Parse one stored value column, mapping bad JSON to `malformed-medium`. */
@@ -95,28 +96,48 @@ export class SqliteKvUnit implements KvUnit {
     }
   }
 
-  async putRecord(table: string, key: string, value: unknown): Promise<void> {
-    this.ensureOpen()
-    this.statementsFor(table).upsert.run(key, JSON.stringify(value))
+  putRecord(table: string, key: string, value: unknown): Promise<void> {
+    return this.settle(() => {
+      this.statementsFor(table).upsert.run(key, JSON.stringify(value))
+    })
   }
 
-  async deleteRecord(table: string, key: string): Promise<void> {
-    this.ensureOpen()
-    this.statementsFor(table).remove.run(key)
+  deleteRecord(table: string, key: string): Promise<void> {
+    return this.settle(() => {
+      this.statementsFor(table).remove.run(key)
+    })
+  }
+
+  setGlobal(value: unknown): Promise<void> {
+    return this.settle(() => {
+      if (this.globalUpsert === undefined) {
+        throw new Error(`kv unit '${this.descriptor.name}' declared no global slot`)
+      }
+      this.globalUpsert.run(this.descriptor.name, JSON.stringify(value))
+    })
   }
 
-  async setGlobal(value: unknown): Promise<void> {
-    this.ensureOpen()
-    if (this.globalUpsert === undefined) {
-      throw new Error(`kv unit '${this.descriptor.name}' declared no global slot`)
+  close(): Promise<void> {
+    if (!this.closed) {
+      this.closed = true
+      this.onClose()
     }
-    this.globalUpsert.run(this.descriptor.name, JSON.stringify(value))
+    return Promise.resolve()
   }
 
-  async close(): Promise<void> {
-    if (this.closed) return
-    this.closed = true
-    this.onClose()
+  /**
+   * Run one synchronous primitive behind the closed guard, mapping a throw to
+   * a rejection so the Promise-returning contract never throws synchronously.
+   */
+  private settle<T>(operation: () => T): Promise<T> {
+    try {
+      this.ensureOpen()
+      return Promise.resolve(operation())
+    } catch (error) {
+      // Non-Error throws can only enter through JSON.stringify propagating a
+      // value's own toJSON throw; wrap those, preserve every real Error.
+      return Promise.reject(error instanceof Error ? error : new Error(String(error)))
+    }
   }
 
   private ensureOpen(): void {

+ 11 - 0
packages/storage/storage-sqlite/tests/sqlite-backend.spec.ts

@@ -171,6 +171,17 @@ describe('sqlite backend specifics', () => {
     await reopened.close()
   })
 
+  it('wraps a non-Error toJSON throw into an Error rejection', async () => {
+    const backend = backendAt(':memory:')
+    const unit = await backend.kv.open(DESCRIPTOR)
+    // JSON.stringify propagates a value's own toJSON throw verbatim; the unit
+    // must still reject with an Error instance.
+    const hostile = { toJSON: () => { throw 'not an error' } }
+    await expect(unit.putRecord('records', 'k', hostile)).rejects.toThrow('not an error')
+    await expect(unit.putRecord('records', 'k', hostile)).rejects.toBeInstanceOf(Error)
+    await backend.close()
+  })
+
   it('rejects setGlobal on a unit without a global slot and writes to undeclared tables', async () => {
     const backend = backendAt(':memory:')
     const unit = await backend.kv.open({ ...DESCRIPTOR, hasGlobal: false })

+ 1 - 1
packages/storage/storage/src/backend.ts

@@ -69,7 +69,7 @@ export interface KvUnit {
    * @returns every table's records keyed by table name, plus the global
    * singleton (`null` when never written or not declared).
    */
-  loadAll(): Promise<{ tables: Record<string, Record<string, unknown>>; global: unknown | null }>
+  loadAll(): Promise<{ tables: Record<string, Record<string, unknown>>; global: unknown }>
 
   /**
    * Upsert one record durably. Overwrite semantics: an existing key is replaced.

+ 1 - 1
packages/storage/storage/src/index.ts

@@ -76,7 +76,7 @@ export class Storage extends Service {
 
   /** Domain data form; present once the domain layer plugin is loaded. */
   get domain(): StorageForms extends { domain: infer D } ? D : never {
-    return this.form('domain' as keyof StorageForms) as StorageForms extends { domain: infer D } ? D : never
+    return this.form('domain' as keyof StorageForms)
   }
 }
 

+ 1 - 1
packages/storage/storage/tests/registry.spec.ts

@@ -69,7 +69,7 @@ expect.extend({
       received()
     } catch (error) {
       const pass = Object.entries(expected).every(
-        (entry) => (error as Record<string, unknown>)[entry[0]] === entry[1],
+        entry => (error as Record<string, unknown>)[entry[0]] === entry[1],
       )
       return { pass, message: () => `expected thrown error to match ${JSON.stringify(expected)}, got ${String(error)}` }
     }