sova-devtools 0.1.10

In-app DevTools bar for Sova (HTML inject, SSE timeline, request snapshots)
Documentation
<script setup lang="ts">
import { computed } from "vue";
import { FileJson } from "@lucide/vue";
import CodeBlock from "../components/CodeBlock.vue";
import Chip from "../components/Chip.vue";
import EmptyState from "../components/EmptyState.vue";
import Pane from "../components/Pane.vue";
import { useDevToolsStore } from "../stores/devtools";

const store = useDevToolsStore();
const cfg = computed(
  () =>
    store.config as {
      profile?: string;
      plugins?: string[];
      features?: string[];
      mounts?: Record<string, Record<string, unknown>>;
    } | null,
);
const profile = computed(() => cfg.value?.profile ?? "—");
const features = computed(() => cfg.value?.features ?? []);
const hasI18n = computed(() => features.value.includes("i18n"));
const mounts = computed(() => cfg.value?.mounts ?? {});
const graphqlMount = computed(
  () => mounts.value.graphql as Record<string, unknown> | undefined,
);
const grpcMount = computed(
  () => mounts.value.grpc as Record<string, unknown> | undefined,
);
const rabbitMount = computed(
  () => mounts.value.rabbit as Record<string, unknown> | undefined,
);
const raw = computed(() => JSON.stringify(store.config ?? {}, null, 2));
</script>

<template>
  <EmptyState
    v-if="store.config == null && !store.isPlayground"
    title="No config payload"
    hint="Hub config endpoint returned empty."
    :icon="FileJson"
  />
  <div v-else class="flex flex-col gap-3">
    <Pane title="Runtime" :icon="FileJson" :hint="profile">
      <div class="mb-3 flex flex-wrap gap-2">
        <Chip label="profile" :value="profile" tone="info" />
        <Chip
          v-for="f in features"
          :key="f"
          label="feature"
          :value="f"
          tone="ok"
        />
        <span
          v-if="!features.length"
          class="text-[12px] text-[var(--dt-faint)]"
          >no optional DevTools features compiled in</span
        >
      </div>
      <Pane
        v-if="hasI18n"
        title="Internationalization"
        :icon="FileJson"
        hint="sova-i18n middleware"
      >
        <p class="m-0 text-[11px] leading-relaxed text-[var(--dt-muted)]">
          When <code class="dt-mono">devtools-i18n</code> is enabled, resolved
          <code class="dt-mono">locale</code> is captured on each request snapshot
          (Request tab → locale).
        </p>
      </Pane>
      <Pane
        v-if="graphqlMount"
        title="GraphQL server"
        :icon="FileJson"
        hint="Mounted paths from sova-graphql"
      >
        <div class="mb-2 flex flex-wrap gap-2">
          <Chip
            v-for="(val, key) in graphqlMount"
            :key="key"
            :label="String(key)"
            :value="val == null ? 'off' : String(val)"
            tone="info"
          />
        </div>
        <p class="m-0 text-[11px] leading-relaxed text-[var(--dt-muted)]">
          Open GraphiQL in the browser for ad-hoc queries; operations on POST
          <code class="dt-mono">{{ graphqlMount.api ?? '/graphql' }}</code>
          show up in the GraphQL tab.
        </p>
      </Pane>
      <Pane
        v-if="grpcMount"
        title="gRPC client"
        :icon="FileJson"
        hint="Connect-JSON from sova-grpc"
      >
        <div class="mb-2 flex flex-wrap gap-2">
          <Chip
            v-for="(val, key) in grpcMount"
            :key="key"
            :label="String(key)"
            :value="Array.isArray(val) ? val.join(', ') : val == null ? 'off' : String(val)"
            tone="info"
          />
        </div>
      </Pane>
      <Pane
        v-if="rabbitMount"
        title="RabbitMQ"
        :icon="FileJson"
        hint="sova-rabbit broker"
      >
        <div class="mb-2 flex flex-wrap gap-2">
          <Chip
            v-for="(val, key) in rabbitMount"
            :key="key"
            :label="String(key)"
            :value="val == null ? 'off' : String(val)"
            tone="info"
          />
        </div>
      </Pane>
      <CodeBlock :code="raw" title="config" language="json" />
    </Pane>
  </div>
</template>