Stop SDK chunks from importing private @executor-js/api#755
Merged
Conversation
Each plugin's `src/sdk/plugin.ts` was reaching into `../api/group` and
`../api/handlers` to fill the optional `routes`/`handlers`/
`extensionService` fields. tsup followed those imports into the
published SDK chunk, which carried `import { InternalError } from
"@executor-js/api"` and `import { addGroup, capture } from
"@executor-js/api"`. Because `@executor-js/api` is `private: true`,
plain ESM consumers hit `Cannot find package '@executor-js/api'` on
`import("@executor-js/plugin-mcp/core")` (and graphql / openapi).
Changes:
- Move `InternalError` (the wire-level 500 schema) to
`@executor-js/sdk/core`. `@executor-js/api/observability.ts`
re-exports it for back-compat — server code is unaffected.
- Each plugin's `src/api/group.ts` now imports `InternalError` from
`@executor-js/sdk/core` instead of `@executor-js/api`.
- Each plugin's `src/sdk/plugin.ts` no longer imports `../api/*` and
no longer sets `routes`/`handlers`/`extensionService` on the
returned plugin.
- New `*HttpPlugin` factories on the `/api` subpath wrap the SDK
factory and add the HTTP fields. Hosts that mount HTTP routes
switch to the `/api` subpath and the new factory name
(`mcpHttpPlugin`, `graphqlHttpPlugin`, `openApiHttpPlugin`,
`onepasswordHttpPlugin`, `googleDiscoveryHttpPlugin`).
- Apps cloud / local / marketing updated to use the `*HttpPlugin`
factories from `/api`.
- `@executor-js/api` demoted from `dependencies` to devDep + optional
peerDep on `plugin-onepassword` and `plugin-google-discovery`,
matching the other plugins.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-marketing | c3ce5a0 | Commit Preview URL Branch Preview URL |
May 11 2026, 05:36 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-cloud | c3ce5a0 | May 11 2026, 05:36 AM |
@executor-js/cli
@executor-js/config
@executor-js/execution
@executor-js/sdk
@executor-js/storage-core
@executor-js/codemode-core
@executor-js/runtime-quickjs
@executor-js/plugin-file-secrets
@executor-js/plugin-google-discovery
@executor-js/plugin-graphql
@executor-js/plugin-keychain
@executor-js/plugin-mcp
@executor-js/plugin-onepassword
@executor-js/plugin-openapi
executor
commit: |
Catches the regression class where a published `@executor-js/*` bundle transitively imports a private workspace package (e.g. the `@executor-js/api` leak this branch fixes). Runs as a release-gate step before `release:publish:packages`, so a broken bundle blocks publish. How it works: - Reuses `publish-packages.ts --dry-run` to pack every public package with `publishConfig.exports` and `workspace:*` rewrites applied. - For each tarball, installs into a fresh temp dir with npm `overrides` pointing every other `@executor-js/*` transitive dep at its local tarball — without that, npm pulls the currently-published registry version of `@executor-js/sdk` etc. and masks any unreleased-symbol drift. - Reads the installed manifest (post-`publishConfig`) and dynamically `import()`s every subpath in its `exports` map. - Hard-fails on any `Cannot find package '@executor-js/*'`. Other resolution failures (missing `react`, `effect`, `@effect/vitest`, etc.) are logged as `skip` since they reflect a missing peer in the smoke env, not a bug in the bundle. `publish-packages.ts` reordered so pack always happens (was skipped when the version was already on npm). The "already published" check now only short-circuits the `npm publish` step, so smoke tests and pkg-pr-new previews always have a fresh tarball to work with. Wired up: - `bun run release:smoke:packages` — invoke locally. - `release.yml` runs it before `release:publish:packages`. Reverse-verified by temporarily restoring the pre-fix mcp files — script reports `FAIL @executor-js/plugin-mcp — references private '@executor-js/api'` and exits 1.
RhysSullivan
added a commit
that referenced
this pull request
May 31, 2026
* Stop SDK chunks from importing private @executor-js/api
Each plugin's `src/sdk/plugin.ts` was reaching into `../api/group` and
`../api/handlers` to fill the optional `routes`/`handlers`/
`extensionService` fields. tsup followed those imports into the
published SDK chunk, which carried `import { InternalError } from
"@executor-js/api"` and `import { addGroup, capture } from
"@executor-js/api"`. Because `@executor-js/api` is `private: true`,
plain ESM consumers hit `Cannot find package '@executor-js/api'` on
`import("@executor-js/plugin-mcp/core")` (and graphql / openapi).
Changes:
- Move `InternalError` (the wire-level 500 schema) to
`@executor-js/sdk/core`. `@executor-js/api/observability.ts`
re-exports it for back-compat — server code is unaffected.
- Each plugin's `src/api/group.ts` now imports `InternalError` from
`@executor-js/sdk/core` instead of `@executor-js/api`.
- Each plugin's `src/sdk/plugin.ts` no longer imports `../api/*` and
no longer sets `routes`/`handlers`/`extensionService` on the
returned plugin.
- New `*HttpPlugin` factories on the `/api` subpath wrap the SDK
factory and add the HTTP fields. Hosts that mount HTTP routes
switch to the `/api` subpath and the new factory name
(`mcpHttpPlugin`, `graphqlHttpPlugin`, `openApiHttpPlugin`,
`onepasswordHttpPlugin`, `googleDiscoveryHttpPlugin`).
- Apps cloud / local / marketing updated to use the `*HttpPlugin`
factories from `/api`.
- `@executor-js/api` demoted from `dependencies` to devDep + optional
peerDep on `plugin-onepassword` and `plugin-google-discovery`,
matching the other plugins.
* Add pack-and-import smoke test for public library packages
Catches the regression class where a published `@executor-js/*` bundle
transitively imports a private workspace package (e.g. the
`@executor-js/api` leak this branch fixes). Runs as a release-gate
step before `release:publish:packages`, so a broken bundle blocks
publish.
How it works:
- Reuses `publish-packages.ts --dry-run` to pack every public
package with `publishConfig.exports` and `workspace:*` rewrites
applied.
- For each tarball, installs into a fresh temp dir with npm
`overrides` pointing every other `@executor-js/*` transitive dep at
its local tarball — without that, npm pulls the currently-published
registry version of `@executor-js/sdk` etc. and masks any
unreleased-symbol drift.
- Reads the installed manifest (post-`publishConfig`) and dynamically
`import()`s every subpath in its `exports` map.
- Hard-fails on any `Cannot find package '@executor-js/*'`. Other
resolution failures (missing `react`, `effect`, `@effect/vitest`,
etc.) are logged as `skip` since they reflect a missing peer in the
smoke env, not a bug in the bundle.
`publish-packages.ts` reordered so pack always happens (was skipped
when the version was already on npm). The "already published" check
now only short-circuits the `npm publish` step, so smoke tests and
pkg-pr-new previews always have a fresh tarball to work with.
Wired up:
- `bun run release:smoke:packages` — invoke locally.
- `release.yml` runs it before `release:publish:packages`.
Reverse-verified by temporarily restoring the pre-fix mcp files —
script reports `FAIL @executor-js/plugin-mcp — references private
'@executor-js/api'` and exits 1.
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
The published plugin bundles (
@executor-js/plugin-mcp,-graphql,-openapi, etc.) carryimport { InternalError } from "@executor-js/api"(andaddGroup/capture) inside their SDK chunks. Because@executor-js/apiisprivate: trueand isn't on npm, plain Node ESM consumers fail withCannot find package '@executor-js/api'onimport("@executor-js/plugin-mcp/core")(same for graphql / openapi).Reproduced in a fresh
/tmpdir against the live npm package; the dist files now have zero@executor-js/apistrings after this change.Fix
InternalError(a 10-lineSchema.TaggedErrorClassfor the wire-level 500) into@executor-js/sdk/core.@executor-js/api/observability.tsre-exports it for back-compat — server code is unaffected.src/api/group.tsimportsInternalErrorfrom@executor-js/sdk/coreinstead of the private package.src/sdk/plugin.tsno longer reaches sideways into../api/*and no longer sets the optionalroutes/handlers/extensionServicefields. Those are layered on by a new HTTP-augmented variant on the/apisubpath.import { mcpHttpPlugin } from "@executor-js/plugin-mcp/api"(andgraphqlHttpPlugin,openApiHttpPlugin,onepasswordHttpPlugin,googleDiscoveryHttpPlugin). Apps cloud / local / marketing updated.@executor-js/apidemoted fromdependenciesto devDep + optional peerDep onplugin-onepasswordandplugin-google-discovery, matching the other plugins.Net result:
Breaking change
Any host code that read
mcpPlugin(opts).routes/.handlers/.extensionServicedirectly off the SDK factory's return value must switch to the*HttpPluginfactory from@executor-js/plugin-*/api. Every host in this repo was updated; out-of-tree callers that compose plugins by hand need the same import switch.Changeset bumps the fixed group as
minor(pre-1.0).Test plan
bun run typecheck— 33/33 passbun run lint— 0 warnings, 0 errorsbun run format:check— cleanbun run test— only pre-existing failure (returns 401 for malformed bearer tokensincloud/mcp-miniflare.e2e.node.test.ts) reproduces onmainwithout these changesdist/*.jsfiles: zero@executor-js/apireferences afterbun run build