Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
3 changes: 3 additions & 0 deletions apps/host-selfhost/executor.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { mcpHttpPlugin } from "@executor-js/plugin-mcp/api";
import { graphqlHttpPlugin } from "@executor-js/plugin-graphql/api";
import { encryptedSecretsPlugin } from "@executor-js/plugin-encrypted-secrets";
import { toolkitsPlugin } from "@executor-js/plugin-toolkits/server";
import { appsPlugin } from "@executor-js/plugin-apps/api";

import { resolveSecretKey } from "./src/config";
import { getSelfHostAppsBackings } from "./src/apps-backings";

// ---------------------------------------------------------------------------
// Single source of truth for the self-hosted app's plugin list.
Expand Down Expand Up @@ -36,6 +38,7 @@ export default defineExecutorConfig({
mcpHttpPlugin({ dangerouslyAllowStdioMCP: false }),
graphqlHttpPlugin(),
toolkitsPlugin({ activeToolkitSlug }),
appsPlugin({ backings: getSelfHostAppsBackings() }),
// First writable secret provider -> the default for `secrets.set`.
encryptedSecretsPlugin({ key: resolveSecretKey() }),
] as const,
Expand Down
2 changes: 2 additions & 0 deletions apps/host-selfhost/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@executor-js/execution": "workspace:*",
"@executor-js/fumadb": "workspace:*",
"@executor-js/host-mcp": "workspace:*",
"@executor-js/plugin-apps": "workspace:*",
"@executor-js/plugin-encrypted-secrets": "workspace:*",
"@executor-js/plugin-google": "workspace:*",
"@executor-js/plugin-graphql": "workspace:*",
Expand All @@ -48,6 +49,7 @@
},
"devDependencies": {
"@effect/vitest": "catalog:",
"@executor-js/emulate": "^0.13.2",
"@executor-js/vite-plugin": "workspace:*",
"@tailwindcss/vite": "catalog:",
"@tanstack/router-plugin": "^1.167.12",
Expand Down
2 changes: 2 additions & 0 deletions apps/host-selfhost/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { makeSelfHostMcpSeams } from "./mcp";
import { selfHostPlugins } from "./plugins";
import { ErrorCaptureLive } from "./observability";
import { oauthCallbackSignInRedirectLocation } from "./auth/oauth-callback-login";
import { closeSelfHostAppsBackings } from "./apps-backings";

// ===========================================================================
// The self-hosted Executor app, as ONE `ExecutorApp.make` call.
Expand Down Expand Up @@ -139,6 +140,7 @@ export const makeSelfHostApp = async (options: MakeSelfHostAppOptions = {}) => {
toWebHandler,
betterAuth,
closeDb: async () => {
await closeSelfHostAppsBackings();
await mcp.close();
await dbHandle.close();
},
Expand Down
43 changes: 43 additions & 0 deletions apps/host-selfhost/src/apps-backings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { join } from "node:path";

import {
makeGitArtifactStore,
makeQuickjsToolSandbox,
makeSqliteAppsStore,
type AppsBackings,
} from "@executor-js/plugin-apps/api";

import { resolveDataDir } from "./config";

interface SelfHostAppsBackings {
readonly backings: AppsBackings;
readonly close: () => Promise<void>;
}

const createBackings = (dataDir: string): SelfHostAppsBackings => {
const appsDir = join(dataDir, "apps");
return {
backings: {
artifactStore: makeGitArtifactStore({ root: join(appsDir, "artifacts") }),
sandbox: makeQuickjsToolSandbox(),
store: makeSqliteAppsStore({ path: join(appsDir, "store.sqlite") }),
},
close: async () => {},
};
};

let current: { readonly dataDir: string; readonly value: SelfHostAppsBackings } | undefined;

export const getSelfHostAppsBackings = (): AppsBackings => {
const dataDir = resolveDataDir();
if (current && current.dataDir === dataDir) return current.value.backings;
const value = createBackings(dataDir);
current = { dataDir, value };
return value.backings;
};

export const closeSelfHostAppsBackings = async (): Promise<void> => {
const value = current?.value;
current = undefined;
await value?.close();
};
2 changes: 2 additions & 0 deletions apps/host-selfhost/src/testing/test-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
} from "../mcp/session-store";
import { selfHostPlugins } from "../plugins";
import { ErrorCaptureLive } from "../observability";
import { closeSelfHostAppsBackings } from "../apps-backings";

// ===========================================================================
// Self-host TEST harness — the throwaway composition tests use to exercise the
Expand Down Expand Up @@ -217,6 +218,7 @@ export const makeSelfHostTestApp = async (
handler: web.handler,
dispose: async () => {
await web.dispose();
await closeSelfHostAppsBackings();
await sessionStore.close();
await dbHandle.close();
},
Expand Down
1 change: 1 addition & 0 deletions apps/host-selfhost/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"types": ["bun-types"],
"noUnusedLocals": true,
"noImplicitOverride": true,
Expand Down
44 changes: 43 additions & 1 deletion bun.lock

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

Loading
Loading