Qworum for web pages (unreleased experimental version)
A JavaScript library through which websites can access the Qworum features of web browsers.
Note that the persona is an experimental feature, and so are related entities such as users, groups and roles. The latest official version is 1.7.0.
🏷 𝗘𝘅𝗮𝗺𝗽𝗹𝗲 How to run Qworum scripts. Here a website that is part of Qworum's Service Web is calling a remote Qworum service in a Qworum session.
// JavaScript code for web frontends.
import {
QworumScript as qs, Qworum
} from 'https://esm.sh/gh/doga/qworum-for-web-pages@1.8.2/mod.mjs';
const
// Shortcuts for building Qworum scripts.
Json = qs.Json.build,
SemanticData = qs.SemanticData.build,
Return = qs.Return.build,
Sequence = qs.Sequence.build,
Data = qs.Data.build,
Try = qs.Try.build,
Goto = qs.Goto.build,
Call = qs.Call.build,
Fault = qs.Fault.build,
Script = qs.Script.build,
// The Qworum script to be executed.
pathOfQworumObject = ['@', 'a qworum object'],
script = Script(
Try(
Sequence(
// Initialise the Qworum object ? (May be required for Qworum classes that have instance properties)
Try(
// If the state of the Qworum object is readable, then the object exists.
Data([...pathOfQworumObject, 'version']),
{
catch: '* reference',
do: // the Qworum object does not exist; initialise it
Call(
pathOfQworumObject, 'https://a-qworum-service.example/a-qworum-class/new/',
{ name: 'initial state', value: Json({state: {xyz: '…'}}) }
)
}
),
// Call the `edit` method of the Qworum object.
Call(pathOfQworumObject, 'https://a-qworum-service.example/a-qworum-class/edit/'),
// If the call to `edit` hasn't raised a fault, then the caller resumes its execution here.
Goto('group-updated.html')
),
{ do:
// If the call to `edit` has raised a fault, then go back to the current web page.
Goto()
}
)
);
// Run the Qworum script in the web page. The end-user will experience this as a redirection.
await Qworum.eval(script);
🏷 𝗘𝘅𝗮𝗺𝗽𝗹𝗲 How to read and write session state outside of Qworum scripts.
import {
QworumScript as qs, Qworum,
} from 'https://esm.sh/gh/doga/qworum-for-web-pages@1.8.2/mod.mjs';
const
Json = qs.Json.build,
data = await Qworum.getData(['path', 'to', 'data']);
if(!data) await Qworum.setData(['path', 'to', 'data'], Json('some data'));
🏷 𝗘𝘅𝗮𝗺𝗽𝗹𝗲 How to read the persona for the current Qworum session.
import {
Persona, GroupId, UserId, GroupIdSet, Qworum,
Vcard, IndividualVcard, GroupVcard, OrgVcard, Name, Email, Phone, Photo, Address, Types
} from 'https://esm.sh/gh/doga/qworum-for-web-pages@1.8.2/mod.mjs';
// Read the persona.
const persona = await Qworum.getPersona(); // Qworum will launch a user dialog if required.
if(persona){
console.debug(`User: ${persona.userId}`);
console.debug(`User's Vcard: formattedName="${persona.userVcard.formattedName}"`);
console.debug(`User roles: ${persona.userRoleIds.map(id => `${id}`).join(' ')}`);
console.debug(`Group: ${persona.groupId}`);
console.debug(`Group's Vcard: formattedName="${persona.groupVcard.formattedName}"`);
console.debug(`Group roles: ${persona.groupRoleIds.map(id => `${id}`).join(' ')}`);
// Is the group in a partnership with other groups?
if(persona.partnerGroupIds){
console.debug(`Partner groups: ${persona.partnerGroupIds.members.map(id => `${id}`).join(' ')}`);
}
} else {
// The persona has still not been set by the end-user. 2 options at this point:
// 1. Allow the end-user to remain anonymous.
// 2. Call `Qworum.getPersona()` once again.
}
🏷 𝗘𝘅𝗮𝗺𝗽𝗹𝗲 How to create a roleset for an application or an application category. A roleset is simply a set of URLs and/or IRLs (a Qworum-specific Unicode-aware variant of URLs) that have the same web origin, but the Roleset utility class presented here only allows IRLs.
import {
Role, Roleset, Language, I18nText, IRL, irl
} from 'https://esm.sh/gh/doga/qworum-for-web-pages@1.8.2/mod.mjs';
const
en = Language.fromCode('en'),
rolesetId = irl`https://site.example/id/roleset/`,
description = new I18nText().setText('A capability-based roleset for Qworum services. This roleset is agnostic in terms of application category. Alternatively, applications have the option of using another roleset that is specific to their software categories. To this end, applications can define their own rolesets, or use third-party rolesets that are targeting their software vertical.', en),
downloader = new Role({
roleId : irl`${rolesetId}downloader`,
description : new I18nText().setText('The user can download from the Qworum service any data that belongs to the group.', en)
}),
uploader = new Role({
roleId : irl`${rolesetId}uploader`,
parentRoleId: downloader.roleId,
description : new I18nText().setText('The user can upload data that belongs to the group or the persona.', en)
}),
transferrer = new Role({
roleId : irl`${rolesetId}transferrer`,
description : new I18nText().setText('The user can transfer to another group the ownership of any data that belongs to the group.', en)
}),
reader = new Role({
roleId : irl`${rolesetId}reader`,
description : new I18nText().setText('The user can read group-owned data.', en)
}),
upserter = new Role({
roleId : irl`${rolesetId}upserter`,
parentRoleId: reader.roleId,
description : new I18nText().setText('The user can create and update and read group-owned data, but not delete the data.', en)
}),
writer = new Role({
roleId : irl`${rolesetId}writer`,
parentRoleId: upserter.roleId,
description : new I18nText().setText('The user can create, read, update and delete group-owned data.', en)
}),
roleset = new Roleset({
rolesetId, description,
roles: [downloader, uploader, transferrer, reader, upserter, writer]
});
🏷 𝗘𝘅𝗮𝗺𝗽𝗹𝗲 How to verify that a persona has a certain role. Role IDs can be either URLs or IRLs.
import {
Persona, irl, Qworum
} from 'https://esm.sh/gh/doga/qworum-for-web-pages@1.8.2/mod.mjs';
const persona = await Qworum.getPersona();
if(persona){
const
readerRoleId = new URL('https://site.example/id/roleset/reader'),
writerRoleId = irl`https://site.example/id/roleset/writer`, // implies read permissions
canRead = persona.hasRole(readerRoleId, [writerRoleId]),
canWrite = persona.hasRole(writerRoleId);
}
🏷 𝗦𝗲𝗲
class Qworum
Web pages can use the Qworum capabilities of web browsers through this JavaScript class.
These are the main methods that web pages use:
- 𝚎𝚟𝚊𝚕() evaluates a Qworum script.
- 𝚜𝚎𝚝𝙳𝚊𝚝𝚊() sets the value of a data container.
- 𝚐𝚎𝚝𝙳𝚊𝚝𝚊() reads the value of a data container.
Other methods:
- 𝚌𝚑𝚎𝚌𝚔𝙰𝚟𝚊𝚒𝚕𝚊𝚋𝚒𝚕𝚒𝚝𝚢() verifies that Qworum is available on the user's web browser.
All these methods are static and asynchronous.
🏷 𝗘𝘅𝗮𝗺𝗽𝗹𝗲 Check the browser's Qworum availability status.
try{
await Qworum.checkAvailability();
}catch(error){
console.error('Qworum browser extension not installed or not enabled.');
}
🏷 𝗘𝘅𝗮𝗺𝗽𝗹𝗲 Raise a Fault
await Qworum.eval(
Script.build(Fault.build('payment cancelled'))
);
🏷 𝗘𝘅𝗮𝗺𝗽𝗹𝗲 Store data in the current Qworum method call.
await Qworum.setData('year', Qworum.Json(2024));
🏷 𝗘𝘅𝗮𝗺𝗽𝗹𝗲 Read data stored in the current Qworum method call.
const result = await Qworum.getData(['year']); console.info(JSON.stringify(result.value));
static async checkAvailability()
Checks that:
- the Qworum browser extension is installed and running, and
- the website's DNS domain is part of Qworum's Service Web.
🏷 𝗥𝗲𝘁𝘂𝗿𝗻𝘀 Promise<null>
🏷 𝗘𝘅𝗮𝗺𝗽𝗹𝗲 Check Qworum availability in browser
try{
await Qworum.checkAvailability();
}catch(error){
console.error('Qworum browser extension not installed or not enabled.');
}
static async eval(script)
Evaluates a Qworum script.
The outcome is one of:
- Redirection to a new URL (the current Qworum session continues).
- Closing of the browser tab after displaying an alert window (the current Qworum session has terminated).
🏷 𝗣𝗮𝗿𝗮𝗺𝗲𝘁𝗲𝗿 script: Script
🏷 𝗥𝗲𝘁𝘂𝗿𝗻𝘀 Promise<void>
🏷 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
const
Script = Qworum.Script,
Goto = Qworum.Goto;
await Qworum.eval(
Script(
Goto('next-phase/')
)
);
🏷 𝗦𝗲𝗲
static async getData(path)
Reads a value contained in a data container.
🏷 𝗣𝗮𝗿𝗮𝗺𝗲𝘁𝗲𝗿 path: (string[] | string)
The path of the data container.
🏷 𝗥𝗲𝘁𝘂𝗿𝗻𝘀 Promise<(Json | SemanticData | null)>
🏷 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
try{
const result = await Qworum.getData(['a data']);
if (result instanceof Json){
console.info(`The read operation was successful, the result is: ${JSON.stringify(result.value)}`);
} else {
console.info(`The data has not been set yet. Did you call Qworum.getData(['a data']) beforehand ?`);
}
}catch(error){
console.error('An unexpected error has occurred during the read.');
}
🏷 𝗦𝗲𝗲
static async getPersona()
Returns the 𝐏𝐞𝐫𝐬𝐨𝐧𝐚 that is tied to the current Qworum session. If a persona isn't set yet for the session, then the web browser launches a user dialog for helping the end-user choose one.
🏷 𝗥𝗲𝘁𝘂𝗿𝗻𝘀 Promise<(Persona|null)>
🏷 𝗧𝗵𝗿𝗼𝘄𝘀 Error
static async setData(path, value)
Sets the value contained in a data container.
🏷 𝗣𝗮𝗿𝗮𝗺𝗲𝘁𝗲𝗿 path: (string[] | string)
The path of the data container.
🏷 𝗣𝗮𝗿𝗮𝗺𝗲𝘁𝗲𝗿 value: (Json | SemanticData)
🏷 𝗥𝗲𝘁𝘂𝗿𝗻𝘀 Promise<null>
🏷 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
try{
await Qworum.setData('year', Qworum.Json(2022));
console.info('The write operation was successful.');
}catch(error){
console.error('The write operation was not successful.');
}
🏷 𝗦𝗲𝗲
const Address
const Email
const GroupId
const GroupIdSet
const GroupVcard
const IndividualVcard
const Name
const OrgVcard
const Persona
const Phone
const Photo
const Role
const Roleset
const Types
const UserId
const Vcard
const defaultRoleset: qe
📅 𝑪𝒂𝒄𝒉𝒆𝒅 𝒐𝒏 𝑴𝒐𝒏 𝑫𝒆𝒄 𝟢𝟣 𝟤𝟢𝟤𝟧 𝟢𝟦:𝟦𝟩:𝟦𝟥 𝑮𝑴𝑻+𝟢𝟣𝟢𝟢 (𝑪𝒆𝒏𝒕𝒓𝒂𝒍 𝑬𝒖𝒓𝒐𝒑𝒆𝒂𝒏 𝑺𝒕𝒂𝒏𝒅𝒂𝒓𝒅 𝑻𝒊𝒎𝒆)