From 8f7fc5d36b5c446d3d988fb099596a010ef0b9b6 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath <2+defunkt@users.noreply.github.com> Date: Sun, 21 Sep 2025 12:37:21 -0700 Subject: [PATCH] getState --- nose/bin/load.ts | 6 +++--- nose/bin/ls.ts | 4 ++-- nose/bin/project.ts | 4 ++-- nose/bin/projects.ts | 4 ++-- src/commands.ts | 2 +- src/server.tsx | 2 +- src/shell.ts | 15 +++------------ src/state.ts | 15 +++++++++++++++ src/webapp.ts | 3 ++- 9 files changed, 31 insertions(+), 24 deletions(-) create mode 100644 src/state.ts diff --git a/nose/bin/load.ts b/nose/bin/load.ts index 41ecad7..908eac8 100644 --- a/nose/bin/load.ts +++ b/nose/bin/load.ts @@ -1,10 +1,10 @@ import { apps } from "@/webapp" -import { Thread } from "@/shell" +import { getState } from "@/state" export default function (project: string) { - const state = Thread.getStore() + const state = getState() - if (apps().includes(project) && state) { + if (state && apps().includes(project)) { state.project = project } diff --git a/nose/bin/ls.ts b/nose/bin/ls.ts index e017c42..ea98b79 100644 --- a/nose/bin/ls.ts +++ b/nose/bin/ls.ts @@ -1,10 +1,10 @@ import { readdirSync } from "fs" import { NOSE_WWW } from "@/config" -import { Thread } from "@/shell" +import { getState } from "@/state" import { appPath } from "@/webapp" export default function () { - const state = Thread.getStore() + const state = getState() if (!state) return { error: "no state" } const project = state.project diff --git a/nose/bin/project.ts b/nose/bin/project.ts index 4997fb1..b1da363 100644 --- a/nose/bin/project.ts +++ b/nose/bin/project.ts @@ -1,7 +1,7 @@ -import { Thread } from "@/shell" +import { getState } from "@/state" export default function () { - const state = Thread.getStore() + const state = getState() if (!state) return { error: "no state" } return state?.project || "none" diff --git a/nose/bin/projects.ts b/nose/bin/projects.ts index 179bd7d..ddb0604 100644 --- a/nose/bin/projects.ts +++ b/nose/bin/projects.ts @@ -1,8 +1,8 @@ import { apps } from "@/webapp" -import { Thread } from "@/shell" +import { getState } from "@/state" export default function () { - const state = Thread.getStore() + const state = getState() if (!state) return { error: "no state" } return { html: apps().map(app => app === state.project ? `${app}` : app).join(" ") } diff --git a/src/commands.ts b/src/commands.ts index 7237fe2..b4423af 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -1,8 +1,8 @@ import { Glob } from "bun" import { watch } from "fs" -import { NOSE_SYS_BIN, NOSE_BIN } from "./config" import { sendAll } from "./websocket" import { expectDir } from "./utils" +import { NOSE_SYS_BIN, NOSE_BIN } from "./config" const sysCmdWatcher = watch(NOSE_SYS_BIN, async (event, filename) => sendAll({ type: "commands", data: await commands() }) diff --git a/src/server.tsx b/src/server.tsx index 4ba0bfe..081cc08 100644 --- a/src/server.tsx +++ b/src/server.tsx @@ -9,7 +9,7 @@ import { transpile, isFile, tilde } from "./utils" import { apps, serveApp, publishDNS } from "./webapp" import { runCommand } from "./shell" import { commands } from "./commands" -import { send, addWebsocket, removeWebsocket, closeWebsockets, websockets } from "./websocket" +import { send, addWebsocket, removeWebsocket, closeWebsockets } from "./websocket" import { Layout } from "./components/layout" import { Terminal } from "./components/terminal" diff --git a/src/shell.ts b/src/shell.ts index 0e7f9e9..ad036c0 100644 --- a/src/shell.ts +++ b/src/shell.ts @@ -2,20 +2,11 @@ // runs commands and such. import type { CommandResult, CommandOutput } from "./shared/types" +import type { State } from "./state" import { join } from "path" import { NOSE_SYS_BIN, NOSE_BIN } from "./config" import { isFile } from "./utils" -import { AsyncLocalStorage } from "async_hooks" - -// Ensure "Thread" lives between bun's hot reloads -const g = globalThis as typeof globalThis & { __thread?: AsyncLocalStorage } -export const Thread = g.__thread ??= new AsyncLocalStorage() - -type State = { - id?: string - session?: string - project?: string -} +import { ALS } from "./state" const sessions: Map = new Map() @@ -31,7 +22,7 @@ export async function runCommand(session: string, id: string, input: string): Pr const state = getState(session, id) try { - [status, output] = await Thread.run(state, async () => await exec(cmd, args)) + [status, output] = await ALS.run(state, async () => await exec(cmd, args)) } catch (err) { status = "error" output = errorMessage(err) diff --git a/src/state.ts b/src/state.ts new file mode 100644 index 0000000..4f3c9fd --- /dev/null +++ b/src/state.ts @@ -0,0 +1,15 @@ +import { AsyncLocalStorage } from "async_hooks" + +export type State = { + id?: string + session?: string + project?: string +} + +// Ensure "ALS" lives between bun's hot reloads +const g = globalThis as typeof globalThis & { __thread?: AsyncLocalStorage } +export const ALS = g.__thread ??= new AsyncLocalStorage() + +export function getState(): State | undefined { + return ALS.getStore() +} \ No newline at end of file diff --git a/src/webapp.ts b/src/webapp.ts index 5796f0c..ca16cfb 100644 --- a/src/webapp.ts +++ b/src/webapp.ts @@ -1,8 +1,9 @@ -import { type Context, Hono } from "hono" import type { Child } from "hono/jsx" +import { type Context, Hono } from "hono" import { renderToString } from "hono/jsx/dom/server" import { join, dirname } from "path" import { readdirSync, watch } from "fs" + import { NOSE_WWW } from "./config" import { expectDir, isFile } from "./utils"