feat(plugin-sdk): utilize details prop for richer o11y on waiting-deps
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { join } from 'node:path'
|
import { join } from 'node:path'
|
||||||
|
|
||||||
import { createContext, defineEventa, defineInvokeHandler } from '@moeru/eventa'
|
import { createContext, defineEventa, defineInvokeHandler } from '@moeru/eventa'
|
||||||
|
import { moduleStatus } from '@proj-airi/plugin-protocol/types'
|
||||||
import { describe, expect, it, vi } from 'vitest'
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
|
|
||||||
import { FileSystemLoader, PluginHost } from '.'
|
import { FileSystemLoader, PluginHost } from '.'
|
||||||
@@ -268,6 +269,50 @@ describe('for PluginHost', () => {
|
|||||||
expect(session.phase).toBe('ready')
|
expect(session.phase).toBe('ready')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should emit dependency wait details while waiting for required capabilities', async () => {
|
||||||
|
const host = new PluginHost({
|
||||||
|
runtime: 'electron',
|
||||||
|
transport: { kind: 'in-memory' },
|
||||||
|
})
|
||||||
|
|
||||||
|
const session = await host.load(testManifest, { cwd: '' })
|
||||||
|
const statusEvents: Array<{ body?: Record<string, unknown> }> = []
|
||||||
|
session.channels.host.on(moduleStatus, (payload) => {
|
||||||
|
statusEvents.push(payload as unknown as { body?: Record<string, unknown> })
|
||||||
|
})
|
||||||
|
|
||||||
|
const started = host.init(session.id, {
|
||||||
|
requiredCapabilities: ['cap:custom'],
|
||||||
|
capabilityWaitTimeoutMs: 2000,
|
||||||
|
})
|
||||||
|
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 20))
|
||||||
|
|
||||||
|
const waitingStatus = statusEvents.find((event) => {
|
||||||
|
const body = event.body
|
||||||
|
return body?.phase === 'preparing' && typeof body.reason === 'string' && body.reason.includes('Waiting for capabilities:')
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(waitingStatus).toBeDefined()
|
||||||
|
expect(waitingStatus?.body).toMatchObject({
|
||||||
|
phase: 'preparing',
|
||||||
|
details: {
|
||||||
|
lifecyclePhase: 'waiting-deps',
|
||||||
|
requiredCapabilities: ['cap:custom'],
|
||||||
|
unresolvedCapabilities: ['cap:custom'],
|
||||||
|
timeoutMs: 2000,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
reportPluginCapability(host, {
|
||||||
|
key: 'cap:custom',
|
||||||
|
state: 'ready',
|
||||||
|
metadata: { source: 'test' },
|
||||||
|
})
|
||||||
|
const initialized = await started
|
||||||
|
expect(initialized.phase).toBe('ready')
|
||||||
|
})
|
||||||
|
|
||||||
it('should fail when required capabilities timeout', async () => {
|
it('should fail when required capabilities timeout', async () => {
|
||||||
const host = new PluginHost({
|
const host = new PluginHost({
|
||||||
runtime: 'electron',
|
runtime: 'electron',
|
||||||
|
|||||||
@@ -635,14 +635,23 @@ export class PluginHost {
|
|||||||
|
|
||||||
// Optional dependency gate before plugin-owned initialization.
|
// Optional dependency gate before plugin-owned initialization.
|
||||||
if (options.requiredCapabilities?.length) {
|
if (options.requiredCapabilities?.length) {
|
||||||
|
const capabilityTimeoutMs = options.capabilityWaitTimeoutMs ?? 15000
|
||||||
|
const unresolvedCapabilities = options.requiredCapabilities.filter(key => !this.isCapabilityReady(key))
|
||||||
assertTransition(session, 'waiting-deps')
|
assertTransition(session, 'waiting-deps')
|
||||||
session.channels.host.emit(moduleStatus, {
|
session.channels.host.emit(moduleStatus, {
|
||||||
identity: session.identity,
|
identity: session.identity,
|
||||||
phase: 'preparing',
|
phase: 'preparing',
|
||||||
reason: `Waiting for capabilities: ${options.requiredCapabilities.join(', ')}`,
|
reason: `Waiting for capabilities: ${options.requiredCapabilities.join(', ')}`,
|
||||||
|
details: {
|
||||||
|
// For richer observability
|
||||||
|
lifecyclePhase: 'waiting-deps',
|
||||||
|
requiredCapabilities: options.requiredCapabilities,
|
||||||
|
unresolvedCapabilities,
|
||||||
|
timeoutMs: capabilityTimeoutMs,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
await this.waitForCapabilities(options.requiredCapabilities, options.capabilityWaitTimeoutMs)
|
await this.waitForCapabilities(options.requiredCapabilities, capabilityTimeoutMs)
|
||||||
assertTransition(session, 'prepared')
|
assertTransition(session, 'prepared')
|
||||||
session.channels.host.emit(modulePrepared, {
|
session.channels.host.emit(modulePrepared, {
|
||||||
identity: session.identity,
|
identity: session.identity,
|
||||||
|
|||||||
Reference in New Issue
Block a user