Skip to content

Server adapter contract #6

Description

@dvcolomban

Reconciled status, 2026-09-30

Native Devframe/DevTools factories, authenticated remote catalogs, explicit server connections, selected-page handoff, native state and JSON action routing are implemented. Host-ownership and remote authorization tests are in packages/server/tests/ownership.test.ts and remote-client.test.ts. Development, live preview and static snapshots have accepted separate lifetimes in the server packet.

Automatic endpoint discovery beyond the explicit handoff, setup/activation failure coverage, generic transform contracts and complete host/API conformance remain open. Native server view-index composition is now delivered in ef43f0f, with Chromium and Firefox lifecycle acceptance. Remaining renderer work concerns the broader browser/catalog/lifecycle matrix.

Earlier checkpoints below are dated evidence. Their then-pending items are superseded by this status and later accepted resolutions; they do not reopen settled architecture choices.

Accepted two-layer selection amendment, 2026-09-27

The owner chose typed command/results with native state observation, and implementation-owned applicability. Contract migration and authenticated native proof are on main. The architecture diagram and API examples supersede the earlier universal target contract and A1/A2/B mapping questions.

Client selectors choose realm/provider recipients. Selected action/service implementations inspect schema-defined domain/resource input and return their own declared result, such as applied or not-applicable. There is no SDK target envelope, target resolver, accepts hook or new topic/event bus. A not-applicable result is fulfilled; it neither makes the provider unavailable nor triggers fallback/replay. If multiple selected implementations match, all may act.

Provider incarnation, contribution activation generation, exact versions, native authorization/serialization and dispatch ownership remain unchanged. Browser/debugger capabilities still validate actual resources and permissions.

Part of Design a portable contribution SDK and WebExtension runtime.

Current implementation, 2026-09-27: 0c170ec adds the browser-safe native ProviderConnection, authorized catalog query and payload-free invalidations to the existing single-object provider startup and direct strict installation handles. The owner accepted native cancellation: stop local waiting; dispatched backend work may finish; never automatically retry/replay. Native auth, RPC, schema validation, serialization and state remain upstream-owned. dfef733 supplies the runnable browser example on both native hosts. 48 adapter tests, both native examples, 24 Vite-host tests and affected strict checks pass. Full repository CI passed at dfef733: builds, types, strict lint, formatting, packed-consumer checks and tests.

Generic target mapping is no longer a server-adapter prerequisite. Capability inputs and implementations own resource references and applicability. Endpoint discovery, state/renderer/extension integration and full host conformance remain open.

Upstream integration boundary, 2026-09-27

Reuse the existing Devframe/hub/kit contexts and Vite plugins. The implemented createDevframeProvider({ context, ...composition }) and createDevToolsProvider({ context, ...composition }) add owned contributions to those contexts; host construction, authentication, RPC and state retain native APIs. Remote exposure is opt-in adapter work, not a replacement server factory.

See the implementation and map review. This narrows implementation mechanisms without dropping the accepted feature or real-host coverage requirements.

Question

How should devframe and Vite DevTools providers satisfy the common contribution API in development and when serving watched production builds through a live preview backend?

Context and current behavior

The generic SDK will live initially in dvcol/devkit-extension as pnpm/Turbo packages. Server adapters must execute the same build-time contributions used by extension providers, including JSON UI, actions, state, page injection, transforms and native integrations. Their local context can expose underlying devframe/hub objects and Vite primitives where those actually exist.

The inspected devframe branch at a3f967755af99a0a0d8dd82b7b5d4f3dd4aec0bc already provides live HTTP middleware and WS/SSE through initHub and initDevframe. Its Vite hub adapter mounts during configureServer, tears down across restarts, and emits static snapshots during opted-in builds.

At DevTools commit 121656dfc5866b2f8de5baa8e0b6166ec28599c8, server integration also uses configureServer; production output writes backend: 'static'. Neither inspected adapter implements configurePreviewServer. These are branch observations, not assertions about released APIs. Existing live hosting of compiled assets is reusable, while preview attachment and update coordination remain open.

Requirements and scope

  • Define separate devframe-host and DevTools-host adapters that satisfy the common contribution contract and advertise their actual capabilities.
  • Support Vite development HMR and a distinct workflow with build watching, built assets and a live preview backend. Explicitly separate asset build mode from backend lifetime.
  • Specify HTML/head injection, supported HTTP transformation stages, action execution, shared-state access and browser/server communication. Distinguish transforms available only in Vite's source pipeline from HTTP operations available in preview.
  • Expose native devframe/hub context plus optional Vite development or preview primitives locally. A preview server must not masquerade as a full ViteDevServer.
  • Define ownership of connections, middleware, contribution registrations and disposal across starts, restarts and closes. Integrate routing and state contracts without creating adapter-specific alternatives.
  • Isolate endpoint discovery and credentials for simultaneous server connections, including authentication updates and client recreation. An upstream option or another public integration must have a defined consumer distribution strategy; a repository-only patch does not establish external package compatibility.
  • Ship runnable examples for both host adapters, development and watched-build/live-preview modes, with every public server API and hook exercised on real hosts.

