The CWA is in heavy development
The CWA is still in alpha and not ready for production - some code and implementations are likely to change. If you would like to try out the CWA, please enjoy what we have provided and feel free to provide feedback, or get involved on GitHub.
DraftNuxt Module

The useCwa() API

Complete reference for the Cwa class — the central access point for resources, auth, forms, admin, and site config.

useCwa() returns the singleton Cwa instance injected by the module plugin. In templates you can use $cwa directly. In <script setup> and composables, call useCwa().

// In <script setup>
const cwa = useCwa()

// In templates
$cwa.auth.signedIn.value

The Cwa class has six public sub-services:

PropertyClassPurpose
cwa.resourcesResourcesRead-only view of fetched resource state
cwa.resourcesManagerResourcesManagerCRUD operations on resources
cwa.authAuthAuthentication state and actions
cwa.formsFormsForm view state and error access
cwa.adminAdminEdit mode, component stack, admin panel
cwa.siteConfigSiteConfigSite-wide settings from the API

cwa.resources — Resources

The read-only store view. All values are ComputedRef — they react to resource fetches automatically.

cwa.resources exposes two complementary families of page/pageData getters. Understanding the difference is important for using them correctly:

FamilyGettersWhat they returnRequires manifest?Use for
Flat leafpageIri, pageDataIri, page, pageDataThe page/pageData at the leaf of the current URL — i.e. the innermost, deepest target of the routeNoSEO meta, admin identity, reading article data
Depth-awarepageIriAtDepth(n), pageDataIriAtDepth(n), pageAtDepth(n), pageDataAtDepth(n)The page/pageData at a specific rendering depth from the manifestDepths > 0 require a manifest<CwaPage /> rendering, layout-level access

The flat leaf getters follow the fetch path to the deepest resource — for a URL like /events/2024/conference, pageIri resolves to the innermost page. The depth-aware methods read the manifest's irisByDepth array — pageIriAtDepth(0) is the outermost page, pageIriAtDepth(2) is two levels deep. These families are complementary, not interchangeable.

Layout

cwa.resources.layout        // ComputedRef<CwaCurrentResourceInterface | undefined>
cwa.resources.layoutIri     // ComputedRef<string | undefined>

Layout always comes from the depth-0 page regardless of nesting depth.

Flat Leaf Getters

Use these when you need to know what the current URL is about — the page or article the visitor navigated to. They work without a manifest (no pagesDepth requirement) and are what the SEO plugin uses to populate <title> and <meta> tags.

cwa.resources.page          // ComputedRef<CwaCurrentResourceInterface | undefined>
cwa.resources.pageIri       // ComputedRef<string | undefined>

cwa.resources.pageData      // ComputedRef<CwaCurrentResourceInterface | undefined> — defined on dynamic pages only
cwa.resources.pageDataIri   // ComputedRef<string | undefined>

cwa.resources.displayPage   // ComputedRef — the "identity" page shown in the admin (pageData for dynamic pages, page otherwise)
cwa.resources.displayPageIri

Typical use — reading article data in a page template:

const cwa = useCwa()
const headline = computed(() => cwa.resources.pageData.value?.data?.headline)
const title = computed(() => cwa.resources.pageData.value?.data?.title ?? cwa.resources.page.value?.data?.title)

Page Type Flags

cwa.resources.usesPageTemplate   // ComputedRef<boolean> — true when the page is marked isTemplate
cwa.resources.isDataPage         // ComputedRef<boolean> — true when a pageData record is active
cwa.resources.isDynamicPage      // ComputedRef<boolean> — isDataPage && usesPageTemplate

Depth-Aware Methods

Use these when you need to know what renders at a specific nesting level. They read manifest.irisByDepth[n]. At depth 0 they fall back gracefully to the flat fetch path, but at depth 1 and beyond a manifest is required.

These are used internally by <CwaPage /> to pass the correct IRI to each nesting level — you rarely call them with an explicit depth outside of <CwaPage /> itself.

cwa.resources.depthCount                    // ComputedRef<number> — number of depth levels in the manifest (minimum 1)
cwa.resources.pageAtDepth(0)                // ComputedRef — outermost page resource
cwa.resources.pageAtDepth(1)                // ComputedRef — first nested page resource
cwa.resources.pageIriAtDepth(0)             // ComputedRef<string | undefined>
cwa.resources.pageDataAtDepth(0)            // ComputedRef — pageData at a given depth
cwa.resources.pageDataIriAtDepth(0)         // ComputedRef<string | undefined>

