ALERT!

*The Starlane crates and github repository are * NOT currently in a working state!

A new update is coming soon at which time the docs and tutorials will be updated.

DOCUMENTATION

GETTING STARTED

INSTALL RUST

To build Starlane you will need to have rust installed. Follow the official Rust instructions to install Rust.

NIGHTLY TOOLCHAIN

Starlane requires the nightly toolchain for compilation. To switch to the nightly toolchain:

rustup toolchain install nightly
rustup default nightly

BUILD AND INSTALL STARLANE

cargo install starlane

Congrats! You now have Starlane installed on your machine!

START A STARLANE SERVER INSTANCE

Open a terminal and run the following command to start a server instance of Starlane:

starlane 

At this point starlane should be serving a Http Server on port 8080. Open a browser and point it to http://localhost:8080/. You should see a "404" page (since there isn't a localhost space or routing bind.)

COSMIC CLI

You need to have the cosmic-cli installed in order to access your starlane instance:

cargo install cosmic-cli

TERMS

The Cosmic Initiative uses terms with an Astro Physics them in order to avoid name collision with other domains in the architecture. For example a compute Node is called a Star and a Resource is called a Particle.

UNIVERSAL TERMS

These are terms that exist in the Universal Dimension which is not concerned with security or orchestration. Applications are typically built in this dimension in order to quicken development and centralize complexity.

  • Particle - A resource (User,File,Database, Database Row, Mechtron...etc.)
  • Kind - a hierarchtical type descriptor for a particle. A kind can be composed of a nested Base, Sub & a Specific to exactly describe a particle
  • Point - an address that in most cases is the location of a Particle
  • Wave - A message that is transmitted to and from Particles
  • Mechtron - A WebAssembly component that implements the cosmic-universe & mechtron packages giving it the ability to act as a Particle (send and receive Waves)
  • Cosmos - The entirety of the "World" that these Particles live in... The Entire Enterprise.
  • Cosmic Fabric The space between Particles, the space that Waves traverse
  • Universal Dimension - A simplified view and API of the Cosmos that is not concerned with security or orchestration.

HYPERVERSAL TERMS

The Hyperversal Dimension is the infrastructure view of the Cosmos which is responsible for security & orchestration and manages these concepts on behalf of the Universal Dimension.

  • Star - A node/container for managing state and execution of Particles. The Hyperverse distributes its provisioning of Particles amongst its Stars in order to spread computation load for storage, cpu & memory.
  • Lane - Stars are connected via Lanes which serves as the transit mechanism for Waves
    • Driver - Particles are supported through Drivers. Each Particle Kind has exactly one Driver
  • Registry The Registry holds important information on where Particles live and security rules
  • Machine - Although Stars are the 'node' component for managing Particles--the stars are more of 'virtual nodes' that live inside a Machine. The Machine will connect the internal Lanes between Stars, provide a service Stars within other Machines to connect & the Machine manages clients on behalf of its stars that are required to connect to other external Stars. This architecture facilitates the rearrangement of infrastructure without the Stars needing any special knowledge of the Hyperverse cluster that it resides in. For example in the standalone configuration ALL of the Stars execute on one Machine, and in yet another configuration each Star may have it's own Machine but in both cases the Stars see the Hyperverse the same without needing any special knowledge of how the Hyperverse cluster is composed.

PARTICLES POINTERS & KINDS

PARTICLES

A Particle is a resource which can send and receive Waves (messages).

KIND

Particles differ in functionality by their Kind. For example a User Particle will accept different types of Waves than a FileSystem Particle. They do different things.

DENOTATION

Kinds are denoted in angle brackets:

<Space>

Space is a single Base Kind without any Sub Kinds.

SUBS

Kinds can be hierarchical and are notated using delimited angle brackets like so:

<Base<Sub>>

Above you can see that a Base Kind and a Sub Kind are denoted.

For example to reference a Relational database you would denote it like this:

<Database<Rel>>

And You would reference a Graph database like this:

<Database<Graph>>

The more specific the Sub Kind the more custom functionality you can access in the Particle's API.

SPECIFIC

There is one more rung in the Kind hierarchy which is a Specific.

Here is an example of a Specific:

mechtronhub.io:postgres.org:postgres:gis:12.0.0

And it would go with the rest of our Kind definition like this:

<Database<Rel<mechtronhub.io:postgres.org:postgres:gis:12.0.0>>>

A Specific identifies an EXACT implementation of a Particle.

The various parts of the specific can be broken down as follows:

