Installing Runnable Server
Overview
Runnable Server is a great way to build a scalable admin tool. You can connect many clients, for example, a user-service
and an email-service
that can stream their actions to a central location using the Runnable SDK. This is great for services not exposed to the public internet and for services that may be deployed with multiple instances.
Deploying the Runnable Server
You can deploy runnable as a dockerized container.
bash
docker pull ghcr.io/kineticio/runnable:latest
docker pull ghcr.io/kineticio/runnable:latest
Pin Version
It is recommended to pin to a particular version. You can find the latest package version here.
Settings up the required env variables
Environment Variable | Description | How to Generate |
---|---|---|
RUNNABLE_BASE_URL | The base URL for your Runnable instance. This has a default of /admin for Runnable Mini, but should override to be / . | Should just provide '/' |
RUNNABLE_SECRET | A secret key used for encrypting the user's cookie session. | Run openssl rand -hex 32 in your terminal |
RUNNABLE_AUTH_SECRET | A secret key used during the handshake between a Runnable Server and Runnable SDK Client. | Run openssl rand -hex 32 in your terminal |
RUNNABLE_AUTH_PROVIDER_GOOGLE_CLIENT_ID | The client ID for the Google authentication provider. | Generated by Google. |
RUNNABLE_AUTH_PROVIDER_GOOGLE_CLIENT_SECRET | The client secret for the Google authentication provider. | Generated by Google. |
RUNNABLE_AUTH_PROVIDER_GOOGLE_HOSTNAME | The hostname for the Google authentication provider. | E.g. https://admin.company-name.com |
RUNNABLE_AUTH_PROVIDER_GOOGLE_HD | The hosted domain for the Google authentication provider. Setting this will limit the email domain allowed to login. | Provided by Google. |
Installing the Runnable SDK
With npm
bash
npm install -D @runnablejs/sdk
npm install -D @runnablejs/sdk
or with yarn
bash
yarn add -D @runnablejs/sdk
yarn add -D @runnablejs/sdk
or with pnpm
bash
pnpm add -D @runnablejs/sdk
pnpm add -D @runnablejs/sdk
Setting in your server
ts
// index.ts
import { userInfo } from 'node:os';
import { RunnableWs } from '@runnablejs/sdk';
import { getUsers, getTeams, assignTeam } from './db';
import { auth } from './auth';
new RunnableWs(actions, {
// Your admin portal. This can be a staging, development, or local URL.
runnableHost: 'wss://admin.company-name.com',
// Some domain displayed to the user and used to dedupe among multiple instances of the same server.
namespace: process.env.NODE_ENV === 'development' ? `${userInfo().username}_local_development` : 'users',
// Can be a custom logger or defaults to console.
logger: console,
// Shared auth token between Runnable client nad Runnable server.
token: process.env.RUNNABLE_AUTH_SECRET,
}).start();
// index.ts
import { userInfo } from 'node:os';
import { RunnableWs } from '@runnablejs/sdk';
import { getUsers, getTeams, assignTeam } from './db';
import { auth } from './auth';
new RunnableWs(actions, {
// Your admin portal. This can be a staging, development, or local URL.
runnableHost: 'wss://admin.company-name.com',
// Some domain displayed to the user and used to dedupe among multiple instances of the same server.
namespace: process.env.NODE_ENV === 'development' ? `${userInfo().username}_local_development` : 'users',
// Can be a custom logger or defaults to console.
logger: console,
// Shared auth token between Runnable client nad Runnable server.
token: process.env.RUNNABLE_AUTH_SECRET,
}).start();
Example with Next.js
Create the providers for the RunnableWorkflows
.
ts
// actions.provider.ts
import { FactoryProvider, Provider } from '@nestjs/common';
import { RunnableWorkflows, RunnableAppContext } from '@runnablejs/express';
import { AppService } from './app.service';
export const ActionsProvider: FactoryProvider<RunnableWorkflows> = {
provide: 'RUNNABLE_ACTIONS',
inject: [DatabaseService],
useFactory: (database: DatabaseService) => ({
assign_user_to_team: {
// ...
},
create_user: {
// ...
},
}),
};
// actions.provider.ts
import { FactoryProvider, Provider } from '@nestjs/common';
import { RunnableWorkflows, RunnableAppContext } from '@runnablejs/express';
import { AppService } from './app.service';
export const ActionsProvider: FactoryProvider<RunnableWorkflows> = {
provide: 'RUNNABLE_ACTIONS',
inject: [DatabaseService],
useFactory: (database: DatabaseService) => ({
assign_user_to_team: {
// ...
},
create_user: {
// ...
},
}),
};
Create the module for the Actions
.
ts
// actions.module.ts
import { Module } from '@nestjs/common';
import { ActionsProvider } from './actions.provider';
@Module({
imports: [DatabaseModule],
providers: [ActionsProvider],
})
export class ActionsModule {}
// actions.module.ts
import { Module } from '@nestjs/common';
import { ActionsProvider } from './actions.provider';
@Module({
imports: [DatabaseModule],
providers: [ActionsProvider],
})
export class ActionsModule {}
Start your Next.js application with Actions
.
ts
// main.ts
import { installRunnable } from '@runnablejs/express';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Setup Runnable
const actions = app.get('RUNNABLE_ACTIONS');
const config = new RunnableWs(actions, {
// Your admin portal. This can be a staging, development, or local URL.
runnableHost: 'wss://admin.company-name.com',
// Some domain displayed to the user and used to dedupe among multiple instances of the same server.
namespace: process.env.NODE_ENV === 'development' ? `${userInfo().username}_local_development` : 'users',
// Can be a custom logger or defaults to console.
logger: app.get(Logger),
// Shared auth token between Runnable client nad Runnable server.
token: process.env.RUNNABLE_AUTH_SECRET,
}).start();
await app.listen(3000);
}
bootstrap();
// main.ts
import { installRunnable } from '@runnablejs/express';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Setup Runnable
const actions = app.get('RUNNABLE_ACTIONS');
const config = new RunnableWs(actions, {
// Your admin portal. This can be a staging, development, or local URL.
runnableHost: 'wss://admin.company-name.com',
// Some domain displayed to the user and used to dedupe among multiple instances of the same server.
namespace: process.env.NODE_ENV === 'development' ? `${userInfo().username}_local_development` : 'users',
// Can be a custom logger or defaults to console.
logger: app.get(Logger),
// Shared auth token between Runnable client nad Runnable server.
token: process.env.RUNNABLE_AUTH_SECRET,
}).start();
await app.listen(3000);
}
bootstrap();