memsvc

package
v2.14.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 17, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package memsvc is a public, in-memory implementation of the host-side sdk.ServicesFactory (and the matching sdk.AccountStore, sdk.KVStore, sdk.ConfigStore, and leaderboard surfaces). It lets the CLI dev runner and the conformance suite run games WITHOUT the platform's private Postgres / identity services: everything lives in process memory.

It implements the SAME sdk interfaces the production durable (Postgres) factory does — a fire-and-forget sdk.LeaderboardClient.Post, a per-user KV behind an sdk.AccountStore, a slug-bound read-only sdk.ConfigStore, and an sdk.LeaderboardData backend a generic sdk.LeaderboardReader composes — and matches their observable contract:

  • Leaderboard recording records every account-bound result tagged with mode
  • status, dropping only guests (an empty AccountID). It lives here, not in game code; games always Post and never branch on eligibility.
  • Per-user KV is namespaced to (slug, account, key). A key written with the sdk.MergeMax rule is kept MONOTONIC on write — the stored value only ever rises — mirroring the durable store, so out-of-order writers can never regress a max key. All other rules overwrite last-writer-wins; the sum/max/keep-loser accumulation ACROSS accounts happens only at an account merge (Factory.Merge).
  • Per-game config is a slug-bound, read-only surface seeded by the harness (Factory.SetConfig); games can read only their own slug's keys.

The package imports only github.com/shellcade/kit/v2/host/sdk — no shellcade private code — which is the property that lets the kit ship a runnable host.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New() sdk.ServicesFactory

New returns an in-memory sdk.ServicesFactory over the package-level default game registry (sdk.Default). This is the drop-in for the CLI dev runner and conformance: the same shape as the durable factory's constructor minus the platform-only Postgres store argument. Use NewFactory when you need the concrete *Factory (for Factory.Reader, Factory.SetConfig, or Factory.Merge) or a curated registry.

func NewWithRegistry

func NewWithRegistry(log *slog.Logger, reg *sdk.Registry) sdk.ServicesFactory

NewWithRegistry returns an in-memory sdk.ServicesFactory over an explicit registry (a curated roster for the CLI or a conformance fixture).

Types

type Factory

type Factory struct {
	// contains filtered or unexported fields
}

Factory is an in-memory sdk.ServicesFactory plus an sdk.LeaderboardData backend (reachable via Factory.Reader). It is safe for concurrent use.

func NewFactory

func NewFactory(log *slog.Logger, reg *sdk.Registry) *Factory

NewFactory returns the concrete in-memory *Factory over an explicit logger and registry. A nil log defaults to slog.Default; a nil registry defaults to sdk.Default. Prefer New when you only need the sdk.ServicesFactory interface; use this when a test or the CLI also needs the read side (Factory.Reader), config seeding (Factory.SetConfig), or account merge (Factory.Merge).

func (*Factory) For

func (f *Factory) For(roomID, slug string) sdk.Services

For builds a sdk.Services bundle tagged with the room id and game slug. The returned AccountStore, ConfigStore, and LeaderboardClient are all bound to the slug, so a game can reach only its own per-game state.

func (*Factory) Merge

func (f *Factory) Merge(winnerID, loserID string)

Merge folds the loser account's per-user KV into the winner, applying each key's recorded sdk.MergeRule on a collision and moving non-colliding keys across unchanged, then dropping the loser's rows. It is the in-memory twin of the durable store's account-merge reconciliation; the CLI/conformance can call it to exercise the merge-rule semantics without an identity service. The KVStore games hold has no merge method (the rule is only RECORDED on Set) — this models the platform-owned merge that consumes those recorded rules.

Per the ABI contract: the winner's recorded rule governs the collision (falling back to the loser's when the winner has none); keep-winner leaves the winner's value untouched; keep-loser takes the loser's; sum/max combine the two base-10 integers, and a non-integer value under sum/max DEGRADES to keep-winner (so poisoned game data can never break an account merge). An empty/unknown rule is keep-winner.

func (*Factory) Reader

func (f *Factory) Reader() sdk.LeaderboardReader

Reader exposes the leaderboard read side (the lobby/UI surface, never handed to games), composing this factory's in-memory data backend with the registry's per-game specs and providers. Reads reflect every result recorded via the LeaderboardClient.Post returned by Factory.For.

func (*Factory) SetConfig

func (f *Factory) SetConfig(slug, key string, value []byte)

SetConfig seeds a per-game config value into the in-memory backend, so the CLI or a conformance test can exercise a game's config-driven behavior without a database. It mirrors the durable ConfigSet: last-write-wins, global per (slug, key).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL