Skip to content

@privateaim/client-vue ​

Reusable Vue 3 component library for building PrivateAIM client applications. Provides UI components for managing analyses, projects, nodes, registries, and more.

Components are built on the @vuecs/* component family and styled through Tailwind CSS v4 utility classes — consuming applications must load the @privateaim/client-vue-theme stylesheet (or provide an equivalent Tailwind v4 theme) for the components to render styled.

Installation ​

bash
npm install @privateaim/client-vue

Peer Dependencies ​

The library expects the consuming application to provide:

  • vue ^3.5
  • @authup/client-web-kit — Authup UI components
  • @vuecs/* — component framework (forms, list, table, pagination, overlays, icon, button, elements, link, timeago, countdown, …)
  • validup + @validup/vue + @validup/zod — form validation
  • ilingo + @ilingo/vue + @ilingo/validup — translations
  • @privateaim/core-kit, @privateaim/core-http-kit, @privateaim/storage-kit, @privateaim/telemetry-kit — domain types and HTTP clients

Usage ​

Plugin Registration ​

typescript
import { install } from '@privateaim/client-vue';
import { createApp } from 'vue';

const app = createApp(App);

app.use({ install }, {
    coreURL: 'http://localhost:3000/core/',
    storageURL: 'http://localhost:3000/storage/',
    telemetryURL: 'http://localhost:3000/telemetry/',
    components: true,           // register all components globally
    translatorLocale: 'en',
});

Plugin Options ​

typescript
type Options = {
    coreURL: string,            // Core API base URL (required)
    storageURL: string,         // Storage service base URL (required)
    telemetryURL: string,       // Telemetry service base URL (required)
    components?: boolean | string[],  // Register globally (true = all, string[] = selective)
    translatorLocale?: string,  // Locale for translations
    isServer?: boolean,         // SSR mode flag
};

The plugin installs HTTP clients for the core, storage, and telemetry services, a socket manager for real-time updates, and a translator instance.

Components ​

Components can be imported individually:

vue
<script setup>
import {
    FAnalysisList,
    FProjectForm,
    FNodeList,
    FRegistryList,
    FMasterImagePicker,
    FEntityDelete,
    FProcessStatus,
} from '@privateaim/client-vue';
</script>

Available Components ​

AreaComponents
Analysislist, form, details, node assignment, permissions, logs, bucket files
Projectlist, form, node management
Nodelist, details
Registrylist, form, project management
Master Imagelist, picker, group management
Bucket Filelist, upload, stream
Event / Loglist, details
UtilityFEntityDelete, FProcessStatus, FContentAction, login form

FContentAction is the primary action of a collection section, rendered at the right of the section's title row. It is route-aware: + Add on overviewUrl, ← Back on addUrl, and nothing on any other route. A section therefore mounts a single instance no matter which of its routes is active, rather than one per route — and a sibling list route such as an approval queue renders no action at all instead of inheriting a create action.

vue
<FContentAction
    overview-url="/admin/clients"
    add-url="/admin/clients/add"
    :add-disabled="!canCreate"
/>

addDisabled carries the create permission; VCButton blocks activation of a disabled link target, so it cannot navigate into a page the actor would be rejected from.

Composables ​

typescript
import {
    injectCoreHTTPClient,
    injectStorageHTTPClient,
    injectTelemetryHTTPClient,
    injectSocketManager,
    useTranslator,
} from '@privateaim/client-vue';

// Inside a setup function. The injected values are typed as the CONTRACTS —
// ICoreClient / IStorageClient / ITelemetryClient — not the concrete classes,
// so a test can supply a fake without any cast.
const coreClient = injectCoreHTTPClient();       // ICoreClient
const storageClient = injectStorageHTTPClient(); // IStorageClient

Install Options ​

typescript
import { install } from '@privateaim/client-vue';

app.use(install, {
    coreURL: 'http://localhost:4000',
    storageURL: 'http://localhost:4001',
    telemetryURL: 'http://localhost:4002',

    // Opt-in: installs the realtime socket manager. It needs a live authup
    // store and opens a websocket, so it stays OFF unless requested.
    realtime: true,
});
OptionPurpose
coreURL / storageURL / telemetryURLBase URLs used to construct the clients
coreHTTPClient / storageHTTPClient / telemetryHTTPClientPre-built clients used INSTEAD of constructing from the URLs
piniaPinia instance backing authup's store; required outside Nuxt, and forwarded to the socket manager
realtimeInstall the socket manager (default off)
componentsRegister components globally (true, or a name allow-list)
translatorLocaleInitial locale

The install is not self-sufficient

@authup/client-web-kit's auth hook and store must already be provided on the same app — setupBaseHTTPClient calls injectHTTPClientAuthenticationHook(app) and the permission-check composables call injectStore(). Installing only client-vue throws.

Testing with a fake client ​

Pass a FakeClient through the *HTTPClient options rather than pre-providing it: each installer early-returns on isXHTTPClientUsable(app) and authup's provide() is first-wins, so an ordering mistake fails silently, with the real client winning.

typescript
import { createFakeClient } from '@privateaim/core-http-kit/testing';

const coreHTTPClient = createFakeClient({
    handlers: { 'DELETE /projects/:id': () => ({ data: {}, meta: {} }) },
});

app.use(install, { coreURL, storageURL, telemetryURL, coreHTTPClient });

// …then assert against what the component actually dispatched
expect(coreHTTPClient.requests[0]).toMatchObject({ method: 'DELETE', params: { id: 'abc' } });

Working with Response Envelopes ​

Every single-record call on the injected clients resolves to the { data, meta } record envelope (see API Reference). Destructure data at the call site — handing the envelope onward is the failure mode, because a component emit or a Ref<Record> accepts it without complaint and the consuming panel then renders blank:

typescript
// Correct
const { data: node } = await coreClient.node.getOne(nodeId);

// Wrong — `node` is { data, meta }, not the record
const node = await coreClient.node.getOne(nodeId);

Entity managers unwrap for you: createEntityManager(...) exposes the bare record on manager.data, and the created / updated / deleted callbacks (and the matching component emits) receive the bare record too. Collections are unchanged — getMany was always enveloped, and list handlers keep receiving { data, meta }.

Technology ​

  • vue — Vue 3 framework (composition API)
  • @vuecs/* — component framework (forms, lists, tables, pagination, overlays, icons)
  • @vuecs/icon + Iconify — SVG icons (fa6-solid / fa6-brands collections; no webfont). Icon names must be written as literals — consuming apps bundle only the names a build-time scan finds in this package's source, so a composed name (`fa6-brands:${os}`) is never bundled. See client-ui — Icons.
  • validup / @validup/vue / @validup/zod — form validation wired to the core-kit Zod validators
  • ilingo / @ilingo/vue — translations
  • @authup/client-web-kit — authentication UI
  • @vueuse/core — Vue composition utilities
  • @privateaim/core-kit — domain types
  • @privateaim/core-http-kit — Core API client
  • @privateaim/storage-kit — storage types and client
  • @privateaim/telemetry-kit — telemetry types and client