Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions alias.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,8 @@ export const alias = {
'@devframes/json-render/hub': r('json-render/src/hub.ts'),
'@devframes/json-render/node': r('json-render/src/node/index.ts'),
'@devframes/json-render': r('json-render/src/index.ts'),
'@devframes/json-render-ui/components': r('json-render-ui/src/components/index.ts'),
'@devframes/json-render-ui/hub': r('json-render-ui/src/hub.ts'),
'@devframes/json-render-ui/spa': r('json-render-ui/src/spa.ts'),
'@devframes/json-render-ui': r('json-render-ui/src/index.ts'),
'json-render/dashboard': fileURLToPath(new URL('./examples/json-render/src/node/dashboard.ts', import.meta.url)),
'@devframes/plugin-code-server/node': p('code-server/src/node/setup.ts'),
'@devframes/plugin-code-server/constants': p('code-server/src/node/constants.ts'),
Expand Down
5 changes: 2 additions & 3 deletions knip.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,8 @@
// Published node-safe entries are `spa.ts`/`hub.ts`; the browser
// renderer ships only as self-contained Vite bundles (the standalone
// SPA and the prebuilt renderer module, consumed at runtime via the
// hub's renderer manifest). `src/index.ts` stays as the source barrel
// those Vite/Storybook builds resolve, so it's declared as an entry too.
"entry": ["src/{index,spa,hub}.ts", "src/renderer-module/index.ts"],
// hub's renderer manifest).
"entry": ["src/{spa,hub}.ts", "src/renderer-module/index.ts"],
// The standalone SPA's own Vite config (`src/spa/vite.config.ts`)
// mounts `unocss/vite` with no explicit config path, so UnoCSS
// discovers this nested `uno.config.ts` by directory proximity to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,17 @@ function withJsonSchema(json: Record<string, unknown>): StandardSchemaV1 {

describe('argsToJsonSchema', () => {
it('returns an empty object schema when no args', () => {
const { schema, unwrapped } = argsToJsonSchema(undefined)
expect(unwrapped).toBe(false)
const schema = argsToJsonSchema(undefined)
expect(schema).toEqual({ type: 'object', properties: {} })
})

it('uses the schema\'s own Standard JSON Schema converter when present', () => {
const { schema } = argsToJsonSchema([withJsonSchema({ type: 'string' })])
const schema = argsToJsonSchema([withJsonSchema({ type: 'string' })])
expect((schema as any).properties.arg0).toEqual({ type: 'string' })
})

it('falls back to a permissive object for validators without a native converter (valibot)', () => {
const { schema } = argsToJsonSchema([v.string(), v.number()])
const schema = argsToJsonSchema([v.string(), v.number()])
expect((schema as any).properties.arg0).toEqual(PERMISSIVE)
expect((schema as any).properties.arg1).toEqual(PERMISSIVE)
expect(schema).toMatchObject({ type: 'object', required: ['arg0', 'arg1'], additionalProperties: false })
Expand Down
4 changes: 2 additions & 2 deletions packages/devframe/src/adapters/mcp/build-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -428,14 +428,14 @@ function projectTool(name: string, tool: AgentTool, ctx: DevframeNodeContext): T

function computeInputSchema(tool: AgentTool, ctx: DevframeNodeContext): unknown {
if (tool.kind === 'tool')
return argsToJsonSchema(tool.args).schema
return argsToJsonSchema(tool.args)
if (tool.kind !== 'rpc' || !tool.rpcName)
return { type: 'object', properties: {} }
const def = ctx.rpc.definitions.get(tool.rpcName) as RpcFunctionDefinitionAnyWithContext<DevframeNodeContext> | undefined
if (!def)
return { type: 'object', properties: {} }
const args = def.args as readonly StandardSchemaV1[] | undefined
return argsToJsonSchema(args).schema
return argsToJsonSchema(args)
}

function computeOutputSchema(tool: AgentTool, ctx: DevframeNodeContext): unknown {
Expand Down
15 changes: 6 additions & 9 deletions packages/devframe/src/adapters/mcp/to-json-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ export function returnToJsonSchema(schema: StandardSchemaV1 | undefined): unknow
*/
export function argsToJsonSchema(
args: readonly StandardSchemaV1[] | undefined,
): { schema: unknown, unwrapped: boolean } {
): unknown {
if (!args || args.length === 0)
return { schema: { type: 'object', properties: {} }, unwrapped: false }
return { type: 'object', properties: {} }

const properties: Record<string, unknown> = {}
const required: string[] = []
Expand All @@ -61,12 +61,9 @@ export function argsToJsonSchema(
}

return {
schema: {
type: 'object',
properties,
required,
additionalProperties: false,
},
unwrapped: false,
type: 'object',
properties,
required,
additionalProperties: false,
}
}
3 changes: 1 addition & 2 deletions packages/devframe/src/client/rpc-live.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type { DevframeConnectionStatus } from './connection'
import type { DevframeClientRpcHost, DevframeRpcClientMode, DevframeRpcClientOptions, RpcClientEvents } from './rpc'
import { createRpcClient } from 'devframe/rpc/client'
import { DEVFRAME_EVENTS } from '../events'
import { promiseWithResolver } from '../utils/promise'
import { DevframeConnectionError } from './connection'

/** What a live transport's channel factory receives from the shared mode. */
Expand Down Expand Up @@ -53,7 +52,7 @@ export function createLiveRpcClientMode(
let isTrusted = false
let status: DevframeConnectionStatus = 'connecting'
let connectionError: Error | null = null
const trustedPromise = promiseWithResolver<boolean>()
const trustedPromise = Promise.withResolvers<boolean>()

// ── connection status ────────────────────────────────────────────────────

Expand Down
23 changes: 2 additions & 21 deletions packages/devframe/src/client/settings.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { DevframeSettings, DevframeSettingsStore } from 'devframe/types'
import type { SharedState } from 'devframe/utils/shared-state'
import type { DevframeRpcClient } from './rpc'
import { createSettingsStore } from '../settings-store'

function createClientSettingsStore<T extends Record<string, any>>(
rpc: DevframeRpcClient,
Expand All @@ -21,27 +22,7 @@ function createClientSettingsStore<T extends Record<string, any>>(
return statePromise
}

return {
async get(key) {
return ((await store()).value() as T)[key]
},
async set(key, value) {
;(await store()).mutate((draft) => {
;(draft as T)[key] = value
})
},
async delete(key) {
;(await store()).mutate((draft) => {
delete (draft as T)[key]
})
},
async all() {
return (await store()).value() as Readonly<T>
},
async onChange(fn) {
return (await store()).on('updated', full => fn(full as Readonly<T>))
},
}
return createSettingsStore<T>(store)
}

/**
Expand Down
23 changes: 2 additions & 21 deletions packages/devframe/src/node/settings.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { DevframeNodeContext, DevframeRpcSharedStates, DevframeSettings, DevframeSettingsStore } from 'devframe/types'
import type { SharedState } from 'devframe/utils/shared-state'
import { join } from 'pathe'
import { createSettingsStore } from '../settings-store'
import { createStorage } from './storage'

// Map a settings scope to the host storage scope it persists under.
Expand Down Expand Up @@ -32,27 +33,7 @@ function createNodeSettingsStore<T extends Record<string, any>>(
return statePromise
}

return {
async get(key) {
return ((await store()).value() as T)[key]
},
async set(key, value) {
;(await store()).mutate((draft) => {
;(draft as T)[key] = value
})
},
async delete(key) {
;(await store()).mutate((draft) => {
delete (draft as T)[key]
})
},
async all() {
return (await store()).value() as Readonly<T>
},
async onChange(fn) {
return (await store()).on('updated', full => fn(full as Readonly<T>))
},
}
return createSettingsStore<T>(store)
}

/**
Expand Down
6 changes: 5 additions & 1 deletion packages/devframe/src/rpc/types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ import type {
RpcDefinitionsToFunctions,
RpcFunctionDefinitionToFunction,
} from '.'
import type { AssertEqual } from './utils'
import * as v from 'valibot'
import { describe, it } from 'vitest'
import { defineRpcFunction } from '.'

/** Type-level assertion that two types are equal. */
type AssertEqual<X, Y>
= (<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? true : never

/** Fake a typed Standard Schema from a non-valibot vendor. */
function schema<Input, Output = Input>(): StandardSchemaV1<Input, Output> {
return {
Expand Down
5 changes: 0 additions & 5 deletions packages/devframe/src/rpc/utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import type { StandardSchemaV1 } from '@standard-schema/spec'
import type { RpcArgsSchema, RpcReturnSchema } from './types'

/** Type-level assertion that two types are equal */
export type AssertEqual<X, Y>
= (<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? true : never

/** Infers a TypeScript argument tuple from a Standard Schema array */
export type InferArgsType<S extends RpcArgsSchema | undefined>
= S extends readonly [] ? []
Expand Down
34 changes: 34 additions & 0 deletions packages/devframe/src/settings-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { DevframeSettingsStore } from 'devframe/types'
import type { SharedState } from 'devframe/utils/shared-state'

/**
* The key-value store surface over a lazily-resolved shared state, shared by
* the node-side (file-backed) and client-side (RPC-mirrored) settings stores.
* Each side supplies its own `store()` resolver; the read/write/subscribe
* behavior on top of it is identical.
*/
export function createSettingsStore<T extends Record<string, any>>(
store: () => Promise<SharedState<T>>,
): DevframeSettingsStore<T> {
return {
async get(key) {
return ((await store()).value() as T)[key]
},
async set(key, value) {
;(await store()).mutate((draft) => {
;(draft as T)[key] = value
})
},
async delete(key) {
;(await store()).mutate((draft) => {
delete (draft as T)[key]
})
},
async all() {
return (await store()).value() as Readonly<T>
},
async onChange(fn) {
return (await store()).on('updated', full => fn(full as Readonly<T>))
},
}
}
17 changes: 0 additions & 17 deletions packages/devframe/src/utils/promise.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/hub-ui/src/client/state/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,6 @@ export async function createDocksContext(
...toRefs(docksContext) as any,
current: dockEntryStateMap.get(entry.id)!,
messages: messagesClient,
logs: messagesClient,
})
await executeSetupScript(entry, scriptContext)
}
Expand Down
23 changes: 0 additions & 23 deletions packages/hub/src/node/install-devframe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,29 +62,6 @@ async function resolvePageScriptClientScript(
return { ...clientScript, importFrom: joinURL(scriptBase, basename(importFrom)) }
}

/**
* Framework-neutral primitive backing {@link DevframeHubContext.install} -
* installs a {@link DevframeDefinition} as a dock inside a hub-aware context:
* serves the devframe's SPA at the resolved base path, synthesizes an iframe
* dock entry from the definition's metadata, and runs the definition's
* `setup(ctx)`. Reach for it through `ctx.install(devframe)` rather than
* calling it directly.
*
* Framework kits wrap `ctx.install` with their own plugin/middleware
* machinery, e.g. `@vitejs/devtools-kit`'s `createPluginFromDevframe`
* returns a Vite `Plugin` whose `devtools.setup` ultimately delegates here.
*/
/**
* Phase one of an install: run the duplication guard, serve the SPA + meta,
* register the iframe dock, and queue the definition's declarative wire
* services, everything up to (but not including) `setup(ctx)`. Returns a
* deferred setup thunk, or `null` when the devframe was deduplicated.
*
* The hub's initial batch uses this to collect every devframe's services
* across the whole hub, `ready()` them once, and only then run the setups,
* so services are ready before any setup, and a plugin can consume a service
* another plugin declared regardless of mount order.
*/
/**
* Serve a devframe's SPA (and the hub's connection meta) under `base`, if the
* definition ships client assets.
Expand Down
2 changes: 1 addition & 1 deletion packages/json-render-ui/src/action-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export interface ActionBridgeRpc {
call: (method: string, ...args: unknown[]) => Promise<unknown>
}

export interface JsonRenderActionError {
interface JsonRenderActionError {
action: string
error: unknown
}
Expand Down
2 changes: 0 additions & 2 deletions packages/json-render-ui/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export type { JrComponent } from './_shared'

export { Badge } from './Badge'
export { Button } from './Button'
export { Card } from './Card'
Expand Down
2 changes: 1 addition & 1 deletion packages/json-render-ui/src/dock-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { createApp, h, shallowRef } from 'vue'
import { baseRegistry } from './registry'
import { JsonRenderView } from './renderer'

export type { JsonRenderDockMountOptions, JsonRenderDockRenderer } from '@devframes/json-render/hub'
export type { JsonRenderDockRenderer } from '@devframes/json-render/hub'

export interface JsonRenderDockRendererOptions {
/** Registry to render with. Defaults to the base registry. */
Expand Down
14 changes: 0 additions & 14 deletions packages/json-render-ui/src/index.ts

This file was deleted.

25 changes: 1 addition & 24 deletions packages/json-render-ui/src/renderer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Spec } from '@devframes/json-render'
import type { ComponentRegistry } from '@json-render/vue'
import type { Component, PropType } from 'vue'
import type { PropType } from 'vue'
import type { ActionBridgeRpc } from './action-bridge'
import { basePropSchemas } from '@devframes/json-render'
import { JSONUIProvider, Renderer } from '@json-render/vue'
Expand Down Expand Up @@ -126,26 +126,3 @@ export const JsonRenderView = defineComponent({
}
},
})

/** Options for {@link createRenderer}. */
export interface CreateRendererOptions {
/** Component registry to render with. Defaults to the base registry. */
registry?: ComponentRegistry
}

/**
* Create a configured renderer component bound to a registry. The returned
* component is {@link JsonRenderView} with the registry defaulted, so a host
* can `createRenderer({ registry: myRegistry })` to swap the whole registry.
*/
export function createRenderer(options: CreateRendererOptions = {}) {
const registry = options.registry ?? baseRegistry
return defineComponent({
name: 'ConfiguredJsonRenderView',
inheritAttrs: false,
setup(_props, { attrs }) {
// Default the registry; every other prop flows through via attrs.
return () => h(JsonRenderView as Component, { registry, ...attrs })
},
})
}
Loading
Loading