Guides

Vue and Nuxt

Use the SDK in Vue 3 and Nuxt with composables and the app plugin.

@hydraone-sdk/core/vue provides two composables that wrap the core client in reactive state. It requires vue 3.3 or later as a peer dependency.

Composables

import { computed } from 'vue';
import { useWalletBridgeClient } from '@hydraone-sdk/core/vue';

export function useGameSession() {
  const { isConnected, address, balanceADA, connect, disconnect, error } = useWalletBridgeClient({
    autoConnect: true,
  });
  // TEMP auth hidden: const { isAuthenticated, signIn, signOut, isExpired } = useGameAuth();

  const label = computed(() =>
    isConnected.value ? `${address.value} (${balanceADA.value} ADA)` : 'Offline',
  );

  /* TEMP auth hidden
  async function toggleLogin() {
    if (isAuthenticated.value) await signOut();
    else await signIn({ challenge: 'server-issued-nonce' });
  }
  */

  return { label, connect, disconnect, error };
}

useWalletBridgeClient(options?)

Refs: connectionState, isConnected, address, usedAddresses, balanceADA, balanceLovelace (bigint), networkId, hostInfo, isAudioMuted, theme, error. Also returns the client.

Actions: init, connect, disconnect, refreshBalance, refreshAddress, signTx, submitTx, signData, setOrientation, triggerHaptic, requestDepositModal, getPlayerProfile.

Options: any WalletBridgeClientOptions, plus client, autoConnect, autoRefreshBalance.

Connect to the App Center

Inside the App Center, pass appCenterOrigin and the SDK creates the PostMessageTransport for you (and destroys it with the client). You do not need to import PostMessageTransport:

const { connect } = useWalletBridgeClient({
  appCenterOrigin: 'https://alpha.hydraone.app', // or an array: ['https://alpha.hydraone.app', 'https://staging.hydraone.app']
});

The client is shared, so the first composable to run decides its options. Set appCenterOrigin in the first call, or register the plugin below.

createHydraOne gives each app instance its own client and auth manager. Nuxt builds a new app for every request, so nothing is shared between users:

// plugins/hydra.ts
import { createHydraOne } from '@hydraone-sdk/core/vue';

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(createHydraOne({ appCenterOrigin: 'https://alpha.hydraone.app' }));
});

For a plain Vue app, call app.use(createHydraOne({ appCenterOrigin: '...' })) before app.mount. After that, useWalletBridgeClient() and useGameAuth() need no options. On unmount the plugin destroys the client it created; a client you pass in with createHydraOne({ client }) is left alone.

createHydraOne(options) accepts any client option (including appCenterOrigin) plus client (use an existing client) and storage. It provides the client and auth manager under HYDRA_CLIENT_KEY and HYDRA_AUTH_KEY. The composables look up options.client, then the plugin, then the shared instance. On unmount the plugin destroys what it created; a client you pass in is left alone.

Shared instances

Without the plugin, both composables use one shared client and one shared auth manager for the whole app, created on first use with a SafeLocalStorageAdapter (an in-memory one on the server). The first call must pass appCenterOrigin (or a transport), otherwise creating the client throws. On the server the shared instances are not cached, so each call gets a fresh one and nothing leaks between requests.

If you need to share the transport, for example with the host storage relay, create it yourself and register the instances:

import {
  WalletBridgeClient,
  PostMessageTransport,
  HostStorageRelayAdapter,
  GameAuthManager,
} from '@hydraone-sdk/core';
import { setSharedWalletBridgeClient, setSharedGameAuthManager } from '@hydraone-sdk/core/vue';

export function installHydra() {
  const transport = new PostMessageTransport({ appCenterOrigin: 'https://alpha.hydraone.app' });
  const client = new WalletBridgeClient({ transport });
  const storage = new HostStorageRelayAdapter({ transport });

  setSharedWalletBridgeClient(client);
  setSharedGameAuthManager(new GameAuthManager({ client, storage }));
}

Call installHydra() before any component uses the composables, for example in a Nuxt client plugin (plugins/hydra.client.ts) or in your app entry. Pass null to the setters to reset them in tests.

Nuxt

  • Run the setup in a .client.ts plugin, because it needs window and postMessage.
  • The composables are SSR-safe: they check for window, register listeners only after mount, and remove them with onScopeDispose. Register createHydraOne as a universal plugin (without .client) so every server request gets its own client.
  • With ssr: false the plugin is optional; useWalletBridgeClient({ appCenterOrigin }) is enough.
  • Wrap wallet-dependent markup in <ClientOnly> or a v-if on isConnected so server and client markup match.

Testing

Create a WalletBridgeClient with a stub ITransport, register it with setSharedWalletBridgeClient, and mount your component with Vue Test Utils. See Testing and health checks.