Calling without an argument — inside a component rendered by <CwaPage />, omit the depth. The component injects cwa-page-own-depth and the method resolves to the correct level automatically:

// Inside a page template component rendered by <CwaPage /> — no depth arg needed
const pageIri = cwa.resources.pageIriAtDepth()         // resolves to own depth
const pageDataIri = cwa.resources.pageDataIriAtDepth() // resolves to own depth
const page = cwa.resources.pageAtDepth()
const pageData = cwa.resources.pageDataAtDepth()

Inject keys provided by <CwaPage />:

KeyTypeWhat it contains
cwa-page-own-depthnumberThe depth at which the current template is rendered
cwa-page-depthnumberThe depth for a nested <CwaPage /> child (incremented automatically)
cwa-page-data-iriComputedRef<string | undefined>IRI of the PageData record at the current depth

cwa-page-data-iri is the most convenient way to access PageData in a template component — no depth arithmetic needed:

import { inject } from 'vue'
import type { ComputedRef } from 'vue'

const pageDataIri = inject<ComputedRef<string | undefined>>('cwa-page-data-iri')
const eventData = computed(() => {
    if (!pageDataIri?.value) return null
    return cwa.resources.getResource(pageDataIri.value).value
})

Arbitrary Resource Lookup

// Fetch any resource by IRI (returns a ComputedRef tracking that IRI)
const resource = cwa.resources.getResource('/component/titles/018e-...')
resource.value?.data?.title

// All resources currently loaded for this page
cwa.resources.currentResources    // { [iri: string]: CwaCurrentResourceInterface }
cwa.resources.currentIds          // string[] — IRI list for current page

// Find a component group by its reference name
cwa.resources.getComponentGroupByReference('navigation')

Loading State

cwa.resources.isLoading         // ComputedRef<boolean> — true during any primary fetch
cwa.resources.pageLoadProgress  // ComputedRef<{ total, complete, percent, resources[] }>

Publishable Helpers

cwa.resources.findPublishedComponentIri(iri)      // → published IRI for this draft
cwa.resources.findDraftComponentIri(iri)          // → draft IRI for this published resource
cwa.resources.isIriPublishableEquivalent(a, b)    // → true when a and b are draft/publish twins
cwa.resources.findAllPublishableIris(iri)         // → both IRIs for a publishable resource

cwa.resourcesManager — ResourcesManager

CRUD operations that talk to the API. These are used internally by the admin panel and are available for advanced custom UIs.

Creating Resources

await cwa.resourcesManager.createResource({
    endpoint: '/component/titles',
    data: { title: 'Hello', uiComponent: 'Title' }
})

Updating Resources

await cwa.resourcesManager.updateResource({
    endpoint: '/component/titles/018e-...',
    data: { title: 'Updated Title' }
})

Deleting Resources

await cwa.resourcesManager.deleteResource({
    iri: '/component/titles/018e-...'
})

Saving (Upsert-style)

saveResource handles both create and update depending on whether the IRI is the NEW_RESOURCE_IRI sentinel:

cwa.resourcesManager.saveResource({ endpoint, data })

Error Management

cwa.resourcesManager.errors        // CwaErrorEvent[]
cwa.resourcesManager.hasErrors     // boolean
cwa.resourcesManager.addError(event)
cwa.resourcesManager.removeError(id)

cwa.auth — Auth

Authentication state and all user account actions.

State

cwa.auth.signedIn        // ComputedRef<boolean>
cwa.auth.user            // ComputedRef<CwaUser | undefined>
cwa.auth.roles           // ComputedRef<string[]>
cwa.auth.isAdmin         // ComputedRef<boolean> — true for ROLE_ADMIN or higher
cwa.auth.status          // ComputedRef<CwaAuthStatus> (0=SIGNED_OUT, 1=LOADING, 2=SIGNED_IN)
cwa.auth.hasRole('ROLE_ADMIN')  // boolean — check a specific role

Actions

// Sign in with username/password
const result = await cwa.auth.signIn({ username: 'alice@example.com', password: 'secret' })
if (result instanceof FetchError) {
    console.error('Login failed', result.statusCode)
}

// Sign out
await cwa.auth.signOut()

// Request a password reset email
await cwa.auth.forgotPassword('alice@example.com')

