Files
pastilhasandClaude Opus 5 79ff366802 become an Officer plugin
av-club keeps doing exactly what it did — sharp, ffmpeg and ffprobe behind one
API, and the invariant that the caller never names a path. What changes is how it
is reached and who decides who may reach it.

`src/` is `sidecar/`, because that is the name the platform looks for:
`sidecar/index.ts` present means "this plugin ships a process", and presence is
the declaration for everything structural here. `manifest.ts` at the root is the
other half of that rule.

api/router.ts is a proxy and nothing else. the platform authenticates, checks the
`av-club` permission, and forwards — so the sidecar now accepts a request
carrying `X-Officer-User` and no longer demands its own bearer token from
callers who came that way. it binds LOOPBACK to make that trustworthy, which is
the same boundary caldav's DAV door already relies on. AV_CLUB_TOKEN stays, and
still guards anything calling the port directly: fofos/platform is the stated
first consumer and is not Officer.

THREE THINGS HAD TO GO, and each one broke it in a way worth writing down.

package.json and bun.lock: a package.json inside a plugin is a package boundary,
so bun stops walking up for the platform's tsconfig and `@@/sidecar/connect`
stops resolving. the sidecar died on its first import, fifteen times. npm
dependencies go in the manifest instead, where npm-deps.ts intersects them across
plugins into one plugins/node_modules — which is also how this surfaced a real
conflict: sharp ^0.33.5 (atelier) and ^0.35.3 here do not overlap, since a 0.x
caret pins the minor. atelier moved up; it calls one method.

tsconfig.json: same failure one layer earlier, shadowing the platform's `@@/*`
paths so api/router.ts would not mount. no other plugin has one.

no screens, deliberately. this is an API and a body of documentation; its callers
are a commander watching a folder, an agent, or curl. a dock tile would advertise
a page with nothing on it.

verified through /api/av-club with an agent key: a 3000x2000 jpeg uploaded,
probed, and resized to a 1200x800 avif — 166 KB to 1 KB — without the caller ever
holding av-club's own token.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
2026-08-28 22:36:53 +01:00

13 KiB
Raw Permalink Blame History

sharp — the operation vocabulary

Generated from sidecar/sharp/vocabulary.ts by scripts/gen-docs.ts. Do not edit by hand — run bun run docs.

Every operation is named what sharp names it and takes sharp's own arguments, so sharp's documentation describes what each one does. This page describes what av-club accepts: the bounds, which exist because an unbounded number here is a denial of service rather than a picture.

Requests go to POST /v1/sharp — see API.md for the envelope.

{
  "input": "as_9f86d081884c7d659a2feaa0c55ad015",
  "options": { "failOn": "warning" },
  "pipeline": [
    { "rotate": {} },
    { "resize": { "width": 1200, "fit": "inside", "withoutEnlargement": true } }
  ],
  "output": { "format": "avif", "options": { "quality": 55 } }
}

Three things that catch people

rotate with no angle applies the EXIF orientation. Output is re-encoded and metadata is dropped, so a photo that looked upright in a phone's gallery arrives sideways on the web unless you include { "rotate": {} }. This is the most commonly forgotten operation.

resize enlarges by default. A 300px source asked for 800px comes back 800px and soft. Pass withoutEnlargement: true unless you actually want that.

Metadata is always stripped and there is no way to keep it. withMetadata is deliberately not in this vocabulary — it is how a client's GPS coordinates end up published. Dimensions come back in the response instead.

Input options

sharp's constructor options, passed as options.

Parameter Accepts
failOn none · truncated · error · warning. How strict to be about a damaged file. sharp's default is 'warning'.
density number, 1–2400. DPI for vector input.
pages integer, -1–1000. Pages to read from a multi-page input. -1 for all.
page integer, 0–100000. First page to read.
animated boolean. Read all frames of an animated GIF/WebP. Equivalent to pages: -1.
ignoreIcc boolean. Ignore any embedded ICC profile.
autoOrient boolean. Apply EXIF orientation on load. See the note about rotate() in docs/SHARP.md.
sequentialRead boolean
level integer, 0–256. Level to extract from a multi-level input.
subifd integer, -1–100000. Subldeaf IFD to extract from an OME-TIFF.

limitInputPixels is not accepted: it is the decompression-bomb guard and is set by the server. A 1 KB PNG can expand to tens of gigabytes.

