ComposerAttachment composer.attachment@1
Generated at from
openvibe-contracts v0.419.0 and
openvibe-sdk v0.161.0.
- Version
- 1.0.0
- Owner
- media
- Visibility
- public
- Status
- active
- Compatibility
- backward
- Schema
https://openvibe.network/contracts/composer/attachment.v1.json
composer.attachment@1: one file a person attached to a message in the shared composer. Media stores it and answers this shape from POST /api/v1/attachments (multipart field `file`); a client keeps it until the message is sent, then names it in POST /api/v1/attachments/:id/keep. `kind` is sniffed from the bytes, never taken from the browser: image, video, audio, file or code. `thumb` is a small preview for images and video (absent for the rest), `w`/`h` the pixel size when the file is one Media can measure. An attachment nobody keeps expires after 24 hours; `expires_at` says when, and a keep extends it to the message's life.
Fields
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
id | string | yes | The attachment id (att_ + ULID): what DELETE /api/v1/attachments/:id and POST /api/v1/attachments/:id/keep name. |
|
kind | enum | yes | Decided by Media from the bytes, not the client's claim: image/video/audio when the signature matches, code for recognised source text, otherwise file. Executables are refused at upload. |
|
name | string | yes | The file's original name, sanitised for display; never a path. |
|
size | integer | yes | Bytes stored. |
|
mime | string | yes | The content type Media serves the bytes as, from the sniffed kind and format. | |
url | string | yes | Absolute https URL the bytes are served at. It stays valid while the attachment exists; a kept attachment is the message's to serve. |
|
thumb | string | null | Absolute URL of a preview image: an image's own small copy or a video's first frame. Null when Media could not make one (or the kind has none). |
| |
w | integer | null | Pixel width of an image, video or video preview; null when unknown. |
| |
h | integer | null | Pixel height of an image, video or video preview; null when unknown. |
| |
expires_at | string | yes | When an unkept attachment is deleted. The upload answers now + 24 hours; a keep moves it to the kept window. |
|
Examples
From the contract's own test fixtures: valid ones validate, rejected ones must fail.
Valid: file
{
"id": "att_01JAB2C3D4E5F6G7H8J9K0MNPS",
"kind": "file",
"name": "notes.txt",
"size": 42,
"mime": "text/plain",
"url": "https://openvibe.media/a/01JAB2C3D4E5F6G7H8J9K0MNPS/notes.txt",
"expires_at": "2026-11-11T12:00:00.000Z"
}Valid: image
{
"id": "att_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"kind": "image",
"name": "screenshot.png",
"size": 184320,
"mime": "image/png",
"url": "https://openvibe.media/a/01JAB2C3D4E5F6G7H8J9K0MNPQ/screenshot.png",
"thumb": "https://openvibe.media/a/01JAB2C3D4E5F6G7H8J9K0MNPQ/thumb.jpg",
"w": 1280,
"h": 720,
"expires_at": "2026-11-11T12:00:00.000Z"
}Valid: video
{
"id": "att_01JAB2C3D4E5F6G7H8J9K0MNPR",
"kind": "video",
"name": "clip.mp4",
"size": 52428800,
"mime": "video/mp4",
"url": "https://openvibe.media/a/01JAB2C3D4E5F6G7H8J9K0MNPR/clip.mp4",
"thumb": "https://openvibe.media/a/01JAB2C3D4E5F6G7H8J9K0MNPR/thumb.jpg",
"w": 1920,
"h": 1080,
"expires_at": "2026-11-11T12:00:00.000Z"
}Rejected: bad-id
{
"id": "att_1",
"kind": "file",
"name": "a.txt",
"size": 1,
"mime": "text/plain",
"url": "https://openvibe.media/a/x/a.txt",
"expires_at": "2026-11-11T12:00:00.000Z"
}Rejected: bad-kind
{
"id": "att_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"kind": "spreadsheet",
"name": "book.xlsx",
"size": 12,
"mime": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"url": "https://openvibe.media/a/x/book.xlsx",
"expires_at": "2026-11-11T12:00:00.000Z"
}Rejected: no-url
{
"id": "att_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"kind": "image",
"name": "screenshot.png",
"size": 184320,
"mime": "image/png",
"expires_at": "2026-11-11T12:00:00.000Z"
}Validate
const contracts = require('openvibe-contracts');
contracts.validate('composer.attachment@1', value); // { valid, errors: [{ path, message }] }