Autobase
Multi-writer linearization layer for building deterministic views from many Hypercores.
Autobase is a higher-level composition over underlying Hypercores. Writers append causal nodes to local cores, Autobase linearizes that graph into an eventually consistent order, and your apply handler materializes a deterministic view, often into a Hyperbee.
Install
npm i autobaseQuickstart
This minimal flow opens a view, appends one record, updates the linearizer, and reads the materialized value back from base.view.
import Corestore from 'corestore'
import Autobase from 'autobase'
const store = new Corestore('./autobase-demo')
const base = new Autobase(store, null, {
open: (viewStore) => viewStore.get({ name: 'messages', valueEncoding: 'json' }),
apply: async (nodes, view) => {
for (const { value } of nodes) await view.append(value)
}
})
await base.ready()
await base.append({ type: 'message', text: 'hello from Autobase' })
await base.update()
console.log(await base.view.get(0))
// { type: 'message', text: 'hello from Autobase' }Autobase can reorder previously seen nodes as new causal information arrives. Keep open and apply deterministic, derive state from the provided store, and mutate only the provided view inside apply.
API Reference
Constructor and lifecycle
new Autobase(store, bootstrap, opts)
- Signature:
const base = new Autobase(store, bootstrap, opts)(GitHub) - Parameters (GitHub):
store: theCorestorethat manages Autobase system, writer, and view cores.bootstrap: an existing Autobase key when reopening a base; omit it or passnullto create a new one.opts: configuration for view creation and linearization.open(store, host): creates the view from the passed store.apply(nodes, view, host): deterministically applies linearized nodes into the view.optimistic: enables optimistic appends from non-writers that are later acknowledged.close(view): closes the view when Autobase closes it.valueEncoding: encoding for appended values.ackInterval: auto-ack interval in milliseconds.encryptionKey: promise or buffer used to encrypt the base.encrypt: encrypt the base if it is currently unencrypted and no key is provided.encrypted: require the base to be encrypted.fastForward: enable fast-forwarding to a quorum-signed state.wakeup: custom wakeup protocol implementation.bigBatches: enables largerapplybatches.
- Returns: a new
Autobaseinstance. (GitHub) - Example:
const base = new Autobase(store, null, { open, apply })
When optimistic is enabled, validate optimistic blocks inside apply before calling host.ackWriter(key). Otherwise any peer that can write to the underlying network path could attempt to inject values.
await base.ready()
- Signature:
await base.ready()(GitHub) - Parameters: none. (GitHub)
- Returns: a promise that resolves when the base and its view are ready to use. (GitHub)
- Example:
await base.ready()
State and derived view
base.key: primary key for the Autobase. Example:const bootstrap = base.keybase.discoveryKey: discovery key associated with the Autobase. Example:swarm.join(base.discoveryKey)base.isIndexer:truewhen this instance is acting as an indexer. Example:if (base.isIndexer) await base.ack()base.writable:truewhen this instance can append as a writer. Example:if (base.writable) await base.append(value)base.view: the materialized view returned byopen. Example:const row = await base.view.get(0)base.length: length of the Autobase system core, not the writer or view length. Example:console.log(base.length)base.signedLength: highest quorum-signed system index that will not be reordered. Example:console.log(base.signedLength)base.paused: whether Autobase is currently paused. Example:if (base.paused) await base.resume()
Writes and linearization
await base.append(value, opts)
- Signature:
await base.append(value, opts)(GitHub) - Parameters (GitHub):
value: the entry to append to the local writer.opts: append options.optimistic: allows an optimistic append from a non-writer when the base was created withoptimistic: true.
- Returns: a promise that resolves when the append has been written locally. (GitHub)
- Example:
await base.append({ type: 'message', text: 'hi' })
await base.update()
- Signature:
await base.update()(GitHub) - Parameters: none. (GitHub)
- Returns: a promise that resolves after Autobase fetches available data and reruns linearization. (GitHub)
- Example:
await base.update()
await base.ack(bg = false)
- Signature:
await base.ack(bg = false)(GitHub) - Parameters (GitHub):
bg: whentrue, schedules the ack through the automatic ack timer instead of appending immediately.
- Returns: a promise that resolves after the acknowledgement has been appended or scheduled. (GitHub)
- Example:
await base.ack(true)
Only indexers can acknowledge. An ack appends a null node that references the known heads so peers can converge faster without changing the view.
const heads = base.heads()
- Signature:
const heads = base.heads()(GitHub) - Parameters: none. (GitHub)
- Returns: the current writer-head nodes with no causal dependents. (GitHub)
- Example:
const heads = base.heads()
await base.pause()
- Signature:
await base.pause()(GitHub) - Parameters: none. (GitHub)
- Returns: a promise that resolves when Autobase has paused before the next
apply. (GitHub) - Example:
await base.pause()
await base.resume()
- Signature:
await base.resume()(GitHub) - Parameters: none. (GitHub)
- Returns: a promise that resolves after Autobase resumes and checks for updates. (GitHub)
- Example:
await base.resume()
base.setBigBatches(enable = true)
- Signature:
base.setBigBatches(enable = true)(GitHub) - Parameters (GitHub):
enable: whether to enable largerapplybatches.
- Returns: nothing. (GitHub)
- Example:
base.setBigBatches(true)
Big batches let Autobase call apply with more nodes at once, trading responsiveness for larger deterministic batches.
Replication and metadata
const hash = await base.hash()
- Signature:
const hash = await base.hash()(GitHub) - Parameters: none. (GitHub)
- Returns: the hash of the system core Merkle tree roots. (GitHub)
- Example:
const hash = await base.hash()
const stream = base.replicate(isInitiator || stream, opts)
- Signature:
const stream = base.replicate(isInitiator || stream, opts)(GitHub) - Parameters (GitHub):
isInitiator || stream: either an initiator boolean or an existing replication stream.opts: the same replication options accepted byCorestore#replicate().
- Returns: a replication stream for the Autobase. (GitHub)
- Example:
const stream = base.replicate(true)
await base.setUserData(key, value)
- Signature:
await base.setUserData(key, value)(GitHub) - Parameters (GitHub):
key: user-data key as a string.value: string or buffer value to store.
- Returns: a promise that resolves after the value is stored. (GitHub)
- Example:
await base.setUserData('app', 'chat')
const value = await base.getUserData(key)
- Signature:
const value = await base.getUserData(key)(GitHub) - Parameters (GitHub):
key: user-data key as a string.
- Returns: the stored string or buffer value for that key. (GitHub)
- Example:
const appName = await base.getUserData('app')
Static helpers
const core = Autobase.getLocalCore(store, handlers, encryptionKey)
- Signature:
const core = Autobase.getLocalCore(store, handlers, encryptionKey)(GitHub) - Parameters (GitHub):
store: the store used to create the local writer core.handlers: handler options passed through tostore.encryptionKey: optional encryption key for the local core.
- Returns: a local core suitable for an Autobase writer. (GitHub)
- Example:
const core = Autobase.getLocalCore(store, { name: 'local-writer' })
const { referrer, view } = Autobase.getUserData(core)
- Signature:
const { referrer, view } = Autobase.getUserData(core)(GitHub) - Parameters (GitHub):
core: an Autobase-related core.
- Returns: user-data metadata, including the Autobase
referrerkey and theviewname. (GitHub) - Example:
const meta = Autobase.getUserData(core)
const isBase = Autobase.isAutobase(core, opts)
- Signature:
const isBase = Autobase.isAutobase(core, opts)(GitHub) - Parameters (GitHub):
core: the core to inspect.opts: the same options accepted bycore.get(index, opts).
- Returns: whether the core is an Autobase core. (GitHub)
- Example:
const isBase = Autobase.isAutobase(core)
View store helper
const core = store.get(name || { name, valueEncoding })
- Signature:
const core = store.get(name || { name, valueEncoding })(GitHub) - Parameters (GitHub):
name: view name as a string, or an options object withnameandvalueEncoding.
- Returns: a
Hypercoreloaded from the Autobase view store. (GitHub) - Example:
const view = store.get({ name: 'messages', valueEncoding: 'json' })
This store instance is the AutoStore passed into open, and it is the intended place to create the cores that make up your deterministic view.
Apply host calls
await host.addWriter(key, { indexer = true })
- Signature:
await host.addWriter(key, { indexer = true })(GitHub) - Parameters (GitHub):
key: writer key to add to the Autobase.indexer: whentrue, adds the writer as an indexer as well.
- Returns: a promise that resolves after the writer has been added. (GitHub)
- Example:
await host.addWriter(newWriterKey, { indexer: true })
await host.removeWriter(key)
- Signature:
await host.removeWriter(key)(GitHub) - Parameters (GitHub):
key: writer key to remove.
- Returns: a promise that resolves after the writer has been removed. (GitHub)
- Example:
await host.removeWriter(oldWriterKey)
This throws when the writer cannot be removed, such as when it would leave the system without a removable indexer set.
await host.ackWriter(key)
- Signature:
await host.ackWriter(key)(GitHub) - Parameters (GitHub):
key: writer key to acknowledge.
- Returns: a promise that resolves after the writer has been acknowledged for optimistic application. (GitHub)
- Example:
await host.ackWriter(node.from.key)
host.interrupt(reason)
- Signature:
host.interrupt(reason)(GitHub) - Parameters (GitHub):
reason: optional reason explaining whyapplymust stop.
- Returns: nothing. (GitHub)
- Example:
host.interrupt('unsupported block type')
Interrupting closes the Autobase and emits the interrupt event so the application can upgrade its apply logic or recover intentionally.
host.removeable(key)
- Signature:
host.removeable(key)(GitHub) - Parameters (GitHub):
key: writer key to inspect.
- Returns: whether that writer can be removed. (GitHub)
- Example:
if (host.removeable(key)) await host.removeWriter(key)
The last indexer cannot be removed.
Events
base.on('update', () => {}): emitted afterapplyfinishes and the view has updated.base.on('interrupt', (reason) => {}): emitted whenhost.interrupt(reason)stopsapply.base.on('fast-forward', (to, from) => {}): emitted when Autobase fast-forwards fromfromtotosigned length.base.on('is-indexer', () => {}): emitted when this instance becomes an indexer.base.on('is-non-indexer', () => {}): emitted when this instance is not an indexer.base.on('writable', () => {}): emitted when this instance becomes writable.base.on('unwritable', () => {}): emitted when this instance is no longer writable.base.on('warning', (warning) => {}): emitted when Autobase raises a warning.base.on('error', (err) => {}): emitted when updating the Autobase raises an error.
See also
- Work with many Hypercores using Corestore — manage the groups of cores that Autobase coordinates.
- Corestore — storage and replication manager typically used for Autobase system, writer, and view cores.
- Hypercore — append-only log primitive that Autobase writers build on.
- Hyperbee — common materialized-view target for deterministic indexed state.