UNPKG

@theweave/api

Version:

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).

190 lines (161 loc) 6.71 kB
# @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](theweave.social#tryit). 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 ```typescript= import { WeaveClient, isWeaveContext } from '@theweave/api'; if (!isWeaveContext) { // 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 ```typescript= 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"); } ```