diff --git a/AGENTS.md b/AGENTS.md index 1847c03d..038d6386 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -45,12 +45,13 @@ Ahead-of-time build artifacts that live under `src/` - the shadow-root styleshee - Shared state via `devframe/utils/shared-state`; keep values serializable. - Utility imports use the package-path form `devframe/utils/*`, never relative `../utils/*`. - Dependencies go through the pnpm catalogs in `pnpm-workspace.yaml` (`cli`, `inlined`, `testing`, `types`) - add to a catalog and reference as `catalog:`, don't pin versions in `package.json`. +- **A plugin's default export is its `createDevframe` factory, never a pre-built instance.** Don't write `const xDevframe = createXDevframe(); export default xDevframe` (or the inline `export default createXDevframe()` equivalent) - that eagerly constructs a `DevframeDefinition` the moment the module loads, at import time, whether or not any consumer wants that exact zero-config shape; a host that needs its own options (an id override, a data directory, …) ends up paying for a second, discarded instance alongside the one it actually uses. Alias the factory itself as the default export instead - `export default createXDevframe` - so importing the module costs nothing beyond defining the function, and every consumer calls it (with or without options) to get their own instance: `import createA11yDevframe from '@devframes/plugin-a11y'` then `createA11yDevframe(options)`. ### Framework adapter packages: two scopes, one shape The framework adapter packages - `@devframes/vite`, `@devframes/nuxt`, `@devframes/next` - each split their surface into **two clearly-scoped subpaths**, because a consumer is always doing one of two distinct jobs. Keep all three parallel: -- **`.../dev-spa`** - **build & dev-serve a single devframe's SPA** with that tool (the "I'm authoring one devframe" scope). Vite: the `devframeVitePlugin` / `devframeViteBridge` / `devframeVite` plugins. Next: `withDevframe` + `createDevframeNextHandler`, with its React client at `.../dev-spa/client`. Nuxt: the Nuxt module (registered as `modules: ['@devframes/nuxt/dev-spa']`). +- **`.../single`** - **build & dev-serve a single devframe's SPA** with that tool (the "I'm authoring one devframe" scope). Vite: the `devframeVitePlugin` / `devframeViteBridge` / `devframeVite` plugins. Next: `withDevframe` + `createDevframeNextHandler`, with its React client at `.../single/client`. Nuxt: the Nuxt module (registered as `modules: ['@devframes/nuxt/single']`). - **`.../hub`** - **mount a whole `@devframes/hub` (many integrations) inside that tool** (the "I'm standing up devtools" scope). Wraps `initHub`, defaults the UI slot to `@devframes/hub-ui`'s `createUi()` (overridable via `ui`, or `ui: false` for headless), and ships a browser client helper at `.../hub/client` (a thin, lifecycle-managing wrapper over `@devframes/hub/client`'s `createDevframeClientHost`). `@devframes/hub` and `@devframes/hub-ui` are **optional peers** of these packages; `hub-ui` is loaded lazily (a bundler-ignored dynamic `import()` in the Next hub) so it stays optional and its `import.meta.url` asset lookups resolve at request time. - **The bare root (`.`) throws** a helpful error pointing at the two subpaths - never put real code on it. - **Vite and Nuxt already have native hub viewers** (`@vitejs/devtools-kit`, `@nuxt/devtools`), so `@devframes/vite/hub` and `@devframes/nuxt/hub` still work but emit a one-time `console.warn` recommending those (silence with `{ quiet: true }`). `@devframes/next/hub` has no native counterpart, so it warns nothing. diff --git a/alias.ts b/alias.ts index 5e81c3a5..53913c2b 100644 --- a/alias.ts +++ b/alias.ts @@ -51,16 +51,16 @@ export const alias = { '@devframes/hub': r('hub/src/index.ts'), '@devframes/hub-ui': r('hub-ui/src/index.ts'), '@devframes/nuxt/runtime/plugin.client': r('nuxt/src/runtime/plugin.client.ts'), - '@devframes/nuxt/dev-spa': r('nuxt/src/dev-spa.ts'), + '@devframes/nuxt/single': r('nuxt/src/single.ts'), '@devframes/nuxt/hub/client': r('nuxt/src/hub-client.ts'), '@devframes/nuxt/hub': r('nuxt/src/hub.ts'), '@devframes/nuxt': r('nuxt/src/index.ts'), - '@devframes/next/dev-spa/client': r('next/src/client.tsx'), - '@devframes/next/dev-spa': r('next/src/dev-spa.ts'), + '@devframes/next/single/client': r('next/src/client.tsx'), + '@devframes/next/single': r('next/src/single.ts'), '@devframes/next/hub/client': r('next/src/hub-client.tsx'), '@devframes/next/hub': r('next/src/hub.ts'), '@devframes/next': r('next/src/index.ts'), - '@devframes/vite/dev-spa': r('vite/src/dev-spa.ts'), + '@devframes/vite/single': r('vite/src/single.ts'), '@devframes/vite/hub/client': r('vite/src/hub-client.ts'), '@devframes/vite/hub': r('vite/src/hub.ts'), '@devframes/vite': r('vite/src/index.ts'), diff --git a/docs/frameworks/index.md b/docs/frameworks/index.md index 65ea37b9..906aefff 100644 --- a/docs/frameworks/index.md +++ b/docs/frameworks/index.md @@ -8,20 +8,20 @@ The framework packages — [`@devframes/vite`](./vite), [`@devframes/nuxt`](./nu | Scope | Subpath | You are… | |-------|---------|----------| -| **dev-spa** | `.../dev-spa` | building & dev-serving a **single devframe's SPA** with that tool | +| **single** | `.../single` | building & dev-serving a **single devframe's SPA** with that tool | | **hub** | `.../hub` | mounting a whole **[devframes-hub](/guide/hub)** (many integrations) inside that tool | The bare package root (`@devframes/vite`, `@devframes/nuxt`, `@devframes/next`) has no export — it throws with a pointer to the two subpaths, so an accidental bare import fails loudly instead of resolving to nothing. -| Package | dev-spa | hub | -|---------|---------|-----| +| Package | single | hub | +|---------|--------|-----| | [`@devframes/vite`](./vite) | `devframeVitePlugin` / `devframeViteBridge` / `devframeVite` | `viteDevframeHub` (+ `/hub/client`) | -| [`@devframes/nuxt`](./nuxt) | the Nuxt module (`modules: ['@devframes/nuxt/dev-spa']`) | the hub Nuxt module (+ `/hub/client`) | -| [`@devframes/next`](./next) | `withDevframe` + `createDevframeNextHandler` (+ `/dev-spa/client`) | `nextDevframeHub` (+ `/hub/client`) | +| [`@devframes/nuxt`](./nuxt) | the Nuxt module (`modules: ['@devframes/nuxt/single']`) | the hub Nuxt module (+ `/hub/client`) | +| [`@devframes/next`](./next) | `withDevframe` + `createDevframeNextHandler` (+ `/single/client`) | `nextDevframeHub` (+ `/hub/client`) | -## dev-spa: author one devframe +## single: author one devframe -The `dev-spa` scope is for when the thing you're building **is** a devframe — you author its UI with Vite/Nuxt/Next and want its RPC backend running during development. See each package's page for the details; for the framework-neutral CLI/build/embedded outputs, reach for the [adapters](/adapters/) instead. +The `single` scope is for when the thing you're building **is** a devframe — you author its UI with Vite/Nuxt/Next and want its RPC backend running during development. See each package's page for the details; for the framework-neutral CLI/build/embedded outputs, reach for the [adapters](/adapters/) instead. ## hub: mount a devframes-hub diff --git a/docs/frameworks/next.md b/docs/frameworks/next.md index 445f158c..29ed09fa 100644 --- a/docs/frameworks/next.md +++ b/docs/frameworks/next.md @@ -9,19 +9,19 @@ outline: deep `@devframes/next` hosts devframes from a Next.js App Router app. Next runs on webpack/Turbopack rather than Vite, so it hosts through a route handler instead of the [Vite](./vite): the package serves each devframe's SPA and its `__connection.json` from a single `fetch` handler your catch-all route delegates to, reusing devframe's own [`serveStaticHandler`](/adapters/dev) for SPA fallback, content types, and path-traversal guarding. -`@devframes/next` splits into two scopes: `@devframes/next/dev-spa` (author one devframe with Next) and [`@devframes/next/hub`](#mounting-a-hub) (mount a whole devframes-hub). The bare `@devframes/next` import throws with a pointer to both. +`@devframes/next` splits into two scopes: `@devframes/next/single` (author one devframe with Next) and [`@devframes/next/hub`](#mounting-a-hub) (mount a whole devframes-hub). The bare `@devframes/next` import throws with a pointer to both. -The `dev-spa` scope comes in two parts: +The `single` scope comes in two parts: 1. **`withDevframe()`** — applies the one Next config setting a devframe host needs. 2. **`createDevframeNextHandler()`** — hosts a single devframe (the common case). -Plus a React client surface at `@devframes/next/dev-spa/client`. +Plus a React client surface at `@devframes/next/single/client`. ## Config ```ts [next.config.mjs] -import { withDevframe } from '@devframes/next/dev-spa' +import { withDevframe } from '@devframes/next/single' export default withDevframe({ // ...your own Next config @@ -35,7 +35,7 @@ export default withDevframe({ `createDevframeNextHandler(definition)` statically serves the devframe's built SPA and starts a side-car RPC/WebSocket server, advertising it at `/__connection.json`. Delegate your catch-all route to its `fetch`: ```ts [app/__my-tool/[[...path]]/route.ts] -import { createDevframeNextHandler } from '@devframes/next/dev-spa' +import { createDevframeNextHandler } from '@devframes/next/single' import myDevframe from '@/devframe' export const runtime = 'nodejs' @@ -88,11 +88,11 @@ export async function GET(request: Request): Promise { ## React client -`@devframes/next/dev-spa/client` connects to the RPC backend and provides the client to your component tree — the React counterpart to `@devframes/nuxt`'s `$rpc` plugin. Children render immediately, so your shell and a connection indicator stay visible while the client connects. +`@devframes/next/single/client` connects to the RPC backend and provides the client to your component tree — the React counterpart to `@devframes/nuxt`'s `$rpc` plugin. Children render immediately, so your shell and a connection indicator stay visible while the client connects. ```tsx [app/providers.tsx] 'use client' -import { RpcProvider } from '@devframes/next/dev-spa/client' +import { RpcProvider } from '@devframes/next/single/client' export function Providers({ children }: { children: React.ReactNode }) { return {children} @@ -103,7 +103,7 @@ export function Providers({ children }: { children: React.ReactNode }) { ```tsx [app/panel.tsx] 'use client' -import { useRpc, useRpcStatus } from '@devframes/next/dev-spa/client' +import { useRpc, useRpcStatus } from '@devframes/next/single/client' export function Panel() { const rpc = useRpc()?.scope('my-tool:') diff --git a/docs/frameworks/nuxt.md b/docs/frameworks/nuxt.md index ffd6a605..7d606a1c 100644 --- a/docs/frameworks/nuxt.md +++ b/docs/frameworks/nuxt.md @@ -4,9 +4,9 @@ outline: deep # Nuxt -The `@devframes/nuxt/dev-spa` module wires a Nuxt-built SPA as a devframe client, and optionally serves the dev-time RPC bridge alongside `nuxt dev`. It runs inside the Nuxt app that consumes your devframe. +The `@devframes/nuxt/single` module wires a Nuxt-built SPA as a devframe client, and optionally serves the dev-time RPC bridge alongside `nuxt dev`. It runs inside the Nuxt app that consumes your devframe. -`@devframes/nuxt` splits into two scopes: `@devframes/nuxt/dev-spa` (this page — author one devframe with Nuxt) and [`@devframes/nuxt/hub`](#mounting-a-hub) (mount a whole devframes-hub). The bare `@devframes/nuxt` import throws with a pointer to both. +`@devframes/nuxt` splits into two scopes: `@devframes/nuxt/single` (this page — author one devframe with Nuxt) and [`@devframes/nuxt/hub`](#mounting-a-hub) (mount a whole devframes-hub). The bare `@devframes/nuxt` import throws with a pointer to both. It handles the four things every Nuxt-powered standalone devtool needs: @@ -19,7 +19,7 @@ It handles the four things every Nuxt-powered standalone devtool needs: ```ts [nuxt.config.ts] export default defineNuxtConfig({ - modules: ['@devframes/nuxt/dev-spa'], + modules: ['@devframes/nuxt/single'], }) ``` @@ -47,7 +47,7 @@ export function usePayload() { ```ts [nuxt.config.ts] export default defineNuxtConfig({ - modules: ['@devframes/nuxt/dev-spa'], + modules: ['@devframes/nuxt/single'], devframe: { baseURL: './', // where the devframe snapshot lives, relative to the page skipAppDefaults: false, // opt out of the app.baseURL / vite.base defaults @@ -66,7 +66,7 @@ Pass your devframe definition to wire `nuxt dev` up to the RPC backend: import devframe from './src/devframe' // defineDevframe(...) export export default defineNuxtConfig({ - modules: [['@devframes/nuxt/dev-spa', { devframe }]], + modules: [['@devframes/nuxt/single', { devframe }]], }) ``` @@ -83,7 +83,7 @@ The bridge is **on by default** whenever `devframe` is set. Skip it (back to cli ```ts [nuxt.config.ts] export default defineNuxtConfig({ - modules: [['@devframes/nuxt/dev-spa', { + modules: [['@devframes/nuxt/single', { devframe, devMiddleware: { port: 7777, diff --git a/docs/frameworks/vite.md b/docs/frameworks/vite.md index a346beb3..980c1eac 100644 --- a/docs/frameworks/vite.md +++ b/docs/frameworks/vite.md @@ -4,14 +4,14 @@ outline: deep # Vite -`@devframes/vite` splits into two scopes: **`@devframes/vite/dev-spa`** (this page — dev-serve one devframe's SPA with Vite) and [**`@devframes/vite/hub`**](#mounting-a-hub) (mount a whole devframes-hub inside a Vite app). The bare `@devframes/vite` import throws with a pointer to both. +`@devframes/vite` splits into two scopes: **`@devframes/vite/single`** (this page — dev-serve one devframe's SPA with Vite) and [**`@devframes/vite/hub`**](#mounting-a-hub) (mount a whole devframes-hub inside a Vite app). The bare `@devframes/vite` import throws with a pointer to both. -The `dev-spa` scope exports two Vite plugins for mounting a single devframe inside an existing Vite dev server — `devframeVitePlugin` (static mount) and `devframeViteBridge` (RPC bridge) — plus `devframeVite`, a convenience wrapper that picks between them. Used by [`@devframes/nuxt`](./nuxt) and available for any Vite-based host (Astro, SolidStart, plain Vite apps). +The `single` scope exports two Vite plugins for mounting a single devframe inside an existing Vite dev server — `devframeVitePlugin` (static mount) and `devframeViteBridge` (RPC bridge) — plus `devframeVite`, a convenience wrapper that picks between them. Used by [`@devframes/nuxt`](./nuxt) and available for any Vite-based host (Astro, SolidStart, plain Vite apps). This sits below the [`vite` adapter](/adapters/vite) on the abstraction ladder: the adapter targets the full Vite DevTools dock; these are the lower-level Vite plugins you reach for when you want a devframe to ride along with an existing app's dev server without the DevTools dock. ```ts -import { devframeViteBridge, devframeVitePlugin } from '@devframes/vite/dev-spa' +import { devframeViteBridge, devframeVitePlugin } from '@devframes/vite/single' import { defineConfig } from 'vite' import devframe from './devframe' diff --git a/docs/guide/hub.md b/docs/guide/hub.md index 884d8461..dc521284 100644 --- a/docs/guide/hub.md +++ b/docs/guide/hub.md @@ -162,7 +162,9 @@ Dev servers with a module bundler (Next's Turbopack/webpack) statically analyse const pkgs = ['@devframes/plugin-git', '@devframes/plugin-terminals'] const defs = await Promise.all( pkgs.map(p => import(/* webpackIgnore: true */ /* turbopackIgnore: true */ p)), -).then(mods => mods.map(m => m.default)) + // Each package's default export is its `createDevframe` factory, not a + // pre-built instance — call it to get one. +).then(mods => mods.map(m => m.default())) for (const def of defs) await ctx.install(def) diff --git a/docs/guide/migration-0.9.md b/docs/guide/migration-0.9.md index 8de11ec4..62648941 100644 --- a/docs/guide/migration-0.9.md +++ b/docs/guide/migration-0.9.md @@ -33,16 +33,23 @@ Every entry below has a drop-in replacement. At a glance: **Framework adapters (`@devframes/vite` / `@devframes/nuxt` / `@devframes/next`)** -Each splits into two scoped subpaths — `.../dev-spa` (author one devframe's SPA) and `.../hub` (mount a whole `@devframes/hub`) — and the bare package root throws with a pointer to both. +Each splits into two scoped subpaths — `.../single` (author one devframe's SPA) and `.../hub` (mount a whole `@devframes/hub`) — and the bare package root throws with a pointer to both. | Removed / moved | Replacement | |---|---| -| `devframe/helpers/vite` (`viteDevBridge`) | `@devframes/vite/dev-spa` (`devframeVite` / `devframeVitePlugin` / `devframeViteBridge`) | -| `@devframes/nuxt` (bare module) | `@devframes/nuxt/dev-spa` | -| `@devframes/next` root (`withDevframe`, `createDevframeNextHandler`) | `@devframes/next/dev-spa` | -| `@devframes/next/client` | `@devframes/next/dev-spa/client` | +| `devframe/helpers/vite` (`viteDevBridge`) | `@devframes/vite/single` (`devframeVite` / `devframeVitePlugin` / `devframeViteBridge`) | +| `@devframes/nuxt` (bare module) | `@devframes/nuxt/single` | +| `@devframes/next` root (`withDevframe`, `createDevframeNextHandler`) | `@devframes/next/single` | +| `@devframes/next/client` | `@devframes/next/single/client` | | mount a hub inside a tool | `@devframes/{vite,nuxt,next}/hub` (+ `/hub/client`) | +**Built-in plugins** + +| Removed / moved | Replacement | +|---|---| +| `@devframes/plugin-{a11y,assets,data-inspector,inspect,messages,og}/vite` | `devframeVite(def, options)` from `@devframes/vite/single`, against an instance from the plugin's default export | +| default export is a pre-built `DevframeDefinition` | default export is the `createDevframe` factory — call it for an instance | + ## `devframe/adapters/cli` is removed The CLI adapter was renamed to `cac` in 0.7. The `devframe/adapters/cli` entry - `createCli`, `CreateCliOptions`, and `CliHandle` - is now gone. Import from `devframe/adapters/cac` instead: @@ -250,11 +257,11 @@ import { DEFAULT_CATEGORIES_ORDER } from '@devframes/hub/constants' ## The Vite bridge moves to `@devframes/vite` -`devframe/helpers/vite` is now its own package, `@devframes/vite` — so it can depend on `vite` directly (its plugins are typed against Vite's real `Plugin` / `ViteDevServer`) while `devframe` core stays free of a Vite dependency. It also splits into two scoped subpaths, and the single `viteDevBridge` becomes three purpose-named plugins on `@devframes/vite/dev-spa`: +`devframe/helpers/vite` is now its own package, `@devframes/vite` — so it can depend on `vite` directly (its plugins are typed against Vite's real `Plugin` / `ViteDevServer`) while `devframe` core stays free of a Vite dependency. It also splits into two scoped subpaths, and the single `viteDevBridge` becomes three purpose-named plugins on `@devframes/vite/single`: | 0.8.x | 0.9 | |---|---| -| `import { viteDevBridge } from 'devframe/helpers/vite'` | `import { devframeVite } from '@devframes/vite/dev-spa'` | +| `import { viteDevBridge } from 'devframe/helpers/vite'` | `import { devframeVite } from '@devframes/vite/single'` | | `viteDevBridge(def)` (static mount) | `devframeVitePlugin(def)` | | `viteDevBridge(def, { devMiddleware: true })` (RPC bridge) | `devframeViteBridge(def)` | | `viteDevBridge(def, { devMiddleware: { port, host, flags } })` | `devframeViteBridge(def, { port, host, flags })` | @@ -272,7 +279,7 @@ export default defineConfig({ ```ts // 0.9 -import { devframeViteBridge } from '@devframes/vite/dev-spa' +import { devframeViteBridge } from '@devframes/vite/single' export default defineConfig({ plugins: [devframeViteBridge(devframe)], @@ -281,9 +288,65 @@ export default defineConfig({ `@devframes/vite` (and `@devframes/nuxt` / `@devframes/next`) take `@devframes/hub` and `@devframes/hub-ui` as **optional** peers — only the `/hub` scope needs them. Install `vite` as a peer as before. See [`@devframes/vite`](/frameworks/vite) for the full reference. -## `@devframes/nuxt` and `@devframes/next` split into `/dev-spa` and `/hub` +## Built-in plugins' `/vite` subpath is removed + +`a11yVitePlugin`, `assetsVitePlugin`, `dataInspectorVitePlugin`, `inspectVitePlugin`, `messagesVitePlugin`, and `ogVitePlugin` — each plugin's `@devframes/plugin-/vite` export — were one-line renames over `devframeVite(def, options)`. For a Vite app, mount the plugin into [Vite DevTools](https://devtools.vite.dev) instead, with `createPluginFromDevframe` from `@vitejs/devtools-kit/node`: + +```ts +// 0.8.x +import { a11yVitePlugin } from '@devframes/plugin-a11y/vite' + +export default defineConfig({ + plugins: [a11yVitePlugin()], +}) +``` + +```ts +// 0.9 +import createA11yDevframe from '@devframes/plugin-a11y' +import { createPluginFromDevframe } from '@vitejs/devtools-kit/node' + +export default defineConfig({ + plugins: [createPluginFromDevframe(createA11yDevframe())], +}) +``` + +Without Vite DevTools, call `devframeVite` directly against an instance from the plugin's default export instead — the lower-level, DevTools-free path: + +```ts +import createA11yDevframe from '@devframes/plugin-a11y' +import { devframeVite } from '@devframes/vite/single' + +export default defineConfig({ + plugins: [devframeVite(createA11yDevframe())], +}) +``` + +`@devframes/plugin-code-server`'s `codeServerVite` and `@devframes/plugin-terminals`'s `terminalsVite` are unaffected — they mount a bridge and a static plugin together (and build their devframe from the passed options), not a plain `devframeVite` delegation. + +## Built-in plugins' default export is now the factory, not an instance + +Every built-in plugin (`@devframes/plugin-{a11y,assets,code-server,data-inspector,git,inspect,messages,og,terminals}`) used to construct one `DevframeDefinition` at module scope and export that instance as its default export — eagerly, the moment anything imported the package, whether or not that consumer wanted the zero-config shape. The default export is now the `createDevframe` factory itself; call it to get an instance: + +```ts +// 0.8.x +import a11yDevframe from '@devframes/plugin-a11y' + +await ctx.install(a11yDevframe) +``` + +```ts +// 0.9 +import createA11yDevframe from '@devframes/plugin-a11y' + +await ctx.install(createA11yDevframe()) +``` + +The named `createDevframe` export (for passing options) is unchanged. + +## `@devframes/nuxt` and `@devframes/next` split into `/single` and `/hub` -Both packages now serve their single-devframe surface from a `.../dev-spa` subpath, and the bare package root throws with a pointer to the two scopes. +Both packages now serve their single-devframe surface from a `.../single` subpath, and the bare package root throws with a pointer to the two scopes. Nuxt — register the module by its subpath: @@ -292,16 +355,16 @@ Nuxt — register the module by its subpath: export default defineNuxtConfig({ modules: ['@devframes/nuxt'] }) // 0.9 [nuxt.config.ts] -export default defineNuxtConfig({ modules: ['@devframes/nuxt/dev-spa'] }) +export default defineNuxtConfig({ modules: ['@devframes/nuxt/single'] }) ``` Next — the config/handler helpers and the React client move down a level: | 0.8.x | 0.9 | |---|---| -| `import { withDevframe } from '@devframes/next'` | `import { withDevframe } from '@devframes/next/dev-spa'` | -| `import { createDevframeNextHandler } from '@devframes/next'` | `import { createDevframeNextHandler } from '@devframes/next/dev-spa'` | -| `import { RpcProvider, useRpc } from '@devframes/next/client'` | `import { RpcProvider, useRpc } from '@devframes/next/dev-spa/client'` | +| `import { withDevframe } from '@devframes/next'` | `import { withDevframe } from '@devframes/next/single'` | +| `import { createDevframeNextHandler } from '@devframes/next'` | `import { createDevframeNextHandler } from '@devframes/next/single'` | +| `import { RpcProvider, useRpc } from '@devframes/next/client'` | `import { RpcProvider, useRpc } from '@devframes/next/single/client'` | ## Mounting a hub: the new `/hub` scope diff --git a/docs/guide/standalone-cli.md b/docs/guide/standalone-cli.md index 72e42c48..a0253718 100644 --- a/docs/guide/standalone-cli.md +++ b/docs/guide/standalone-cli.md @@ -90,7 +90,7 @@ For the Nuxt side, add the devframe helper module — it sets `app.baseURL: './' ```ts [nuxt.config.ts] export default defineNuxtConfig({ ssr: false, - modules: ['@devframes/nuxt/dev-spa'], + modules: ['@devframes/nuxt/single'], nitro: { preset: 'static', output: { dir: './dist' }, // matches createCac's distDir of ./dist/public diff --git a/docs/plugins/a11y.md b/docs/plugins/a11y.md index 4b82e26a..c8cc78aa 100644 --- a/docs/plugins/a11y.md +++ b/docs/plugins/a11y.md @@ -35,9 +35,9 @@ The agent and panel talk over a same-origin `BroadcastChannel` rather than the R The agent is the a11y dock's [client script](/guide/client-context): attach the exported `a11yAgentBundlePath` as the dock's `clientScript` and the hub's client host imports it into the host page, calling its default export with the client-script context. Booted that way, the agent also mirrors each scan into the hub's messages feed — a summary entry driven through the loading → idle lifecycle, plus one entry per violated rule carrying the impact-mapped level, WCAG tags as labels, and the offending element's selector and bounding box: ```ts -import a11yDevframe, { a11yAgentBundlePath } from '@devframes/plugin-a11y' +import createA11yDevframe, { a11yAgentBundlePath } from '@devframes/plugin-a11y' -await ctx.install(a11yDevframe, { +await ctx.install(createA11yDevframe(), { dock: { clientScript: { importFrom: `/@fs/${a11yAgentBundlePath}` } }, }) ``` @@ -54,14 +54,32 @@ Runs the panel alone, without a host page to scan — serves at `/__devframes_pl ## Mount into a Vite host +For a [Vite DevTools](https://devtools.vite.dev) app, mount the panel with `createPluginFromDevframe` from `@vitejs/devtools-kit/node`: + +```ts +// vite.config.ts +import createA11yDevframe from '@devframes/plugin-a11y' +import { createPluginFromDevframe } from '@vitejs/devtools-kit/node' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [ + createPluginFromDevframe(createA11yDevframe()), + ], +}) +``` + +Without Vite DevTools, `devframeVite` from `@devframes/vite/single` mounts the panel directly, no DevTools dock required: + ```ts // vite.config.ts -import { a11yVitePlugin } from '@devframes/plugin-a11y/vite' +import createA11yDevframe from '@devframes/plugin-a11y' +import { devframeVite } from '@devframes/vite/single' import { defineConfig } from 'vite' export default defineConfig({ plugins: [ - a11yVitePlugin(), + devframeVite(createA11yDevframe()), ], }) ``` diff --git a/docs/plugins/assets.md b/docs/plugins/assets.md index 3cf9d555..831c8e46 100644 --- a/docs/plugins/assets.md +++ b/docs/plugins/assets.md @@ -28,14 +28,32 @@ pnpx @devframes/plugin-assets --read-only # disable upload / rename / delete / m ## Mount into a Vite host +For a [Vite DevTools](https://devtools.vite.dev) app, mount the panel with `createPluginFromDevframe` from `@vitejs/devtools-kit/node`: + +```ts +// vite.config.ts +import createAssetsDevframe from '@devframes/plugin-assets' +import { createPluginFromDevframe } from '@vitejs/devtools-kit/node' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [ + createPluginFromDevframe(createAssetsDevframe()), + ], +}) +``` + +Without Vite DevTools, `devframeVite` from `@devframes/vite/single` mounts the panel directly, no DevTools dock required: + ```ts // vite.config.ts -import { assetsVitePlugin } from '@devframes/plugin-assets/vite' +import createAssetsDevframe from '@devframes/plugin-assets' +import { devframeVite } from '@devframes/vite/single' import { defineConfig } from 'vite' export default defineConfig({ plugins: [ - assetsVitePlugin(), + devframeVite(createAssetsDevframe()), ], }) ``` diff --git a/docs/plugins/data-inspector.md b/docs/plugins/data-inspector.md index ae06d6af..0e58bff7 100644 --- a/docs/plugins/data-inspector.md +++ b/docs/plugins/data-inspector.md @@ -106,15 +106,18 @@ pnpx @devframes/plugin-data-inspector attach # attach to a process ## Mount into a Vite host +For a [Vite DevTools](https://devtools.vite.dev) app, mount the panel with `createPluginFromDevframe` from `@vitejs/devtools-kit/node`: + ```ts +import createDataInspectorDevframe from '@devframes/plugin-data-inspector' import { registerDataSource } from '@devframes/plugin-data-inspector/registry' // vite.config.ts -import { dataInspectorVitePlugin } from '@devframes/plugin-data-inspector/vite' +import { createPluginFromDevframe } from '@vitejs/devtools-kit/node' import { defineConfig } from 'vite' export default defineConfig({ plugins: [ - dataInspectorVitePlugin(), + createPluginFromDevframe(createDataInspectorDevframe()), { name: 'my-app:data-sources', configureServer(server) { @@ -130,7 +133,15 @@ export default defineConfig({ }) ``` -Hub hosts mount the default export like any devframe definition. +Without Vite DevTools, `devframeVite` from `@devframes/vite/single` mounts the panel directly, no DevTools dock required — swap it in for `createPluginFromDevframe` above: + +```ts +import { devframeVite } from '@devframes/vite/single' + +devframeVite(createDataInspectorDevframe()) +``` + +Hub hosts mount an instance from the default export like any devframe definition. ## Programmatic diff --git a/docs/plugins/inspect.md b/docs/plugins/inspect.md index 767f6e8b..e6fdc10d 100644 --- a/docs/plugins/inspect.md +++ b/docs/plugins/inspect.md @@ -42,14 +42,32 @@ Opens the inspector against a fresh standalone devframe connection — handy as ## Mount into a Vite host +For a [Vite DevTools](https://devtools.vite.dev) app, mount the panel with `createPluginFromDevframe` from `@vitejs/devtools-kit/node`: + +```ts +// vite.config.ts +import createInspectDevframe from '@devframes/plugin-inspect' +import { createPluginFromDevframe } from '@vitejs/devtools-kit/node' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [ + createPluginFromDevframe(createInspectDevframe()), + ], +}) +``` + +Without Vite DevTools, `devframeVite` from `@devframes/vite/single` mounts the panel directly, no DevTools dock required: + ```ts // vite.config.ts -import { inspectVitePlugin } from '@devframes/plugin-inspect/vite' +import createInspectDevframe from '@devframes/plugin-inspect' +import { devframeVite } from '@devframes/vite/single' import { defineConfig } from 'vite' export default defineConfig({ plugins: [ - inspectVitePlugin(), + devframeVite(createInspectDevframe()), ], }) ``` diff --git a/docs/plugins/og.md b/docs/plugins/og.md index ae8ab651..d6060e83 100644 --- a/docs/plugins/og.md +++ b/docs/plugins/og.md @@ -22,14 +22,32 @@ pnpx @devframes/plugin-og ## Mount into a Vite host +For a [Vite DevTools](https://devtools.vite.dev) app, mount the panel with `createPluginFromDevframe` from `@vitejs/devtools-kit/node`: + +```ts +// vite.config.ts +import createOgDevframe from '@devframes/plugin-og' +import { createPluginFromDevframe } from '@vitejs/devtools-kit/node' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [ + createPluginFromDevframe(createOgDevframe()), + ], +}) +``` + +Without Vite DevTools, `devframeVite` from `@devframes/vite/single` mounts the panel directly, no DevTools dock required: + ```ts // vite.config.ts -import { ogVitePlugin } from '@devframes/plugin-og/vite' +import createOgDevframe from '@devframes/plugin-og' +import { devframeVite } from '@devframes/vite/single' import { defineConfig } from 'vite' export default defineConfig({ plugins: [ - ogVitePlugin(), + devframeVite(createOgDevframe()), ], }) ``` diff --git a/examples/a11y-messages-playground/vite.config.ts b/examples/a11y-messages-playground/vite.config.ts index 01ec4ba2..07078162 100644 --- a/examples/a11y-messages-playground/vite.config.ts +++ b/examples/a11y-messages-playground/vite.config.ts @@ -1,10 +1,13 @@ -import a11yDevframe, { a11yAgentBundlePath } from '@devframes/plugin-a11y' -import messagesDevframe from '@devframes/plugin-messages' +import createA11yDevframe, { a11yAgentBundlePath } from '@devframes/plugin-a11y' +import createMessagesDevframe from '@devframes/plugin-messages' import UnoCSS from 'unocss/vite' import { defineConfig } from 'vite' import { alias } from '../../alias' import { a11yMessagesPlayground } from './src/a11y-messages-playground' +const a11yDevframe = createA11yDevframe() +const messagesDevframe = createMessagesDevframe() + export default defineConfig({ resolve: { alias }, server: { allowedHosts: true, strictPort: false }, diff --git a/examples/hub-next-minimal/src/client/hub.ts b/examples/hub-next-minimal/src/client/hub.ts index 28b32aeb..57eaa803 100644 --- a/examples/hub-next-minimal/src/client/hub.ts +++ b/examples/hub-next-minimal/src/client/hub.ts @@ -66,7 +66,7 @@ async function loadHub(): Promise { // gets a colon-free id override to be a valid `/` segment; the // assets watcher is off since this host demonstrates mounting, not authoring. const devframes: DevframeDefinition[] = [ - ...builtins.map(mod => mod.default as DevframeDefinition), + ...builtins.map(mod => (mod.default as () => DevframeDefinition)()), (dataInspector.createDataInspectorDevframe as (options: { id: string }) => DevframeDefinition)({ id: 'devframes_plugin_data-inspector' }), (assets.createAssetsDevframe as (options: { watch: boolean }) => DevframeDefinition)({ watch: false }), ] diff --git a/examples/hub-next-minimal/src/client/next.config.mjs b/examples/hub-next-minimal/src/client/next.config.mjs index 9a406e4a..36a0fb97 100644 --- a/examples/hub-next-minimal/src/client/next.config.mjs +++ b/examples/hub-next-minimal/src/client/next.config.mjs @@ -1,4 +1,4 @@ -import { withDevframe } from '@devframes/next/dev-spa' +import { withDevframe } from '@devframes/next/single' // `withDevframe` applies the settings a devframe host requires (currently // `skipTrailingSlashRedirect: true`, so mounted SPAs' relative assets under diff --git a/examples/hub-next/src/client/devframe/next-devframe-hub.ts b/examples/hub-next/src/client/devframe/next-devframe-hub.ts index b86bc79e..7c5c7939 100644 --- a/examples/hub-next/src/client/devframe/next-devframe-hub.ts +++ b/examples/hub-next/src/client/devframe/next-devframe-hub.ts @@ -42,7 +42,7 @@ async function loadBuiltinPlugins(): Promise { pkg => import(/* webpackIgnore: true */ /* turbopackIgnore: true */ pkg), ), ) - return mods.map(mod => mod.default as DevframeDefinition) + return mods.map(mod => (mod.default as () => DevframeDefinition)()) } /** @@ -116,7 +116,7 @@ async function loadA11yAgentMount(): Promise { const mod = await import(/* webpackIgnore: true */ /* turbopackIgnore: true */ '@devframes/plugin-a11y') const bundle = mod.a11yAgentBundlePath as string return { - dockId: (mod.default as DevframeDefinition).id, + dockId: (mod.default as () => DevframeDefinition)().id, dir: dirname(bundle), importFrom: `${A11Y_AGENT_MOUNT_BASE}inject.js`, } diff --git a/examples/hub-next/src/client/next.config.mjs b/examples/hub-next/src/client/next.config.mjs index c6605272..afd0986d 100644 --- a/examples/hub-next/src/client/next.config.mjs +++ b/examples/hub-next/src/client/next.config.mjs @@ -1,4 +1,4 @@ -import { withDevframe } from '@devframes/next/dev-spa' +import { withDevframe } from '@devframes/next/single' // `withDevframe` applies the settings a devframe host requires (currently // `skipTrailingSlashRedirect: true`, so mounted SPAs' relative assets under diff --git a/examples/hub-vite/vite.config.ts b/examples/hub-vite/vite.config.ts index 7900f053..faabdb20 100644 --- a/examples/hub-vite/vite.config.ts +++ b/examples/hub-vite/vite.config.ts @@ -2,16 +2,16 @@ import type { DevframeHubContext } from '@devframes/hub/node' import { defineHubRpcFunction } from '@devframes/hub' import { jsonRenderUiRenderer } from '@devframes/json-render-ui/hub' import { toJsonRenderDockEntry } from '@devframes/json-render/hub' -import a11yDevframe, { a11yAgentBundlePath } from '@devframes/plugin-a11y' -import assetsDevframe from '@devframes/plugin-assets' -import codeServerDevframe from '@devframes/plugin-code-server' +import createA11yDevframe, { a11yAgentBundlePath } from '@devframes/plugin-a11y' +import createAssetsDevframe from '@devframes/plugin-assets' +import createCodeServerDevframe from '@devframes/plugin-code-server' import { createDataInspectorDevframe } from '@devframes/plugin-data-inspector' import { registerDataSource } from '@devframes/plugin-data-inspector/registry' -import gitDevframe from '@devframes/plugin-git' -import inspectDevframe from '@devframes/plugin-inspect' -import messagesDevframe from '@devframes/plugin-messages' -import ogDevframe from '@devframes/plugin-og' -import terminalsDevframe from '@devframes/plugin-terminals' +import createGitDevframe from '@devframes/plugin-git' +import createInspectDevframe from '@devframes/plugin-inspect' +import createMessagesDevframe from '@devframes/plugin-messages' +import createOgDevframe from '@devframes/plugin-og' +import createTerminalsDevframe from '@devframes/plugin-terminals' import { viteDevframeHub } from '@devframes/vite/hub' import { createDashboardView } from 'json-render/dashboard' import UnoCSS from 'unocss/vite' @@ -21,6 +21,14 @@ import demoDevframe from './src/devframe' import tabbedToolDevframe from './src/tabbed-tool' import { unrenderedDockEntry } from './src/unrendered-dock' +const a11yDevframe = createA11yDevframe() +const assetsDevframe = createAssetsDevframe() +const codeServerDevframe = createCodeServerDevframe() +const gitDevframe = createGitDevframe() +const inspectDevframe = createInspectDevframe() +const messagesDevframe = createMessagesDevframe() +const ogDevframe = createOgDevframe() +const terminalsDevframe = createTerminalsDevframe() // Colon-free id override: the hub instance derives each frame's mount path // (`/__devframes//`) from its id, and `:` - which the plugin's default id // (`devframes:plugin:data-inspector`) carries - is a route-param marker to diff --git a/examples/next-runtime-snapshot/src/client/app/components/connect.tsx b/examples/next-runtime-snapshot/src/client/app/components/connect.tsx index 2a21f777..b9b35aa6 100644 --- a/examples/next-runtime-snapshot/src/client/app/components/connect.tsx +++ b/examples/next-runtime-snapshot/src/client/app/components/connect.tsx @@ -2,7 +2,7 @@ import type { DevframeScopedClientContext } from 'devframe/client' import type { ReactNode } from 'react' -import { RpcProvider as DevframeRpcProvider, useRpc as useDevframeRpc, useRpcStatus } from '@devframes/next/dev-spa/client' +import { RpcProvider as DevframeRpcProvider, useRpc as useDevframeRpc, useRpcStatus } from '@devframes/next/single/client' import { useMemo } from 'react' // Inlined (not imported from the server `rpc/index.ts`) so the client @@ -17,7 +17,7 @@ interface ConnectionState { } /** - * Connect to the RPC backend via `@devframes/next/dev-spa/client` — the connect + + * Connect to the RPC backend via `@devframes/next/single/client` — the connect + * status machinery lives in the package now; this file only scopes the client * to this tool's namespace and reshapes the status for the local UI. */ diff --git a/knip.jsonc b/knip.jsonc index c6d1d6f3..db711509 100644 --- a/knip.jsonc +++ b/knip.jsonc @@ -11,6 +11,15 @@ // imported in source - the same false-positive class knip's own docs // describe for icon-collection dependencies. "ignoreDependencies": ["@iconify-json/.+", "@unocss/preset-icons"], + // Every built-in plugin's `src/index.ts` aliases its `createDevframe` + // factory as both the named and default export (AGENTS.md § "A plugin's + // default export is its `createDevframe` factory") - `export default + // createXDevframe` right below `export function createXDevframe(...) {}`. + // Deliberate, not an accidental duplicate: the named export is for options, + // the default export is the conventional single-devframe import. + "ignoreIssues": { + "plugins/*/src/index.ts": ["duplicates"] + }, "workspaces": { ".": { // `design/*.ts` is the shared design system (AGENTS.md § "Design diff --git a/packages/hub-ui/playground/hub-plugin.ts b/packages/hub-ui/playground/hub-plugin.ts index 297018e1..0794e2b7 100644 --- a/packages/hub-ui/playground/hub-plugin.ts +++ b/packages/hub-ui/playground/hub-plugin.ts @@ -2,7 +2,7 @@ import type { HubInstance } from '@devframes/hub/initiate' import type { Plugin, ViteDevServer } from 'vite' import { Server as NodeHttpServer } from 'node:http' import { DEVFRAMES_HUB_BASE, initHub } from '@devframes/hub/initiate' -import gitDevframe from '@devframes/plugin-git' +import createGitDevframe from '@devframes/plugin-git' import { PLAYGROUND_GROUP_ID } from './constants' import { seedPlayground } from './seed' @@ -22,8 +22,8 @@ import { seedPlayground } from './seed' * slot), a cyclic workspace dependency for no real benefit. * * `@devframes/plugin-git` is the one built-in plugin that doesn't itself - * depend on `@devframes/vite` (every other plugin does, for its own - * dev-spa/build tooling) — mounting any of those here would reintroduce the + * depend on `@devframes/vite` (every other plugin does, for its own SPA + * dev-serve/build tooling) — mounting any of those here would reintroduce the * same cyclic dependency `@devframes/vite/hub` avoids, just one hop further * out (hub-ui → that plugin → `@devframes/vite` → hub-ui again, via its peer * dependency). @@ -67,7 +67,7 @@ export function hubUiPlaygroundHub(): Plugin { // to stage/commit from. Inspects this very checkout: `cwd` above is // this package's own directory. devframes: [ - { devframe: gitDevframe, dock: { groupId: PLAYGROUND_GROUP_ID } }, + { devframe: createGitDevframe(), dock: { groupId: PLAYGROUND_GROUP_ID } }, ], configure: seedPlayground, }) diff --git a/packages/hub-ui/src/client/state/context.ts b/packages/hub-ui/src/client/state/context.ts index 07771410..437180d7 100644 --- a/packages/hub-ui/src/client/state/context.ts +++ b/packages/hub-ui/src/client/state/context.ts @@ -1,10 +1,10 @@ import type { DevframeClientCommand, DevframeDockEntry, DevframeDockUserEntry, DevframeRpcClientFunctions, DevframeViewIframe } from '@devframes/hub' -import type { CommandsContext, DevframeRpcClient, DockClientScriptContext, DockEntryState, DockPanelStorage, DockRegistration, DockRendererManifest, DocksContext } from '@devframes/hub/client' +import type { CommandsContext, DevframeClientContext, DevframeRpcClient, DockClientScriptContext, DockEntryState, DockPanelStorage, DockRegistration, DockRendererManifest, DocksContext } from '@devframes/hub/client' import type { SharedState } from 'devframe/utils/shared-state' import type { WhenContext } from 'devframe/utils/when' import type { Ref } from 'vue' import type { DevframeDocksUserSettings } from './dock-settings' -import { attachFrameNavClient } from '@devframes/hub/client' +import { attachFrameNavClient, createDockRenderersContext } from '@devframes/hub/client' import { DEFAULT_STATE_USER_SETTINGS, DOCK_RENDERERS_STATE_KEY } from '@devframes/hub/constants' import { computed, markRaw, reactive, ref, toRefs, watch, watchEffect } from 'vue' import { BUILTIN_ENTRIES, BUILTIN_ENTRY_SETTINGS, DEFAULT_CATEGORIES_ORDER, HUB_UI_HIDE_EVENT } from '../constants' @@ -14,7 +14,6 @@ import { docksGroupByCategories, getCategoryLabel, getGroupMembers, getGroupMemb import { createDockEntryState, DEFAULT_DOCK_PANEL_STORE, sharedStateToRef, useDocksEntries } from './docks' import { createClientMessagesClient } from './messages-client' import { registerMainFrameDockActionHandler, triggerMainFrameDockAction, useIsDockPopupOpen } from './popup' -import { createDockRenderers } from './renderers' import { executeSetupScript } from './setup-script' const docksContextByRpc = new WeakMap() @@ -538,7 +537,10 @@ export async function createDocksContext( }, events: rpc.events, }, - renderers: markRaw(createDockRenderers(() => docksContext, () => rendererManifest.value)), + renderers: markRaw(createDockRenderersContext({ + context: () => docksContext as DevframeClientContext, + manifest: () => rendererManifest.value, + })), rpc: markRaw(rpc), clientType, }) diff --git a/packages/hub-ui/src/client/state/renderers.ts b/packages/hub-ui/src/client/state/renderers.ts deleted file mode 100644 index 40a195b4..00000000 --- a/packages/hub-ui/src/client/state/renderers.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { - DevframeClientContext, - DockRendererManifest, - DockRenderersContext, - DocksContext, -} from '@devframes/hub/client' -import { createDockRenderersContext } from '@devframes/hub/client' - -/** - * The client-side dock-renderer registry required by the hub's `DocksContext`. - * Delegates to the hub's shared factory, so local-first resolution, lazy - * imports from the hub's renderer manifest (`initHub({ renderers })` → - * the `devframe:dock-renderers` shared-state slot), and the typed mount - * result behave exactly like `createDevframeClientHost`'s registry. - * - * hub-ui renders its native dock types directly in `ViewEntry.vue`; every - * other type routes through this registry via `ViewDockRenderer.vue` — e.g. a - * `'json-render'` dock renders with whatever implementation the host - * composed (`jsonRenderUiRenderer()` from `@devframes/json-render-ui/hub`, - * or any community renderer), and falls back to the missing-renderer view - * when none is present. - */ -export function createDockRenderers( - getContext: () => DocksContext, - manifest: () => DockRendererManifest, -): DockRenderersContext { - return createDockRenderersContext({ - context: () => getContext() as DevframeClientContext, - manifest, - }) -} diff --git a/packages/hub/src/constants.ts b/packages/hub/src/constants.ts index 35179d0b..f169e761 100644 --- a/packages/hub/src/constants.ts +++ b/packages/hub/src/constants.ts @@ -1,7 +1,22 @@ import type { DevframeDocksUserSettings } from './types/settings' +import { cleanDoubleSlashes, withLeadingSlash, withTrailingSlash } from 'ufo' export * from 'devframe/constants' +/** Default mount base for a hub instance — one namespace, one catch-all. */ +export const DEVFRAMES_HUB_BASE = '/__devframes/' + +/** + * Normalize a hub mount base to an absolute path with leading and trailing + * slashes (e.g. `devframes` → `/devframes/`), collapsing any doubled + * slashes the input introduced. The one implementation every hub-aware + * host (`@devframes/hub` itself, and the Vite/Nuxt/Next adapters) resolves + * `options.base` through. + */ +export function normalizeHubBase(base: string): string { + return cleanDoubleSlashes(withTrailingSlash(withLeadingSlash(base))) +} + /** * The default ordering weight for each known dock category — lower sorts * earlier. Downstream viewers (e.g. `@vitejs/devtools-kit`) import this as the diff --git a/packages/hub/src/node/initiate.ts b/packages/hub/src/node/initiate.ts index 94395ebe..9c175d43 100644 --- a/packages/hub/src/node/initiate.ts +++ b/packages/hub/src/node/initiate.ts @@ -16,8 +16,8 @@ import { createH3DevframeHost, createInstanceShell, resolveInstanceRegister } fr import { mountStaticHandler } from 'devframe/utils/serve-static' import { H3 } from 'h3' import { resolve } from 'pathe' -import { cleanDoubleSlashes, joinURL, withLeadingSlash, withoutLeadingSlash, withTrailingSlash } from 'ufo' -import { DOCK_RENDERERS_STATE_KEY } from '../constants' +import { joinURL, withoutLeadingSlash, withTrailingSlash } from 'ufo' +import { DEVFRAMES_HUB_BASE, DOCK_RENDERERS_STATE_KEY, normalizeHubBase } from '../constants' import { createHubContext } from './context' import { diagnostics } from './diagnostics' @@ -35,8 +35,8 @@ function normalizeDevframeEntry(entry: DevframeDefinition | HubDevframeEntry): H return 'devframe' in entry ? entry : { devframe: entry } } -/** Default mount base for a hub instance — one namespace, one catch-all. */ -export const DEVFRAMES_HUB_BASE = '/__devframes/' +/** Default mount base for a hub instance — re-exported from `../constants` (the client-safe home) for existing importers of this node entry. */ +export { DEVFRAMES_HUB_BASE } /** Content-type for a UI asset key, inferred from its file extension. */ function assetContentType(key: string): string { @@ -333,10 +333,6 @@ function resolveDevframesInput(input: DevframesInput): Promise arrays.flat()) } -function normalizeBase(base: string): string { - return cleanDoubleSlashes(withTrailingSlash(withLeadingSlash(base))) -} - /** * Validate the renderer-module registrations fail-fast: route-safe types * (each becomes the `__renderers/.mjs` URL segment), one module @@ -401,7 +397,7 @@ function renderClientImportsModule(ctx: DevframeHubContext): string { * through {@link HubInstance.attach}. */ export function initHub(options: InitHubOptions): HubInstance { - const base = normalizeBase(options.base) + const base = normalizeHubBase(options.base) const baseNoSlash = base.slice(0, -1) const app = new H3() const cwd = options.cwd ?? process.cwd() diff --git a/packages/next/package.json b/packages/next/package.json index 6f5d8e3f..66dfbde1 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -24,11 +24,11 @@ "types": "./dist/index.d.mts", "default": "./dist/index.mjs" }, - "./dev-spa": { - "types": "./dist/dev-spa.d.mts", - "default": "./dist/dev-spa.mjs" + "./single": { + "types": "./dist/single.d.mts", + "default": "./dist/single.mjs" }, - "./dev-spa/client": { + "./single/client": { "types": "./dist/client.d.mts", "default": "./dist/client.mjs" }, @@ -74,8 +74,7 @@ } }, "dependencies": { - "h3": "catalog:deps", - "ufo": "catalog:deps" + "h3": "catalog:deps" }, "devDependencies": { "@devframes/hub": "workspace:*", diff --git a/packages/next/src/config.ts b/packages/next/src/config.ts index ac505a4c..28a1cff7 100644 --- a/packages/next/src/config.ts +++ b/packages/next/src/config.ts @@ -19,7 +19,7 @@ export interface DevframeNextConfig { * connect. Serving the base path verbatim keeps relative resolution intact. * * ```js [next.config.mjs] - * import { withDevframe } from '@devframes/next/dev-spa' + * import { withDevframe } from '@devframes/next/single' * * export default withDevframe({ * // ...your own Next config diff --git a/packages/next/src/handler.ts b/packages/next/src/handler.ts index fbaef245..94659d19 100644 --- a/packages/next/src/handler.ts +++ b/packages/next/src/handler.ts @@ -96,7 +96,7 @@ function defaultGetStorageDir(scope: DevframeStorageScope): string { * * ```ts [app/%5F_my-tool/[[...path]]/route.ts] * import myDevframe from '@/devframe' - * import { createDevframeNextHandler } from '@devframes/next/dev-spa' + * import { createDevframeNextHandler } from '@devframes/next/single' * * export const runtime = 'nodejs' * export const dynamic = 'force-dynamic' diff --git a/packages/next/src/hub-client.tsx b/packages/next/src/hub-client.tsx index e33d1dba..980aaae3 100644 --- a/packages/next/src/hub-client.tsx +++ b/packages/next/src/hub-client.tsx @@ -2,13 +2,11 @@ import type { DevframeClientHost, DevframeClientHostOptions } from '@devframes/hub/client' import { createDevframeClientHost } from '@devframes/hub/client' +import { DEVFRAMES_HUB_BASE } from '@devframes/hub/constants' import { useEffect, useState } from 'react' export type { DevframeClientHost, DevframeClientHostOptions } from '@devframes/hub/client' -/** Default hub mount base — mirrors `@devframes/hub`'s `DEVFRAMES_HUB_BASE`. */ -const DEVFRAMES_HUB_BASE = '/__devframes/' - export interface UseDevframeHubClientOptions extends DevframeClientHostOptions { /** * Hub mount base to connect to. Forwarded as `connect.baseURL` when no diff --git a/packages/next/src/hub.ts b/packages/next/src/hub.ts index 18834fc9..ac393672 100644 --- a/packages/next/src/hub.ts +++ b/packages/next/src/hub.ts @@ -1,6 +1,6 @@ import type { DevframeHubUi, HubInstance, InitHubOptions } from '@devframes/hub/initiate' -import { DEVFRAMES_HUB_BASE, initHub } from '@devframes/hub/initiate' -import { cleanDoubleSlashes, withLeadingSlash, withTrailingSlash } from 'ufo' +import { DEVFRAMES_HUB_BASE, normalizeHubBase } from '@devframes/hub/constants' +import { initHub } from '@devframes/hub/initiate' // The "bring your own DevframeHost" seam for `initHub({ context })`. export type { @@ -80,7 +80,7 @@ export interface NextDevframeHubOptions { * instead of leaking a side-car per reload. */ export async function createNextDevframeHub(options: NextDevframeHubOptions = {}): Promise { - const base = normalizeBase(options.base ?? DEVFRAMES_HUB_BASE) + const base = normalizeHubBase(options.base ?? DEVFRAMES_HUB_BASE) const ui = options.ui === false ? undefined @@ -149,7 +149,7 @@ function hubRegistry(): Map> { * ``` */ export function nextDevframeHub(options: NextDevframeHubOptions = {}): NextDevframeHubHandle { - const base = normalizeBase(options.base ?? DEVFRAMES_HUB_BASE) + const base = normalizeHubBase(options.base ?? DEVFRAMES_HUB_BASE) const ready = (): Promise => { const registry = hubRegistry() @@ -188,7 +188,3 @@ async function loadDefaultUi(): Promise { const mod = await import(/* webpackIgnore: true */ /* turbopackIgnore: true */ '@devframes/hub-ui') return (mod.createUi as () => DevframeHubUi)() } - -function normalizeBase(base: string): string { - return cleanDoubleSlashes(withTrailingSlash(withLeadingSlash(base))) -} diff --git a/packages/next/src/index.ts b/packages/next/src/index.ts index 3770f159..946b4b2d 100644 --- a/packages/next/src/index.ts +++ b/packages/next/src/index.ts @@ -1,9 +1,9 @@ // `@devframes/next` has no root export — it splits into two clearly-scoped // subpaths so a consumer picks the job they're doing: // -// • `@devframes/next/dev-spa` — host a SINGLE devframe's SPA in a +// • `@devframes/next/single` — host a SINGLE devframe's SPA in a // Next.js App Router app (`withDevframe`, `createDevframeNextHandler`), -// with its React client at `@devframes/next/dev-spa/client`. +// with its React client at `@devframes/next/single/client`. // • `@devframes/next/hub` — mount a whole devframes-hub (many // integrations) from one catch-all route, `@devframes/hub-ui` by default, // with a React client helper at `@devframes/next/hub/client`. @@ -12,6 +12,6 @@ // the pointer above instead of silently resolving to nothing. throw new Error( '[@devframes/next] has no root export. Import from a scoped subpath instead:\n' - + ' • "@devframes/next/dev-spa" (+ "/dev-spa/client") — host one devframe\'s SPA\n' - + ' • "@devframes/next/hub" (+ "/hub/client") — mount a devframes-hub\n', + + ' • "@devframes/next/single" (+ "/single/client") — host one devframe\'s SPA\n' + + ' • "@devframes/next/hub" (+ "/hub/client") — mount a devframes-hub\n', ) diff --git a/packages/next/src/dev-spa.ts b/packages/next/src/single.ts similarity index 76% rename from packages/next/src/dev-spa.ts rename to packages/next/src/single.ts index 570171ae..2641829f 100644 --- a/packages/next/src/dev-spa.ts +++ b/packages/next/src/single.ts @@ -1,9 +1,9 @@ -// `@devframes/next/dev-spa` — host a SINGLE devframe's SPA inside a Next.js +// `@devframes/next/single` — host a SINGLE devframe's SPA inside a Next.js // App Router app: the config helper that lets mounted SPAs' relative assets // resolve, and the catch-all route handler that serves one devframe. // // The React client that connects the page to the devframe RPC lives at -// `@devframes/next/dev-spa/client` (a `'use client'` module). +// `@devframes/next/single/client` (a `'use client'` module). export type { DevframeNextConfig } from './config' export { withDevframe } from './config' diff --git a/packages/next/tsdown.config.ts b/packages/next/tsdown.config.ts index bbd2cc44..3bf6313e 100644 --- a/packages/next/tsdown.config.ts +++ b/packages/next/tsdown.config.ts @@ -10,13 +10,13 @@ const nodeDeps = { } export default defineConfig([ - // Node entries — the throwing root, the single-devframe dev-spa surface, - // and the hub host. + // Node entries — the throwing root, the single-devframe surface, and the + // hub host. { entry: { - 'index': 'src/index.ts', - 'dev-spa': 'src/dev-spa.ts', - 'hub': 'src/hub.ts', + index: 'src/index.ts', + single: 'src/single.ts', + hub: 'src/hub.ts', }, platform: 'node', tsconfig, diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index fe9d60e6..71814eee 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -23,9 +23,9 @@ "types": "./dist/index.d.mts", "default": "./dist/index.mjs" }, - "./dev-spa": { - "types": "./dist/dev-spa.d.mts", - "default": "./dist/dev-spa.mjs" + "./single": { + "types": "./dist/single.d.mts", + "default": "./dist/single.mjs" }, "./hub": { "types": "./dist/hub.d.mts", diff --git a/packages/nuxt/src/hub-client.ts b/packages/nuxt/src/hub-client.ts index 9b836283..4aa43bd0 100644 --- a/packages/nuxt/src/hub-client.ts +++ b/packages/nuxt/src/hub-client.ts @@ -1,13 +1,11 @@ import type { DevframeClientHost, DevframeClientHostOptions } from '@devframes/hub/client' import type { Ref } from 'vue' import { createDevframeClientHost } from '@devframes/hub/client' +import { DEVFRAMES_HUB_BASE } from '@devframes/hub/constants' import { onScopeDispose, shallowRef } from 'vue' export type { DevframeClientHost, DevframeClientHostOptions } from '@devframes/hub/client' -/** Default hub mount base — mirrors `@devframes/hub`'s `DEVFRAMES_HUB_BASE`. */ -const DEVFRAMES_HUB_BASE = '/__devframes/' - export interface UseDevframeHubClientOptions extends DevframeClientHostOptions { /** * Hub mount base to connect to. Forwarded as `connect.baseURL` when no diff --git a/packages/nuxt/src/hub.ts b/packages/nuxt/src/hub.ts index 2a15eed4..1036a64e 100644 --- a/packages/nuxt/src/hub.ts +++ b/packages/nuxt/src/hub.ts @@ -1,10 +1,8 @@ import type { ViteDevframeHubOptions } from '@devframes/vite/hub' +import { DEVFRAMES_HUB_BASE, normalizeHubBase } from '@devframes/hub/constants' import { viteDevframeHub } from '@devframes/vite/hub' import { addVitePlugin, createResolver, defineNuxtModule } from '@nuxt/kit' -/** Default hub mount base — mirrors `@devframes/hub`'s `DEVFRAMES_HUB_BASE`. */ -const DEVFRAMES_HUB_BASE = '/__devframes/' - export interface DevframeNuxtHubOptions extends Omit { /** * Inject `@devframes/hub-ui`'s floating-dock bootstrap (`embedded.js`) @@ -48,7 +46,7 @@ function recommendNuxtDevtools(): void { * integrates the same hub protocol natively and is the recommended path for a * Nuxt app, so this module emits a one-time notice to that effect (silence it * with `{ quiet: true }`). To wire a Nuxt app up as a single devframe client, - * reach for `@devframes/nuxt/dev-spa` instead. + * reach for `@devframes/nuxt/single` instead. * * ```ts [nuxt.config.ts] * export default defineNuxtConfig({ @@ -72,7 +70,7 @@ export default defineNuxtModule({ createResolver(import.meta.url) - const base = normalizeBase(options.base ?? DEVFRAMES_HUB_BASE) + const base = normalizeHubBase(options.base ?? DEVFRAMES_HUB_BASE) const { injectEmbedded, quiet: _quiet, ...hubOptions } = options // Wire the hub into Nuxt's own Vite dev server. `quiet: true` suppresses @@ -94,10 +92,3 @@ export default defineNuxtModule({ } }, }) - -function normalizeBase(base: string): string { - let out = base.startsWith('/') ? base : `/${base}` - if (!out.endsWith('/')) - out = `${out}/` - return out -} diff --git a/packages/nuxt/src/index.ts b/packages/nuxt/src/index.ts index b01dade1..82822643 100644 --- a/packages/nuxt/src/index.ts +++ b/packages/nuxt/src/index.ts @@ -1,17 +1,17 @@ // `@devframes/nuxt` has no root export — it splits into two clearly-scoped // subpaths so you pick the job you're doing: // -// • `@devframes/nuxt/dev-spa` — wire a Nuxt app up as a SINGLE devframe's +// • `@devframes/nuxt/single` — wire a Nuxt app up as a SINGLE devframe's // client (the Nuxt module + its dev-time RPC bridge). -// • `@devframes/nuxt/hub` — mount a whole devframes-hub (many +// • `@devframes/nuxt/hub` — mount a whole devframes-hub (many // integrations) alongside `nuxt dev`, `@devframes/hub-ui` by default, // with a client composable at `@devframes/nuxt/hub/client`. // // Register the module by its subpath, e.g. -// `modules: ['@devframes/nuxt/dev-spa']`. Importing the bare package throws +// `modules: ['@devframes/nuxt/single']`. Importing the bare package throws // with the pointer above instead of silently resolving to nothing. throw new Error( '[@devframes/nuxt] has no root export. Use a scoped subpath instead:\n' - + ' • modules: ["@devframes/nuxt/dev-spa"] — Nuxt app as one devframe client\n' - + ' • modules: ["@devframes/nuxt/hub"] — mount a devframes-hub with nuxt dev\n', + + ' • modules: ["@devframes/nuxt/single"] — Nuxt app as one devframe client\n' + + ' • modules: ["@devframes/nuxt/hub"] — mount a devframes-hub with nuxt dev\n', ) diff --git a/packages/nuxt/src/dev-spa.ts b/packages/nuxt/src/single.ts similarity index 98% rename from packages/nuxt/src/dev-spa.ts rename to packages/nuxt/src/single.ts index 51beae1e..06239c4a 100644 --- a/packages/nuxt/src/dev-spa.ts +++ b/packages/nuxt/src/single.ts @@ -1,5 +1,5 @@ import type { DevframeDefinition } from 'devframe' -import { devframeViteBridge } from '@devframes/vite/dev-spa' +import { devframeViteBridge } from '@devframes/vite/single' import { addPlugin, addVitePlugin, createResolver, defineNuxtModule } from '@nuxt/kit' export interface DevframeNuxtModuleOptions { diff --git a/packages/nuxt/tsdown.config.ts b/packages/nuxt/tsdown.config.ts index e0c3374d..5034f59b 100644 --- a/packages/nuxt/tsdown.config.ts +++ b/packages/nuxt/tsdown.config.ts @@ -22,9 +22,9 @@ export default defineConfig([{ // Node/neutral entries — the throwing root, the single-devframe Nuxt module, // and the hub Nuxt module. entry: { - 'index': 'src/index.ts', - 'dev-spa': 'src/dev-spa.ts', - 'hub': 'src/hub.ts', + index: 'src/index.ts', + single: 'src/single.ts', + hub: 'src/hub.ts', }, clean: true, dts: true, @@ -63,7 +63,7 @@ export default defineConfig([{ const tsdownPkg = require('tsdown/package.json') const { name, version } = require('./package.json') // copy runtime types + generate the client-plugin d.ts and the Nuxt - // module metadata (describing the default `@devframes/nuxt/dev-spa` module). + // module metadata (describing the default `@devframes/nuxt/single` module). await Promise.all([ fs.cp('src/runtime/types.d.ts', 'dist/runtime/types.d.ts'), fs.writeFile('dist/runtime/plugin.client.d.ts', `import type { Plugin } from '#app'; @@ -74,7 +74,7 @@ declare const plugin: Plugin<{ export default plugin; `, 'utf-8'), fs.writeFile('dist/module.json', `{ - "name": "${name}/dev-spa", + "name": "${name}/single", "configKey": "devframe", "version": "${version}", "builder": { diff --git a/packages/vite/package.json b/packages/vite/package.json index 29bc1e00..8c217818 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -20,7 +20,7 @@ "sideEffects": false, "exports": { ".": "./dist/index.mjs", - "./dev-spa": "./dist/dev-spa.mjs", + "./single": "./dist/single.mjs", "./hub": "./dist/hub.mjs", "./hub/client": "./dist/hub-client.mjs", "./package.json": "./package.json" diff --git a/packages/vite/src/hub-client.ts b/packages/vite/src/hub-client.ts index db54446f..30158458 100644 --- a/packages/vite/src/hub-client.ts +++ b/packages/vite/src/hub-client.ts @@ -1,11 +1,9 @@ import type { DevframeClientHost, DevframeClientHostOptions } from '@devframes/hub/client' import { createDevframeClientHost } from '@devframes/hub/client' +import { DEVFRAMES_HUB_BASE } from '@devframes/hub/constants' export type { DevframeClientHost, DevframeClientHostOptions } from '@devframes/hub/client' -/** Default hub mount base — mirrors `@devframes/hub`'s `DEVFRAMES_HUB_BASE`. */ -const DEVFRAMES_HUB_BASE = '/__devframes/' - export interface MountDevframeHubClientOptions extends DevframeClientHostOptions { /** * Hub mount base to connect to. Forwarded as `connect.baseURL` when no diff --git a/packages/vite/src/hub.ts b/packages/vite/src/hub.ts index 3ab97a68..3001c51d 100644 --- a/packages/vite/src/hub.ts +++ b/packages/vite/src/hub.ts @@ -5,7 +5,8 @@ import type { DevframeDefinition } from 'devframe' import type { Plugin, ResolvedConfig, ViteDevServer } from 'vite' import { Server as NodeHttpServer } from 'node:http' import process from 'node:process' -import { DEVFRAMES_HUB_BASE, initHub } from '@devframes/hub/initiate' +import { DEVFRAMES_HUB_BASE, normalizeHubBase } from '@devframes/hub/constants' +import { initHub } from '@devframes/hub/initiate' export interface ViteDevframeHubOptions { /** @@ -112,10 +113,10 @@ function recommendViteDevtools(): void { * (`@vitejs/devtools-kit`) integrates the same hub protocol natively and is * the recommended path for a Vite app, so this plugin emits a one-time notice * to that effect (silence it with `{ quiet: true }`). For dev-serving a - * single devframe's own SPA, reach for `@devframes/vite/dev-spa` instead. + * single devframe's own SPA, reach for `@devframes/vite/single` instead. */ export function viteDevframeHub(options: ViteDevframeHubOptions = {}): Plugin { - const base = normalizeBase(options.base ?? DEVFRAMES_HUB_BASE) + const base = normalizeHubBase(options.base ?? DEVFRAMES_HUB_BASE) let viteConfig: ResolvedConfig | undefined let instance: HubInstance | undefined // Set once the hub is up if its UI ships an `embedded.js` bootstrap — the @@ -248,10 +249,3 @@ function attachClientScripts( : { devframe: def, dock: { clientScript } } }) } - -function normalizeBase(base: string): string { - let out = base.startsWith('/') ? base : `/${base}` - if (!out.endsWith('/')) - out = `${out}/` - return out -} diff --git a/packages/vite/src/index.ts b/packages/vite/src/index.ts index 3f8a2eee..d3d7c38d 100644 --- a/packages/vite/src/index.ts +++ b/packages/vite/src/index.ts @@ -1,16 +1,16 @@ // `@devframes/vite` has no root export — it splits into two clearly-scoped // subpaths so a consumer picks the job they're doing: // -// • `@devframes/vite/dev-spa` — build & dev-serve a SINGLE devframe's SPA +// • `@devframes/vite/single` — build & dev-serve a SINGLE devframe's SPA // with Vite (the `devframeVitePlugin` / `devframeViteBridge` / `devframeVite` // plugins). -// • `@devframes/vite/hub` — mount a whole devframes-hub (many +// • `@devframes/vite/hub` — mount a whole devframes-hub (many // integrations) inside a Vite dev server, `@devframes/hub-ui` by default. // // Importing the bare package is almost always a mistake, so it throws with // the pointer above instead of silently resolving to nothing. throw new Error( '[@devframes/vite] has no root export. Import from a scoped subpath instead:\n' - + ' • "@devframes/vite/dev-spa" — dev-serve one devframe\'s SPA with Vite\n' - + ' • "@devframes/vite/hub" — mount a devframes-hub inside a Vite app\n', + + ' • "@devframes/vite/single" — dev-serve one devframe\'s SPA with Vite\n' + + ' • "@devframes/vite/hub" — mount a devframes-hub inside a Vite app\n', ) diff --git a/packages/vite/src/dev-spa.ts b/packages/vite/src/single.ts similarity index 100% rename from packages/vite/src/dev-spa.ts rename to packages/vite/src/single.ts diff --git a/packages/vite/test/dev-spa.test.ts b/packages/vite/test/single.test.ts similarity index 99% rename from packages/vite/test/dev-spa.test.ts rename to packages/vite/test/single.test.ts index debcb67e..b3efe862 100644 --- a/packages/vite/test/dev-spa.test.ts +++ b/packages/vite/test/single.test.ts @@ -1,6 +1,6 @@ import type { DevframeDefinition } from 'devframe' import type { IncomingMessage, Server as NodeHttpServer, ServerResponse } from 'node:http' -import type { DevframeViteDevServerLike, DevframeVitePlugin } from '../src/dev-spa' +import type { DevframeViteDevServerLike, DevframeVitePlugin } from '../src/single' import { mkdtempSync, writeFileSync } from 'node:fs' import { createServer } from 'node:http' import { tmpdir } from 'node:os' @@ -10,7 +10,7 @@ import { createRpcClient } from 'devframe/rpc/client' import { createWsRpcChannel } from 'devframe/rpc/transports/ws-client' import { getPort } from 'get-port-please' import { afterEach, describe, expect, it } from 'vitest' -import { devframeVite, devframeViteBridge, devframeVitePlugin } from '../src/dev-spa' +import { devframeVite, devframeViteBridge, devframeVitePlugin } from '../src/single' function defineTestDef(overrides: Partial = {}): DevframeDefinition { return { diff --git a/packages/vite/tsdown.config.ts b/packages/vite/tsdown.config.ts index 3b15bddb..a794a149 100644 --- a/packages/vite/tsdown.config.ts +++ b/packages/vite/tsdown.config.ts @@ -20,13 +20,13 @@ const deps = { } export default defineConfig([ - // Node entries — the throwing root, the single-devframe dev-spa plugins, - // and the hub host plugin. + // Node entries — the throwing root, the single-devframe plugins, and the + // hub host plugin. { entry: { - 'index': 'src/index.ts', - 'dev-spa': 'src/dev-spa.ts', - 'hub': 'src/hub.ts', + index: 'src/index.ts', + single: 'src/single.ts', + hub: 'src/hub.ts', }, platform: 'node', tsconfig, diff --git a/plugins/a11y/README.md b/plugins/a11y/README.md index a2d0c473..8263f4f6 100644 --- a/plugins/a11y/README.md +++ b/plugins/a11y/README.md @@ -115,10 +115,9 @@ pnpm -C plugins/a11y dev # from source: same, at /__devframes_plugin_a11 | Path | Export | Purpose | |------|--------|---------| -| `src/index.ts` | `.` | `createA11yDevframe()` + the default `DevframeDefinition`; `a11yAgentBundlePath` — the agent module a hub attaches as this dock's client script | +| `src/index.ts` | `.` | `createA11yDevframe()` (also the default export); `a11yAgentBundlePath` — the agent module a hub attaches as this dock's client script | | `src/node/index.ts` | `/node` | `setupA11y(ctx, options?)` — registers the RPC functions with the runtime config | | `src/cli.ts` | `/cli` | `createA11yCli()` — backs the `devframes_plugin_a11y` bin | -| `src/vite.ts` | `/vite` | `a11yVitePlugin()` — mounts the panel into a Vite host | | `src/client/index.ts` | `/client` | `connectA11y()` — typed browser RPC client wrapper | | `src/rpc/` | — | `get-config` static RPC + the type-safe client registry | | `src/shared/protocol.ts` | — | the agent ↔ panel `BroadcastChannel` contract | diff --git a/plugins/a11y/demo/server.mjs b/plugins/a11y/demo/server.mjs index 26ff52e3..0c22ba90 100644 --- a/plugins/a11y/demo/server.mjs +++ b/plugins/a11y/demo/server.mjs @@ -27,11 +27,12 @@ import { mountStaticHandler } from 'devframe/utils/serve-static' import { getPort } from 'get-port-please' import { H3, toNodeHandler } from 'h3' import { resolve } from 'pathe' -import devframe from '../src/index.ts' +import createA11yDevframe from '../src/index.ts' const HERE = fileURLToPath(new URL('.', import.meta.url)) const ROOT = resolve(HERE, '..') +const devframe = createA11yDevframe() const mode = process.argv[2] === 'build' ? 'build' : 'dev' const basePath = devframe.basePath const injectDir = resolve(ROOT, 'dist/inject') diff --git a/plugins/a11y/package.json b/plugins/a11y/package.json index 4d8697c0..caa26591 100644 --- a/plugins/a11y/package.json +++ b/plugins/a11y/package.json @@ -26,7 +26,6 @@ "./client": "./dist/client/index.mjs", "./cli": "./dist/cli.mjs", "./node": "./dist/node/index.mjs", - "./vite": "./dist/vite.mjs", "./package.json": "./package.json" }, "types": "./dist/index.d.mts", @@ -62,7 +61,6 @@ } }, "dependencies": { - "@devframes/vite": "workspace:*", "cac": "catalog:deps" }, "devDependencies": { diff --git a/plugins/a11y/src/cli.ts b/plugins/a11y/src/cli.ts index 1fee09de..4e93eeff 100644 --- a/plugins/a11y/src/cli.ts +++ b/plugins/a11y/src/cli.ts @@ -1,6 +1,6 @@ import type { CacHandle } from 'devframe/adapters/cac' import { createCac } from 'devframe/adapters/cac' -import a11yDevframe from './index.ts' +import createA11yDevframe from './index.ts' /** * Build the standalone CLI for the a11y inspector — backs the package `bin` @@ -9,5 +9,5 @@ import a11yDevframe from './index.ts' * `dev` / `build` command shell. */ export function createA11yCli(): CacHandle { - return createCac(a11yDevframe) + return createCac(createA11yDevframe()) } diff --git a/plugins/a11y/src/index.ts b/plugins/a11y/src/index.ts index d0250520..00759d56 100644 --- a/plugins/a11y/src/index.ts +++ b/plugins/a11y/src/index.ts @@ -99,8 +99,5 @@ export function createA11yDevframe(options: A11yDevframeOptions = {}): DevframeD }) } -/** The default a11y inspector devframe definition. */ -const a11yDevframe: DevframeDefinition = createA11yDevframe() - -export default a11yDevframe +export default createA11yDevframe export type { Impact, ScanReport, Violation, ViolationNode } from './shared/protocol.ts' diff --git a/plugins/a11y/src/vite.ts b/plugins/a11y/src/vite.ts deleted file mode 100644 index 0d85b270..00000000 --- a/plugins/a11y/src/vite.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { DevframeViteOptions, DevframeVitePlugin } from '@devframes/vite/dev-spa' -import { devframeVite } from '@devframes/vite/dev-spa' -import a11yDevframe from './index.ts' - -export type { DevframeViteOptions } - -/** - * Mount the a11y inspector panel into an existing Vite dev server. In the - * default static-mount mode it serves the built panel at - * `/__devframes_plugin_a11y/`; pass `{ bridge: true }` for the bridge mode - * where the host owns the SPA and devframe runs a side-car RPC + WS - * server. - * - * The in-page agent that scans the host is loaded separately: a hub loads it - * as this dock's client script (see {@link a11yAgentBundlePath}); a standalone - * host adds `