Skip to content

Packaging A Hermes Application

Each Hermes application is distributed in an HDF5 File, which is organized as a rooted and directed graph. For practical purposes, the objects in the graph are named HDF5 objects (defined in the HDF5 Abstract Data Model). The graph is navigated in a similar fashion to POSIX file-systems, by concatenating object names with "/".

For example:

/group1/group2/" traverses the graph from the root, which contains group1, which contains and retrieves group2.

Prerequisites to Packaging an Application

  1. A valid metadata.json for the application.
  2. Any files required for static data need to be prepared and ready for inclusion.
  3. Any files for /usr/lib need to be prepared and ready for inclusion.
  4. Each WASM Component Module required needs to be pre-packaged and signed.
  5. The hermes engine executable.

Tooling

All Packaging operations can be performed with the hermes engine when used from the command line.

To get a list of options related to packaging:

./hermes package --help

The Application Packaging Process

  1. Create an unsigned Application Package.
  2. Sign it as one or more authors.
  3. Optionally, Sign it as one or more publishers.

Creating the unsigned Application Package

./hermes app package <manifest.json> [<optional output path>] [--name <app name override>]
  • manifest.json - Defines the location of all the src artifacts needed to build the package. This file must conform to the manifests json schema. An example manifest of this json schema if here.
  • [<optional output path>] - By default the application will be created in the same directory where manifest placed. This option allows the path of the generated application to be set, it can be absolute or relative to the manifest directory.
  • --name app name override - The name to give the application, instead of taking it from the manifest file.

Note: the extension .happ will automatically be added to the app name to signify this is a Hermes Application.

Signing the Application Package

As the author of the Application:

./hermes package sign <X.509 Private Cert> <app_package_name>

This takes the X.509 Private Certificate presented, and signs or counter-signs the Application package.

As the publisher of the Application:

./hermes package sign --publisher <X.509 Private Cert> <app_package_name>

This takes the X.509 Private Certificate presented, and signs or counter-signs the Application package.

Note: A Hermes Application is INVALID if it does not contain at least 1 Author Signature.

Inspecting a Hermes Application

./hermes package inspect <app_package_name>

This command will dump the logical contents of the Application package and if it is considered valid or not. It does not extract files from the package.
If files need to be extracted or individually accessed outside of Hermes, any HDF5 Viewer can be used.

Manifest Schema

Schema: hermes_app_manifest.schema.json
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "https://raw.githubusercontent.com/input-output-hk/hermes/main/hermes/schemas/hermes_app_manifest.schema.json",
    "title": "Hermes Application Package Manifest Schema",
    "description": "Defines the src packages which are used to build a Hermes Application.\nIt is important that one of the properties `www` or `share` is set or `module` array has at least one item.\nIf all of them are not set and `modules` array is empty, an application cannot be built.",
    "type": "object",
    "additionalProperties": false,
    "properties": {
        "$schema": {
            "type": "string",
            "title": "Application Package Manifest Schema Reference",
            "default": "https://raw.githubusercontent.com/input-output-hk/hermes/main/hermes/schemas/hermes_app_manifest.schema.json",
            "pattern": "^(https://raw.githubusercontent.com/input-output-hk/hermes/main/hermes/schemas/)|(.*/)hermes_app_manifest.schema.json$",
            "description": "Reference to the Application Manifest Schema.\nShould be to https:// this will be validated.\nLocal references are only to simplify development."
        },
        "name": {
            "type": "string",
            "title": "Hermes Application Package name.",
            "description": "Name of the Hermes application package with which it will be created.",
            "default": "app"
        },
        "icon": {
            "type": "string",
            "title": "Application Icon",
            "description": "Link to the Hermes application icon svg file.\nWill be renamed to `icon.svg` inside the package.\nIt Could be a valid URI or regular local path on your system.",
            "pattern": "^([a-z0-9-_\\.+]+://)?(/?([a-zA-Z0-9-_\\.]+))+$",
            "default": "icon.svg"
        },
        "metadata": {
            "type": "string",
            "title": "Application Metadata File",
            "description": "Link to the Hermes application metadata JSON file.\nWill be renamed to `metadata.json` inside the package.\nIt Could be a valid URI or regular local path on your system.",
            "pattern": "^([a-z0-9-_\\.+]+://)?(/?([a-zA-Z0-9-_\\.]+))+$",
            "default": "metadata.json"
        },
        "modules": {
            "type": "array",
            "title": "Application Module Files",
            "description": "List of WASM Component Library Module Files.",
            "items": {
                "type": "object",
                "title": "Application WASM Module Package definition",
                "description": "Prepackaged Hermes WASM Component Module.",
                "additionalProperties": false,
                "properties": {
                    "package": {
                        "type": "string",
                        "title": "Application WASM Module Package File",
                        "description": "Path to the WASM Component Library Module Package File.",
                        "pattern": "^([a-z0-9-_\\.+]+://)?(/?([a-zA-Z0-9-_\\.]+))+[.]hmod$"
                    },
                    "name": {
                        "type": "string",
                        "title": "Application WASM Module Name",
                        "description": "Name of the WASM Component Library Module.\nMust be unique within the Application.\nIf not defined is extracted from the WASM Module itself."
                    },
                    "config": {
                        "type": "string",
                        "title": "Application WASM Module Config",
                        "description": "Path to the WASM Component Library Module Config File.\nThis will replace any `config.json` inside the module.\nIf defined it must be valid according to the modules `config.schema.json` file.",
                        "pattern": "^([a-z0-9-_\\.+]+://)?(/?([a-zA-Z0-9-_\\.]+))+$"
                    },
                    "share": {
                        "type": "string",
                        "title": "Application WASM Module Package Share Dataset.",
                        "description": "Path to the WASM Component Library Module Shareable Data.\nWill replace or augment any data defined within the module itself.",
                        "pattern": "^([a-z0-9-_\\.+]+://)?(/?([a-zA-Z0-9-_\\.]+))+$"
                    }
                },
                "required": [
                    "package"
                ]
            },
            "uniqueItems": true
        },
        "www": {
            "type": "string",
            "title": "Data to be served to a browser at the applications URL from /",
            "description": "A Directory or archive of data to be served to a browser for the App.\nIt Could be a valid URI or regular local path on your system.",
            "pattern": "^([a-z0-9-_\\.+]+://)?(/?([a-zA-Z0-9-_\\.]+))+$"
        },
        "share": {
            "type": "string",
            "title": "Data to be shared amongst all modules within the application.",
            "description": "A Directory or archive of data to be shared with all Modules in the application.\nIt Could be a valid URI or regular local path on your system.",
            "pattern": "^([a-z0-9-_\\.+]+://)?(/?([a-zA-Z0-9-_\\.]+))+$"
        }
    },
    "required": [
        "$schema"
    ]
}

Manifest Example

Example: hermes_app_manifest.json
{
    "$schema": "https://raw.githubusercontent.com/input-output-hk/hermes/main/hermes/schemas/hermes_app_manifest.schema.json",
    "icon": "file://icon.svg",
    "metadata": "file://metadata.json",
    "modules": [
        {
            "package": "file://modules/counter.hmod"
        },
        {
            "package": "file://modules/counter.hmod",
            "name": "counter1",
            "config": "file://modules/counter1/config.json"
        },
        {
            "package": "file://modules/counter.hmod",
            "name": "counter2",
            "config": "file://modules/counter2/config.json",
            "share": "file://modules/counter2/share"
        }
    ],
    "srv": {
        "www": "file://srv/flutter_app.zst",
        "share": "file://srv/share"
    }
}