Operations

32 operations, run in the order given.

resize

Resize to given dimensions.

Parameter Accepts
width integer, 1–16383
height integer, 1–16383
fit cover · contain · fill · inside · outside. How the image fits the box. Default 'cover'.
position centre · center · top · right top · right · right bottom · bottom · left bottom · left · left top · north · northeast · east · southeast · south · southwest · west · northwest · entropy · attention. Which part survives when fit is 'cover'. 'attention' picks the busiest region.
background colour — a CSS string like #ffffff, or {r, g, b, alpha}. Fill colour when fit is 'contain'.
kernel nearest · linear · cubic · mitchell · lanczos2 · lanczos3
withoutEnlargement boolean. Never scale UP. Almost always what you want — see docs/SHARP.md.
withoutReduction boolean. Never scale DOWN.
fastShrinkOnLoad boolean

extend

Add pixels to the edges.

Parameter Accepts
top integer, 0–16383
bottom integer, 0–16383
left integer, 0–16383
right integer, 0–16383
extendWith background · copy · repeat · mirror
background colour — a CSS string like #ffffff, or {r, g, b, alpha}

extract

Crop to a region.

Parameter Accepts
left integer, 0–16383
top integer, 0–16383
width integer, 1–16383
height integer, 1–16383

trim

Trim uniform borders.

Parameter Accepts
background colour — a CSS string like #ffffff, or {r, g, b, alpha}
threshold number, 0–255
lineArt boolean

rotate

Rotate. With no angle, applies the EXIF orientation — see docs/SHARP.md.

Parameter Accepts
angle number, -3600–3600. Multiples of 90 are lossless; anything else needs a background.
background colour — a CSS string like #ffffff, or {r, g, b, alpha}

flip

Mirror vertically.

Takes flip directly — { "flip": { "flip": … } }.

Parameter Accepts
flip boolean

flop

Mirror horizontally.

Takes flop directly — { "flop": { "flop": … } }.

Parameter Accepts
flop boolean

sharpen

Sharpen.

Parameter Accepts
sigma number, 0.000001–10
m1 number, 0–1000000
m2 number, 0–1000000
x1 number, 0–1000000
y2 number, 0–1000000
y3 number, 0–1000000

blur

Gaussian blur.

Takes sigma directly — { "blur": { "sigma": … } }.

Parameter Accepts
sigma number, 0.3–1000

median

Median filter — good for noise.

Takes size directly — { "median": { "size": … } }.

Parameter Accepts
size integer, 1–1000

dilate

Morphological dilate.

Takes width directly — { "dilate": { "width": … } }.

Parameter Accepts
width integer, 1–1000

erode

Morphological erode.

Takes width directly — { "erode": { "width": … } }.

Parameter Accepts
width integer, 1–1000

flatten

Composite transparency onto a background.

Parameter Accepts
background colour — a CSS string like #ffffff, or {r, g, b, alpha}

unflatten

Make pure white pixels transparent.

Takes no options.

gamma

Apply gamma correction.

Parameter Accepts
gamma number, 1–3
gammaOut number, 1–3

negate

Invert.

Parameter Accepts
alpha boolean. Also invert the alpha channel.

normalise

Stretch the histogram to full range.

Parameter Accepts
lower number, 0–99
upper number, 1–100

clahe

Contrast-limited adaptive histogram equalisation.

Parameter Accepts
width integer, 1–16383
height integer, 1–16383
maxSlope integer, 0–100

convolve

Apply a convolution kernel.

Parameter Accepts
width integer, 1–100
height integer, 1–100
kernel array of 1–10000 numbers, each -1000–1000
scale number, -10000–10000
offset number, -10000–10000

threshold

Reduce to black and white at a cutoff.

Parameter Accepts
threshold integer, 0–255
greyscale boolean

linear

Multiply and add: out = in * a + b.

Parameter Accepts
a array of 1–4 numbers, each -1000–1000
b array of 1–4 numbers, each -1000–1000

recomb

Recombine channels with a 3x3 matrix.

Takes matrix directly — { "recomb": { "matrix": … } }.

Parameter Accepts
matrix array of 9 numbers, each -100–100

modulate

Adjust brightness, saturation, hue and lightness.

Parameter Accepts
brightness number, 0–100
saturation number, 0–100
hue number, -3600–3600. Degrees.
lightness number, -100–100

