Structured Diagnostics

ctx.diagnostics is a thin layer over nostics for author-defined coded diagnostics, each with a stable code, docs URL, and structured payload.

ctx.diagnostics is a thin layer over nostics for author-defined coded diagnostics, each with a stable code, docs URL, and structured payload.

SurfacePurposeExample
ctx.diagnosticsCoded errors and warnings emitted from node-side codeMYP0001: Plugin foo not configured
ctx.messagesFree-form, user-facing notifications shown in the Messages panel'Audit complete: 3 issues found'

Shape

interface DevframeDiagnosticsHost {
  /** Proxy-backed lookup over every registered code. */
  readonly logger: Record<string, DiagnosticHandle>

  /** Register additional diagnostic definitions. */
  register: (definitions: Record<string, unknown>) => void

  /** Build a typed diagnostics object with devframe's ANSI reporter pre-wired. */
  defineDiagnostics: typeof defineDiagnostics
}

The diagnostics host ships pre-seeded with devframe's DF* codes plus the host framework's own (DTK*, etc.); call register() to add your own.

Register your own codes

export function MyPlugin(): PluginWithDevTools {
  return {
    name: 'my-plugin',
    devtools: {
      setup(ctx) {
        const myDiagnostics = ctx.diagnostics.defineDiagnostics({
          docsBase: 'https://example.com/errors',
          codes: {
            MYP0001: {
              why: (p: { name: string }) => `Plugin "${p.name}" is not configured`,
              fix: 'Add the plugin to your `vite.config.ts` and pass an options object.',
            },
            MYP0002: {
              why: 'Cache directory missing; running cold.',
            },
          },
        })

        ctx.diagnostics.register(myDiagnostics)

        // Emit through the host framework's shared reporter:
        myDiagnostics.MYP0002()
      },
    },
  }
}

Code conventions

Codes are a 4-letter prefix + 4-digit number (e.g. MYP0001); pick one distinctive enough to avoid collisions.

DF belongs to devframe itself; the @vitejs/devtools packages own DTK, RDDT, and VDT. The prefixes in use are listed in the Node-Side API reference.

A definition takes a why (message) and optional fix (resolution), string or function; docsBase auto-attaches the URL to each diagnostic.

Emit a diagnostic

Each registered code becomes a callable DiagnosticHandle: call it to report, or throw to raise.

// Throw: control flow stops here
throw myDiagnostics.MYP0001({ name: 'foo' })

// Report without throwing (default console method: `warn`)
myDiagnostics.MYP0002()

// Override the console method per call
myDiagnostics.MYP0002({}, { method: 'error' })

// Attach a `cause`: merged into the params object
throw myDiagnostics.MYP0001({ name: 'foo', cause: error })

The returned Diagnostic extends Error, so throw narrows following lines as unreachable.

Typed handle reference

ctx.diagnostics.logger is loosely typed over all registered codes; for autocompletion, keep and call the typed result of defineDiagnostics() directly, whose pre-wired ANSI reporter gives it and the lookup identical output.

Document your codes

Pair each code with a documentation page:

docs/errors/
  index.md            # Table of all codes
  MYP0001.md          # One page per code
  MYP0002.md

Each page covers message, cause, example, and fix; see any DF code page for the template.

When to use what

ctx.diagnostics covers coded, docs-backed conditions, targeting tool authors and CI; ctx.messages covers user-facing UI activity, targeting the human at the panel.