feat(studio): add host.apiBaseUrl and keep axios off the plugin surface - #1270
Merged
Conversation
…t axios Two fixes to the Studio plugin system, both found while building the first plugin that calls its own service. host.apiBaseUrl A plugin that ships its own client had no way to reach the platform. Studio's dev-server `/apis` proxy is opt-in (gated on VITE_PLATFORM_PROXY_DOMAIN and an empty base URL), so a relative `/apis/...` request hits the dev server rather than the platform whenever VITE_PLATFORM_BASE_URL is set. host.sdk covers platform services only, so there was no workaround short of reaching into Studio's internals. @nemo/common plugin surface Anything exported from plugin.ts is bundled into vendor/common.js, which every plugin loads through the import map. Two components reach axios — ErrorPanel via api/common/utils, CancelJobButton via @nemo/sdk/generated/platform/api — and axios resolves to its Node build there, emitting bare imports of crypto, http, https, url, events, stream and zlib. The browser cannot resolve those, so the dynamic import of *every* plugin throws, and loadPlugin swallows it with a logger.warn: the only symptom is a plugin silently not appearing. Neither is exported, and both now carry a comment saying why, since the failure mode gives no hint about the cause. Also adds ControlledTextArea, ENTITY_NAME_HELP and entityNameSchema to the surface — all free of SDK and axios reach. Signed-off-by: mschwab <mschwab@nvidia.com>
The renderer builds it from PLATFORM_BASE_URL, which is optional. Asserting the type catches the undefined case, where every plugin request would be prefixed with the string "undefined". Signed-off-by: mschwab <mschwab@nvidia.com>
Signed-off-by: mschwab <mschwab@nvidia.com>
steramae-nvidia
approved these changes
Aug 12, 2026
Contributor
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughChangesPlugin API updates
Possibly related PRs
Mergeability Score: ⚪ Minimal · up to The PR adds a supported platform base URL for plugins and removes axios-bearing exports that could prevent browser plugin loading. Targeted checks pass, and no actionable merge-blocking risk remains after normal review. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Contributor
|
marcusds
added a commit
that referenced
this pull request
Aug 13, 2026
The host.apiBaseUrl paragraph landed in #1270 without a worked example, because the plugin it describes was not on main yet. Signed-off-by: mschwab <mschwab@nvidia.com>
marcusds
added a commit
that referenced
this pull request
Aug 13, 2026
The host.apiBaseUrl paragraph landed in #1270 without a worked example, because the plugin it describes was not on main yet. Signed-off-by: mschwab <mschwab@nvidia.com>
koralchapnik
pushed a commit
that referenced
this pull request
Aug 13, 2026
The host.apiBaseUrl paragraph landed in #1270 without a worked example, because the plugin it describes was not on main yet. Signed-off-by: mschwab <mschwab@nvidia.com>
15 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two fixes to the Studio plugin system, both found while building the first plugin that calls its own backend service rather than only platform services.
A plugin shipping its own API client previously had no supported way to reach the platform, and two entries on the
@nemo/commonplugin surface silently broke every plugin's bundle.Related Issue
Changes
host.apiBaseUrl— new field on the plugin host handle.host.sdkcovers platform services only. A plugin that ships its own generated client has to build its own URLs, and a relative/apis/...request does not work: Studio's dev-server/apisproxy is opt-in (gated onVITE_PLATFORM_PROXY_DOMAINand an empty base URL,web/packages/studio/vite.config.ts:501), so wheneverVITE_PLATFORM_BASE_URLis set the request hits the Vite dev server instead of the platform. There was no workaround short of reaching into Studio's internals, which the plugin contract forbids.PluginRendererpopulates it fromPLATFORM_BASE_URL, defaulting to''for the same-origin case.Keeping axios off the
@nemo/commonplugin surface.Everything exported from
web/packages/common/src/plugin.tsis bundled intopublic/vendor/common.js, which every plugin resolves through Studio's import map. Two components reach axios —ErrorPanelviaapi/common/utils,CancelJobButtonvia@nemo/sdk/generated/platform/api— and in the vendor build axios resolves to its Node build, socommon.jsemits bare imports ofcrypto,http,https,url,events,streamandzlib.The browser cannot resolve those, so the dynamic
import()of any plugin throws:loadPlugincatches that, logslogger.warnand returnsnull(web/packages/studio/src/plugins/utils.ts), so the only user-visible symptom is a plugin quietly not appearing — no error surface at all. Becausecommon.jsis shared, one bad export breaks every installed plugin, not just the one using it.Neither is exported. Both now carry a comment explaining why, since nothing about the failure points back to the cause.
Surface additions —
ControlledTextArea,ENTITY_NAME_HELP,entityNameSchema. All verified free of any transitive reach to@nemo/sdk's axios-bearing client.Type of Change
Quality Gates
PluginRenderer.test.tsxassertshost.apiBaseUrlis a string — the case that matters isPLATFORM_BASE_URLbeing unset, where every plugin request would otherwise be prefixed with the literal"undefined".plugins/example-plugin/web/AGENTS.mdis the canonical template plugins copy, so it carries the contract change and the rule about prefixing requests.The axios guard is enforced by comment rather than by a test. A lint rule or a build assertion that fails when
vendor/common.jsemits an unmapped bare specifier would be the durable fix; I did not add one here to keep this change small, and it is worth doing separately.Verification
Signed-off-by:traileruv run pre-commit run -apasses, or any blocked checks are identified belowTargeted validation:
pnpm --filter nemo-studio-ui typecheckpnpm --filter @nemo/common typecheckpnpm --filter nemo-studio-ui test src/pluginseslint packages/studio/src/plugins packages/common/src/plugin.tstsc --noEmitinplugins/example-plugin/webuv run pre-commit run -apre-commit run -ais not fully green on my machine:helm-docs— the binary is not installed locally. Touches no file in this change.uv-lock— the hook requires uv0.9.14; this machine has0.9.30. The separateCheck for uv.lock drifthook passes, so the lockfile is in sync; only the version guard fails.uv.lockis untouched by this PR.Every other hook passes, including
ruff,ty, copyright headers,Run UI lint-staged, andPlugins must not import from nmp-common.Manually verified against a running platform that
vendor/common.jsand the other vendor bundles now emit only import-map specifiers, with no unmapped bare imports.Summary by CodeRabbit