@wooshiiltd/assist-canvas-sdk
v1.0.0
Published
SDK for Assist Canvas: real-time state, WebSocket + polling, token handling
Readme
@wooshiiltd/assist-canvas-sdk
SDK for building apps that connect to Assist Canvas: real-time state sync over WebSocket with HTTP polling fallback, token handling, and optional origin checks.
The SDK is generic — it does not assume any state shape. Your app defines its own types and API calls; the SDK handles auth, fetching/streaming state, and reconnection.
Installation
pnpm add @wooshiiltd/assist-canvas-sdk
# or
npm install @wooshiiltd/assist-canvas-sdk- React — peer:
react(>=18). Import from@wooshiiltd/assist-canvas-sdk/react. - Vue — peer:
vue(>=3). Import from@wooshiiltd/assist-canvas-sdk/vue. - Vanilla / other — import from
@wooshiiltd/assist-canvas-sdkand usefetchState,createConnection, andgetAuthHeaders.
React
import { useCanvasConnection, getAuthHeaders } from '@wooshiiltd/assist-canvas-sdk/react';
function getToken() {
return new URLSearchParams(window.location.search).get('assist_token');
}
function App() {
const { state, outputId, error, loading, connectionMode, refetch } =
useCanvasConnection<MyState>({
getToken,
pollingIntervalMs: 5000,
pollingBackoffMs: 2000,
});
const handleAction = async () => {
const token = getToken();
if (!token) return;
await fetch('/api/...', {
method: 'PATCH',
headers: getAuthHeaders(token),
body: JSON.stringify({ ... }),
});
};
if (loading) return <div>Loading…</div>;
if (error) return <div>{error} <button onClick={refetch}>Retry</button></div>;
return <div>{/* render state */}</div>;
}Vue
<script setup lang="ts">
import { useCanvasConnection, getAuthHeaders } from '@wooshiiltd/assist-canvas-sdk/vue';
function getToken() {
return new URLSearchParams(window.location.search).get('assist_token');
}
const { state, outputId, error, loading, connectionMode, refetch } =
useCanvasConnection<MyState>({
getToken,
pollingIntervalMs: 5000,
pollingBackoffMs: 2000,
});
</script>
<template>
<div v-if="loading">Loading…</div>
<div v-else-if="error">{{ error }} <button @click="refetch">Retry</button></div>
<div v-else><!-- render state --></div>
</template>In Vue, useCanvasConnection returns refs (state, error, etc.); in templates they auto-unwrap. For TypeScript, the return type is UseCanvasConnectionResultVue<T>.
Config
| Option | Description |
|--------|-------------|
| getToken | () => string \| null — e.g. from URL query or storage. |
| baseUrl | Optional. API base (default: current origin). |
| pollingIntervalMs | Interval when using polling (default 5000). |
| pollingBackoffMs | Backoff step when polling fails (default 2000). |
| maxPollingIntervalMs | Cap for polling interval (default 60000). |
| allowedOrigins | Optional. If set, only these origins can fetch/connect (e.g. ['https://app.example.com']). Used by fetchState and createConnection. |
Core API (framework-agnostic)
fetchState<T>(token, config?)—GET /api/state, returnsPromise<{ outputId: string; state: T }>. In the browser, ifconfig.allowedOriginsis set, the current origin is checked first.getAuthHeaders(token)—{ Authorization: 'Bearer …', 'Content-Type': 'application/json' }for your ownfetchcalls.createConnection<T>(token, config, callbacks)— Starts WebSocket; on close/error switches to polling. Returns a disconnect function. Callbacks:onState,onError, optionalonConnectionMode.
Your app is responsible for any other endpoints (e.g. PATCH for moving a card); use getAuthHeaders(token) when calling them.
Types
StateResponse<T>—{ outputId: string; state: T }.Tis your app’s state type.
Security
- Origin validation — Set
allowedOriginsso the client only runs on trusted domains. Checked in bothfetchStateandcreateConnectionwhen running in the browser. - IDs —
outputIdis validated (alphanumeric,_,-, length). UsesanitizeOutputIdif you need to validate IDs elsewhere. - Tokens are never logged; use
getToken()only when needed and avoid putting tokens in URLs beyond the initial load if possible.
Content Security Policy (CSP)
The SDK does not set CSP headers. The page that embeds your canvas app (or the server that serves it) should send a strict Content-Security-Policy so that only your app and the canvas API can be loaded.
Example for a page that embeds the canvas in an iframe and allows the canvas API origin:
Content-Security-Policy: default-src 'self'; connect-src 'self' https://your-canvas-api.example.com wss://your-canvas-api.example.com; frame-src 'self' https://your-canvas-api.example.com; script-src 'self'; style-src 'self' 'unsafe-inline';Tighten or relax as needed (e.g. add frame-ancestors if the canvas is in an iframe and you want to restrict which parents can embed it).
Building
pnpm install
pnpm buildOutput is in dist/ (ESM + types).
