artisanpack-ui/media-library
A Laravel media library for handling uploads, storage, and image conversions, with a UI-friendly API for attaching and managing files across your application.
Architecture fit
Media, a service-layer status transition, an Artisan backfill command, and a shared upload path across helper/trait/Livewire/HTTP entry points. This is a good fit for Laravel applications already using the media library.MediaUploaded remains the most strategically useful backend addition: it decouples downstream enrichment such as AI alt-text generation from the upload request lifecycle. TPM value is that feature teams can subscribe with ShouldQueue listeners without forcing synchronous work into uploads.optimization_status, byte counts, formats, and error text. Treat those fields as public API for planning and support.enabled option on useMediaPicker (React and Vue) formalizes a data-fetching contract the package previously left implicit: fetches are now deferrable and gated on consumer intent. That is architecturally the right move — it pushes request timing to the component that knows when the picker is visible.MediaModal change is a behavioral default, not just an additive option. Because MediaModal now passes its own open state into enabled automatically, any app that mounts a closed modal and relied on data arriving in the background will observe the first open as a loading event. Additive API, changed default behavior.autoFetch: false StrictMode fix and the Vue first-filter-change fix are correctness repairs to existing options, not new surface.DOCS_API_TOKEN is unset. Zero runtime impact; it is a publication-pipeline dependency, not a package feature.Integration feasibility
OptimizationStatus and MediaOptimization reduce frontend drift if consumers adopt them. v1.6.0 does not change these types.Technical risk
media:backfill-optimization-status marks existing image rows as optimized. If run incorrectly or incompletely, it can misrepresent historical optimization state. Batching, resumability, and dry-run visibility are key questions. (Unchanged in v1.6.0.)ap.mediaLibrary.uploaded could accidentally duplicate AI alt-text work unless they migrate or disable the old listener. (Unchanged in v1.6.0.)MediaUploaded listener could generate duplicate alt text or duplicate downstream records. (Unchanged in v1.6.0.)processImage() sets failed on exception but still surfaces the exception. That is correct for observability, but upload UX may show failure after the media record already exists. Status may not capture partial format generation. (Unchanged in v1.6.0.)/api/media will now fail or silently pass against an empty list. Any consumer that reads picker results synchronously after mount without awaiting the first open needs review.refresh() calls made while closed are queued and applied on next open. That is sensible, but it means a refresh() issued against a closed modal does not guarantee fresh data at the moment of the call. Consumers assuming synchronous invalidation should re-check.enabled is a footgun if mis-wired. A consumer passing a value that never becomes true, or a Vue getter that does not track correctly, produces a permanently empty picker with no error. Worth an explicit guard or dev warning from the package.ap.mediaLibrary.uploaded hook and the queueable event still needs an explicit migration stance.Key questions
MediaUploaded dispatch after database commit? What payload does it carry? Can a listener failure affect the upload response?pending, and are status transitions atomic under concurrent processing?Media models or overriding MediaResource?ap.mediaLibrary.uploaded for AI alt-text?null, and does the UI render them as N/A without generating support noise?MediaModal auto-wiring of open → enabled opt-outable, or must consumers use a bare useMediaPicker to restore eager fetching? Documenting the escape hatch matters for teams that intentionally prefetch.autoFetch paths?enabled ref/getter typed, and does it handle undefined gracefully?DOCS_API_TOKEN and what happens on rotation?Stack fit
ShouldQueue listeners. Teams without queue infrastructure can still upgrade, but the event's main benefit is reduced until workers exist.MediaUploadService.MediaModal in a persistent layout, dashboard shell, or settings page now gets automatic request suppression while closed. That is a direct win for apps with heavy /api/media volume and is the strongest reason to take v1.6.0 promptly rather than batched into a later UI refresh.Migration path
MediaUploaded listeners and ensure queue workers are running.media:backfill-optimization-status against legacy libraries in batches, monitoring runtime and error output.ap.mediaLibrary.uploaded AI alt-text listener to avoid duplicate work.Compatibility
optimization_formats, package migration auto-discovery, and any published migrations or custom Media model overrides.StrictMode double-invocation behaves differently. Confirm build tooling picks up the new composable signature without a major version bump of the package's frontend entry points.Sequencing
Maintenance
pending rows, unexpected failed rows, and mismatches between optimization_status and actual generated formats.optimization_error is safe to display./api/media traffic but changes where latency appears. Monitoring should track first-open load time for the picker, not just aggregate request counts, or the efficiency gain will be misread as a performance regression.DOCS_API_TOKEN. It fails open (skipped when unset) rather than failing the release, which is the right default — but ownership for secret rotation and for noticing stale docs should be explicit.Support
Scaling
/api/media calls, and reopen without filter changes does not refetch. For apps with modals in persistent shells, this is a straightforward reduction in API and database read load, and it is the cheapest scaling win in either release.Failure modes
failed while the upload response also errors, creating ambiguous user experience.ShouldQueue, impacting upload latency or success.OptimizationStatus/MediaOptimization are not adopted consistently.enabled wired to a condition that never becomes true, producing a silently empty picker.refresh() issued against a closed modal not taking effect until the next open, surprising consumers expecting immediate invalidation.DOCS_API_TOKEN is unset in CI, without a failing signal.Ramp-up
MediaModal, confirm loading affordances on first open, and re-run frontend tests. Budget half a day of frontend QA for a typical app; more if the picker is embedded in multiple shells or inside server-rendered surfaces.How can I help you explore Laravel packages today?