Transports — core API
Generated reference for @aparte/core. How a request reaches a model, straight from the browser or through your endpoint, and the handlers that endpoint can use.
On this page
Classes
Section titled “Classes”AparteBackendTransport
Section titled “AparteBackendTransport”Defined in: packages/core/src/transport/backend-transport.ts:43
Backend-proxied transport — RECOMMENDED for production.
POSTs { providerId, request } to YOUR endpoint. The backend resolves the API
key server-side, calls the vendor, runs the vendor parser server-side, and
streams back already-normalized AparteStreamEvents as NDJSON (one JSON object
per line). The key never reaches the browser and — unlike a raw proxy — the
client stays fully vendor-agnostic (it never runs the vendor’s parseStream,
so switching the server-side provider needs no client change). Non-streaming
requests get a JSON { text } reply.
This is NOT the Vercel AI SDK Data Stream Protocol; the wire format is a plain
NDJSON of AparteStreamEvent (see parseAparteEventStream).
The matching /api/chat handler ships as a real, framework-free function —
createAparteChatHandler (Web fetch API, same @aparte/* adapters run
server-side, key held server-side). Drop it into a Next.js route handler,
Deno, Bun, or a Worker rather than hand-rolling one.
Implements
Section titled “Implements”Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new AparteBackendTransport(options): AparteBackendTransport;Defined in: packages/core/src/transport/backend-transport.ts:44
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
options | BackendTransportOptions |
Returns
Section titled “Returns”Methods
Section titled “Methods”chat()
Section titled “chat()”chat(
_provider,
request,
_auth,
ctx): Promise<AparteChatResponse>;Defined in: packages/core/src/transport/backend-transport.ts:46
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
_provider | AparteAIProvider |
request | AparteChatRequest |
_auth | string | Record<string, string> | undefined |
ctx | AparteTransportContext |
Returns
Section titled “Returns”Promise<AparteChatResponse>
Implementation of
Section titled “Implementation of”AparteDirectTransport
Section titled “AparteDirectTransport”Defined in: packages/core/src/transport/direct-transport.ts:32
Browser-direct transport (BYOK / local / prototyping) — the DEFAULT.
Calls the vendor endpoint straight from the browser, injecting the resolved
key via the adapter’s authHeaders. This is the pre-refactor behaviour and
is only safe when the user brings their own key or the model runs locally.
Production apps that must keep a key server-side should use AparteBackendTransport.
When a real key is sent straight from the browser and the transport was not
flagged { byok: true }, a one-time console.warn names the exposure — the
default should be loud, not silent. Local providers (no key) never warn.
Legacy providers (still exposing chat() rather than the adapter surface) are
delegated to untouched, so the migration can proceed provider-by-provider.
Implements
Section titled “Implements”Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new AparteDirectTransport(options?): AparteDirectTransport;Defined in: packages/core/src/transport/direct-transport.ts:36
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
options | DirectTransportOptions |
Returns
Section titled “Returns”Methods
Section titled “Methods”chat()
Section titled “chat()”chat(
provider,
request,
auth,
ctx): Promise<AparteChatResponse>;Defined in: packages/core/src/transport/direct-transport.ts:40
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
provider | AparteAIProvider |
request | AparteChatRequest |
auth | string | Record<string, string> | undefined |
ctx | AparteTransportContext |
Returns
Section titled “Returns”Promise<AparteChatResponse>
Implementation of
Section titled “Implementation of”Functions
Section titled “Functions”createAparteAgentHandler()
Section titled “createAparteAgentHandler()”function createAparteAgentHandler(options): (req) => Promise<Response>;Defined in: packages/core/src/transport/agent-handler.ts:123
Build a framework-free handler that runs the agent loop on your server — next to your
tools — and streams it to createAgentStreamRunner in the browser.
The browser’s AparteClient keeps doing what it does: rows, Stop, the approval panel
and your approval policy. A call that needs a person, or a tool that runs in the
browser, SUSPENDS the run: the stream ends on run-suspended with a signed ticket, the
page asks, and a second request carries the ticket and the answer. Nothing is stored
here — the paused call lives in the conversation the app saves — so the person can
leave and answer days later.
The wire is NDJSON: one StreamRunEvent per line, the suspension line with its
ticket, and a run-error line (sanitised) when the run fails after the stream began.
// app/api/agent/route.ts (Next.js)
import { createAparteAgentHandler } from '@aparte/core';
export const POST = createAparteAgentHandler({
providers: { openai: createOpenAICompatProvider(presets.OPENAI) },
resolveKey: () => process.env.OPENAI_KEY,
authorize: (req) => isSignedIn(req),
secret: process.env.AGENT_SECRET!,
tools: [{ tool: readFile, handler: readFileHandler }],
});Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
options | AparteAgentHandlerOptions |
Returns
Section titled “Returns”(req) => Promise<Response>
createAparteChatHandler()
Section titled “createAparteChatHandler()”function createAparteChatHandler(options): (req) => Promise<Response>;Defined in: packages/core/src/transport/backend-handler.ts:65
Build a framework-free /api/chat handler for AparteBackendTransport — the
server counterpart that keeps the key off the client.
The returned handler speaks the Web fetch API (Request → Response), so
it drops into a Next.js route handler, Deno, Bun, or a Cloudflare Worker
unchanged. It reads { providerId, request }, runs the matching format
adapter server-side (buildRequest → auth → vendor fetch → parseStream),
and streams back normalized AparteStreamEvents as NDJSON — the exact wire
format AparteBackendTransport expects. The vendor key is injected here and never
travels to the browser.
// app/api/chat/route.ts (Next.js)
import { createAparteChatHandler } from '@aparte/core';
import { createOpenAICompatProvider, presets } from '@aparte/provider-openai-compat';
export const POST = createAparteChatHandler({
providers: { openai: createOpenAICompatProvider(presets.OPENAI) },
resolveKey: (id) => process.env[`${id.toUpperCase()}_KEY`],
// Required: this route spends your key. Your own session check goes here.
authorize: async (req) => Boolean(await getSession(req)),
});Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
options | AparteChatHandlerOptions |
Returns
Section titled “Returns”(req) => Promise<Response>
isFormatAdapter()
Section titled “isFormatAdapter()”function isFormatAdapter(p): p is AparteAIProvider & Required<Pick<AparteFormatAdapter, "defaultEndpoint" | "buildRequest" | "parseStream">>;Defined in: packages/core/src/transport/types.ts:67
True once a provider has been refactored to the format-adapter surface.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
p | AparteAIProvider |
Returns
Section titled “Returns”p is AparteAIProvider & Required<Pick<AparteFormatAdapter, “defaultEndpoint” | “buildRequest” | “parseStream”>>
Interfaces
Section titled “Interfaces”AparteAgentTool
Section titled “AparteAgentTool”Defined in: packages/core/src/transport/agent-handler.ts:13
A server tool: its definition (what the model sees) and its handler (what runs here).
Properties
Section titled “Properties”tool: AparteTool;Defined in: packages/core/src/transport/agent-handler.ts:14
handler
Section titled “handler”handler: AparteToolHandler;Defined in: packages/core/src/transport/agent-handler.ts:15
acceptsApprovalPayload?
Section titled “acceptsApprovalPayload?”optional acceptsApprovalPayload?: boolean;Defined in: packages/core/src/transport/agent-handler.ts:21
Accept the payload an approval may carry — data merged into the call’s input.
Off by default: from a browser, a payload rewrites what the model chose to call
with, so only a tool whose approval UI edits the arguments on purpose opts in.
AparteAgentHandlerOptions
Section titled “AparteAgentHandlerOptions”Defined in: packages/core/src/transport/agent-handler.ts:24
Properties
Section titled “Properties”providers
Section titled “providers”providers: Record<string, AparteAIProvider>;Defined in: packages/core/src/transport/agent-handler.ts:30
Your server-side format adapters, keyed by the providerId the client sends. A page
that registers no provider sends none, and the handler runs its only one; with
several, the page names one.
defaultModel?
Section titled “defaultModel?”optional defaultModel?: string;Defined in: packages/core/src/transport/agent-handler.ts:35
The model a turn runs on when the page selected none, which is the case when the page registers no provider of its own. A model the page selects wins.
authorize
Section titled “authorize”authorize: (req) => boolean | Response | Promise<boolean | Response>;Defined in: packages/core/src/transport/agent-handler.ts:41
Gate run on EVERY request before any work. Required, for the reason
createAparteChatHandler gives: this endpoint spends your key and runs your
tools. Return false for 401, a Response to answer yourself, true to proceed.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
req | Request |
Returns
Section titled “Returns”boolean | Response | Promise<boolean | Response>
secret
Section titled “secret”secret: string | readonly string[];Defined in: packages/core/src/transport/agent-handler.ts:47
Signs the pending calls of a suspended run, so a resume runs only calls this server emitted. Required, at least 32 characters. An array rotates: the first signs, all verify.
tools?
Section titled “tools?”optional tools?: readonly AparteAgentTool[];Defined in: packages/core/src/transport/agent-handler.ts:49
The tools that run here. tool.needsApproval is the gate.
resolveKey?
Section titled “resolveKey?”optional resolveKey?: (providerId) => string | Promise<string | undefined> | undefined;Defined in: packages/core/src/transport/agent-handler.ts:51
The vendor key for a providerId, from env or a secret store.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
providerId | string |
Returns
Section titled “Returns”string | Promise<string | undefined> | undefined
approvalPolicy?
Section titled “approvalPolicy?”optional approvalPolicy?: AparteApprovalPolicy;Defined in: packages/core/src/transport/agent-handler.ts:53
Server-side rules, per call: allow, ask, deny (refused without asking).
clientTools?
Section titled “clientTools?”optional clientTools?: boolean | readonly string[];Defined in: packages/core/src/transport/agent-handler.ts:59
Accept tools the browser declares and runs itself (ask_user). true by default;
false refuses them; a list allows those names only. A browser tool named like a
server tool is always refused.
prepareRequest?
Section titled “prepareRequest?”optional prepareRequest?: (request, req) =>
| AparteChatRequest
| Promise<AparteChatRequest>;Defined in: packages/core/src/transport/agent-handler.ts:64
Rewrite the request before the run — impose your system prompt, drop messages. The resume checks read what it returns: the loop runs on that, not on what the browser sent.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
request | AparteChatRequest |
req | Request |
Returns
Section titled “Returns”| AparteChatRequest
| Promise<AparteChatRequest>
maxTurns?
Section titled “maxTurns?”optional maxTurns?: number;Defined in: packages/core/src/transport/agent-handler.ts:66
How many model turns one run may take before it stops.
Default
Section titled “Default”10toolTimeoutMs?
Section titled “toolTimeoutMs?”optional toolTimeoutMs?: number;Defined in: packages/core/src/transport/agent-handler.ts:68
How long one tool call may run, in milliseconds, before it is abandoned.
Default
Section titled “Default”300000 (5 minutes)ticketMaxAgeMs?
Section titled “ticketMaxAgeMs?”optional ticketMaxAgeMs?: number;Defined in: packages/core/src/transport/agent-handler.ts:70
How long a suspended run can wait for its answer.
Default
Section titled “Default”7 daysonTicket?
Section titled “onTicket?”optional onTicket?: (ticketId) => boolean | Promise<boolean>;Defined in: packages/core/src/transport/agent-handler.ts:76
Called with a ticket’s id before a resume. Return false to refuse it (409) — the
hook for a host that can remember used tickets and make them single-use. A server
that stores nothing cannot tell a replay from a first use.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
ticketId | string |
Returns
Section titled “Returns”boolean | Promise<boolean>
transport?
Section titled “transport?”optional transport?: AparteTransport;Defined in: packages/core/src/transport/agent-handler.ts:78
How the vendor is called.
Default
Section titled “Default”an AparteDirectTransport (the key is on this server by design).
crypto?
Section titled “crypto?”optional crypto?: SubtleCrypto;Defined in: packages/core/src/transport/agent-handler.ts:80
Web Crypto.
Default
Section titled “Default”globalThis.crypto.subtle; on Node 18, pass (await import('node:crypto')).webcrypto.subtle.
AparteAgentRequestBody
Section titled “AparteAgentRequestBody”Defined in: packages/core/src/transport/agent-handler.ts:84
What createAgentStreamRunner POSTs.
Properties
Section titled “Properties”v: 1;Defined in: packages/core/src/transport/agent-handler.ts:85
providerId?
Section titled “providerId?”optional providerId?: string;Defined in: packages/core/src/transport/agent-handler.ts:87
Absent when the page registered no provider: the handler runs its only one.
messageId
Section titled “messageId”messageId: string;Defined in: packages/core/src/transport/agent-handler.ts:88
request
Section titled “request”request: AparteChatRequest;Defined in: packages/core/src/transport/agent-handler.ts:89
clientTools?
Section titled “clientTools?”optional clientTools?: AparteTool[];Defined in: packages/core/src/transport/agent-handler.ts:91
Definitions of the tools the browser runs; the server marks them external.
resume?
Section titled “resume?”optional resume?: {
ticket: string;
outcomes: Record<string, StreamDeferredOutcome>;
};Defined in: packages/core/src/transport/agent-handler.ts:92
ticket
Section titled “ticket”ticket: string;outcomes
Section titled “outcomes”outcomes: Record<string, StreamDeferredOutcome>;AparteChatHandlerOptions
Section titled “AparteChatHandlerOptions”Defined in: packages/core/src/transport/backend-handler.ts:5
Properties
Section titled “Properties”providers
Section titled “providers”providers: Record<string, AparteAIProvider>;Defined in: packages/core/src/transport/backend-handler.ts:11
Your server-side format adapters, keyed by the providerId the client
sends. The same adapters as the browser (@aparte/provider-*), running here
so the vendor key never leaves the server.
authorize
Section titled “authorize”authorize: (req) => boolean | Response | Promise<boolean | Response>;Defined in: packages/core/src/transport/backend-handler.ts:28
Gate run on EVERY request before any work. Required.
This endpoint spends your server-held vendor key, so leaving it open means anyone who finds the URL spends your money. It used to be optional, and both the JSDoc example here and the primary snippet in the docs omitted it — so the copy-paste path was the unauthenticated one. Making it required moves that decision from “did you notice?” to a compile error.
Return false to reject with 401, a Response to reject with your own
status/body (e.g. 403 + a message), or true to proceed. Reads
cookies/headers via req.
A deliberately open endpoint is still possible — authorize: () => true —
but now it is a line someone wrote on purpose.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
req | Request |
Returns
Section titled “Returns”boolean | Response | Promise<boolean | Response>
resolveKey?
Section titled “resolveKey?”optional resolveKey?: (providerId) => string | Promise<string | undefined> | undefined;Defined in: packages/core/src/transport/backend-handler.ts:33
Resolve the vendor API key for a providerId — from env / a secret store.
Runs server-side only. Return undefined for keyless/local providers.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
providerId | string |
Returns
Section titled “Returns”string | Promise<string | undefined> | undefined
fetchImpl?
Section titled “fetchImpl?”optional fetchImpl?: {
(input, init?): Promise<Response>;
(input, init?): Promise<Response>;
};Defined in: packages/core/src/transport/backend-handler.ts:38
The fetch used to call the vendor. Defaults to the global fetch
(Node 18+, Deno, Bun, Workers). Override in tests or to add a proxy.
Call Signature
Section titled “Call Signature”(input, init?): Promise<Response>;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
input | RequestInfo | URL |
init? | RequestInit |
Returns
Section titled “Returns”Promise<Response>
Call Signature
Section titled “Call Signature”(input, init?): Promise<Response>;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
input | string | Request | URL |
init? | RequestInit |
Returns
Section titled “Returns”Promise<Response>
BackendTransportOptions
Section titled “BackendTransportOptions”Defined in: packages/core/src/transport/backend-transport.ts:7
Properties
Section titled “Properties”endpoint
Section titled “endpoint”endpoint: string;Defined in: packages/core/src/transport/backend-transport.ts:9
Your backend chat endpoint, e.g. /api/chat.
headers?
Section titled “headers?”optional headers?: Record<string, string>;Defined in: packages/core/src/transport/backend-transport.ts:16
Extra headers to send with each request. A session cookie rides along
automatically only for a SAME-ORIGIN endpoint — the request uses fetch’s
default credentials: 'same-origin', so a cross-origin endpoint sends no
cookie; authenticate it with a header here instead.
buildBody?
Section titled “buildBody?”optional buildBody?: (request, providerId) => unknown;Defined in: packages/core/src/transport/backend-transport.ts:21
Override how the request is serialised to your backend. Default body is
{ providerId, request }. Return any JSON-serialisable value.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
request | AparteChatRequest |
providerId | string |
Returns
Section titled “Returns”unknown
DirectTransportOptions
Section titled “DirectTransportOptions”Defined in: packages/core/src/transport/direct-transport.ts:7
Options for AparteDirectTransport.
Properties
Section titled “Properties”optional byok?: boolean;Defined in: packages/core/src/transport/direct-transport.ts:14
Set when the key is the end-user’s own (BYOK) or the model runs locally —
i.e. you intend the credential to live in the browser. This silences the
one-time insecure-key warning. Leave it unset for keys that must stay
server-side, and use AparteBackendTransport for those instead.
AparteVendorRequest
Section titled “AparteVendorRequest”Defined in: packages/core/src/transport/types.ts:21
A vendor HTTP request built from an Aparte request — auth is injected separately.
Properties
Section titled “Properties”path: string;Defined in: packages/core/src/transport/types.ts:23
Appended to the transport’s endpoint, e.g. /chat/completions.
body: unknown;Defined in: packages/core/src/transport/types.ts:25
Vendor-shaped JSON body.
headers?
Section titled “headers?”optional headers?: Record<string, string>;Defined in: packages/core/src/transport/types.ts:27
Content headers (NOT auth — the transport adds auth).
AparteFormatAdapter
Section titled “AparteFormatAdapter”Defined in: packages/core/src/transport/types.ts:31
The vendor-format concern, with no transport/auth coupling.
Properties
Section titled “Properties”id: string;Defined in: packages/core/src/transport/types.ts:32
defaultEndpoint
Section titled “defaultEndpoint”defaultEndpoint: string;Defined in: packages/core/src/transport/types.ts:34
Base URL for browser-direct calls (overridable per request via config).
Methods
Section titled “Methods”buildRequest()
Section titled “buildRequest()”buildRequest(request): AparteVendorRequest;Defined in: packages/core/src/transport/types.ts:36
Map an Aparte request to the vendor HTTP request (without auth).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
request | AparteChatRequest |
Returns
Section titled “Returns”authHeaders()?
Section titled “authHeaders()?”optional authHeaders(key): Record<string, string>;Defined in: packages/core/src/transport/types.ts:38
Vendor auth headers for a resolved key (browser-direct only). Most vendors.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
key | string |
Returns
Section titled “Returns”Record<string, string>
authQuery()?
Section titled “authQuery()?”optional authQuery(key): Record<string, string>;Defined in: packages/core/src/transport/types.ts:40
Vendor auth as URL query params for a resolved key (e.g. Gemini ?key=).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
key | string |
Returns
Section titled “Returns”Record<string, string>
parseStream()
Section titled “parseStream()”parseStream(body): ReadableStream<AparteStreamEvent>;Defined in: packages/core/src/transport/types.ts:42
Parse a streaming vendor response body into unified events.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
body | ReadableStream<Uint8Array<ArrayBufferLike>> |
Returns
Section titled “Returns”ReadableStream<AparteStreamEvent>
parseText()?
Section titled “parseText()?”optional parseText(json): string;Defined in: packages/core/src/transport/types.ts:44
Extract text from a non-streaming vendor JSON response.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
json | unknown |
Returns
Section titled “Returns”string
AparteTransportContext
Section titled “AparteTransportContext”Defined in: packages/core/src/transport/types.ts:47
Properties
Section titled “Properties”providerId
Section titled “providerId”providerId: string;Defined in: packages/core/src/transport/types.ts:48
signal?
Section titled “signal?”optional signal?: AbortSignal;Defined in: packages/core/src/transport/types.ts:49
AparteTransport
Section titled “AparteTransport”Defined in: packages/core/src/transport/types.ts:57
Decides where a chat request goes and how auth is handled. Given a provider (adapter or legacy), the request, and the already-resolved auth, it returns unified events (streaming) or a string (non-streaming).
Methods
Section titled “Methods”chat()
Section titled “chat()”chat(
provider,
request,
auth,
ctx): Promise<AparteChatResponse>;Defined in: packages/core/src/transport/types.ts:58
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
provider | AparteAIProvider |
request | AparteChatRequest |
auth | string | Record<string, string> | undefined |
ctx | AparteTransportContext |
Returns
Section titled “Returns”Promise<AparteChatResponse>