feat: add toolbox contract shell and testkit

This commit is contained in:
2026-07-20 17:53:56 +02:00
commit ce9bddb218
53 changed files with 8950 additions and 0 deletions

View File

@@ -0,0 +1,261 @@
// @vitest-environment node
import { readFileSync } from "node:fs";
import Ajv2020, { type ValidateFunction } from "ajv/dist/2020.js";
import { describe, expect, it } from "vitest";
import { parseToolboxApp, parseToolboxCatalog } from "../src/index.js";
const appSchema = JSON.parse(
readFileSync(
new URL("../../../schemas/toolbox-app.v1.schema.json", import.meta.url),
"utf8",
),
) as object;
const catalogSchema = JSON.parse(
readFileSync(
new URL("../../../schemas/toolbox-catalog.v1.schema.json", import.meta.url),
"utf8",
),
) as object;
const ajv = new Ajv2020({
allErrors: true,
strict: true,
// `not: { required: [...] }` intentionally names the opposite union arm.
strictRequired: false,
});
const validateApp = ajv.compile(appSchema);
const validateCatalog = ajv.compile(catalogSchema);
type Parser = (value: unknown) => unknown;
function runtimeAccepts(parser: Parser, value: unknown): boolean {
try {
parser(value);
return true;
} catch {
return false;
}
}
function expectParity(
validate: ValidateFunction,
parser: Parser,
value: unknown,
expected: boolean,
): void {
const schemaAccepted = validate(value);
expect(
schemaAccepted,
ajv.errorsText(validate.errors, { separator: "\n" }),
).toBe(expected);
expect(runtimeAccepts(parser, value)).toBe(expected);
}
const validApp = (): Record<string, unknown> => ({
schemaVersion: 1,
id: "de.add-ideas.example",
name: "Example",
version: "1.2.3",
description: "Example application",
entry: "./",
icon: "./icon.svg",
categories: ["documents"],
tags: ["example"],
integration: {
contextVersion: 1,
launchModes: ["navigate"],
embedding: "unsupported",
},
requirements: {
secureContext: false,
workers: false,
indexedDb: false,
crossOriginIsolated: false,
},
privacy: {
processing: "local",
fileUploads: false,
telemetry: false,
},
source: {
repository: "https://example.test/source",
license: "MIT",
},
});
const validCatalog = (): Record<string, unknown> => ({
schemaVersion: 1,
id: "de.add-ideas.toolbox",
name: "Example Toolbox",
home: "./",
theme: { mode: "system", brand: "Example" },
apps: [{ manifest: "./apps/example/toolbox-app.json", enabled: true }],
});
describe("canonical schema and runtime parser parity", () => {
const acceptedApps: Array<[string, () => Record<string, unknown>]> = [
["the baseline app", validApp],
[
"relative references containing spaces and path @ signs",
() => ({
...validApp(),
entry: " ./nested app/?mode=1#result ",
actions: [{ id: "docs", label: "Docs", url: "./people/@me" }],
}),
],
[
"case-insensitive and compact absolute HTTP URLs",
() => ({
...validApp(),
source: { repository: "HTTPS:example.test", license: "MIT" },
}),
],
];
it.each(acceptedApps)("accepts %s", (_label, fixture) => {
expectParity(validateApp, parseToolboxApp, fixture(), true);
});
const rejectedApps: Array<[string, () => Record<string, unknown>]> = [
["a whitespace-only name", () => ({ ...validApp(), name: " \t " })],
[
"a whitespace-only list item",
() => ({ ...validApp(), categories: ["documents", " \n "] }),
],
[
"a non-web entry scheme",
() => ({ ...validApp(), entry: "javascript:alert(1)" }),
],
["a backslash path", () => ({ ...validApp(), icon: ".\\icon.svg" })],
["an empty HTTP authority", () => ({ ...validApp(), entry: "https://" })],
[
"a credential-bearing privacy URL",
() => ({
...validApp(),
privacy: {
processing: "local",
fileUploads: false,
telemetry: false,
url: "https://user:secret@example.test/privacy",
},
}),
],
[
"a relative source repository",
() => ({
...validApp(),
source: { repository: "../source", license: "MIT" },
}),
],
[
"a compact credential-bearing source repository",
() => ({
...validApp(),
source: { repository: "https:user@example.test", license: "MIT" },
}),
],
[
"a whitespace-only action label",
() => ({
...validApp(),
actions: [{ id: "docs", label: " ", url: "./docs" }],
}),
],
];
it.each(rejectedApps)("rejects %s", (_label, fixture) => {
expectParity(validateApp, parseToolboxApp, fixture(), false);
});
const acceptedCatalogs: Array<[string, () => Record<string, unknown>]> = [
["the baseline catalog", validCatalog],
[
"an uppercase HTTPS manifest URL",
() => ({
...validCatalog(),
apps: [
{
manifest: "HTTPS://example.test/apps/example/toolbox-app.json",
enabled: true,
},
],
}),
],
];
it.each(acceptedCatalogs)("accepts %s", (_label, fixture) => {
expectParity(validateCatalog, parseToolboxCatalog, fixture(), true);
});
const rejectedCatalogs: Array<[string, () => Record<string, unknown>]> = [
[
"a whitespace-only catalog name",
() => ({ ...validCatalog(), name: " " }),
],
[
"a whitespace-only brand",
() => ({
...validCatalog(),
theme: { mode: "system", brand: "\t" },
}),
],
[
"a non-web home URL",
() => ({ ...validCatalog(), home: "file:///tmp/toolbox" }),
],
[
"a backslash manifest path",
() => ({
...validCatalog(),
apps: [{ manifest: ".\\apps\\toolbox-app.json", enabled: true }],
}),
],
[
"a credential-bearing manifest URL",
() => ({
...validCatalog(),
apps: [
{
manifest: "https://user:secret@example.test/toolbox-app.json",
enabled: true,
},
],
}),
],
[
"a non-web external entry",
() => ({
...validCatalog(),
apps: [
{
name: "External",
entry: "data:text/html,hello",
launch: "new-tab",
enabled: true,
},
],
}),
],
[
"a whitespace-only external name",
() => ({
...validCatalog(),
apps: [
{
name: " ",
entry: "https://example.test/",
launch: "new-tab",
enabled: true,
},
],
}),
],
];
it.each(rejectedCatalogs)("rejects %s", (_label, fixture) => {
expectParity(validateCatalog, parseToolboxCatalog, fixture(), false);
});
});