feat(web): add read-only Loader plugin inventory
This commit is contained in:
16
packages/host/plugin-inventory/tests/invariant.spec.ts
Normal file
16
packages/host/plugin-inventory/tests/invariant.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import InvariantService from '@deepseek-ai/dsh-invariants'
|
||||
import * as PluginInventoryInvariant from '../src/invariant.ts'
|
||||
|
||||
describe('plugin-inventory invariant companion', () => {
|
||||
it('registers the package-owned empty installer', async () => {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(InvariantService, { enabled: true })
|
||||
const fiber = ctx.plugin(PluginInventoryInvariant)
|
||||
await expect(fiber.await()).resolves.toBeDefined()
|
||||
await fiber.dispose()
|
||||
await expect(ctx.plugin(PluginInventoryInvariant).await()).resolves.toBeDefined()
|
||||
await ctx.fiber.dispose()
|
||||
})
|
||||
})
|
||||
89
packages/host/plugin-inventory/tests/inventory.spec.ts
Normal file
89
packages/host/plugin-inventory/tests/inventory.spec.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import { Context, type Plugin } from '@deepseek-ai/cordis'
|
||||
import Loader from '@deepseek-ai/cordis-plugin-loader'
|
||||
import { remoteMethods } from '@deepseek-ai/dsh-type-meta'
|
||||
import PluginInventoryService from '../src/index.ts'
|
||||
|
||||
const contexts: Context[] = []
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(contexts.splice(0).map(ctx => ctx.fiber.dispose()))
|
||||
})
|
||||
|
||||
const activePlugin: Plugin.Function = () => {}
|
||||
const pendingPlugin: Plugin.Object = {
|
||||
inject: ['neverReady'],
|
||||
apply() {},
|
||||
}
|
||||
|
||||
async function harness(): Promise<{
|
||||
ctx: Context
|
||||
inventory: PluginInventoryService
|
||||
}> {
|
||||
const ctx = new Context()
|
||||
contexts.push(ctx)
|
||||
await ctx.plugin(Loader)
|
||||
ctx.loader.builtins.active = activePlugin
|
||||
ctx.loader.builtins.pending = pendingPlugin
|
||||
await ctx.plugin(PluginInventoryService)
|
||||
const inventory = ctx.get('pluginInventory') as PluginInventoryService
|
||||
return { ctx, inventory }
|
||||
}
|
||||
|
||||
describe('PluginInventoryService', () => {
|
||||
it('publishes one direct list method under the pluginInventory namespace', async () => {
|
||||
const { inventory } = await harness()
|
||||
expect(inventory.typertGateway).toMatchObject({
|
||||
serviceKey: 'pluginInventory',
|
||||
namespace: 'pluginInventory',
|
||||
})
|
||||
expect(remoteMethods(inventory)).toEqual([
|
||||
{ method: 'list', invocation: { kind: 'direct' } },
|
||||
])
|
||||
})
|
||||
|
||||
it('projects current non-group Loader entries without a second cache', async () => {
|
||||
const { ctx, inventory } = await harness()
|
||||
const activeId = await ctx.loader.create({ name: 'cordis:active' })
|
||||
const pendingId = await ctx.loader.create({ name: 'cordis:pending' })
|
||||
const disabledId = await ctx.loader.create({
|
||||
name: 'cordis:not-installed',
|
||||
disabled: true,
|
||||
})
|
||||
await ctx.loader.create({ name: 'cordis:active', group: true })
|
||||
|
||||
expect(inventory.list()).toEqual({
|
||||
entries: [
|
||||
{
|
||||
entryId: activeId,
|
||||
displayId: activeId,
|
||||
enabled: true,
|
||||
fiberPhase: 'active',
|
||||
},
|
||||
{
|
||||
entryId: pendingId,
|
||||
displayId: pendingId,
|
||||
enabled: true,
|
||||
fiberPhase: 'pending',
|
||||
},
|
||||
{
|
||||
entryId: disabledId,
|
||||
displayId: disabledId,
|
||||
enabled: false,
|
||||
fiberPhase: null,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
await ctx.loader.update(activeId, { disabled: true })
|
||||
expect(inventory.list().entries.find(entry => entry.entryId === activeId)).toEqual({
|
||||
entryId: activeId,
|
||||
displayId: activeId,
|
||||
enabled: false,
|
||||
fiberPhase: null,
|
||||
})
|
||||
|
||||
await ctx.loader.remove(pendingId)
|
||||
expect(inventory.list().entries.some(entry => entry.entryId === pendingId)).toBe(false)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user