TypeScript SDK
The TypeScript SDK connects external Node.js/browser applications to NoClick workflows via WebSocket (Socket.IO). It’s also the SDK used inside custom components.
Installation
npm install noclick socket.io-client
socket.io-client is required for external apps (WebSocket transport). Custom components don’t need it — the SDK uses postMessage in iframe context.
Quick Start
import { init, nodes, execution, state } from 'noclick';
// Connect with your API key
await init({
apiKey: 'nk_live_...',
workflowId: '...', // optional — scope to a specific workflow
});
// Read a node's output
const output = await nodes.getOutput('gmail-node-id');
// Run a node and get results
const results = await execution.runNodesAndGetOutput(
['data-fetcher'],
['data-fetcher']
).all();
// Persistent state
await state.set('counter', 42);
const val = await state.get('counter'); // 42
Authentication
External apps use API keys created in Settings > Developer. Keys have three permission levels:
| Permission | Allows |
|---|
read | nodes.getOutput, nodes.list, nodes.getConfig, state.get, state.keys, dataset.getRows, resources.list, auth.listCredentials |
execute | execution.runNodesAndGetOutput, execution.runNodesInBackground, execution.stop |
write | nodes.setConfig, state.set, state.del, dataset.appendRows, dataset.create, resources.upload, auth.createCredential |
Reading Data
// List all nodes in the workflow
const allNodes = await nodes.list();
// [{ id, type, label, hasOutput }, ...]
// Read a node's last output
const output = await nodes.getOutput('gmail-node-id');
console.log(output.emails);
// Read a node's config
const config = await nodes.getConfig('http-node-id');
console.log(config.url);
Running Nodes
// Fire and forget
execution.runNodesInBackground(['data-fetcher']);
// With temporary config overrides (doesn't persist to the node)
execution.runNodesInBackground([
{ id: 'http-node', config: { url: 'https://api.example.com/data' } }
]);
// Run and stream output as nodes complete
const stream = execution.runNodesAndGetOutput(
['data-fetcher'], // nodes to execute
['formatter', 'chart'] // nodes whose output we want
);
stream.on('output', (nodeId, data) => {
console.log(`${nodeId} completed:`, data);
});
stream.on('done', () => {
console.log('All targets completed');
});
// Or await all results at once
const results = await stream.all();
// { 'formatter': {...}, 'chart': {...} }
State Management
Requires a State Manager node in the workflow.
await state.set('counter', 0);
const val = await state.get('counter'); // 0
await state.update('counter', n => (n || 0) + 1);
await state.del('counter');
const keys = await state.keys(); // ['counter', ...]
// Subscribe to changes (fires from any source — other clients, workflow execution)
state.onChange('counter', (newVal) => {
console.log('Counter changed:', newVal);
});
Real-time Subscriptions
Subscribe to node changes from any trigger (cron, webhooks, manual runs, other SDK clients):
// React to new data from a cron-triggered node
execution.onNodeOutput('data-fetcher', (output) => {
console.log('New data:', output);
});
// Track execution state
execution.onNodeState('data-fetcher', (state) => {
console.log('State:', state); // 'running' | 'completed' | 'error'
});
Credentials
// List all credentials
const creds = await auth.listCredentials();
// [{ id, type, name }, ...]
// Check if a credential type exists
const has = await auth.hasCredential('google_gmail_oauth'); // true/false
// Create an API key credential
const cred = await auth.createCredential('telegram_bot_token', {
token: apiKey
}, 'My Bot');
// { id, type, name }
auth.requestCredential() (OAuth popup flow) is only available in custom components, not external apps.
Resources (File Storage)
// Upload a file
const { resourceId, uploadUrl } = await resources.upload('photo.jpg', 'image/jpeg', file.size);
await fetch(uploadUrl, { method: 'PUT', body: file });
// Get download URL
const url = await resources.getUrl(resourceId);
// List resources
const files = await resources.list('file');
// Delete
await resources.remove(resourceId);
Dataset CRUD
// Create
const dsId = await dataset.create('User Submissions');
// Append rows
await dataset.appendRows(dsId, [
{ name: 'Alice', score: 95 },
{ name: 'Bob', score: 87 },
]);
// Read (paginated)
const page = await dataset.getRows(dsId, { limit: 100, offset: 0 });
// { rows: [{ id, data, created_at }], totalCount: 1000 }
// Update a row
await dataset.updateRow(dsId, rowId, { score: 98 });
// Delete rows
await dataset.deleteRows(dsId, [rowId]);
// List all datasets
const datasets = await dataset.list();
Workflow Info
const info = await workflow.getInfo();
// { id, name, nodeCount }
Full API Reference
See the API Reference for complete method signatures with TypeScript and Python examples side by side.