Skip to content

@lands.io/mod-sdk / ReadonlyModStorage

Class: ReadonlyModStorage

Interface for mod persistent storage operations. This is the public API that mods use to interact with persistent storage.

Implements

Table of contents

Constructors

Methods

Constructors

constructor

new ReadonlyModStorage(modId): ReadonlyModStorage

Parameters

Name Type
modId string

Returns

ReadonlyModStorage

Methods

delete

delete(_scope, _key, _ownerId?): Promise\<boolean>

Delete an entry from persistent storage

Parameters

Name Type
_scope string
_key string
_ownerId? string

Returns

Promise\<boolean>

Implementation of

IModStorage.delete


filter

filter(scope, key, equals): Promise\<string[]>

Filter entries by matching value (returns owner IDs)

Parameters

Name Type
scope string
key string
equals unknown

Returns

Promise\<string[]>

Implementation of

IModStorage.filter


get

get(scope, key, ownerId?): Promise\<unknown>

Retrieve a value from persistent storage

Parameters

Name Type
scope string
key string
ownerId? string

Returns

Promise\<unknown>

Implementation of

IModStorage.get


getOrderedAsc

getOrderedAsc(scope, key, limit?): Promise\<{ ownerId: string ; value: unknown }[]>

Get entries ordered by value in ascending order

Parameters

Name Type
scope string
key string
limit? number

Returns

Promise\<{ ownerId: string ; value: unknown }[]>

Implementation of

IModStorage.getOrderedAsc


getOrderedDesc

getOrderedDesc(scope, key, limit?): Promise\<{ ownerId: string ; value: unknown }[]>

Get entries ordered by value in descending order

Parameters

Name Type
scope string
key string
limit? number

Returns

Promise\<{ ownerId: string ; value: unknown }[]>

Implementation of

IModStorage.getOrderedDesc


getPlayer

getPlayer(playerId): Promise\<Record\<string, unknown>>

Get all data for a specific player

Parameters

Name Type
playerId string

Returns

Promise\<Record\<string, unknown>>

Implementation of

IModStorage.getPlayer


listKeys

listKeys(scope): Promise\<string[]>

List all keys in a scope

Parameters

Name Type
scope string

Returns

Promise\<string[]>

Implementation of

IModStorage.listKeys


search(scope, key, substring): Promise\<{ ownerId: string ; value: unknown }[]>

Search for entries containing a substring (case-insensitive)

Parameters

Name Type
scope string
key string
substring string

Returns

Promise\<{ ownerId: string ; value: unknown }[]>

Implementation of

IModStorage.search


set

set(_scope, _key, _value, _ownerId?): Promise\<void>

Store a value in persistent storage (upsert operation)

Parameters

Name Type
_scope string
_key string
_value unknown
_ownerId? string

Returns

Promise\<void>

Implementation of

IModStorage.set


Source Code

View full implementation
export class ReadonlyModStorage implements IModStorage {
  private readonly modId: string;
  private readonly apiBaseUrl: string;

  constructor(modId: string) {
    this.modId = modId;
    this.apiBaseUrl = getPublicApiUrl();
  }

  /**
   * Helper to build query string from params
   */
  private buildQueryString(
    params: Record<string, string | number | undefined>
  ): string {
    const queryParams = new URLSearchParams();
    for (const [key, value] of Object.entries(params)) {
      if (value !== undefined) {
        queryParams.append(key, String(value));
      }
    }
    return queryParams.toString();
  }

  /**
   * Helper to make fetch requests
   */
  private async fetchJson<T>(
    endpoint: string,
    params: Record<string, string | number | undefined>
  ): Promise<T> {
    const queryString = this.buildQueryString(params);
    const url = `${this.apiBaseUrl}/api/mod-storage/${endpoint}?${queryString}`;

    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`Failed to fetch ${endpoint}: ${response.statusText}`);
    }

    return response.json();
  }

  async get(scope: string, key: string, ownerId?: string): Promise<unknown> {
    const result = await this.fetchJson<{ value: unknown }>('get', {
      modId: this.modId,
      scope,
      key,
      ownerId,
    });
    return result.value;
  }

  async filter(scope: string, key: string, equals: unknown): Promise<string[]> {
    const result = await this.fetchJson<{ ownerIds: string[] }>('filter', {
      modId: this.modId,
      scope,
      key,
      equals: JSON.stringify(equals),
    });
    return result.ownerIds;
  }

  async getOrderedDesc(
    scope: string,
    key: string,
    limit?: number
  ): Promise<Array<{ ownerId: string; value: unknown }>> {
    const result = await this.fetchJson<{
      entries: Array<{ ownerId: string; value: unknown }>;
    }>('ordered-desc', {
      modId: this.modId,
      scope,
      key,
      limit,
    });
    return result.entries;
  }

  async getOrderedAsc(
    scope: string,
    key: string,
    limit?: number
  ): Promise<Array<{ ownerId: string; value: unknown }>> {
    const result = await this.fetchJson<{
      entries: Array<{ ownerId: string; value: unknown }>;
    }>('ordered-asc', {
      modId: this.modId,
      scope,
      key,
      limit,
    });
    return result.entries;
  }

  async search(
    scope: string,
    key: string,
    substring: string
  ): Promise<Array<{ ownerId: string; value: unknown }>> {
    const result = await this.fetchJson<{
      entries: Array<{ ownerId: string; value: unknown }>;
    }>('search', {
      modId: this.modId,
      scope,
      key,
      substring,
    });
    return result.entries;
  }

  async listKeys(scope: string): Promise<string[]> {
    const result = await this.fetchJson<{ keys: string[] }>('list-keys', {
      modId: this.modId,
      scope,
    });
    return result.keys;
  }

  async getPlayer(playerId: string): Promise<Record<string, unknown>> {
    const result = await this.fetchJson<{ data: Record<string, unknown> }>(
      'player',
      {
        modId: this.modId,
        playerId,
      }
    );
    return result.data;
  }

  // Write operations - throw errors as this is read-only
  async set(
    _scope: string,
    _key: string,
    _value: unknown,
    _ownerId?: string
  ): Promise<void> {
    throw new Error(
      'ReadonlyModStorage: set() is not supported. This is a read-only storage implementation.'
    );
  }

  async delete(
    _scope: string,
    _key: string,
    _ownerId?: string
  ): Promise<boolean> {
    throw new Error(
      'ReadonlyModStorage: delete() is not supported. This is a read-only storage implementation.'
    );
  }
}