Via the required structure wrapper, you expose your package directories
to Fusion and users by marking them with their paths. Each path is relative to
the package root, begins with a leading /, can include multiple segments
separated by /, and maps to values explained in the following sections:
Note
Paths can map to existing directories or ones Fusion will generate. Do not create empty directories manually.
Stateful Directory Indicator
The only required structure entry is the stateful directory indicator. It
specifies a custom path inside your package where Fusion stores stateful files:
{
"structure": {
"/path": "stateful"
}
}
Stateful files are data generated during task execution that reflect the current state of the package rather than its static source files. Depending on the task, the package's position in the dependency graph, and the environment-specific metadata files, Fusion regenerates all or a subset of the following files each time it manages the package.
Requireable files returning datasets in each package individually:
asap.php: pre-loadable code registrylazy.php: on-demand loadable code registryprefixes.php: on-demand namespace prefixes of all packagesextensions.php: mapped extension dirs
Additional root package files:
PrefixAutoloader.php: prebuilt autoloadersnapshot.local.json: local dependency versionssnapshot.dev.json: shared dependency versionssnapshot.json: production dependency versions
Dependency Source
Packages usually depend on other packages to reuse existing logic. To let
Fusion resolve and download such dependencies for your package, define
their source locations in the metadata structure as a sequence of segments
separated by /.
Note
As an example of a typical sequence of segments, we use Fusion's own source
valvoid.com/valvoid/fusion/1.1.0, available on the
package's detail page.
Leading API Segment
The first segment of a source identifies which of the configured hub APIs to use:
valvoid.com: our example sourcegitlab.comgithub.combitbucket.orggitdir
Wrapped Path Segments
The segments between the leading API segment and the trailing reference segment define the path to the package on the external host, which, depending on the platform, may represent various naming conventions such as package, organization/project, project, or another type of identifier.
Note
In addition to the external platform identifier, the path segments also serve as the package identifier segments in the metadata, and therefore must match them.
As in our example source, the path segments valvoid/fusion correspond to
the default Valvoid API identifier:
$url = "<api>/v1/registry/" .
// identifier
urlencode("valvoid/fusion") . "/1.1.0/fusion.json";
And the metadata package identifier it returns:
{
"id": "valvoid/fusion"
}
In the case of a superset path, non-identifier segments are excluded
by the single quote ' character prefix. For example, Fusion also has a
GitLab repository illustrating a superset path:
gitlab.com/valvoid/fusion/'code
Trailing Reference Segment
The last source segment is a logical expression that the required package versions must satisfy. In addition to the semantic version, the expression may consist of the following parts:
- The
&&and||operators - The condition brackets
() - The version tag name
{0,10}indicator - The offset
:indicator - One of the signs as prefix before the version:
!=not equal==equal=greater than or equal<=less than or equal>greater than<less than
In our example source, the trailing segment 1.1.0 covers all production
versions without breaking changes and is shorthand for >=1.1.0 && <2.0.0
(valvoid.com/valvoid/fusion/>=1.1.0 && <2.0.0), meaning versions must be
at least 1.1.0 but less than 2.0.0. Production here refers to semantic
versions without a release part (for example, 1.1.0-alpha), which Fusion
ignores by default if not explicitly defined.
Note
Since a semantic version by itself already implies a range, signless semantic version references are used as shorthand range expressions for all versions without breaking changes.
Note
Fusion ignores by default the release part if not explicitly defined.
If a source, such as Fusion's GitLab gitlab.com/valvoid/fusion/'code,
points to a VCS repository, the trailing reference segment may need to be more
flexible, allowing a version tag prefix, such as v1.2.3, or an offset,
such as:
==v1.1.3-dev:main: branch (head commit)==1.2.3:541bae1712ad746fecc67b633ae4e1f2de73851e: commit==v1.2.3+23453:v1.0.0: tag
Note
Fake offset versions must be prefixed with == and use : to
specify a VCS reference.
Nested Dependencies
Once a source is defined, besides specifying the external location, it also
serves as a directory-type indicator marking a custom dependencies directory
inside your package, such as:
{
"structure": {
"/dependencies": [
"valvoid.com/valvoid/fusion/1.1.0"
]
}
}
Inside the marked directory, Fusion normalizes the dependency graph by using package identifiers as subdirectories. This approach keeps the structure user-readable (if you need to check a dependency in your package) and avoids conflicts, since a path can contain multiple sources and dependencies can have their own dependencies.
For example, our source would result in the subdirectory
/dependencies/valvoid/fusion, and if we add another source such as the
Box - PHP DI Container,
whether added directly or as a nested dependency from Fusion, the directory
structure would be:
/dependencies/valvoid/box/fusion
The normalized directory is also shareable between scoped metadata files. For
example, the structure is the same whether Box is specified in the shared
fusion.dev.php or local fusion.local.php metadata:
return [
"structure" => [
"/dependencies" => [
"valvoid.com/valvoid/box/1.0.0"
]
]
];
Note
Metadata files cannot contain the same source, but they can share the same path.
Recursive Self-Dependency
Since Fusion also manages root packages, you can declare a nice-to-have dependency on your own package, as shown in the metadata of our example source:
{
"structure": {
"valvoid.com/valvoid": "fusion/1.1.0"
}
}
The missing path makes this source different from nested dependencies. It
points to the package root, making the source argument optional when
updating a root package, such as Fusion:
fusion build
Otherwise, you would need to run:
fusion build build.source=valvoid.com/valvoid/fusion/1.1.0
Note
This type of source acts as a default usability fallback for missing input. It does not apply if a source is explicitly provided by the user, or if the package is nested within another project where the parent package already defines the source.
In shared or local development, you typically do not want the package to update
automatically to a production version. You can prevent this by setting the
recursive dependency to null in the optional fusion.local.php or
fusion.dev.php metadata, as shown in our example (GitLab repo):
return [
"structure" => [
"valvoid.com/valvoid/fusion" => null
]
];
Structure Segmentation
All metadata files are optimized for user-friendly input. Paths and sources can be broken into segments to reduce redundancy and make configuration easier. For example, using the sources from our previous examples, you can write:
{
"structure": {
"valvoid.com/valvoid": {
"/dependencies": [
"fusion/1.1.0",
"box/1.0.0"
]
}
}
}
Path segments start with / and must be used as keys. Source segments do
not start with / and can appear as either keys or values. If a source is
split into segments, its key can begin anywhere in the structure, but the
final part must always be the source value.
Extendable Directory Indicator
The optional extendable directory indicator marks a path inside your
package that can be extended through Fusion's built-in extension logic:
{
"structure": {
"/path": "extendable"
}
}
Note
The directory must not exist if your package has no default content.
A parent package can map its own directory to this internal path as a reference:
{
"structure": {
"/custom": ":your/package/identifier/path"
}
}
Note
The mapping starts with : followed by the package identifier and ends with
the extendable path inside the package.
Mappings are stored in the stateful extensions.php file, listing absolute
directories of all extenders. Array keys indicate package positions in the
dependency graph, in top-down order:
return [
"/path" => [
// dependency of the root package
// extends your package
2 => "/absolute/extender/dir",
// root package
// has "2" as dependency and also extends your package
7 => "/other/extender/dir"
]
];
Note
The mapped directory is only a reference. The extended package must iterate over or process the linked directory. Fusion does not automatically inject its contents.
Mutable Directory Indicator
Fusion recycles existing packages when building a new external package state.
The optional mutable directory indicator marks non-recyclable content in your
package, for example files generated by a lifecycle callback, that must be
copied from the new state into the existing package each time:
{
"structure": {
"/path": "mutable"
}
}
Note
Use mutable for content that cannot be reused across package states. Fusion
ensures the latest version is injected into the recycled package during the
build process.