sovereign-harness / src /worm.mjs
SNAPKITTYWEST's picture
push from SNAPKITTYWEST/sovereign-harness
afe5a51 verified
Raw History Blame Contribute Delete
1.54 kB
// src/worm.mjs
// Browser WORM chain — SHA-256 sealed, localStorage persisted
// Matches snapkitty-shell/src/worm/chain.mjs semantics
export class WormChain {
constructor(namespace = 'sovereign') {
this.key = `sk-worm-${namespace}`
this.prev = this._loadLast()
}
_loadLast() {
try {
const chain = JSON.parse(localStorage.getItem(this.key) || '[]')
return chain.length ? chain.at(-1).seal : '0'.repeat(64)
} catch { return '0'.repeat(64) }
}
async seal(event, payload) {
const chain = JSON.parse(localStorage.getItem(this.key) || '[]')
const ts = Date.now()
const raw = JSON.stringify({ event, payload, ts, prev: this.prev })
const seal = await this._sha256(raw)
chain.push({ seq: chain.length, event, ts, prev: this.prev, seal })
localStorage.setItem(this.key, JSON.stringify(chain))
this.prev = seal
return seal
}
verify() {
const chain = JSON.parse(localStorage.getItem(this.key) || '[]')
for (let i = 1; i < chain.length; i++) {
if (chain[i].prev !== chain[i - 1].seal)
return { valid: false, length: chain.length, broken: i }
}
return { valid: true, length: chain.length }
}
length() {
return JSON.parse(localStorage.getItem(this.key) || '[]').length
}
async _sha256(str) {
const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str))
return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2,'0')).join('')
}
}