API Reference
Root Module
local lsd = require("./lsd")lsd.store(config)
Creates and returns a new Store instance.
local store = lsd.store({
name = "player_data",
template = { ... },
})- Parameters:
config: StoreConfig<T> - Returns:
Store<T>
lsd.shutdown()
Closes all active stores and flushes pending data and telemetry. This is registered automatically with game:BindToClose.
lsd.shutdown()lsd.telemetry(callback)
Registers a telemetry sink callback that receives batched metrics and event logs every 10 seconds and on shutdown.
local disconnect = lsd.telemetry(function(batch) ... end)- Parameters:
callback: (batch: TelemetryBatch) -> () - Returns:
disconnect: () -> ()
lsd.validator
Namespace containing the schema definition and validation engine. See Validator API.
Store Configuration
Passed to lsd.store(config):
| Field | Type | Default | Description |
|---|---|---|---|
name | string | Required | DataStore namespace for player profiles. |
template | T | Required | Default data structure for new players and missing keys. |
validate | (data: T) -> boolean | nil | Validator function or compiled schema. |
migrations | { Migration<T> } | {} | Ordered list of versioned schema upgrades. |
on_load_error | (player, reason, message) -> () | nil | Handler called when profile loading fails after all retries. |
on_global_update | (player, update, data) -> T | nil | Handler for queued cross-server global updates. |
steal_on_locked | boolean | false | Automatically steal session lock if held by another server. |
max_load_attempts | number | 3 | Maximum number of attempts before triggering on_load_error. |
Store Instance
local store = lsd.store(...)store.load(player)
Yields while acquiring exclusive session ownership and loading the player's profile.
store.load(player)store.steal(player)
Immediately steals session ownership from any remote server and loads the player's profile.
store.steal(player)store.unload(player)
Closes the player's session, clears processed updates, saves pending changes, and releases ownership.
store.unload(player)store.get(player)
Returns the player's current profile. The returned table is deeply frozen.
local data = store.get(player)- Returns:
T
store.update(player, transform)
Deep-copies the profile and executes transform(data) on the mutable clone. If transform returns false, changes are discarded.
local success = store.update(player, function(data)
data.coins += 50
end)- Returns:
boolean(trueif updated,falseif cancelled)
store.save(player)
Requests an immediate save for the player's session without waiting for autosave.
store.save(player)store.is_loaded(player)
Returns whether the player currently has an active, loaded session on this server.
local loaded = store.is_loaded(player)- Returns:
boolean
store.is_locked(user_id)
Checks whether an active distributed lock is held for the given user ID.
local locked = store.is_locked(user_id)- Returns:
boolean
store.on_close(player, callback)
Registers a callback invoked when the player's session closes. Returns a disconnect function.
local disconnect = store.on_close(player, function(reason)
print(`Session closed: {reason}`)
end)Close Reasons: "manual" | "lock_lost" | "shutdown" | "stolen" | "save_unknown" | "transaction_unknown"
store.peek(user_id)
Reads offline data from DataStore without acquiring a lock. Applies template defaults and pending migrations.
local data = store.peek(user_id)- Returns:
T?
store.transact(participants, transform)
Executes an atomic transaction across multiple online or offline participants.
local success = store.transact({ player_a, player_b }, function(states)
states[tostring(player_a.UserId)].coins -= 10
states[tostring(player_b.UserId)].coins += 10
end)- Parameters:
participants: { Player | number | string }transform: (states: { [string]: T }) -> boolean?
- Returns:
boolean
store.send_global_update(user_id, data)
Appends an update payload to the target player's queue.
store.send_global_update(user_id, { reward = "gift_box" })store.erase(user_id)
Permanently removes all stored records, shards, and queued updates for a player. Fails if a session is currently active.
store.erase(user_id)store.list_loaded()
Returns an array of all Player instances with active sessions in this store.
local active_players = store.list_loaded()- Returns:
{ Player }
store.get_session_info(player)
Returns metadata about the active session, or nil if not loaded.
local info = store.get_session_info(player)- Returns:
{ key: string, is_dirty: boolean, is_saving: boolean, open_time: number, last_save_time: number, version: number }?
store.close()
Closes all sessions in this store and flushes pending saves.
store.close()Validator API
local validator = lsd.validatorPrimitive Rules
validator.boolean: Booleans (true/false).validator.number: Finite numbers (rejectsNaNandInf).validator.integer: Finite integers (value % 1 == 0).validator.string: Valid UTF-8 strings.validator.any: Any DataStore-serializable value subtree.
Structure Rules
validator.record(fields): Strict table with fixed string fields.validator.list(item_rule): Contiguous 1-indexed array.validator.map(value_rule): Open dictionary with string keys.validator.optional(rule): Acceptsnilor the inner rule.
Composition Rules
validator.literal(expected): Exact scalar equality match.validator.enum(values): Value must match one of the items in the set.validator.either(...rules): Ordered union; matches first passing rule.validator.where(rule, predicate, [message]): Custom refinement constraint.
Compilation & Execution
validator.create(fields): Shorthand forvalidator.compile(validator.record(fields)).validator.compile(root_rule): Compiles a rule into a validator function(value: T) -> (boolean, string?).validator.check(checker, value): Safely tests a value withpcall, returning(boolean, string?).validator.assert_valid(checker, value, context): Asserts validity or throws"{context}: {message}".