
# Marketplace

`vsix` adds a Marketplace icon to the activity bar. It opens a search over
[Open VSX](https://open-vsx.org), a card per result, and an install button on each one. A click
fetches the extension's `.vsix`, unpacks it in the browser, and runs it beside your built-ins.

```ts
import { vsix } from "codelet/extensions/vsix";
import { extensions } from "codelet/extensions/extensions";
import { logs } from "codelet/extensions/logs";
import { Workbench, FileSystem } from "codelet/workbench";

const workbench = new Workbench({
  parent: document.getElementById("app")!,
  fs: new FileSystem({ "/README.md": "# Hello" }),
  extensions: [vsix(), extensions, logs()],
});
```

Mount [Logs](/extensions/logs) beside it: an extension that reaches for something codelet
doesn't answer shows up there, stack trace and all. [Extensions view](/extensions/extensions)
lists what an installed extension actually contributed.

::warning
Not every published extension runs. Enough of the `vscode` namespace is answered for some to
work end to end; others fail partway through. Treat this as a way to find out what an extension
asks for, not as a way to depend on one running.
::

::note
Two things leave the page: a search is a `POST` to Open VSX's gallery endpoint, and installing
is a `GET` for the `.vsix` itself. A card's icon is whatever image the publisher hosted. Nothing
else is fetched.
::

## Options

| Option     | Type       | Default     | Description                                                               |
| ---------- | ---------- | ----------- | ------------------------------------------------------------------------- |
| `registry` | `Registry` | `openVsx()` | Where a search goes. `openVsx(site)` points at another Open VSX instance. |

`Registry` is `(query: string, signal: AbortSignal) => Promise<Listing>`. Pass a function of
your own to put a company gallery behind the same search box — the pane doesn't care what shape
the address is, only that it answers with a listing.

## What it adds

- A **Marketplace** pane in the activity bar: a search box, a card per result, and an install or
  uninstall button on each.
- A tab per extension, opened by clicking its card: the packaged manifest, every contribution
  point it declares, and its files, largest first. Each file opens read-only in its own tab.
- Three commands other extensions already call: `workbench.extensions.search`,
  `workbench.view.extensions`, and `workbench.extensions.action.showExtensionsWithIds`. A
  welcome card's `[Browse](command:...)` link lands here without knowing this pane exists.

## An install lasts the session

Nothing about an install is written down. Reload the page and you get the workbench you built,
without it — the same button on the card is the way back out before then. What _is_ kept is the
downloaded archive itself, by version, in the browser's cache storage, so reinstalling the same
version doesn't fetch it twice.

The bundle runs in the page, not a worker, so it shares the same objects your own extensions do.
That's also the cost: an installed extension isn't sandboxed from your page. Open VSX doesn't
review what it hosts, so install counts are the only signal there is — under a thousand installs,
a card is drawn dim with a caution.

## What can actually run

An extension the registry marks as having no `browser` entry point is sorted to the bottom and
drawn grey, with a button reading "Try anyway" instead of "Install" — that tag is the registry's
word, not the archive's, and a manifest can contribute plenty with no code at all.

Once something is installed:

- **There's no node.** `require("fs")` and friends load without error and warn on use; a bundle
  that reads `process` or `Buffer` before anything else runs dies at that line.
- **Activation events are ignored.** Everything installed activates immediately, same as every
  built-in.
- **A webview reads its own files only through what its manifest already named.** `asWebviewUri`
  resolves a packaged file into a `data:` URI at build time; an address assembled at runtime
  points nowhere a browser can load.

:read-more{to="/extensions"}
