pub mod executor;
pub mod ops;
pub mod tests;
use fraiseql_error::Result;
use crate::{
HostContext,
runtime::FunctionRuntime,
types::{EventPayload, FunctionModule, FunctionResult, ResourceLimits},
};
pub const FRAISEQL_HOST_TYPES: &str = r"
// FraiseQL host operations type definitions for TypeScript
// These are available on Deno.core.ops
interface HttpResponse {
status: number;
headers: Array<[string, string]>;
body: Uint8Array;
}
// Execute a GraphQL query
async function fraiseql_query(
graphql: string,
variables: string, // JSON string
): Promise<string>; // JSON string
// Execute a raw SQL query
async function fraiseql_sql_query(
sql: string,
params: string, // JSON array string
): Promise<string>; // JSON array string
// Make an HTTP request
async function fraiseql_http_request(
method: string,
url: string,
headers: Array<[string, string]>,
body: Uint8Array | null,
): Promise<HttpResponse>;
// Retrieve an object from storage
async function fraiseql_storage_get(
bucket: string,
key: string,
): Promise<Uint8Array>;
// Store an object to storage
async function fraiseql_storage_put(
bucket: string,
key: string,
body: Uint8Array,
content_type: string,
): Promise<void>;
// Get the current authenticated user's context
function fraiseql_auth_context(): string; // JSON string
// Get an environment variable
function fraiseql_env_var(name: string): string | null;
// Log a message
function fraiseql_log(level: number, message: string): void;
// Levels: 0=debug, 1=info, 2=warn, 3=error
";
#[derive(Debug, Clone)]
pub struct DenoConfig {
pub enable_typescript: bool,
pub v8_flags: Vec<String>,
}
impl Default for DenoConfig {
fn default() -> Self {
Self {
enable_typescript: true,
v8_flags: vec![],
}
}
}
pub struct DenoRuntime {
config: DenoConfig,
}
impl std::fmt::Debug for DenoRuntime {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DenoRuntime").field("config", &self.config).finish()
}
}
impl Clone for DenoRuntime {
fn clone(&self) -> Self {
Self {
config: self.config.clone(),
}
}
}
impl DenoRuntime {
pub fn new(config: &DenoConfig) -> Result<Self> {
Ok(Self {
config: config.clone(),
})
}
}
impl FunctionRuntime for DenoRuntime {
#[allow(clippy::manual_async_fn)] fn invoke<H>(
&self,
module: &FunctionModule,
event: EventPayload,
_host: &H,
limits: ResourceLimits,
) -> impl std::future::Future<Output = Result<FunctionResult>> + Send
where
H: HostContext + ?Sized,
{
let source = String::from_utf8_lossy(&module.bytecode).to_string();
let event_data = event.data;
async move {
let start = std::time::Instant::now();
let (tx, rx) = tokio::sync::oneshot::channel::<
std::result::Result<executor::ExecutionResult, String>,
>();
std::thread::spawn(move || {
let result = executor::run_in_dedicated_thread(&source, &event_data, &limits);
let _ = tx.send(result);
});
let duration = start.elapsed();
let exec_result = rx.await.map_err(|_| fraiseql_error::FraiseQLError::Internal {
message: "Deno executor thread crashed".to_string(),
source: None,
})?;
match exec_result {
Ok(execution_result) => Ok(FunctionResult {
value: Some(execution_result.value),
logs: execution_result.logs,
duration,
memory_peak_bytes: 0,
}),
Err(e) if e.starts_with("SyntaxError") => {
Err(fraiseql_error::FraiseQLError::Validation {
message: e,
path: None,
})
},
Err(e) => Err(fraiseql_error::FraiseQLError::Unsupported { message: e }),
}
}
}
fn supported_extensions(&self) -> &[&str] {
&[".js", ".ts", ".mjs", ".mts"]
}
fn supports_hot_reload(&self) -> bool {
false
}
fn name(&self) -> &'static str {
"deno"
}
}