[loader] Add Electron plugin asset protocol #218

Closed
opened 2026-06-02 09:43:33 +00:00 by steve · 0 comments
Owner

Problem

Electron renderer ESM plugin modules need a secure URL space for installed plugin files, including relative ESM imports, without exposing arbitrary filesystem or vault content.

Goal

Serve installed plugin assets to the Electron renderer through a narrow secure lapis-plugin:// protocol.

Scope

  • Register lapis-plugin as a privileged, standard, secure, fetch-capable protocol before app.ready.
  • Add protocol handling for lapis-plugin://[vault-id]/[plugin-id]/[version-or-hash]/[path].
  • Validate active vault mapping, plugin ID, version or hash, path, file type, and installed metadata.
  • Serve verified plugin files with correct MIME types.
  • Add tests for nested ESM relative imports and path traversal rejection.

Non-goals

  • Do not expose arbitrary host files through the protocol.
  • Do not implement Node ESM sidecar loading in this issue.
  • Do not expose renderer host wrapper modules through a broad file protocol.

Acceptance Criteria

  • Electron renderer can import lapis-plugin://.../main.mjs.
  • Relative ESM imports resolve from the same plugin URL space.
  • The protocol cannot serve arbitrary filesystem or vault user files.
  • Unsafe paths and unsupported file types fail safely.

Implementation Notes

  • Register schemes before app readiness.
  • Attach handlers to the same session used by the renderer window.
  • Keep host module serving separate from plugin asset serving unless a narrow lapis-host:// protocol is explicitly needed.

Active Implementation Plan

  • Register lapis-plugin as a privileged secure fetch-capable Electron scheme alongside lapis-vault-resource.
  • Add a renderer-side PluginAssetServer implementation that verifies installed metadata through the active vault adapter, registers the plugin asset context with Electron main through a typed preload IPC command, and returns versioned lapis-plugin:// URLs.
  • Add main-process protocol handling that resolves only previously registered active vault/plugin/version contexts, checks plugin ID/version/path against the installed metadata, reads from /.obsidian/plugins/<id>/, verifies size and SHA-256, and serves the file with the shared MIME policy.
  • Advertise the capability through the native bridge as plugin-assets so the workspace can distinguish Electron renderer asset support from generic file-resource support.
  • Cover URL registration, traversal rejection, unregistered context rejection, nested relative import paths, and MIME behavior with focused package tests.

Affected Packages and Files

  • packages/api/src/lib/plugin-asset-server.ts
  • packages/api/src/lib/storage/desktop-native.ts
  • packages/api/src/lib/__tests__/plugin-asset-server.test.ts
  • packages/desktop-electron/src/main.ts
  • packages/desktop-electron/src-electron/main.ts
  • packages/desktop-electron/src-electron/preload.ts
  • spec/src/20-packages/desktop-electron/index.md
  • spec/src/30-cross-package-contracts/plugin-runtime.md

Suggested Files or Specs To Inspect

  • spec/src/20-packages/desktop-electron/index.md
  • spec/src/30-cross-package-contracts/plugin-runtime.md
  • spec/src/30-cross-package-contracts/plugin-host-boundary.md
  • packages/desktop-electron/src-electron/
  • packages/api/src/lib/plugin-asset-server.ts

Validation Commands

  • pnpm --filter @lapis-notes/api check:all
  • pnpm --filter @lapis-notes/desktop-electron check:all
  • pnpm check:all

Follow-up Tasks

Implementation Summary

Implemented the Electron lapis-plugin protocol path with renderer-side PluginAssetServer registration, preload capability metadata, main-process context tracking, path/version/hash verification, cleanup on window close, documentation, and validation coverage.

## Problem Electron renderer ESM plugin modules need a secure URL space for installed plugin files, including relative ESM imports, without exposing arbitrary filesystem or vault content. ## Goal Serve installed plugin assets to the Electron renderer through a narrow secure `lapis-plugin://` protocol. ## Scope - Register `lapis-plugin` as a privileged, standard, secure, fetch-capable protocol before `app.ready`. - Add protocol handling for `lapis-plugin://[vault-id]/[plugin-id]/[version-or-hash]/[path]`. - Validate active vault mapping, plugin ID, version or hash, path, file type, and installed metadata. - Serve verified plugin files with correct MIME types. - Add tests for nested ESM relative imports and path traversal rejection. ## Non-goals - Do not expose arbitrary host files through the protocol. - Do not implement Node ESM sidecar loading in this issue. - Do not expose renderer host wrapper modules through a broad file protocol. ## Acceptance Criteria - Electron renderer can import `lapis-plugin://.../main.mjs`. - Relative ESM imports resolve from the same plugin URL space. - The protocol cannot serve arbitrary filesystem or vault user files. - Unsafe paths and unsupported file types fail safely. ## Implementation Notes - Register schemes before app readiness. - Attach handlers to the same session used by the renderer window. - Keep host module serving separate from plugin asset serving unless a narrow `lapis-host://` protocol is explicitly needed. ## Active Implementation Plan - Register `lapis-plugin` as a privileged secure fetch-capable Electron scheme alongside `lapis-vault-resource`. - Add a renderer-side `PluginAssetServer` implementation that verifies installed metadata through the active vault adapter, registers the plugin asset context with Electron main through a typed preload IPC command, and returns versioned `lapis-plugin://` URLs. - Add main-process protocol handling that resolves only previously registered active vault/plugin/version contexts, checks plugin ID/version/path against the installed metadata, reads from `/.obsidian/plugins/<id>/`, verifies size and SHA-256, and serves the file with the shared MIME policy. - Advertise the capability through the native bridge as `plugin-assets` so the workspace can distinguish Electron renderer asset support from generic file-resource support. - Cover URL registration, traversal rejection, unregistered context rejection, nested relative import paths, and MIME behavior with focused package tests. ## Affected Packages and Files - `packages/api/src/lib/plugin-asset-server.ts` - `packages/api/src/lib/storage/desktop-native.ts` - `packages/api/src/lib/__tests__/plugin-asset-server.test.ts` - `packages/desktop-electron/src/main.ts` - `packages/desktop-electron/src-electron/main.ts` - `packages/desktop-electron/src-electron/preload.ts` - `spec/src/20-packages/desktop-electron/index.md` - `spec/src/30-cross-package-contracts/plugin-runtime.md` ## Suggested Files or Specs To Inspect - `spec/src/20-packages/desktop-electron/index.md` - `spec/src/30-cross-package-contracts/plugin-runtime.md` - `spec/src/30-cross-package-contracts/plugin-host-boundary.md` - `packages/desktop-electron/src-electron/` - `packages/api/src/lib/plugin-asset-server.ts` ## Validation Commands - `pnpm --filter @lapis-notes/api check:all` - `pnpm --filter @lapis-notes/desktop-electron check:all` - `pnpm check:all` ## Related Issues ## Follow-up Tasks ## Implementation Summary Implemented the Electron lapis-plugin protocol path with renderer-side PluginAssetServer registration, preload capability metadata, main-process context tracking, path/version/hash verification, cleanup on window close, documentation, and validation coverage. <!-- backlog:task_id=TASK-PLUGIN-LOADER-006 source_spec=spec/src/30-cross-package-contracts/plugin-runtime.md -->
Sign in to join this conversation.
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#218
No description provided.