tint

Tint with a colour.

Takes color directly — { "tint": { "color": … } }.

Parameter Accepts
color colour — a CSS string like #ffffff, or {r, g, b, alpha}

greyscale

Convert to greyscale.

Takes greyscale directly — { "greyscale": { "greyscale": … } }.

Parameter Accepts
greyscale boolean

toColourspace

Convert to a colourspace.

Takes colourspace directly — { "toColourspace": { "colourspace": … } }.

Parameter Accepts
colourspace srgb · rgb · cmyk · lab · b-w · hsv · scrgb · lch · grey16 · rgb16

pipelineColourspace

Set the colourspace operations are performed in.

Takes colourspace directly — { "pipelineColourspace": { "colourspace": … } }.

Parameter Accepts
colourspace srgb · rgb · cmyk · lab · b-w · hsv · scrgb · lch · grey16 · rgb16

removeAlpha

Drop the alpha channel.

Takes no options.

ensureAlpha

Add an alpha channel if absent.

Takes alpha directly — { "ensureAlpha": { "alpha": … } }.

Parameter Accepts
alpha number, 0–1

extractChannel

Keep one channel.

Takes channel directly — { "extractChannel": { "channel": … } }.

Parameter Accepts
channel red · green · blue · alpha · 0 · 1 · 2 · 3

bandbool

Boolean-combine all channels into one.

Takes operator directly — { "bandbool": { "operator": … } }.

Parameter Accepts
operator and · or · eor

composite

Overlay another asset. input is an asset id, never a path.

Parameter Accepts
input asset id (never a path). The asset to overlay. Must already be uploaded.
blend clear · source · over · in · out · atop · dest · dest-over · dest-in · dest-out · dest-atop · xor · add · saturate · multiply · screen · overlay · darken · lighten · colour-dodge · color-dodge · colour-burn · color-burn · hard-light · soft-light · difference · exclusion
gravity centre · center · north · northeast · east · southeast · south · southwest · west · northwest
top integer, 0–16383
left integer, 0–16383
tile boolean
premultiplied boolean

Output formats

Given as output.format, with output.options carrying the encoder settings. Defaults to webp.

jpeg

JPEG.

Parameter Accepts
quality integer, 1–100
progressive boolean
chromaSubsampling 4:4:4 · 4:2:2 · 4:2:0
optimiseCoding boolean
mozjpeg boolean. Turns on a bundle of mozjpeg settings at once.
trellisQuantisation boolean
overshootDeringing boolean
optimiseScans boolean

png

PNG.

Parameter Accepts
progressive boolean
compressionLevel integer, 0–9
adaptiveFiltering boolean
palette boolean. Quantise to a palette — much smaller for flat graphics.
quality integer, 0–100
effort integer, 1–10
colours integer, 2–256
dither number, 0–1

webp

WebP.

Parameter Accepts
quality integer, 1–100
alphaQuality integer, 0–100
lossless boolean
nearLossless boolean
smartSubsample boolean
preset default · photo · picture · drawing · icon · text
effort integer, 0–6
loop integer, 0–100000
minSize boolean
mixed boolean

avif

AVIF. Smaller than WebP at the same quality, slower to encode.

Parameter Accepts
quality integer, 1–100
lossless boolean
effort integer, 0–9. Higher is smaller and much slower.
chromaSubsampling 4:4:4 · 4:2:0
bitdepth 8 · 10 · 12

tiff

TIFF.

Parameter Accepts
quality integer, 1–100
compression none · jpeg · deflate · packbits · ccittfax4 · lzw · webp · zstd · jp2k
predictor none · horizontal · float
pyramid boolean
tile boolean
tileWidth integer, 1–16383
tileHeight integer, 1–16383
xres number, 0.01–100000
yres number, 0.01–100000
resolutionUnit inch · cm
bitdepth 1 · 2 · 4 · 8

gif

GIF.

Parameter Accepts
reuse boolean
progressive boolean
colours integer, 2–256
effort integer, 1–10
dither number, 0–1
interFrameMaxError number, 0–32
interPaletteMaxError number, 0–256
loop integer, 0–100000

jp2

JPEG 2000.

Parameter Accepts
quality integer, 1–100
lossless boolean
tileWidth integer, 1–16383
tileHeight integer, 1–16383
chromaSubsampling 4:4:4 · 4:2:2 · 4:2:0