useArchiva Hook

The useArchiva hook provides access to the Archiva context in client components. Use it when you need to build custom event displays or integrate Archiva into your own components.

When to Use It

Use the useArchiva hook when:

  • You want to build a custom event display (not using the Timeline component)
  • You need to fetch events programmatically
  • You want to integrate Archiva into existing components
  • You need access to tokens for custom API calls

If you just want to display events, the Timeline component is easier and handles everything for you.

Basic Usage

'use client';

import { useArchiva } from '@archiva/archiva-nextjs/react/client';

export function CustomComponent() {
  const { apiBaseUrl, getToken, forceRefreshToken } = useArchiva();
  
  // Use the context values...
}

Return Value

The hook returns an object with:

PropertyTypeDescription
apiBaseUrlstringBase URL for the Archiva API (e.g., 'https://api.archiva.app')
getToken() => Promise<string>Get current frontend token (cached if valid, fetches new one if expired)
forceRefreshToken() => Promise<string>Force refresh the frontend token (bypasses cache)
projectIdstring | undefinedProject ID if provided to ArchivaProvider

Examples

Fetching Events Manually

Build a custom event list:

'use client';

import { useArchiva } from '@archiva/archiva-nextjs/react/client';
import { useState, useEffect } from 'react';

export function CustomEventList({ entityId }: { entityId: string }) {
  const { apiBaseUrl, getToken } = useArchiva();
  const [events, setEvents] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    async function loadEvents() {
      try {
        setLoading(true);
        const token = await getToken();
        
        const response = await fetch(
          `${apiBaseUrl}/api/events?entityId=${entityId}`,
          {
            headers: {
              Authorization: `Bearer ${token}`,
            },
          }
        );

        if (!response.ok) {
          throw new Error(`Failed to load events: ${response.statusText}`);
        }

        const data = await response.json();
        setEvents(data.items);
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Unknown error');
      } finally {
        setLoading(false);
      }
    }

    loadEvents();
  }, [entityId, apiBaseUrl, getToken]);

  if (loading) return <div>Loading events...</div>;
  if (error) return <div>Error: {error}</div>;

  return (
    <ul>
      {events.map((event) => (
        <li key={event.id}>
          {event.actionKey} - {event.receivedAt}
        </li>
      ))}
    </ul>
  );
}

Manual Token Refresh

Force a token refresh when needed:

'use client';

import { useArchiva } from '@archiva/archiva-nextjs/react/client';

export function RefreshButton() {
  const { forceRefreshToken } = useArchiva();
  const [refreshing, setRefreshing] = useState(false);

  const handleRefresh = async () => {
    try {
      setRefreshing(true);
      const newToken = await forceRefreshToken();
      console.log('Token refreshed:', newToken);
      // Token is now cached and ready to use
    } catch (error) {
      console.error('Failed to refresh token:', error);
    } finally {
      setRefreshing(false);
    }
  };

  return (
    <button onClick={handleRefresh} disabled={refreshing}>
      {refreshing ? 'Refreshing...' : 'Refresh Token'}
    </button>
  );
}

Using API Base URL

Access the configured API base URL:

'use client';

import { useArchiva } from '@archiva/archiva-nextjs/react/client';

export function ApiInfo() {
  const { apiBaseUrl } = useArchiva();
  
  return <div>Connected to: {apiBaseUrl}</div>;
}

Pagination Example

Implement custom pagination:

'use client';

import { useArchiva } from '@archiva/archiva-nextjs/react/client';
import { useState, useEffect } from 'react';

export function PaginatedEventList() {
  const { apiBaseUrl, getToken } = useArchiva();
  const [events, setEvents] = useState([]);
  const [cursor, setCursor] = useState<string | undefined>();
  const [loading, setLoading] = useState(false);

  const loadMore = async () => {
    setLoading(true);
    try {
      const token = await getToken();
      const params = new URLSearchParams({ limit: '25' });
      if (cursor) params.set('cursor', cursor);

      const response = await fetch(
        `${apiBaseUrl}/api/events?${params}`,
        {
          headers: { Authorization: `Bearer ${token}` },
        }
      );

      const data = await response.json();
      setEvents((prev) => [...prev, ...data.items]);
      setCursor(data.nextCursor);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    loadMore();
  }, []);

  return (
    <div>
      {events.map((event) => (
        <div key={event.id}>{event.actionKey}</div>
      ))}
      {cursor && (
        <button onClick={loadMore} disabled={loading}>
          {loading ? 'Loading...' : 'Load More'}
        </button>
      )}
    </div>
  );
}

Token Management

getToken()

Gets the current frontend token. If a valid token is cached, it returns immediately. If the token is expired or missing, it automatically fetches a new one.

Why use this? The SDK handles token caching and refresh automatically. You don't need to worry about token expiration—just call getToken() whenever you need to make an API request.

forceRefreshToken()

Forces a token refresh, bypassing the cache. Use this when:

  • You suspect the current token is invalid
  • You want to ensure you have a fresh token
  • You're debugging token issues

Note: In most cases, getToken() is sufficient. The SDK automatically refreshes tokens 30 seconds before they expire.

Error Handling

The hook will throw an error if:

  • Used outside of an ArchivaProvider
  • Token endpoint returns an error
  • Network request fails

Always wrap token calls in try/catch:

try {
  const token = await getToken();
  // Use token...
} catch (error) {
  // Handle error (e.g., show error message to user)
}

Requirements

  • Must be used within an ArchivaProvider (see ArchivaProvider)
  • Must be in a client component (use 'use client' directive)
  • Requires the frontend token route to be set up (see Frontend Token Route)

Import Path

Important: Always import from the client entrypoint:

import { useArchiva } from '@archiva/archiva-nextjs/react/client';

Do NOT import from the root package or /react in client components.

Next Steps