87 lines
3.1 KiB
TypeScript
87 lines
3.1 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import { dirname, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
import { createBubbleSpecValidator } from "../src/plugin-sdk-bubble-validation.js";
|
|
import type { PluginHostCapabilities } from "../src/plugin-sdk-types.js";
|
|
|
|
const desktopRoot = process.env.FAMILIAROS_DESKTOP_ROOT ?? resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
const pluginSdkApiBuilderSource = readFileSync(resolve(desktopRoot, "src/plugin-sdk-api-builder.ts"), "utf8");
|
|
const pluginSdkBubbleValidationSource = readFileSync(resolve(desktopRoot, "src/plugin-sdk-bubble-validation.ts"), "utf8");
|
|
const pluginSdkValidatorsSource = readFileSync(resolve(desktopRoot, "src/plugin-sdk-validators.ts"), "utf8");
|
|
const pluginSdkBubbleSupportSource = readFileSync(resolve(desktopRoot, "src/plugin-sdk-bubble-support.ts"), "utf8");
|
|
|
|
assert.match(pluginSdkApiBuilderSource, /from "\.\/plugin-sdk-bubble-validation(?:\.js)?"/, "Plugin SDK API builder must import the extracted bubble validation seam.");
|
|
assert.match(pluginSdkBubbleValidationSource, /export function createBubbleSpecValidator/, "Plugin SDK bubble validation seam must export the validator factory.");
|
|
assert.match(pluginSdkValidatorsSource, /from "\.\/plugin-sdk-bubble-support(?:\.js)?"/, "Plugin SDK validators must import the extracted bubble support seam.");
|
|
assert.match(pluginSdkBubbleSupportSource, /export function validateBubbleInput/, "Plugin SDK bubble support must export input validation.");
|
|
assert.match(pluginSdkBubbleSupportSource, /export function renderLimitedMarkdown/, "Plugin SDK bubble support must export limited markdown rendering.");
|
|
|
|
const requestedPermissions: string[] = [];
|
|
const validateBubbleSpec = createBubbleSpecValidator({
|
|
capabilities: {
|
|
settings: {
|
|
dynamicSpeechAllowed: () => true,
|
|
},
|
|
} as PluginHostCapabilities,
|
|
requirePermission(permission) {
|
|
requestedPermissions.push(permission);
|
|
},
|
|
quotas: {
|
|
dynamicTextChars: 2_000,
|
|
markdownChars: 600,
|
|
},
|
|
resolveAssetRef(ref, kinds) {
|
|
const name = typeof ref === "object" && ref !== null && "name" in ref ? String((ref as { name: unknown }).name) : "asset";
|
|
return {
|
|
kind: kinds[0]!,
|
|
name,
|
|
path: `/tmp/${kinds[0]}/${name}.svg`,
|
|
};
|
|
},
|
|
});
|
|
|
|
const hudBubble = validateBubbleSpec({
|
|
pin: true,
|
|
hud: {
|
|
items: [
|
|
{
|
|
icon: { kind: "icon", name: "focus" },
|
|
value: 79.6,
|
|
tone: "amber",
|
|
label: "Focus",
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
assert.equal(hudBubble.pin, true);
|
|
assert.equal(requestedPermissions.includes("familiar:pin"), true);
|
|
assert.deepEqual(hudBubble.hud?.items, [
|
|
{
|
|
svgPath: "/tmp/icons/focus.svg",
|
|
value: 80,
|
|
tone: "amber",
|
|
label: "Focus",
|
|
},
|
|
]);
|
|
|
|
assert.throws(
|
|
() =>
|
|
validateBubbleSpec({
|
|
pin: true,
|
|
text: "hello",
|
|
hud: {
|
|
items: [
|
|
{
|
|
icon: { kind: "icon", name: "focus" },
|
|
value: 40,
|
|
},
|
|
],
|
|
},
|
|
}),
|
|
/Plugin bubble HUD cannot be combined with text(?: or markdown|, markdown, body media, or indicator)\./,
|
|
);
|
|
|
|
console.error("Plugin SDK bubble validation seam passed.");
|