provider-domain:vendor-domain:product:variant:version

Provider Domain is the provider of the one supplying the Driver for the given Kind... which may not be the same as the vendor that actually supplies the product.

POINT

Every particle has a Point which acts as an address and unique identifier. The Particles Point is used in security, searching, message routing, logging and more.

Points are hierarchical and are usually delimited by a ':'. Here is an example of a Point:

my-domain.com:users:my-user

Notice above the first Point Segment my-domain.com is a domain name and in fact the first segment MUST be a lowercase valid hostname or domain name. The first segment is also required to be a Space Kind.

Also note that only the Space segment is allowed to have dots in it, the rest of the Base segments are lowercase kebab.

POINT + KIND

Point & Kind can be put together when referencing a Particle like this:

my-domain.com:users:my-user<User>

As you can see the Particle is identified by Point and Kind by immediately appending the Kind denotation after the Point.

FILESYSTEM POINTS

When referencing the children of a FileSystem Particle the Point Rules change a little.

my-domain.com:my-files:/some-file.txt

Notice that there is now a leading slash (which identifies the root of the FileSystem). Once the point segments pass a slash the rules change so that segments are delimited by slashes, and they can have any valid file characters.

Here is Another example showing directory structure:

my-domain.com:my-files:/some-dir/My-file.txt

Again, notice that My-file.txt has a capital letter in it, not allowed in the regular Base segments, but perfectly allowed once the transition is made to FileSystem segments.

ARTIFACT BUNDLES

Artifact Bundles are zip files that can be downloaded and cached by other services. They exist in a repo and are versioned. A Bundle must live underneath an ArtifactBundleSeries which in turn must be under a Repo.

Since a Bundle is versioned its Point Segment is a version number:

my-domain:repo:my-bundle-series:1.0.0

It is required that after a version is declared remaining segments will use FileSystem style which makes sense because an Artifact Bundle is really just a zip file. In order to reference an artifact:

my-domain:repo:my-bundle-series:1.0.0:/bind/my-particle.bind

SELECTING

The following describes how to select using the Command Line Interface. Cli can also be used within Mechtrons and Controls

To start with you can select a Particle by its exact name but that isn't very useful other than to test if it exists or not:

select localhost

And you can select a list of Particles you can use a very familiar wildcard:

select my-domain.com:*

If you want to get a recursive result use **:

select my-domain.com:**

What if you want to get a recursive result but you also want to include my-domain.com ? You can use the inclusive operator:

select my-domain.com:+**

If you want to select by Kind you can do that too:

select **<User>

The above will return ALL users in the Cosmos.

You can combine Point & Kind selects:

select my-domain.com:**<User>

Also you can wildcard a Sub Kind:

select my-domain.com:**<Database<*>>

For Artifact Bundles you can use SemVer matching rules:

select my-domain.com:repo:my-app:(^3.0.0);

The above will return all Bundles with a version 3.0.0 and greater

AND you can select for a Specific Version:

select my-domain.com:**<Database<Rel<mechtronhub.io:postgres.org:postgres:*:(^9.0.0)>>>

The above will return all Postgres databases above version 9.0.0 any variant.

CREATE

You can also create Particles from the Cli. To do so you must specify a Point and a Kind:

create my-domain.com<Space>

If you are creating a Particle with a Specific you can use Selection rules so that the Hyperverse will provision the best match for your needs. For example:

create my-domain:users<UserBase<OAuth<mechtronhub.io:keycloak.com:keycloak:*:(^10.0.0)>>>;

Above we are asking to create an instance of Keycloak, any variant version 10.0.0 or above. The Hyperverse should select the highest version that it has available that matches the given criteria.

PROPERTIES

Sometimes passing configuration properties is required when creating a Particle. For example an App MUST have a config:

create my-domain.com:app<App>{ +config=my-domain.com:repo:company-app:1.0.0:/config/my-app.config };

Above the realm of properties is entered using the curly brackets and adding new property definitions by using the + operator with assigned value.

ARGS

A particular Bind/Config may also require Args to be passed to it.

IMPORTANT: Properties are part of the Kind and Args are expected by the Bind and/or the Config. Try not to get them mixed up!

Pass args by using Parenthesis:

create my-domain.com:app<App>( company-name="ACME" )

ENVS

Finally, you can set Environment variables when creating a Particle by using square brackets:

create my-domain.com:app<App>[ users=my-domain.com:users ]

Environment variables Are also part of the Bind & Config however their values cascade down to all child references meaning that a Particle at point domain.com:users:my-user would have all the environment variables that were set from domain.com & domain.com:users

