Skip to content

Latest commit

 

History

History
134 lines (95 loc) · 5.58 KB

File metadata and controls

134 lines (95 loc) · 5.58 KB

Package Endpoint Contract

The installer talks to a single HTTP endpoint for runner, plugin and data packages. Only the installer self-update still uses GitHub directly.

This document defines the request format, the headers, and the response shapes. For the broader architecture see architecture.md. For how a package ends up on disk see install-manifest.md.

Related documents

  • architecture.md – where the endpoint client sits in the installer.
  • security.md – HTTPS, bearer tokens, install UUID privacy.

Endpoint URL

The base URL is taken from config.php under the project_api_url key. Every request goes to that base URL with package_type (and install_uuid) appended as query parameters.

Example: if project_api_url is https://packages.example.test/api, the installer requests:

GET https://packages.example.test/api?package_type=runner&install_uuid=0192f8e3-7c8e-7c2f-9d2a-...
POST https://packages.example.test/api  (form body: package_type, install_uuid, optionally more)

In the local Docker setup the default endpoint is http://web-server/index.php and the dev token is oak-local-dev-token.

Headers sent with every request

Header Value Notes
Accept application/json Only on the package list query.
Authorization Bearer <project_api_token> Only if project_api_token is configured.
X-Install-UUID The current install UUID Always sent, alongside the same value as install_uuid query parameter.

The install UUID is a UUID v7 generated by InstallUuidManager and stored in .env.local.

Request payload

The installer sends a form-encoded body with the following fields:

Field Description
type Legacy alias for package_type. Always set.
package_type runner, plugin or data.
install_uuid The current UUID v7 from .env.local.

Implementation: ProjectPackageApiClient::request().

Response shape

Package list

The endpoint can answer the package list query with either a plain JSON array or an object that has a packages key. The installer accepts both.

Plain array:

[
  {
    "package_type": "runner",
    "package_id": "oak-runner",
    "version": "1.2.3",
    "channel": "stable",
    "package_name": "oak/runner",
    "archive_size": 1234567,
    "archive_sha256": "f3d0e…",
    "download_url": "https://packages.example.test/oak-runner-1.2.3.tar.gz",
    "composer": {
      "name": "oak/runner",
      "extra": {
        "oak-engine-runner": {
          "version": "1.2.3",
          "channel": "stable"
        }
      }
    }
  }
]

Object with packages:

{
  "packages": [ /* same shape as above */ ]
}

Package detail

The detail call (getPackage) is a filtered list call: the installer still hits the same endpoint with package_type and install_uuid, then filters by package_id and optional version in memory. There is no separate detail endpoint.

Field reference

Field Type Notes
package_type string runner, plugin, or data. The installer drops entries whose package_type does not match the client it is asking with.
package_id string The stable identifier of the package (used for filtering and for the install dir for plugin/data).
version string Semver version string, e.g. 1.4.2.
channel string stable, beta, … Used for display only. Defaults to unknown.
package_name string The human-readable name (often the composer name).
archive_size int Size in bytes.
archive_sha256 string SHA256 of the archive.
download_url string Absolute URL or path relative to project_api_url.
composer object Composer metadata. The installer reads extra.<package-type> for the version + channel.

Package types and their composer keys

Package type Composer key in extra
runner oak-engine-runner
plugin oak-engine-plugin
data oak-engine-data

If extra.<key>.env.dir is set, the installer uses it as the install directory basename. Otherwise it falls back to the basename of composer.name. See resolvePackageInstallDirFromMetadata.

Downloading the archive

Once the installer has chosen a package from the list, it calls downloadPackage($package_id, $version). That issues a plain HTTP GET to download_url and streams the response body into a temp file. The temp file is then handed to ProjectPackageArchiveExtractor, which extracts it into the target directory.

Caching

The package list response is cached for 5 minutes in <target>/var/cache/packages/<hash>.json, where <hash> is derived from the base URL, the package type and the install UUID. The cache file is removed:

  • Manually via the Refresh data button (refresh_packages POST).
  • Automatically when its mtime is older than the TTL.

There is no shared cache between runner, plugin and data – each client has its own cache file.

Error handling

  • HTTP 4xx/5xx → the installer shows a generic error page. The endpoint should return JSON with an error message if possible.
  • Curl errors (DNS, TLS, timeout) → the same generic error path with the curl error message.
  • Empty or malformed response → throws RuntimeException and the user sees the error.

The installer never retries automatically. The user can hit Refresh data to retry.