spora-ai / installer
Routes `spora-plugin` packages to `plugins/{$name}/`, `spora-frontend` packages to `public/spora/`, and `spora-plugin-frontend` packages to `public/plugins/{$slug}/` when installed via Composer. Companion to spora-ai/spora-core.
Package info
github.com/spora-ai/spora-installer
Type:composer-plugin
pkg:composer/spora-ai/installer
Requires
- php: ^8.4.1
- composer-plugin-api: ^2.0
Requires (Dev)
- composer/composer: ^2.7
- mockery/mockery: ^1.6
- pestphp/pest: ^4.0
README
Composer plugin for Spora. Routes three Composer package types:
spora-plugin→plugins/{$name}/spora-frontend→public/spora/spora-plugin-frontend→public/plugins/{$slug}/
…instead of Composer's default vendor/ install location.
You don't install this directly — it ships as a transitive dependency of
spora-ai/spora-core.
The Spora host application activates it automatically the first time
Composer runs in a project that depends on spora-ai/spora-core.
Usage
composer require spora-ai/spora-core # Any package with type "spora-plugin" now installs to plugins/<name>/ # instead of vendor/<vendor>/<name>/.
This is the package-type router that powers Spora's plugin system.
Frontend bundles (spora-plugin-frontend)
A second installer routes spora-plugin-frontend packages into
public/plugins/<slug>/ (the directory the host SPA lazy-loads
/plugins/<slug>/main.js from at runtime). The destination <slug> is
not derived from the package short name — that previously produced a
runtime 404 when the parent PHP plugin's plugin.json#slug (e.g. foo)
differed from the frontend package's short name (e.g.
spora-plugin-foo-frontend).
The frontend package declares the slug explicitly in composer.json:
{
"name": "spora-ai/spora-plugin-foo-frontend",
"type": "spora-plugin-frontend",
"extra": {
"spora-plugin-slug": "foo"
}
}
Rules:
extra.spora-plugin-slugMUST equal the parent PHP plugin'splugin.json#slug.- The installer fails loud (
InvalidArgumentException) when the field is missing, empty, or not a string. There is no fallback to the package short name. - Slugs must match
^[a-z0-9]+(?:-[a-z0-9]+)*$after trimming —/,\,.., whitespace, uppercase, and underscores are rejected as path-traversal protection under the public web root.
See docs/spora-plugin-frontend.md for the full contract, error messages, and the Spora docs → Declaring the install destination slug for the operator-facing guide.
License
MIT.