pub struct PiJsRuntime<C: SchedulerClock = WallClock> { /* private fields */ }Expand description
Integrated PiJS runtime combining QuickJS, scheduler, and Promise bridge.
This is the main entry point for running JavaScript extensions with proper async hostcall support. It provides:
- Promise-based
pi.*methods that enqueue hostcall requests - Deterministic event loop scheduling
- Automatic microtask draining after macrotasks
- Hostcall completion → Promise resolution/rejection
§Example
// Create runtime
let runtime = PiJsRuntime::new().await?;
// Evaluate extension code
runtime.eval("
pi.tool('read', { path: 'foo.txt' }).then(result => {
console.log('Got:', result);
});
").await?;
// Process hostcall requests
while let Some(request) = runtime.drain_hostcall_requests().pop_front() {
// Execute the hostcall
let result = execute_tool(&request.kind, &request.payload).await;
// Deliver completion back to JS
runtime.complete_hostcall(&request.call_id, result)?;
}
// Tick the event loop to deliver completions
let stats = runtime.tick().await?;Implementations§
Source§impl PiJsRuntime<WallClock>
impl PiJsRuntime<WallClock>
Source§impl<C: SchedulerClock + 'static> PiJsRuntime<C>
impl<C: SchedulerClock + 'static> PiJsRuntime<C>
Sourcepub async fn with_clock(clock: C) -> Result<Self>
pub async fn with_clock(clock: C) -> Result<Self>
Create a new PiJS runtime with a custom clock.
Sourcepub async fn with_clock_and_config(
clock: C,
config: PiJsRuntimeConfig,
) -> Result<Self>
pub async fn with_clock_and_config( clock: C, config: PiJsRuntimeConfig, ) -> Result<Self>
Create a new PiJS runtime with a custom clock and runtime config.
Sourcepub async fn with_clock_and_config_with_policy(
clock: C,
config: PiJsRuntimeConfig,
policy: Option<ExtensionPolicy>,
) -> Result<Self>
pub async fn with_clock_and_config_with_policy( clock: C, config: PiJsRuntimeConfig, policy: Option<ExtensionPolicy>, ) -> Result<Self>
Create a new PiJS runtime with a custom clock, runtime config, and optional policy.
pub async fn reset_for_warm_reload(&self) -> Result<PiJsWarmResetReport>
Sourcepub async fn call_global_void(&self, name: &str) -> Result<()>
pub async fn call_global_void(&self, name: &str) -> Result<()>
Invoke a zero-argument global JS function and drain immediate microtasks.
This is useful for hot loops that need to trigger pre-installed JS helpers
without paying per-call parser/compile overhead from eval().
Sourcepub const fn repair_mode(&self) -> RepairMode
pub const fn repair_mode(&self) -> RepairMode
The configured repair mode for this runtime.
Sourcepub const fn auto_repair_enabled(&self) -> bool
pub const fn auto_repair_enabled(&self) -> bool
Whether the auto-repair pipeline should apply repairs.
Sourcepub fn record_repair(&self, event: ExtensionRepairEvent)
pub fn record_repair(&self, event: ExtensionRepairEvent)
Record an auto-repair event. The event is appended to the internal log and emitted as a structured tracing span so external log sinks can capture it.
Sourcepub fn drain_repair_events(&self) -> Vec<ExtensionRepairEvent>
pub fn drain_repair_events(&self) -> Vec<ExtensionRepairEvent>
Drain all accumulated repair events, leaving the internal buffer empty. Useful for conformance reports that need to distinguish clean passes from repaired passes.
Sourcepub fn repair_count(&self) -> u64
pub fn repair_count(&self) -> u64
Number of repair events recorded since the runtime was created.
Sourcepub fn reset_transient_state(&self)
pub fn reset_transient_state(&self)
Reset transient module state for warm isolate reuse.
Clears extension roots, dynamic virtual modules, named export tracking, repair events, and cache counters while preserving the compiled sources cache (both in-memory and disk). This lets the runtime be reloaded with a fresh set of extensions without paying the SWC transpilation cost again.
Sourcepub async fn read_global_json(&self, name: &str) -> Result<Value>
pub async fn read_global_json(&self, name: &str) -> Result<Value>
Read a global variable from the JS context and convert it to JSON.
This is primarily intended for integration tests and diagnostics; it intentionally
does not expose raw rquickjs types as part of the public API.
Sourcepub fn drain_hostcall_requests(&self) -> VecDeque<HostcallRequest>
pub fn drain_hostcall_requests(&self) -> VecDeque<HostcallRequest>
Drain pending hostcall requests from the queue.
Returns the requests that need to be processed by the host.
After processing, call complete_hostcall() for each.
Sourcepub async fn drain_microtasks(&self) -> Result<usize>
pub async fn drain_microtasks(&self) -> Result<usize>
Drain pending QuickJS jobs (Promise microtasks) until fixpoint.
Sourcepub fn next_timer_deadline_ms(&self) -> Option<u64>
pub fn next_timer_deadline_ms(&self) -> Option<u64>
Return the next timer deadline (runtime clock), if any.
Sourcepub fn pending_hostcall_count(&self) -> usize
pub fn pending_hostcall_count(&self) -> usize
Peek at pending hostcall requests without draining.
Sourcepub fn hostcall_queue_telemetry(&self) -> HostcallQueueTelemetry
pub fn hostcall_queue_telemetry(&self) -> HostcallQueueTelemetry
Snapshot queue depth/backpressure counters for diagnostics.
Sourcepub fn hostcall_queue_wait_ms(&self, call_id: &str) -> Option<u64>
pub fn hostcall_queue_wait_ms(&self, call_id: &str) -> Option<u64>
Queue wait (enqueue -> dispatch start) in milliseconds for a pending hostcall.
Sourcepub fn is_hostcall_pending(&self, call_id: &str) -> bool
pub fn is_hostcall_pending(&self, call_id: &str) -> bool
Check whether a given hostcall is still pending.
This is useful for streaming hostcalls that need to stop polling/reading once the JS side has timed out or otherwise completed the call.
Sourcepub async fn get_registered_tools(&self) -> Result<Vec<ExtensionToolDef>>
pub async fn get_registered_tools(&self) -> Result<Vec<ExtensionToolDef>>
Get all tools registered by loaded JS extensions.
Sourcepub async fn get_global_json(&self, name: &str) -> Result<Value>
pub async fn get_global_json(&self, name: &str) -> Result<Value>
Read a global value by name and convert it to JSON.
This is intentionally a narrow helper that avoids exposing raw rquickjs
types in the public API (useful for integration tests and debugging).
Sourcepub fn complete_hostcall(
&self,
call_id: impl Into<String>,
outcome: HostcallOutcome,
)
pub fn complete_hostcall( &self, call_id: impl Into<String>, outcome: HostcallOutcome, )
Enqueue a hostcall completion to be delivered on next tick.
Sourcepub fn complete_hostcalls_batch<I>(&self, completions: I)
pub fn complete_hostcalls_batch<I>(&self, completions: I)
Enqueue multiple hostcall completions in one scheduler borrow.
Sourcepub fn enqueue_event(&self, event_id: impl Into<String>, payload: Value)
pub fn enqueue_event(&self, event_id: impl Into<String>, payload: Value)
Enqueue an inbound event to be delivered on next tick.
Sourcepub fn set_timeout(&self, delay_ms: u64) -> u64
pub fn set_timeout(&self, delay_ms: u64) -> u64
Set a timer to fire after the given delay.
Returns the timer ID for cancellation.
Sourcepub fn clear_timeout(&self, timer_id: u64) -> bool
pub fn clear_timeout(&self, timer_id: u64) -> bool
Cancel a timer by ID.
Sourcepub fn has_pending(&self) -> bool
pub fn has_pending(&self) -> bool
Check if there are pending tasks (macrotasks or timers).
Sourcepub async fn tick(&self) -> Result<PiJsTickStats>
pub async fn tick(&self) -> Result<PiJsTickStats>
Execute one tick of the event loop.
This will:
- Move due timers to the macrotask queue
- Execute one macrotask (if any)
- Drain all pending QuickJS jobs (microtasks)
Returns statistics about what was executed.
Sourcepub fn add_allowed_read_root(&self, root: PathBuf)
pub fn add_allowed_read_root(&self, root: PathBuf)
Install the pi.* bridge with Promise-returning hostcall methods.
The bridge uses a two-layer design:
- Rust native functions (
__pi_*_native) that return call_id strings - JS wrappers (
pi.*) that create Promises and register them
This avoids lifetime issues with returning Promises from Rust closures.
Register an additional filesystem root that readFileSync is allowed
to access. Called before loading each extension so it can read its own
bundled assets (HTML templates, markdown docs, etc.).
Sourcepub fn add_extension_root(&self, root: PathBuf)
pub fn add_extension_root(&self, root: PathBuf)
Register an extension root directory so the resolver can detect
monorepo escape patterns (Pattern 3). Also registers the root
for readFileSync access.
Sourcepub fn add_extension_root_with_id(
&self,
root: PathBuf,
extension_id: Option<&str>,
)
pub fn add_extension_root_with_id( &self, root: PathBuf, extension_id: Option<&str>, )
Register an extension root with optional extension ID metadata.
Pattern 4 (missing npm dependency proxy stubs) uses this metadata to
apply stricter policy for official/first-party extensions and to allow
same-scope package imports (@scope/*) when scope can be discovered.
Trait Implementations§
Source§impl<C: SchedulerClock + 'static> ExtensionDispatcherRuntime<C> for PiJsRuntime<C>
impl<C: SchedulerClock + 'static> ExtensionDispatcherRuntime<C> for PiJsRuntime<C>
fn as_js_runtime(&self) -> &PiJsRuntime<C>
Auto Trait Implementations§
impl<C> Freeze for PiJsRuntime<C>
impl<C = WallClock> !RefUnwindSafe for PiJsRuntime<C>
impl<C = WallClock> !Send for PiJsRuntime<C>
impl<C = WallClock> !Sync for PiJsRuntime<C>
impl<C> Unpin for PiJsRuntime<C>
impl<C> UnsafeUnpin for PiJsRuntime<C>
impl<C = WallClock> !UnwindSafe for PiJsRuntime<C>
Blanket Implementations§
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, _span: NoopSpan) -> Self
fn instrument(self, _span: NoopSpan) -> Self
Source§fn in_current_span(self) -> Self
fn in_current_span(self) -> Self
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more