mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-13 21:01:21 +08:00
Freestyle mock
This commit is contained in:
parent
e2dd390925
commit
7a0a26d6fd
@ -110,6 +110,9 @@
|
||||
<li>
|
||||
4318: OTel collector
|
||||
</li>
|
||||
<li>
|
||||
8119: Freestyle mock
|
||||
</li>
|
||||
</ul>
|
||||
<noscript>
|
||||
This page requires JavaScript.
|
||||
|
||||
@ -134,6 +134,22 @@ services:
|
||||
- svix-redis
|
||||
- svix-db
|
||||
|
||||
# ================= Freestyle mock =================
|
||||
|
||||
freestyle-mock:
|
||||
build:
|
||||
context: ./freestyle-mock
|
||||
dockerfile: Dockerfile
|
||||
image: freestyle-mock
|
||||
container_name: freestyle-mock
|
||||
ports:
|
||||
- "8119:8080" # POST http://localhost:8119/execute/v1/script
|
||||
environment:
|
||||
DENO_DIR: /deno-cache
|
||||
volumes:
|
||||
- deno-cache:/deno-cache
|
||||
|
||||
|
||||
# ================= volumes =================
|
||||
|
||||
volumes:
|
||||
@ -141,6 +157,7 @@ volumes:
|
||||
inbucket-data:
|
||||
svix-redis-data:
|
||||
svix-postgres-data:
|
||||
deno-cache:
|
||||
|
||||
# ================= configs =================
|
||||
|
||||
|
||||
90
docker/dependencies/freestyle-mock/Dockerfile
Normal file
90
docker/dependencies/freestyle-mock/Dockerfile
Normal file
@ -0,0 +1,90 @@
|
||||
FROM denoland/deno:1.46.1
|
||||
|
||||
# ---- app setup --------------------------------------------------------------
|
||||
WORKDIR /app
|
||||
|
||||
# Drop the whole server inline
|
||||
RUN cat <<'EOF' > server.ts
|
||||
import { serve } from "https://deno.land/std@0.224.0/http/server.ts";
|
||||
import { ensureDir } from "https://deno.land/std@0.224.0/fs/ensure_dir.ts";
|
||||
import { join } from "https://deno.land/std@0.224.0/path/mod.ts";
|
||||
|
||||
type LogLine = { message: string; type: string };
|
||||
|
||||
serve(async (req) => {
|
||||
const url = new URL(req.url);
|
||||
if (!(req.method === "POST" && url.pathname === "/execute/v1/script")) {
|
||||
return new Response("Not found", { status: 404 });
|
||||
}
|
||||
|
||||
const { script, config = {} } = await req.json();
|
||||
|
||||
// 1. temp dir --------------------------------------------------------------
|
||||
const workDir = join("/tmp", "job-" + crypto.randomUUID());
|
||||
await ensureDir(workDir);
|
||||
|
||||
// 2. write user script -----------------------------------------------------
|
||||
const scriptFile = join(workDir, "user_script.ts");
|
||||
await Deno.writeTextFile(scriptFile, script);
|
||||
|
||||
// 3. (optional) pre-cache npm deps ----------------------------------------
|
||||
if (config.nodeModules && Object.keys(config.nodeModules).length) {
|
||||
const pkgs = Object.entries<string>(config.nodeModules).map(
|
||||
([name, ver]) => `npm:${name}@${ver}`,
|
||||
);
|
||||
await new Deno.Command("deno", {
|
||||
cwd: workDir,
|
||||
args: ["cache", "--unstable", "--node-modules-dir", ...pkgs],
|
||||
}).output();
|
||||
}
|
||||
|
||||
// 4. run user script & capture logs ---------------------------------------
|
||||
const logs: LogLine[] = [];
|
||||
const proxied = new Proxy(console, {
|
||||
get(t, p) {
|
||||
if (typeof p === "string" && typeof t[p as keyof Console] === "function") {
|
||||
return (...args: unknown[]) => {
|
||||
logs.push({ message: args.map(String).join(" "), type: p });
|
||||
// @ts-ignore - let it still log to container stdout
|
||||
t[p](...args);
|
||||
};
|
||||
}
|
||||
// @ts-ignore
|
||||
return t[p];
|
||||
},
|
||||
});
|
||||
|
||||
let result: unknown = null;
|
||||
try {
|
||||
const original = globalThis.console;
|
||||
// @ts-ignore
|
||||
globalThis.console = proxied;
|
||||
|
||||
for (const [k, v] of Object.entries(config.envVars ?? {})) Deno.env.set(k, v);
|
||||
|
||||
const mod = await import(`file://${scriptFile}?t=${Date.now()}`);
|
||||
if (typeof mod.default !== "function") throw new Error("default export missing");
|
||||
result = await mod.default();
|
||||
|
||||
// @ts-ignore
|
||||
globalThis.console = original;
|
||||
} catch (err) {
|
||||
return new Response(JSON.stringify({ error: err.message, logs }), {
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
} finally {
|
||||
try { await Deno.remove(workDir, { recursive: true }); } catch { /* ignore */ }
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({ result, logs }), {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}, { port: 8080 });
|
||||
EOF
|
||||
|
||||
# ---- network ----------------------------------------------------------------
|
||||
EXPOSE 8080
|
||||
|
||||
# ---- launch -----------------------------------------------------------------
|
||||
CMD ["deno", "run", "--unstable", "-A", "server.ts"]
|
||||
Loading…
Reference in New Issue
Block a user