plugins 2.0 update

This commit is contained in:
KingKDot
2026-06-22 10:52:27 -05:00
parent e1f5e4c800
commit 30dfdda3ed
55 changed files with 2534 additions and 128 deletions
+41
View File
@@ -0,0 +1,41 @@
import type { RpcResponse } from "./shared";
type PluginContext = {
db: {
exec(sql: string): void;
prepare(sql: string): {
get(...args: unknown[]): any;
run(...args: unknown[]): any;
};
};
log: { info(message: string): void };
};
function now(): string {
return new Date().toISOString();
}
function response(message: string, count?: number): RpcResponse {
return { message, count, at: now() };
}
export default {
setup(ctx: PluginContext) {
ctx.db.exec("CREATE TABLE IF NOT EXISTS counter (id INTEGER PRIMARY KEY CHECK (id = 1), value INTEGER NOT NULL)");
ctx.db.prepare("INSERT OR IGNORE INTO counter (id, value) VALUES (1, 0)").run();
ctx.log.info("sample-ts-fullstack ready");
},
rpc: {
ping(): RpcResponse {
return response("hello from TypeScript server");
},
increment(ctx: PluginContext, params: unknown): RpcResponse {
const by = typeof (params as any)?.by === "number" ? Math.trunc((params as any).by) : 1;
ctx.db.prepare("UPDATE counter SET value = value + ? WHERE id = 1").run(by);
const row = ctx.db.prepare("SELECT value FROM counter WHERE id = 1").get();
return response("counter updated", Number(row?.value || 0));
},
},
};
+10
View File
@@ -0,0 +1,10 @@
export type RpcResponse = {
message: string;
count?: number;
at: string;
};
export function formatLine(label: string, value: RpcResponse): string {
const count = typeof value.count === "number" ? ` count=${value.count}` : "";
return `${label}: ${value.message}${count} at ${value.at}`;
}
+39
View File
@@ -0,0 +1,39 @@
import { formatLine, type RpcResponse } from "./shared";
const output = document.getElementById("sample-ts-output");
const pingButton = document.getElementById("sample-ts-ping");
const countButton = document.getElementById("sample-ts-count");
function append(message: string) {
if (!output) return;
output.textContent = `${message}\n${output.textContent || ""}`;
}
async function rpc(method: string, params?: unknown): Promise<RpcResponse> {
const res = await fetch("/api/plugins/sample-ts-fullstack/rpc", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ method, params }),
});
const body = await res.json();
if (!res.ok || body.ok === false) {
throw new Error(body.error || res.statusText);
}
return body.result as RpcResponse;
}
pingButton?.addEventListener("click", async () => {
try {
append(formatLine("ping", await rpc("ping")));
} catch (err) {
append(`ping failed: ${err instanceof Error ? err.message : String(err)}`);
}
});
countButton?.addEventListener("click", async () => {
try {
append(formatLine("increment", await rpc("increment", { by: 1 })));
} catch (err) {
append(`increment failed: ${err instanceof Error ? err.message : String(err)}`);
}
});