{"_id":"@basementstudio/sanity-media-library","_rev":"3-f9a0fb7de91040c9c8a1677948f7c1c8","name":"@basementstudio/sanity-media-library","dist-tags":{"latest":"0.2.0"},"versions":{"0.0.0":{"name":"@basementstudio/sanity-media-library","version":"0.0.0","keywords":["sanity","sanity-plugin","media","media-library","asset-source","dam"],"_id":"@basementstudio/sanity-media-library@0.0.0","maintainers":[{"name":"fedealvarezcampos","email":"fedealvarezcampos@gmail.com"},{"name":"bertodev","email":"bautista@basement.studio"},{"name":"gitchad","email":"tobias@basement.studio"},{"name":"mesteban","email":"mariana@basement.studio"},{"name":"valentinabearzotti","email":"valebearzotti1@gmail.com"},{"name":"mike.aguilar.bsmnt","email":"miqueas@basement.studio"},{"name":"ignmandagaran","email":"ignaciofmandagaran@gmail.com"},{"name":"tomasfdev","email":"hellotomasdev@gmail.com"},{"name":"joserago","email":"jose@basement.studio"}],"homepage":"https://github.com/basementstudio/sanity-media-library#readme","bugs":{"url":"https://github.com/basementstudio/sanity-media-library/issues"},"dist":{"shasum":"1c1618b95b35e6e58a073a3939709ec0854f70d1","tarball":"https://registry.npmjs.org/@basementstudio/sanity-media-library/-/sanity-media-library-0.0.0.tgz","fileCount":62,"integrity":"sha512-OU9vcZUOUuKQu0lEr9GzoYv1/ASYm1xbwuU1AMW10LhrmadDkYtBDtpvxWN0Y3L+cUAYG254Qh5PmYQZnGxGwQ==","signatures":[{"sig":"MEUCIAHPgNlTeii1tvRK+SacyY8oGlP8Kj92oyC91J8XWHxWAiEAk35Iy3ozQHm2M1fm+FMAnP7dZQPmbBk78EHJy2CNUv4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":155659},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20.19 <22 || >=22.12"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"c42ca013dd064c9c40629780171cb1c5d3f8e7c7","private":false,"scripts":{"test":"bun test tests","build":"tsc -p tsconfig.build.json","check":"tsc -p tsconfig.json --noEmit","release":"changeset publish","changeset":"changeset","prepublishOnly":"bun run build","release-canary":"changeset publish --tag canary --no-git-tag","version-canary":"changeset version --snapshot canary","version-packages":"changeset version"},"_npmUser":{"name":"valentinabearzotti","email":"valebearzotti1@gmail.com"},"repository":{"url":"git+https://github.com/basementstudio/sanity-media-library.git","type":"git"},"_npmVersion":"11.11.0","description":"Folder-based media library tool and image asset source for Sanity Studio, with optional per-workspace scoping.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.1","_hasShrinkwrap":false,"packageManager":"bun@1.3.7","devDependencies":{"react":"^19.2.4","sanity":"^5.31.1","react-dom":"^19.2.4","@sanity/ui":"^3.3.5","@types/bun":"^1.3.6","typescript":"^5.9.3","@types/react":"^19.2.9","@sanity/icons":"^3.8.0","@changesets/cli":"^2.29.8","@types/react-dom":"^19.2.3","@changesets/changelog-github":"^0.5.2"},"peerDependencies":{"react":"^19.2.0","sanity":"^5.0.0","react-dom":"^19.2.0","@sanity/ui":"^3.1.13","@sanity/icons":"^3.7.0"},"_npmOperationalInternal":{"tmp":"tmp/sanity-media-library_0.0.0_1786017458039_0.5665835680815832","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@basementstudio/sanity-media-library","version":"0.1.0","keywords":["sanity","sanity-plugin","media","media-library","asset-source","dam"],"_id":"@basementstudio/sanity-media-library@0.1.0","maintainers":[{"name":"fedealvarezcampos","email":"fedealvarezcampos@gmail.com"},{"name":"bertodev","email":"bautista@basement.studio"},{"name":"gitchad","email":"tobias@basement.studio"},{"name":"mesteban","email":"mariana@basement.studio"},{"name":"valentinabearzotti","email":"valebearzotti1@gmail.com"},{"name":"mike.aguilar.bsmnt","email":"miqueas@basement.studio"},{"name":"ignmandagaran","email":"ignaciofmandagaran@gmail.com"},{"name":"tomasfdev","email":"hellotomasdev@gmail.com"},{"name":"joserago","email":"jose@basement.studio"}],"homepage":"https://github.com/basementstudio/sanity-media-library#readme","bugs":{"url":"https://github.com/basementstudio/sanity-media-library/issues"},"dist":{"shasum":"f5c39a9a398f5a0f1b507b04a77b8015f886c56c","tarball":"https://registry.npmjs.org/@basementstudio/sanity-media-library/-/sanity-media-library-0.1.0.tgz","fileCount":62,"integrity":"sha512-H76T8t0pYz95M17zsdL7mk1b6P2sStKFAoQfY36GEzSLV420ooktJJsvbu1PrNqE2xs121DnCjVI+CIGTOiDvg==","signatures":[{"sig":"MEUCIFEkPskJ2/fnWvlzVnBa1vUSlKwIX4QZoEWH1dfVVgc1AiEA2fTA1FZHQjqx8jQq7OBAChcvmQzGnX9Hn2uE28RAtBo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":163196},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20.19 <22 || >=22.12"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"b5814e34bd3c5641631101dabca9bae03d74682e","private":false,"scripts":{"test":"bun test tests","build":"tsc -p tsconfig.build.json","check":"tsc -p tsconfig.json --noEmit","release":"changeset publish","changeset":"changeset","prepublishOnly":"bun run build","release-canary":"changeset publish --tag canary --no-git-tag","version-canary":"changeset version --snapshot canary","version-packages":"changeset version"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:8a524958-8d08-4fb5-a978-b687a93fd8ac"}},"repository":{"url":"git+https://github.com/basementstudio/sanity-media-library.git","type":"git"},"_npmVersion":"11.6.2","description":"Folder-based media library tool and image asset source for Sanity Studio, with optional per-workspace scoping.","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","_hasShrinkwrap":false,"packageManager":"bun@1.3.7","devDependencies":{"react":"^19.2.4","sanity":"^5.31.1","react-dom":"^19.2.4","@sanity/ui":"^3.3.5","@types/bun":"^1.3.6","typescript":"^5.9.3","@types/react":"^19.2.9","@sanity/icons":"^3.8.0","@changesets/cli":"^2.29.8","@types/react-dom":"^19.2.3","@changesets/changelog-github":"^0.5.2"},"peerDependencies":{"react":"^19.2.0","sanity":"^5.0.0","react-dom":"^19.2.0","@sanity/ui":"^3.1.13","@sanity/icons":"^3.7.0"},"_npmOperationalInternal":{"tmp":"tmp/sanity-media-library_0.1.0_1786021171023_0.4731545979689247","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@basementstudio/sanity-media-library","private":false,"version":"0.2.0","packageManager":"bun@1.3.7","description":"Folder-based media library tool and image asset source for Sanity Studio, with optional per-workspace scoping.","type":"module","sideEffects":false,"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./package.json":"./package.json"},"repository":{"type":"git","url":"git+https://github.com/basementstudio/sanity-media-library.git"},"scripts":{"build":"tsc -p tsconfig.build.json","check":"tsc -p tsconfig.json --noEmit","prepublishOnly":"bun run build","test":"bun test tests","changeset":"changeset","version-packages":"changeset version","release":"changeset publish","version-canary":"changeset version --snapshot canary","release-canary":"changeset publish --tag canary --no-git-tag"},"keywords":["sanity","sanity-plugin","media","media-library","asset-source","dam"],"peerDependencies":{"@sanity/icons":"^3.7.0","@sanity/ui":"^3.1.13","react":"^19.2.0","react-dom":"^19.2.0","sanity":"^5.0.0"},"engines":{"node":">=20.19 <22 || >=22.12"},"devDependencies":{"@changesets/changelog-github":"^0.5.2","@changesets/cli":"^2.29.8","@sanity/icons":"^3.8.0","@sanity/ui":"^3.3.5","@types/bun":"^1.3.6","@types/react":"^19.2.9","@types/react-dom":"^19.2.3","react":"^19.2.4","react-dom":"^19.2.4","sanity":"^5.31.1","typescript":"^5.9.3"},"gitHead":"6fbdba040a536e2981782180a22e6418dd777856","_id":"@basementstudio/sanity-media-library@0.2.0","bugs":{"url":"https://github.com/basementstudio/sanity-media-library/issues"},"homepage":"https://github.com/basementstudio/sanity-media-library#readme","_nodeVersion":"24.18.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-EywQJjZWCliIOiuaAYI7f2DSAiha5t3EUHBE/MqwCBr6SLozeTaQaYMjCJTXGc3lcSXub6hQFMiAjLWRn1q1UQ==","shasum":"29e20b9f2ab2851d2ef1c1602657ba2fa9758c1a","tarball":"https://registry.npmjs.org/@basementstudio/sanity-media-library/-/sanity-media-library-0.2.0.tgz","fileCount":70,"unpackedSize":205925,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDtXk2kN5OTU+qMN+V1IMe0uVS2MnngEaGGneRJZUKVGQIgH+CRreWhxdHt2AD62RuInh24ty7Betlp5h+EXZ2AJlk="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:8a524958-8d08-4fb5-a978-b687a93fd8ac"}},"directories":{},"maintainers":[{"name":"fedealvarezcampos","email":"fedealvarezcampos@gmail.com"},{"name":"bertodev","email":"bautista@basement.studio"},{"name":"gitchad","email":"tobias@basement.studio"},{"name":"mesteban","email":"mariana@basement.studio"},{"name":"valentinabearzotti","email":"valebearzotti1@gmail.com"},{"name":"mike.aguilar.bsmnt","email":"miqueas@basement.studio"},{"name":"ignmandagaran","email":"ignaciofmandagaran@gmail.com"},{"name":"tomasfdev","email":"hellotomasdev@gmail.com"},{"name":"joserago","email":"jose@basement.studio"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sanity-media-library_0.2.0_1786114199697_0.798402084547341"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-06T11:57:37.859Z","modified":"2026-08-07T14:50:00.073Z","0.0.0":"2026-08-06T11:57:38.192Z","0.1.0":"2026-08-06T12:59:31.162Z","0.2.0":"2026-08-07T14:49:59.864Z"},"bugs":{"url":"https://github.com/basementstudio/sanity-media-library/issues"},"homepage":"https://github.com/basementstudio/sanity-media-library#readme","keywords":["sanity","sanity-plugin","media","media-library","asset-source","dam"],"repository":{"type":"git","url":"git+https://github.com/basementstudio/sanity-media-library.git"},"description":"Folder-based media library tool and image asset source for Sanity Studio, with optional per-workspace scoping.","maintainers":[{"name":"fedealvarezcampos","email":"fedealvarezcampos@gmail.com"},{"name":"bertodev","email":"bautista@basement.studio"},{"name":"gitchad","email":"tobias@basement.studio"},{"name":"mesteban","email":"mariana@basement.studio"},{"name":"valentinabearzotti","email":"valebearzotti1@gmail.com"},{"name":"mike.aguilar.bsmnt","email":"miqueas@basement.studio"},{"name":"ignmandagaran","email":"ignaciofmandagaran@gmail.com"},{"name":"tomasfdev","email":"hellotomasdev@gmail.com"},{"name":"joserago","email":"jose@basement.studio"}],"readme":"# @basementstudio/sanity-media-library\n\nA folder-based media library for Sanity Studio: a **Media tool** for browsing,\norganizing and cleaning up image assets, plus a matching **image asset source**\nso editors pick from the same library on every image field.\n\nIt works on a plain Studio out of the box, and can additionally **scope assets\nper workspace** — several sites sharing one dataset, each seeing only its own\nimages.\n\n## Features\n\n- File-explorer UI: nested folders, grid/list views, sorting, search\n- Folders nest to any depth, with a breadcrumb trail to navigate back up\n- Drag and drop assets into folders (single or multi-select), including onto\n  breadcrumb ancestors to move them up\n- Upload straight into the current folder\n- Asset dialog: rename, alt text, folder, dimensions/size/MIME info\n- \"Used by\" tab listing the published documents referencing an asset\n- Bulk delete and one-click cleanup of unreferenced assets — anything still in\n  use is detected and kept\n- Optional per-workspace scoping, with a control to reassign an asset to other\n  scopes\n- Image asset source that browses the same library from any image field, with\n  the same grid/list views as the Media tool\n\n## Install\n\n```sh\nnpm install @basementstudio/sanity-media-library\n# or\nbun add @basementstudio/sanity-media-library\n```\n\nPeer dependencies: `sanity` v5, `@sanity/ui` v3, `@sanity/icons` v3, `react` and\n`react-dom` v19.\n\n## Usage\n\n```ts\n// sanity.config.ts\nimport { defineConfig } from \"sanity\"\nimport { structureTool } from \"sanity/structure\"\nimport { mediaLibrary } from \"@basementstudio/sanity-media-library\"\n\nexport default defineConfig({\n  name: \"default\",\n  projectId: \"…\",\n  dataset: \"production\",\n  plugins: [structureTool(), mediaLibrary()],\n})\n```\n\nThat registers a `Media` tool at `/studio/media`, a `mediaFolder` document type,\nand an image asset source that replaces the built-in ones.\n\n### Scoped to a workspace\n\nScoping partitions one dataset between several Studio workspaces. Each workspace\npasses its own `scope.value`; the tool and the asset source then only ever show\nassets stamped with it.\n\n```ts\nconst SITES = [\n  { name: \"business\", title: \"Business\" },\n  { name: \"money\", title: \"Money\" },\n]\n\nexport default defineConfig(\n  SITES.map((site) => ({\n    name: site.name,\n    title: site.title,\n    basePath: `/studio/${site.name}`,\n    projectId: \"…\",\n    dataset: \"production\",\n    plugins: [\n      structureTool(),\n      mediaLibrary({\n        scope: {\n          value: site.name,\n          // Assets predating scoping carry no `sites` field — treat them as\n          // belonging to this scope.\n          fallback: \"business\",\n          // Shown in the asset dialog so an editor can share an asset.\n          options: SITES,\n        },\n      }),\n    ],\n  }))\n)\n```\n\nAn asset can belong to several scopes at once: uploads stamp `sites: [scope]`,\nand the asset dialog toggles the rest. Identical files dedupe to one asset\ndocument in Sanity, so the scope is merged rather than overwritten.\n\n## Configuration\n\n| Option        | Default     | Description                                                                                             |\n| ------------- | ----------- | ------------------------------------------------------------------------------------------------------- |\n| `scope`       | –           | Enables per-workspace scoping (see below). Omit for a single shared library.                              |\n| `folderType`  | `mediaFolder` | Document type used for folders.                                                                         |\n| `toolName`    | `media`     | Tool name, and the Studio URL segment.                                                                    |\n| `toolTitle`   | `Media`     | Tool title in the navbar.                                                                                 |\n| `assetSource` | `replace`   | `replace` hides the built-in image sources, `append` keeps them, `false` registers none.                  |\n| `apiVersion`  | `2025-02-19` | API version for the Studio client.                                                                       |\n\n### `scope`\n\n| Option        | Default | Description                                                                  |\n| ------------- | ------- | ---------------------------------------------------------------------------- |\n| `value`       | –       | Required. The scope this workspace browses and uploads into.                  |\n| `fallback`    | –       | Scope that assets with no scope field belong to. Set it on the legacy scope.  |\n| `options`     | `[]`    | All scopes, listed in the asset dialog so an asset can be reassigned.         |\n| `assetField`  | `sites` | Array field stamped on `sanity.imageAsset`.                                   |\n| `folderField` | `site`  | String field stamped on folder documents.                                     |\n\n## Data model\n\n- **Folders are documents** (`mediaFolder` by default) whose `title` holds the\n  folder's **full path** — `brand/logos`. An asset points at one through the same\n  path string in its `folder` field. Folders are documents rather than a derived\n  list so an empty folder can be created and persists.\n- **Nesting is a materialized path**, not a parent reference. That keeps listing\n  and filtering to plain string comparisons — GROQ cannot express recursive\n  traversal — and means a flat folder created before nesting is already a valid\n  one-segment path, so there is nothing to migrate. The cost is that renaming or\n  moving a folder has to re-point its descendants, which the plugin does in a\n  single transaction.\n- **Intermediate folders can be implied.** An asset in `brand/logos` puts\n  `brand` on screen even when no folder document exists for it, so a path is\n  never unreachable. Creating `brand/logos` does not create a `brand` document.\n- Folder names cannot contain `/`; nesting comes from creating a folder while\n  inside another one.\n- **Assets are untouched `sanity.imageAsset` documents.** Scoping adds an array\n  field (`sites`) and organizing adds `folder`; nothing else is duplicated, so\n  the assets stay usable by any query or plugin.\n- **Deletion is reference-safe.** Before deleting, the plugin counts incoming\n  references per asset and only removes the unreferenced ones, reporting how many\n  were kept. Drafts and release versions count as references. Deleting a folder\n  cascades through its nested folders, and the confirmation says how many folders\n  and images that adds up to. Deletion is a hard delete — Sanity removes the\n  underlying file, so there is no undo beyond your project's history retention\n  and backups.\n\n## Notes\n\n- Native (drag-onto-the-field) uploads bypass the plugin and are therefore\n  unscoped and unfoldered. Assign them from the Media tool, or set\n  `assetSource: \"replace\"` (the default) so browsing always goes through the\n  library.\n- Search is recursive: inside a folder it matches assets in that folder *and*\n  everything nested below it, since a search that stopped at the current level\n  would miss most of a nested library. Browsing without a search term stays\n  scoped to the folder's own contents.\n- Folder documents appear in the default document type list of `structureTool`.\n  Filter them out in a custom `structure` if you don't want editors there — the\n  plugin already removes the type from the global \"create new\" menu.\n- **Drafts and releases protect an asset.** Deletion checks and the \"Used by\"\n  tab count every document that references an asset — published, drafts and\n  release versions alike — so an image used only in an unpublished draft is\n  never deleted by cleanup. These reads run under the `raw` perspective for\n  exactly that reason; a `published` perspective reports a draft-only asset as\n  unreferenced. The tab marks such documents `Unpublished`, so it is clear why\n  an asset was kept.\n\n## Development\n\n```sh\nbun install\nbun run check   # typecheck\nbun run build   # emit dist/\nbun test\n```\n\nReleases run on changesets: add one with `bun run changeset` in every PR that\nchanges `src/`. Merging to `main` opens (or updates) a release PR; merging that\npublishes to npm.\n","readmeFilename":"README.md"}