This document is part of Generic toolkit for server and web applications.
App templates based on HDS Model, provide frameworks to build applications for HDS.
- AppManagingAccount: App which manages Collectors. A "Collector" handles a "Request" and set of "Responses". => With access to some HDS data from other accounts.
- AppClientAccount: Handles requests from
AppManagingAccountand corresponding responses (agree, refuse, revoke).
Both templates extend Application class
An application is based on
- one
connection: an instance ofpryv.Connection - one
baseStreamId: the streamId where the application will store its own operation data (i.e. state management) - This stream should be a children of streamapplications. - one
appName
Either use:
App{ExtensionName}.newFromApiEndpoint(baseStreamId, apiEndpoint, appName)App{ExtensionName}.newFromConnection(baseStreamId, connection, appName)
It will return an instance already initialized with eventual necessary streams created.
Check the code for mode details.
Either use:
AppManagingAccount.newFromApiEndpoint(baseStreamId, apiEndpoint, appName)AppManagingAccount.newFromConnection(baseStreamId, connection, appName)
Params:
- apiEndpoint or connection must have
masterorpersonnalaccess rights.
Get current Collector instances related to this app
Get one Collectorfrom its id.
Create new Collector
A collector is holding
- A single request for accessing a set of streams
- A set of
CollectorInvitewhich are to be submitted to clients
It has 3 possible states draft=> active => deactivated
Collector instances are created and managed by AppManagingAccount.
You may use this as a reference to retrieve a specific collector from an app
One of 'draft', 'active', 'deactivated'
Payload that can be modified
After modifying collector.request you should save it.
Once the edition is done and saved, validate and publish. (Can be done just once);
List of current invites
Check if new 'accept', 'refuse', 'revoke' messages have been received.
A collector invite represents the state of a 1 - 1 relationship between a Collector => A User
It's materialized by an event in one of the streams of the Collector
collectorInvite instances are created and retrieved by Collector instances.
Returns the display name set at creation
When pending this will return an apiEndpoint and an eventId to be shared with a 3rd party app using ApplicationClient. This data will be consumed by appclient.handleIncomingRequest(apiEndpoint, eventId) to initiate the relationship.
Returns one of pending, active, error.
In case of error, (meaning, means not accessible) the call collectorInvite.errorType() will return revoked or refused.
As an invite is a 1 - 1 relationship, when active, it holds a connection to the matching account.
Returns a Dateobject.
Check if connection is valid. (only if active) If the result is "forbidden" update and set as revoked.
Returns the accessInfo on success, which can be useful to get the hds username or other infos and the account.
The counterpart of AppManagingAccount for "client" applications.
Either use:
AppClientAccount.newFromApiEndpoint(baseStreamId, apiEndpoint, appName)AppClientAccount.newFromConnection(baseStreamId, connection, appName)
To be called when the app receives a new request issued by AppManagingAccount's collectorInvite.getSharingData(). Returns a CollectorClient instance.
Get current CollectorClient instances.
Get a specific CollectorClient instance.
Identifier to retrieve a collector from appClientAccount.
One of 'Incoming', 'Active', 'Deactivated', 'Refused'
The data holding the requestFrom the invite
Accept current request
Revoke current request
Refuse current request
Apps can extend the shared HDS data-model at init time without forking data-model. Pass an HDSModelOverload to initHDSModel():
import { initHDSModel, extractOverloadAsDefinitions } from 'hds-lib';
const overload = {
// Add brand new items
items: {
'mood-happy': {
version: 'v1',
label: { en: 'Happy', fr: 'Heureux' },
description: { en: 'Feeling happy' },
streamId: 'mood-happy',
eventType: 'activity/plain',
type: 'checkbox',
repeatable: 'unlimited'
},
// Refine an existing item: add a translation, override repeatable
'body-weight': {
label: { fr: 'Poids' },
repeatable: 'P1D'
}
},
// Add new streams (must hang under an existing parent — or be a new root)
streams: [
{ id: 'mood', name: 'Mood', parentId: null, children: [
{ id: 'mood-happy', name: 'Happy' }
]}
],
// App-specific settings, eventTypes, datasources, appStreams also supported
settings: {
fontSize: { eventType: 'settings/font-size', type: 'number', default: 14 }
}
};
await initHDSModel({ overload });The overload is validated before merging — attempting to change the parentId of an existing stream, the type/schema of an existing eventType, or the type/streamId/eventType of an existing item throws HDSLibError listing every violation.
To later contribute your overload upstream, dump it to data-model/data-model/definitions/-shaped files:
import { writeFileSync, mkdirSync } from 'node:fs';
import { dirname } from 'node:path';
const files = extractOverloadAsDefinitions(overload);
for (const [path, content] of Object.entries(files)) {
mkdirSync(dirname(`./out/${path}`), { recursive: true });
writeFileSync(`./out/${path}`, content);
}Note: runtime overload validation only enforces the policy table (no AJV schema). For full schema validation, run data-model/data-model/src/schemas/items.js AJV against your overload at build time.