Class Name | Container |
Extends | Logger |
Source | container.ts |
Examples | container.spec.ts |
TL;DR: usage examples and a data flow can be found here <./digital-twin-usage-examples>
.
The Container
is an API layer over DataContract <./data-contract>
and combines its functionalities into a more use case oriented straight forward interface.
To reduce complexity the most common usage patterns from DataContract <./data-contract>
have been set as fixed in the Container
implementation. Therefore the Container
follows these principles:
- data is always encrypted
- each entry gets an own key for encryption
- each entry get an own role for granting write permissions
- an identity always is created for the container
- adding validations adds the validation topic to the contract description to allow listing of all validations
- a property called
type
is added to theContainer
at creation type and marks its template type
new Container(options, config);
Create new Container
instance. This will not create a smart contract contract but is used to load existing containers. To create a new contract, use the static create <container_create>
function.
options
-ContainerOptions
: runtime for new containercontractLoader
-ContractLoader
_:ContractLoader
_ instancecryptoProvider
-CryptoProvider
_:CryptoProvider
_ instancedataContract
-DataContract
_:DataContract
_ instancedescription
-Description
_:Description
_ instanceexecutor
-Executor
_:Executor
_ instancenameResolver
-NameResolver
_:NameResolver
_ instancerightsAndRoles
-RightsAndRoles
_:RightsAndRoles
_ instancesharing
-Sharing
_:Sharing
_ instanceverifications
-Verifications
_:Verifications
_ instanceweb3
-Web3
_:Web3
_ instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
_ (optional): messages with this level will be logged withlog
logLog
-LogLogInterface
_ (optional): container for collecting log messageslogLogLevel
-LogLevel
_ (optional): messages with this level will be pushed tologLog
config
-DigitalTwinconfIg
: config for new containeraccountId
-string
: account id of user, that interacts with containeraddress
-string
: address of aDataContract
instance, can be ENS or contract address
Container
instance
const container = new Container(
runtime,
{
accountId: '0x0000000000000000000000000000000000000000',
address: 'samplecontainer.somewhere.evan',
},
);
Container.create(runtime, config);
Creates a new digital container contract on the blockchain.
Note, that this function is static. It is used on the Container
class object and returns a Container
class instance.
The options argument has the same structure as the options object that is passed to the constructor as it is used for the new Container
instance. The config
argument requires a proper value for the property description
.
options
-ContainerOptions
: runtime for new containercontractLoader
-ContractLoader
_:ContractLoader
_ instancecryptoProvider
-CryptoProvider
_:CryptoProvider
_ instancedataContract
-DataContract
_:DataContract
_ instancedescription
-Description
_:Description
_ instanceexecutor
-Executor
_:Executor
_ instancenameResolver
-NameResolver
_:NameResolver
_ instancerightsAndRoles
-RightsAndRoles
_:RightsAndRoles
_ instancesharing
-Sharing
_:Sharing
_ instanceverifications
-Verifications
_:Verifications
_ instanceweb3
-Web3
_:Web3
_ instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
_ (optional): messages with this level will be logged withlog
logLog
-LogLogInterface
_ (optional): container for collecting log messageslogLogLevel
-LogLevel
_ (optional): messages with this level will be pushed tologLog
config
-DigitalTwinconfIg
: config for new containeraccountId
-string
: account id of user, that interacts with containeraddress
-string
: ENS address used for containerdescription
-string
: description has to be passed to.create
to apply it to to contractfactoryAddress
-string
(optional): factory address can be passed to.create
for customer container factorytemplate
-string|ContainerTemplate
(optional): template to be used in.create
, can be string with name or aContainerTemplate
Promise
returns Container
: new instance bound to new DataContract
const container = await Container.create(options, config);
console.log(await container.getContractAddress());
// Output:
// 0x0000000000000000000000000000000000001234
Container.clone(options, config, source[, copyValues]);
Clone Container
instance into template and creates new Container
with it.
Cloning containers:
- is done with account from
config.accountId
, this account will be owner of the new contract - copies all fields from source container to new container (including roles, that have permissions on them)
- copies values for entry-fields (no lists) to new container, if
copyValues
is set does not copy role membership
config.accountId
is the owner of the new contract and also a member of the contract (role 0 and 1)- other roles receive permissions on fields, but do not get members added to them
does not copy sharings
- a new sharing with new keys is generated for this container
- only the owner of the container receives keys shared to it for this container
- does not copy validations
does not copy the description
config.description
is used for the cloned contract- fields are dynamically added to the description when generating the clone
options
-ContainerOptions
: runtime for new containercontractLoader
-ContractLoader
_:ContractLoader
_ instancecryptoProvider
-CryptoProvider
_:CryptoProvider
_ instancedataContract
-DataContract
_:DataContract
_ instancedescription
-Description
_:Description
_ instanceexecutor
-Executor
_:Executor
_ instancenameResolver
-NameResolver
_:NameResolver
_ instancerightsAndRoles
-RightsAndRoles
_:RightsAndRoles
_ instancesharing
-Sharing
_:Sharing
_ instanceverifications
-Verifications
_:Verifications
_ instanceweb3
-Web3
_:Web3
_ instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
_ (optional): messages with this level will be logged withlog
logLog
-LogLogInterface
_ (optional): container for collecting log messageslogLogLevel
-LogLevel
_ (optional): messages with this level will be pushed tologLog
config
-DigitalTwinconfIg
: config for new containeraccountId
-string
: account id of user, that interacts with containeraddress
-string
: ENS address used for containerdescription
-string
: description has to be passed to.create
to apply it to to contractfactoryAddress
-string
(optional): factory address can be passed to.create
for customer container factorytemplate
-string|ContainerTemplate
(optional): template to be used in.create
, can be string with name or aContainerTemplate
source
-Container
: container to clonecopyValues
-boolean
: copy entry values from source contract to new contract
Promise
returns Container
: new instance bound to new DataContract
and a copy of source
const container = await Container.create(options, config);
console.log(await container.getContractAddress());
// Output:
// 0x0000000000000000000000000000000000001234
const clone = await Container.clone(options, config, container);
console.log(await container.getContractAddress());
// Output:
// 0x0000000000000000000000000000000000005678
container.deleteContainerTemplate(profile);
Remove a container template from a users profile.
Profile
-Profile
_: profile instancename
-string
: template name
Promise
returns void
await Container.deleteContainerTemplate(profile, 'awesometemplate');
container.getContainerTemplate(profile, name);
Get one container template for a users profile by name.
Profile
-Profile
_: profile instancename
-string
: template name
Promise
returns ContainerTemplate
const accountId1 = '0x0000000000000000000000000000000000000001';
const template = await Container.getContainerTemplate(profile, 'awesometemplate');
// create container with accountId1
const container = await Container.create(options, {
...config,
accountId: accountId1,
description: template.description,
template: template.template,
});
container.getContainerTemplates(profile);
Get all container templates for a users profile.
Profile
-Profile
_: profile instanceloadContracts
- boolean (default = true): run loadBcContract directly for all saved entries (if false, unresolved ipld tree will be returned as value)
Promise
returns Array<ContainerTemplate>
const accountId1 = '0x0000000000000000000000000000000000000001';
const templates = await Container.getContainerTemplates(profile);
// create container with accountId1
const container = await Container.create(options, {
...config,
accountId: accountId1,
description: templates['awesometemplate'].description,
template: templates['awesometemplate'].template,
});
container.saveContainerTemplate(profile);
Persists a template including an dbcp description to the users profile.
Profile
-Profile
_: profile instancename
-string
: template namedescription
-any
: predefined template dbcp descriptiontemplate
-ContainerTemplate
: container template object
Promise
returns void
const templates = await Container.saveContainerTemplate(
profile,
'awesometemplate',
{ ... }
);
container.toTemplate([getValues]);
Export current container state as template. If getValues
is true
, exports entry values as well.
This template can be passed to create <container_create>
and used to create new containers.
getValues
-boolean
: export entry values or not (list entries are always excluded)
Promise
returns ContainerTemplate
: template build from current container
const sampleValue = 123;
await container.setEntry('numberField', sampleValue);
console.dir(await container.toTemplate(true));
container.setEntry(entryName, value);
Set a value for an entry.
entryName
-string
: name of an entry in the containervalue
-any
: value to set
Promise
returns void
: resolved when done
const sampleValue = 123;
await container.setEntry('numberField', sampleValue);
console.log(await container.getEntry('numberField'));
// Output:
// 123
container.getEntry(entryName);
Return entry from contract.
entryName
-string
: entry name
Promise
returns any
: entry value
Entries can be retrieved with:
const sampleValue = 123;
await container.setEntry('numberField', sampleValue);
console.log(await container.getEntry('numberField'));
// Output:
// 123
container.addListEntries(listName, values);
Add list entries to a list list property.
List entries can be added in bulk, so the value argument is an array with values. This array can be arbitrarily large up to a certain degree. Values are inserted on the blockchain side and adding very large arrays this way may take more gas during the contract transaction, than may fit into a single transaction. If this is the case, values can be added in chunks (multiple transactions).
listName
-string
: name of the list in the containervalues
-any[]
: values to add
Promise
returns void
: resolved when done
const listName = 'exampleList';
console.log(await container.getListEntryCount(listName));
// Output:
// 0
const sampleValue = {
foo: 'sample',
bar: 123,
};
await container.addListEntries(listName, [sampleValue]);
console.log(await container.getListEntryCount(listName));
// Output:
// 1
console.dir(await container.getListEntries(listName));
// Output:
// [{
// foo: 'sample',
// bar: 123,
// }]
container.getListEntryCount(listName);
Return number of entries in the list. Does not try to actually fetch and decrypt values, but just returns the count.
listName
-string
: name of a list in the container
Promise
returns number
: list entry count
const listName = 'exampleList';
console.log(await container.getListEntryCount(listName));
// Output:
// 0
const sampleValue = {
foo: 'sample',
bar: 123,
};
await container.addListEntries(listName, [sampleValue]);
console.log(await container.getListEntryCount(listName));
// Output:
// 1
console.dir(await container.getListEntries(listName));
// Output:
// [{
// foo: 'sample',
// bar: 123,
// }]
container.getListEntries(contract, listName, accountId[, dfsStorage, encryptedHashes, count, offset, reverse]);
Return list entries from contract. Note, that in the current implementation, this function retrieves the entries one at a time and may take a longer time when querying large lists, so be aware of that, when you retrieve lists with many entries.
listName
-string
: name of the list in the containercount
-number
(optional): number of elements to retrieve, defaults to10
offset
-number
(optional): skip this many items when retrieving, defaults to0
reverse
-boolean
(optional): retrieve items in reverse order, defaults tofalse
Promise
returns any[]
: list entries
const listName = 'exampleList';
console.log(await container.getListEntryCount(listName));
// Output:
// 0
const sampleValue = {
foo: 'sample',
bar: 123,
};
await container.addListEntries(listName, [sampleValue]);
console.log(await container.getListEntryCount(listName));
// Output:
// 1
console.dir(await container.getListEntries(listName));
// Output:
// [{
// foo: 'sample',
// bar: 123,
// }]
container.getListEntry(listName, index);
Return a single list entry from contract.
listName
-string
: name of the list in the containerindex
-number
: list entry id to retrieve
Promise
returns any
: list entry
const listName = 'exampleList';
console.log(await container.getListEntryCount(listName));
// Output:
// 0
const sampleValue = {
foo: 'sample',
bar: 123,
};
await container.addListEntries(listName, [sampleValue]);
const count = await container.getListEntryCount(listName);
console.log(count);
// Output:
// 1
console.dir(await container.getListEntry(listName, count - 1));
// Output:
// {
// foo: 'sample',
// bar: 123,
// }
container.shareProperties(shareConfigs);
Share entry/list to another user; this handles role permissions, role memberships.
Share configurations are given per user, that receives gets data shared with. The properties have the following meaning
accountId
:- account, that gets properties shared
- this user will be invited to the contract as a consumer (role 1)
read
:- list of properties, that are shared read-only
- for each property here, a key sharing for the user will be added if not already done so
- this field will always be expanded by the field
type
, which is read only accessible for every member by default, even ifread
is omitted - if not already done so, a hash key sharing will be added for given user
readWrite
:- properties listed here will be threaded the same way as those in the field
read
- additionally the following applies:
- if not already done so, a role, that has
Set
permissions will be added for this field - given
accountId
will be added to the group responsible for this field - aforementioned roles roles start at role 64, the first 64 roles are system reserved for smart contract custom logic or in-detail role configurations
- possible roles can go up to 255, so it is possible to add up to 192 properties to a container
- if not already done so, a role, that has
- properties listed here will be threaded the same way as those in the field
shareConfigs
-ContainerShareConfig[]
: list of share configs
Promise
returns void
: resolved when done
const accountId1 = '0x0000000000000000000000000000000000000001';
const accountId2 = '0x0000000000000000000000000000000000000002';
// create container with accountId1
const container = await Container.create(options, { ...config, accountId: accountId1 });
await container.setEntry('myField', 123);
console.log(await container.getEntry('myField'));
// Output:
// 123
// share field from accountId1 to accountId2
await container.shareProperties([{
accountId: accountId2,
read: ['myField'],
}]);
// fetch value with accountId2
const accountId2Container = new Container(options, { ...config, accountId: accountId2 });
console.log(await accountId2Container.getEntry('myField'));
// Output:
// 123
container.getContainerShareConfigForAccount(accountId);
Check permissions for given account and return them as ContainerShareConfig object.
accountId
-string
: account to check permissions for
Promise
returns ContainerShareConfig
: resolved when done
const accountId1 = '0x0000000000000000000000000000000000000001';
const accountId2 = '0x0000000000000000000000000000000000000002';
// create container with accountId1
const container = await Container.create(options, { ...config, accountId: accountId1 });
await container.setEntry('myField', 123);
console.log(await container.getEntry('myField'));
// Output:
// 123
// share field from accountId1 to accountId2
await container.shareProperties([{
accountId: accountId2,
read: ['myField'],
}]);
// fetch value with accountId2
const accountId2Container = new Container(options, { ...config, accountId: accountId2 });
console.log(await accountId2Container.getEntry('myField'));
// Output:
// 123
const shareConfig = await container.getContainerShareConfigForAccount(accountId2);
console.dir(shareConfig);
// Output:
// {
// accountId: '0x0000000000000000000000000000000000000002',
// read: ['myField']
// }
container.getContainerShareConfigs();
Check permissions for given account and return them as ContainerShareConfig object.
Promise
returns ContainerShareConfig[]
: resolved when done
const accountId1 = '0x0000000000000000000000000000000000000001'; // account in runtime
const accountId2 = '0x0000000000000000000000000000000000000002'; // account to invite
const container = await Container.create(runtime, defaultConfig);
const randomString1 = Math.floor(Math.random() * 1e12).toString(36);
await container.setEntry('testField1', randomString1);
const randomString2 = Math.floor(Math.random() * 1e12).toString(36);
await container.setEntry('testField2', randomString2);
await container.shareProperties([
{ accountId: accountId2, readWrite: ['testField1'], read: ['testField2'] },
]);
console.dir(await container.getContainerShareConfigs());
// Output:
// [ { accountId: '0x0000000000000000000000000000000000000001',
// readWrite: [ 'testField1', 'testField2' ] },
// { accountId: '0x0000000000000000000000000000000000000002',
// read: [ 'testField2' ],
// readWrite: [ 'testField1' ] } ]
container.addVerifications(verifications);
Add verifications to this container; this will also add verifications to contract description.
If the calling account is the owner of the identity of the container
- the description will is automatically updated with tags for verifications
- verifications issued with this function will be accepted automatically
See interface ContainerVerificationEntry
for input data format.
verifications
-ContainerVerificationEntry[]
: list of verifications to add
Promise
returns void
: resolved when done
await container.addVerifications([{ topic: 'exampleVerification' }]);
container.getOwner();
Gets the owner account id for the container.
Promise
returns string
: owner account id
const isOwner = (await container.getOwner()) === runtime.activeAccount;
container.getVerifications();
Gets verifications from description and fetches list of verifications for each of them.
See Verifications
_ documentation for details on output data format.
Promise
returns any
: list of verification lists from Verifications
_, getVerifications
await container.addVerifications([{ topic: 'exampleVerification' }]);
const verifications = await container.getVerifications());
container.getDescription();
Get description from container contract.
Promise
returns any
: public part of the description
const description = await container.getDescription();
console.dir(description);
// Output:
// { name: 'test container',
// description: 'container from test run',
// author: 'evan GmbH',
// version: '0.1.0',
// dbcpVersion: 2,
// identity:
// '0x70c969a64e880fc904110ce9ab72ba5f95f706a252ac085ae0525bd7a284337c',
// dataSchema: { type: { type: 'string', '$id': 'type_schema' } } }
container.setDescription(description);
Write given description to containers DBCP.
description
-any
: description (public part)
Promise
returns void
: resolved when done
// get current description
const description = await container.getDescription();
console.dir(description);
// Output:
// { name: 'test container',
// description: 'container from test run',
// author: 'evan GmbH',
// version: '0.1.0',
// dbcpVersion: 2,
// identity:
// '0x70c969a64e880fc904110ce9ab72ba5f95f706a252ac085ae0525bd7a284337c',
// dataSchema: { type: { type: 'string', '$id': 'type_schema' } } }
// update description
description.version = '0.1.1';
await container.setDescription(description);
// fetch again
console.dir(await container.getDescription());
// Output:
// { name: 'test container',
// description: 'container from test run',
// author: 'evan GmbH',
// version: '0.1.1',
// dbcpVersion: 2,
// identity:
// '0x70c969a64e880fc904110ce9ab72ba5f95f706a252ac085ae0525bd7a284337c',
// dataSchema: { type: { type: 'string', '$id': 'type_schema' } } }
container.getContractAddress();
Get contract address of underlying DataContract
.
Promise
returns string
: address of the DataContract
const container = await Container.create(options, config);
console.log(await container.getContractAddress());
// Output:
// 0x0000000000000000000000000000000000001234
container.ensureProperty(propertyName, dataSchema[, propertyType]);
Ensure that container supports given property.
Promise
returns void
: resolved when done
await container.ensureProperty('testField', Container.defaultSchemas.stringEntry);
config properties, specific to Container instances
accountId
-string
: account id of user, that interacts with containeraddress
-string
(optional): address of aDataContract
instance, can be ENS or contract addressdescription
-string
(optional): description has to be passed to.create
to apply it to to contractfactoryAddress
-string
(optional): factory address can be passed to.create
for customer container factorytemplate
-string|ContainerTemplate
(optional): template to be used in.create
, can be string with name or aContainerTemplate
description and content of a single file, usually used in arrays (add/get/set operations)
name
-string
: filename, e.g.animal-animal-photography-cat-96938.jpg
fileType
-string
: mime type of the file, e.g.image/jpeg
file
-Buffer
: file data as Buffer
config for sharing multiple fields to one account (read and/or readWrite access)
accountId
-string
: account, that gets properties sharedread
-string[]
(optional): list of properties, that are shared read-onlyreadWrite
-string[]
(optional): list of properties, that are shared readable and writable
template for container instances, covers properties setup and permissions
type
-string
: type of the template (equals name of the template)properties
-{ [id: string]: ContainerTemplateProperty; }
(optional): list of properties included in this template, key is field name, value is property setup
config for sharing multiple fields to one account (read and/or readWrite access)
dataSchema
-any
: Ajv data schema for fieldpermissions
-{ [id: number]: string[] }
: permissions for this template, key is role id, value is array with 'set' and/or 'remove'type
-string
: type of property (entry/list)value
-any
(optional): value of property
data for verifications for containers
topic
-string
: validation pathdescriptionDomain
-string
(optional): domain, where the description of this validation is storeddisableSubverifications
-boolean
(optional): if set, validations created in a sub-path are invalid by default, defaults tofalse
expirationDate
-number
(optional): expiration date, validations do not expire if omitted, defaults to0
verificationValue
-string
(optional): reference to additional validation details
Default description used when no specific description is given to .create <container_create>
.
Predefined simple schemas, contains basic schemas for files, number, object, string entries and their list variants.
Default template used when no specific description is given to .create <container_create>
. Default template is metadata
.
Key that is used in user profile to store templates, default is templates.datacontainer.digitaltwin.evan
Predefined templates for containers, currently only contains the metadata
template.