# Submitting a game

Every game on the Hub is published by a **publisher**, and a game goes on the Hub, with every
new version of it, as a zip its publisher uploads: from the publisher dashboard, or with one of
the publisher's submission keys. `npx -p @unikia/upe-cli uniplay submit` does all of it for you; this page is what
happens underneath.

## Publishers

A publisher is the name players see a game published under. It has its own name and picture,
and a profile in the Hub that showcases its games. One or more Hub accounts are its
**members** and manage it; an account can be a member of several publishers.

- Ask for one with a **Publisher profile** request from the Feedback window in the Hub, signed
  in with your account, saying the publisher's name. An admin creates it, with you as its first
  member, and replies to your account's email.
- Members manage it in the **publisher dashboard** at [`/publisher/`](/publisher/) (Settings →
  Publisher dashboard in the Hub): upload zips from `uniplay pack` and play them before they go
  live, see its games and versions, set its name and picture, add or remove members by Hub
  nickname, and make submission keys.
- A publisher uploads new games and new versions of its own. A game belongs to the publisher
  that sent its first version; the manifest's [`developers`](manifest.md#unihubmanifestjson) are
  credits and needn't include whoever uploads it.
- Verified publishers are marked as verified beside their name, in Game details and on their
  profile.

## Submission keys

For uploading from the command line, UPE or CI. A submission key is `uk_sub_` followed by 32
characters. It is private: keep it out of your repository, and treat it like a password.

- Any member makes one in the publisher dashboard's **Keys** tab, naming what it's for. It's
  shown once; revoke it there if it leaks.
- A key uploads as its publisher, whichever member made it. `npx -p @unikia/upe-cli uniplay whoami` says which.
- A publisher can upload 10 times a day, by keys and dashboard together.

## Uploading

Pack the game into its [zip](manifest.md#the-game-package), then send it in three steps. First
ask for a place to upload it, giving its size in bytes:

```http
POST /api/submissions/uploads HTTP/1.1
Host: play.unikia.es
Authorization: Bearer uk_sub_0123456789abcdefghijklmnopqrstuv
Content-Type: application/json

{ "size": 296747008 }
```

The Hub answers `201 Created` with where to put it, valid for an hour:

```json
{ "upload": "…", "url": "https://…", "method": "PUT", "headers": { "content-type": "application/zip" }, "expiresAt": 1793000000000 }
```

Send the zip to `url` with that method and those headers, and nothing else (no `Authorization`:
the URL carries its own permission, for exactly that size). Then submit it:

```http
POST /api/submissions HTTP/1.1
Host: play.unikia.es
Authorization: Bearer uk_sub_0123456789abcdefghijklmnopqrstuv
Content-Type: application/json

{ "upload": "…" }
```

A zip under 100 MB can also go as the body of `POST /api/submissions` itself
(`Content-Type: application/zip`); bigger ones only reach the Hub the first way.

The Hub answers `202 Accepted` with the submission:

```json
{ "id": "…", "status": "pending", "validation": { … } }
```

`validation` is the result of the same checks `uniplay validate` runs. Follow the submission
with `GET /api/submissions/:id`, using any of the publisher's keys. `GET /api/submissions/key`
answers which publisher a key uploads as. A submission's `status` is one of:

| Status | Meaning |
|---|---|
| `pending` | Uploaded and waiting for review. |
| `rejected` | Not published, with the reasons. Fix them and submit again. |
| `approved` | Accepted, about to go live. |
| `live` | Players see this version in the Hub. |

## Review

A game's first version waits for an admin, who plays it before it goes live. After that, each
game is Manual or Automated: updates to a Manual game wait for an admin too, and updates to a
game an admin set to Automated go live as soon as they pass validation.

An admin may also verify a publisher: everything a verified publisher uploads, first versions
included, goes live as soon as it passes validation, with no daily limit. A publisher an admin disabled can't
upload, by dashboard or key, or change its profile until it's enabled again; its games stay on
the Hub.

## Rolling back

A version that went wrong can be taken back: in the Publisher dashboard's games, pick an earlier
version and **Make live**. Players get it at once, and Uniplay for desktop installs it as an
update. The live version and the 3 published most recently besides it (more if an admin raises it)
can be downloaded in the app; any older one can still be made live, and becomes downloadable again.

Buds play a game together on the same version, so after an update or a rollback the one behind is
offered the update before joining. A game whose versions stay compatible can let any of them play
together with `coopAcrossVersions` in its [manifest](manifest.md).

## `uniplay submit`

```sh
npx -p @unikia/upe-cli uniplay submit --key uk_sub_…   # pack the game in this folder and upload it
npx -p @unikia/upe-cli uniplay submit game.zip --wait  # upload a zip from uniplay pack and wait for the result
npx -p @unikia/upe-cli uniplay status <submission id>  # how a submission is doing
```

`uniplay submit` takes a game folder (by default the current one, packed as `uniplay pack`
does) or a zip, uploads it and reports its status; `--wait` checks again until it's no longer
`pending`. Without `--key`, it reads the key from the `UNIPLAY_SUBMIT_KEY` environment
variable, which keeps it out of your shell history and works in CI.
