SDK Interface & App flow

Most important functions live on the root.
Low-level functions are available through “sub modules”.

// Important
sdk.initialise()
sdk.redirectToLobby()

// Low Level
sdk.did.local()
sdk.ucan.build()
sdk.fs                /* FileSystem class */
sdk.lobby             /* Lobby functions such as `createAccount` */

I included an overview of all the functions and modules at the end.

Auth

There’s 3 basic scenarios regarding auth:

  1. Not authenticated, at some time we redirect to the auth lobby using sdk.redirectToLobby()
  2. We got redirected back from the lobby, we have some url params:
    a. User authorised the app
    b. User did not authorise the app (cancelled)
  3. User authenticated before (auth ucan was stored in cache, which we’ll use now)
// We'll cover the `initialise` arguments later
sdk.initialise( ... ).then((scenario, state) => {
  if (scenario.notAuthenticated) {
    // state.authenticated = false

  } else if (scenario.authSucceeded) {
    // state.authenticated = true
    // state.throughLobby = true
    // state.newUser = true | false
    // state.username = ...

    // state.fs : FileSystemInstance
    // state.app : ScopedFileSystemInstance

  } else if (scenario.authCancelled) {
    // state.authenticated = false
    // state.throughLobby = true
    // state.newUser = true | false
    // state.cancellationReason = "DENIED"

  } else if (scenario.continuum) {
    // state.authenticated = true
    // state.throughLobby = false
    // state.username = ...

    // state.fs : FileSystemInstance
    // state.app : ScopedFileSystemInstance

  }
})

Additional notes:

  • We store the UCAN from the authorisation in indexed-db, along with the username. Which is how we detect the continuum scenario.
  • These stored values can be removed via sdk.deauthenticate()
  • Username can be requested separately via sdk.authenticatedUsername()

Interacting with the file system

Two basic scenarios:

  1. Use the app scoped file system.
    Requires app uuid.
  2. Use the unscoped, default, file system instance.
    Requires access to specific paths.
    (do we create a scoped file-system instance for each granted path? :thinking:)
// Scenario (1)
const { app } = await sdk.initialise({ app: "my-app-uuid" })
app.private.write("config.json", "{}")
app.private.read("config.json")
app.private.rm()

// Scenario (2)
const { fs } = await sdk.initialise({ paths: [ "private/Music" ] })
const musicList = await fs.ls()

// Failure scenario (invalid combination of arguments)
sdk.initialise().catch( ... )

Important note:
When redirecting to the auth lobby, the sdk will tell the auth lobby to ask for permission to the application-data directories and/or the given paths.

Additional notes:

  • There is private and public application data (hence app.private and app.public)
  • initialise can fail if not given the proper arguments (or combination of arguments), then you’ll need .catch or try {} catch ()
  • The user’s data root is updated automatically when a file system change occurs. Don’t know yet how that’s exactly going to work with scoped file system instances, but I don’t imagine that being too difficult.

The file system interaction could most likely be done better, since I don’t know what the hard/soft links interface is going to look like, and how we’re dealing exactly with shared data, etc.

Future

Things to consider in the future:

  • Multiple apps

Overview & Types

Functions & Modules

sdk.initialise()

sdk.authenticatedUsername()
sdk.deauthenticate()
sdk.redirectToLobby()

sdk.loadFileSystem() /* Web worker users */

// Config
//   • Host your own Fission API and auth lobby
//   • Custom IPFS settings
sdk.config.endpoints({ api, lobby, user })
sdk.config.ipfs(jsIpfsSettings)

// Low Level Modules
sdk.did
sdk.fs
sdk.lobby
sdk.ucan

Scenarios

Result from sdk.initialise()

type Scenario = {
  notAuthenticated?: true,
  authSucceeded?: true,
  authCancelled?: true,
  continuum?: true,
}

type InitialisationState = NotAuthenticated | AuthSucceeded | AuthCancelled | Continuum

Where Continuum the interface has the type (AuthSucceeded is very similar):

type Continuum = {
  authenticated: true
  throughLobby: false
  username: string

  fs: FileSystem
  app: ScopedAppFileSystem
}

And lastly ScopedAppFileSystem.

type ScopedAppFileSystem = {
  private: ScopedFileSystem,
  public: ScopedFileSystem
}

Besides that, ScopedFileSystem is pretty much the same as a normal file system. Except that for certain methods you can omit the param to target the scope itself. For example, if the scope is private/Apps/Example, you could do scopedFs.ls() to list everything in that Example path.

not 100% related, but close enough and want to capture here