refactor(stage-tamagotchi): better formatting and naming

This commit is contained in:
Neko Ayaka
2026-06-12 19:09:30 +08:00
parent 1ae161c273
commit eb98845b11
8 changed files with 100 additions and 124 deletions
@@ -1,10 +1,10 @@
import type { StaticAssetService } from '../../../http-server/static-assets'
import type { StaticAssetSession } from '../../../http-server/static-assets/types'
import type { PluginAssetCookie, PluginAssetCookieAdapter } from './index'
import type { ExtensionAssetCookie, ExtensionAssetCookieAdapter } from './index'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createPluginAssetService } from './index'
import { createExtensionAssetService } from './index'
const mockState = vi.hoisted(() => ({
createStaticAssetService: vi.fn(),
@@ -45,8 +45,8 @@ function createFakeServer(options: {
}
function createFakeCookieAdapter() {
const setCookies: PluginAssetCookie[] = []
const removedCookies: PluginAssetCookie[] = []
const setCookies: ExtensionAssetCookie[] = []
const removedCookies: ExtensionAssetCookie[] = []
return {
adapter: {
@@ -56,13 +56,13 @@ function createFakeCookieAdapter() {
removeCookie: vi.fn(async (cookie) => {
removedCookies.push(cookie)
}),
} satisfies PluginAssetCookieAdapter,
} satisfies ExtensionAssetCookieAdapter,
removedCookies,
setCookies,
}
}
describe('createPluginAssetService', () => {
describe('createExtensionAssetService', () => {
beforeEach(() => {
mockState.createStaticAssetService.mockReset()
})
@@ -75,7 +75,7 @@ describe('createPluginAssetService', () => {
const { adapter, setCookies } = createFakeCookieAdapter()
mockState.createStaticAssetService.mockReturnValue(server)
const service = createPluginAssetService({
const service = createExtensionAssetService({
getManifestEntryByName: () => new Map(),
cookieAdapter: adapter,
})
@@ -122,7 +122,7 @@ describe('createPluginAssetService', () => {
const { adapter, setCookies } = createFakeCookieAdapter()
mockState.createStaticAssetService.mockReturnValue(server)
const service = createPluginAssetService({
const service = createExtensionAssetService({
getManifestEntryByName: () => new Map(),
cookieAdapter: adapter,
})
@@ -134,7 +134,7 @@ describe('createPluginAssetService', () => {
routeAssetPath: 'assets/app.js',
pathPrefix: 'assets/',
ttlMs: 60_000,
})).rejects.toThrow('Plugin asset server base URL is unavailable')
})).rejects.toThrow('Extension asset server base URL is unavailable')
expect(server.revokeSession).toHaveBeenCalledWith('asset-session-2')
expect(adapter.setCookie).not.toHaveBeenCalled()
@@ -148,7 +148,7 @@ describe('createPluginAssetService', () => {
})
const { adapter } = createFakeCookieAdapter()
mockState.createStaticAssetService.mockReturnValue(server)
const service = createPluginAssetService({
const service = createExtensionAssetService({
getManifestEntryByName: () => new Map(),
cookieAdapter: adapter,
})
@@ -160,7 +160,7 @@ describe('createPluginAssetService', () => {
routeAssetPath: '../secret.txt',
pathPrefix: '',
ttlMs: 60_000,
})).rejects.toThrow('Plugin asset session routeAssetPath must be a safe plugin asset path')
})).rejects.toThrow('Extension asset session routeAssetPath must be a safe extension asset path')
expect(server.revokeSession).toHaveBeenCalledWith('asset-session-3')
expect(adapter.setCookie).not.toHaveBeenCalled()
@@ -195,14 +195,14 @@ describe('createPluginAssetService', () => {
const { adapter, removedCookies } = createFakeCookieAdapter()
mockState.createStaticAssetService.mockReturnValue(server)
const service = createPluginAssetService({
const service = createExtensionAssetService({
getManifestEntryByName: () => new Map(),
cookieAdapter: adapter,
})
await service.revokeSession('direct-asset-session')
await service.revokeByOwnerSessionId('owner-session-1')
await service.revokeByPluginId('airi-plugin-game-chess')
await service.revokeByExtensionId('airi-plugin-game-chess')
await service.revokeAll()
expect(server.revokeSession).toHaveBeenCalledWith('direct-asset-session')
@@ -251,7 +251,7 @@ describe('createPluginAssetService', () => {
const { adapter, removedCookies } = createFakeCookieAdapter()
mockState.createStaticAssetService.mockReturnValue(server)
const service = createPluginAssetService({
const service = createExtensionAssetService({
getManifestEntryByName: () => new Map(),
cookieAdapter: adapter,
})
@@ -6,11 +6,11 @@ import { createStaticAssetService } from '../../../http-server/static-assets'
import { buildMountedStaticAssetPath } from '../../../http-server/static-assets/paths'
/**
* Describes one plugin asset session creation request.
* Describes one extension asset session creation request.
*
* Use when:
* - A extension-owned asset URL must be mounted behind the local loopback server with cookie auth
* - Snapshot builders need a transport-agnostic way to authorize one plugin asset route before iframe load
* - An extension-owned asset URL must be mounted behind the local loopback server with cookie auth
* - Snapshot builders need a transport-agnostic way to authorize one extension asset route before iframe load
*
* Expects:
* - `pluginId` matches a manifest entry registered in the asset host
@@ -20,10 +20,10 @@ import { buildMountedStaticAssetPath } from '../../../http-server/static-assets/
* Returns:
* - N/A
*/
export interface PluginAssetSessionInput {
/** Plugin id that owns the static asset root. */
export interface ExtensionAssetSessionInput {
/** Extension/plugin manifest id that owns the static asset root. */
pluginId: string
/** Plugin version expected by the server-side session validator. */
/** Extension/plugin version expected by the server-side session validator. */
version: string
/** Parent extension session id used for owner-scoped revocation. */
ownerSessionId: string
@@ -36,7 +36,7 @@ export interface PluginAssetSessionInput {
}
/**
* Describes the cookie material Electron must apply before loading a plugin asset URL.
* Describes the cookie material Electron must apply before loading an extension asset URL.
*
* Use when:
* - Main process bridges server-side asset sessions into Electron's cookie jar
@@ -49,7 +49,7 @@ export interface PluginAssetSessionInput {
* Returns:
* - N/A
*/
export interface PluginAssetCookie {
export interface ExtensionAssetCookie {
/** Cookie name generated for the asset session. */
name: string
/** Opaque cookie value required by the static asset route. */
@@ -63,7 +63,7 @@ export interface PluginAssetCookie {
}
/**
* Applies and removes plugin asset cookies from the Electron host.
* Applies and removes extension asset cookies from the Electron host.
*
* Use when:
* - Asset sessions must exist in Electron's cookie jar before an iframe navigates to its URL
@@ -76,13 +76,13 @@ export interface PluginAssetCookie {
* Returns:
* - N/A
*/
export interface PluginAssetCookieAdapter {
setCookie: (cookie: PluginAssetCookie) => Promise<void>
removeCookie: (cookie: PluginAssetCookie) => Promise<void>
export interface ExtensionAssetCookieAdapter {
setCookie: (cookie: ExtensionAssetCookie) => Promise<void>
removeCookie: (cookie: ExtensionAssetCookie) => Promise<void>
}
/**
* Describes the plugin asset methods needed while building renderer-facing snapshots.
* Describes the extension asset methods needed while building renderer-facing snapshots.
*
* Use when:
* - Snapshot builders must request route-scoped asset sessions without depending on HTTP server internals
@@ -95,13 +95,13 @@ export interface PluginAssetCookieAdapter {
* Returns:
* - A mounted asset URL and cookie-backed session metadata
*/
export interface PluginAssetSnapshotService {
export interface ExtensionAssetSnapshotService {
getBaseUrl: () => string | undefined
createAssetSession: (input: Omit<PluginAssetSessionInput, 'ttlMs'>) => Promise<PluginAssetSession>
createAssetSession: (input: Omit<ExtensionAssetSessionInput, 'ttlMs'>) => Promise<ExtensionAssetSession>
}
/**
* Describes a plugin asset session prepared for renderer iframe navigation.
* Describes an extension asset session prepared for renderer iframe navigation.
*
* Use when:
* - A plugin iframe needs a mounted static asset URL and pre-applied cookie state
@@ -113,13 +113,13 @@ export interface PluginAssetSnapshotService {
* Returns:
* - Renderer-facing URL plus server and cookie metadata
*/
export interface PluginAssetSession {
export interface ExtensionAssetSession {
/** Absolute mounted asset URL safe to hand to a renderer iframe after cookie setup. */
url: string
/** Opaque server-side asset session id embedded in mounted asset routes. */
assetSessionId: string
/** Cookie data that was applied through the host adapter. */
cookie: PluginAssetCookie
cookie: ExtensionAssetCookie
/** Unix timestamp in milliseconds when the cookie-backed asset session expires. */
expiresAt: number
}
@@ -129,24 +129,24 @@ export interface PluginAssetSession {
*
* Use when:
* - Plugin snapshots need mounted asset URLs without depending on the H3 server shape
* - Host teardown must revoke plugin asset access independently from widget/gamelet logic
* - Host teardown must revoke extension asset access independently from widget/gamelet logic
*
* Expects:
* - Implementations own the underlying transport, cookie, and session lifecycle
*
* Returns:
* - A startable/stoppable asset-hosting service with generic plugin-facing methods
* - A startable/stoppable asset-hosting service with generic extension-facing methods
*/
export interface PluginAssetService extends ServerManager {
export interface ExtensionAssetService extends ServerManager {
getBaseUrl: () => string | undefined
createAssetSession: (input: PluginAssetSessionInput) => Promise<PluginAssetSession>
createAssetSession: (input: ExtensionAssetSessionInput) => Promise<ExtensionAssetSession>
revokeSession: (assetSessionId: string) => Promise<void>
revokeByOwnerSessionId: (ownerSessionId: string) => Promise<void>
revokeByPluginId: (pluginId: string) => Promise<void>
revokeByExtensionId: (extensionId: string) => Promise<void>
revokeAll: () => Promise<void>
}
function createPluginAssetCookie(baseUrl: string, session: StaticAssetSession): PluginAssetCookie {
function createExtensionAssetCookie(baseUrl: string, session: StaticAssetSession): ExtensionAssetCookie {
return {
name: session.cookieName,
value: session.cookieValue,
@@ -156,36 +156,24 @@ function createPluginAssetCookie(baseUrl: string, session: StaticAssetSession):
}
}
function requireBaseUrl(baseUrl: string | undefined) {
if (!baseUrl) {
throw new Error('Plugin asset server base URL is unavailable; start the asset server before creating asset sessions')
}
return baseUrl
}
async function removeCookies(cookieAdapter: PluginAssetCookieAdapter, baseUrl: string, sessions: readonly StaticAssetSession[]) {
await Promise.all(sessions.map(session => cookieAdapter.removeCookie(createPluginAssetCookie(baseUrl, session))))
}
/**
* Creates the plugin asset host service backed by the extension static asset server.
* Creates the extension asset host service backed by the extension static asset server.
*
* Use when:
* - The extension host needs to expose mounted asset URLs to renderer snapshots
* - Asset session lifecycle should stay inside the plugin domain instead of the HTTP server layer
* - Asset session lifecycle should stay inside the extension domain instead of the HTTP server layer
*
* Expects:
* - `getManifestEntryByName` returns the latest extension root/version map
* - `cookieAdapter` writes and removes cookies in the Electron host session used by plugin iframes
*
* Returns:
* - A plugin-facing asset host service with generic plugin asset methods
* - An extension-facing asset host service with generic extension asset methods
*/
export function createPluginAssetService(options: {
export function createExtensionAssetService(options: {
getManifestEntryByName: () => Map<string, StaticAssetManifestEntry>
cookieAdapter: PluginAssetCookieAdapter
}): PluginAssetService {
cookieAdapter: ExtensionAssetCookieAdapter
}): ExtensionAssetService {
const server = createStaticAssetService({ getManifestEntryByName: options.getManifestEntryByName })
let lastBaseUrl: string | undefined
@@ -201,11 +189,13 @@ export function createPluginAssetService(options: {
return
}
await removeCookies(options.cookieAdapter, baseUrl, sessions)
await Promise.all(
sessions.map(session => options.cookieAdapter.removeCookie(createExtensionAssetCookie(baseUrl, session))),
)
}
return {
key: 'plugin-assets',
key: 'extension-assets',
async start() {
await server.start()
},
@@ -226,7 +216,11 @@ export function createPluginAssetService(options: {
})
try {
const baseUrl = requireBaseUrl(readBaseUrl())
const baseUrl = readBaseUrl()
if (!baseUrl) {
throw new Error('Extension asset server base URL is unavailable; start the asset server before creating asset sessions')
}
const mountedPath = buildMountedStaticAssetPath({
extensionId: input.pluginId,
assetSessionId: session.assetSessionId,
@@ -234,10 +228,10 @@ export function createPluginAssetService(options: {
})
if (!mountedPath) {
throw new RangeError('Plugin asset session routeAssetPath must be a safe plugin asset path')
throw new RangeError('Extension asset session routeAssetPath must be a safe extension asset path')
}
const cookie = createPluginAssetCookie(baseUrl, session)
const cookie = createExtensionAssetCookie(baseUrl, session)
await options.cookieAdapter.setCookie(cookie)
return {
@@ -263,8 +257,8 @@ export function createPluginAssetService(options: {
async revokeByOwnerSessionId(ownerSessionId) {
await revokeSessions(server.revokeByOwnerSessionId(ownerSessionId))
},
async revokeByPluginId(pluginId) {
await revokeSessions(server.revokeByExtensionId(pluginId))
async revokeByExtensionId(extensionId) {
await revokeSessions(server.revokeByExtensionId(extensionId))
},
async revokeAll() {
await revokeSessions(server.revokeAll())
@@ -4,7 +4,7 @@ import type {
PluginHostDebugSnapshot,
PluginHostModuleSummary,
} from '../../../../../shared/eventa/plugin/host'
import type { PluginAssetSnapshotService } from '../features/static-assets'
import type { ExtensionAssetSnapshotService } from '../features/static-assets'
import type { ExtensionConfig, ManifestEntry } from '../types'
import { rewriteWidgetModuleAssetUrl } from '../kits/widget'
@@ -15,12 +15,12 @@ import { buildPluginRegistrySnapshot } from './registry'
*
* Use when:
* - Renderer devtools need sessions, kits, modules, and capability state
* - Widget iframe asset URLs must be rewritten to mounted plugin asset URLs
* - Widget iframe asset URLs must be rewritten to mounted extension asset URLs
*
* Expects:
* - `host` is the initialized extension host instance
* - `manifestEntryByName` contains entries for any extension-owned modules being inspected
* - `pluginAssetService` owns plugin asset URL/session lifecycle when mounted asset URLs are needed
* - `extensionAssetService` owns extension asset URL/session lifecycle when mounted asset URLs are needed
*
* Returns:
* - A full debug snapshot with registry, sessions, kits, modules, and capabilities
@@ -32,9 +32,9 @@ export function buildPluginHostDebugSnapshot(options: {
config: ExtensionConfig
loaded: Set<string>
manifestEntryByName: Map<string, ManifestEntry>
pluginAssetService?: PluginAssetSnapshotService
extensionAssetService?: ExtensionAssetSnapshotService
}): Promise<PluginHostDebugSnapshot> {
const pluginAssetService = options.pluginAssetService
const extensionAssetService = options.extensionAssetService
const modules = Promise.all(options.host
.listBindings()
.map(module =>
@@ -42,8 +42,8 @@ export function buildPluginHostDebugSnapshot(options: {
module as PluginHostModuleSummary,
options.manifestEntryByName,
{
pluginAssetBaseUrl: pluginAssetService?.getBaseUrl(),
...(pluginAssetService
pluginAssetBaseUrl: extensionAssetService?.getBaseUrl(),
...(extensionAssetService
? {
createAssetSession: ({ extensionId, version, sessionId, routeAssetPath, sessionPathPrefix }: {
extensionId: string
@@ -51,7 +51,7 @@ export function buildPluginHostDebugSnapshot(options: {
sessionId: string
routeAssetPath: string
sessionPathPrefix: string
}) => pluginAssetService.createAssetSession({
}) => extensionAssetService.createAssetSession({
pluginId: extensionId,
version,
ownerSessionId: sessionId,
@@ -5,9 +5,9 @@ import type {
PluginRegistrySnapshot,
} from '../../../../../shared/eventa/plugin/host'
import type {
PluginAssetCookie,
PluginAssetSession,
PluginAssetSnapshotService,
ExtensionAssetCookie,
ExtensionAssetSession,
ExtensionAssetSnapshotService,
} from '../features/static-assets'
import type { ExtensionHostService, SetupExtensionHostOptions } from '../types'
@@ -18,7 +18,7 @@ import { ExtensionHost } from '@proj-airi/plugin-sdk/plugin-host'
import { app, session as electronSession } from 'electron'
import { createExtensionAutoReloadFeature } from '../features/auto-reload'
import { createPluginAssetService } from '../features/static-assets'
import { createExtensionAssetService } from '../features/static-assets'
import { createBuiltInExtensionKitRuntime } from '../kits'
import { createExtensionHostConfigStore } from './config'
import { buildPluginHostDebugSnapshot } from './debug'
@@ -34,7 +34,7 @@ const extensionAssetSessionTtlMs = 30 * 24 * 60 * 60 * 1000
function createElectronExtensionAssetCookieAdapter() {
return {
async setCookie(cookie: PluginAssetCookie) {
async setCookie(cookie: ExtensionAssetCookie) {
await electronSession.defaultSession.cookies.set({
url: cookie.url,
name: cookie.name,
@@ -46,7 +46,7 @@ function createElectronExtensionAssetCookieAdapter() {
expirationDate: Math.floor(cookie.expiresAt / 1000),
})
},
async removeCookie(cookie: PluginAssetCookie) {
async removeCookie(cookie: ExtensionAssetCookie) {
await electronSession.defaultSession.cookies.remove(cookie.url, cookie.name)
},
}
@@ -169,7 +169,7 @@ export interface ExtensionHostServiceInternal extends ExtensionHostService {
* - Host debugging needs a fresh runtime snapshot after registry refresh
*
* Expects:
* - The host and plugin asset service are both initialized
* - The host and extension asset service are both initialized
*
* Returns:
* - The full debug snapshot exposed through plugin inspection IPC
@@ -184,10 +184,10 @@ export interface ExtensionHostServiceInternal extends ExtensionHostService {
* - Snapshot consumers need the current loopback asset mount base
*
* Expects:
* - The plugin asset service may be started before this is called
* - The extension asset service may be started before this is called
*
* Returns:
* - The current plugin asset base URL, or an empty string when unavailable
* - The current extension asset base URL, or an empty string when unavailable
*/
getAssetBaseUrl: () => string
@@ -233,10 +233,8 @@ export async function setupExtensionHostServiceInternal(
// Kit API, Host
const builtInKitRuntime = createBuiltInExtensionKitRuntime(options)
const host = new ExtensionHost({ runtime: 'electron', contributions: builtInKitRuntime.contributions })
builtInKitRuntime.attachHost(host) // reverse dependency injection
const host = new ExtensionHost({ runtime: 'electron' })
log.withFields({ extensionsRoot }).log('loading extension manifests')
// Once kit injected the host, then apply kits
builtInKitRuntime.registerHostKits(host)
// extension registry
@@ -249,19 +247,19 @@ export async function setupExtensionHostServiceInternal(
}
// Extension feature: Static Assets serving
const pluginAssetService = createPluginAssetService({
const extensionAssetService = createExtensionAssetService({
getManifestEntryByName: () => extensionRegistry.getManifestEntryByName(),
cookieAdapter: createElectronExtensionAssetCookieAdapter(),
})
await pluginAssetService.start()
await extensionAssetService.start()
const loaded = new Set<string>()
const loadedSessionIds = new Map<string, string>()
const moduleAssetSessionCache = new Map<string, PluginAssetSession>()
const moduleAssetSessionCache = new Map<string, ExtensionAssetSession>()
const clearModuleAssetSessionCacheByExtensionId = (pluginId: string) => {
const clearModuleAssetSessionCacheByExtensionId = (extensionId: string) => {
for (const key of moduleAssetSessionCache.keys()) {
if (key.startsWith(`${pluginId}:`)) {
if (key.startsWith(`${extensionId}:`)) {
moduleAssetSessionCache.delete(key)
}
}
@@ -305,7 +303,7 @@ export async function setupExtensionHostServiceInternal(
return cachedSession
}
const session = await pluginAssetService.createAssetSession({
const session = await extensionAssetService.createAssetSession({
pluginId,
version,
ownerSessionId,
@@ -317,8 +315,8 @@ export async function setupExtensionHostServiceInternal(
return session
}
const pluginAssetSnapshotService: PluginAssetSnapshotService = {
getBaseUrl: pluginAssetService.getBaseUrl,
const extensionAssetSnapshotService: ExtensionAssetSnapshotService = {
getBaseUrl: extensionAssetService.getBaseUrl,
createAssetSession: ({ pluginId, version, ownerSessionId, routeAssetPath, pathPrefix }) => {
return createModuleAssetSession({
pluginId,
@@ -338,7 +336,7 @@ export async function setupExtensionHostServiceInternal(
config: getConfig(),
loaded,
manifestEntryByName: extensionRegistry.getManifestEntryByName(),
pluginAssetService: pluginAssetSnapshotService,
extensionAssetService: extensionAssetSnapshotService,
})
}
@@ -374,7 +372,7 @@ export async function setupExtensionHostServiceInternal(
loaded.delete(name)
clearModuleAssetSessionCacheByOwnerSessionId(sessionId)
await pluginAssetService.revokeByOwnerSessionId(sessionId)
await extensionAssetService.revokeByOwnerSessionId(sessionId)
log.log('extension unloaded', { extension: name, sessionId })
}
@@ -436,6 +434,9 @@ export async function setupExtensionHostServiceInternal(
return {
host,
// REVIEW: Tool registry ownership is currently hidden inside the built-in kit runtime even though
// the host service also exposes it for IPC listing/invocation. Consider moving registry ownership
// to this host service and passing it into kit registration as a dependency.
tools: builtInKitRuntime.tools,
manifests: extensionRegistry.listManifests(),
async list() {
@@ -454,7 +455,7 @@ export async function setupExtensionHostServiceInternal(
else {
enabled.delete(payload.name)
clearModuleAssetSessionCacheByExtensionId(payload.name)
await pluginAssetService.revokeByPluginId(payload.name)
await extensionAssetService.revokeByExtensionId(payload.name)
}
const entry = extensionRegistry.findManifestEntry(payload.name)
@@ -514,15 +515,15 @@ export async function setupExtensionHostServiceInternal(
return await inspectSnapshot()
},
getAssetBaseUrl() {
return pluginAssetService.getBaseUrl() ?? ''
return extensionAssetService.getBaseUrl() ?? ''
},
async dispose() {
autoReloadFeature.dispose()
builtInKitRuntime.dispose()
moduleAssetSessionCache.clear()
await pluginAssetService.revokeAll()
await pluginAssetService.stop()
await extensionAssetService.revokeAll()
await extensionAssetService.stop()
},
}
}
@@ -19,12 +19,8 @@ import { defineInvoke } from '@moeru/eventa'
import { ExtensionHost } from '@proj-airi/plugin-sdk/plugin-host'
import { afterEach, beforeEach, describe, expect, expectTypeOf, it, vi } from 'vitest'
import {
electronPluginGetAssetBaseUrl,
} from '../../../../shared/eventa/plugin/assets'
import {
electronPluginUpdateCapability,
} from '../../../../shared/eventa/plugin/capabilities'
import { electronPluginGetAssetBaseUrl } from '../../../../shared/eventa/plugin/assets'
import { electronPluginUpdateCapability } from '../../../../shared/eventa/plugin/capabilities'
import {
electronPluginInspect,
electronPluginList,
@@ -34,15 +30,11 @@ import {
electronPluginSetEnabled,
electronPluginUnload,
} from '../../../../shared/eventa/plugin/host'
import {
electronPluginToolsChanged,
} from '../../../../shared/eventa/plugin/tools'
import { electronPluginToolsChanged } from '../../../../shared/eventa/plugin/tools'
import { setupExtensionHostServiceInternal } from './host'
import { loadManifestsFrom } from './host/registry'
import { setupExtensionHost as setupExtensionHostService } from './index'
import {
gameletPluginKitDescriptor,
} from './kits/gamelet'
import { gameletPluginKitDescriptor } from './kits/gamelet'
import { createGameletOrchestrationRuntime } from './kits/gamelet/orchestration'
import { widgetPluginKitDescriptor } from './kits/widget'
@@ -4,9 +4,7 @@ import { defineInvoke, defineInvokeHandler } from '@moeru/eventa'
import { createContext } from '@moeru/eventa/adapters/electron/main'
import { app, ipcMain } from 'electron'
import {
electronPluginGetAssetBaseUrl,
} from '../../../../shared/eventa/plugin/assets'
import { electronPluginGetAssetBaseUrl } from '../../../../shared/eventa/plugin/assets'
import {
electronPluginUpdateCapability,
pluginProtocolListProviders,
@@ -3,10 +3,7 @@ import type { ManifestEntry } from '../../types'
import { isPlainObject } from 'es-toolkit'
import {
buildMountedStaticAssetPath,
normalizeStaticAssetPath,
} from '../../../http-server/static-assets/paths'
import { buildMountedStaticAssetPath, normalizeStaticAssetPath } from '../../../http-server/static-assets/paths'
/**
* Describes one widget iframe asset as seen from the mounted `/ui` route.
@@ -1,12 +1,6 @@
import type {
ExtensionHost,
KitDescriptor,
} from '@proj-airi/plugin-sdk/plugin-host'
import type { ExtensionHost, KitDescriptor } from '@proj-airi/plugin-sdk/plugin-host'
export {
resolveWidgetAssetRoute,
rewriteWidgetModuleAssetUrl,
} from './asset-url'
export { resolveWidgetAssetRoute, rewriteWidgetModuleAssetUrl } from './asset-url'
/**
* Declares the built-in widget kit exposed by `stage-tamagotchi`.