Migrating to Aperture
Moving scripts that already upload elsewhere: what changes, what does not, and how to roll back.
The short version
Scripts that call the routes below change the base URL and the key, nothing
else. lb-phone 2.9.0 is the exception: it switches to its Custom method,
which is a change to its configuration rather than to its code.
Aperture answers on the exact paths deployed scripts already call, in the exact shape they already parse. There is no SDK to swap and no script to rewrite: screenshot-basic calls and the upload scripts written against these routes work as they are once the host and the key change.
| Route your scripts call | Here |
|---|---|
POST /api/v3/file |
same path, same body |
POST /api/v3/file/base64 |
same path, same body |
POST /api/v2/{image,video,audio} |
same path, same body |
POST /api/{image,video,audio} |
same path, same body |
| lb-upload base URL | POST /lb-upload |
The oldest of these APIs is documented nowhere any more. Its shape was read out
of an older lb-phone shared/upload.lua rather than out of documentation, which
is how we found that it puts url at the root of the response rather than under
data, and that its audio form field is named recording.
lb-phone: switch to the Custom method
This applies to lb-phone 2.9.0, the release these instructions were written
against, and to any release whose upload method for your old host holds
url = "PRESIGNED_URL" in lb-phone/shared/upload.lua.
In 2.9.0 every hosted upload method holds that line: lb-phone asks the host for
an upload address at each upload, so the block has no address of its own to
change, no headers and no error path. Typing an Aperture URL in place of
PRESIGNED_URL in your old host's block does not bring a single photo here:
the upload either still goes to your old host, or reaches Aperture without an
Authorization header and is refused with missing_token. The Custom method
is the one that carries both the URL and the key.
In lb-phone/shared/upload.lua, inside UploadMethods.Custom, give each
kind the Aperture URL, the Authorization header and the two response paths:
Custom = {
Video = {
url = "https://your-instance/api/v1/uploads",
field = "file",
headers = { ["Authorization"] = "API_KEY" },
error = { path = "status", value = "error" },
success = { path = "data.url" },
},
Image = {
url = "https://your-instance/api/v1/uploads",
field = "file",
headers = { ["Authorization"] = "API_KEY" },
error = { path = "status", value = "error" },
success = { path = "data.url" },
},
Audio = {
url = "https://your-instance/api/v1/uploads",
field = "file",
headers = { ["Authorization"] = "API_KEY" },
error = { path = "status", value = "error" },
success = { path = "data.url" },
},
}Leave API_KEY exactly as written. It is a placeholder, listed at the top of
upload.lua among the ones lb-phone fills in, and lb-phone puts the key of that
kind in its place. success.path is where our response carries the URL, and
error.path with value = "error" is how the phone tells a refusal apart.
In lb-phone/server/apiKeys.lua, put an Aperture token in place of each old
key. The table is keyed by kind, and each upload uses the key of its own kind:
API_KEYS = {
Video = "YOUR_VIDEO_TOKEN",
Image = "YOUR_IMAGE_TOKEN",
Audio = "YOUR_AUDIO_TOKEN",
}Give each token the upload scope of its own kind, and nothing else. This
server-side file keeps the keys out of shared/upload.lua, which is sent to
every player who joins, so a key written there can be read out of any player's
cache. It does not keep them from players: lb-phone sends each upload from the
player's game, so the key of that kind reaches the game of the player who
uploads, and a curious player can read it there. Treat these tokens as exposed:
upload scope only, one per kind, used by no other script, and revoked and
replaced from the dashboard as soon as one turns up where it should not.
In lb-phone/config/config.lua, move the three kinds to Custom:
Config.UploadMethod.Video = "Custom"
Config.UploadMethod.Image = "Custom"
Config.UploadMethod.Audio = "Custom"Then add your delivery host to Config.UploadWhitelistedDomains, in the same
file, as the lb-phone guide explains: without it the
upload succeeds and the photo never appears in the phone.
Other scripts: switch the base URL
A screenshot-basic call or a Lua script posting with PerformHttpRequest
keeps its path. Change the host in front of it, and put an Aperture token where
the old key was:
exports['screenshot-basic']:requestScreenshotUpload(
'https://your-instance/api/v3/file',
'file',
{ headers = { Authorization = 'YOUR_TOKEN' } },
function(data)
print(json.decode(data).data.url)
end
)A key passed in the query string as ?apiKey= is read the same way here. The
screenshot-basic guide covers both forms and
the error codes worth branching on.
If you are rewriting a script anyway, point it at /api/v1/uploads: it is the
API we document, and it puts no compatibility layer between your script and the
response.
What happens to your old files
They stay where they are. Aperture does not reach into another provider's storage, and your existing URLs keep working as long as that account does.
Plan for that: the reason to move is usually that the other account is going away, and a link written into a phone database outlives the decision to migrate.
Rolling back
Put the old URL and the old keys back. For lb-phone, set Config.UploadMethod
back to the method you used before and put the old keys back in
server/apiKeys.lua; the Custom block can stay, since nothing uses it once no
kind names it.
Nothing here rewrites your game server database, and files uploaded to Aperture keep their URLs whether or not anything still points here.
Two things a script gains here
Who uploaded what. A script can send a player-metadata header with an
upload. When it does, Aperture records it and the library shows the player
behind that screenshot, with nothing to set up on this side.
Retries stop costing twice. PerformHttpRequest has no dependable timeout,
so a lost response is a real possibility. Send an Idempotency-Key, one value
per upload, and a retry returns the first upload instead of storing a
duplicate.
lb-phone gains neither from its Custom block. Its headers are the same fixed
strings on every upload, so it cannot send a key per upload, and it does not
retry a failed upload anyway. Never add an Idempotency-Key to those headers:
for a day, every later photo, clip and voice note would come back with the
first one's URL. lb-phone could send the player as PLAYER_DATA in a
player-metadata header, but the phone's interface runs in the game's browser,
which refuses to send a header holding a character outside Latin-1 (the Western
European character set): a player whose name has an emoji or a Cyrillic letter
could not upload at all, and accented letters such as é arrive in a form
Aperture cannot decode. The Custom block above leaves it out for that reason.