fix(plugin-inventory): rename install Remote to installPlugin
The RemoteNamespaceService reserves `install` as its private registration method, so a Remote method also named `install` collided at client-api boot (`pluginInventory/install conflicts with its namespace service`). Rename the plugin-install Remote to `installPlugin` across host, client, and tests. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+3
-3
@@ -22,7 +22,7 @@ export interface PluginInventorySettingsTabInjected {
|
|||||||
/** List the offline-installable optional bundles. */
|
/** List the offline-installable optional bundles. */
|
||||||
availableBundles: () => Promise<AvailableBundlesSnapshot>
|
availableBundles: () => Promise<AvailableBundlesSnapshot>
|
||||||
/** Install a bundle or registry plugin; the host persists the change. */
|
/** Install a bundle or registry plugin; the host persists the change. */
|
||||||
install: (spec: InstallSpec) => Promise<InstallResult>
|
installPlugin: (spec: InstallSpec) => Promise<InstallResult>
|
||||||
/** Un-compose an offline optional bundle. */
|
/** Un-compose an offline optional bundle. */
|
||||||
uninstall: (name: string) => Promise<InstallResult>
|
uninstall: (name: string) => Promise<InstallResult>
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ type BundleState =
|
|||||||
|
|
||||||
/** Render the current Loader inventory with per-plugin enable/disable and install. */
|
/** Render the current Loader inventory with per-plugin enable/disable and install. */
|
||||||
export function PluginInventorySettingsTab({
|
export function PluginInventorySettingsTab({
|
||||||
list, setEnabled, availableBundles, install, uninstall, t,
|
list, setEnabled, availableBundles, installPlugin, uninstall, t,
|
||||||
}: PluginInventorySettingsTabProps): ReactNode {
|
}: PluginInventorySettingsTabProps): ReactNode {
|
||||||
const catalogId = useId()
|
const catalogId = useId()
|
||||||
const [request, setRequest] = useState(0)
|
const [request, setRequest] = useState(0)
|
||||||
@@ -126,7 +126,7 @@ export function PluginInventorySettingsTab({
|
|||||||
setInstallBusy(name)
|
setInstallBusy(name)
|
||||||
setInstallNote(null)
|
setInstallNote(null)
|
||||||
const action = mode === 'install'
|
const action = mode === 'install'
|
||||||
? install({ type: 'bundle', name })
|
? installPlugin({ type: 'bundle', name })
|
||||||
: uninstall(name)
|
: uninstall(name)
|
||||||
void action.then(
|
void action.then(
|
||||||
() => {
|
() => {
|
||||||
|
|||||||
@@ -47,10 +47,10 @@ export function apply(ctx: ClientContext): void {
|
|||||||
}
|
}
|
||||||
return result.value
|
return result.value
|
||||||
}
|
}
|
||||||
const install: PluginInventorySettingsTabInjected['install'] = async (spec) => {
|
const installPlugin: PluginInventorySettingsTabInjected['installPlugin'] = async (spec) => {
|
||||||
const result = await ctx.remote.pluginInventory.install(spec)
|
const result = await ctx.remote.pluginInventory.installPlugin(spec)
|
||||||
if (!result.ok) {
|
if (!result.ok) {
|
||||||
throw new Error(`pluginInventory.install failed: ${result.error.code}: ${result.error.message}`)
|
throw new Error(`pluginInventory.installPlugin failed: ${result.error.code}: ${result.error.message}`)
|
||||||
}
|
}
|
||||||
return result.value
|
return result.value
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ export function apply(ctx: ClientContext): void {
|
|||||||
return result.value
|
return result.value
|
||||||
}
|
}
|
||||||
const injected = (): PluginInventorySettingsTabInjected => ({
|
const injected = (): PluginInventorySettingsTabInjected => ({
|
||||||
list, setEnabled, availableBundles, install, uninstall,
|
list, setEnabled, availableBundles, installPlugin, uninstall,
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
|
ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ const t = ((key: PluginInventoryLocaleKey): string => en[key]) as PluginInventor
|
|||||||
function props(
|
function props(
|
||||||
list: PluginInventorySettingsTabInjected['list'],
|
list: PluginInventorySettingsTabInjected['list'],
|
||||||
bundles: PluginInventorySettingsTabInjected['availableBundles'] = async () => ({ available: [] }),
|
bundles: PluginInventorySettingsTabInjected['availableBundles'] = async () => ({ available: [] }),
|
||||||
install: PluginInventorySettingsTabInjected['install'] = async () => ({ ok: true as const, restartRequired: true }),
|
installPlugin: PluginInventorySettingsTabInjected['installPlugin'] = async () => ({ ok: true as const, restartRequired: true }),
|
||||||
uninstall: PluginInventorySettingsTabInjected['uninstall'] = async () => ({ ok: true as const, restartRequired: true }),
|
uninstall: PluginInventorySettingsTabInjected['uninstall'] = async () => ({ ok: true as const, restartRequired: true }),
|
||||||
): PluginInventorySettingsTabProps {
|
): PluginInventorySettingsTabProps {
|
||||||
return {
|
return {
|
||||||
t,
|
t,
|
||||||
list,
|
list,
|
||||||
availableBundles: bundles,
|
availableBundles: bundles,
|
||||||
install,
|
installPlugin,
|
||||||
uninstall,
|
uninstall,
|
||||||
} as PluginInventorySettingsTabProps
|
} as PluginInventorySettingsTabProps
|
||||||
}
|
}
|
||||||
@@ -163,7 +163,7 @@ describe('PluginInventorySettingsTab', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('renders the installable bundles with install and uninstall actions', async () => {
|
it('renders the installable bundles with install and uninstall actions', async () => {
|
||||||
const install = vi.fn<PluginInventorySettingsTabInjected['install']>(async () => ({ ok: true, restartRequired: true }))
|
const installPlugin = vi.fn<PluginInventorySettingsTabInjected['installPlugin']>(async () => ({ ok: true, restartRequired: true }))
|
||||||
const uninstall = vi.fn<PluginInventorySettingsTabInjected['uninstall']>(async () => ({ ok: true, restartRequired: true }))
|
const uninstall = vi.fn<PluginInventorySettingsTabInjected['uninstall']>(async () => ({ ok: true, restartRequired: true }))
|
||||||
const bundles: PluginInventorySettingsTabInjected['availableBundles'] = async () => ({
|
const bundles: PluginInventorySettingsTabInjected['availableBundles'] = async () => ({
|
||||||
available: [
|
available: [
|
||||||
@@ -171,7 +171,7 @@ describe('PluginInventorySettingsTab', () => {
|
|||||||
{ name: '@deepseek-ai/dsh-installed-bundle', installed: true },
|
{ name: '@deepseek-ai/dsh-installed-bundle', installed: true },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
render(<PluginInventorySettingsTab {...props(async () => SNAPSHOT, bundles, install, uninstall)} />)
|
render(<PluginInventorySettingsTab {...props(async () => SNAPSHOT, bundles, installPlugin, uninstall)} />)
|
||||||
|
|
||||||
expect(await screen.findByText(en.available)).toBeTruthy()
|
expect(await screen.findByText(en.available)).toBeTruthy()
|
||||||
expect(screen.getByText('@deepseek-ai/dsh-new-bundle')).toBeTruthy()
|
expect(screen.getByText('@deepseek-ai/dsh-new-bundle')).toBeTruthy()
|
||||||
@@ -179,7 +179,7 @@ describe('PluginInventorySettingsTab', () => {
|
|||||||
|
|
||||||
// Install a not-installed bundle.
|
// Install a not-installed bundle.
|
||||||
fireEvent.click(screen.getByRole('button', { name: en.install }))
|
fireEvent.click(screen.getByRole('button', { name: en.install }))
|
||||||
expect(install).toHaveBeenCalledWith({ type: 'bundle', name: '@deepseek-ai/dsh-new-bundle' })
|
expect(installPlugin).toHaveBeenCalledWith({ type: 'bundle', name: '@deepseek-ai/dsh-new-bundle' })
|
||||||
expect(await screen.findByText(en.restartRequired)).toBeTruthy()
|
expect(await screen.findByText(en.restartRequired)).toBeTruthy()
|
||||||
|
|
||||||
// Uninstall an installed bundle.
|
// Uninstall an installed bundle.
|
||||||
|
|||||||
@@ -138,8 +138,8 @@ export class PluginInventoryGateway extends TypertRemoteService {
|
|||||||
* @param spec - the bundle name or registry package spec to install.
|
* @param spec - the bundle name or registry package spec to install.
|
||||||
* @returns a confirmation; `restartRequired` tells the caller to restart.
|
* @returns a confirmation; `restartRequired` tells the caller to restart.
|
||||||
*/
|
*/
|
||||||
@Remote('install')
|
@Remote('installPlugin')
|
||||||
install(spec: InstallSpec): InstallResult {
|
installPlugin(spec: InstallSpec): InstallResult {
|
||||||
const profileDir = this.profileDir()
|
const profileDir = this.profileDir()
|
||||||
const anchor = this.ctx.get('dshInstallAnchor') as string | undefined
|
const anchor = this.ctx.get('dshInstallAnchor') as string | undefined
|
||||||
if (anchor === undefined) {
|
if (anchor === undefined) {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ describe('PluginInventoryGateway', () => {
|
|||||||
{ method: 'list', invocation: { kind: 'direct' } },
|
{ method: 'list', invocation: { kind: 'direct' } },
|
||||||
{ method: 'setEnabled', invocation: { kind: 'direct' } },
|
{ method: 'setEnabled', invocation: { kind: 'direct' } },
|
||||||
{ method: 'availableBundles', invocation: { kind: 'direct' } },
|
{ method: 'availableBundles', invocation: { kind: 'direct' } },
|
||||||
{ method: 'install', invocation: { kind: 'direct' } },
|
{ method: 'installPlugin', invocation: { kind: 'direct' } },
|
||||||
{ method: 'uninstall', invocation: { kind: 'direct' } },
|
{ method: 'uninstall', invocation: { kind: 'direct' } },
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
@@ -151,9 +151,9 @@ describe('PluginInventoryGateway', () => {
|
|||||||
ctx.baseUrl = pathToFileURL(dir + '/').href
|
ctx.baseUrl = pathToFileURL(dir + '/').href
|
||||||
writeFileSync(join(dir, 'package.json'), JSON.stringify({ name: 'dsh-profile-test', dsh: { profile: { bundles: [] } } }))
|
writeFileSync(join(dir, 'package.json'), JSON.stringify({ name: 'dsh-profile-test', dsh: { profile: { bundles: [] } } }))
|
||||||
try {
|
try {
|
||||||
expect(() => inventory.install({ type: 'bundle', name: 'x' })).toThrow(/install anchor is unavailable/)
|
expect(() => inventory.installPlugin({ type: 'bundle', name: 'x' })).toThrow(/install anchor is unavailable/)
|
||||||
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
|
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
|
||||||
expect(() => inventory.install({ type: 'registry', spec: 'x' })).toThrow(/not permitted/)
|
expect(() => inventory.installPlugin({ type: 'registry', spec: 'x' })).toThrow(/not permitted/)
|
||||||
} finally {
|
} finally {
|
||||||
rmSync(dir, { recursive: true, force: true })
|
rmSync(dir, { recursive: true, force: true })
|
||||||
}
|
}
|
||||||
@@ -185,7 +185,7 @@ describe('PluginInventoryGateway', () => {
|
|||||||
writeFileSync(join(dir, 'node_modules', 'b', 'cordis.patch.yml'), '[]\n')
|
writeFileSync(join(dir, 'node_modules', 'b', 'cordis.patch.yml'), '[]\n')
|
||||||
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
|
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
|
||||||
try {
|
try {
|
||||||
inventory.install({ type: 'bundle', name: 'b' })
|
inventory.installPlugin({ type: 'bundle', name: 'b' })
|
||||||
expect(readProfileManifest('dsh', dir).dsh?.profile?.bundles).toEqual(['b'])
|
expect(readProfileManifest('dsh', dir).dsh?.profile?.bundles).toEqual(['b'])
|
||||||
} finally {
|
} finally {
|
||||||
rmSync(dir, { recursive: true, force: true })
|
rmSync(dir, { recursive: true, force: true })
|
||||||
@@ -203,7 +203,7 @@ describe('PluginInventoryGateway', () => {
|
|||||||
try {
|
try {
|
||||||
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
|
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
|
||||||
ctx.provide('dshAllowPluginInstall', true)
|
ctx.provide('dshAllowPluginInstall', true)
|
||||||
expect(inventory.install({ type: 'registry', spec: 'some-pkg' }).restartRequired).toBe(true)
|
expect(inventory.installPlugin({ type: 'registry', spec: 'some-pkg' }).restartRequired).toBe(true)
|
||||||
} finally {
|
} finally {
|
||||||
delete process.env.DSH_PNPM
|
delete process.env.DSH_PNPM
|
||||||
rmSync(dir, { recursive: true, force: true })
|
rmSync(dir, { recursive: true, force: true })
|
||||||
@@ -260,7 +260,7 @@ describe('PluginInventoryGateway', () => {
|
|||||||
try {
|
try {
|
||||||
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
|
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
|
||||||
ctx.provide('dshAllowPluginInstall', true)
|
ctx.provide('dshAllowPluginInstall', true)
|
||||||
expect(() => inventory.install({ type: 'registry', spec: 'x' })).toThrow(/bundled pnpm is unavailable/)
|
expect(() => inventory.installPlugin({ type: 'registry', spec: 'x' })).toThrow(/bundled pnpm is unavailable/)
|
||||||
} finally {
|
} finally {
|
||||||
rmSync(dir, { recursive: true, force: true })
|
rmSync(dir, { recursive: true, force: true })
|
||||||
}
|
}
|
||||||
@@ -276,7 +276,7 @@ describe('PluginInventoryGateway', () => {
|
|||||||
try {
|
try {
|
||||||
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
|
ctx.provide('dshInstallAnchor', join(dir, 'package.json'))
|
||||||
ctx.provide('dshAllowPluginInstall', true)
|
ctx.provide('dshAllowPluginInstall', true)
|
||||||
expect(() => inventory.install({ type: 'registry', spec: 'x' })).toThrow(/failed to read profile manifest/)
|
expect(() => inventory.installPlugin({ type: 'registry', spec: 'x' })).toThrow(/failed to read profile manifest/)
|
||||||
} finally {
|
} finally {
|
||||||
delete process.env.DSH_PNPM
|
delete process.env.DSH_PNPM
|
||||||
rmSync(dir, { recursive: true, force: true })
|
rmSync(dir, { recursive: true, force: true })
|
||||||
|
|||||||
Reference in New Issue
Block a user