Features

Hooks

Extend frontend-core and orchestr behavior using Nuxt runtime hooks

Frontend-core and orchestr expose Nuxt runtime hooks that let you extend or modify the complete behaviour of your Laioutr Frontend. Register hooks inside a Nuxt plugin for client-side hooks, or a Nitro plugin for server-side hooks.

Frontend Core Hooks

These hooks run on the client. Register them in a Nuxt plugin with nuxtApp.hook().

Three hooks let you override how linkResolver resolves links, switches locale paths, and switches market URLs. If your hook sets result.value, the default resolution is skipped entirely.

HookArgumentsWhen it fires
frontend-core:link-resolver:resolve{ link: Link, result }On every call to linkResolver.resolve()
frontend-core:link-resolver:switch-locale-path{ targetLanguageId: string, result }When switching the current page to another language
frontend-core:link-resolver:switch-market-url{ targetMarketId: string, targetLanguageId?: string, result }When switching to a different market (may include host change)

In all three cases, result has the shape { value: string | undefined } and can be used to override the default resolution.

app/plugins/custom-link-resolver.ts
export default defineNuxtPlugin((nuxtApp) => {
  // Resolve product references to an external catalog URL
  nuxtApp.hook('frontend-core:link-resolver:resolve', ({ link, result }) => {
    if (link.type === 'reference' && link.reference.type === 'Product') {
      result.value = `https://catalog.example.com/p/${link.reference.slug}`;
    }
  });

  // Override locale switching for a specific market
  nuxtApp.hook('frontend-core:link-resolver:switch-locale-path', ({ targetLanguageId, result }) => {
    if (targetLanguageId === 'fr-CH') {
      result.value = `/fr-ch${useRoute().path}`;
    }
  });
});

Page Renderer

This hook lets you control which page variant is rendered. Pages can have multiple variants (for A/B testing, personalization, or conditional layouts). If you set result.value to a RenderPageVariant, that variant is used instead of the default.

HookArgumentsWhen it fires
frontend-core:page-renderer:select-page-variant{ page: RenderPage, result }When the PageRenderer component selects a variant

Here result has the shape { value: RenderPageVariant | undefined }. The page object contains id, type, path, and a variants array.

app/plugins/ab-testing.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('frontend-core:page-renderer:select-page-variant', ({ page, result }) => {
    const variantId = useCookie('ab-variant').value;
    const match = page.variants.find((v) => v.id === variantId);
    if (match) {
      result.value = match;
    }
  });
});

Orchestr Client Hooks

These hooks fire during client-side action execution. They follow the lifecycle pattern: before fires before the request, success or error after resolution, and finally always. All receive a token string that identifies the action (e.g. ecommerce/cart/add-items).

Fetch Action Hooks

Fired by fetchAction, useFetchAction, useQueryAction, and useMutationAction (which uses fetchAction internally).

HookArguments
orchestr:action:fetch:before{ token, input }
orchestr:action:fetch:success{ token, output }
orchestr:action:fetch:error{ token, error }
orchestr:action:fetch:finally{ token, output?, error?, input }

Mutation Action Hooks

Fired by useMutationAction.

HookArguments
orchestr:action:mutation:before{ token, input }
orchestr:action:mutation:success{ token, output, input, context }
orchestr:action:mutation:error{ token, error, context }
orchestr:action:mutation:finally{ token, output?, error?, input, context }

The context value comes from Pinia Colada's mutation context and is set by the onMutate callback.

app/plugins/action-error-tracking.ts
export default defineNuxtPlugin((nuxtApp) => {
  // Track all failed actions (both fetch and mutation)
  nuxtApp.hook('orchestr:action:fetch:error', ({ token, error }) => {
    errorTracker.capture(error, { action: token, type: 'fetch' });
  });

  nuxtApp.hook('orchestr:action:mutation:error', ({ token, error }) => {
    errorTracker.capture(error, { action: token, type: 'mutation' });
  });
});

Client Environment

The orchestr:client-env:modify hook fires synchronously every time orchestr builds the clientEnv object before sending an action request. Use it to set locale, currency, or custom fields based on the current frontend state.

HookArguments
orchestr:client-env:modify{ clientEnv: ClientEnv }

The ClientEnv object has the following shape:

{
  locale: string;
  currency: string;
  isPreview?: boolean;
  custom?: Record<string, any>;
}

Mutate clientEnv directly; don't replace it.

app/plugins/client-env.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('orchestr:client-env:modify', ({ clientEnv }) => {
    clientEnv.locale = useLanguage().value.locale;
    clientEnv.currency = useCurrency().value;
  });
});
This hook is called synchronously (not async). Avoid async work inside the callback.

Orchestr Server Hooks

These hooks fire during server-side action handler execution. They are Nitro runtime hooks and must be registered in a Nitro plugin, not a Nuxt plugin.

HookArguments
orchestr:action:handler:before{ token, input, clientEnv }
orchestr:action:handler:error{ token, error }
orchestr:action:handler:success{ token, output }
orchestr:action:handler:finally{ token, output?, error?, input }
server/plugins/action-logging.ts
export default defineNitroPlugin((nitroApp) => {
  const pending = new Map<string, number>();

  nitroApp.hooks.hook('orchestr:action:handler:before', ({ token }) => {
    pending.set(token, Date.now());
  });

  nitroApp.hooks.hook('orchestr:action:handler:error', ({ token, error }) => {
    const startedAt = pending.get(token);
    const duration = startedAt ? Date.now() - startedAt : undefined;
    console.error(`[orchestr] ${token} failed after ${duration}ms`, error);
    pending.delete(token);
  });
});