Package · sdk-s5w

Entities

The objects the SDK turns server answers into. They are all immutable (readonly) and describe the state at the moment of the answer; to see the new state, use what the changing method returned, or read the object again.

Namespace Flytachi\Winter\SDK\S5w\Entity

General

Dates are DateTimeImmutable with the server’s time zone.

Enums are PHP enum objects (Retention::WEEK), not numbers. See Options & enums.

JSON. Every entity implements JsonSerializable and a toArray() method, so it can go straight into a response: ResponseEntity::ok($file). In JSON, dates are ISO 8601 strings (2026-11-07T14:54:51+00:00), enums are names ("WEEK"), nested objects are arrays.

php
json_encode($folder);
// {"name":"avatars","public":true,"retention":"NONE",
//  "cache":{"maxAge":null,"visibility":null},
//  "createdAt":"2026-11-07T14:54:51+00:00","updatedAt":"2026-11-07T14:54:51+00:00"}

Answer checks. If the server’s answer lacks a field or has the wrong type in it, the SDK throws ResponseException with the path to the field — e.g. S5W v1/check: bytes.quota must be int, got string.

File

A file in the bucket.

Field Type Description
id string 16 characters of A-Za-z0-9_-; addresses the file everywhere. The server calls it a slug. Does not change on rename or move
name string the name; unique within the folder
folder ?string the folder’s name; null — the bucket root
content FileContent size, type, extension, hash
public bool whether it is served at publicUrl without a key; follows the folder
deduplicated bool these bytes were already in the bucket — no disk space spent
processed ?Processing the image processing report; only in the answer to an upload, null when read
expiresAt ?DateTimeImmutable when the folder’s retention deletes the file; null — it is not deleted by itself
privateUrl string the /p/{id} address — serves the file with any key in the Authorization header
publicUrl ?string the /o/{bucketId}/{id} address — no key; null while the file is not public
createdAt DateTimeImmutable when uploaded
updatedAt DateTimeImmutable when changed (name, folder)

The addresses are built from the server’s PUBLIC_BASE_URL — see S5W configuration.

File::ID_PATTERN, File::isValidId()

The id format: /^[A-Za-z0-9_-]{16}$/. The method checks only the shape, not whether the file exists — handy to drop junk from a page address before any request.

php
public const string ID_PATTERN = '/^[A-Za-z0-9_-]{16}$/';
public static function isValidId(string $id): bool
php
File::isValidId('FXOkqegbdrNRWQgc');   // true
File::isValidId('../etc/passwd');      // false

FileContent

The file’s bytes. Two files with the same content point at the same bytes.

Field Type Description
size int size in bytes
mime string MIME type, detected by the server from the content
extension string the extension matching the type; may be empty
hash string SHA-256 of the content, 64 lowercase characters

Processing

What the server did with an image at upload.

Field Type Description
applied bool whether processing happened
reason ?string why it didn’t: no options, nothing to do, animated, output is larger than source; null if it did
operations list<string> what was done, e.g. ["resize:400x267", "encode:webp@80"]
source ?ImageInfo the original image; null if nothing was done
result ?ImageInfo the result; null if nothing was done

Methods

saved(): int — bytes saved: source->size - result->size. Negative if the result is heavier; 0 if nothing was done.

ImageInfo

Field Type Description
width int width, pixels
height int height, pixels
size int size, bytes
mime string MIME type

Folder

A folder. One level, no nesting; the name is unique within the bucket.

Field Type Description
name string the name
public bool the files inside are served without a key
retention Retention how long the files live
cache CachePolicy the folder’s cache policy
createdAt DateTimeImmutable when created
updatedAt DateTimeImmutable when changed

Folder::ROOT

The bucket root, wherever a folder is expected.

php
public const string ROOT = '/';

/ can never be a real folder’s name, so there is no confusion. Where it applies:

Method What Folder::ROOT means
files()->list(), files()->all() only the files outside any folder
files()->move(), files()->update() move into the root (the file becomes public)
files()->upload(), uploads()->send() and the other uploads upload into the root — the same as null

CachePolicy

A cache override at the folder level. Every null field is inherited from the bucket.

Field Type Description
maxAge ?int max-age, seconds
visibility ?CacheVisibility who may cache

Methods

isInherited(): bool — true if both fields are null: the folder overrides nothing.

Page

One page of a list. Mirrors the server’s { meta, data } format.

Field Type Description
items list<T> this page’s items (File or Folder)
current int the page number, from 1
size int the page size the server applied
total int how many items match in total, across all pages
pages int how many pages in total
previous ?int the previous page’s number, or null
next ?int the next page’s number, or null

Methods

hasNext(): bool — whether there is a next page.

isEmpty(): bool — whether this page is empty.

count($page) — how many items are on this page (Countable). Not to be confused with total.

foreach ($page as $item) — walks this page’s items (IteratorAggregate).

map(callable $fn): Page — a new page where every item went through $fn; the meta is kept. Handy to turn entities into your own DTOs.

toArray() / jsonSerialize() — { meta: { current, size, total, pages, previous, next }, data: [...] }.

php
$page = $s5w->files()->list(limit: 10);

count($page);       // 10 — on this page
$page->total;       // 134 — in total
$page->hasNext();   // true

$names = $page->map(fn(File $f) => $f->name);
json_encode($names);   // {"meta":{…},"data":["a.txt","b.txt",…]}

previous past the last page

Ask for a page beyond the last one and the server returns an empty list, but previous equals current - 1 — e.g. 998 with pages = 1. For navigation rely on pages.

UploadSession

The state of a chunked upload. Every uploads() call returns a new session carrying the server’s current offset.

Field Type Description
id string the session’s UUID; an empty string if deduplication kicked in
name string the name declared at the start
size int the declared size, bytes
offset int how many bytes are already on the server — the next chunk starts here
chunkSize int the chunk size the server asks for; 0 on deduplication
expiresAt ?DateTimeImmutable when the session is removed if no chunk arrives; null on deduplication
file ?File the ready file, if the content was already in the bucket

Methods

isDeduplicated(): bool — the content was in the bucket, the file is ready, nothing to send.

isComplete(): bool — every byte is on the server (offset >= size), ready to assemble.

remaining(): int — how many bytes are left to send.

KeyInfo

The answer of check(): what is behind the key.

Field Type Description
bucket BucketRef the key’s bucket
access TokenAccess the access level
expiresAt ?DateTimeImmutable when the key expires; null — never
storage Storage space in the bucket

Methods

expiresBefore(DateTimeInterface $at = now): bool — whether the key will have expired by $at.

php
if ($s5w->check()->expiresBefore(new DateTimeImmutable('+7 days'))) {
  $logger->warning('The S5W key expires within a week');
}

BucketRef

Field Type Description
id string the bucket’s UUID; the {bucketId} in public addresses /o/{bucketId}/{id}
name string the bucket’s name

Storage

Space in the bucket, in bytes.

Field Type Description
quota int the quota
used int used
free int free

Methods

fits(int $bytes): bool — whether $bytes more would fit.

usage(): float — the used share, from 0.0 to 1.0.