Definition
The definition object, how the hub identifies and versions an app, and the parent/child metadata.
const definition = {
name: 'Porch Light', // required — shown in the install picker
namespace: 'com.example', // required — a string you control; with name, it is the app's identity
description: 'Light the porch at dusk.',
author: 'Jane Developer',
category: 'lighting', // free text used for grouping: lighting, climate, security, automation, …
iconUrl: '', // optional 1× icon
iconX2Url: '', // optional 2× icon
};The full field list is on the SmartAppDefinition reference.
Identity
The hub identifies a definition by namespace + name. Registering code with the same pair again
updates that definition instead of creating a second one, and every installed instance follows the
update on its next run. Rename either field and you have a new, unrelated app.
Pick a namespace like a reverse domain (com.example) or an organisation handle. novon.system is
reserved for the built-in apps.
Versioning
Do not put a version in the definition. The hub assigns an integer version to each
definition and increments it whenever the stored source changes. (Some older examples show a semver
string; it is ignored.)
Parent and child apps
A definition can declare that it hosts children, or that it is a child of another definition:
| Metadata | Meaning |
|---|---|
childApps: [{ namespace, name }] | this app is a container; the listed definitions can be installed under it |
parent: { namespace, name } | this app can only be installed under an instance of that parent |
singleInstance: true | at most one instance per location |
singletonPerParent: true | at most one instance per parent instance |
deprecated: true | hidden from the install picker; existing instances keep running |
These live in the definition's metadata when the app is registered (built-ins declare them in a JSDoc manifest at the top of the file). How parents and children cooperate at run time is covered in Parent and child apps.
Writing style
The examples on this site declare definition and preferences as top-level consts and
handlers as top-level functions; the hub reads them by name from the global scope. In TypeScript
the built-ins use an explicit $g.definition = … assignment instead — see
TypeScript authoring. Both work.