This Nextcloud app opens and edits .bfly files with Butterfly's supported
embed API. Documents stay in Nextcloud and are loaded into the editor only
while they are open. The app is based on the official
Nextcloud app template at commit
a75bc6ed28ecff0f043f0b36e1b6f46d2d798976.
- Nextcloud 31–34
- PHP 8.1 or newer
- Node.js 24.11 or newer in the 24.x release line, and npm 11, for building the frontend
- Composer for PHP development and tests
nvm install
nvm use
npm ci
npm run build
composer installThe generated js/ and css/ directories are ignored by Git and must be
present in an installed or packaged app.
Build the frontend, then start the included development instance:
npm ci
npm run build
chmod a+rx .
docker compose up -d
docker compose exec --user www-data nextcloud php occ app:enable butterflyOpen http://localhost:8080 and sign in with admin / admin. Upload a
.bfly document, then click it or choose Open in Butterfly from its action
menu. You can also create one from New → New Butterfly document.
Stop the instance with:
docker compose downThe Docker volume keeps the test instance between runs. Use
docker compose down --volumes only when you intentionally want a clean
instance.
If occ app:enable butterfly reports that it cannot write into the apps
directory, make sure this app directory is traversable by the container and
recreate it so Docker applies the SELinux mount label:
chmod a+rx .
docker compose up -d --force-recreate
docker compose exec --user www-data nextcloud php occ app:enable butterflyThe Butterfly bind mount is intentionally read-only. Nextcloud does not need to write to an app that is already present; that error usually means it could not discover the mounted app and attempted to install it instead.
npm run check
composer lint
composer cs:check
composer psalm
composer test:unitSee CONTRIBUTING.md for the complete development workflow.
The app adds a default Files action for .bfly documents. Its authenticated
controller reads the file from the current user's storage, sends the bytes to
the Butterfly iframe with postMessage, and writes bytes back when Butterfly
emits save or exit. Saves include the loaded ETag, so an external change is
reported instead of overwritten.
The editor iframe currently uses https://preview.butterfly.linwood.dev/embed.
The Nextcloud file name is passed through Butterfly's visual-only fileName
embed option. Butterfly provides the title and exit controls; exiting saves
the document and returns to its directory in Nextcloud Files. Only messages
from that exact origin and iframe window are accepted.
Contributions are welcome. Read CONTRIBUTING.md before opening a pull request. Please report vulnerabilities according to SECURITY.md, rather than through a public issue.