@theweave/api
v0.2.1
Published
This package contains the interfaces and contracts that a Holochain app UI needs to implement in order to run as a Tool in a Weave Frame like [Moss](theweave.social#tryit).
Downloads
194
Readme
@theweave/api
This package contains the interfaces and contracts that a Holochain app UI needs to implement in order to run as a Tool in a Weave Frame like Moss.
The differences between a Weave Tool and a normal Holochain App are:
- A Weave Tool can make use of the profiles zome provided by the Frame instead of using its own profiles module
- A Weave Tool can provide more than just the default "main" UI. It can additionally provide:
- UI elements to display single "assets"
- UI widgets/blocks of any kind
- UI elements ("main" view or "blocks") that render information across all instances of that same Tool type
- A Weave Tool can provide
AppletServices
for the Frame or other Applets to use, including:- search: Searching in the Tool that returns Holochain Resource Locators (HRLs) with context pointing to an asset
- creatables: Assets that can be created on-the-fly by a user.
- getAssetInfo(): A function that returns info for the asset associated to the WAL if it exists in the Tool and the method is implemented.
- blockTypes: Types of UI widgets/blocks that this Tool can render if requested by the Frame.
Definition: An "Asset" is anything that a) can be identified with an HRL plus arbitrary context and b) has an associated "asset-view", i.e. it can be displayed by the applet if requested.
Implementing a most basic applet UI
import { WeaveClient, isWeContext } from '@theweave/api';
if (!isWeContext) {
// do non-the Frame related rendering logic (launcher, kangaroo, electron, ...)
}
const weaveClient = await WeaveClient.connect();
if (
(weaveClient.renderInfo.type !== "applet-view")
|| (weaveClient.renderInfo.view.type !== "main")
) throw new Error("This Tool only implements the applet main view.");
const appAgentClient = weaveClient.renderInfo.appletClient;
const profilesClient = weaveClient.renderInfo.profilesClient;
// Your normal rendering logic here...
Implementing an (almost) full-fletched Weave Tool
import { WeaveClient, AppletServices, WAL, AssetInfo } from '@theweave/api';
// First define your AppletServices that the Frame can call on your applet
// to do things like search your applet or get information
// about the available block views etc.
const appletServices: Appletservices = {
// Types of attachment that this Tool offers for other Applets to attach
creatables: {
'post': {
label: 'post',
icon_src: 'data:image/png;base64,iVBORasdwsfvawe',
}
},
'comment': {
...
}
},
// Types of UI widgets/blocks that this Tool supports
blockTypes: {
'most_recent_posts': {
label: 'most_recent_posts',
icon_src: 'data:image/png;base64,KJNjknAKJkajsn',
view: "applet-view",
},
'bookmarked_posts': {
label: 'bookmarked_posts',
icon_src: 'data:image/png;base64,LKlkJElkjJnlksja',
view: "cross-applet-view",
}
},
getAssetInfo: async (
appletClient: AppClient,
roleName: RoleName,
integrityZomeName: ZomeName,
entryType: string,
wal: WAL,
): Promise<AssetInfo | undefined> => {
// your logic here...
// for example
const post = appletClient.callZome({
'get_post',
...
});
return {
title: post.title,
icon_src: 'data:image/png;base64,iVBORasdwsfvawe'
};
},
search: async (appletClient: AppClient, appletHash: AppletHash, weaveServices: WeaveServices, searchFilter: string): Promise<Array<WAL>> => {
// Your search logic here. For example
let searchResults: Array<Record> = await appletClient.callZome({
zome_name: 'search_posts',
...
});
const appInfo = await appletClient.appInfo();
const dnaHash = (appInfo.cell_info.notebooks[0] as any)[
CellType.Provisioned
].cell_id[0];
return searchResults.map((record) => {
hrl: [
dnaHash,
record.signed_action.hashed.hash
],
context: {}
}
);
},
}
// Now connect to the WeaveClient by passing your appletServices
const weaveClient = await WeaveClient.connect(appletServices);
// Then handle all the different types of views that you offer
switch (weaveClient.renderInfo.type) {
case "applet-view":
switch (weaveClient.renderInfo.view.type) {
case "main":
// here comes your rendering logic for the main view
case "block":
switch(weaveClient.renderInfo.view.block) {
case "most_recent_posts":
// your rendering logic to display this block type
case "bookmarked_posts":
// Your rendering logic to display this block type
default:
throw new Error("Unknown applet-view block type");
}
case "asset":
switch (weaveClient.renderInfo.view.roleName) {
case "forum":
switch (weaveClient.renderInfo.view.integrityZomeName) {
case "posts_integrity":
switch (weaveClient.renderInfo.view.entryType) {
case "post":
// here comes your rendering logic for that specific entry type
default:
throw new Error("Unknown entry type");
}
default:
throw new Error("Unknown integrity zome");
}
default:
throw new Error("Unknown role name");
}
case "creatable":
switch (weaveClient.renderInfo.view.creatableName) {
case "post":
// here comes your rendering logic to create this creatable type.
// Once created, you need to call
// weaveClient.renderInfo.view.resolve(${WAL of your created creatable here});
// or if there's an error:
// weaveClient.renderInfo.view.reject("Failed to create asset.");
// or if the user cancelled the creation:
// weaveClient.renderInfo.view.cancel();
}
default:
throw new Error("Unknown applet-view type");
}
case "cross-applet-view":
switch (this.weaveClient.renderInfo.view.type) {
case "main":
// here comes your rendering logic for the cross-applet main view
case "block":
//
default:
throw new Error("Unknown cross-applet-view render type.")
`;
}
default:
throw new Error("Unknown render view type");
}