// OverlayRepoSubstrate — present an OverlayRepoStore as the KV substrate RepoBase expects
// (`{ set, del, get, list, listNow }`), so RepoBase's record ops read/write content-addressed
// FILES instead of an append-only autobase. This is the seam that moves the multi-DID path's
// records off the StateBase (see hyper-proto-peer/docs/DESIGN-multidid-record-decoupling.md).
//
// RepoBase keys are "<collection>/<rkey>" (the FIRST "/" separates; atproto NSIDs + rkeys forbid
// "/"). Reserved "__"-prefixed / single-segment control keys (__members__, __commit__/<rev>, …)
// NEVER reach here — swarm-device writes those directly to the StateBase — so this substrate is
// records-only and throws on a non-record key (fail-loud if that assumption is ever violated).
//
// listNow == list: file reads are always current, so there is no blocking base.update() to avoid
// (RepoBase.listRecords({now:true}) uses listNow for its liveness-critical, non-blocking path).
const SEP = '/'
function split (key) {
const k = String(key)
const i = k.indexOf(SEP)
if (i < 0) throw new Error('OverlayRepoSubstrate: expected a "collection/rkey" record key, got ' + JSON.stringify(key))
return { collection: k.slice(0, i), rkey: k.slice(i + 1) }
}
export class OverlayRepoSubstrate {
constructor (store) {
if (!store || typeof store.put !== 'function' || typeof store.records !== 'function') {
throw new Error('OverlayRepoSubstrate: an OverlayRepoStore (put/get/del/records) is required')
}
this.store = store
}
async set (key, value) { const { collection, rkey } = split(key); await this.store.put(collection, rkey, value) }
async del (key) { const { collection, rkey } = split(key); await this.store.del(collection, rkey) }
async get (key) { const { collection, rkey } = split(key); return this.store.get(collection, rkey) }
// Return { key: record } for every record whose key starts with `prefix` ("" = all,
// "<collection>/" = one collection) — the shape RepoBase.listRecords folds over.
async list (prefix = '') {
const out = {}
for (const { key, record } of await this.store.records()) if (key.startsWith(prefix)) out[key] = record
return out
}
async listNow (prefix = '') { return this.list(prefix) } // files are always current — no base.update() to block on
}