From af2316cd4461ef565093fecdf574997adb5f5e0b Mon Sep 17 00:00:00 2001 From: "Anthony Fu (via agent)" Date: Wed, 19 Aug 2026 01:38:18 +0000 Subject: [PATCH] feat: add Fastify, SvelteKit, and Deno hub examples Extend the hub-*-minimal family with three more runtimes and mounting styles, each mounting the same initHub() instance: - hub-fastify-minimal: hub.nodeMiddleware via @fastify/middie, with the RPC socket riding Fastify's own node:http server through hub.attach(server) - hub-sveltekit-minimal: a catch-all +server.ts delegating to hub.handler, with a side-car socket (ws.sidecar) and trailingSlash: 'ignore' so the hub's trailing-slash URLs are served verbatim - hub-deno-minimal: Deno.serve delegating to hub.handler, with a same-origin fetch-upgrade socket Add the Deno WebSocket transport that the Deno example binds: devframe/rpc/transports/ws-deno (attachDenoWsTransport, crossws' Deno adapter), mirroring the existing ws-bun tier. Register it in the package exports, tsdown entries, alias/tsconfig paths, and knip config. Docs: add an examples page per host, and update the examples index, the sidebar, and the hub-initiate socket guide to match. Created with the help of an agent. --- alias.ts | 1 + docs/.vitepress/config.ts | 3 + docs/examples/hub-deno-minimal.md | 26 + docs/examples/hub-fastify-minimal.md | 26 + docs/examples/hub-sveltekit-minimal.md | 26 + docs/examples/index.md | 3 + docs/guide/hub-initiate.md | 4 +- examples/hub-deno-minimal/README.md | 16 + examples/hub-deno-minimal/package.json | 28 + examples/hub-deno-minimal/src/hub.ts | 82 +++ examples/hub-deno-minimal/src/server.ts | 70 ++ examples/hub-deno-minimal/tsconfig.json | 19 + examples/hub-fastify-minimal/README.md | 16 + examples/hub-fastify-minimal/package.json | 31 + examples/hub-fastify-minimal/src/hub.ts | 75 +++ examples/hub-fastify-minimal/src/server.ts | 46 ++ examples/hub-fastify-minimal/tsconfig.json | 19 + examples/hub-sveltekit-minimal/.gitignore | 3 + examples/hub-sveltekit-minimal/README.md | 17 + examples/hub-sveltekit-minimal/package.json | 33 + examples/hub-sveltekit-minimal/src/app.d.ts | 6 + examples/hub-sveltekit-minimal/src/app.html | 15 + examples/hub-sveltekit-minimal/src/hub.ts | 57 ++ .../src/routes/+page.svelte | 13 + .../routes/__devframes/[...path]/+server.ts | 16 + .../hub-sveltekit-minimal/svelte.config.js | 10 + examples/hub-sveltekit-minimal/tsconfig.json | 21 + examples/hub-sveltekit-minimal/vite.config.ts | 6 + knip.jsonc | 8 +- packages/devframe/package.json | 1 + .../devframe/src/rpc/transports/ws-deno.ts | 59 ++ packages/devframe/tsdown.config.ts | 1 + pnpm-lock.yaml | 610 +++++++++++++++++- pnpm-workspace.yaml | 4 + .../rpc/transports/ws-deno.snapshot.d.ts | 16 + .../rpc/transports/ws-deno.snapshot.js | 6 + tsconfig.base.json | 3 + 37 files changed, 1369 insertions(+), 27 deletions(-) create mode 100644 docs/examples/hub-deno-minimal.md create mode 100644 docs/examples/hub-fastify-minimal.md create mode 100644 docs/examples/hub-sveltekit-minimal.md create mode 100644 examples/hub-deno-minimal/README.md create mode 100644 examples/hub-deno-minimal/package.json create mode 100644 examples/hub-deno-minimal/src/hub.ts create mode 100644 examples/hub-deno-minimal/src/server.ts create mode 100644 examples/hub-deno-minimal/tsconfig.json create mode 100644 examples/hub-fastify-minimal/README.md create mode 100644 examples/hub-fastify-minimal/package.json create mode 100644 examples/hub-fastify-minimal/src/hub.ts create mode 100644 examples/hub-fastify-minimal/src/server.ts create mode 100644 examples/hub-fastify-minimal/tsconfig.json create mode 100644 examples/hub-sveltekit-minimal/.gitignore create mode 100644 examples/hub-sveltekit-minimal/README.md create mode 100644 examples/hub-sveltekit-minimal/package.json create mode 100644 examples/hub-sveltekit-minimal/src/app.d.ts create mode 100644 examples/hub-sveltekit-minimal/src/app.html create mode 100644 examples/hub-sveltekit-minimal/src/hub.ts create mode 100644 examples/hub-sveltekit-minimal/src/routes/+page.svelte create mode 100644 examples/hub-sveltekit-minimal/src/routes/__devframes/[...path]/+server.ts create mode 100644 examples/hub-sveltekit-minimal/svelte.config.js create mode 100644 examples/hub-sveltekit-minimal/tsconfig.json create mode 100644 examples/hub-sveltekit-minimal/vite.config.ts create mode 100644 packages/devframe/src/rpc/transports/ws-deno.ts create mode 100644 tests/__snapshots__/tsnapi/devframe/rpc/transports/ws-deno.snapshot.d.ts create mode 100644 tests/__snapshots__/tsnapi/devframe/rpc/transports/ws-deno.snapshot.js diff --git a/alias.ts b/alias.ts index 839d87a0..824084ce 100644 --- a/alias.ts +++ b/alias.ts @@ -10,6 +10,7 @@ export const alias = { 'devframe/rpc/transports/sse-client': r('devframe/src/rpc/transports/sse-client.ts'), 'devframe/rpc/transports/sse-server': r('devframe/src/rpc/transports/sse-server.ts'), 'devframe/rpc/transports/ws-bun': r('devframe/src/rpc/transports/ws-bun.ts'), + 'devframe/rpc/transports/ws-deno': r('devframe/src/rpc/transports/ws-deno.ts'), 'devframe/rpc/transports/ws-server': r('devframe/src/rpc/transports/ws-server.ts'), 'devframe/rpc/transports/ws-client': r('devframe/src/rpc/transports/ws-client.ts'), 'devframe/rpc/client': r('devframe/src/rpc/client.ts'), diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 7c3753df..f7e21814 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -129,6 +129,9 @@ function examplesItems(prefix: string) { { text: 'hub-next-minimal', link: `${prefix}/examples/hub-next-minimal` }, { text: 'hub-nitro-minimal', link: `${prefix}/examples/hub-nitro-minimal` }, { text: 'hub-hono-minimal', link: `${prefix}/examples/hub-hono-minimal` }, + { text: 'hub-fastify-minimal', link: `${prefix}/examples/hub-fastify-minimal` }, + { text: 'hub-sveltekit-minimal', link: `${prefix}/examples/hub-sveltekit-minimal` }, + { text: 'hub-deno-minimal', link: `${prefix}/examples/hub-deno-minimal` }, { text: 'hub-rsbuild-minimal', link: `${prefix}/examples/hub-rsbuild-minimal` }, ] satisfies DefaultTheme.NavItemWithLink[] } diff --git a/docs/examples/hub-deno-minimal.md b/docs/examples/hub-deno-minimal.md new file mode 100644 index 00000000..e56dd629 --- /dev/null +++ b/docs/examples/hub-deno-minimal.md @@ -0,0 +1,26 @@ +--- +outline: deep +--- + +# hub-deno-minimal + +The minimal [Deno](https://deno.com) host for [`@devframes/hub`](/guide/hub): one `initHub()` call served through `Deno.serve`, the UI supplied by `@devframes/hub-ui`. + +Package: `hub-deno-minimal` · framework: **Deno** + +## What it shows + +- `initHub({ base, devframes, ui: createUi() })` in `src/hub.ts`, memoized on `globalThis`. No transport option, so the entry wires the socket itself. +- `Deno.serve(options, handler)` serves HTTP (web `Request` → `Response`), and the whole namespace flows through `hub.handler(request)`. +- WebSockets arrive as fetch upgrades, so `src/server.ts` binds Deno's transport with `createContextRpcServer` + `attachDenoWsTransport` (crossws' Deno adapter) and answers `${hub.base}__ws` on the app's own origin. crossws attaches the socket to the `Response` its `handleUpgrade` returns, so there is no separate `websocket` handler object. + +## Run it + +```sh +pnpm install +pnpm --filter hub-deno-minimal dev +``` + +## Source + +[`examples/hub-deno-minimal`](https://github.com/devframes/devframe/tree/main/examples/hub-deno-minimal) diff --git a/docs/examples/hub-fastify-minimal.md b/docs/examples/hub-fastify-minimal.md new file mode 100644 index 00000000..d762f8db --- /dev/null +++ b/docs/examples/hub-fastify-minimal.md @@ -0,0 +1,26 @@ +--- +outline: deep +--- + +# hub-fastify-minimal + +The minimal [Fastify](https://fastify.dev) host for [`@devframes/hub`](/guide/hub): one `initHub()` call mounted through Fastify's connect-middleware layer, the UI supplied by `@devframes/hub-ui`. + +Package: `hub-fastify-minimal` · framework: **Fastify** + +## What it shows + +- `initHub({ base, devframes, ui: createUi() })` in `src/hub.ts`, memoized on `globalThis`. No transport option, so the socket rides Fastify's own server. +- Fastify is the `nodeMiddleware` host: `src/server.ts` registers `hub.nodeMiddleware` — the same `(req, res, next)` shape Vite's dev server consumes — through [`@fastify/middie`](https://github.com/fastify/middie). Requests under `${hub.base}` are served by the hub; the rest fall through `next()` to Fastify's routes. +- `hub.attach(fastify.server)` routes the HTTP server's upgrade events to the RPC socket at `${hub.base}__ws`, on the app's own origin — no side-car port. + +## Run it + +```sh +pnpm install +pnpm --filter hub-fastify-minimal dev +``` + +## Source + +[`examples/hub-fastify-minimal`](https://github.com/devframes/devframe/tree/main/examples/hub-fastify-minimal) diff --git a/docs/examples/hub-sveltekit-minimal.md b/docs/examples/hub-sveltekit-minimal.md new file mode 100644 index 00000000..3c099d33 --- /dev/null +++ b/docs/examples/hub-sveltekit-minimal.md @@ -0,0 +1,26 @@ +--- +outline: deep +--- + +# hub-sveltekit-minimal + +The minimal [SvelteKit](https://svelte.dev/docs/kit) host for [`@devframes/hub`](/guide/hub): one `initHub()` call behind a single catch-all endpoint, the UI supplied by `@devframes/hub-ui`. + +Package: `hub-sveltekit-minimal` · framework: **SvelteKit** + +## What it shows + +- `initHub({ base, devframes, ui: createUi() })` in `src/hub.ts`, memoized on `globalThis`. The RPC socket runs on a side-car port (`ws: { sidecar: true }`) advertised via `__connection.json` — SvelteKit's `+server.ts` handlers hand over `Request`s and never see WebSocket upgrades, so the hub takes a socket of its own. +- `src/routes/__devframes/[...path]/+server.ts` mounts the whole namespace: `fallback` answers every method with `hub.handler(event.request)`, and the `[...path]` rest param matches the namespace root as well as everything beneath it. +- The endpoint exports `trailingSlash = 'ignore'` so SvelteKit serves the hub's trailing-slash URLs (the standalone viewer and each frame SPA) verbatim instead of 308-redirecting them, and `src/app.html` injects `${hub.base}embedded.js` to mount the floating dock. + +## Run it + +```sh +pnpm install +pnpm --filter hub-sveltekit-minimal dev +``` + +## Source + +[`examples/hub-sveltekit-minimal`](https://github.com/devframes/devframe/tree/main/examples/hub-sveltekit-minimal) diff --git a/docs/examples/index.md b/docs/examples/index.md index 35e4065d..94b5d11b 100644 --- a/docs/examples/index.md +++ b/docs/examples/index.md @@ -23,6 +23,9 @@ The **minimal** family instead mounts one `initHub({ ui: createUi() })` handler | [hub-next-minimal](./hub-next-minimal) | Next.js | The hub handler on an App Router catch-all route. | | [hub-nitro-minimal](./hub-nitro-minimal) | Nitro | The hub handler on a Nitro catch-all route. | | [hub-hono-minimal](./hub-hono-minimal) | Hono | The hub handler on Hono, running on Node and Bun. | +| [hub-fastify-minimal](./hub-fastify-minimal) | Fastify | The hub handler on Fastify via `nodeMiddleware`. | +| [hub-sveltekit-minimal](./hub-sveltekit-minimal) | SvelteKit | The hub handler on a SvelteKit catch-all endpoint. | +| [hub-deno-minimal](./hub-deno-minimal) | Deno | The hub handler on `Deno.serve`, with a Deno fetch-upgrade socket. | | [hub-rsbuild-minimal](./hub-rsbuild-minimal) | Rsbuild | The hub handler on Rsbuild's dev middleware. | ## Run any example diff --git a/docs/guide/hub-initiate.md b/docs/guide/hub-initiate.md index 9499a080..c1abaec6 100644 --- a/docs/guide/hub-initiate.md +++ b/docs/guide/hub-initiate.md @@ -22,7 +22,7 @@ export const hub = initHub({ ## The shared socket -One transport serves the whole namespace, and the hub binds nothing on its own — the same four choices `initDevframe` offers, in the same precedence: `ws.port` pins a side-car, `server` shares the host's `node:http` upgrade at `__ws`, `ws: { sidecar: true }` takes a free port (for Next.js, Nitro and Rsbuild hosts, whose handlers never see upgrades), and passing none of them leaves the socket to the host: +One transport serves the whole namespace, and the hub binds nothing on its own — the same four choices `initDevframe` offers, in the same precedence: `ws.port` pins a side-car, `server` shares the host's `node:http` upgrade at `__ws`, `ws: { sidecar: true }` takes a free port (for Next.js, Nitro, SvelteKit and Rsbuild hosts, whose handlers never see upgrades), and passing none of them leaves the socket to the host — a Node host hands over its server with `hub.attach(server)`, and Bun and Deno hosts complete the upgrade on their own origin with `attachBunWsTransport` / `attachDenoWsTransport`: ```ts import { serve } from '@hono/node-server' @@ -125,4 +125,4 @@ Hosts that assemble `createHubContext` + `ctx.install` themselves (with their ow const hub = initHub({ base: DEVFRAMES_HUB_BASE, context: ctx }) ``` -The instance then serves the hub-level endpoints and transport only; serve each frame's meta from `hub.connectionMeta()` yourself. The two reference examples — `examples/hub-vite` and `examples/hub-next` — use the declarative mode with their own hand-built viewer UIs, while the `hub-*-minimal` family (`hub-vite-minimal`, `hub-next-minimal`, `hub-nitro-minimal`, `hub-hono-minimal`, `hub-rsbuild-minimal`) shows the minimal `createUi()` mount across frameworks (the Hono one on Node and Bun). +The instance then serves the hub-level endpoints and transport only; serve each frame's meta from `hub.connectionMeta()` yourself. The two reference examples — `examples/hub-vite` and `examples/hub-next` — use the declarative mode with their own hand-built viewer UIs, while the `hub-*-minimal` family (`hub-vite-minimal`, `hub-next-minimal`, `hub-nitro-minimal`, `hub-hono-minimal`, `hub-fastify-minimal`, `hub-sveltekit-minimal`, `hub-deno-minimal`, `hub-rsbuild-minimal`) shows the minimal `createUi()` mount across frameworks (the Hono one on Node and Bun, the Deno one on `Deno.serve`). diff --git a/examples/hub-deno-minimal/README.md b/examples/hub-deno-minimal/README.md new file mode 100644 index 00000000..28982799 --- /dev/null +++ b/examples/hub-deno-minimal/README.md @@ -0,0 +1,16 @@ +# hub-deno-minimal + +The minimal [Deno](https://deno.com) host for `@devframes/hub` — one `initHub()` call served through `Deno.serve`, with the RPC socket riding a same-origin fetch upgrade. + +```sh +pnpm --filter hub-deno-minimal dev +``` + +Open — the host page carries the floating dock via one script tag — or for the standalone viewer. + +## How it works + +- [`src/hub.ts`](./src/hub.ts) — `initHub({ devframes, ui: createUi({ branding }) })` (rebranded to Deno's own green, `#70ffaf`), memoized on `globalThis` so a dev-time reload reuses the live hub. No `ws` option is passed, so the entry wires the socket itself. +- [`src/server.ts`](./src/server.ts) — Deno serves HTTP through `Deno.serve(options, handler)` (web `Request` → `Response`), and the whole namespace flows through `hub.handler(request)`. WebSockets arrive as fetch upgrades rather than `node:http` `upgrade` events, so the entry binds Deno's own transport to the hub context with `createContextRpcServer` + `attachDenoWsTransport` (crossws' Deno adapter) and answers `/__devframes/__ws` itself — the socket rides the app's own origin with no side-car port. crossws attaches the socket to the `Response` its `handleUpgrade` returns, so there is no separate `websocket` handler object to register. + +The same `initHub` instance mounts identically on Vite, Hono, Nitro, Fastify, and Next.js — see the sibling examples. diff --git a/examples/hub-deno-minimal/package.json b/examples/hub-deno-minimal/package.json new file mode 100644 index 00000000..71a983bd --- /dev/null +++ b/examples/hub-deno-minimal/package.json @@ -0,0 +1,28 @@ +{ + "name": "hub-deno-minimal", + "type": "module", + "version": "0.9.1", + "private": true, + "description": "Minimal Deno host that serves the devframe hub over a fetch-upgrade WebSocket.", + "scripts": { + "dev": "deno run --allow-net --allow-read --allow-env --node-modules-dir src/server.ts", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@devframes/hub": "workspace:*", + "@devframes/hub-ui": "workspace:*", + "@devframes/plugin-a11y": "workspace:*", + "@devframes/plugin-assets": "workspace:*", + "@devframes/plugin-code-server": "workspace:*", + "@devframes/plugin-data-inspector": "workspace:*", + "@devframes/plugin-git": "workspace:*", + "@devframes/plugin-inspect": "workspace:*", + "@devframes/plugin-messages": "workspace:*", + "@devframes/plugin-og": "workspace:*", + "@devframes/plugin-terminals": "workspace:*", + "devframe": "workspace:*" + }, + "devDependencies": { + "@types/node": "catalog:types" + } +} diff --git a/examples/hub-deno-minimal/src/hub.ts b/examples/hub-deno-minimal/src/hub.ts new file mode 100644 index 00000000..f40f2fbc --- /dev/null +++ b/examples/hub-deno-minimal/src/hub.ts @@ -0,0 +1,82 @@ +import type { HubInstance } from '@devframes/hub/initiate' +import { createUi } from '@devframes/hub-ui' +import { DEVFRAMES_HUB_BASE, initHub } from '@devframes/hub/initiate' +import { createA11yDevframe } 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 { 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' + +// One `initHub` call, memoized on globalThis so a dev-time reload returns the +// live hub instead of leaking transports. No `ws` option is passed: on Deno, +// WebSockets arrive as fetch upgrades rather than `node:http` `upgrade` +// events, so `src/server.ts` binds Deno's own transport to the hub context +// and answers the upgrade route itself — the socket rides the app's own +// origin with no side-car port. +const globalRef = globalThis as { __hubDenoMinimal?: HubInstance } + +export const hub: HubInstance = globalRef.__hubDenoMinimal ??= initHub({ + base: DEVFRAMES_HUB_BASE, + // Every built-in plugin, dogfooded end to end through the hub mount path. + // `data-inspector`'s default id carries `:` (a route-param marker), so it + // gets a colon-free id override to be a valid `/` segment; the + // assets watcher is off since this host demonstrates mounting, not authoring. + devframes: [ + createGitDevframe(), + createTerminalsDevframe(), + createCodeServerDevframe(), + createInspectDevframe(), + createDataInspectorDevframe({ id: 'devframes_plugin_data-inspector' }), + createA11yDevframe(), + createMessagesDevframe(), + createOgDevframe(), + createAssetsDevframe({ watch: false }), + ], + // Rebrand the reference UI to Deno's own navy — one field, no CSS: + // `createUi`'s `branding` option publishes `ConnectionMeta.configs.ui.branding`, + // which the dock reads at connect time and feeds into `--devframe-primary` + // (see `@devframes/hub-ui`'s `primary-ramp.css`). + ui: createUi({ branding: { primaryColor: '#70ffaf', productName: 'Devframes on Deno' } }), + // Gate with devframe's interactive OTP (the default). The hub prints a + // 6-digit code + magic link on startup, and the reference UI's authorization + // view exchanges it for a bearer token. See docs/guide/security.md. + configure(ctx) { + ctx.commands.register({ + id: 'example:hub-deno-minimal:ping', + title: 'Deno Hub · Ping', + icon: 'ph:bell-duotone', + category: 'kit', + handler: () => 'pong', + }) + ctx.rpc.register({ + name: 'example:hub-deno-minimal:probe', + type: 'query', + jsonSerializable: true, + handler: () => 'pong', + }) + }, +}) + +/** The host page — one script tag turns any page into a devtools host. */ +export const hostPage = ` + + + + + Deno Devframe Hub + + +

Deno Devframe Hub

+

This page is the host app. The devtools ride along:

+ + + +` diff --git a/examples/hub-deno-minimal/src/server.ts b/examples/hub-deno-minimal/src/server.ts new file mode 100644 index 00000000..5ef37306 --- /dev/null +++ b/examples/hub-deno-minimal/src/server.ts @@ -0,0 +1,70 @@ +import { createContextRpcServer } from 'devframe/internal' +import { createInteractiveAuth } from 'devframe/recipes/interactive-auth' +import { attachDenoWsTransport } from 'devframe/rpc/transports/ws-deno' +import { hostPage, hub } from './hub' + +// `Deno` is a global on the Deno runtime only; this is the Deno entry. Declare +// the slice this file uses so `tsc` (Node types only, no Deno lib) can check +// it — typing the handler's params here also keeps them from being `any`. +declare const Deno: { + serve: ( + options: { port: number, hostname?: string }, + handler: (request: Request, info: unknown) => Response | Promise, + ) => { finished: Promise, shutdown: () => Promise, addr: { port: number } } + env: { get: (key: string) => string | undefined } +} + +/** + * The Deno entry. Deno serves HTTP through `Deno.serve(options, handler)` (web + * Request → Response), but WebSockets arrive as fetch upgrades rather than + * `node:http` `upgrade` events — so this host binds Deno's own transport to + * the hub context with two public primitives: `createContextRpcServer` (the + * session/auth wiring every devframe transport shares) and + * `attachDenoWsTransport` (crossws' Deno adapter). crossws attaches the socket + * to the `Response` its `handleUpgrade` returns, so there is no separate + * websocket handler object to register. + * + * The hub advertises `/__devframes/__ws` on the app's own origin, so the + * browser client needs no per-runtime knowledge — this file only has to + * answer that route. + */ +export async function startDenoServer(port: number): Promise<{ port: number, close: () => Promise }> { + await hub.ready + const context = await hub.context + // Bind the same interactive-OTP handler the gated `initHub` uses to Deno's + // own WS transport, sharing the context's auth storage and one-time code so + // a client authorizes once regardless of which surface serves it. + const core = createContextRpcServer({ context, auth: createInteractiveAuth(context) }) + const tier = await attachDenoWsTransport(core) + const upgradePath = `${hub.base}__ws` + const baseNoSlash = hub.base.replace(/\/$/, '') + + const server = Deno.serve({ port, hostname: '0.0.0.0' }, (request, info) => { + const { pathname } = new URL(request.url) + if (pathname === upgradePath && request.headers.get('upgrade')?.toLowerCase() === 'websocket') + return tier.handleUpgrade(request, info) + // The whole hub namespace behind one delegation — frame SPAs, + // __connection.json, __index.json, embedded.js, __client-imports.js. + if (pathname === baseNoSlash || pathname.startsWith(hub.base)) + return hub.handler(request) + if (pathname === '/') + return new Response(hostPage, { headers: { 'content-type': 'text/html; charset=utf-8' } }) + return new Response('Not found', { status: 404 }) + }) + + return { + port: server.addr.port, + close: async () => { + await tier.close() + await hub.close() + await server.shutdown() + }, + } +} + +if (import.meta.main) { + void startDenoServer(Number(Deno.env.get('PORT') ?? 5182)).then(({ port }) => { + // eslint-disable-next-line no-console + console.log(`deno-devframe-hub on http://localhost:${port} — devtools at /__devframes/`) + }) +} diff --git a/examples/hub-deno-minimal/tsconfig.json b/examples/hub-deno-minimal/tsconfig.json new file mode 100644 index 00000000..11916e28 --- /dev/null +++ b/examples/hub-deno-minimal/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "lib": [ + "esnext", + "dom" + ], + "types": [ + "node" + ] + }, + "include": [ + "src" + ], + "exclude": [ + "dist", + "node_modules" + ] +} diff --git a/examples/hub-fastify-minimal/README.md b/examples/hub-fastify-minimal/README.md new file mode 100644 index 00000000..369f9076 --- /dev/null +++ b/examples/hub-fastify-minimal/README.md @@ -0,0 +1,16 @@ +# hub-fastify-minimal + +The minimal [Fastify](https://fastify.dev) host for `@devframes/hub` — one `initHub()` call mounted through Fastify's connect-middleware layer, with the RPC socket riding Fastify's own HTTP server. + +```sh +pnpm --filter hub-fastify-minimal dev +``` + +Open — the host page carries the floating dock via one script tag — or for the standalone viewer. + +## How it works + +- [`src/hub.ts`](./src/hub.ts) — `initHub({ devframes, ui: createUi({ branding }) })` (rebranded to Fastify's own black, `#2f2f2f`), memoized on `globalThis` so a dev-time reload reuses the live hub. No `ws` option is passed, so the hub binds nothing on its own. +- [`src/server.ts`](./src/server.ts) — Fastify is the `nodeMiddleware` host: rather than bridging every request to `hub.handler`, it registers `hub.nodeMiddleware` — the same `(req, res, next)` shape a Vite dev server consumes — through [`@fastify/middie`](https://github.com/fastify/middie). Requests under `/__devframes/` are served by the hub; everything else falls through `next()` to Fastify's own routes. The RPC socket rides Fastify's own `node:http` server: `fastify.server` is that server, and `hub.attach(server)` routes its upgrade events to `/__devframes/__ws` on the app's origin — no side-car port. + +The same `initHub` instance mounts identically on Vite, Hono, Nitro, and Next.js — see the sibling examples. diff --git a/examples/hub-fastify-minimal/package.json b/examples/hub-fastify-minimal/package.json new file mode 100644 index 00000000..61839125 --- /dev/null +++ b/examples/hub-fastify-minimal/package.json @@ -0,0 +1,31 @@ +{ + "name": "hub-fastify-minimal", + "type": "module", + "version": "0.9.1", + "private": true, + "description": "Minimal Fastify host that mounts the devframe hub with nodeMiddleware.", + "scripts": { + "dev": "tsx src/server.ts", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@devframes/hub": "workspace:*", + "@devframes/hub-ui": "workspace:*", + "@devframes/plugin-a11y": "workspace:*", + "@devframes/plugin-assets": "workspace:*", + "@devframes/plugin-code-server": "workspace:*", + "@devframes/plugin-data-inspector": "workspace:*", + "@devframes/plugin-git": "workspace:*", + "@devframes/plugin-inspect": "workspace:*", + "@devframes/plugin-messages": "workspace:*", + "@devframes/plugin-og": "workspace:*", + "@devframes/plugin-terminals": "workspace:*", + "@fastify/middie": "catalog:deps", + "devframe": "workspace:*", + "fastify": "catalog:deps" + }, + "devDependencies": { + "@types/node": "catalog:types", + "tsx": "catalog:build" + } +} diff --git a/examples/hub-fastify-minimal/src/hub.ts b/examples/hub-fastify-minimal/src/hub.ts new file mode 100644 index 00000000..6f8756ad --- /dev/null +++ b/examples/hub-fastify-minimal/src/hub.ts @@ -0,0 +1,75 @@ +import type { HubInstance } from '@devframes/hub/initiate' +import { createUi } from '@devframes/hub-ui' +import { DEVFRAMES_HUB_BASE, initHub } from '@devframes/hub/initiate' +import { createA11yDevframe } 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 { 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' + +// One `initHub` call, memoized on globalThis so a dev-time module reload +// returns the live hub instead of leaking transports. No `ws` option is +// passed, so the hub binds nothing on its own — `src/server.ts` hands it +// Fastify's own `node:http` server with `hub.attach(server)` once it exists, +// putting the RPC socket on the app's own origin with no side-car port. +const globalRef = globalThis as { __hubFastifyMinimal?: HubInstance } + +export const hub: HubInstance = globalRef.__hubFastifyMinimal ??= initHub({ + base: DEVFRAMES_HUB_BASE, + // Every built-in plugin, dogfooded end to end through the hub mount path. + // `data-inspector`'s default id carries `:` (a route-param marker), so it + // gets a colon-free id override to be a valid `/` segment; the + // assets watcher is off since this host demonstrates mounting, not authoring. + devframes: [ + createGitDevframe(), + createTerminalsDevframe(), + createCodeServerDevframe(), + createInspectDevframe(), + createDataInspectorDevframe({ id: 'devframes_plugin_data-inspector' }), + createA11yDevframe(), + createMessagesDevframe(), + createOgDevframe(), + createAssetsDevframe({ watch: false }), + ], + // Rebrand the reference UI to Fastify's own black — one field, no CSS: + // `createUi`'s `branding` option publishes `ConnectionMeta.configs.ui.branding`, + // which the dock reads at connect time and feeds into `--devframe-primary` + // (see `@devframes/hub-ui`'s `primary-ramp.css`). + ui: createUi({ branding: { primaryColor: '#2f2f2f', productName: 'Devframes on Fastify' } }), + // Gate with devframe's interactive OTP (the default). The hub prints a + // 6-digit code + magic link on startup, and the reference UI's authorization + // view exchanges it for a bearer token. See docs/guide/security.md. + configure(ctx) { + ctx.commands.register({ + id: 'example:hub-fastify-minimal:ping', + title: 'Fastify Hub · Ping', + icon: 'ph:bell-duotone', + category: 'kit', + handler: () => 'pong', + }) + }, +}) + +/** The host page — one script tag turns any page into a devtools host. */ +export const hostPage = ` + + + + + Fastify Devframe Hub + + +

Fastify Devframe Hub

+

This page is the host app. The devtools ride along:

+ + + +` diff --git a/examples/hub-fastify-minimal/src/server.ts b/examples/hub-fastify-minimal/src/server.ts new file mode 100644 index 00000000..8b650c5a --- /dev/null +++ b/examples/hub-fastify-minimal/src/server.ts @@ -0,0 +1,46 @@ +import process from 'node:process' +import middie from '@fastify/middie' +import Fastify from 'fastify' +import { hostPage, hub } from './hub' + +// Fastify is the connect-middleware host: rather than bridging every request +// to `hub.handler` (web Request → Response), it registers `hub.nodeMiddleware` +// — the same `(req, res, next)` shape a Vite dev server consumes — through +// `@fastify/middie`. Requests under `/__devframes/` are served by the hub; +// everything else falls through `next()` to Fastify's own routes. +// +// The RPC socket rides Fastify's own `node:http` server: `fastify.server` is +// that server, and `hub.attach(server)` routes its `upgrade` events to +// `/__devframes/__ws` on the app's origin — no side-car port to discover. +export async function startFastifyServer(port: number): Promise<{ port: number, close: () => Promise }> { + const app = Fastify() + await app.register(middie) + app.use(hub.nodeMiddleware) + + app.get('/', (_request, reply) => { + reply.type('text/html').send(hostPage) + }) + + const detach = hub.attach(app.server) + await app.listen({ port, host: '0.0.0.0' }) + const address = app.server.address() + const boundPort = typeof address === 'object' && address ? address.port : port + + return { + port: boundPort, + close: async () => { + detach() + await hub.close() + await app.close() + }, + } +} + +if (import.meta.url === `file://${process.argv[1]}`) { + const port = Number(process.env.PORT ?? 5183) + void startFastifyServer(port).then(({ port }) => { + // eslint-disable-next-line no-console + console.log(`fastify-devframe-hub on http://localhost:${port} — devtools at /__devframes/`) + }) + process.on('SIGINT', () => process.exit(0)) +} diff --git a/examples/hub-fastify-minimal/tsconfig.json b/examples/hub-fastify-minimal/tsconfig.json new file mode 100644 index 00000000..11916e28 --- /dev/null +++ b/examples/hub-fastify-minimal/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "lib": [ + "esnext", + "dom" + ], + "types": [ + "node" + ] + }, + "include": [ + "src" + ], + "exclude": [ + "dist", + "node_modules" + ] +} diff --git a/examples/hub-sveltekit-minimal/.gitignore b/examples/hub-sveltekit-minimal/.gitignore new file mode 100644 index 00000000..5318938b --- /dev/null +++ b/examples/hub-sveltekit-minimal/.gitignore @@ -0,0 +1,3 @@ +.svelte-kit +.output +build diff --git a/examples/hub-sveltekit-minimal/README.md b/examples/hub-sveltekit-minimal/README.md new file mode 100644 index 00000000..830ae71d --- /dev/null +++ b/examples/hub-sveltekit-minimal/README.md @@ -0,0 +1,17 @@ +# hub-sveltekit-minimal + +The minimal [SvelteKit](https://svelte.dev/docs/kit) host for `@devframes/hub`: one `initHub()` call behind a single catch-all endpoint, the whole devtools installation live under `/__devframes/`. + +```sh +pnpm --filter hub-sveltekit-minimal dev +``` + +Open — the host page carries the floating dock via one script tag — or for the standalone viewer. + +## How it works + +- [`src/hub.ts`](./src/hub.ts) — `initHub({ devframes, ui: createUi({ branding }) })` (rebranded to Svelte's own orange, `#ff3e00`), memoized on `globalThis` so SvelteKit's dev-time reload reuses the live hub. The RPC socket runs on a side-car port (`ws: { sidecar: true }`) advertised via `__connection.json` — SvelteKit's `+server.ts` handlers hand over `Request`s and never see WebSocket upgrades, so the hub takes a socket of its own; the browser client discovers it automatically. +- [`src/routes/__devframes/[...path]/+server.ts`](./src/routes/__devframes/%5B...path%5D/+server.ts) — the whole namespace behind one catch-all: `fallback` answers every method with `hub.handler(event.request)`, web-standard `Request` in, `Response` out. Its `[...path]` rest param matches the namespace root (`/__devframes/`) as well as everything beneath it. It exports `trailingSlash = 'ignore'` so SvelteKit serves the hub's trailing-slash URLs (the standalone viewer and each frame SPA) verbatim instead of 308-redirecting them. +- [`src/app.html`](./src/app.html) injects `/__devframes/embedded.js` — the one script tag that mounts the floating dock on every page. + +The same `initHub` instance mounts identically on Vite, Hono, Nitro, Fastify, and Next.js — see the sibling examples. diff --git a/examples/hub-sveltekit-minimal/package.json b/examples/hub-sveltekit-minimal/package.json new file mode 100644 index 00000000..ff5511d3 --- /dev/null +++ b/examples/hub-sveltekit-minimal/package.json @@ -0,0 +1,33 @@ +{ + "name": "hub-sveltekit-minimal", + "type": "module", + "version": "0.9.1", + "private": true, + "description": "Minimal SvelteKit host that mounts the devframe hub on a catch-all endpoint.", + "scripts": { + "dev": "vite dev", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@devframes/hub": "workspace:*", + "@devframes/hub-ui": "workspace:*", + "@devframes/plugin-a11y": "workspace:*", + "@devframes/plugin-assets": "workspace:*", + "@devframes/plugin-code-server": "workspace:*", + "@devframes/plugin-data-inspector": "workspace:*", + "@devframes/plugin-git": "workspace:*", + "@devframes/plugin-inspect": "workspace:*", + "@devframes/plugin-messages": "workspace:*", + "@devframes/plugin-og": "workspace:*", + "@devframes/plugin-terminals": "workspace:*", + "devframe": "workspace:*" + }, + "devDependencies": { + "@sveltejs/adapter-node": "catalog:build", + "@sveltejs/kit": "catalog:build", + "@sveltejs/vite-plugin-svelte": "catalog:frontend", + "@types/node": "catalog:types", + "svelte": "catalog:frontend", + "vite": "catalog:build" + } +} diff --git a/examples/hub-sveltekit-minimal/src/app.d.ts b/examples/hub-sveltekit-minimal/src/app.d.ts new file mode 100644 index 00000000..f8810623 --- /dev/null +++ b/examples/hub-sveltekit-minimal/src/app.d.ts @@ -0,0 +1,6 @@ +// See https://svelte.dev/docs/kit/types#app.d.ts +declare global { + namespace App {} +} + +export {} diff --git a/examples/hub-sveltekit-minimal/src/app.html b/examples/hub-sveltekit-minimal/src/app.html new file mode 100644 index 00000000..27ac87af --- /dev/null +++ b/examples/hub-sveltekit-minimal/src/app.html @@ -0,0 +1,15 @@ + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + + + diff --git a/examples/hub-sveltekit-minimal/src/hub.ts b/examples/hub-sveltekit-minimal/src/hub.ts new file mode 100644 index 00000000..60f3856a --- /dev/null +++ b/examples/hub-sveltekit-minimal/src/hub.ts @@ -0,0 +1,57 @@ +import type { HubInstance } from '@devframes/hub/initiate' +import { createUi } from '@devframes/hub-ui' +import { DEVFRAMES_HUB_BASE, initHub } from '@devframes/hub/initiate' +import { createA11yDevframe } 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 { 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' + +// One `initHub` call, memoized on globalThis so SvelteKit's dev-time module +// reload returns the live hub instead of leaking transports. The RPC socket +// runs on a side-car port advertised via __connection.json: SvelteKit's +// `+server.ts` handlers hand over `Request`s and never see WebSocket +// upgrades, so `ws.sidecar` asks for a socket of its own — the browser client +// discovers it automatically. +const globalRef = globalThis as { __hubSvelteKitMinimal?: HubInstance } + +export const hub: HubInstance = globalRef.__hubSvelteKitMinimal ??= initHub({ + base: DEVFRAMES_HUB_BASE, + ws: { sidecar: true }, + // Every built-in plugin, dogfooded end to end through the hub mount path. + // `data-inspector`'s default id carries `:` (a route-param marker), so it + // gets a colon-free id override to be a valid `/` segment; the + // assets watcher is off since this host demonstrates mounting, not authoring. + devframes: [ + createGitDevframe(), + createTerminalsDevframe(), + createCodeServerDevframe(), + createInspectDevframe(), + createDataInspectorDevframe({ id: 'devframes_plugin_data-inspector' }), + createA11yDevframe(), + createMessagesDevframe(), + createOgDevframe(), + createAssetsDevframe({ watch: false }), + ], + // Rebrand the reference UI to Svelte's own orange — one field, no CSS: + // `createUi`'s `branding` option publishes `ConnectionMeta.configs.ui.branding`, + // which the dock reads at connect time and feeds into `--devframe-primary` + // (see `@devframes/hub-ui`'s `primary-ramp.css`). + ui: createUi({ branding: { primaryColor: '#ff3e00', productName: 'Devframes on SvelteKit' } }), + // Gate with devframe's interactive OTP (the default). The hub prints a + // 6-digit code + magic link on startup, and the reference UI's authorization + // view exchanges it for a bearer token. See docs/guide/security.md. + configure(ctx) { + ctx.commands.register({ + id: 'example:hub-sveltekit-minimal:ping', + title: 'SvelteKit Hub · Ping', + icon: 'ph:bell-duotone', + category: 'kit', + handler: () => 'pong', + }) + }, +}) diff --git a/examples/hub-sveltekit-minimal/src/routes/+page.svelte b/examples/hub-sveltekit-minimal/src/routes/+page.svelte new file mode 100644 index 00000000..a5e81e26 --- /dev/null +++ b/examples/hub-sveltekit-minimal/src/routes/+page.svelte @@ -0,0 +1,13 @@ +
+

SvelteKit Devframe Hub

+

This page is the host app. The devtools ride along:

+ +
diff --git a/examples/hub-sveltekit-minimal/src/routes/__devframes/[...path]/+server.ts b/examples/hub-sveltekit-minimal/src/routes/__devframes/[...path]/+server.ts new file mode 100644 index 00000000..bade5293 --- /dev/null +++ b/examples/hub-sveltekit-minimal/src/routes/__devframes/[...path]/+server.ts @@ -0,0 +1,16 @@ +import type { RequestHandler } from '@sveltejs/kit' +import { hub } from '../../../hub' + +// Serve both `/__devframes/foo` and `/__devframes/foo/` verbatim. SvelteKit +// defaults to `trailingSlash: 'never'`, which would 308-redirect the hub's +// trailing-slash URLs (the standalone viewer at `/__devframes/` and each +// frame SPA at `/__devframes//`) and break the SPAs' relative asset +// resolution — the hub owns the exact paths, so opt its routes out. +export const trailingSlash = 'ignore' + +// The whole hub namespace behind one catch-all route: web-standard Request +// in, Response out. `fallback` answers every method, and the `[...path]` rest +// param matches the namespace root (`/__devframes/`) as well as everything +// beneath it. Frame SPAs, __connection.json, __index.json, embedded.js, +// __client-imports.js — all flow through here. +export const fallback: RequestHandler = ({ request }) => hub.handler(request) diff --git a/examples/hub-sveltekit-minimal/svelte.config.js b/examples/hub-sveltekit-minimal/svelte.config.js new file mode 100644 index 00000000..2eac065a --- /dev/null +++ b/examples/hub-sveltekit-minimal/svelte.config.js @@ -0,0 +1,10 @@ +import adapter from '@sveltejs/adapter-node' +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +/** @type {import('@sveltejs/kit').Config} */ +export default { + preprocess: vitePreprocess(), + kit: { + adapter: adapter(), + }, +} diff --git a/examples/hub-sveltekit-minimal/tsconfig.json b/examples/hub-sveltekit-minimal/tsconfig.json new file mode 100644 index 00000000..8e330a33 --- /dev/null +++ b/examples/hub-sveltekit-minimal/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "lib": [ + "esnext", + "dom" + ], + "types": [ + "node" + ] + }, + "include": [ + "src/**/*.ts", + "vite.config.ts" + ], + "exclude": [ + "dist", + "node_modules", + ".svelte-kit" + ] +} diff --git a/examples/hub-sveltekit-minimal/vite.config.ts b/examples/hub-sveltekit-minimal/vite.config.ts new file mode 100644 index 00000000..dd1b8b7f --- /dev/null +++ b/examples/hub-sveltekit-minimal/vite.config.ts @@ -0,0 +1,6 @@ +import { sveltekit } from '@sveltejs/kit/vite' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [sveltekit()], +}) diff --git a/knip.jsonc b/knip.jsonc index 0b1f6a81..ed290803 100644 --- a/knip.jsonc +++ b/knip.jsonc @@ -102,6 +102,12 @@ "config": ["src/client/postcss.config.mjs"] } }, + // The Deno entry runs via `deno run src/server.ts`, a command string knip + // doesn't parse (unlike `tsx`/`bun`), so name the entry explicitly — it + // pulls in `src/hub.ts` and every plugin dependency from there. + "examples/hub-deno-minimal": { + "entry": ["src/server.ts"] + }, "packages/devframe": { // Every `package.json#exports` subpath maps to one of these source // files (see `tsdown.config.ts`'s `serverEntries`/`clientEntries`). @@ -122,7 +128,7 @@ "src/recipes/{common-rpc-functions,interactive-auth}.ts", "src/rpc/{index,client,server}.ts", "src/rpc/dump/index.ts", - "src/rpc/transports/{sse-client,sse-server,ws-bun,ws-client,ws-server}.ts", + "src/rpc/transports/{sse-client,sse-server,ws-bun,ws-deno,ws-client,ws-server}.ts", "src/types/index.ts", "src/utils/*.ts" ] diff --git a/packages/devframe/package.json b/packages/devframe/package.json index d0303199..9beab9cb 100644 --- a/packages/devframe/package.json +++ b/packages/devframe/package.json @@ -41,6 +41,7 @@ "./rpc/transports/sse-client": "./dist/rpc/transports/sse-client.mjs", "./rpc/transports/sse-server": "./dist/rpc/transports/sse-server.mjs", "./rpc/transports/ws-bun": "./dist/rpc/transports/ws-bun.mjs", + "./rpc/transports/ws-deno": "./dist/rpc/transports/ws-deno.mjs", "./rpc/transports/ws-client": "./dist/rpc/transports/ws-client.mjs", "./rpc/transports/ws-server": "./dist/rpc/transports/ws-server.mjs", "./types": "./dist/types/index.mjs", diff --git a/packages/devframe/src/rpc/transports/ws-deno.ts b/packages/devframe/src/rpc/transports/ws-deno.ts new file mode 100644 index 00000000..4d080e40 --- /dev/null +++ b/packages/devframe/src/rpc/transports/ws-deno.ts @@ -0,0 +1,59 @@ +import type { ContextRpcServer } from '../../node/rpc-core' +import type { WsOriginRegistry } from './ws-server' +import { createWsRpcPeerHooks, isAllowedOrigin } from './ws-server' + +export interface AttachDenoWsTransportOptions { + /** Same contract as `WsRpcTransportOptions.allowedOrigins`. */ + allowedOrigins?: readonly string[] | WsOriginRegistry | false +} + +export interface DenoWsTier { + /** + * Complete a WS upgrade request — `Deno.serve`'s handler info as the 2nd + * argument. Unlike Bun, Deno's adapter attaches the socket to the returned + * `Response` itself, so there is no `websocket` handler object to register. + */ + handleUpgrade: (request: Request, info: unknown) => Promise + close: () => Promise +} + +/** + * The Deno fetch-upgrade WebSocket tier for `initDevframe` / `initHub` — the + * same RPC peer wiring as `attachWsRpcTransport`, driven by crossws's Deno + * adapter so upgrades complete through `handleUpgrade(request, info)` on the + * app's own origin, with no side-car server. Load it dynamically so the Deno + * adapter never enters a Node-only bundle path. + */ +export async function attachDenoWsTransport( + core: ContextRpcServer, + options: AttachDenoWsTransportOptions = {}, +): Promise { + const { default: denoAdapter } = await import('crossws/adapters/deno') + const { allowedOrigins } = options + + const ws = denoAdapter({ + hooks: { + ...createWsRpcPeerHooks(core.rpcGroup, { + onConnected: core.onConnected, + onDisconnected: core.onDisconnected, + }), + // The same origin policy `routeUpgrades` applies for the Node + // transport, enforced at the upgrade hook since Deno upgrades arrive + // as fetch requests rather than `upgrade` socket events. + upgrade(request) { + const origin = request.headers.get('origin') ?? undefined + const allowed = allowedOrigins && !Array.isArray(allowedOrigins) + ? (allowedOrigins as WsOriginRegistry).isAllowed(origin) + : isAllowedOrigin(origin, (allowedOrigins as readonly string[] | false | undefined) || []) + if (allowedOrigins !== false && !allowed) + return new Response('Forbidden', { status: 403 }) + }, + }, + }) + + return { + handleUpgrade: (request, info) => + ws.handleUpgrade(request, info as Parameters[1]), + close: () => ws.close(), + } +} diff --git a/packages/devframe/tsdown.config.ts b/packages/devframe/tsdown.config.ts index cc4a01e7..36ac4568 100644 --- a/packages/devframe/tsdown.config.ts +++ b/packages/devframe/tsdown.config.ts @@ -96,6 +96,7 @@ const serverEntries = { 'rpc/transports/sse-client': 'src/rpc/transports/sse-client.ts', 'rpc/transports/sse-server': 'src/rpc/transports/sse-server.ts', 'rpc/transports/ws-bun': 'src/rpc/transports/ws-bun.ts', + 'rpc/transports/ws-deno': 'src/rpc/transports/ws-deno.ts', 'rpc/transports/ws-client': 'src/rpc/transports/ws-client.ts', 'rpc/transports/ws-server': 'src/rpc/transports/ws-server.ts', 'node/index': 'src/node/index.ts', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8464b99a..98cabd87 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,6 +15,12 @@ catalogs: '@rsbuild/core': specifier: ^2.1.11 version: 2.1.11 + '@sveltejs/adapter-node': + specifier: ^5.3.3 + version: 5.5.7 + '@sveltejs/kit': + specifier: ^2.46.4 + version: 2.70.2 '@vitejs/plugin-vue': specifier: ^6.0.8 version: 6.0.8 @@ -46,6 +52,9 @@ catalogs: specifier: ^2.11.14 version: 2.11.14 deps: + '@fastify/middie': + specifier: ^9.0.3 + version: 9.3.3 '@hono/node-server': specifier: ^1.19.17 version: 1.19.17 @@ -70,6 +79,9 @@ catalogs: destr: specifier: ^2.0.5 version: 2.0.5 + fastify: + specifier: ^5.7.1 + version: 5.12.0 get-port-please: specifier: ^3.2.0 version: 3.2.0 @@ -575,6 +587,101 @@ importers: specifier: catalog:deps version: 8.21.3 + examples/hub-deno-minimal: + dependencies: + '@devframes/hub': + specifier: workspace:* + version: link:../../packages/hub + '@devframes/hub-ui': + specifier: workspace:* + version: link:../../packages/hub-ui + '@devframes/plugin-a11y': + specifier: workspace:* + version: link:../../plugins/a11y + '@devframes/plugin-assets': + specifier: workspace:* + version: link:../../plugins/assets + '@devframes/plugin-code-server': + specifier: workspace:* + version: link:../../plugins/code-server + '@devframes/plugin-data-inspector': + specifier: workspace:* + version: link:../../plugins/data-inspector + '@devframes/plugin-git': + specifier: workspace:* + version: link:../../plugins/git + '@devframes/plugin-inspect': + specifier: workspace:* + version: link:../../plugins/inspect + '@devframes/plugin-messages': + specifier: workspace:* + version: link:../../plugins/messages + '@devframes/plugin-og': + specifier: workspace:* + version: link:../../plugins/og + '@devframes/plugin-terminals': + specifier: workspace:* + version: link:../../plugins/terminals + devframe: + specifier: workspace:* + version: link:../../packages/devframe + devDependencies: + '@types/node': + specifier: catalog:types + version: 26.2.0 + + examples/hub-fastify-minimal: + dependencies: + '@devframes/hub': + specifier: workspace:* + version: link:../../packages/hub + '@devframes/hub-ui': + specifier: workspace:* + version: link:../../packages/hub-ui + '@devframes/plugin-a11y': + specifier: workspace:* + version: link:../../plugins/a11y + '@devframes/plugin-assets': + specifier: workspace:* + version: link:../../plugins/assets + '@devframes/plugin-code-server': + specifier: workspace:* + version: link:../../plugins/code-server + '@devframes/plugin-data-inspector': + specifier: workspace:* + version: link:../../plugins/data-inspector + '@devframes/plugin-git': + specifier: workspace:* + version: link:../../plugins/git + '@devframes/plugin-inspect': + specifier: workspace:* + version: link:../../plugins/inspect + '@devframes/plugin-messages': + specifier: workspace:* + version: link:../../plugins/messages + '@devframes/plugin-og': + specifier: workspace:* + version: link:../../plugins/og + '@devframes/plugin-terminals': + specifier: workspace:* + version: link:../../plugins/terminals + '@fastify/middie': + specifier: catalog:deps + version: 9.3.3 + devframe: + specifier: workspace:* + version: link:../../packages/devframe + fastify: + specifier: catalog:deps + version: 5.12.0 + devDependencies: + '@types/node': + specifier: catalog:types + version: 26.2.0 + tsx: + specifier: catalog:build + version: 4.23.12 + examples/hub-hono-minimal: dependencies: '@devframes/hub': @@ -889,6 +996,64 @@ importers: specifier: catalog:types version: 26.2.0 + examples/hub-sveltekit-minimal: + dependencies: + '@devframes/hub': + specifier: workspace:* + version: link:../../packages/hub + '@devframes/hub-ui': + specifier: workspace:* + version: link:../../packages/hub-ui + '@devframes/plugin-a11y': + specifier: workspace:* + version: link:../../plugins/a11y + '@devframes/plugin-assets': + specifier: workspace:* + version: link:../../plugins/assets + '@devframes/plugin-code-server': + specifier: workspace:* + version: link:../../plugins/code-server + '@devframes/plugin-data-inspector': + specifier: workspace:* + version: link:../../plugins/data-inspector + '@devframes/plugin-git': + specifier: workspace:* + version: link:../../plugins/git + '@devframes/plugin-inspect': + specifier: workspace:* + version: link:../../plugins/inspect + '@devframes/plugin-messages': + specifier: workspace:* + version: link:../../plugins/messages + '@devframes/plugin-og': + specifier: workspace:* + version: link:../../plugins/og + '@devframes/plugin-terminals': + specifier: workspace:* + version: link:../../plugins/terminals + devframe: + specifier: workspace:* + version: link:../../packages/devframe + devDependencies: + '@sveltejs/adapter-node': + specifier: catalog:build + version: 5.5.7(@sveltejs/kit@2.70.2(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0)))(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0))) + '@sveltejs/kit': + specifier: catalog:build + version: 2.70.2(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0)))(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0)) + '@sveltejs/vite-plugin-svelte': + specifier: catalog:frontend + version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0)) + '@types/node': + specifier: catalog:types + version: 26.2.0 + svelte: + specifier: catalog:frontend + version: 5.56.8(@typescript-eslint/types@8.67.0) + vite: + specifier: catalog:build + version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0) + examples/hub-vite: dependencies: '@antfu/design': @@ -2846,6 +3011,27 @@ packages: resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@fastify/ajv-compiler@4.0.6': + resolution: {integrity: sha512-NtuzM0SfaMJbGlnjr9LWQUN5LzgSrbB8tf/wRZNas+4E1O/Nmzl53e7ruT61HDZyRCJGC6FxIogmNZO1c5ETBA==} + + '@fastify/error@4.2.0': + resolution: {integrity: sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ==} + + '@fastify/fast-json-stringify-compiler@5.1.0': + resolution: {integrity: sha512-PxcYtKLbQ8Z+yApiqjK8FwxIwvEj38k2OiLc17u8dkJSlmfi2wHHPaSnaoqBPQqtvF8YVsDgDpP2snDCfFrpfw==} + + '@fastify/forwarded@3.0.2': + resolution: {integrity: sha512-NE8HgKLgYejV9lDpqkEFaDKMLYelJBVfHekhB0UKvX0ghagXRJqg68feg8er1NPXxG4N9i6vPxzt8E+3wHfcmA==} + + '@fastify/merge-json-schemas@0.2.1': + resolution: {integrity: sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==} + + '@fastify/middie@9.3.3': + resolution: {integrity: sha512-N2VRS+sfw/lxA/uLD6TvBpvfPfOV/RdYzM7ctAB58Cn2TAYxbRd8+JLFhNhMJoXlSbgChXYUnkn3hPU/JdA4Pg==} + + '@fastify/proxy-addr@5.1.0': + resolution: {integrity: sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw==} + '@floating-ui/core@1.8.0': resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==} @@ -4285,6 +4471,9 @@ packages: shiki: optional: true + '@pinojs/redact@0.4.0': + resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -5184,6 +5373,27 @@ packages: peerDependencies: acorn: ^8.9.0 + '@sveltejs/adapter-node@5.5.7': + resolution: {integrity: sha512-uOfc9eVlI3A37RRSaKcgrheBYPrfJwC9VMqDp8x/O6tlKdcLLvHThSWD0KNIbjQ/d+7bwLGx3vx6aowAcRfd2g==} + peerDependencies: + '@sveltejs/kit': ^2.4.0 + + '@sveltejs/kit@2.70.2': + resolution: {integrity: sha512-RzRoRpuR2KXqc5yMO0akQHDZeT4AslOlznGITURsqHaVbtyYP4Wn3eE3gxj9JcDyNYO0crkxhdwFHc+2vkVm6w==} + engines: {node: '>=18.13'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.0.0 + '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0 + svelte: ^4.0.0 || ^5.0.0-next.0 + typescript: ^5.3.3 || ^6.0.0 + vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + typescript: + optional: true + '@sveltejs/vite-plugin-svelte@7.3.0': resolution: {integrity: sha512-QbRoJyD92e9R0ufeQIWRHrCC0ObcqSv/aBDdrQMoU+sypav3cDx5wytdQ6GLdXjEMO6xjrXGzfkUygng8JMv0A==} engines: {node: ^20.19 || ^22.12 || >=24} @@ -5273,6 +5483,9 @@ packages: '@types/codemirror@5.60.18': resolution: {integrity: sha512-aSBOPXH2PXRYixxUpVP1sJ5+S0vEfKDvR+lABZ7Kju/9Qb0SSbZk72NihWaKoQbANyibs92q4DBfYasywxnNkA==} + '@types/cookie@0.6.0': + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + '@types/d3-array@3.2.2': resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} @@ -6064,6 +6277,9 @@ packages: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} + abstract-logging@2.0.1: + resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} + acorn-import-attributes@1.9.5: resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: @@ -6093,9 +6309,20 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv@6.15.0: resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + alien-signals@3.2.1: resolution: {integrity: sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==} @@ -6188,6 +6415,10 @@ packages: async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + autoprefixer@10.5.4: resolution: {integrity: sha512-MaU0U/za7N3r6brxD4YB/l4NSrFzLPlANv6wEuQVaIPlD3L4W9rFcQPbL/EilY9BHhHvhfcz3gInDLrEtWT4EA==} engines: {node: ^10 || ^12 || >=14} @@ -6195,6 +6426,9 @@ packages: peerDependencies: postcss: ^8.1.0 + avvio@9.3.0: + resolution: {integrity: sha512-g2tQ7LE7oOSqDfwEm3M+ZCMTJc7KiZCdJ4UwyZJb5ckTKyYu50OYmvv0mCFXPuYXoM4zkSt8zM9XQ9KCvxA74A==} + axe-core@4.12.1: resolution: {integrity: sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==} engines: {node: '>=4'} @@ -6523,6 +6757,14 @@ packages: cookie-es@3.1.1: resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} + cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + engines: {node: '>= 0.6'} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + core-js-compat@3.49.0: resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==} @@ -6857,9 +7099,6 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - devalue@5.8.2: - resolution: {integrity: sha512-DObPPAfdtFbXjxLqK8s2Xk9ZuWz5+ZoFEhC7J76es4GU/rEiXwHTmbImoCdyoCOcBH1UF3+Cz6Z2sYD4hyl5TA==} - devalue@5.9.0: resolution: {integrity: sha512-RWrqdArjvPbsATEhOPUo6Wndc/iWnkWKlhIrdlF3zMMYo/c3CVtoaVAyLtWxz5h8nSlkHzxnzV2uLydPXmtF+A==} @@ -7312,6 +7551,9 @@ packages: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} + fast-decode-uri-component@1.0.1: + resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -7325,6 +7567,9 @@ packages: fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + fast-json-stringify@7.0.1: + resolution: {integrity: sha512-eRSayARSbbwlBjpP4vnTTIRD5QPcIrmihPxDeN1DtKnHPg66UuJLx+8hlK1kaFdjvzyQ/dzALoi4vwAQ+T+iZA==} + fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} @@ -7332,15 +7577,30 @@ packages: resolution: {integrity: sha512-99jPl8JkCSCa4VlboNU1XuL98ijm74Pm9CGo6H4BoMVoVh1uhguQcvwLgXDT8Vkl2qj/UEQ0J9gD8beHjTFk1w==} hasBin: true + fast-querystring@1.1.2: + resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} + fast-string-truncated-width@3.0.3: resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} fast-string-width@3.0.2: resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + fast-uri@3.1.5: + resolution: {integrity: sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==} + + fast-uri@4.1.2: + resolution: {integrity: sha512-TyGmBcbDTZXcb2cj5MV89DrF42DKvb3y5DDUNh95iO+IMeAzMkVSxK1PZRrRIpc9yg8U2GhGdbofNa0LS/a4Bw==} + fast-wrap-ansi@0.2.0: resolution: {integrity: sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==} + fastify-plugin@6.0.0: + resolution: {integrity: sha512-fZOty7z3O7vOliF6d8bHE3wiEh1KcNnKEQensSgTk9C1DvN6nRLS++XVd86v33Hw/8u9Un8A1zDrQ8ujcQDHEg==} + + fastify@5.12.0: + resolution: {integrity: sha512-A3RNEaDIHWaxFW8n8rNJaW1wQ+XAXuoU71llfUQJjuh5WaYLmKfRhhanaJBOx8m2EBPQkR6sDBovYdHNe9F6rA==} + fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -7370,6 +7630,10 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + find-my-way@9.8.0: + resolution: {integrity: sha512-JtyUgATO7qxRp2zKhrmWof74Mqxc1ikbwpwMY97p8ipuTj2QtreA4gK2JNAF6SOqqHnYYkwMUvsgQVi2AJxIyw==} + engines: {node: '>=20'} + find-up-simple@1.0.1: resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} engines: {node: '>=18'} @@ -7711,6 +7975,10 @@ packages: resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} engines: {node: '>=12.22.0'} + ipaddr.js@2.5.0: + resolution: {integrity: sha512-aq+t5NAc+cS6rZQQVWC2x98CPqGtKKTMDd4Gaodv0wShnItdKg/51djkGJ1hqH+Oy0ivDftCbSLCQob8zso01w==} + engines: {node: '>= 10'} + iron-webcrypto@1.2.1: resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} @@ -7867,9 +8135,15 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-schema-ref-resolver@3.0.0: + resolution: {integrity: sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -7942,6 +8216,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + light-my-request@6.6.0: + resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==} + lightningcss-android-arm64@1.33.0: resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} engines: {node: '>= 12.0.0'} @@ -8574,6 +8851,10 @@ packages: resolution: {integrity: sha512-08+12qcOVEA0fS9g/VxKS27HaT94nRutUT77J2dr8zv/unzXopvhBuF8tNLWsoLQ5IgrQ6eptGeGqUYat82U1w==} engines: {node: '>=20'} + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -8713,6 +8994,9 @@ packages: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} @@ -8737,6 +9021,16 @@ packages: resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} engines: {node: '>=12'} + pino-abstract-transport@3.0.0: + resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} + + pino-std-serializers@7.1.0: + resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} + + pino@10.3.1: + resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} + hasBin: true + pkce-challenge@5.0.1: resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} engines: {node: '>=16.20.0'} @@ -8978,6 +9272,12 @@ packages: process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + process-warning@4.0.1: + resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} + + process-warning@5.1.0: + resolution: {integrity: sha512-jQSaVHsPgtyw60e1rQ/A+/ArPEj/S8pS/vFnyGa/gYFXrKk/6RuDkoqVDQ5NI5MmS01698ltlAk0NoDBNLujRw==} + process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} @@ -9044,6 +9344,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + quote-js-string@0.1.0: resolution: {integrity: sha512-Y3NoRtprEEZQD8RfxMCfS0ZTqc4e+i18OrXEXAvpM6TfC/3y+0L5rNbZiSnbBBEkDfFzbpd8o+cE8q3/anjMGA==} engines: {node: '>=22'} @@ -9093,6 +9396,13 @@ packages: resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + + real-require@1.0.0: + resolution: {integrity: sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g==} + recast@0.23.11: resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} engines: {node: '>= 4'} @@ -9139,6 +9449,10 @@ packages: peerDependencies: vue: '>= 3.4.0' + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + reserved-identifiers@1.2.0: resolution: {integrity: sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==} engines: {node: '>=18'} @@ -9155,6 +9469,10 @@ packages: engines: {node: '>= 0.4'} hasBin: true + ret@0.5.0: + resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==} + engines: {node: '>=10'} + retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} @@ -9163,6 +9481,9 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + robust-predicates@3.0.3: resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} @@ -9247,6 +9568,14 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-regex2@5.1.1: + resolution: {integrity: sha512-mOSBvHGDZMuIEZMdOz/aCEYDCv0E7nfcNsIhUF+/P+xC7Hyf3FkvymqgPbg9D1EdSGu+uKbJgy09K/RKKc7kJA==} + hasBin: true + + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -9268,6 +9597,9 @@ packages: resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} engines: {node: '>=4'} + secure-json-parse@4.1.0: + resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} + semver@7.8.5: resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} @@ -9302,6 +9634,12 @@ packages: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + + set-cookie-parser@3.1.2: + resolution: {integrity: sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw==} + setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -9389,6 +9727,9 @@ packages: peerDependencies: solid-js: ^1.3 + sonic-boom@4.2.1: + resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -9416,6 +9757,10 @@ packages: spdx-license-ids@3.0.23: resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + splitpanes@4.1.2: resolution: {integrity: sha512-frNchoCv7w0nMQEuaDGgMGMU6jv3NhN6bBGQVfCNgwJdVcYaRmi1dwYDjp7SifAoUFdiQjBRB254LJNidzo15Q==} peerDependencies: @@ -9631,6 +9976,10 @@ packages: text-decoder@1.2.7: resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} + thread-stream@4.2.0: + resolution: {integrity: sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==} + engines: {node: '>=20'} + time-span@5.1.0: resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} engines: {node: '>=12'} @@ -9677,6 +10026,10 @@ packages: resolution: {integrity: sha512-41wJyvKep3yT2tyPqX/4blcfybknGB4D+oETKLs7Q76UiPqRpUJK3hr1nxelyYO0PHKVzJwlu0aCeEAsGI6rpw==} engines: {node: '>=20'} + toad-cache@3.7.4: + resolution: {integrity: sha512-m1TdR/rvT7kgGJZhspNtXdsdYk0fddFpJJFlG5s+UkPFo6lkLoZ3YLOaovPYjq1R75NP5JfeTlSHaOsE09peCg==} + engines: {node: '>=20'} + toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -11342,6 +11695,37 @@ snapshots: '@eslint/core': 1.2.1 levn: 0.4.1 + '@fastify/ajv-compiler@4.0.6': + dependencies: + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + fast-uri: 4.1.2 + + '@fastify/error@4.2.0': {} + + '@fastify/fast-json-stringify-compiler@5.1.0': + dependencies: + fast-json-stringify: 7.0.1 + + '@fastify/forwarded@3.0.2': {} + + '@fastify/merge-json-schemas@0.2.1': + dependencies: + dequal: 2.0.3 + + '@fastify/middie@9.3.3': + dependencies: + '@fastify/error': 4.2.0 + fastify-plugin: 6.0.0 + find-my-way: 9.8.0 + path-to-regexp: 8.4.2 + reusify: 1.1.0 + + '@fastify/proxy-addr@5.1.0': + dependencies: + '@fastify/forwarded': 3.0.2 + ipaddr.js: 2.5.0 + '@floating-ui/core@1.8.0': dependencies: '@floating-ui/utils': 0.2.12 @@ -12665,6 +13049,8 @@ snapshots: react-dom: 19.2.8(react@19.2.8) shiki: 4.3.1 + '@pinojs/redact@0.4.0': {} + '@pkgjs/parseargs@0.11.0': optional: true @@ -13428,9 +13814,38 @@ snapshots: estraverse: 5.3.0 picomatch: 4.0.5 - '@sveltejs/acorn-typescript@1.0.10(acorn@8.16.0)': + '@sveltejs/acorn-typescript@1.0.10(acorn@8.18.0)': dependencies: - acorn: 8.16.0 + acorn: 8.18.0 + + '@sveltejs/adapter-node@5.5.7(@sveltejs/kit@2.70.2(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0)))(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0)))': + dependencies: + '@rollup/plugin-commonjs': 29.0.2(rollup@4.60.3) + '@rollup/plugin-json': 6.1.0(rollup@4.60.3) + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.60.3) + '@rollup/plugin-replace': 6.0.3(rollup@4.60.3) + '@sveltejs/kit': 2.70.2(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0)))(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0)) + rollup: 4.60.3 + + '@sveltejs/kit@2.70.2(@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0)))(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0))': + dependencies: + '@standard-schema/spec': 1.1.0 + '@sveltejs/acorn-typescript': 1.0.10(acorn@8.18.0) + '@sveltejs/vite-plugin-svelte': 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0)) + '@types/cookie': 0.6.0 + acorn: 8.18.0 + cookie: 0.6.0 + devalue: 5.9.0 + esm-env: 1.2.2 + kleur: 4.1.5 + magic-string: 0.30.21 + mrmime: 2.0.1 + set-cookie-parser: 3.1.2 + sirv: 3.0.2 + svelte: 5.56.8(@typescript-eslint/types@8.67.0) + vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0) + optionalDependencies: + typescript: 6.0.3 '@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0))': dependencies: @@ -13541,6 +13956,8 @@ snapshots: dependencies: '@types/tern': 0.23.9 + '@types/cookie@0.6.0': {} + '@types/d3-array@3.2.2': {} '@types/d3-axis@3.0.6': @@ -14085,8 +14502,8 @@ snapshots: dependencies: '@mapbox/node-pre-gyp': 2.0.3(supports-color@10.2.2) '@rollup/pluginutils': 5.3.0(rollup@4.60.3) - acorn: 8.16.0 - acorn-import-attributes: 1.9.5(acorn@8.16.0) + acorn: 8.18.0 + acorn-import-attributes: 1.9.5(acorn@8.18.0) async-sema: 3.1.1 bindings: 1.5.0 estree-walker: 2.0.2 @@ -14545,13 +14962,15 @@ snapshots: dependencies: event-target-shim: 5.0.1 - acorn-import-attributes@1.9.5(acorn@8.16.0): + abstract-logging@2.0.1: {} + + acorn-import-attributes@1.9.5(acorn@8.18.0): dependencies: - acorn: 8.16.0 + acorn: 8.18.0 - acorn-jsx@5.3.2(acorn@8.16.0): + acorn-jsx@5.3.2(acorn@8.18.0): dependencies: - acorn: 8.16.0 + acorn: 8.18.0 acorn@7.4.1: {} @@ -14561,6 +14980,10 @@ snapshots: agent-base@7.1.4: {} + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 @@ -14568,6 +14991,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.5 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + alien-signals@3.2.1: {} ansi-regex@5.0.1: {} @@ -14660,6 +15090,8 @@ snapshots: async@3.2.6: {} + atomic-sleep@1.0.0: {} + autoprefixer@10.5.4(postcss@8.5.26): dependencies: browserslist: 4.28.6 @@ -14669,6 +15101,11 @@ snapshots: postcss: 8.5.26 postcss-value-parser: 4.2.0 + avvio@9.3.0: + dependencies: + '@fastify/error': 4.2.0 + fastq: 1.20.1 + axe-core@4.12.1: {} axe-core@4.13.0: {} @@ -14971,6 +15408,10 @@ snapshots: cookie-es@3.1.1: {} + cookie@0.6.0: {} + + cookie@1.1.1: {} + core-js-compat@3.49.0: dependencies: browserslist: 4.28.6 @@ -15314,8 +15755,6 @@ snapshots: detect-libc@2.1.2: {} - devalue@5.8.2: {} - devalue@5.9.0: {} devlop@1.1.0: @@ -15731,14 +16170,14 @@ snapshots: espree@10.4.0: dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) eslint-visitor-keys: 4.2.1 espree@11.2.0: dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) eslint-visitor-keys: 5.0.1 esprima@4.0.1: {} @@ -15807,6 +16246,8 @@ snapshots: dependencies: is-extendable: 0.1.1 + fast-decode-uri-component@1.0.1: {} + fast-deep-equal@3.1.3: {} fast-fifo@1.3.2: {} @@ -15821,22 +16262,59 @@ snapshots: fast-json-stable-stringify@2.1.0: {} + fast-json-stringify@7.0.1: + dependencies: + '@fastify/merge-json-schemas': 0.2.1 + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + fast-uri: 4.1.2 + json-schema-ref-resolver: 3.0.0 + rfdc: 1.4.1 + fast-levenshtein@2.0.6: {} fast-npm-meta@2.2.0: dependencies: cac: 7.0.0 + fast-querystring@1.1.2: + dependencies: + fast-decode-uri-component: 1.0.1 + fast-string-truncated-width@3.0.3: {} fast-string-width@3.0.2: dependencies: fast-string-truncated-width: 3.0.3 + fast-uri@3.1.5: {} + + fast-uri@4.1.2: {} + fast-wrap-ansi@0.2.0: dependencies: fast-string-width: 3.0.2 + fastify-plugin@6.0.0: {} + + fastify@5.12.0: + dependencies: + '@fastify/ajv-compiler': 4.0.6 + '@fastify/error': 4.2.0 + '@fastify/fast-json-stringify-compiler': 5.1.0 + '@fastify/proxy-addr': 5.1.0 + abstract-logging: 2.0.1 + avvio: 9.3.0 + fast-json-stringify: 7.0.1 + find-my-way: 9.8.0 + light-my-request: 6.6.0 + pino: 10.3.1 + process-warning: 5.1.0 + rfdc: 1.4.1 + secure-json-parse: 4.1.0 + semver: 7.8.5 + toad-cache: 3.7.4 + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -15863,6 +16341,12 @@ snapshots: dependencies: to-regex-range: 5.0.1 + find-my-way@9.8.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-querystring: 1.1.2 + safe-regex2: 5.1.1 + find-up-simple@1.0.1: {} find-up@5.0.0: @@ -16205,6 +16689,8 @@ snapshots: transitivePeerDependencies: - supports-color + ipaddr.js@2.5.0: {} + iron-webcrypto@1.2.1: {} is-builtin-module@5.0.0: @@ -16330,15 +16816,21 @@ snapshots: json-buffer@3.0.1: {} + json-schema-ref-resolver@3.0.0: + dependencies: + dequal: 2.0.3 + json-schema-traverse@0.4.1: {} + json-schema-traverse@1.0.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} json5@2.2.3: {} jsonc-eslint-parser@3.1.0: dependencies: - acorn: 8.16.0 + acorn: 8.18.0 eslint-visitor-keys: 5.0.1 semver: 7.8.5 @@ -16405,6 +16897,12 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + light-my-request@6.6.0: + dependencies: + cookie: 1.1.1 + process-warning: 4.0.1 + set-cookie-parser: 2.7.2 + lightningcss-android-arm64@1.33.0: optional: true @@ -17462,6 +17960,8 @@ snapshots: on-change@6.0.2: {} + on-exit-leak-free@2.1.2: {} + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -17697,6 +18197,8 @@ snapshots: lru-cache: 11.3.6 minipass: 7.1.3 + path-to-regexp@8.4.2: {} + pathe@1.1.2: {} pathe@2.0.3: {} @@ -17711,6 +18213,26 @@ snapshots: picomatch@4.0.5: {} + pino-abstract-transport@3.0.0: + dependencies: + split2: 4.2.0 + + pino-std-serializers@7.1.0: {} + + pino@10.3.1: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 3.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.1.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.1 + thread-stream: 4.2.0 + pkce-challenge@5.0.1: {} pkg-types@1.3.1: @@ -17938,6 +18460,10 @@ snapshots: process-nextick-args@2.0.1: {} + process-warning@4.0.1: {} + + process-warning@5.1.0: {} + process@0.11.10: {} promise@7.3.1: @@ -18032,6 +18558,8 @@ snapshots: queue-microtask@1.2.3: {} + quick-format-unescaped@4.0.4: {} + quote-js-string@0.1.0: {} radix3@1.1.2: {} @@ -18095,6 +18623,10 @@ snapshots: readdirp@5.0.0: {} + real-require@0.2.0: {} + + real-require@1.0.0: {} + recast@0.23.11: dependencies: ast-types: 0.16.1 @@ -18172,6 +18704,8 @@ snapshots: transitivePeerDependencies: - '@vue/composition-api' + require-from-string@2.0.2: {} + reserved-identifiers@1.2.0: {} resolve-from@5.0.0: {} @@ -18185,10 +18719,14 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + ret@0.5.0: {} + retry@0.12.0: {} reusify@1.1.0: {} + rfdc@1.4.1: {} + robust-predicates@3.0.3: {} rolldown-plugin-dts@0.27.13(@volar/typescript@2.4.28(typescript@5.9.3))(oxc-resolver@11.24.2)(rolldown@1.2.3)(typescript@5.9.3): @@ -18332,6 +18870,12 @@ snapshots: safe-buffer@5.2.1: {} + safe-regex2@5.1.1: + dependencies: + ret: 0.5.0 + + safe-stable-stringify@2.5.0: {} + safer-buffer@2.1.2: {} sax@1.6.0: {} @@ -18351,6 +18895,8 @@ snapshots: extend-shallow: 2.0.1 kind-of: 6.0.3 + secure-json-parse@4.1.0: {} + semver@7.8.5: {} send@1.2.1(supports-color@10.2.2): @@ -18392,6 +18938,10 @@ snapshots: transitivePeerDependencies: - supports-color + set-cookie-parser@2.7.2: {} + + set-cookie-parser@3.1.2: {} + setprototypeof@1.2.0: {} sharp@0.34.5: @@ -18552,6 +19102,10 @@ snapshots: transitivePeerDependencies: - supports-color + sonic-boom@4.2.1: + dependencies: + atomic-sleep: 1.0.0 + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -18574,6 +19128,8 @@ snapshots: spdx-license-ids@3.0.23: {} + split2@4.2.0: {} + splitpanes@4.1.2(vue@3.5.41(typescript@5.9.3)): dependencies: vue: 3.5.41(typescript@5.9.3) @@ -18752,14 +19308,14 @@ snapshots: dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 - '@sveltejs/acorn-typescript': 1.0.10(acorn@8.16.0) + '@sveltejs/acorn-typescript': 1.0.10(acorn@8.18.0) '@types/estree': 1.0.9 '@types/trusted-types': 2.0.7 - acorn: 8.16.0 + acorn: 8.18.0 aria-query: 5.3.1 axobject-query: 4.1.0 clsx: 2.1.1 - devalue: 5.8.2 + devalue: 5.9.0 esm-env: 1.2.2 esrap: 2.2.13(@typescript-eslint/types@8.67.0) is-reference: 3.0.3 @@ -18830,6 +19386,10 @@ snapshots: transitivePeerDependencies: - react-native-b4a + thread-stream@4.2.0: + dependencies: + real-require: 1.0.0 + time-span@5.1.0: dependencies: convert-hrtime: 5.0.0 @@ -18864,6 +19424,8 @@ snapshots: '@sindresorhus/base62': 1.0.0 reserved-identifiers: 1.2.0 + toad-cache@3.7.4: {} + toidentifier@1.0.1: {} token-stream@1.0.0: {} @@ -19014,7 +19576,7 @@ snapshots: unctx@2.5.0: dependencies: - acorn: 8.16.0 + acorn: 8.18.0 estree-walker: 3.0.3 magic-string: 0.30.21 unplugin: 2.3.11 @@ -19056,7 +19618,7 @@ snapshots: unimport@6.3.1(@rspack/core@2.1.9(@swc/helpers@0.5.23))(esbuild@0.28.0)(oxc-parser@0.143.0)(rolldown@1.2.3)(rollup@4.60.3)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.47.1)(tsx@4.23.12)(yaml@2.9.0)): dependencies: - acorn: 8.16.0 + acorn: 8.18.0 escape-string-regexp: 5.0.0 estree-walker: 3.0.3 local-pkg: 1.2.1 @@ -19196,7 +19758,7 @@ snapshots: unplugin@2.3.11: dependencies: '@jridgewell/remapping': 2.3.5 - acorn: 8.16.0 + acorn: 8.18.0 picomatch: 4.0.5 webpack-virtual-modules: 0.6.2 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c928edd5..e402a856 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -63,6 +63,8 @@ catalogs: '@nuxt/kit': *nuxt '@preact/preset-vite': ^2.10.6 '@rsbuild/core': ^2.1.11 + '@sveltejs/adapter-node': ^5.3.3 + '@sveltejs/kit': ^2.46.4 '@vitejs/plugin-vue': ^6.0.8 lightningcss: ^1.33.0 magic-string: ^1.1.1 @@ -74,6 +76,7 @@ catalogs: vite: ^8.2.1 vite-plugin-solid: ^2.11.14 deps: + '@fastify/middie': ^9.0.3 '@hono/node-server': ^1.19.17 '@json-render/core': ^0.19.0 '@modelcontextprotocol/client': ^2.0.0 @@ -84,6 +87,7 @@ catalogs: chokidar: ^5.0.0 crossws: ^0.4.10 destr: ^2.0.5 + fastify: ^5.7.1 get-port-please: ^3.2.0 h3: ^2.0.1-rc.26 hono: ^4.13.1 diff --git a/tests/__snapshots__/tsnapi/devframe/rpc/transports/ws-deno.snapshot.d.ts b/tests/__snapshots__/tsnapi/devframe/rpc/transports/ws-deno.snapshot.d.ts new file mode 100644 index 00000000..28315ab8 --- /dev/null +++ b/tests/__snapshots__/tsnapi/devframe/rpc/transports/ws-deno.snapshot.d.ts @@ -0,0 +1,16 @@ +/** + * Generated by tsnapi — public API snapshot of `devframe/rpc/transports/ws-deno` + */ +// #region Interfaces +export interface AttachDenoWsTransportOptions { + allowedOrigins?: readonly string[] | WsOriginRegistry | false; +} +export interface DenoWsTier { + handleUpgrade: (_: Request, _: unknown) => Promise; + close: () => Promise; +} +// #endregion + +// #region Functions +export declare function attachDenoWsTransport(_: ContextRpcServer, _?: AttachDenoWsTransportOptions): Promise; +// #endregion \ No newline at end of file diff --git a/tests/__snapshots__/tsnapi/devframe/rpc/transports/ws-deno.snapshot.js b/tests/__snapshots__/tsnapi/devframe/rpc/transports/ws-deno.snapshot.js new file mode 100644 index 00000000..5e5fbef2 --- /dev/null +++ b/tests/__snapshots__/tsnapi/devframe/rpc/transports/ws-deno.snapshot.js @@ -0,0 +1,6 @@ +/** + * Generated by tsnapi — public API snapshot of `devframe/rpc/transports/ws-deno` + */ +// #region Functions +export async function attachDenoWsTransport(_, _) {} +// #endregion \ No newline at end of file diff --git a/tsconfig.base.json b/tsconfig.base.json index 62e621e2..c22b300e 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -16,6 +16,9 @@ "devframe/rpc/transports/ws-bun": [ "./packages/devframe/src/rpc/transports/ws-bun.ts" ], + "devframe/rpc/transports/ws-deno": [ + "./packages/devframe/src/rpc/transports/ws-deno.ts" + ], "devframe/rpc/transports/ws-server": [ "./packages/devframe/src/rpc/transports/ws-server.ts" ],