V0.38.3 extension config sections (#236)

Co-authored-by: gobha <jasafpro@gmail.com>
Co-committed-by: gobha <jasafpro@gmail.com>
This commit is contained in:
2026-03-25 16:38:38 +00:00
committed by xcaliber
parent 2136535176
commit fe5894b6e2
11 changed files with 338 additions and 12 deletions

View File

@@ -272,6 +272,99 @@
}
});
// ── v0.38.3: Config section manifest ──
await T.test('packages', 'config-section-install', 'install pkg with config_section → manifest stored', async function () {
var manifest = makeManifest({
tier: 'browser',
type: 'extension',
config_section: {
label: 'SDK Test Config',
icon: 'M12 2L2 7',
component: 'js/config.js',
surfaces: ['admin', 'settings'],
category: 'system'
}
});
// Extension needs at least one of tools/pipes/hooks
var file = makePkgFile(manifest, [
{ name: 'js/config.js', content: 'export default function() { return "config"; }' }
]);
var r = await sw.api.admin.packages.install(file);
T.assert(r && r.id === manifest.id, 'expected install success');
// Verify manifest roundtrip
var pkg = await sw.api.admin.packages.get(manifest.id);
T.assert(pkg && pkg.manifest, 'expected manifest in response');
var cs = pkg.manifest.config_section;
T.assert(cs && cs.label === 'SDK Test Config', 'expected config_section.label preserved');
T.assert(cs.surfaces && cs.surfaces.length === 2, 'expected 2 surfaces');
T.assert(cs.component === 'js/config.js', 'expected component preserved');
// Cleanup
T.cleanup.push(async function () {
try { await sw.api.admin.packages.del(manifest.id); } catch (_) {}
});
});
await T.test('packages', 'config-section-settings', 'config section settings round-trip', async function () {
var manifest = makeManifest({
tier: 'browser',
type: 'extension',
config_section: {
label: 'SDK Config RT',
component: 'js/config.js',
surfaces: ['settings']
}
});
var file = makePkgFile(manifest, [
{ name: 'js/config.js', content: 'export default function() { return "config"; }' }
]);
var r = await sw.api.admin.packages.install(file);
T.assert(r && r.id, 'install success');
// Write settings
var settings = { api_key_label: 'My Service', timeout: 30 };
await sw.api.admin.packages.updateSettings(manifest.id, settings);
// Read back
var stored = await sw.api.admin.packages.settings(manifest.id);
T.assert(stored && stored.api_key_label === 'My Service', 'expected settings round-trip');
T.assert(stored.timeout === 30, 'expected numeric setting preserved');
// Cleanup
T.cleanup.push(async function () {
try { await sw.api.admin.packages.del(manifest.id); } catch (_) {}
});
});
await T.test('packages', 'config-section-list', 'list packages → config_section visible', async function () {
var manifest = makeManifest({
tier: 'browser',
type: 'extension',
config_section: {
label: 'SDK List Test',
component: 'js/config.js',
surfaces: ['admin']
}
});
var file = makePkgFile(manifest, [
{ name: 'js/config.js', content: 'export default function() {}' }
]);
await sw.api.admin.packages.install(file);
var list = await sw.api.admin.packages.list();
var found = (list || []).find(function (p) { return p.id === manifest.id; });
T.assert(found, 'expected package in list');
T.assert(found.manifest && found.manifest.config_section, 'expected config_section in list response');
T.assert(found.manifest.config_section.label === 'SDK List Test', 'expected label match');
// Cleanup
T.cleanup.push(async function () {
try { await sw.api.admin.packages.del(manifest.id); } catch (_) {}
});
});
await T.test('packages', 'consumer-bad-dep', 'consumer with non-existent dependency → 400', async function () {
var manifest = makeManifest({ dependencies: { 'nonexistent-lib-xyz': '>=1.0.0' } });
var file = makePkgFile(manifest, [