// Complete a password reset (from link parameters)
await cwa.auth.resetPassword({
    username: 'alice',
    token: 'abc123',
    passwords: { first: 'new_password', second: 'new_password' }
})

// Verify email address (from link parameters)
await cwa.auth.verifyEmail({ username: 'alice', token: 'abc123' })

// Confirm email address change (from link parameters)
await cwa.auth.confirmEmail({ username: 'alice', token: 'abc123', newEmail: 'new@example.com' })

// Re-send verification email
await cwa.auth.resendVerifyEmail('alice')
await cwa.auth.resendVerifyNewEmail('alice')

// Re-hydrate user from the /me endpoint (e.g. after updating profile)
await cwa.auth.refreshUser()

cwa.forms — Forms

Access the structured form view data for Form component resources.

getForm(iri)

Returns a ComputedRef of the structured form view, keyed by field name:

const formView = cwa.forms.getForm('/component/forms/018e-...')

// Access a field's vars
const nameField = formView.value?.['contact[name]']
nameField?.vars.value     // current value
nameField?.vars.errors    // string[]
nameField?.vars.required  // boolean
nameField?.vars.block_prefixes  // ['form', 'text', '_contact_name'] — for type-specific rendering

getFormViewErrors(formIri, field)

Convenience computed that returns the error array for a specific field, or undefined if there are none:

const nameErrors = cwa.forms.getFormViewErrors('/component/forms/018e-...', 'contact[name]')
// nameErrors.value → ['This field is required'] or undefined

cwa.admin — Admin

Controls admin edit mode and the component selection stack. Mostly used internally, but exposed for custom admin UIs.

cwa.admin.isEditing.value        // boolean — whether the admin panel is open in edit mode
cwa.admin.toggleEdit(true)       // open edit mode
cwa.admin.toggleEdit(false)      // close edit mode
cwa.admin.toggleEdit()           // toggle
cwa.admin.emptyStack()           // clear the selected component stack
cwa.admin.emitRedraw()           // force re-render of the component overlay

The admin tracks unsaved changes and shows a confirmation dialog on navigate:

cwa.navigationDisabled.value                    // boolean
cwa.adminNavigationGuardFn                      // pass to router.beforeEach

cwa.siteConfig — SiteConfig

Site-wide settings persisted in the API and cached in the Pinia store.

cwa.siteConfig.config           // the resolved config object (ComputedRef via store)
cwa.siteConfig.savedSiteConfig  // the server-persisted config (before any unsaved changes)
cwa.siteConfig.isLoading        // boolean

// Load or refresh from the API
await cwa.siteConfig.loadConfig()

// Save changed keys (only changed values are PATCHed)
cwa.siteConfig.saveConfig({
    siteName: 'My New Site Name',
    robotsEnabled: false
})

Top-Level Methods on cwa

These are lower-level fetch primitives. Most application code uses the composables instead.

// Fetch a specific resource by IRI
cwa.fetchResource({ path: '/component/titles/018e-...', isPrimary: false })

// Fetch the route manifest for a given Vue Router route
cwa.fetchRoute(route)

// Generic fetch (used internally)
cwa.fetch(event)

// Cancel the current primary page fetch
cwa.clearPrimaryFetch()

// Get the API Platform documentation (for component metadata)
await cwa.getApiDocumentation()
await cwa.getComponentMetadata(refresh, includePosition)

// Access the resolved API URL
cwa.apiUrlBase   // string

// Access the module's nuxt.config registrations
cwa.resourcesConfig    // the cwa.resources: {} config object
cwa.layoutsConfig      // the cwa.layouts: {} config object
cwa.pagesConfig        // the cwa.pages: {} config object
cwa.pageDataConfig     // the cwa.pageData: {} config object

Common Patterns

Auth-conditional rendering

Always wrap in <ClientOnly> — auth state is only available after client-side hydration:

<ClientOnly>
    <UserMenu v-if="$cwa.auth.signedIn.value" />
    <NuxtLink v-else to="/login">Sign in</NuxtLink>
</ClientOnly>

Accessing the current page title

const pageTitle = computed(() =>
    cwa.resources.pageData.value?.data?.title
    ?? cwa.resources.page.value?.data?.title
    ?? ''
)

Checking load state before rendering

const isReady = computed(() =>
    !cwa.resources.isLoading.value && !!cwa.resources.page.value?.data
)