ALL TOGETHER NOW

And of course you can chain them together into one monster create statement:

create my-domain.com:app<App>{ +config=my-domain.com:repo:company-app:1.0.0:/config/my-app.config }( company-name="ACME" )[ users=my-domain.com:users ]

GET, SET & DELETE

GET

To get a property value:

get my-domain.com:users:uberscott{ email }

ENV

And if you want to grab an environment variable:

get my-domain.com:app:mechtrons:my-mechtron[ app ]

ARG

And for args:

get my-domain.com:app:mechtrons:my-mechtron( company-name )

SET

To set a property value:

set my-domain.com{ +bind=my-domain.com:repo:my-site:2.7.3:bind/routes.bind }

The Same goes for environment variables:

set my-domain.com[ slogan="We can do it!" ]

REMOVE

You can remove a Property if it is allowed:

set my-domain.com{ !bind }

ARGS NOT ACCESSIBLE

Args which are used in the process of creation of a particle cannot be modified by Set

DELETE

When you grow tired of your Particle you can delete it:

delete my-domain.com:app

The above will delete recursively, but you can also delete selectively:

delete my-domain.com:app:**<Mechtron>

SECURITY

AGENT

Every Wave that is sent from one Particle to another references an Agent which is just a Point that access rules can be applied to. Usually a Particle sends itself as the Agent, but there are cases where It can use other Agents if the Hyperverse allows it.

HYPERUSER

The HyperUser is the only user that access is not checked on. It can do anything (just like the Root user in unix OS.)

GRANT PERMISSION

to grant permission on a particle to a particle:

grant perm +csd-Rwx on my-domain.com:** to my-domain.com:**<User>

Above we are granting READ access to all users under my-domain.com on every particle under my-domain.com.

Let's examine this part: +csd-Rwx The letters stand for Create, Select, Delete, Read, Write and Execute. if the letter is capitalized then the permission is flagged as on, if lowercase it is off.

Also note the leading + operator. That is saying to OR these permissions with existing permissions. You can also choose to AND the permissions via the & operator which would have looked like this:

grant perm &csd-Rwx on my-domain.com:** to my-domain.com:**<User>

NOTE: The rules of how the Ands and the Ors are combined are consistent but a bit tricky and I will expand on it in a later iteration of this document -- uberscott

CSD

First let's break down CSD:

  • CREATE - Permission to create children under the Particle
  • SELECT - Permission to select this Particle and children
  • DELETE - Permission to delete this Particle and children

RWX

Let's break down the RWX:

  • READ - Permission to read the state of the Particle (not all particles have state)
  • WRITE - Permission to write the state of the Particle (not all particles have state)
  • EXECUTE - Permission to send Waves to the Particle

PRIVILEGES

Sometimes security has to be a little more fine-grained that broad permissions. For this we have Privileges.

One built in Privilege in the system is the User email property. Even if a Particle has full CSD-RWX access to a User Particle it cannot get the value of the email property unless it has been granted privilege to do so.

To grant a privilege:

grant priv prop:email<Read> on my-domain.com:users:**<User> to my-domain.com:my-app:mechtrons:emailer

As you can see above we are giving only one mechtron in our application, the emailer mecthtron the privilege to see the email addresses, all other mechtrons are untrusted.

LISTING GRANTS

You can list the grants on a particular Pattern:

grant list on my-domain.com:my-app+:**;

And that will result in a list with a numbered id with every grant. You can then revoke the grant using the number:

grant revoke 1

OWNERSHIP & CHOWN

When a Particle creates another Particle that Particle owns it and perform any action upon it full permissions and full privileges. To change ownership:

chown localhost:users:uberscott localhost:something;

CAPTURE MAPPING

There are times when you may want to capture and reuse a segment to make more complicated permission rules

grant perm +CSR-RWX on my-domain.com:profiles:$(user) to my-domain.com:users:${user}

Above the variable user is captured in profiles and filled in the UserBase giving each user complete access to his or her own profile.

SUPER

The HyperUser has complete access to the entire Cosmos, however it is also desirable to have SuperUsers which have complete access to only a portion of the overall cosmos. To accomplish this we can grant another user SuperUser access:

grant super on my-domain.com:** to my-domain.com:users:what-a-great-guy<User>

Above you can see that what-a-great-guy has been granted superuser access to everything under the my-domain, and he will have full access to anything that matches that pattern,

The use of SuperUser can be particularly useful for Apps which may need to control every aspect of their children:

