Typed framework bindings

useEntities, useEntity, and useMutation for Vue, React, and Svelte on top of trellis/schema.

Generic hooks in trellis/react, trellis/vue, and trellis/svelte accept string types and loose records. Typed bindings take a defineType schema handle and infer row shapes, where filters, and resolve specs.

FrameworkImport path
Vue 3trellis/vue/typed
React 18+trellis/react/typed
Svelte 5trellis/svelte/typed

Install

npm install trellis@^3.2.0

Run a Trellis entity server (graph sidecar) in remote mode. Local embedded kernel subscriptions are not live yet.

npx trellis serve --port 8230
# or: just graph-nav  (from trellis repo serves :8230 + Vite demo)

Vue

<script setup lang="ts">
  import { TrellisDb } from "trellis/client/sdk";
  import { useEntities, useEntity, useMutation } from "trellis/vue/typed";

  import { NavItem, NavSection } from "./schema";

  const client = new TrellisDb({ url: "http://localhost:8230" });
  await client.registerType(NavSection);
  await client.registerType(NavItem);

  const sections = useEntities(client, NavSection, { resolve: { items: true } });
  const nav = useMutation(client, NavSection);
</script>

<template>
  <ul v-if="!sections.loading">
    <li v-for="s in sections.data" :key="s.id">{{ s.label }}</li>
  </ul>
</template>

Vue API

ComposableReturns
useEntities(client, schema, opts?){ data, loading, error } list
useEntity(client, schema, id, opts?){ data, loading, error } single row
useMutation(client, schema)create, update, delete typed to schema

opts may include where (field equality or whereCondition filters) and resolve (relation expansion).

React

import { useEntities, useMutation } from "trellis/react/typed";

function Sidebar({ client }: { client: TrellisDb }) {
  const { data: sections, loading } = useEntities(client, NavSection, {
    resolve: { items: true },
  });
  const nav = useMutation(client, NavSection);
  // ...
}

Semantics match Vue: same liveEntities / liveEntity signals underneath.

Svelte

<script lang="ts">
  import { useEntities, useMutation } from "trellis/svelte/typed";

  const sections = useEntities(client, NavSection, { resolve: { items: true } });
  const nav = useMutation(client, NavSection);
</script>

Svelte 5 runes bridge the shared Signal from trellis/client.

Generic vs typed

Generic (trellis/react)Typed (trellis/react/typed)
Type paramManual <T>Inferred from defineType
whereUntyped recordSchema field keys
resolveNot availableInferResolvedType aware
EntryReact hooksThis page

Parity demo

The graph-nav example ships React, Vue, and Svelte entries that share one schema.ts and one WebSocket channel. Open two tabs on the same framework URL; edits sync within a second.

From the trellis repo:

just graph-nav
# Hub: http://localhost:4200/  React / Vue / Svelte mounts

Full walkthrough: Typed SDK guide.