Initializing Stores
It's recommended to specify
permissions
on either Tome
or its subclasses. The schema is:interface Perm {
read: 'our' | 'space' | 'open'
write: 'our' | 'space' | 'open'
admin: 'our' | 'space' | 'open'
}
our
is our ship only (src.bowl
)space
is any ship in the current Holium space. If Realm is not installed, this becomesour
.open
is anyone, including comets.
read
/ write
/ admin
mean slightly different things based on the store type, so they will be described below.Tome.init(api?: Urbit, app?: string, options?)
api
: The optional Urbit connection to be used for requests. If not set, TomeDB will attempt to use localStorage for storing key-value pairs.app
: An optional app name to store under. Defaults to'all'
. It's recommended to set this to the name of your application (be wary of collisions, though!)
Optional
ship
, space
, agent
, permissions
, and realm
flag for initializing a Tome.options: {
realm?: boolean = false
ship?: string = api.ship
space?: string = 'our'
agent?: string = 'tome'
permissions?: Perm
}
ship
can be specified with or without the~
.agent
specifies both the desk and agent name that the JavaScript client will use. This is useful if you want to distribute a copy of TomeDB in the desk alongside your application.- If
realm
isfalse
, Tome will useship
andspace
as specified. - If
realm
istrue
,ship
andspace
must be either set together or not at all.- If neither are set, Tome will automatically detect and use the current Realm space and corresponding host ship, as well as handle switching application data when a user changes spaces in Realm.
- To create a "locked" Tome, specify
ship
andspace
together. A locked Tome will work only in that specific space (think internal DAO tooling).
permissions
is a default permissions level to be used by sub-classes. When creating many store instances with the same permissions, simply specify them once here.
Returns:
Promise<Tome>
All storage types must be created from a
Tome
instance, so do this first.const api = new Urbit('', '', window.desk)
api.ship = window.ship
const db = await Tome.init(api, 'demo', {
realm: true,
ship: 'lomder-librun',
space: 'Realm Forerunners',
agent: 'tome',
permissions: { read: 'space', write: 'space', admin: 'our' }
})
db.keyvalue(options?)
Optional
bucket
, permissions
, preload
flag, and callbacks for the key-value store.options: {
bucket?: string = 'def'
preload?: boolean = true
permissions?: Perm
onDataChange?: (data: Map<string, Value>()) => void
onLoadChange?: (loaded: boolean) => void
onReadyChange?: (ready: boolean) => void
onWriteChange?: (write: boolean) => void
onAdminChange?: (admin: boolean) => void
}
bucket
is the bucket name to store key-value pairs under. If your app needs multiple key-value stores with different permissions, they should be different buckets. Separating buckets can also save on download sizes depending on the application.preload
is whether the client should fetch and cache all key-value pairs in the bucket, and subscribe to live updates. This helps with responsiveness when using an application, since most requests won't go to Urbit.permissions
is the permissions for the key-value store. If not set, defaults to the Tome-level permissions.read
can read any key-value pairs from the bucket.write
can create new key-value pairs or update their own values.admin
can create or overwrite any values in the bucket.
onDataChange
is called whenever data in the key-value store changes, and can be used to re-render an application with new data.onReadyChange
is called whenever the store changesready
state: after initial app configuration, and whenever a user changes between spaces in Realm. Use combined withpreload
set tofalse
to know when to show a loading screen, and when to start making requests.- If preload is
true
, useonLoadChange
instead to be notified when all data has been loaded and is addressable. This also handles the case of switching between Realm spaces. onWriteChange
andonAdminChange
are called when the current user'swrite
andadmin
permissions have been detected to change.
Returns:
Promise<KeyValueStore>
Initialize or connect to a key-value store. It uses localStorage if the corresponding
Tome
has no Urbit connection.const db = await Tome.init(api, 'demo', {
realm: true
})
const kv = await db.keyvalue({
bucket: 'preferences',
permissions: { read: 'space', write: 'space', admin: 'our' },
preload: true,
onDataChange: setData,
onReadyChange: setReady,
onWriteChange: setWrite,
onAdminChange: setAdmin
})
db.feed(options?)
or db.log(options?)
Optional
bucket
, permissions
, preload
flag, and callbacks for the log or feed store.options: {
bucket?: string = 'def'
preload?: boolean = true
permissions?: Perm
onDataChange?: (data: FeedlogEntry[]) => void
onLoadChange?: (loaded: boolean) => void
onReadyChange?: (ready: boolean) => void
onWriteChange?: (write: boolean) => void
onAdminChange?: (admin: boolean) => void
}
permissions
is the permissions for the feedlog store. If not set, defaults to the Tome-level permissions.read
can read any posts and metadata from the bucket.- For a
feed
,write
can create or update their own posts / links. For alog
,write
only allows creating new posts. admin
can create or overwrite any posts / links in the bucket.
Returns:
Promise<FeedStore>
or Promise<LogStore>
Initialize a feed or log store. These must be created from a
Tome
with a valid Urbit connection. feed
and log
are very similar, the only differences are:write
for a log can't update any values. This makes a log more similar to an "append-only" data structure.- "Links" (comments, reactions, etc.) currently aren't supported for logs but are for feeds.
const db = await Tome.init(api, 'demo', {
realm: true
})
const feed = await db.feed({
bucket: 'posts',
preload: true,
permissions: { read: 'space', write: 'space', admin: 'our' },
onLoadChange: setLoaded,
onDataChange: (data) => {
// newest records first.
// if you want a different order, you can sort the data here.
// need to spread array to trigger re-render
setData([...data])
},
onWriteChange: setWrite,
onAdminChange: setAdmin
})
Last modified 2mo ago