Turbocache

Runnable Mini is a great way to get started with Runnable and a perfectly viable long-term solution. It's easy to set up and doesn't require any additional infrastructure.
Runnable Mini integrates directly with your Next.js or Express application by adding a new authenticated route to your existing router framework at a desired path (e.g. /admin).
With npm
npm install -D @runnablejs/expressor with yarn
yarn add -D @runnablejs/expressor with pnpm
pnpm add -D @runnablejs/express| 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_PROVIDER_FORM | (Optional) Set to true to enable login via a form. You must also pass verifyLogin option to installRunnable. | Set to true or omit. |
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. |
// index.ts
import express from "express";
import { installRunnable } from "@runnablejs/express";
import { getUsers, getTeams, assignTeam } from "./db";
import { auth } from "./auth";
const app = express();
// ... normal express setup
installRunnable(
app,
{
assign_user_to_team: {
title: "Assign a user to a team",
execute: async (io) => {
const users = await getUsers();
const user = await io.select.dropdown({
label: "Select a user",
data: users,
getLabel: (user) => user.name,
getValue: (user) => user.id,
});
const teams = await getTeams();
const team = await io.select.table({
label: "Select a team",
data: teams,
headers: ["Name", "Team size"],
initialSelection: user.teamId,
getValue: (team) => team.id,
getRow: (team) => [team.name, team.members.length],
});
await assignTeam(user.id, team.id);
},
},
},
{ auth: auth }
);
app.listen(3000);Create the providers for the RunnableWorkflows and RunnableAppContext.
// actions.provider.ts
import { FactoryProvider, Provider } from "@nestjs/common";
import { RunnableWorkflows, RunnableAppContext } from "@runnablejs/express";
import { DatabaseService } from "./db.service";
export const ActionsProvider: FactoryProvider<RunnableWorkflows> = {
provide: "RUNNABLE_ACTIONS",
inject: [DatabaseService],
useFactory: (database: DatabaseService) => ({
assign_user_to_team: {
// ...
},
create_user: {
// ...
},
}),
};
export const RunnableAppContextProvider: Provider<RunnableAppContext> = {
provide: "RUNNABLE_CONTEXT",
useFactory: (authService: AuthService) => ({
auth: {
verifyLogin: (opts) => authService.verifyLogin(opts),
},
}),
};Create the module for the Actions and ActionsContext.
// actions.module.ts
import { Module } from "@nestjs/common";
import {
ActionsProvider,
RunnableAppContextProvider,
} from "./actions.provider";
import { AppController } from "./app.controller";
@Module({
providers: [ActionsProvider, ActionsActionsContextProvider],
})
export class ActionsModule {}Start your Next.js application with Actions.
// 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);
// Runnable
const actions = app.get("RUNNABLE_ACTIONS");
const context = app.get("RUNNABLE_CONTEXT");
installRunnable(app, actions, context);
await app.listen(3000);
}
bootstrap();