grant super on my-domain.com:app:+** to my-domain.com:app<App>

above the App can now administer itself and its children with full access.

CONFIGURATION DOCS

Starlane features a rich DSL called Arrow Notation for configuration Docs.

Docs Bind & Config have very similar content and are therefore documented together:

BIND

Bind describes a contract between the particle and the Fabric... it enumerates the required args and environment variables that must be passed or set and requires other particles it should have access to. The Route shows the legal waves that other Particles can send to it but also describes the required pipeline those waves must travel. The Bind Cannot set Arg or Env Vars or Particles. Bind also restricts the permissions of the particle... A bind is sometimes set FOR a particle not BY the particle (and in some cases the bind is locked so the particle cannot change it.). this is for security and conformity ... it is saying "you can install any particle that is satisfied by and follows the rules of this bind"

CONFIG

Config is always under the control of the Particle. It has some overlap with Bind but is usually more powerful... for instance it can set/override Env vars whereas Bind can only set default values. Config also has the *Install selector which can create other particles and/or set permission ... basically it can access the Cli. Finally, a Config for a Mechtron or App will point to the actual Wasm guest binary.

CONTEXT

Points within the Bind & Config can be contextual, meaning they can be referenced relative to the Particle Point that the Bind or Config is describing.

For example within a Bind for my-domain:app instead of referencing a child Point like this:

my-domain:app:mechtron

It can instead be referenced using the working Point:

.:mechtron

Parent points can also be referenced using ..:

..:another-app

BUILTIN VARS

There are also some builtin Variables that can be used in a Document for example bundle:

${bundle}:/bind/special.bind

Above the ${bundle} var references the Artifact bundle that the document came from, this can be useful when you want to group related documents together in a release.

DOCUMENT DECL

The first part of a Doc is that it's Kind and Version must be declared:

Bind(version=1.0.0) { }

This tells the Doc parser what is being parsed and what version it must be translated from

Arg

The Arg Scope tells the Bind & Config which Arguments are expected to be passed to the Particle at creation time:

Bind(version=1.0.0) {
  Arg {
    # ensure company-name is set and is a <Text>
    company-name<Text>;

    # if num-employees is not set then throw the error message "Please set num-employees!"
    num-employees<Int> !! "Please set num-employees!";

    # if not set default to 'LCC'
    company-type<Text> ?= "LCC";
  }
}

And an example of a Config which can actually set vars:

App(version=1.0.0) {
  Arg {
    num-employees<Int> = 100;
  }
}

Env

Like Arg we can also ensure that environment variables are set. Environment variables are inherited from the parent.

Bind(version=1.0.0) {
  Env {
    slogan<Text> !! "everyone needs a slogan!"
  }
}

Environment Particles can also be required and set if needed:

Bind(version=1.0.0) {
  Env {
    # require that App has been set by a parent
    app<App>;

    users<UserBase> !! "must have a UserBase!";
  }
}

And the config for App:

App(version=1.0.0) {
  Env {
    # here the App is setting the environment variable app to itself so that the children of the app will have a reference to it
    app<App> = .;

    # if userbase does not exist, then create it
    users<UserBase> ?= create .:users<UserBase<OAuth<mechtronhub.io:keycloak.com:keycloak:community:(^10.0.0)>>>;
  }
}

The above example is interesting because the App can be provided with a UserBase (in the case where you may want to share the UserBase with several apps) but if not present it will create its own UserBase.

INSTALL

Config has a special document scope Install which allows for custom installation scripts:

App(version=1.0.0) {

  # Let's set some Env vars first
  Env {
    # so all child mechrons can reference this App
    app<App> = .;

    # let's ensure there is a UserBase for us (create one if not)
    users<UserBase> ?= create .:users<UserBase<OAuth<mechtronhub.io:keycloak.com:keycloak:community:(^10.0.0)>>>;
  }

  Install {
    # set the bind property
    set .{ bind=${bundle}/bind/my-app.bind };

    # let's create a place to hold our Mechtrons
    create .:mechs<Base>;

    # and a place for holding user profiles
    create .:profiles<Base>;

    # Create a specific mechtron, notice we can reference
    # The bundle that THIS document came from using ${bundle} variable
    create .:mechs:my-mechtron<Mechtron>{ config=${bundle}:/config/my-mechtron.config +bind=${bundle}/my-mechtron.bind };

    # create the emailer
    create .:mechs:emailer<Mechtron>{ config=${bundle}:/config/emailer.config +bind=${bundle}/emailer.bind };

    # you can see we are now referencing env.users variable:
    grant perm +cSd-RwX on ${env.users}:**<User> to .:mechs:**;

    # the emailer needs to have Read permission on users' email addresses
    grant priv +prop:email<Read> on ${env.users}:*<User> to .:mechs:emailer;

    # users should have complete access to their profiles
    # notice we capture username from porfiles so it will match the username in user account
    grant +CSD-RWX on .:profiles:$(username) to ${env.users}:${username};
  }
}

