fix(plugin-sdk,server-*): type mismatch

This commit is contained in:
Neko Ayaka
2026-02-07 03:31:44 +08:00
parent 795e12f13b
commit b49cf9275a
10 changed files with 106 additions and 27 deletions
@@ -38,6 +38,7 @@ export default defineConfig({
// Thanks to [@Maqsyo](https://github.com/Maqsyo)
// https://github.com/alex8088/electron-vite/issues/99#issuecomment-1862671727
base: './',
build: {
rolldownOptions: {
input: {
@@ -46,6 +47,7 @@ export default defineConfig({
},
},
},
optimizeDeps: {
exclude: [
// Internal Packages
@@ -74,6 +76,7 @@ export default defineConfig({
'@framework/model/cubismmoc',
],
},
resolve: {
alias: {
'@proj-airi/server-sdk': resolve(join(import.meta.dirname, '..', '..', 'packages', 'server-sdk', 'src')),
@@ -83,6 +86,7 @@ export default defineConfig({
'@proj-airi/stage-shared': resolve(join(import.meta.dirname, '..', '..', 'packages', 'stage-shared', 'src')),
},
},
server: {
warmup: {
clientFiles: [
@@ -91,6 +95,7 @@ export default defineConfig({
],
},
},
worker: {
format: 'es',
rollupOptions: {
@@ -1,4 +1,4 @@
import type { ContextInit } from '../../apis/plugin/shared'
import type { ContextInit } from '../../plugin/shared'
export async function init(_initContext: ContextInit) {
return false
+42 -5
View File
@@ -23,16 +23,19 @@ import {
matchesDestinations,
} from './middlewares'
function createServerEventMetadata(serverInstanceId: string, parentId?: string) {
function createServerEventMetadata(serverInstanceId: string, parentId?: string): { source: MetadataEventSource, event: { id: string, parentId?: string } } {
return {
event: {
id: nanoid(),
parentId,
},
source: {
plugin: WebSocketEventSource.Server,
instanceId: serverInstanceId,
version: packageJSON.version,
kind: 'plugin',
plugin: {
id: WebSocketEventSource.Server,
version: packageJSON.version,
},
id: serverInstanceId,
},
}
}
@@ -160,6 +163,24 @@ export function setupApp(options?: {
}
}
function listKnownModules() {
return Array.from(peers.values())
.filter(peerInfo => peerInfo.name && peerInfo.identity)
.map(peerInfo => ({
name: peerInfo.name,
index: peerInfo.index,
identity: peerInfo.identity!,
}))
}
function sendRegistrySync(peer: Peer, parentId?: string) {
send(peer, {
type: 'registry:modules:sync',
data: { modules: listKnownModules() },
metadata: createServerEventMetadata(instanceId, parentId),
})
}
app.get('/ws', defineWebSocketHandler({
open: (peer) => {
if (authToken) {
@@ -168,6 +189,7 @@ export function setupApp(options?: {
else {
peer.send(RESPONSES.authenticated)
peers.set(peer.id, { peer, authenticated: true, name: '', lastHeartbeatAt: Date.now() })
sendRegistrySync(peer)
}
logger.withFields({ peer: peer.id, activePeers: peers.size }).log('connected')
@@ -228,6 +250,8 @@ export function setupApp(options?: {
p.authenticated = true
}
sendRegistrySync(peer, event.metadata?.event.id)
return
}
@@ -253,6 +277,11 @@ export function setupApp(options?: {
return
}
}
if (!identity || identity.kind !== 'plugin' || !identity.plugin?.id) {
send(peer, RESPONSES.error('module identity must include kind=plugin and a plugin id for event \'module:announce\'', instanceId))
return
}
if (authToken && !p.authenticated) {
send(peer, RESPONSES.error('must authenticate before announcing', instanceId))
@@ -271,7 +300,15 @@ export function setupApp(options?: {
}
case 'ui:configure': {
const { moduleName, moduleIndex, config } = event.data
const data = event.data as {
moduleName?: string
moduleIndex?: number
identity?: MetadataEventSource
config?: Record<string, unknown>
}
const moduleName = data.moduleName ?? data.identity?.plugin?.id ?? ''
const moduleIndex = data.moduleIndex
const config = data.config
if (moduleName === '') {
send(peer, RESPONSES.error('the field \'moduleName\' can\'t be empty for event \'ui:configure\'', instanceId))
@@ -19,7 +19,7 @@ function createPeer(options: {
authenticated: true,
name: options.name,
identity: options.plugin && options.instanceId
? { plugin: options.plugin, instanceId: options.instanceId, labels: options.labels }
? { kind: 'plugin', plugin: { id: options.plugin }, id: options.instanceId, labels: options.labels }
: undefined,
}
}
@@ -39,7 +39,7 @@ function createSparkNotifyEvent(overrides: Partial<WebSocketEventOf<'spark:notif
type: 'spark:notify',
data,
metadata: overrides.metadata ?? {
source: { plugin: 'server-runtime', instanceId: 'test' },
source: { kind: 'plugin', plugin: { id: 'server-runtime' }, id: 'test' },
event: { id: data.id },
},
route: overrides.route,
@@ -25,22 +25,31 @@ export interface RouteContext {
export type RouteMiddleware = (context: RouteContext) => RouteDecision | void
function getPeerLabels(peer: AuthenticatedPeer) {
return {
...peer.identity?.plugin?.labels,
...peer.identity?.labels,
}
}
export function isDevtoolsPeer(peer: AuthenticatedPeer) {
const devtoolsLabel = peer.identity?.labels?.devtools
const devtoolsLabel = getPeerLabels(peer).devtools
const isDevtoolsLabel = devtoolsLabel === 'true' || devtoolsLabel === '1'
return Boolean(isDevtoolsLabel || peer.name.includes('devtools'))
}
export function peerMatchesPolicy(peer: AuthenticatedPeer, policy: RoutingPolicy) {
if (policy.allowPlugins?.length && !policy.allowPlugins.includes(peer.identity?.plugin ?? '')) {
const pluginId = peer.identity?.plugin?.id ?? ''
if (policy.allowPlugins?.length && !policy.allowPlugins.includes(pluginId)) {
return false
}
if (policy.denyPlugins?.length && policy.denyPlugins.includes(peer.identity?.plugin ?? '')) {
if (policy.denyPlugins?.length && policy.denyPlugins.includes(pluginId)) {
return false
}
const labels = peer.identity?.labels ?? {}
const labels = getPeerLabels(peer)
if (policy.allowLabels?.length && !matchesLabelSelectors(policy.allowLabels, labels)) {
return false
}
@@ -33,6 +33,13 @@ export function matchesLabelSelectors(selectors: string[], labels: Record<string
return selectors.every(selector => matchesLabelSelector(selector, labels))
}
function getPeerLabels(peer: AuthenticatedPeer) {
return {
...peer.identity?.plugin?.labels,
...peer.identity?.labels,
}
}
export function matchesRouteExpression(expression: RouteTargetExpression, peer: AuthenticatedPeer) {
switch (expression.type) {
case 'and':
@@ -40,9 +47,10 @@ export function matchesRouteExpression(expression: RouteTargetExpression, peer:
case 'or':
return expression.any.some(expr => matchesRouteExpression(expr, peer))
case 'glob': {
const pluginId = peer.identity?.plugin?.id
const matched = matchesGlob(expression.glob, peer.name)
|| matchesGlob(expression.glob, peer.identity?.plugin)
|| matchesGlob(expression.glob, peer.identity?.instanceId)
|| matchesGlob(expression.glob, pluginId)
|| matchesGlob(expression.glob, peer.identity?.id)
return expression.inverted ? !matched : matched
}
@@ -51,15 +59,15 @@ export function matchesRouteExpression(expression: RouteTargetExpression, peer:
return expression.inverted ? !matched : matched
}
case 'plugin': {
const matched = expression.plugins.includes(peer.identity?.plugin ?? '')
const matched = expression.plugins.includes(peer.identity?.plugin?.id ?? '')
return expression.inverted ? !matched : matched
}
case 'instance': {
const matched = expression.instances.includes(peer.identity?.instanceId ?? '')
const matched = expression.instances.includes(peer.identity?.id ?? '')
return expression.inverted ? !matched : matched
}
case 'label': {
const matched = matchesLabelSelectors(expression.selectors, peer.identity?.labels ?? {})
const matched = matchesLabelSelectors(expression.selectors, getPeerLabels(peer))
return expression.inverted ? !matched : matched
}
case 'module': {
@@ -89,21 +97,23 @@ export function matchesDestination(destination: string | RouteTargetExpression,
switch (prefix) {
case 'plugin':
return peer.identity?.plugin === value
return peer.identity?.plugin?.id === value
case 'instance':
return peer.identity?.instanceId === value
return peer.identity?.id === value
case 'label':
return matchesLabelSelectors([value], peer.identity?.labels ?? {})
return matchesLabelSelectors([value], getPeerLabels(peer))
case 'peer':
return peer.peer.id === value
case 'module':
return peer.name === value
case 'source':
return peer.name === value
default:
default: {
const pluginId = peer.identity?.plugin?.id
return matchesGlob(destination, peer.name)
|| matchesGlob(destination, peer.identity?.plugin)
|| matchesGlob(destination, peer.identity?.instanceId)
|| matchesGlob(destination, pluginId)
|| matchesGlob(destination, peer.identity?.id)
}
}
}
+2
View File
@@ -74,6 +74,8 @@ export class Client<C = undefined> {
onAnyMessage: () => {},
onAnySend: () => {},
possibleEvents: [],
dependencies: [],
configSchema: undefined,
onError: () => {},
onClose: () => {},
autoConnect: true,
@@ -708,6 +708,10 @@ interface ModuleStatusChangeEvent {
details?: Record<string, unknown>
}
interface ModuleConfigureEvent<C = undefined> {
config: C | Record<string, unknown>
}
interface UiConfigureEvent<C = undefined> {
moduleName: string
moduleIndex?: number
@@ -845,6 +849,8 @@ export const moduleContributeCapabilityActivated = defineEventa<ModuleContribute
export const moduleStatusChange = defineEventa<ModuleStatusChangeEvent>('module:status:change')
export const moduleConfigure = defineEventa<ModuleConfigureEvent>('module:configure')
export const uiConfigure = defineEventa<UiConfigureEvent>('ui:configure')
export const inputText = defineEventa<WebSocketEventInputText>('input:text')
@@ -953,6 +959,10 @@ export interface WebSocketEvents<C = undefined> {
* Request a phase transition (module → host).
*/
'module:status:change': ModuleStatusChangeEvent
/**
* Push configuration down to module (host → module).
*/
'module:configure': ModuleConfigureEvent<C>
'ui:configure': UiConfigureEvent<C>
+4 -1
View File
@@ -10,7 +10,10 @@ function formatMetadataSource(source?: MetadataEventSource) {
if (!source?.plugin)
return undefined
return source.instanceId ? `${source.plugin}:${source.instanceId}` : source.plugin
const pluginId = source.plugin.id
const instanceId = source.id
return instanceId ? `${pluginId}:${instanceId}` : pluginId
}
export function getEventSourceKey(event: EventSourcePayload, fallback = 'unknown') {
@@ -28,9 +28,12 @@ export function createClientState(): ClientState {
function createIdentity() {
return {
plugin: PLUGIN_NAME,
instanceId: nanoid(),
version: typeof packageJSON.version === 'string' ? packageJSON.version : undefined,
kind: 'plugin',
plugin: {
id: PLUGIN_NAME,
version: typeof packageJSON.version === 'string' ? packageJSON.version : undefined,
},
id: nanoid(),
labels: {
runtime: 'web-extension',
},