Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions openworkflow.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { BackendPostgres } from "@openworkflow/backend-postgres";
import { OpenWorkflow } from "openworkflow";

const backend = await BackendPostgres.connect(
"postgresql://postgres:postgres@localhost:5432/postgres",
);
const ow = new OpenWorkflow({ backend });

export default {
ow,
port: 3000,
};
58 changes: 58 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# CLI

Proof of concept:

- Uses tsx
- Only resolves openworkflow.config.ts from project root

Production:

- Should compile with tsc
- Robustly resolve config
- Use esbuild internally to compile and then load openworkflow.config.ts
13 changes: 13 additions & 0 deletions packages/cli/bin/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env -S tsx

import { serveCommand } from "../serve.js";
import { Command } from "commander";

const program = new Command();

program
.name("ow")
.description("OpenWorkflow CLI")
.version("0.1.0")
.addCommand(serveCommand)
.parse();
13 changes: 13 additions & 0 deletions packages/cli/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import path from "node:path";
import { OpenWorkflow } from "openworkflow";

export async function resolveConfig(): Promise<Config> {
const configPath = path.resolve(process.cwd(), "openworkflow.config.ts");
const config = (await import(configPath)) as { default: Config };
return config.default;
}

export interface Config {
ow: OpenWorkflow;
port: number;
}
13 changes: 13 additions & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "@openworkflow/cli",
"version": "0.1.0",
"type": "module",
"bin": {
"ow": "./bin/cli.ts"
},
"dependencies": {
"@openworkflow/dashboard": "file:../dashboard",
"commander": "^14.0.2",
"openworkflow": "file:../openworkflow"
}
}
9 changes: 9 additions & 0 deletions packages/cli/serve.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { resolveConfig } from "./config.js";
import { Command } from "commander";

export const serveCommand = new Command("serve")
.description("Start the OpenWorkflow server")
.action(async () => {
const { ow, port } = await resolveConfig();
await ow.serve({ port });
});
3 changes: 3 additions & 0 deletions packages/dashboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Dashboard

Frontend framework tbd, it should build index.html, etc to dist/
Empty file added packages/dashboard/index.js
Empty file.
13 changes: 13 additions & 0 deletions packages/dashboard/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "@openworkflow/dashboard",
"version": "0.1.0",
"type": "module",
"main": "index.js",
"files": [
"dist"
],
"dependencies": {
"@hono/node-server": "^1.0.0",
"hono": "^4.0.0"
}
}
15 changes: 15 additions & 0 deletions packages/openworkflow/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,21 @@ export class OpenWorkflow {

return definition;
}

async serve(options?: { port?: number }): Promise<void> {
let observability: typeof import("./observability.js");

try {
observability = await import("./observability.js");
} catch {
throw new Error(
"Install @openworkflow/dashboard to enable observability:\n\n" +
"npm install @openworkflow/dashboard\n",
);
}

observability.serve({ ow: this, port: options?.port ?? 3000 });
}
}

//
Expand Down
38 changes: 38 additions & 0 deletions packages/openworkflow/observability.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { OpenWorkflow } from "./index.js";
import { serve as serveNode } from "@hono/node-server";
import { serveStatic } from "@hono/node-server/serve-static";
import { Hono } from "hono";
import path from "node:path";
import { fileURLToPath } from "node:url";

export function serve(options: ObservabilityOptions) {
const port = options.port ?? 3000;
const app = new Hono();

const dashboardPath = path.dirname(
fileURLToPath(
import.meta.resolve("@openworkflow/dashboard", import.meta.url),
),
);

// API endpoints are a slim HTTP wrapper around the OpenWorkflow client
app.get("/api/test", (c) => {
return c.json({
message: "Fetched from openworkflow observability server",
});
});

// Serve the dashboard SPA
app.get("/", serveStatic({ root: path.resolve(dashboardPath, "dist") }));

serveNode({ fetch: app.fetch, port });

console.info(
`OpenWorkflow dashboard running on http://localhost:${port.toString()}/`,
);
}

export interface ObservabilityOptions {
ow: OpenWorkflow;
port?: number;
}