@cxpa/sdk/zone

Exports

SymbolKindPurpose
createZoneMiddlewarefactoryNext.js middleware that verifies the per-request zone JWT.
getSessionhelperRead the verified claims and bearer token inside a server component.
getZoneTokenhelperRead just the bearer token from request headers.
createZoneClientfactoryHTTP client for the zone-scoped platform endpoints.
ApiErrorclassThrown by client methods on non-2xx responses.

createZoneMiddleware(options)

Drop into middleware.ts at the root of your zone app.

ts
import { createZoneMiddleware } from '@cxpa/sdk/zone'

export const middleware = createZoneMiddleware({
  secret: process.env.ZONE_JWT_SECRET!,
  audience: process.env.AUDIENCE_ID!,
})

export const config = {
  matcher: ['/:orgSlug/:agentSlug/app/:path*', '/:orgSlug/:agentSlug/app'],
}

Options:

FieldTypeDefaultDescription
secretstringHS256 secret shared with the platform for this agent.
audiencestringAudience claim — must match the value the platform mints.
clockToleranceSecondsnumber5Allowed clock skew.
tokenHeaderstring'x-zone-token'Incoming header that carries the JWT.

On success the middleware attaches the decoded claims to x-zone-claims and forwards the original token in x-zone-token. On failure it returns 401.

getSession()

ts
import { getSession } from '@cxpa/sdk/zone'

export default async function Page() {
  const { claims, token } = await getSession()
  return <div>Hello {claims.userId}</div>
}

Throws if called outside a request that the zone middleware processed.

createZoneClient(options | session)

ts
import { createZoneClient, getSession } from '@cxpa/sdk/zone'

const session = await getSession()
const cxpa = createZoneClient({
  baseUrl: process.env.PLATFORM_API_BASE_URL!,
  token:   session.token,
  agentId: session.claims.agentId,
})

const { runId } = await cxpa.runs.create({ payload: { url } })
const run = await cxpa.runs.get(runId)
const cred = await cxpa.credentials.get('hubspot')

Methods

MethodHTTP under the hood
runs.create({ payload })POST /api/zones/agents/{agentId}/runs
runs.createAndWait({ payload, timeoutMs? })POST /api/zones/agents/{agentId}/runs/trigger-and-wait
runs.createAndDownload({ payload, timeoutMs? })POST /api/zones/agents/{agentId}/runs/trigger-and-download
runs.get(runId)GET /api/zones/agents/{agentId}/runs/{runId}
credentials.get(integrationKey)GET /api/zones/agents/{agentId}/credentials/{key}

All requests run with cache: 'no-store' and throw ApiError on non-2xx.

Synchronous run + output (PDF reports, generated documents)

runs.createAndWait is the zone equivalent of triggerRunAndWait: it starts a run and blocks until the run reaches a terminal state or the server-side wait window elapses. The returned object is either a terminal Run row (with output_data) or a { timedOut: true } placeholder. Use it when the zone UI hands the output directly to the user — for example, a "Generate Report" button that returns a PDF link.

ts
const result = await cxpa.runs.createAndWait({
  payload:   { topic: 'Q3 financial summary' },
  timeoutMs: 120_000,
})

if (result.timedOut) {
  // Run is still in flight — fall back to cxpa.runs.get(result.runId).
} else if (result.status === 'completed') {
  // result.output_data has whatever the agent returned.
}

The effective wait is capped server-side by the agent's running_timeout_ms and a platform hard ceiling. On wait-window expiry the route returns 202; the run continues asynchronously and can be retrieved with runs.get(runId).

Binary file download

runs.createAndDownload is the binary-streaming companion to runs.createAndWait. The platform pipes the runtime's response body straight through; the bytes never land in output_data. Use it when the agent's value is a file (PDF, spreadsheet, image) and the zone forwards that file to the user's browser.

ts
const result = await cxpa.runs.createAndDownload({
  payload: { topic: 'Q3 financial summary' },
})

// Forward straight to the browser — single byte stream end-to-end.
return new Response(result.body, {
  headers: {
    'content-type': result.contentType,
    'content-disposition':
      result.contentDisposition ?? `attachment; filename="${result.filename}"`,
  },
})

Eligibility: the bound agent must be platform-managed with output_kind = 'file_download' on a runtime that supports streaming binary output. The platform records the run with metadata only (filename, mime type, byte count) — file bytes are not persisted, so re-download is not available.