There's a lot going on there, but you can see that some important mechtrons are being created which are part of composing this application at install time.

MECHTRONS & APPS

Mechtrons and Apps have special configurations because they reference WebAssembly binaries:

Mechtron(version=1.0.0) {

  Wasm {
    bin = ${bundle}/wasm/my-wasm.wasm;

    # a wasm MechtronGuest can contain many Kinds of mechtrons, so we need to tell it which one we are talking about
    mechtron = my-mechtron;
  }

}

BIND ROUTES & PIPELINES

One of the most important interfaces that the Bind provides are the Routes & Pipelines.

ROUTE

Routes are selectors which take a Directed Wave's Method & Path and if matched forward that Wave through the selected Pipeline.

PIPELINE

The pipeline describes the series of filters, steps and stops to process the Directed Wave.

GET EXAMPLE

Here is a simple Route & Pipeline definition in arrow notation:

Bind(version=1.0.0) {
  Route<Http<Get>>> -> my-domain:app => &;
}

Let's break this down:

THE ROUTE SELECTOR

  • Route - This tells the Bind config that we are dealing with a Route
  • Http - this selects the Kind of wave we want to intercept... in this case an Http Wave
  • Get - this is a standard Http Get Method

THE PIPELINE

If the incoming Directed Wave matches the Route Selector then it enters the pipeline:

  • -> - This is a Pipeline Step segment. It will take any Directed Wave and pass it forward
  • my-domain:app - This is a Pipeline Stop segment. The Wave will be routed to the my-domain:app Particle
  • => - This Pipeline Step filters for a Reflected Wave (denoted by => intead of -> )
  • & - The final Pipeline Stop segment indicates that the Pipeline is complete and the result should be returned

EXPANDABLE OR COLLAPSABLE

To Make things as easy to read as needed, the Route declarations can be expanded or collapsed in these varieties:

  Route<Http<Get>>> -> my-domain:app => &;

  # is the same as:

  Route {
    Http<Get> -> my-domain:app => &;
  }

  # which is also the same as:

  Route {
    Http {
      Get -> my-domain:app => &;
    }
  }

WILDCARDS

You can apply Wildcards for the Method:

Route<Http<*>> -> my-domain.com:deal-with-all-traffic => &;

AUTH FILTERS

Filters can be applied for Authorization:

Route {
  Http(auth) {
    Get -> my-domain:members-only => &;
    Post -> my-domain:members-only => &;
  }

  Http {
    Get -> my-domain:anonymous => &;
    Post -> my-domain:anonymous => &;
  }
}

PATH FILTERS

Path Filters can also be applied:

Route<Http<Get>>/some-path -> my-domain.com:app:process-some-path => &;

CORE STOP

Use the (()) operator to denote that the directed should now go into the core of the Mechtron for processing


Route {
   Http<Post> -> (()) => &;
}

CHAINING PIPELINES

You can chain your pipeline however you like to transform the incomming request or filter input:

Route<Http<Post>>/set-password -> my-domain:password-validator -> (()) => &;

Above the password validator will throw an error if it isn't valid. Also note that my-domain:password-validator returns a new Directed Wave in the body of its Reflected Wave which is grabbed when the -> Pipeline step is encoutered.

FILTERING BODY

The Body of a Directed and Reflected Wave can be filtered by Type:

Route<Http<Post>>/set-password -[ Text ]-> my-domain:password-validator -[ Text ]-> (()) =[ Json ]=> &;

If the submitter tries to send an image it will be rejected. And this bind enforces that the underlying Mechtron return Json.

VAR SUBSTITUTION

Some examples of Var substitution have already been shown, but it's good to know you can use Vars throughout the pipeline:

# redirect to app
<Http<Get>> -> ${env.app} => &;

PATH CAPTURING

And Path fragments can be captured using Regex and captured variables can be used later in the pipeline:

Route {
  Http(auth) {
     Post/users/(?P<user>.*)/profile-pic -> my-domain:app:profiles:${user} => &;
  }
}