SAFE Services NPM Module (DRAFT)

SAFE Services NPM Module

Created Tuesday 09 January 2018

This is a draft specification for a services nodejs module, posted here for feedback. It may well not make sense, so all levels of question are welcome and I’m happy to go back to the drawing board if this is not a good approach. I’m writing it up now in case it is a good approach!


The idea for this springs from my attempt to show how Solid Apps can use SAFE Network as a drop in replacement for SOLID servers (work in progress). In a nutshell, I’ve managed to minimise the changes needed in Solid apps by intercepting the standard browser fetch() and handling any safe: URIs. I plan to implement this as if it were a standard web service, the Linked Data Platform (LDP) so that apps using this service will need very few changes to swap Solid storage for SAFE storage.

I have yet to implement the LDP service logic, but my work on RemoteStorage suggests that this is feasible and shouldn’t take long now I have a framework in place (and almost saving an RDF/Turtle format blog post from solid-plume to SAFE network, alpha 2). Just a teeny bug holding that up atm. Still far from complete though! :slight_smile:

This spec is a bit scrappy, for which I apologise, being exported from my PIM app (I use Zim Wiki).

The idea

solid-safenetwork.js can be the basis of a safe-services.js NPM module

  • solid - LDP service (safe://ldp.<name> )
    * supports useful subset of LDP RESTful API
    * fakes LDP style response headers, metadata etc
    * what about permissions?

  • share / short - SAFE URL SERVICES (safe://share.<name> and safe://short.<name> )
    * SAFE NFS file sharing via URLs: safe://share.<name>/original-path (original-path is key to datamap, can be cleared & share invalidated)
    * shortened URIs as a service: safe://short.<name>/shortname (shortname is key to datamap, can be cleared & shortname invalidated)
    * Interface supports (for example example):
    * upload file and provide share URI, ability to over-ride default share name
    * choose a public or private SAFE file and create a share URI (as above). If file is private a public copy is made (with a warning).
    * I/f can be via JS and also REST like (using fetch())

  • www - WEB services (safe://[www.]<name>)
    * mimics http style GET - as Browser now
    * basic POST,PUT,DELETE etc for simple websites
    * WebDav and other standard server APIs

  • other:
    * RemoteStorage
    * Dropbox
    * etc

safe-services.js module

  • a nodejs module built for use in the browser (solid-safenetwork wip branch is the prototype, and demonstrates how it will work)
  • safe-services.js supports a set of standards based services (e.g. LDP for Solid apps, RemoteStorage etc)
  • each service is implemented in a modular fashion making it easy to add your own service or provide alternative implementations to an existing app
  • works with web apps using window.fetch(), which can be easily converted from XmlHttpRequest() in order to use this module
  • could be included in the SAFE browser DOM API, avoiding the need for apps to be modified at all


  • Dual interface:
    • ServiceInterface methods and helpers for service operations. Maybe later, until then…
    • RESTful API based on safe: URIs for easy conversion of any web application that already accesses a standard web service using RESTful fetch() operations (GET/PUT/POST/DELETE). Uses protoFetch in the same way as solid-safenetwork to minimise code changes to existing web apps.
  • Services would be checked in a similar way to the browser supporting www:
    * safe fetch() handles all safe: URIs
    * if it is www or no prefix, it can hand it over to the browser (until implemeting www services - see above)
    * if one of a standard set of service prefixes (e.g. ldp for Solid apps), it checks the service ID and if supported calls the relevant service fetch() implementation
    * if not, the library can be configured to either assume it is really www and pass to the browser, or check the actual service ID and either handle it or generate an unsupported service error. Making this optional avoids the need to do extra processing for anything but a standard service prefix.

Dream Code
module.exports = SafenetworkServices
module.exports.serviceInterface = SafenetworkServiceInterface

Allows app to initialise a service interface, access an initialised service interface, list all initialised services
Maybe query for a list of services supported by the library
// SafenetworkServices.InitialiseSevice(publicID,"LDP",permissions)
// adds an object to self for each initialised service, accessible as[serviceName] (e.g.[“LDP”])
// Returns a Promise which if successful resolves to a SafenetworkServiceInterface

// SafenetworkServiceInterface
// Common interface:
// ???>>>MEATYBITTODO<<< status, permissions, initialise a previously uninitialised publicID to support the given service (maybe put this in SafenetworkServices?), access objects to read service related information from a publicID (with handling if not yet initialised)
// Service specific interface
// - helpful to have some standards to follow (e.g. for storage services in general - could use LDP or RemoteStorage as a template)
// - this can, but need not include, a RESTful API to allow access to the service as if it was a standard HTTP API being accessed through fetch()

Application Logic

  1. User visits SAFE website/app (safe: URI) which has safe-services.js support (ie uses this nodejs module!)
  2. App checks to see if logged into SAFE Network:
    • ☐ How to check - can an app check to see what if any container rights it has without trying auth? If so, use a check for ‘Read’ on _public.
    • App updates “Log In/Out”
  • Immediately, or when needed, or lazily… app interrogates the public ID to initialise read-only safe-services. Example

    // Returns a Promise resolving an initialised SafenetworkServiceInterface object if successful

  • If user chooses Log In, App attempts to authorise with SAFE Authenticator (including request for ‘Read’ on _public)

    • This causes Authenticator to prompt user to Log in to SAFE, and optionally authenticates the app.
    • App updates Log In/Out and other UI according to auth result.

    See 3a. / 3b. below.

    • If user chooses Log Out, App frees SAFE application objects and updates Log In/Out and other UI

    See 3a. below.

    3a. If User Not Logged In to SAFE
    The UI disables ability to modify any SAFE services used by the app (e.g. to create online content, upload files, share etc.)
    Content is displayed but anything accessed through services will be read-only, until the user chooses to Log In

    3b. If User Logged In to SAFE
    Immediately, or when needed, or lazily… app interrogates the public ID to initialise any read-write services. Example:
    // Returns a Promise resolving an initialised SafenetworkServiceInterface object if successful

    The App interrogates the service (e.g. for permissions granted by the user) and updates UI to reflect ability to modify any SAFE services used by the app (e.g. to create online content, upload files, share etc.).
    Content may be accessed and displayed, and the UI allows it to be created, updated etc. according to user granted permssions.


5 posts were split to a new topic: How does SAFE Network keeps track of itself in terms of state/health

When I started reading about Solid and LDP the first thing that came up to my mind was that we could expose such a service from the browser app itself, as a RESTful interface. This brings some security concerns we need to first analyse carefully.

Just FYI, this is already possible in safe_client_libs, and we are planning to add it for next version of safe-node-app (WIP PR: and DOM API, you’ll just need to provide the auth URI and you’ll get the list of containers and permissions granted for each of them.