import type { SkillListing } from "../../../shared/skills"; import type { SkillIdentity, SkillManagementRequest, SkillManagementResult, } from "../../../shared/skill-management"; import type { CustomerQuerySession } from "../customer-query-session"; import type { SettingsConnection } from "../owner-rpc"; export function skillIdentityFor(skill: SkillListing): SkillIdentity { return { source: skill.origin.kind === "bundled" ? "bundled" : "installed", name: skill.name, fingerprint: skill.fingerprint, revision: skill.revision, }; } export function skillIdentityKey(skill: SkillIdentity) { return JSON.stringify([ skill.source, skill.name, skill.fingerprint, skill.revision, ]); } export class SkillManagementError extends Error {} export async function manageSkill( cache: CustomerQuerySession, connection: SettingsConnection, request: SkillManagementRequest, cancelled: AbortSignal, ): Promise { const epoch = cache.getSnapshot().epoch; if (!connection?.isReady() || !navigator.onLine) throw new SkillManagementError("Reconnect and open the Skill again."); const signal = AbortSignal.any([ cancelled, connection.signal, AbortSignal.timeout(20_000), ]); const check = () => { signal.throwIfAborted(); if (!connection.isReady() || cache.getSnapshot().epoch !== epoch) throw new SkillManagementError("Reconnect and open the Skill again."); }; check(); const response = await fetch("/api/skills/manage", { method: "POST", credentials: "same-origin", headers: { "Content-Type": "application/json" }, body: JSON.stringify(request), signal, }); check(); if (response.status === 401 || response.status === 403) { cache.revoke(epoch); throw new SkillManagementError("Sign in again before managing Skills."); } const value = await response.json(); check(); if (!response.ok) { const error = value?.error; if ( typeof error?.message === "string" && error.message.length <= 1000 && typeof error?.path === "string" && error.path.length <= 240 ) throw new SkillManagementError( `${error.path ? `${error.path}: ` : ""}${error.message}`, ); throw new SkillManagementError( "Could not read this package. Reload Skills, or replace the installed package and try again.", ); } return value as SkillManagementResult; }