go/pkg/coredeno/runtime/modules.ts
Claude af98accc03
feat(coredeno): Tier 2 bidirectional bridge — Go↔Deno module lifecycle
Wire the CoreDeno sidecar into a fully bidirectional bridge:

- Deno→Go (gRPC): Deno connects as CoreService client via polyfilled
  @grpc/grpc-js over Unix socket. Polyfill patches Deno 2.x http2 gaps
  (getDefaultSettings, pre-connected socket handling, remoteSettings).
- Go→Deno (JSON-RPC): Go connects to Deno's newline-delimited JSON-RPC
  server for module lifecycle (LoadModule, UnloadModule, ModuleStatus).
  gRPC server direction avoided due to Deno http2.createServer limitations.
- ProcessStart/ProcessStop: gRPC handlers delegate to process.Service
  with manifest permission gating (run permissions).
- Deno runtime: main.ts boots DenoService server, connects CoreService
  client with retry + health-check round-trip, handles SIGTERM shutdown.

40 unit tests + 2 integration tests (Tier 1 boot + Tier 2 bidirectional).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 22:43:12 +00:00

50 lines
1.2 KiB
TypeScript

// Module registry — tracks loaded modules and their lifecycle status.
// Tier 2: status tracking only. Tier 3 adds real Deno worker isolates.
export type ModuleStatus = "UNKNOWN" | "LOADING" | "RUNNING" | "STOPPED" | "ERRORED";
// Status enum values matching the proto definition.
export const StatusEnum: Record<ModuleStatus, number> = {
UNKNOWN: 0,
LOADING: 1,
RUNNING: 2,
STOPPED: 3,
ERRORED: 4,
};
export interface Module {
code: string;
entryPoint: string;
permissions: string[];
status: ModuleStatus;
}
export class ModuleRegistry {
private modules = new Map<string, Module>();
load(code: string, entryPoint: string, permissions: string[]): void {
this.modules.set(code, {
code,
entryPoint,
permissions,
status: "RUNNING",
});
console.error(`CoreDeno: module loaded: ${code}`);
}
unload(code: string): boolean {
const mod = this.modules.get(code);
if (!mod) return false;
mod.status = "STOPPED";
console.error(`CoreDeno: module unloaded: ${code}`);
return true;
}
status(code: string): ModuleStatus {
return this.modules.get(code)?.status ?? "UNKNOWN";
}
list(): Module[] {
return Array.from(this.modules.values());
}
}