@ducking-mind/proxy-app-sdk
v0.1.0
Published
TypeScript SDK for Proxy apps using HTTP APIs and compatible iframe Bridge runtimes
Readme
@ducking-mind/proxy-app-sdk
SDK for Proxy App Market applications. It supports the published v1 iframe
compatibility runtime and the v2 standalone HTTP runtime described in
app/docs/HTTP_RUNTIME_DESIGN.md.
Current status: local development defaults to HTTP for both models and application resources. Update Gateway and Admin before restarting the CLI. Published iframe apps retain Bridge. Full page-runtime publishing and PKCE login are still migration targets; the local login handoff is unchanged.
import { createAppClient } from '@ducking-mind/proxy-app-sdk'
// Generated by `proxy-app init` and replaced after `proxy-app create`.
const app = createAppClient('app.proxy.local.generated')
const profile = await app.user.getProfile()
const capabilities = await app.platform.capabilities()
const value = await app.platform.call('theme.read')
// Model/media APIs use the short-lived in-memory App Session issued by the
// platform host. The SDK never persists this token.
const models = await app.api.request('/models')
// Binary media endpoints are decoded automatically from Content-Type. An
// explicit responseType is also available when the response format is known.
const video = await app.api.request<Blob>('/videos/video-id/content', {
responseType: 'blob',
})
for await (const event of app.api.stream('/responses/stream', {
method: 'POST',
body: JSON.stringify({ model: 'your-model', input: 'Hello' }),
})) {
console.log(event.data)
}Bridge failures are returned as AppSdkError instances with stable code values
such as APP_BRIDGE_TIMEOUT, APP_BRIDGE_DISCONNECTED, and
APP_BRIDGE_ERROR. The SDK derives the host origin from the iframe referrer; pass
targetOrigin explicitly when the host uses a non-standard embedding setup.
Data-plane failures preserve the platform error code, HTTP status, response
X-Request-ID (as requestId) and structured response payload (as details).
app.api.request() accepts responseType: 'auto' | 'json' | 'text' | 'blob' |
'arrayBuffer' | 'response'; auto selects JSON/text/blob from Content-Type.
JSON request bodies automatically receive Content-Type: application/json when
the caller did not provide a header. FormData, URLSearchParams and binary
bodies are left to fetch so multipart boundaries and media types remain intact.
The SDK uses HTTP locally and in direct runtime, and the narrow Bridge protocol only
when embedded. It never reads Portal tokens.
Pricing, supplier costs, platform fees and commission settlement are platform
infrastructure; they are not exposed as SDK methods or app runtime APIs.
When embedded by Portal, the host handshake supplies an ast_ App Session;
app.api.request() attaches it only to the allow-listed /v1 data plane
(the Session's gateway_url already contains that prefix).
Applications should handle APP_SESSION_UNAVAILABLE and ask the host to retry
the handshake when a session expires. app.platform.createSession() proactively
refreshes the in-memory session. Automatic replay is limited to a single 401
that explicitly identifies an App Session expiry before execution; provider
authentication failures and requests with unknown execution state are returned
without replay.
For local development, use proxy-app dev. It does not require AppHost, but it
does require a linked platform app and the user must sign in when the app first
requests a platform capability. The CLI starts a loopback Relay; the Relay
uses the signed-in user's short-lived App Session and forwards requests to the
real Gateway. Models, provider routing, quota and billing are real. Import the Vite helper
in vite.config.ts:
import { defineConfig } from 'vite'
import { createPlatformDevProxy } from '@ducking-mind/proxy-app-sdk/vite'
export default defineConfig({
base: './',
server: {
host: '127.0.0.1',
proxy: createPlatformDevProxy(),
},
})Start the app with:
proxy-app dev <app-dir>The first data-plane request may require a platform user sign-in. The SDK opens the real platform login flow automatically; applications should also expose a user-initiated fallback for browsers that block automatic popups:
try {
await app.api.request('/models')
} catch (error) {
// Render this action only for APP_LOGIN_REQUIRED or APP_LOGIN_POPUP_BLOCKED.
await app.auth.login()
}app.auth.login() opens the current platform login handoff from a user gesture.
app.auth.logout() clears the local relay session and revokes the current App
Session, allowing another platform user to sign in. These methods are local
development helpers; embedded production apps authenticate through the host.
dev does not require PROXY_ACCESS_TOKEN; that credential is only the current
user's control-plane session for commands such as create, upload and publish. The local
Relay uses PROXY_API_BASE_URL and PROXY_PORTAL_URL only as platform
endpoints, then obtains the user session through the browser login flow.
The CLI sets private process-only variables for the Vite helper. The default
paths are /v1/* and /api/app-runtime/v1/*, including local login status.
--legacy-bridge exposes the old /__platform/bridge for old SDKs; a new SDK
must also set localBridgePath explicitly to select that compatibility mode.
/__platform/v1 and /__platform/auth remain aliases for old clients.
Application resource requests are forwarded as HTTP, without Bridge RPC. Portal tokens stay in
the CLI/Relay memory and are never injected into the app. The helper is not
included in the production app bundle.
npm run dev remains useful for UI-only work but cannot call platform APIs
without the Relay.
Standalone integrations can use the direct runtime with an externally supplied
App Session and refresh callback. The platform App PKCE flow is not yet built.
For both Gateway and Runtime APIs, request a v2 token through the existing
session issuance API with runtime_protocol: 2:
const app = createAppClient('app.proxy.example', {
runtime: 'direct',
appSession,
refreshAppSession,
runtimeBasePath: '/api/app-runtime/v1',
})
const models = await app.api.request('/models')ast_* is the user's runtime session, not a developer key. The Gateway still
enforces installation, version, scopes, quota, billing and provider routing.
Direct runtime also supports profile, capabilities, preferences and storage over
HTTP. Storage retains the existing app/user data and last-write-wins semantics;
CAS and development namespaces are not implemented. notification.show is not
available over HTTP; render application notifications locally. Portal management
APIs remain inaccessible to AppSession tokens.
After build, pack and upload, use My Apps > Test version
for real permissions, models, provider routing, quota and billing.
Full platform documentation:
../docs/APP_MARKET.md