Repository navigation
Frontend: one public entry point (public-api) with an exports map for extensions #886
Copy link
Copy link
Closed
Copy link
Labels
enhancementNew feature or requestNew feature or requestfrontendFrontend (React/TypeScript)Frontend (React/TypeScript)
Milestone
Description
Goal
The frontend has one public entry point for extensions and embedding apps: src/public-api.ts, reachable by package name (smart-ssh/public-api) through an exports map. Everything an extension may use is exported there; internal module paths are no longer part of the contract, so renaming an internal file does not break anyone outside this repository.
Context
apps/smart-ssh-community/frontend/package.json(namesmart-ssh) has noexportsmap. Code outside the frontend that builds on it can only import internal files by relative path (…/frontend/src/api,…/src/components/ui, …).- Items such code needs today, by module:
extensions(registry functions,useEntitlements,publishFeatureLocked,FeatureLockedDialog,ModalBackdrop, types) –src/extensions/index.tsextensions/entitlements(Entitlements,Feature,Tier,FeatureLockedPayload)api(commandErrorMessage,commandErrorCode,commandErrorFeatureLocked,listServers,getStartupState) – the centralinvokewrapperapi.ts:95-106(reportsfeature_lockedto the dialog bus) is not exported, so callers use the rawinvokeand lose the locked-feature dialogcomponents/ui(Button,Field,FIELD_CONTROL_CLASS, …),ErrorBoundary(Frontend: isolate every extension contribution and the app root with an error boundary #880)technicalInputProps(TECHNICAL_INPUT_PROPS),hooks/useIsNarrow,resolveSectionLabel,fileDialog(pickAndReadTextFile),languages(SUPPORTED_LANGUAGES),i18n(settingsStore,initI18n),types(DTO types such asAiProviderConfigDto,ChatSessionSummaryDto,StartupStateDto)bootstrap(Frontend: move the start sequence into an exported bootstrap() for embedding apps #882)- in tests:
test/matchMedia(installMatchMediaMock,setWide)
- The reactive registry functions come from Extension registry: make document actions and first-run notice extensions reactive #884.
Requirements
- New
src/public-api.ts: a header doc comment (English) saying this is the only supported import surface for extensions and embedding apps, with the stability rule (exports change only with a changelog entry and a spec update). It re-exports:- everything exported by
src/extensions/index.ts - entitlement types from
extensions/entitlements bootstrapandBootstrapOptionsErrorBoundaryand thecomponents/uibuilding blocks exported bycomponents/ui/index.tsinvokeCommand<T>(cmd, args?)– the central wrapper fromapi.ts:95-106, exported under this name (same behaviour: reportsfeature_lockedto the dialog bus, rethrows unchanged)commandErrorMessage,commandErrorCode,commandErrorFeatureLocked,commandErrorConnectLog,listServers,getStartupStateTECHNICAL_INPUT_PROPS,useIsNarrow,resolveSectionLabel,pickAndReadTextFile,SUPPORTED_LANGUAGES,settingsStore,initI18n- the DTO types listed under Context (type-only exports)
- everything exported by
- New
src/test-support.tsre-exporting the test helpersinstallMatchMediaMock,setWide(and nothing used by production code). package.jsongets anexportsmap with exactly"./public-api": "./src/public-api.ts"and"./test-support": "./src/test-support.ts"; the app's own build, dev server, vitest and Playwright keep working (they do not import by package name).- A vitest guard
src/publicApi.test.tsasserts that every name in an explicit list (the list above) is exported bypublic-apiwith the expected kind (function/component/object), so removing or renaming an export fails the test. - Spec 0038 section 4 lists
smart-ssh/public-apias the supported surface and states that relative imports of internal files are not supported.
Acceptance Criteria
-
src/public-api.tsandsrc/test-support.tsexist with the exports above. -
invokeCommandbehaves like the internal wrapper: test that a rejected call withfeature_lockedpublishes on the feature-locked bus and rethrows the same error object; a rejection without it publishes nothing. -
package.jsonexportscontains exactly the two entries;npm run build,npm test,npm run test:e2epass. - A small fixture in the test (
import … from "smart-ssh/public-api"resolved through the workspace, orimport.meta.resolve) proves the package-name import resolves. -
src/publicApi.test.tsfails when one listed export is removed (counter-check documented in the test). - Spec 0038 section 4 updated.
- Relevant automated tests pass (
npm run lint,npm test,tsc -b).
Technical Notes
- Files:
src/public-api.ts,src/test-support.ts,src/publicApi.test.ts(new),src/api.ts(export the wrapper underinvokeCommand, keep the internal name working),package.json,docs/specs/0038-repository-app-shell-ci.md. - Re-export only; do not move code. Keep
extensions/index.tsas it is (public-api builds on it). scripts/check-tauri-commands.mjsscansinvoke("…")call sites; make sure exporting the wrapper does not change what it detects (runnpm run check-commands).
Spec impact: update 0038
Open questions
- none
Related Work
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or requestfrontendFrontend (React/TypeScript)Frontend (React/TypeScript)
Type
Fields
Priority
P2 - Normal
Activity
feat(frontend): public-api entry point with exports map (#886)
smart-ssh-coder commentedon Oct 28, 2026
Implementation ready for review. PR #999. Added src/public-api.ts, src/test-support.ts, invokeCommand export and the package exports map, plus publicApi.test.ts (export list guard, invokeCommand behaviour, package-name resolution) and Spec 0038 section 4 update. Lint, tsc, vitest green locally; CI green on PR #999.
smart-ssh-reviewer commentedon Oct 28, 2026
Review passed – moving on to merge. Approved: public-api and test-support entry points, the exports map, invokeCommand and the Spec 0038 update match the issue. The guard test goes red when an export is removed, and CI is green.
feat(frontend): public-api entry point with exports map (#886) (#999)
smart-ssh-coordinator commentedon Oct 28, 2026
Merged and branch deleted: PR #999 (squash) in develop