Options and recommendation

Reusing the existing static-build path is suitable for snapshots but cannot supply live actions or server state. Keeping a separate permanently running sidecar offers clear ownership but adds ports, discovery and lifecycle coordination. Attaching a live provider to each host's HTTP lifecycle keeps discovery and assets together, while requiring explicit support for both development and preview server interfaces.

The recommendation to evaluate is a reusable live provider backed by devframe/hub, with thin host bindings for standalone devframe, Vite DevTools development and preview. Reuse upstream middleware and transports where audited exports permit it. Same-preview-process HTTP/backend ownership is accepted. Ordinary updates follow Vite and native host lifecycle. Specify middleware ordering and owned cleanup without adding a generic process-recovery controller.

Proposed API or experiment

Use the implemented provider factory inside the native host setup/lifetime. This example receives an actual hub context and imports the maintained shared contribution:

import { createDevframeProvider } from '@devkit/server';
import { counterCapability, increaseCounterAction } from '@devkit/example-contribution';
import { counterService, counterActionsPlugin } from '@devkit/example-server-contexts';

const provider = await createDevframeProvider({
  context: hubContext,
  providerId: 'example.remote',
  services: [counterService],
  plugins: [counterActionsPlugin],
  expose: {
    actions: [increaseCounterAction],
    capabilities: [counterCapability],
  },
});
await provider.invoke({ action: increaseCounterAction, input: { amount: 1 } });
await provider.dispose();

Use createDevToolsProvider with the same options shape and the actual kit context. The native host owns HTTP, RPC authentication and shutdown. expose registers explicit contracts for the host lifetime; unavailable implementations reject calls, and reusing a host requires its original finite method set. Strict startup and late installation return handles directly. Relaxed mode returns admitted/skipped outcomes. Existing local installation does not automatically expose a contract.

The server package documentation defines native method identity and (expectedIncarnation, input) invocation. Operations carry schema-defined input; implementations own resource applicability, freshness and permissions. Native observer failures leave partial registrations unavailable; no rollback is claimed. Authorized remote catalogs are implemented. JSON-view integration and browser capability implementations remain unfinished.

For preview feasibility, start an actual production build watcher and preview server, open a page, invoke an action and update a JSON spec. Rebuild a renderer, then a contribution backend module, then a page script. Observe which layers can update in place and which require disposal, restart, reconnection or reload. Agree the adapter's lifecycle events and restoration responsibilities; broader reload policy must use those events consistently.

Scenarios and acceptance criteria

  • One contribution works in a standalone devframe example and a DevTools-host example with the same JSON UI and action definitions.
  • A real preview page reaches live actions and receives state updates after a production build; generated static metadata cannot silently select the snapshot backend.
  • A server restart replaces old middleware and connections without duplicate registrations, leaked listeners or hanging calls. Recovery restores only state allowed by the common state contract.
  • Injection and transforms run at the documented stage with deterministic ordering. Unsupported preview transformations return the declared capability outcome instead of pretending success.
  • A failed watched build retains or rejects the last usable output according to a settled rule, and clients receive an explicit status. Partial output must not be advertised as a completed update.
  • The API inventory maps every host-binding hook and feature to runnable examples and real development/preview assertions. Extension hosts verify unsupported outcomes for server-only APIs wherever those APIs remain part of the common SDK.

Dependencies

Blocked by Contribution and realm contract using the tracker's native blocking relationship. Its resolved capability, registration and native-context contracts are necessary inputs. The adapter resolution documents handoff points for routing, state recovery and reload coordination; it does not redefine those independent contracts. The parent map contains the named decision pointer after resolution.

Definition of Ready

  • Name the public native registration/lifecycle APIs and demonstrate any missing cleanup behavior before adding adapter methods. See the native lifecycle investigation.

  • Contribution and realm contract is resolved, with server-relevant operations and lifecycle ownership specified.

  • Upstream reuse findings identify permissible public imports and versions for both adapters.

  • The development and watched-production/live-preview requirement is recorded with actual launch commands available for feasibility checks.

Definition of Done

  • Real host tests preserve native authorization and host ownership; adapter disposal releases its additions without shutting down an externally owned host.

  • A user-reviewed resolution specifies both adapter interfaces, host bindings, capability differences, native contexts, transport/discovery behavior and cleanup ownership.

  • Development, preview and snapshot behavior are explicitly separated; restart and asset-update events have defined consumers and restoration responsibilities.

  • Preview feasibility has direct evidence or a precise blocker; source-dev success is not accepted as preview proof.

  • Runnable example applications and complete API/hook test obligations are enumerated, including unsupported, failure and lifecycle cases across supported hosts.

  • Record remaining cross-ticket dependencies, close this decision, and add a named summary link to the map. Production implementation and its complete test execution belong to subsequent work.

  • The human has confirmed the resolution through discussion; the agent has not supplied the human side of the decision.

Resolution record

Post the selected interfaces, host/mode capability table, middleware and transport decisions, lifecycle sequences, feasibility evidence, runnable-example matrix and rejected alternatives as the resolution comment.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

wayfinder:grillingDecision requiring discussion with the project owner

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions