Skip to content

Scripting Shops

000hen edited this page Jul 7, 2026 · 1 revision

Scripting: Mod Shops

Shop scripts power the JustHostMC Mod Shop window, enabling users to browse, search, and download mods and plugins from online sources such as Modrinth or CurseForge directly within the app.

Registration & Storage

Built-in shops live in the engine at engine/internal/scripting/builtin_shops/. User-imported shops are managed via ShopService.Import and persist under <data>/shops/. The permission grants for these scripts are persisted in shop-grants.json.

The meta Table

A shop script must define a meta table. It can set needs_key = true if the source requires an API key.

meta = {
  id = "myshop", 
  name = "My Shop", 
  version = "1.0.0",
  needs_key = false, -- true => engine refuses calls until a key is configured by the user
  permissions = { { kind = "network", reason = "Query the shop API" } },
}

The Shop Contract

A shop script must define five global functions. Each takes a ctx table and returns a specifically formatted table.

1. home(ctx)

Populates the default homepage of the shop.

  • Input: ctx contains mc_version, loader, kind ("mod" or "plugin"), and config (which contains api_key if needs_key is true).
  • Returns: A table of sections containing projects.
function home(ctx)
  return { sections = { { title_key = "shop.home.popular", projects = { ... } } } }
end

2. search(ctx)

Performs a search query.

  • Input: Extends the home context with query, sort ("relevance"|"downloads"|"follows"|"newest"|"updated"), offset, and limit.
  • Returns: A list of projects and the total count.
function search(ctx)
  return { projects = { ... }, total = 123 }
end

3. detail(ctx)

Fetches detailed info for a single project.

  • Input: ctx.project_id.
  • Returns: Project metadata, description body, and gallery.
function detail(ctx)
  return { 
    project = {...}, 
    body = "...", 
    body_format = "markdown", -- or "html"
    gallery = {{url="...", title="...", description="..."}}, 
    links = {website="...", source="...", issues="...", wiki="...", discord="..."}
  }
end

4. versions(ctx)

Fetches available downloadable versions for a project.

  • Input: ctx contains project_id, mc_version, and loader.
  • Returns: A list of versions.
function versions(ctx)
  return { versions = { { id="...", name="...", version_number="...", channel="release" } } }
end

5. resolve_file(ctx)

Resolves the final download URL and checksums for a specific version.

  • Input: ctx contains project_id, version_id (empty string means latest compatible), mc_version, and loader.
  • Returns: The URL, filename, and checksum (sha1 or sha512). The engine will handle the actual download and verification.
function resolve_file(ctx)
  return { url="...", filename="...", size=1234, sha1="..." } 
end

Caching HTTP Requests

When building a Shop script, it is highly recommended to use jhmc.http_cache instead of the standard jhmc.http_get.

jhmc.http_cache{ url=..., headers=..., ttl=... } acts as a disk-backed ETag cache (utilizing If-None-Match and 304 Not Modified). This ensures that repeated detail views cost almost nothing. The ttl (Time-To-Live) parameter specifies the number of seconds during which the engine will return the cached response without even making a network request.

Handling Errors

Shop APIs may return specific errors when a file or project cannot be found or distributed. Raise an error to surface these explicitly to the UI:

  • error("... not found") maps to SHOP_PROJECT_NOT_FOUND
  • error("... not distributable") maps to SHOP_FILE_NOT_DISTRIBUTABLE

Navigation

Clone this wiki locally