import manifest from "../../python-runtime/manifest.json" with { type: "json" }; import { fnv1a64 } from "./replay.mjs"; export const PYTHON_BRIDGE_SCHEMA = "python-worker-bridge.v1"; function clone(value) { return structuredClone(value); } function finiteJson(value) { if (value === null || typeof value !== "object") return true; if (typeof value === "number") return Number.isFinite(value); return Array.isArray(value) ? value.every(finiteJson) : Object.values(value).every(finiteJson); } export class PythonBridge { constructor({ loadPyodide = globalThis.loadPyodide, maxSourceBytes = 65536, maxCalls = 256 } = {}) { this.loadPyodide = loadPyodide; this.maxSourceBytes = maxSourceBytes; this.maxCalls = maxCalls; this.pyodide = null; this.initialized = false; this.state = { imports: [], calls: [], errors: [], capabilities: [], tick: 0 }; } capabilities() { return { schema: PYTHON_BRIDGE_SCHEMA, runtime: manifest.runtime, version: manifest.version, python_version: manifest.python_version, abi_version: manifest.abi_version, platform: manifest.platform, worker_only: manifest.worker_only, virtual_modules: clone(manifest.virtual_modules), denied_capabilities: [...manifest.denied_capabilities], initialized: this.initialized, }; } async initialize() { if (this.initialized) return { status: "verified", capabilities: this.capabilities() }; if (typeof this.loadPyodide !== "function") return this.fail("python_runtime_unavailable", "python.runtime_unavailable"); try { this.pyodide = await this.loadPyodide({ indexURL: manifest.index_url }); this.initialized = true; return { status: "verified", capabilities: this.capabilities() }; } catch (error) { return this.fail("python_runtime_init", String(error?.message ?? error)); } } importModule(module) { const symbols = manifest.virtual_modules[module]; if (!symbols) return this.fail("python_unsupported_module", "python.unsupported_module", { module }); if (!this.state.imports.includes(module)) this.state.imports.push(module); return { status: "verified", module, symbols: [...symbols], state_hash: this.hash() }; } checkCapability(capability) { if (manifest.denied_capabilities.includes(capability)) return this.fail("real_hardware_excluded", "python.host_capability_denied", { capability, status: "REAL-EXCLUDED" }); if (typeof capability !== "string" || capability.length === 0) return this.fail("python_capability_invalid", "python.capability_invalid"); if (!this.state.capabilities.includes(capability)) this.state.capabilities.push(capability); return { status: "verified", capability, state_hash: this.hash() }; } invoke(module, symbol, args = []) { const symbols = manifest.virtual_modules[module]; if (!symbols || !symbols.includes(symbol)) return this.fail("python_symbol_unsupported", "python.symbol_unsupported", { module, symbol }); if (!Array.isArray(args) || !finiteJson(args)) return this.fail("python_argument_invalid", "python.argument_invalid"); if (this.state.calls.length >= this.maxCalls) return this.fail("python_call_limit", "python.call_limit"); if (!this.state.imports.includes(module)) this.state.imports.push(module); const call = { module, symbol, args: clone(args), tick: this.state.tick }; this.state.calls.push(call); return { status: "verified", value: { module, symbol, args: clone(args) }, state_hash: this.hash() }; } async execute(source) { if (typeof source !== "string" || new TextEncoder().encode(source).length > this.maxSourceBytes) return this.fail("python_source_limit", "python.source_limit"); const denied = manifest.denied_capabilities.find((capability) => new RegExp(`(?:^|[^A-Za-z0-9_])${capability.replaceAll(".", "\\.")}(?:$|[^A-Za-z0-9_])`).test(source)); if (denied) return this.fail("real_hardware_excluded", "python.host_capability_denied", { capability: denied, status: "REAL-EXCLUDED" }); if (!this.pyodide || typeof this.pyodide.runPythonAsync !== "function") return this.fail("python_runtime_unavailable", "python.runtime_unavailable"); try { const value = await this.pyodide.runPythonAsync(source); return { status: "verified", value: value === undefined ? null : value, state_hash: this.hash() }; } catch (error) { return this.fail("python_exception", "python.exception", { detail: String(error?.message ?? error) }); } } fail(code, message_key, extra = {}) { this.state.errors.push({ code, tick: this.state.tick }); return { status: extra.status ?? "blocked", code, message_key, retryable: false, ...extra, state_hash: this.hash() }; } setTick(tick) { if (Number.isSafeInteger(tick) && tick >= 0) this.state.tick = tick; } exportState() { return { schema: PYTHON_BRIDGE_SCHEMA, initialized: this.initialized, state: clone(this.state) }; } restoreState(value) { if (!value || value.schema !== PYTHON_BRIDGE_SCHEMA || !value.state) return this.fail("python_state_invalid", "python.state_invalid"); this.initialized = Boolean(value.initialized); this.state = clone(value.state); return { status: "verified", state_hash: this.hash() }; } hash() { return fnv1a64(this.state); } } export { manifest };