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

183 lines 8.95 kB
import { decodeHashFromBase64, encodeHashToBase64, } from '@holochain/client'; import { postMessage } from './utils.js'; import { decode, encode } from '@msgpack/msgpack'; import { fromUint8Array, toUint8Array } from 'js-base64'; /** * The null hash is used in case a WAL is to address a DNA only, not specific * DHT content. It starts with the prefix of an EntryHash, followed by zeroes */ export const NULL_HASH = new Uint8Array([132, 33, 36, 219, 175, ...new Uint8Array(34)]); /** * * @returns bool: Returns whether this function is being called in a Weave context. */ export const isWeaveContext = () => window.location.protocol === 'applet:' || !!window.__WEAVE_API__; /** * * @param appletHash Hash of the applet to generate the link for * @param webPrefix Whether to make the link work via web browsers. Default is true. * @returns */ export const weaveUrlFromAppletHash = (appletHash, webPrefix = false) => { let url = ''; if (webPrefix) { url = 'https://theweave.social/wal?'; } url = url + `weave-${window.__WEAVE_PROTOCOL_VERSION__ || '0.12'}://applet/${encodeHashToBase64(appletHash)}`; return url; }; export function weaveUrlFromWal(wal, webPrefix = false) { let url = ''; if (webPrefix) { url = 'https://theweave.social/wal?'; } url = url + `weave-${window.__WEAVE_PROTOCOL_VERSION__ || '0.12'}://hrl/${encodeHashToBase64(wal.hrl[0])}/${encodeHashToBase64(wal.hrl[1])}${wal.context ? `?context=${encodeContext(wal.context)}` : ''}`; return url; } export function weaveUrlToLocation(url) { if (!url.startsWith(`weave-${window.__WEAVE_PROTOCOL_VERSION__ || '0.12'}://`)) { throw new Error(`Got invalid Weave url: ${url}`); } const split = url.split('://'); // ['we', 'hrl/uhC0k-GO_J2D51Ibh2jKjVJHAHPadV7gndBwrqAmDxRW3b…kzMgM3yU2RkmaCoiY8IVcUQx_TLOjJe8SxJVy7iIhoVIvlZrD'] const split2 = split[1].split('/'); // ['hrl', 'uhC0k-GO_J2D51Ibh2jKjVJHAHPadV7gndBwrqAmDxRW3buMpVRa9', 'uhCkkzMgM3yU2RkmaCoiY8IVcUQx_TLOjJe8SxJVy7iIhoVIvlZrD'] if (split2[0] === 'hrl') { const contextSplit = split2[2].split('?context='); return { type: 'asset', wal: { hrl: [decodeHashFromBase64(split2[1]), decodeHashFromBase64(contextSplit[0])], context: contextSplit[1] ? decodeContext(contextSplit[1]) : undefined, }, }; } else if (split2[0] === 'group') { throw new Error('Needs to be implemented in Moss version 0.13.x by changing group to invitation'); } else if (split2[0] === 'applet') { return { type: 'applet', appletHash: decodeHashFromBase64(split2[1]), }; } throw new Error(`Got We url of unknown format: ${url}`); } export function weaveUrlToWAL(url) { const weaveLocation = weaveUrlToLocation(url); if (weaveLocation.type !== 'asset') { throw new Error('Passed URL is not a valid asset locator.'); } return weaveLocation.wal; } export function stringifyHrl(hrl) { return `hrl://${encodeHashToBase64(hrl[0])}/${encodeHashToBase64(hrl[1])}`; } export function stringifyWal(wal) { // If the context field is missing, it will be encoded differently than if it's undefined // or null so the field needs to be explicitly added here to make sure it leads to a // consistent result in both cases wal = { hrl: wal.hrl, context: 'context' in wal ? wal.context : null, }; return fromUint8Array(encode(wal)); } export function deStringifyWal(walStringified) { return decode(toUint8Array(walStringified)); } export function encodeContext(context) { return fromUint8Array(encode(context), true); } export function decodeContext(contextStringified) { return decode(toUint8Array(contextStringified)); } export const initializeHotReload = async () => { try { const appletIframeScript = await postMessage({ type: 'get-applet-iframe-script', }); eval(appletIframeScript); } catch (e) { throw new Error(`Failed to initialize applet hot-reloading: ${e}.\n\nIf the applet is running in production mode (.webhapp) 'initializeHotReload()' needs to be removed.`); } }; export class AppletServices { constructor() { (this.creatables = {}), (this.blockTypes = {}), (this.search = async (_appletClient, _appletHash, _weaveServices, _searchFilter) => []), (this.getAssetInfo = async (_appletClient, _wal, _recordInfo) => undefined); } } export class WeaveClient { get renderInfo() { return window.__WEAVE_RENDER_INFO__; } constructor() { this.mossVersion = () => window.__MOSS_VERSION__; this.onPeerStatusUpdate = (callback) => window.__WEAVE_API__.onPeerStatusUpdate(callback); this.onBeforeUnload = (callback) => window.__WEAVE_API__.onBeforeUnload(callback); this.openAppletMain = async (appletHash) => window.__WEAVE_API__.openAppletMain(appletHash); this.openAppletBlock = async (appletHash, block, context) => window.__WEAVE_API__.openAppletBlock(appletHash, block, context); this.openCrossGroupMain = (appletBundleId) => window.__WEAVE_API__.openCrossGroupMain(appletBundleId); this.openCrossGroupBlock = (appletBundleId, block, context) => window.__WEAVE_API__.openCrossGroupBlock(appletBundleId, block, context); this.openAsset = (wal, mode) => window.__WEAVE_API__.openAsset(wal, mode); this.assets = { dragAsset: (wal) => window.__WEAVE_API__.assets.dragAsset(wal), assetInfo: (wal) => window.__WEAVE_API__.assets.assetInfo(wal), assetToPocket: (wal) => window.__WEAVE_API__.assets.assetToPocket(wal), userSelectAsset: (from) => window.__WEAVE_API__.assets.userSelectAsset(from), userSelectAssetRelationTag: () => window.__WEAVE_API__.assets.userSelectAssetRelationTag(), addTagsToAsset: (wal, tags) => window.__WEAVE_API__.assets.addTagsToAsset(wal, tags), removeTagsFromAsset: (wal, tags) => window.__WEAVE_API__.assets.removeTagsFromAsset(wal, tags), addAssetRelation: (srcWal, dstWal, tags) => window.__WEAVE_API__.assets.addAssetRelation(srcWal, dstWal, tags), removeAssetRelation: (relationHash) => window.__WEAVE_API__.assets.removeAssetRelation(relationHash), addTagsToAssetRelation: (relationHash, tags) => window.__WEAVE_API__.assets.addTagsToAssetRelation(relationHash, tags), removeTagsFromAssetRelation: (relationHash, tags) => window.__WEAVE_API__.assets.removeTagsFromAssetRelation(relationHash, tags), getAllAssetRelationTags: (crossGroup) => window.__WEAVE_API__.assets.getAllAssetRelationTags(crossGroup), assetStore: (wal) => window.__WEAVE_API__.assets.assetStore(wal), }; this.groupProfile = (groupHash) => window.__WEAVE_API__.groupProfile(groupHash); this.appletInfo = (appletHash) => window.__WEAVE_API__.appletInfo(appletHash); this.notifyFrame = (notifications) => window.__WEAVE_API__.notifyFrame(notifications); this.userSelectScreen = () => window.__WEAVE_API__.userSelectScreen(); this.requestClose = () => window.__WEAVE_API__.requestClose(); this.myGroupPermissionType = () => window.__WEAVE_API__.myGroupPermissionType(); this.appletParticipants = () => window.__WEAVE_API__.appletParticipants(); this.sendRemoteSignal = (payload) => window.__WEAVE_API__.sendRemoteSignal(payload); this.onRemoteSignal = (callback) => window.__WEAVE_API__.onRemoteSignal(callback); this.createCloneCell = (req, publicToGroupMembers) => window.__WEAVE_API__.createCloneCell(req, publicToGroupMembers); this.enableCloneCell = (req) => window.__WEAVE_API__.enableCloneCell(req); this.disableCloneCell = (req) => window.__WEAVE_API__.disableCloneCell(req); } static async connect(appletServices) { if (window.__WEAVE_RENDER_INFO__) { if (appletServices) { window.__WEAVE_APPLET_SERVICES__ = appletServices; } window.dispatchEvent(new CustomEvent('weave-client-connected')); return new WeaveClient(); } else { await new Promise((resolve, _reject) => { const listener = () => { window.removeEventListener('applet-iframe-ready', listener); resolve(null); }; window.addEventListener('applet-iframe-ready', listener); }); if (appletServices) { window.__WEAVE_APPLET_SERVICES__ = appletServices; } window.dispatchEvent(new CustomEvent('weave-client-connected')); return new WeaveClient(); } } } //# sourceMappingURL=api.js.map