Skip to content

Persistence

A key/value store for data that must outlive a session — player profiles, saved levels, high scores. Available in both roles; the runtime routes to the appropriate backing store. All operations are asynchronous: you pass a callback that the runtime invokes on completion.

Callbacks, briefly

Munos functions aren't first-class, but a builtin's callback slot accepts either an inline function literal or the name of a top-level function. You may declare the callback with any prefix of its full parameter list — trailing parameters you don't need are dropped.

The optional trailing ctx: i32 is an integer you supply at the call site and the runtime passes back to your callback unchanged — a lightweight way to route one shared callback by context (which key, which request).

Reading

munos
db_get(namespace: string, key: string, cb, ctx: i32 = 0)
// cb(success: bool, data: u8[], ctx: i32)
munos
db_get("profiles", "player42", got_profile)

function got_profile(success: bool, data: u8[]) {
    if !success { return }
    // ...decode data...
}

Writing and deleting

munos
db_set(namespace: string, key: string, data: u8[], cb?, ctx?)
// cb(success: bool, ctx: i32)

db_del(namespace: string, key: string, cb?, ctx?)
// cb(success: bool, ctx: i32)

For db_set and db_del the callback and its trailing ctx are jointly optional — omit both for fire-and-forget:

munos
db_set("profiles", "player42", encoded)            // fire-and-forget
db_set("profiles", "player42", encoded, on_saved)  // with confirmation

Listing keys

munos
db_list(namespace: string, prefix: string, cb, ctx: i32 = 0,
        start: string = "", limit: i32 = 0, reverse: bool = false)
// cb(success: bool, keys: string[], ctx: i32)

Pass an empty prefix to list the whole namespace. Keys come back in ascending byte order — the same order on every backend.

munos
db_list("levels", "world1-", got_levels)

function got_levels(success: bool, keys: string[]) {
    for (var i = 0; i < len(keys); i = i + 1) { print(keys[i]) }
}

Paging through a large namespace

start, limit, and reverse return an ordered page instead of every matching key at once. The cursor is exclusive: pass the last key you received as the next call's start, and the first page uses start = "".

  • reverse = false (ascending): keys K with K > start, up to limit.
  • reverse = true (descending): keys K with K < start, up to limit. start = "" begins at the largest key.
  • limit = 0 means unlimited (the whole matching set).

They sit after cb/ctx so the shorter db_list(ns, prefix, cb) call still works unchanged. Name the ones you want if you don't need ctx:

munos
// First page of 50, ascending. Resume by feeding back the last key.
db_list("levels", "world1-", on_page, 0, cursor, 50, false)

// Top 10, highest first — for a leaderboard keyed by a zero-padded score
// so byte order matches numeric order.
db_list("@scores", "", on_top, limit = 10, reverse = true)

Encode the order you want into the key (zero-padded numbers, timestamps) and db_list becomes a scalable index you read a page at a time — no need to pull a whole catalog into the script to sort it.

The error event

munos
event db_error(op: string, namespace: string, key: string, msg: string)

Fires in addition to the success = false callback path when an operation hit infrastructure trouble (store unreachable, quota overflow). Declaring it is optional — failures are still observable through success = false — but it gives you the failure reason in one place. Available in both roles.

TIP

Data goes in and out as u8[]. Use pack/unpack or base64_decode / string_from_bytes to turn your records into bytes and back.

Part of the MultiNostalgia project.