Telescope
mediaTelescopeExtension — a first-class @adonis-agora/telescope extension that adds a "Media" overview dashboard (uploads, storage operations, image conversions) built from the agora:media:* diagnostics events. Telescope stays an optional, never-imported peer.
@adonis-agora/media already publishes agora:media:* lifecycle events onto the diagnostics bus (see Configuration → Diagnostics). When Telescope is installed, its generic diagnostics watcher records those events automatically — so you get media entries with zero wiring. mediaTelescopeExtension goes one step further: it contributes a dedicated "Media" overview dashboard built from those recorded events.
Telescope is an optional, never-imported peer (>=0.4.0 <1.0.0 — every 0.x from 0.4 on). The extension object structurally (not nominally) satisfies Telescope's TelescopeExtension contract, so @adonis-agora/media never depends on @adonis-agora/telescope — installed or not, the media library behaves identically.
Wire it up
Import the extension from the ./telescope subpath and add it to config/telescope.ts:
import { defineConfig } from '@adonis-agora/telescope'
import { mediaTelescopeExtension } from '@adonis-agora/media/telescope'
export default defineConfig({
extensions: [mediaTelescopeExtension()],
})That's it — no changes to config/media.ts. As long as emitDiagnostics is on (the default), media operations flow onto the bus, Telescope's generic watcher records them as type: 'diagnostic', tag: 'lib:media', and the dashboard's panels read those recorded entries.
What the dashboard shows
mediaTelescopeExtension() registers a "Media" dashboard and the data providers its panels bind to, sourced from the media diagnostics events (attach, delete, conversion, attachment.*, and the upload.* lifecycle):
- Active resumable uploads
- Upload success rate and throughput
- Uploads over time
- Recent uploads
- Storage operations over time
- Attachment activity
- Conversions over time
- Recent conversions
The extension contributes no watcher and no dedicated media entry type. Media events are recorded under the generic diagnostic entry type (tag: 'lib:media'), so the "Media" dashboard is the entry point rather than a separate navigable entry list. (Same design as @adonis-agora/durable/telescope.)
mediaTelescopeExtension(opts) accepts the dashboard options (MediaDashboardOptions) if you need to tune it; the default (mediaTelescopeExtension()) is the common case.
MediaWatcher — richer entries, wired by hand
A watcher does exist, exported as MediaWatcher from the same subpath. It is not part of the extension above, because the AdonisJS Telescope SDK's TelescopeExtension contract doesn't accept watchers — its watchers are core and emitter-based. So it is offered for standalone wiring by a host that wants more than the generic bridge gives it.
import { MediaWatcher } from '@adonis-agora/media/telescope'
const watcher = new MediaWatcher()
watcher.register({ store: telescopeStore }) // your Telescope store
// …later
watcher.dispose()What it buys you over the generic diagnostics watcher: a per-operation entry of type: 'media', with the event's payload flattened into structured content rather than stored as a raw envelope — so an upload entry carries its disk, key, mode and size as fields you can read, not as a nested blob.
Three details make it safe to run alongside everything else:
- No double-recording.
register()claims each channel it records through the reference-countedSymbol.for('@agora/diagnostics:claims')registry, and the genericDiagnosticsWatcherskips claimed channels by default.dispose()releases the claim and detaches every subscription. That skip is honoured from@adonis-agora/telescope0.6.0 onward; on 0.4.x/0.5.x the generic watcher predates the claim registry, so running both records each event twice. The overview dashboard is unaffected either way — it reads the generic entries, and this watcher is opt-in. upload.progressis deliberately excluded — neither recorded nor claimed. A per-chunk event would flood the timeline; it stays available on its channel for programmatic subscribers.- Still zero coupling. It subscribes to the same
node:diagnostics_channelchannels media publishes on. Neither@adonis-agora/telescopenor@adonis-agora/diagnosticsis imported.
Next steps
- Configuration → Diagnostics — the
agora:media:*events the dashboard reads - Upload modes and Resumable / TUS — sources of the
upload.*events
Stores & Processors
The three pluggable seams behind the library — the MediaStore (in-memory + Lucid, with a published migration), the ImageProcessor (sharp), and the Disk contract that reuses @adonisjs/drive. Plus how to write your own.
Errors
Every error class @adonis-agora/media exports, with its stable code, when it is thrown, and which properties it carries — so you can branch on a code instead of a message string.