npm package: @keeex/stories-sdk
Description: SDK for Stories' customer API Chains-X
Author: KeeeX SAS
Latest version: 1.0.3

`@keeex/stories-sdk`
====================

SDK to provide access to the KeeeX Stories customer API "Chains-X".

This SDK provides some level of abstraction over the base API; when applicable these difference are
noted below.
The actual "Chains-X" API is documented here: [Chains-X](https://stories.keeex.me/documentations/v1/#/Chains-X).

Short description of Stories
----------------------------
KeeeX Stories is a data registry that is used to record series of chronological events collected in
"stories".
A story is identified by three things:

- a community: communities are large repositories of data attached to a customer or shared for s
               specific purpose. A single API key allow access to one community.
- a scope: scopes are categories stored under a community. While there is no restrictions on scopes,
           they are usually limited to identifying different kinds of stories.
- identifiers: each story have at least one identifier, which is a string unique to this community
               and scope pairing. It is possible to append multiple identifiers to the same story,
               keeping in mind the uniqueness restriction.

Each chronological event in a story can be attached to a keeexed file (stored externally) and have
it's own set of metadata, publicly visible to everyone with a valid access to the KeeeX Stories
service.

Some example of community/scope/identifiers:

- community would be a customer name for a private usage, or something like "ship_logistics_project"
  for a project involving multiple actors creating a shared logistic service.
- scopes could be things like "product", "box", "factory" to track physical things, or "shipment",
  "report", "pictures" to track a sequence of event or items relative to other stories.
- identifier needs to be unique per scope and community. This usually lead to using unique,
  long-lived identifiers when interfacing with existing systems, serial numbers, etc.

Each link in a story can have metadata attached to it.
These data can be retrieved by anyone with access to the service.
They are usually used either for public data, or to indicate the nature of the content referenced by
the link.

Using this SDK, the metadata have an additional layer of formatting; the raw metadata written on the
KeeeX Stories service is comprised of an object with two properties: `public` containing the actual
public metadata provided, and `links` as described in the paragraph below.
This extra layer is handled automatically through the SDK but is important to know if you perform
direct calls to the service's API.

Finally, a provision to create links between stories have been normalised to help take advantages of
such references.
This SDK accept both references and IDX as references, but ultimately the stored format only keeps
references through scope names and link's IDX.

Data authenticity
-----------------
The "Chains-X" API provides two ways to authenticate data.
The first option is to leave the server to create authentication data.
This mean that data will be signed by the server, and provides limited authenticity against third
parties.

The second option is to provide user-side digital signatures, meaning that each link created in
Stories will be authenticated by a digital identity under the sole control of the caller and not the
KeeeX Stories service's operator.

This SDK abstract the required calls to provide digitally signed entries in single-call methods that
takes as their parameters either nothing (to perform server-side signature), a key in the format of
KeeeX's key library, or a basic callback to perform digital signature in a compatible way through
other means.

Data verification
-----------------
Each link in KeeeX Stories lead to the creation of metadata files that are keeexed, timestamped and
digitally signed (see above).
These files includes cross-references between them making it very difficult to tamper without traces
once created.
There is a fetch feature that allows retrieving these files to keep as verifiable proof.
You can pass the `fullData` parameter to `fetch()` and `latest()`.

SDK features
------------
The SDK is fully documented using TypeScript and JSDoc-compatible comments.
Any recent IDE should pick details for each methods; the documentation here simply underlines the
name of the methods and their expected flow.

### Initialize the SDK
To use the SDK, it must be first initialized with an API key provided by KeeeX.
This API key provides full access to a single community.

```TypeScript
import Sdk from "@keeex/stories-sdk/lib/index.js";

const sdk = new Sdk({apiKey: "api key"});
```

### Create a story
To create a new story the `create()` method is used.
The first parameter are the details of the new story.
An optional second parameter can be used for client-side authentication by providing a key.

```TypeScript
const res = await sdk.create({scope: "ship", identifier: "ref1"}, someKey);
```

### Adding a node to a story
To append a new entry to a story you should use the `insert()` method.
Similar to `create()` it takes two parameters, the second being an optional key.

```TypeScript
const res = await sdk.insert({
  story: {scope: "ship", reference: "ref1"},
  idx: "xuseg-nerim-vizit-tesas-gifih-ciruc-figig-bacan-lulol-bizyd-zagif-macem-kumuc-navyt-mosev-polof-zyxix",
  publicMetadata: {
    filetype: "picture",
    content: "container damages",
    geolocation: "-21.120807,79.974954",
    url: "https://some.service.invalid/getFileByIDX",
  }
});
```

The above exemple uses a mock-up of something that could be used to provide some details about a
file while keeping the actual data behind a private portal.

To add cross-references between stories, it is possible to use the `links` metadata, although usage
and meaning is application dependant:

```TypeScript
const res = await sdk.insert({
  story: {scope: "pictures", reference: "someRef"},
  idx: "xedir-tisih-subul-ficas-nypel-gisif-picol-sotaf-lygyb-gukad-mekuc-henuc-sevom-sizeb-sovut-mygac-soxex",
  publicMetadata: {
    filetype: "picture",
    content: "production site",
    geolocation: "-80.912656,111.632091",
    url: "https://some.service.invalid/getFileByIDX",
  },
  references: {
    "ship": "ref1",
  },
});
```

A link created/inserted with the `references` property set will indicate upon reading a reference to
the stories with the given scope (key) and identifier (string or array of strings).
The identifiers can be link's IDX, data IDX or existing text identifiers.

### Retrieving data from a story
Using the `fetch()` and `list()` methods it is possible to retrieve data from a story.
Both methods takes the same input parameters but the `list()` method only enumerate each link's IDX
while the `fetch()` method returns the metadata and other details.

These methods have pagination, and the return value includes a `next` property that can be used to
fetch the remaining data.

```TypeScript
// Fetch from the start
const res1 = await sdk.fetch({type: "story", scope: "ship", reference: "ref1", limit: 10});
// Fetch backward from the end
const res2 = await sdk.fetch({type: "storyEnd", scope: "ship", reference: "ref1", limit: 10});
// Fetch forward from a specific link
const res3 = await sdk.fetch({type: "idx", scope: "ship", idx: "xevol-gilic-vybyd-resez-lopyb-fyzyk-domod-gylur-cymyf-tuvek-zehut-nucog-nimug-nigon-pidig-paruv-zoxux", limit: 10, reverse: false});
```

### Marking a link as deleted
Links can be marked as deleted.
They are not actually deleted from the service, but the date, reason, and author of the deletion (if
applicable) are stored and cross-referenced.

```TypeScript
const res = await sdk.delete({idxOrReference: {scope: "ship1", reference: "ref1"}}, someKey);
```

### Sequential access
The KeeeX Stories service provides some basic enumeration capabilities, allowing listing of known
stories for a scope and accessing a link through its index in its story.
These capabilities are limited and relatively expensive as they require reading a whole story up to
the requested point.
The SDK provides some level of caching over these features, but initial access still incurs a lot
of read operations.

Here's an example of using these features through the SDK:

```TypeScript
const storyCount = await sdk.getScopeStoryCount("scope2");

// Return the identifier of the fourth created story in the scope "scope2"
const someStoryIdentifier = await sdk.getScopeStory("scope2", 3);

const storyLength = await sdk.getStoryLength({scope: "scope2", reference: "test1"})

// Return the content of the third link (starts at 0)
const elem = await sdk.getStoryEntry({scope: "scope2", reference: "test1"}, 2);
```