Harden external plugin install-bundle dependency resolution #211

Closed
opened 2026-06-01 22:44:34 +00:00 by steve · 0 comments
Owner

First-party external plugin install bundles can require explicit public subpath
modules that are not present in the runtime dependency registry. The current
plugin execution host resolves dependency keys by exact match, so valid bundled
plugins can fail during startup with Cannot require ... even when the subpath
is part of an allowed first-party package surface.

Problem

lapis-notebook fails to load from its installed bundle because the bundle
requires @lapis-notes/api/editor/extensions/class-highlighter, while the
runtime dependency registry only registered package roots such as
@lapis-notes/api.

Goal

External first-party plugin install bundles should load from their packaged
artifacts when all bare require(...) entries target explicitly registered
runtime dependencies. Unknown bare modules must still fail loudly.

Scope

  • Register explicit external dependency subpaths used by first-party install
    bundles.
  • Keep PluginManager dependency lookup exact-first and constrained to known
    registered module keys.
  • Add regression coverage that loads each install-bundle artifact through the
    runtime plugin manager path.
  • Add a dependency coverage guard that scans bundle main.js files for bare
    require(...) entries and fails when a requirement is not registered.

Non-goals

  • No broad Node-style package export walking.
  • No implicit fallback for arbitrary bare specifiers.
  • No change to unknown-module failure behavior.

Acceptance Criteria

  • lapis-notebook can load from /.obsidian/plugins/lapis-notebook without a
    Cannot require @lapis-notes/api/editor/extensions/class-highlighter error.
  • First-party external plugin install bundles have parameterized load tests that
    seed manifest and dist artifacts into /.obsidian/plugins/<id>/, enable the
    plugin, and assert it loads without module evaluation failures.
  • A negative test proves an unknown bare module still throws Cannot require.
  • A coverage guard scans install-bundle dist/main.js files and fails when a
    bare dependency is absent from the registered dependency registry.
  • API/workspace package checks covering the touched code pass before handoff.

Implementation Notes

  • Prefer explicit dependency registration in packages/workspace/src/lib/deps.ts
    over heuristic resolution.
  • Keep packages/api/src/lib/plugin-manager.ts lookup exact-first. Any fallback
    should only return modules that are already explicit keys in the registered
    dependency map.
  • Tests should exercise install-bundle artifacts, including main files and
    related chunk files copied from each plugin dist/ directory.

Suggested Files or Specs To Inspect

  • packages/workspace/src/lib/deps.ts
  • packages/api/src/lib/plugin-manager.ts
  • packages/api/src/lib/__tests__/plugin-manager.test.ts
  • spec/src/30-cross-package-contracts/plugin-system/design.md
  • spec/src/20-packages/plugins/index.md

Validation Commands

  • pnpm --filter @lapis-notes/api test -- src/lib/__tests__/plugin-manager.test.ts
  • pnpm --filter @lapis-notes/api check:all
  • pnpm --filter @lapis-notes/workspace check:all
  • pnpm test:smoke if runtime boot behavior needs full smoke coverage.

Follow-up Tasks

Implementation Summary

Added tracked ambient declarations for install-bundle dependency-map modules lacking package typings so API and workspace type checks pass.

Reopen Reason

Fix type-check regressions from install-bundle dependency registration.

First-party external plugin install bundles can require explicit public subpath modules that are not present in the runtime dependency registry. The current plugin execution host resolves dependency keys by exact match, so valid bundled plugins can fail during startup with `Cannot require ...` even when the subpath is part of an allowed first-party package surface. ## Problem `lapis-notebook` fails to load from its installed bundle because the bundle requires `@lapis-notes/api/editor/extensions/class-highlighter`, while the runtime dependency registry only registered package roots such as `@lapis-notes/api`. ## Goal External first-party plugin install bundles should load from their packaged artifacts when all bare `require(...)` entries target explicitly registered runtime dependencies. Unknown bare modules must still fail loudly. ## Scope - Register explicit external dependency subpaths used by first-party install bundles. - Keep `PluginManager` dependency lookup exact-first and constrained to known registered module keys. - Add regression coverage that loads each install-bundle artifact through the runtime plugin manager path. - Add a dependency coverage guard that scans bundle `main.js` files for bare `require(...)` entries and fails when a requirement is not registered. ## Non-goals - No broad Node-style package export walking. - No implicit fallback for arbitrary bare specifiers. - No change to unknown-module failure behavior. ## Acceptance Criteria - `lapis-notebook` can load from `/.obsidian/plugins/lapis-notebook` without a `Cannot require @lapis-notes/api/editor/extensions/class-highlighter` error. - First-party external plugin install bundles have parameterized load tests that seed manifest and dist artifacts into `/.obsidian/plugins/<id>/`, enable the plugin, and assert it loads without module evaluation failures. - A negative test proves an unknown bare module still throws `Cannot require`. - A coverage guard scans install-bundle `dist/main.js` files and fails when a bare dependency is absent from the registered dependency registry. - API/workspace package checks covering the touched code pass before handoff. ## Implementation Notes - Prefer explicit dependency registration in `packages/workspace/src/lib/deps.ts` over heuristic resolution. - Keep `packages/api/src/lib/plugin-manager.ts` lookup exact-first. Any fallback should only return modules that are already explicit keys in the registered dependency map. - Tests should exercise install-bundle artifacts, including main files and related chunk files copied from each plugin `dist/` directory. ## Suggested Files or Specs To Inspect - `packages/workspace/src/lib/deps.ts` - `packages/api/src/lib/plugin-manager.ts` - `packages/api/src/lib/__tests__/plugin-manager.test.ts` - `spec/src/30-cross-package-contracts/plugin-system/design.md` - `spec/src/20-packages/plugins/index.md` ## Validation Commands - `pnpm --filter @lapis-notes/api test -- src/lib/__tests__/plugin-manager.test.ts` - `pnpm --filter @lapis-notes/api check:all` - `pnpm --filter @lapis-notes/workspace check:all` - `pnpm test:smoke` if runtime boot behavior needs full smoke coverage. ## Related Issues - Follow-up to #185 — [Migrate remaining installable first-party plugins to the official registry](../open/185-migrate-remaining-installable-first-party-plugins-to-the-official-registry.md) ## Follow-up Tasks ## Implementation Summary Added tracked ambient declarations for install-bundle dependency-map modules lacking package typings so API and workspace type checks pass. ## Reopen Reason Fix type-check regressions from install-bundle dependency registration. <!-- backlog:task_id=TASK-PLUGIN-INSTALL-BUNDLE-DEPS source_spec=spec/src/30-cross-package-contracts/plugin-system/design.md related_issue=185 -->
steve added this to the Full Registry V1 milestone 2026-06-01 22:44:34 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lapis-notes/lapis#211
No description provided.