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
13 KiB
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 |