The overall Web of Things (WoT) concepts are described in the [WoT Architecture](https://w3c.github.io/wot-architecture/) document. The Web of Things is made of entities (Things) that can describe their capabilities in a machine-interpretable format, the Thing Description (TD) and expose these capabilities through the WoT Interface, that is, network interactions modeled as Properties for reading and writing values, Actions to execute remote procedures with or without return values and Events for signaling notifications.

This specification describes a programming interface representing the WoT Interface that allows scripts run on a Thing to discover and consume (retrieve) other Thing Descriptions and to expose Things characterized by WoT Interactions specified by a script.

Scripting is an optional "convenience" building block in WoT and it is typically used in gateways that are able to run a WoT Runtime and script management, providing a convenient way to extend WoT support to new types of endpoints and implement WoT applications like Thing Directory.

Implementers need to be aware that this specification is considered unstable. Vendors interested in implementing this specification before it eventually reaches the Candidate Recommendation phase should subscribe to the [repository](https://github.com/w3c/wot-scripting-api) and take part in the discussions.

Please contribute to this draft using the GitHub Issue feature of the WoT Scripting API repository. For feedback on security and privacy considerations, please use the WoT Security and Privacy Issues.

Introduction

WoT provides layered interoperability based on how Things are modeled: as being "consumed" and "exposed".

By consuming a TD, a client Thing creates a runtime resource model that allows accessing the Properties, Actions and Events exposed by the server Thing exposed on a remote device.

Exposing a Thing requires defining a Thing Description (TD) and instantiating a software stack to serve requests for accessing the exposed Properties, Actions and Events. This specification describes how to expose and consume Things by a script.

Typically scripts are meant to be used on devices able to provide resources (with a WoT interface) for managing (installing, updating, running) scripts, such as bridges or gateways that expose and control simpler devices as WoT Things.

This specification does not make assumptions on how the WoT Runtime handles and runs scripts, including single or multiple tenancy, script deployment and lifecycle management. The API already supports the generic mechanisms that make it possible to implement script management, for instance by exposing a manager Thing whose Actions (action handlers) implement script lifecycle management operations.

For an introduction on how scripts could be used in Web of Things, check the [Primer](https://w3c.github.io/wot-scripting-api/primer) document. For some background on API design decisions check the [Rationale](https://w3c.github.io/wot-scripting-api/rationale) document.

Use Cases

The following scripting use cases are supported in this specification:

Discovery

Consuming a Thing

Exposing a Thing

The WoT object

The WoT object is the API entry point and it is exposed by an implementation of the WoT Runtime. The WoT object does not expose properties, only methods for discovering, consuming and exposing a Thing.

Browser implementations SHOULD use a namespace object such as navigator.wot. Node.js-like runtimes MAY provide the API object through the require() or import mechanism.

      // [SecureContext]
      // [NamespaceObject]
      interface WoT {
        Observable<ThingDescription> discover(optional ThingFilter filter);
        Promise<ThingDescription> fetch(USVString url);
        ConsumedThing consume(ThingDescription td);
        ExposedThing produce(ThingModel model);
        Promise<void> register(USVString directory, ExposedThing thing);
        Promise<void> unregister(USVString directory, ExposedThing thing);
      };
      typedef dictionary ThingTemplate;
      typedef USVString ThingDescription;
      typedef (ThingTemplate or ThingDescription or ConsumedThing) ThingModel;
    

The algorithms for the WoT methods will be specified later, including error handling and security considerations.

The ThingModel type represents either a ThingTemplate, or a ThingDescription or a ConsumedThing object.

The ThingDescription type

Serialized representation of the Thing Description (a JSON-LD document).

In this version of the API, Thing Descriptions are represented as an opaque USVString that can be transmitted between devices.

The ThingTemplate dictionary

ThingTemplate is a dictionary that contains properties representing semantic metadata and interactions (Properties, Actions and Events). It is used for initializing an internal representation of a Thing Description as defined in [[!WOT-TD]], and it is also used in ThingFilter. The set of core properties is defined below. In addition, ThingTemplate may contain other properties as well as defined in the Thing Description from which the Thing object is created.

Support for configuration and security metadata will be added later.

The fetch() method

Accepts an url argument of type USVString that represents a URL (e.g. "file://..." or "https://...") and returns a Promise that resolves with a ThingDescription (a serialized JSON-LD document of type USVString).

The consume() method

Accepts an td argument of type ThingDescription and returns a ConsumedThing object instantiated based on parsing that description.

The produce() method

Accepts a model argument of type ThingModel and returns an ExposedThing object. An ExposedThing can be created in the following ways:

  1. from a ThingTemplate, then adding Properties, Actions, Events and request handlers;
  2. from a Thing Description or a ConsumedThing object, then adding request handlers.

The register() method

Takes two mandatory arguments:

Generate the Thing Description as td, given the Properties, Actions and Events defined for this ExposedThing object. Then make a request to register td to the given WoT Thing Directory.

The unregister() method

Takes two mandatory arguments:

Makes a request to unregister the thing from the given WoT Thing Directory.

The discover() method

Starts the discovery process that will provide ThingDescriptions that match the optional argument ThingFilter. When the argument is not provided, uses all supported discovery methods. Returns an [Observable](https://github.com/tc39/proposal-observable) object that can be subscribed to and unsubscribed from. Errors are also signaled at the subscription object.

Note that canceling a discovery (via invoking unsubscribe()) may not be successful in all cases, for instance when discovery is based on open ended multicast requests. However, once unsubscribe() has been called, implementations MUST suppress further event handling ( i.e. further discoveries and errors) on the Observable. Also, a discovery error may not mean the end of the discovery process. However, in order to respect Observable semantics (error always terminates processing), implementations MUST close or suppress further event handling on the Observable.

The DiscoveryMethod enumeration

          typedef DOMString DiscoveryMethod;
        

DiscoveryMethod represents the discovery type to be used:

  • "any" does not provide any restriction
  • "local" for discovering Things defined in the same device or connected to the device by wired or wireless means.
  • "directory" for discovery based on a service provided by a Thing Directory.
  • "multicast" for discovering Things in the device's network by using a supported multicast protocol.

The ThingFilter dictionary

The ThingFilter dictionary that represents the constraints for discovering Things as key-value pairs.

          dictionary ThingFilter {
            DiscoveryMethod method = "any";
            USVString url;
            USVString query;
            ThingTemplate template;
          };
        

The method property represents the discovery type that should be used in the discovery process. The possible values are defined by the DiscoveryMethod enumeration that MAY be extended by string values defined by solutions (with no guarantee of interoperability).

The url property represents additional information for the discovery method, such as the URL of the target entity serving the discovery request, for instance a Thing Directory (if method is "directory") or a Thing (otherwise).

The query property represents a query string accepted by the implementation, for instance a SPARQL or JSON query. Support may be implemented locally in the WoT Runtime or remotely as a service in a Thing Directory.

The template property represents a ThingTemplate dictionary used for matching against discovered Things.

Queries and templates are experimental features. Implementations are not required to support them. The template matching algorithm will be defined later, but there are two possibilities: either direct matching (property to property) or serializing the template and matching that against TDs.

If queries are specified, but not supported, implementations should signal a NotSupportedError on the subscription objects. For security errors (e.g. authentication error) a SecurityError should be signaled. For query validation errors a TypeError should be signaled. For other errors an Error should be signaled.

Examples

        let discoveryFilter = {
          method: "directory",
          url: "http://directory.wotservice.org"
        };
        let subscription = wot.discover(discoveryFilter).subscribe(
          td => {
            console.log("Found Thing " + td.name);
            // fetch the TD and create a ConsumedThing
            let thing = wot.consume(td);
          },
          error => { console.log("Discovery finished because an error: " + error.message); },
          () => { console.log("Discovery finished successfully");}
        );
        setTimeout( () => {
            subscription.unsubscribe();
            console.log("Discovery timeout");
          },
          5000);
      
        let subscription = wot.discover({ method: "local" }).subscribe(
          td => { console.log("Found local Thing " + td.name); },
          error => { console.log("Discovery error: " + error.message); },
          () => { console.log("Discovery finished successfully");}
        );
      
        let subscription = wot.discover({ method: "local" }).subscribe({
          td => { console.log("Found local Thing " + td.name); },
          error: err => { console.log("Discovery error: " + err.message); },
          complete: () => { console.log("Discovery finished successfully");}
        });
      
        // Use a proprietary extension of "local" discovery via "constraints"
        let bleSub = wot.discover({
          method: "local",
          constraints: [{ protocol: "BLE-4.2" }, { protocol: "NFC" }]
        }).subscribe(
          td => { console.log("Found nearby Thing " + td.name); },
          error => { console.log("Discovery error: " + error.message); }
        );
      
        let subscription = wot.discover({
          method: "myOwnMethod", // not standardized
          url: myDirectoryURL,
          // includes non-standard, app-specific property "constraints"
          constraints: [{ account: "XYZ123", key: "..."}]
        }).subscribe(
          td => { console.log("Found Thing " + td.name); },
          error => { console.log("Discovery error: " + error.message); },
          () => { console.log("Discovery finished successfully");}
        );
      

The ConsumedThing interface

The ConsumedThing interface is a client API for sending requests to servers in order to retrieve or update Properties, invoke Actions, and observe Properties and Events.

      interface ConsumedThing {
        readonly attribute maplike<DOMString, ThingProperty> properties;
        readonly attribute maplike<DOMString, ThingAction> actions;
        readonly attribute maplike<DOMString, ThingEvent> events;
        readonly attribute FrozenArray<WebLink> links;
        // getter for ThingTemplate properties
        getter any(DOMString name);
      };
      ConsumedThing implements Observable;  // for TD changes
    

ConsumedThing represents a local proxy object of the remote Thing.

The properties property represents a dictionary of ThingProperty items.

The actions property represents a dictionary of ThingAction items.

The events property represents a dictionary of ThingEvent items.

  • The links property represents an array of WebLink objects.
  • Examples

    Below a ConsumedThing interface example is given.

            try {
              let subscription = wot.discover({ method: "local" }).subscribe(
                td => {
                  let thing = wot.consume(td);
                  console.log("Thing " + thing.name + " has been consumed.");
                  let subscription = thing.onPropertyChange("temperature")
                    .subscribe(function(value) {
                      console.log("Temperature + " has changed to " + value);
                    });
                  thing.actions["startMeasurement"].run({ units: "Celsius" })
                    .then(() => { console.log("Temperature measurement started."); })
                    .catch(e => {
                       console.log("Error starting measurement.");
                       subscription.unsubscribe();
                     })
                },
                error => { console.log("Discovery error: " + error.message); },
                () => { console.log("Discovery finished successfully");}
              );
            } catch(error) {
              console.log("Error: " + error.message);
            };
          

    The ExposedThing interface

    The ExposedThing interface is the server API that allows defining request handlers, properties, Actions, and Events to a Thing. It also implements the ConsumedThing interface. An ExposedThing is created by the produce() method.

          ExposedThing implements ConsumedThing;
          interface ExposedThing {
            // setter for ThingTemplate properties
            setter void(DOMString name, any value);
            // define how to expose and run the Thing
            Promise<void> expose();
            Promise<void> destroy();
            Promise<void> emitEvent(DOMString eventName, any payload);
            // define Thing Description modifiers
            ExposedThing addProperty(DOMString name, PropertyInit property);
            ExposedThing removeProperty(DOMString name);
            ExposedThing addAction(DOMString name, ActionInit action);
            ExposedThing removeAction(DOMString name);
            ExposedThing addEvent(DOMString name, EventInit event);
            ExposedThing removeEvent(DOMString name);
            // define request handlers
            ExposedThing setPropertyReadHandler(DOMString name, PropertyReadHandler readHandler);
            ExposedThing setPropertyWriteHandler(DOMString name, PropertyWriteHandler writeHandler);
            ExposedThing setActionHandler(DOMString name, ActionHandler action);
          };
          callback PropertyReadHandler = Promise<any>();
          callback PropertyWriteHandler = Promise<void>(any value);
          callback ActionHandler = Promise<any>(any parameters);
        

    The expose() method

    Start serving external requests for the Thing, so that WoT interactions using Properties, Actions and Events will be possible.

    The destroy() method

    Stop serving external requests for the Thing and destroy the object. Note that eventual unregistering should be done before invoking this method.

    The emitEvent() method

    Emits an the event initialized with the event name specified by the eventName argument and data specified by the payload argument.

    The addProperty() method

    Adds a Property with name defined by the name argument and qualifiers and initialization value provided by the property argument of type PropertyInit. It updates the Thing Description. Throws on error. Returns a reference to the same object for supporting chaining.

    The removeProperty() method

    Removes the Property specified by the name argument and updates the Thing Description. Throws on error. Returns a reference to the same object for supporting chaining.

    The addAction() method

    Adds an Action with name defined by the name argument and qualifiers and initialization value provided by the action argument of type ActionInitto the Thing object and updates the Thing Description. Throws on error. Returns a reference to the same object for supporting chaining.

    The removeAction() method

    Removes the Action specified by the name argument and updates the Thing Description. Throws on error. Returns a reference to the same object for supporting chaining.

    The addEvent() method

    Adds an event with name defined by the name argument and qualifiers and initialization value provided by the event argument of type EventInitto the Thing object and updates the Thing Description. Throws on error. Returns a reference to the same object for supporting chaining.

    The removeEvent() method

    Removes the event specified by the name argument and updates the Thing Description. Returns a reference to the same object for supporting chaining.

    The PropertyReadHandler callback

    A function that returns a Promise and resolves it with the value of the Property matching the name argument to the setPropertyReadHandler function, or rejects with an error if the property is not found or the value cannot be retrieved.

    The PropertyWriteHandler callback

    A function called with value as argument that returns a Promise which is resolved when the value of the Property matching the name argument to the setPropertyReadHandler function is updated with value, or rejects with an error if the property is not found or the value cannot be updated.

    Note that this function is invoked by implementations before the property is updated, so the code in this callback function can invoke the readProperty() method to find out the old value of the property, if needed. Therefore the old value is not provided to this method.

    The ActionHandler callback

    A function called with a parameters dictionary argument assembled by the WoT runtime based on the Thing Description and the external client request. It returns a Promise that rejects with an error or resolves if the action is successful or ongoing (may also resolve with a control object such as an Observable for actions that need progress notifications or that can be canceled).

    The setPropertyReadHandler() method

    Takes name as string argument and readHandler as argument of type PropertyReadHandler. Sets the handler function for reading the specified Property matched by name. Throws on error. Returns a reference to the same object for supporting chaining.

    The readHandler callback function will implement reading a Property and SHOULD be called by implementations when a request for reading a Property is received from the underlying platform.

    There SHOULD be at most one handler for any given Property and newly added handlers replace the old handlers. If no handler is initialized for any given Property, implementations SHOULD implement a default property read handler.

    The setPropertyWriteHandler() method

    Takes name as string argument and writeHandler as argument of type PropertyWriteHandler. Sets the handler function for writing the specified Property matched by name. Throws on error. Returns a reference to the same object for supporting chaining.

    There SHOULD be at most one write handler for any given Property and newly added handlers replace the old handlers. If no write handler is initialized for any given Property, implementations SHOULD implement default property update and notifying observers on change.

    The setActionHandler() method

    Takes name as string argument and action as argument of type ActionHandler. Sets the handler function for the specified Action matched by name. Throws on error. Returns a reference to the same object for supporting chaining.

    If provided, this callback function will implement invoking an Action and SHOULD be called by implementations when a request for invoking a Action is received from the underlying platform. The callback will receive a parameters dictionary argument.

    There SHOULD be exactly one handler for any given Action. If no handler is initialized for any given Action, implementations SHOULD return error if the action is invoked by any client.

    Examples

    Below some ExposedThing interface examples are given.

            try {
              var temperatureValueDefinition = {
                type: "number",
                value: 0.0,
                minimum: -50,
                maximum: 10000
              };
              var temperaturePropertyDefinition = temperatureValueDefinition;
              // add the 'forms' property
              temperaturePropertyDefinition.forms = [ ... ];
              var thing = WoT.produce({
                name: "tempSensor",
                properties: {
                  temperature: temperaturePropertyDefinition
                },
                actions: {
                  reset: {
                    description: "Reset the temperature sensor",
                    input: {
                      temperature: temperatureValueDefinition
                    },
                    output: null,
                    forms: []
                  },
                },
                events: {
                  onchange: temperatureValueDefinition
                },
                links: []
              });
              thing.expose().then(() => {
                  thing.register();
              });
              // define Thing business logic
              setInterval( async () => {
                let mock = Math.random()*100;
                thing.writeProperty("temperature", mock);
                let old = await thing.readProperty("temperature");
                if (old < mock) {
                  thing.writeProperty("temperature", mock);
                  thing.emitEvent("onchange", mock);
                }
              }, 1000);
            } catch (err) {
               console.log("Error creating ExposedThing: " + err);
            }
          
            try {
              var statusValueDefinition = {
                type: "object",
                properties: {
                  brightness: {
                    type: "number",
                    minimum: 0.0,
                    maximum: 100.0,
                    required: true
                  },
                  rgb: {
                    type: "array",
                    "minItems": 3,
                    "maxItems": 3,
                    items : {
                        "type" : "number",
                        "minimum": 0,
                        "maximum": 255
                    }
                  }
              };
              var statusPropertyDefinition = statusValueDefinition;
              // add the 'forms' property
              statusPropertyDefinition["forms"] = [];
              var thing = WoT.produce({
                name: "mySensor",
                properties: {
                  brightness: {
                    type: "number",
                    value: 0.0,
                    minimum: 0.0,
                    maximum: 100.0,
                    required: true,
                  },
                  status: statusPropertyDefinition
                },
                actions: {
                  status: {
                    description: "Get status object",
                    input: null,
                    output: {
                      status : statusValueDefinition;
                    },
                    forms: []
                  },
                },
                events: {
                  onstatuschange: statusValueDefinition;
                },
                links: []
              });
              thing.expose().then(() => {
                  thing.register();
              });
            } catch (err) {
               console.log("Error creating ExposedThing: " + err);
            }
          
            let thingDescription = '{ \
              "name": "mySensor", \
              "@context": [ "https://w3c.github.io/wot/w3c-wot-td-context.jsonld",\
                 "https://w3c.github.io/wot/w3c-wot-common-context.jsonld" ],\
              "@type": [ "Thing", "Sensor" ], \
              "geo:location": "testspace", \
              "properties": { \
                "prop1": { \
                  "type": "number",\
                  "@type": [ "Property", "Temperature" ], \
                  "saref:TemperatureUnit": "degree_Celsius" \
              } } }';
            try {
              // note that produce() fails if thingDescription contains error
              let thing = WoT.produce(thingDescription);
              // Interactions were added from TD
              // WoT adds generic handler for reading any property
              // define a specific handler for one property
              let name = "examplePropertyName";
              thing.setPropertyReadHandler(name, () => {
                console.log("Handling read request for " + name);
                return new Promise((resolve, reject) => {
                    let examplePropertyValue = 5;
                    resolve(examplePropertyValue);
                  },
                  e => {
                    console.log("Error");
                  });
              });
              thing.expose();
            } catch(err) {
               console.log("Error creating ExposedThing: " + err);
            }
          
            // fetch an external TD, e.g., to set up a proxy for that Thing
            WoT.fetch("http://myservice.org/mySensor/description").then(td => {
              // WoT.produce() ignores instance-specific metadata (security, form)
              let thing = WoT.produce(td);
              // Interactions were added from TD
              // add server functionality
              // ...
            });
          

    Data types used in a Thing

    Every Thing describes its metadata as defined in ThingTemplate, and basic interactions as defined in ConsumedThing: Properties, Actions and Events. The following data types are used for representing these interactions, as defined in [[!WOT-TD]].

    The Link dictionary

            dictionary Link {
              required USVString href;
              USVString mediaType;
              DOMString rel;
            };
          

    The href property is a hypertext reference that defines the Link.

    The mediaType property represents the IANA media type associated with the Link.

    The rel property represents a semantic label that specifies how to interact with the linked resource.

    The WebLink dictionary

            dictionary WebLink: Link {
              USVString anchor;
            };
          

    The anchor property represents a URI that overrides the default context of a Link.

    The Form dictionary

            dictionary Form: Link {
              SecurityScheme security;
            };
          

    The security property represents the security requirements for the linked resource.

    The Interaction interface

    The Interaction interface is an abstract class to represent Thing interactions: Properties, Actions and Events.

    The InteractionInit dictionary holds the common properties of PropertyInit, ActionInit and EventInit dictionaries used for initializing ThingProperty, ThingAction and ThingEvent objects in a ThingTemplate dictionary used for creating an ExposedThing object.

            interface Interaction {
              attribute DOMString label;
              readonly attribute FrozenArray<Form> forms;
            };
            Interaction implements Observable;
          

    The label property represents a text label for the interaction.

    The forms read-only property represents the protocol bindings initialization data and is initialized by the WoT Runtime.

    The InteractionInit dictionary

              dictionary InteractionInit {
                DOMString label;
              };
            

    The label property initializes the text label for the interaction.

    The ThingProperty interface

    The ThingProperty interface is used in ConsumedThing and ExposedThing objects to represent Thing Property interactions.

    The PropertyInit dictionary is used for initializing Property objects in a ThingTemplate dictionary used for creating an ExposedThing object. It MUST implement one of the DataSchema dictionaries.

            interface ThingProperty: Interaction {
              // getter for PropertyInit properties
              getter any(DOMString name);
              // get and set interface for the Property
              Promise<any> get();
              Promise set(any value);
            };
            ThingProperty implements PropertyInit;
            ThingProperty implements Observable;
          

    The ThingProperty interface contains all the properties defined on PropertyInit as read-only properties.

    The type read-only property represents the type definition for the Property. If it matches a DataType, then it MUST implement the corresponding DataSchema dictionary.

    The writable read-only property tells whether the Property value can be updated. If it is false, then the set(value) method SHOULD always reject.

    The observable read-only property tells whether the Property supports subscribing to value change notifications. If it is false, then the subscribe() method SHOULD always fail.

    The const read-only property - defined in DataSchema - tells whether the Property value is a constant. If true, the set() and subscribe() methods SHOULD always fail.

    The required read-only property - defined in DataSchema - tells whether the Property should be always present on the ExposedThing object.

    The get() method will fetch the value of the Property. Returns a Promise that resolves with the value, or rejects with an error.

    The set() method will attempt to set the value of the Propertyspecified in the value argument whose type SHOULD match the o9ne specified by the type property. Returns a Promise that resolves on success, or rejects on an error.

    The PropertyInit dictionary

    Defines the standardized part of the dictionary that initializes a ThingProperty object.
              dictionary PropertyInit: InteractionInit {
                boolean writable = false;
                boolean observable = false;
                any value;  // initialization value
              };
              PropertyInit implements DataSchema;
            

    The writable property initializes access to the Property value. The default value is false.

    The observable property initializes observability access to the Property. The default value is false.

    The value property represents the initialization value of the property. Its type should match the one defined in the type property. If not provided in the dictionary object, it SHOULD be initialized as undefined.

    The ThingAction interface

            interface ThingAction: Interaction {
              readonly attribute DataSchema? input;
              readonly attribute DataSchema? output;
              readonly attribute DOMString description;
              Promise<any> run(optional any inputValue);
            };
          

    The input read-only property represents the input of type DataSchema to the ThingAction. Multiple arguments can be provided by applications as an array or as an object. If the value is null, the action does not take any arguments and rejects if any arguments are provided. If the value is undefined, the action will ignore any arguments provided.

    The output read-only property represents the output of type DataSchema of the ThingAction. If the value is null or undefined, the action does not return any values.

    The description read-only property represents a human-readable textual description of the Action interaction.

    The run() method when invoked, starts the Action interaction with the input value provided by the inputValue argument. If inputValue is null, the action does not take any arguments and rejects if any arguments are provided. If the value is undefined, the action will ignore any arguments provided. Otherwise the type of inputValue SHOULD match the DataSchema definition in the input property. Returns a Promise that will reject with an error or will resolve with a value of type defined by the output property.

    The ActionInit dictionary

              dictionary ActionInit: InteractionInit {
                DataSchema? input;
                DataSchema? output;
                DOMString description;
              };
            

    The input property initializes the input of type DataSchema to the ThingAction. Multiple arguments can be provided by applications as an array or as an object.

    The output property initializes the output of type DataSchema of the ThingAction.

    The description read-only property initializes a human-readable textual description of the Action interaction.

    The ThingEvent interface

            interface ThingEvent {
            };
            ThingEvent implements ThingProperty;
          

    The data events are carrying is represented as a Property. ThingEvent SHOULD also implement the event mechanism of the underlying platform (such as a DOM Event or a Node.js Event).

    The EventInit dictionary

              typedef PropertyInit EventInit;
            

    The value an event is carrying is initialized as a Property value.

    Value types

    Value types are used in Property, Event and Action parameter definitions in a ThingTemplate. Basically correspond to a JSON object definition.

    The DataType enumeration type

              enum DataType { "boolean", "integer", "number", "string", "object", "array", "null" };
            

    Defines the types that values can take, i.e. "null" "boolean", "integer", "number", "string", "object" and "array".

    The Number type

              typedef (long or unrestricted double) Number;
            

    A number is either an integer or floating point number supported by the underlying platform. A number value may have associated a permited range between a minimum and maximum value.

    The DataSchema dictionary

              dictionary DataSchema {
                required DataType type;
                boolean required = "false";
                DOMString description;
                boolean const;
              };
            

    Represents the common properties of a value type definition.

    The type property represents the value type enumerated in DataType.

    The required property tells whether this value is required to be speficied.

    The description property represents a textual description of the value.

    The const property tells whether this value is constant.

    The NumberSchema dictionary

              dictionary NumberSchema: DataSchema {
                required DOMString type;
                Number minimum;
                Number maximum;
              };
            

    The type property MUST have either the value "number" (representing a floating point number) or "integer" (representing an integer) as defined by the underlying platform.

    The minimum property may be present when the value is of type "number" and if present, it defines the minimum value that can be used.

    The maximum property may be present when the value is of type "number" and if present, it defines the maximum value that can be used.

    The BooleanSchema dictionary

              dictionary BooleanSchema: DataSchema {
                const type = "boolean";
              };
            

    The type property MUST have the value "boolean".

    The StringSchema dictionary

              dictionary StringSchema: DataSchema {
                const type = "string";
                sequence<DOMString>? enum;
              };
            

    The type property MUST have the value "string".

    The enum property represents the list of allowed string values as a string array.

    The ObjectSchema dictionary

              dictionary ObjectSchema: DataSchema {
                const type = "object";
                maplike<DOMString, DataSchema>? properties;
                sequence<DOMString> required;
              };
            

    The type property MUST have the value "object".

    The properties property is a dictionary that contains the names and types of each of the object properties. If not provided in the dictionary object, it SHOULD be initialized to undefined. The value null is accepted, as well as an empty object.

    The required property is a string array that containes the names that are mandatory to be present from the object properties. If not provided, it SHOULD be initialized to undefined. An empty array is accepted.

    The ArraySchema dictionary

              dictionary ArraySchema: DataSchema {
                const type = "array";
                DataSchema? items;
                unsigned long minItems;
                unsigned long maxItems;
              };
            

    The type property MUST have the value "array".

    The items property represents the type of the elements in the array. If not provided in the dictionary object, it SHOULD be initialized to "undefined". The value null is accepted.

    The minItems property represents the minimum number of elements required to be in the array.

    The maxItems property represents the maximum number of elements that can be specified in the array.

    The value-matching algorithm

    The value-matching algorithm is applied to a value input in relation to a valueType property of type DataSchema, for instance the value and type properties of a PropertyInit object, or the inputValue parameter to the run() method of a ThingAction object in relation to the same object. It executes the following steps:

    1. If valueType.type is not defined, or does not fully match a string enumerated in DataType, return false.
    2. Otherwise, if valueType.type is "null": if value is null, return true, otherwise return false.
    3. Otherwise, if valueType.type is "boolean": if value is either true or false, then return true, otherwise return false.
    4. Otherwise, if valueType.type is "integer": if value is not an integer type defined by the underlying platform (such as long or long long), then return false, otherwise execute the following sub-steps:
      1. If valueType.minimum is defined and value is not greater or equal than that value, return false.
      2. If valueType.maximum is defined and value is not less or equal than that value, return false.
      3. Return true.
    5. Otherwise, if valueType.type is "number", if value is not an integer or floating point type defined by the underlying platform (such as long or long long or double), then return false, otherwise otherwise execute the following sub-steps:
      1. If valueType.minimum is defined and value is not greater or equal than that value, return false.
      2. If valueType.maximum is defined and value is not less or equal than that value, return false.
      3. Return true.
    6. Otherwise, if valueType.type is "string": if value is not a string type defined by the underlying platform, then return false, otherwise return true. In this case the algorithm expects a third parameter valueType.enum and runs the following sub-steps:
      • If valueType.enum is an array of strings, then if value fully matches one of the strings defined in the array, return true.
      • Otherwise, return false.
    7. Otherwise, if valueType.type is "array", execute the following sub-steps:
      1. If valueType.minItems is defined, and value is not an array that contains at least valueType.minItems elements, return false.
      2. If valueType.maxItems is defined, and value is not an array that contains at maximum valueType.maxItems elements, return false.
      3. Otherwise, if value is not an array, return false.
      4. Otherwise, if valueType.items is undefined, return false.
      5. Otherwise, if valueType.items is null, return true (i.e. any type is accepted as array element, including heterogenous arrays).
      6. Otherwise, for each element of the array value run the value-matching algorithm against the valueType.items object. If any of these runs returns false, then return false.
      7. Otherwise, return true.
    8. Otherwise, if type is "object", execute the following sub-steps:
      1. If value is not an Object or null, return false.
      2. If valueType.properties is not defined or is not null or it is not an object, return false.
      3. If valueType.properties is null, return true (i.e. accept any object value).
      4. For each string in the valueType.required array, if it does not match a property name in the value.properties object or in the value object, then return false.
      5. For each property with name propName and value propDataSchema found in valueType.properties, run the following sub-steps:
        1. If the result of applying the value-matching algorithm on the value value[propName] and propDataSchema is false, then return false.
      6. Return true.

    Observables

    Observables are proposed to be included in ECMAScript and are used for handling pushed data associated with various possible sources, for instance events, timers, streams, etc. A minimal required implementation is described here.

    This section is informal and contains rather laconic information for implementations on what to support for interoperability.

          interface Observable {
            Subscription subscribe((Observer or OnNext) next,
                                   optional OnError error,
                                   optional OnComplete complete);
          };
          interface Subscription {
            void unsubscribe();
            readonly attribute boolean closed;
          };
          interface Observer {
            void next(any value);
            void error(Error error);
            void complete();
          };
          callback OnNext = void (any value);
          callback OnError = void (Error error);
          callback OnComplete = void ();
        

    The Observer interface

    The Observer interface defines the callbacks needed to handle an Observable:

    The Subscription interface

    Contains the closed property of type boolean that tells if the subscription is closed or active.

    Also, contains the unsubscribe() method that cancels the subscription, i.e. makes a request to the underlying platform to stop receiving data from the source, and sets the closed property to false.

    The Observable interface

    The Observable interface enabled subscribing to pushed data notifications by the subscribe() method:

    Security and Privacy

    Please see the WoT Security and Privacy repository for work in progress regarding threat models, assets, risks, recommended mitigations, and best practices for security and privacy for systems using the Web of Things. Once complete, security and privacy considerations relevant to the Scripting API will be summarized in this section.

    The SecuritySchemeType enumeration type

            enum SecuritySchemeType { "basic", "digest", "bearer", "pop", "oauth2", "apikey" };
          

    Defines the supported security schemes, i.e. "basic", "digest", "bearer", "pop", "oauth2" and "apikey".

    The AuthenticationType enumeration type

            enum AuthenticationType { "header", "body", "query", "cookie" };
          

    Defines the location of the authentication information, i.e. "header", "body", "query" and "cookie".

    The SecurityScheme dictionary

    Represents the base class for security related configuration. One of the subclasses (differentiated by scheme) SHOULD be used.

            dictionary SecurityScheme {
              required SecuritySchemeType scheme;
            };
          

    The scheme property represents the identification of the security scheme to be used for the Thing.

    The BasicSecurityScheme dictionary

            dictionary BasicSecurityScheme: SecurityScheme {
              const scheme = "basic";
              DOMString in;
              DOMString pname;
            };
          

    The scheme property represents the identification of the security scheme to be used for the Thing.

    The in property of type AuthenticationType represents represents the location of the authentication information.

    The pname property represents the authentication parameter name.

    The DigestSecurityScheme dictionary

            dictionary DigestSecurityScheme: BasicSecurityScheme {
              const scheme = "digest";
              DOMString qop = "auth";
            };
          

    The scheme property represents the identification of the security scheme and MUST be "digest".

    The qop property represents the quality of protection. The default value is "auth". The other accepted value is "auth-int".

    The BearerSecurityScheme dictionary

            dictionary BearerSecurityScheme: BasicSecurityScheme {
              const scheme = "bearer";
              USVString authorizationURL;
              DOMString alg = "ES256";
              DOMString format = "jwt";
            };
          

    The scheme property represents the identification of the security scheme and MUST be "bearer".

    The authorizationURL property represents the authorization server URL.

    The alg property represents the encoding, encryption or digest algorithm. Accepted values include "MD5", "ES256", "ES512-256". The default value is "ES256".

    The format property represents the format of the authentication information. Accepted values are "jwt" (the default value), "jwe" and "jws".

    The PopSecurityScheme dictionary

    Represents the proof-of-possession token authentication security configuration.

            dictionary PopSecurityScheme: DigestSecurityScheme {
              const scheme = "pop";
            };
          

    The scheme property represents the identification of the security scheme and MUST be "pop".

    The ApikeySecurityScheme dictionary

    Represents the API key authentication security configuration, where the access token is opaque and is not using a standard token format.

            dictionary ApikeySecurityScheme: BasicSecurityScheme {
              const scheme = "apikey";
            };
          

    The scheme property represents the identification of the security scheme and MUST be "apikey".

    The OAuth2SecurityScheme dictionary

    Represents the OAuth2 authentication security configuration.

            dictionary OAuth2SecurityScheme: SecurityScheme {
              const scheme = "oauth2";
              USVString tokenURL;
              USVString authorizationURL;
              USVString refreshURL;
              sequence<DOMString> scopes;
              DOMString flow = "implicit";
            };
          

    The scheme property represents the identification of the security scheme and MUST be "oauth2".

    The tokenURL property represents the URL of the token server.

    The authorizationURL property represents the URL of the authorization server.

    The refreshURL property represents the URL of the refresh server.

    The scopes property represents the authorization scope identifiers as an array of strings.

    The flow property represents the authorization flow of type. Accepted values are: "implicit" (the default value), "password", "client", or "code".

    For the "implicit" flow the authorizationURL and scopes properties are required. For the "password" and "client" flows the tokenURL and scopes properties are required. For the "code" flow the authorizationURL, tokenURL and scopes properties are required.

    Terminology and conventions

    The generic WoT terminology is defined in [[!WOT-ARCHITECTURE]]: Thing, Thing Description (in short TD), Web of Things (in short WoT), WoT Interface, Protocol Bindings, WoT Runtime, Consuming a Thing Description, Thing Directory, WoT Interactions, Property, Action, Event etc.

    JSON-LD is defined in [[!JSON-LD]] as a JSON document that is augmented with support for Linked Data.

    The terms URL and URL path are defined in [[!URL]].

    The following terms are defined in [[!HTML5]] and are used in the context of browser implementations: browsing context, top-level browsing context, global object, incumbent settings object, Document, document base URL, Window, WindowProxy, origin, ASCII serialized origin, executing algorithms in parallel, queue a task, task source, iframe, valid MIME type.

    A browsing context refers to the environment in which Document objects are presented to the user. A given browsing context has a single WindowProxy object, but it can have many Document objects, with their associated Window objects. The script execution context associated with the browsing context identifies the entity which invokes this API, which can be a web app, a web page, or an iframe.

    The term secure context is defined in [[!WEBAPPSEC]].

    Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError , script execution context, Promise, JSON, JSON.stringify and JSON.parse are defined in [[!ECMASCRIPT]].

    DOMString, USVString, ArrayBuffer, BufferSource and any are defined in [[!WEBIDL]].

    The algorithms utf-8 encode, and utf-8 decode are defined in [[!ENCODING]].

    IANA media types (formerly known as MIME types) are defined in RFC2046.

    The terms hyperlink reference and relation type are defined in [[!HTML5]] and RFC8288.

    This document defines conformance criteria that apply to a single product: the UA (user agent) that implements the interfaces it contains.

    This specification can be used for implementing the WoT Scripting API in multiple programming languages. The interface definitions are specified in [[!WEBIDL]].

    The user agent (UA) may be implemented in the browser, or in a separate runtime environment, such as [Node.js](https://nodejs.org/en/) or small embedded runtimes.

    Implementations that use ECMAScript executed in a browser to implement the APIs defined in this document MUST implement them in a manner consistent with the ECMAScript Bindings defined in the Web IDL specification [[!WEBIDL]].

    Implementations that use TypeScript or ECMAScript in a runtime to implement the APIs defined in this document MUST implement them in a manner consistent with the TypeScript Bindings defined in the TypeScript specification [[!TYPESCRIPT]].

    This document serves a general description of the WoT Scripting API. Language and runtime specific issues are discussed in separate extensions of this document.

    Changes

    The following is a list of major changes to the document. For a complete list of changes, see the [github change log](https://github.com/w3c/wot-scripting-api/commits/master). You can also view the [recently closed bugs](https://github.com/w3c/wot-scripting-api/issues?page=1&state=closed).

    Open issues

    The following problems are being discussed and need most attention:

    Acknowledgements

    Special thanks to former editor Johannes Hund (until August 2017, when at Siemens AG) for developing this specification. Also, the editors would like to thank Dave Raggett, Matthias Kovatsch, Michael Koster and Michael McCool for their comments and guidance.