feat: add project plugin management (#501)

This commit is contained in:
Wassim SAMAD
2026-07-16 10:26:59 -04:00
committed by GitHub
parent 4f0aa7f7b6
commit 9ca3eaa7fe
88 changed files with 684 additions and 3100 deletions
@@ -432,6 +432,21 @@ describe('SceneBridge', () => {
expect(Object.keys(bridge.getNodes()).length).toBe(Object.keys(snap.nodes).length)
})
test('loadJSON preserves explicit plugin installs', () => {
const snap = bridge.exportJSON()
bridge.loadJSON({ ...snap, installedPlugins: ['pascal:trees'] })
expect(bridge.exportJSON().installedPlugins).toEqual(['pascal:trees'])
})
test('legacy graphs do not become explicitly uninstalled on export', () => {
const snap = bridge.exportJSON()
const { installedPlugins: _installedPlugins, ...legacy } = snap
bridge.loadJSON(legacy)
expect(Object.hasOwn(bridge.exportJSON(), 'installedPlugins')).toBe(false)
})
test('loadJSON throws on malformed JSON string', () => {
expect(() => bridge.loadJSON('not json')).toThrow(/invalid JSON/)
})
+9
View File
@@ -72,6 +72,9 @@ export class SceneBridge {
nodes: state.nodes,
rootNodeIds: state.rootNodeIds,
collections: state.collections ?? {},
...(state.hasExplicitPluginInstallState || state.installedPlugins.length > 0
? { installedPlugins: state.installedPlugins }
: {}),
}),
)
}
@@ -117,6 +120,12 @@ export class SceneBridge {
}
this.setScene(nodes as Record<AnyNodeId, AnyNode>, rootNodeIds as AnyNodeId[])
if (Array.isArray(obj.installedPlugins)) {
useScene.getState().setInstalledPlugins(
obj.installedPlugins.filter((id): id is string => typeof id === 'string'),
{ explicit: true },
)
}
}
/** Read a single node, or `null` if not present. */
@@ -150,6 +150,7 @@ class SceneOperationsFacade implements SceneOperations {
nodes: exported.nodes,
rootNodeIds: exported.rootNodeIds,
collections: exported.collections as SceneGraph['collections'],
installedPlugins: exported.installedPlugins,
}
}