@composedb/devtools
Version:
Development tools for ComposeDB projects.
70 lines (69 loc) • 3.53 kB
JavaScript
import { Model } from '@ceramicnetwork/stream-model';
import { Cacao } from '@didtools/cacao';
// The hardcoded "model" StreamID that all Model streams have in their metadata. This provides
// a "model" StreamID that can be indexed to query the set of all published Models.
// The StreamID uses the "UNLOADABLE" StreamType, and has string representation: "kh4q0ozorrgaq2mezktnrmdwleo1d"
const MODEL_STREAM_ID = Model.MODEL.toString();
export function isSignedCommitContainer(input) {
return Object.keys(input).includes('jws') && Object.keys(input).includes('linkedBlock');
}
export function assertAuthenticatedDID(ceramic) {
if (!ceramic.did?.authenticated) {
throw new Error(`An authenticated DID must be attached to the Ceramic instance`);
}
}
export function assertValidModelInterfaceType(definition, expectInterface) {
if (expectInterface && (definition.version === '1.0' || !definition.interface)) {
throw new Error(`Model ${definition.name} is not an interface model`);
}
if (!expectInterface && definition.version !== '1.0' && definition.interface) {
throw new Error(`Model ${definition.name} is expected to be an non-interface model but is an interface model`);
}
}
export function assertValidCacao(cacao, controller) {
if (cacao.p.iss !== controller) {
throw new Error(`Cacao issuer ${cacao.p.iss} does not match controller ${controller}`);
}
if (cacao.p.exp != null) {
throw new Error(`only did:pkh CACAO without expiry is supported`);
}
const hasModelResource = cacao.p.resources?.includes(`ceramic://*?model=${MODEL_STREAM_ID}`);
if (!hasModelResource) {
throw new Error(`only cacao with resource "ceramic://*?model=${MODEL_STREAM_ID}" is supported`);
}
}
export async function assertSupportedReadModelController(model, signedCommitContainer) {
const controller = model.metadata.controller;
const unsupported = `Unsupported model controller ${controller}`;
if (controller.startsWith('did:pkh:') && signedCommitContainer.cacaoBlock != null) {
const cacao = await Cacao.fromBlockBytes(signedCommitContainer.cacaoBlock);
if (cacao == null) {
throw new Error(`${unsupported}, only did:pkh with CACAO is supported`);
}
assertValidCacao(cacao, controller);
} else if (!controller.startsWith('did:key:')) {
throw new Error(`${unsupported}, only did:key is supported`);
}
}
export function assertSupportedWriteModelController(model, ceramic) {
const controller = model.metadata.controller;
const unsupported = `Unsupported model controller ${controller}`;
if (controller.startsWith('did:pkh:')) {
if (ceramic.did == null) {
throw new Error(`${unsupported}, did missing from ceramic context`);
}
if (!ceramic.did.hasCapability) {
throw new Error(`${unsupported}, only did:pkh with CACAO is supported`);
}
const cacao = ceramic.did.capability;
if (cacao.p.exp != null) {
throw new Error(`${unsupported}, only did:pkh CACAO without expiry is supported`);
}
const hasModelResource = cacao.p.resources?.includes(`ceramic://*?model=${MODEL_STREAM_ID}`);
if (!hasModelResource) {
throw new Error(`${unsupported}, only cacao with resource ${MODEL_STREAM_ID} is supported`);
}
} else if (!controller.startsWith('did:key:')) {
throw new Error(`${unsupported}, only did:key and did:pkh are supported`);
}
}