use noxid_execution_ir::{
EndpointExecutionBoundary, ExecutionBoundary, ExecutionProgram, QueueExecutionBoundary,
TaskExecutionBoundary,
};
use noxid_ir::{
EndpointInputSection, EndpointKind, EndpointLimitScope, EndpointLimitWindow, SemanticBinaryOp,
SemanticExpr, SemanticExprKind, SemanticId, SemanticTemplatePart,
};
use noxid_source::js_escape;
mod agents;
pub use agents::AgentRuntimeOptions;
pub const HANDLER_SCHEMA_VERSION: u32 = 8;
const SERVER_LIFECYCLE_EXPORTS: &str = include_str!("../../../tools/server-lifecycle-exports.txt");
/// The compiler-owned server surface that must survive composition and
/// deployment bundling. Keep the names in the shared tools file so the Rust
/// emitters and the Farm bridge cannot drift independently.
pub fn server_lifecycle_exports() -> impl Iterator<Item = &'static str> {
SERVER_LIFECYCLE_EXPORTS
.lines()
.filter(|line| !line.is_empty())
}
pub fn server_lifecycle_export_required(name: &str, tracing_export: ServerTracingExport) -> bool {
tracing_export == ServerTracingExport::Otlp
|| !matches!(
name,
"flushNoxidTracing" | "abandonNoxidTracing" | "noxidTracingExporterSnapshot"
)
}
fn missing_server_lifecycle_exports(
handler: &str,
tracing_export: ServerTracingExport,
) -> Vec<&'static str> {
server_lifecycle_exports()
.filter(|name| server_lifecycle_export_required(name, tracing_export))
.filter(|name| {
![
format!("export const {name} "),
format!("export function {name}("),
format!("export async function {name}("),
]
.iter()
.any(|declaration| handler.contains(declaration))
})
.collect()
}
const LANGUAGE_VALUE_EQUALITY_FUNCTION: &str = r#"function $noxEqual($noxLeft, $noxRight) {
if ($noxLeft === $noxRight) return true;
if (Array.isArray($noxLeft) || Array.isArray($noxRight)) return Array.isArray($noxLeft) && Array.isArray($noxRight) && $noxLeft.length === $noxRight.length && $noxLeft.every(($noxValue, $noxIndex) => $noxEqual($noxValue, $noxRight[$noxIndex]));
if ($noxLeft === null || $noxRight === null || typeof $noxLeft !== "object" || typeof $noxRight !== "object") return false;
const $noxLeftKeys = Object.keys($noxLeft).sort();
const $noxRightKeys = Object.keys($noxRight).sort();
return $noxLeftKeys.length === $noxRightKeys.length && $noxLeftKeys.every(($noxKey, $noxIndex) => $noxKey === $noxRightKeys[$noxIndex] && $noxEqual($noxLeft[$noxKey], $noxRight[$noxKey]));
}
"#;
#[derive(Clone, Debug)]
pub struct ServerJavaScriptOutput {
pub handler: String,
pub manifest: String,
pub server_actions: usize,
pub edge_actions: usize,
}
#[derive(Clone, Copy, Debug, Default)]
pub struct AgentSurfaceOptions<'a> {
pub openapi_json: Option<&'a str>,
pub serve_openapi: bool,
pub mcp: bool,
pub principal_authority_import: Option<&'a str>,
}
#[derive(Clone, Debug)]
pub struct ServerRuntimeOptions {
pub db_pool: u64,
pub pubsub: Option<PubSubRuntimeOptions>,
pub development_trace_capture: bool,
pub application_namespace: Option<String>,
/// WO-30 model declarations. Empty means the emitted graph carries no
/// models runtime section at all.
pub models: ModelRuntimeOptions,
pub tracing_export: ServerTracingExport,
pub tracing_service_name: String,
pub otlp_endpoint_secret: bool,
pub otlp_headers_secret: bool,
/// WO-31 agent declarations. An agent without `model:` is not an engine
/// agent, so a build with none carries no `agents` runtime section.
pub agents: AgentRuntimeOptions,
}
/// The compile-time half of the model boundary: every declared model, plus the
/// strict JSON Schema for every declared type a `generateObject` call could
/// name. Both are frozen into the emitted graph so a request resolves nothing
/// but its own secret.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct ModelRuntimeOptions {
pub models: Vec<noxid_model_ir::LoweredModel>,
pub type_schemas: Vec<noxid_model_ir::ModelTypeSchema>,
}
impl ModelRuntimeOptions {
pub fn is_empty(&self) -> bool {
self.models.is_empty()
}
}
impl Default for ServerRuntimeOptions {
fn default() -> Self {
Self {
db_pool: 10,
pubsub: None,
development_trace_capture: false,
application_namespace: None,
models: ModelRuntimeOptions::default(),
tracing_export: ServerTracingExport::Stdout,
tracing_service_name: "noxid.application".into(),
otlp_endpoint_secret: false,
otlp_headers_secret: false,
agents: AgentRuntimeOptions::default(),
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum ServerTracingExport {
#[default]
Stdout,
Otlp,
}
impl ServerTracingExport {
pub fn as_str(self) -> &'static str {
match self {
Self::Stdout => "stdout",
Self::Otlp => "otlp",
}
}
}
/// Emit one lazy getter per declared server secret. Values resolve and cache
/// only when their own property is read, so a missing telemetry credential
/// cannot poison an unrelated application-secret read.
pub fn server_secrets_prelude_javascript(secrets: &[String]) -> String {
if secrets.is_empty() {
return "const __NOXID_TRACING_SECRET_FAILURE__ = false;\nconst __noxidServerEnvironment = (environment) => environment;\n".into();
}
let names = secrets
.iter()
.map(|name| format!("\"{}\"", js_escape(name)))
.collect::<Vec<_>>()
.join(", ");
format!(
r#"const __NOXID_DECLARED_SECRETS__ = Object.freeze([{names}]);
const __NOXID_SECRET_CACHE__ = Object.create(null);
let __NOXID_TRACING_SECRET_FAILURE__ = false;
let __NOXID_TRACING_SECRET_ERROR_LOGGED__ = false;
function __noxidResolveSecret(name) {{
if (Object.hasOwn(__NOXID_SECRET_CACHE__, name)) return __NOXID_SECRET_CACHE__[name];
const value = globalThis.process?.env?.[name];
if (typeof value !== "string" || value.length === 0) {{
if (name === "OTEL_EXPORTER_OTLP_ENDPOINT" || name === "OTEL_EXPORTER_OTLP_HEADERS") {{
__NOXID_TRACING_SECRET_FAILURE__ = true;
if (!__NOXID_TRACING_SECRET_ERROR_LOGGED__) {{
__NOXID_TRACING_SECRET_ERROR_LOGGED__ = true;
try {{ console.error(JSON.stringify(Object.freeze({{ schema: "noxid.tracing.error.v1", event: "tracing.export.disabled", code: "TRACING_EXPORT_SECRET_MISSING", exporter: "otlp" }}))); }} catch {{}}
}}
}}
throw new Error("error[SERVER_SECRET_MISSING]: declared server secret " + name + " is missing from the environment");
}}
Object.defineProperty(__NOXID_SECRET_CACHE__, name, {{ value, enumerable: true }});
return value;
}}
const __NOXID_SECRET_VALUES__ = Object.create(null);
for (const name of __NOXID_DECLARED_SECRETS__) {{
Object.defineProperty(__NOXID_SECRET_VALUES__, name, {{ get: () => __noxidResolveSecret(name), enumerable: true }});
}}
Object.freeze(__NOXID_SECRET_VALUES__);
function __noxidServerEnvironment(environment) {{
if (environment !== null && typeof environment === "object" && Object.getOwnPropertyDescriptor(environment, "secrets")) return environment;
const enriched = Object.create(environment ?? null);
Object.defineProperty(enriched, "secrets", {{ value: __NOXID_SECRET_VALUES__, enumerable: false }});
return enriched;
}}
"#
)
}
/// The single compiler-owned bridge from the closed `noxid.trace.v1` record
/// schema to OpenTelemetry semantic-convention attributes. Keeping duplicate
/// source fields (such as `code`) explicit makes the exported contract golden-
/// testable without teaching the JavaScript runtime Noxid semantics.
pub fn otel_span_attribute_mapping() -> &'static [(&'static str, &'static str, Option<&'static str>)]
{
&[
("method", "http.request.method", None),
("route", "http.route", None),
("status", "http.response.status_code", None),
("durationMs", "noxid.duration_ms", None),
("code", "error.type", None),
("semanticId", "noxid.semantic_id", None),
("code", "noxid.diagnostic_code", None),
("capability", "noxid.capability", None),
("state", "noxid.queue.state", Some("queue.state")),
]
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PubSubDriver {
Memory,
Postgres,
Redis,
}
impl PubSubDriver {
fn as_str(self) -> &'static str {
match self {
Self::Memory => "memory",
Self::Postgres => "postgres",
Self::Redis => "redis",
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct PubSubRuntimeOptions {
pub driver: PubSubDriver,
pub coalescing_ms: u64,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum ServerTracingMode {
Off,
#[default]
Requests,
Full,
}
impl ServerTracingMode {
pub fn as_str(self) -> &'static str {
match self {
Self::Off => "off",
Self::Requests => "requests",
Self::Full => "full",
}
}
}
pub fn generate(
program: &ExecutionProgram,
host_import: &str,
validator_import: &str,
middleware_import: &str,
base_path: &str,
server_secrets: &[String],
) -> Result<ServerJavaScriptOutput, String> {
generate_with_startup(
program,
host_import,
validator_import,
middleware_import,
None,
base_path,
server_secrets,
)
}
pub fn generate_with_startup(
program: &ExecutionProgram,
host_import: &str,
validator_import: &str,
middleware_import: &str,
startup_import: Option<&str>,
base_path: &str,
server_secrets: &[String],
) -> Result<ServerJavaScriptOutput, String> {
generate_with_agent_surfaces(
program,
host_import,
validator_import,
middleware_import,
startup_import,
base_path,
server_secrets,
AgentSurfaceOptions::default(),
)
}
#[allow(clippy::too_many_arguments)]
pub fn generate_with_agent_surfaces(
program: &ExecutionProgram,
host_import: &str,
validator_import: &str,
middleware_import: &str,
startup_import: Option<&str>,
base_path: &str,
server_secrets: &[String],
agent_surfaces: AgentSurfaceOptions<'_>,
) -> Result<ServerJavaScriptOutput, String> {
generate_with_tracing(
program,
host_import,
validator_import,
middleware_import,
startup_import,
base_path,
server_secrets,
agent_surfaces,
ServerTracingMode::Requests,
)
}
// Keep the established import/base-path arguments explicit while adding
// compiler-owned surface and tracing contracts; call sites should not assemble
// an opaque options bag containing unrelated handler inputs.
#[allow(clippy::too_many_arguments)]
pub fn generate_with_tracing(
program: &ExecutionProgram,
host_import: &str,
validator_import: &str,
middleware_import: &str,
startup_import: Option<&str>,
base_path: &str,
server_secrets: &[String],
agent_surfaces: AgentSurfaceOptions<'_>,
tracing_mode: ServerTracingMode,
) -> Result<ServerJavaScriptOutput, String> {
generate_with_runtime_options(
program,
host_import,
validator_import,
middleware_import,
startup_import,
base_path,
server_secrets,
agent_surfaces,
tracing_mode,
ServerRuntimeOptions::default(),
)
}
#[allow(clippy::too_many_arguments)]
pub fn generate_with_runtime_options(
program: &ExecutionProgram,
host_import: &str,
validator_import: &str,
middleware_import: &str,
startup_import: Option<&str>,
base_path: &str,
server_secrets: &[String],
agent_surfaces: AgentSurfaceOptions<'_>,
tracing_mode: ServerTracingMode,
runtime_options: ServerRuntimeOptions,
) -> Result<ServerJavaScriptOutput, String> {
let callable = program
.boundaries
.iter()
.filter(|boundary| matches!(boundary.target.as_str(), "server" | "edge"))
.collect::<Vec<_>>();
let schemas = callable
.iter()
.map(|boundary| schema_javascript(boundary))
.collect::<Vec<_>>()
.join(",\n ");
let compiled_actions = callable
.iter()
.filter_map(|boundary| {
boundary.body.as_ref().map(|body| {
Ok(format!(
"\"{}\": async (args) => ({})",
js_escape(boundary.action.as_str()),
compiler_body_javascript(body)?,
))
})
})
.collect::<Result<Vec<_>, String>>()?
.join(",\n ");
let endpoint_schemas = program
.endpoints
.iter()
.map(endpoint_schema_javascript)
.collect::<Vec<_>>()
.join(",\n ");
let uses_uploads = program
.endpoints
.iter()
.flat_map(|endpoint| &endpoint.inputs)
.any(|input| input.file.is_some());
let compiled_endpoints = program
.endpoints
.iter()
.filter_map(|endpoint| {
if endpoint.statements.is_empty() {
return None;
}
Some(
noxid_ir::computational_statements_javascript(
&endpoint.statements,
2,
&compiler_body_javascript,
)
.map(|body| {
// ADR 0137 rule 2: the dispatcher already passes the
// frozen data context as the second argument, so binding
// it here is the whole of `context.principal`.
format!(
"\"{}\": async (args, context) => {{\n{}{}}}",
js_escape(endpoint.id.as_str()),
body,
" ",
)
}),
)
})
.collect::<Result<Vec<_>, String>>()?
.join(",\n ");
let task_schemas = program
.tasks
.iter()
.map(task_schema_javascript)
.collect::<Vec<_>>()
.join(",\n ");
let compiled_tasks = program
.tasks
.iter()
.filter_map(|task| {
if task.host_key.is_some() {
return None;
}
Some(
compiler_statements_javascript(&task.statements, 2).map(|body| {
format!(
"\"{}\": async (_args, context) => {{\n{body} }}",
js_escape(task.id.as_str()),
)
}),
)
})
.collect::<Result<Vec<_>, String>>()?
.join(",\n ");
let queue_schemas = program
.queues
.iter()
.map(queue_schema_javascript)
.collect::<Vec<_>>()
.join(",\n ");
let live_resource_schemas = program
.live_resources
.iter()
.map(|resource| {
let capabilities = resource
.capabilities
.iter()
.map(|capability| format!("\"{}\"", js_escape(capability)))
.collect::<Vec<_>>()
.join(", ");
let route_scopes = resource
.route_scopes
.iter()
.map(|scope| {
let parameters = scope
.parameters
.iter()
.map(|parameter| format!(
"Object.freeze({{ name: \"{}\", type: \"{}\", catchAll: {} }})",
js_escape(¶meter.name),
js_escape(¶meter.ty),
parameter.catch_all,
))
.collect::<Vec<_>>()
.join(", ");
let middleware = scope
.middleware
.iter()
.filter_map(|id| id.as_str().strip_prefix("middleware:"))
.map(|name| format!("\"{}\"", js_escape(name)))
.collect::<Vec<_>>()
.join(", ");
format!(
"Object.freeze({{ id: \"{}\", pattern: \"{}\", parameters: Object.freeze([{}]), middleware: Object.freeze([{}]) }})",
js_escape(scope.route.as_str()),
js_escape(&scope.pattern),
parameters,
middleware,
)
})
.collect::<Vec<_>>()
.join(", ");
format!(
"Object.freeze({{ id: \"{}\", name: \"{}\", capabilities: Object.freeze([{}]), routeScopes: Object.freeze([{}]) }})",
js_escape(resource.id.as_str()),
js_escape(&resource.name),
capabilities,
route_scopes,
)
})
.collect::<Vec<_>>()
.join(",\n ");
let presence_schemas = program
.presences
.iter()
.map(|presence| {
let capabilities = presence
.capabilities
.iter()
.map(|capability| format!("\"{}\"", js_escape(capability)))
.collect::<Vec<_>>()
.join(", ");
let route_scopes = presence
.route_scopes
.iter()
.map(|scope| {
let parameters = scope
.parameters
.iter()
.map(|parameter| format!(
"Object.freeze({{ name: \"{}\", type: \"{}\", catchAll: {} }})",
js_escape(¶meter.name),
js_escape(¶meter.ty),
parameter.catch_all,
))
.collect::<Vec<_>>()
.join(", ");
let middleware = scope
.middleware
.iter()
.filter_map(|id| id.as_str().strip_prefix("middleware:"))
.map(|name| format!("\"{}\"", js_escape(name)))
.collect::<Vec<_>>()
.join(", ");
format!(
"Object.freeze({{ id: \"{}\", pattern: \"{}\", parameters: Object.freeze([{}]), middleware: Object.freeze([{}]) }})",
js_escape(scope.route.as_str()),
js_escape(&scope.pattern),
parameters,
middleware,
)
})
.collect::<Vec<_>>()
.join(", ");
format!(
"Object.freeze({{ id: \"{}\", component: \"{}\", stream: \"{}\", recordType: \"{}\", memberType: \"{}\", snapshotType: \"{}\", capabilities: Object.freeze([{}]), routeScopes: Object.freeze([{}]), ttlMilliseconds: {}, heartbeatMilliseconds: {} }})",
js_escape(presence.id.as_str()),
js_escape(&presence.component_name),
js_escape(presence.stream.as_str()),
js_escape(presence.record_type.as_str()),
js_escape(presence.member_type.as_str()),
js_escape(presence.snapshot_type.as_str()),
capabilities,
route_scopes,
presence.ttl_ms,
presence.heartbeat_ms,
)
})
.collect::<Vec<_>>()
.join(",\n ");
let live_surface = !program.live_resources.is_empty() || !program.presences.is_empty();
let application_namespace = runtime_options
.application_namespace
.as_deref()
.unwrap_or("codegen_test");
let pubsub_options = runtime_options.pubsub.or_else(|| {
live_surface.then_some(PubSubRuntimeOptions {
driver: PubSubDriver::Memory,
coalescing_ms: 250,
})
});
let compiled_queues = program
.queues
.iter()
.filter_map(|queue| {
if queue.host_key.is_some() {
return None;
}
Some(
compiler_statements_javascript(&queue.statements, 2).map(|body| {
format!(
"\"{}\": async (args, context) => {{\n{body} }}",
js_escape(queue.id.as_str()),
)
}),
)
})
.collect::<Result<Vec<_>, String>>()?
.join(",\n ");
// Remote bodies may call temporal builtins; the helper module travels
// with the handler when any compiled body needs it.
let compiled_server_bodies =
format!("{compiled_actions}\n{compiled_endpoints}\n{compiled_tasks}\n{compiled_queues}");
let date_helpers = if compiled_server_bodies.contains("$noxDate.") {
format!("{}\n", noxid_ir::DATE_HELPERS_JS)
} else {
String::new()
};
let endpoint = if base_path == "/" {
"/_noxid/actions/".to_string()
} else {
format!("{base_path}/_noxid/actions/")
};
let invalidation_endpoint = if base_path == "/" {
"/_noxid/revalidate".to_string()
} else {
format!("{base_path}/_noxid/revalidate")
};
let task_endpoint = if base_path == "/" {
"/_noxid/tasks/".to_string()
} else {
format!("{base_path}/_noxid/tasks/")
};
let queue_drain_endpoint = if base_path == "/" {
"/_noxid/queue/drain".to_string()
} else {
format!("{base_path}/_noxid/queue/drain")
};
let live_resource_endpoint = if base_path == "/" {
"/_noxid/live".to_string()
} else {
format!("{base_path}/_noxid/live")
};
let presence_write_endpoint = if base_path == "/" {
"/_noxid/presence".to_string()
} else {
format!("{base_path}/_noxid/presence")
};
let equality_function = if compiled_server_bodies.contains("$noxEqual(") {
LANGUAGE_VALUE_EQUALITY_FUNCTION
} else {
""
};
let uses_endpoint_storage = program
.endpoints
.iter()
.any(|endpoint| endpoint.limit.is_some() || endpoint.idempotent);
let uses_redis_pubsub =
pubsub_options.is_some_and(|options| options.driver == PubSubDriver::Redis);
let uses_presence_storage = !program.presences.is_empty();
// The agent engine persists every run under the `agent_runs` namespace, so
// an engine agent brings the storage runtime in on its own.
let uses_agent_storage = !runtime_options.agents.is_empty();
let storage_import_javascript = if uses_endpoint_storage
|| uses_presence_storage
|| uses_redis_pubsub
|| uses_uploads
|| uses_agent_storage
{
format!(
"import * as __noxidServerStorageRuntime from \"./noxid-server.js\";\n{}{}{}",
if uses_endpoint_storage || uses_presence_storage || uses_agent_storage {
"const __noxidStorage = __noxidServerStorageRuntime.storage;\nconst __noxidSharedRateLimit = __noxidServerStorageRuntime.__noxidEndpointRateLimit;\nconst __noxidSharedIdempotencyPrepare = __noxidServerStorageRuntime.__noxidEndpointIdempotencyPrepare;\nconst __noxidSharedIdempotencyComplete = __noxidServerStorageRuntime.__noxidEndpointIdempotencyComplete;\nconst __noxidSharedIdempotencyRelease = __noxidServerStorageRuntime.__noxidEndpointIdempotencyRelease;\n"
} else {
""
},
if uses_redis_pubsub {
"const __noxidRedisPubSubPublish = __noxidServerStorageRuntime.__noxidRedisPubSubPublish;\nconst __noxidRedisPubSubSubscribe = __noxidServerStorageRuntime.__noxidRedisPubSubSubscribe;\n"
} else {
""
},
if uses_uploads {
"const __noxidCreateUploadSink = __noxidServerStorageRuntime.__noxidCreateUploadSink;\n"
} else {
""
},
)
} else {
String::new()
};
let startup_import_javascript = startup_import.map_or_else(String::new, |specifier| {
format!(
"import {{ startServerPlugins as __noxidStartServerPlugins }} from \"{}\";\n",
js_escape(specifier)
)
});
let principal_authority_import_javascript = agent_surfaces
.principal_authority_import
.map_or_else(|| "const __noxidCloseDatabase = async () => {};\n".into(), |specifier| {
format!(
"import {{ __installNoxidPrincipalAuthority, closeDatabase as __noxidCloseDatabase }} from \"{}\";\n",
js_escape(specifier)
)
});
let otlp_import_javascript = match runtime_options.tracing_export {
ServerTracingExport::Stdout => String::new(),
ServerTracingExport::Otlp => {
"import { createOtlpTraceExporter } from \"../assets/noxid-runtime.js\";\n".into()
}
};
let principal_authority_import_javascript =
format!("{principal_authority_import_javascript}{otlp_import_javascript}");
let live_resource_runtime = if live_surface {
format!(
"const liveResourcePath = \"{}\";\nconst presenceWritePath = \"{}\";\nconst liveResourceSchemas = Object.freeze([\n {}\n]);\nconst presenceSchemas = Object.freeze([\n {}\n]);\n{}",
js_escape(&live_resource_endpoint),
js_escape(&presence_write_endpoint),
live_resource_schemas,
presence_schemas,
LIVE_RESOURCE_RUNTIME,
)
} else {
String::new()
};
let handler_runtime = HANDLER_RUNTIME
.replace(
" /* noxid-server:startup */",
if startup_import.is_some() {
" await __noxidStartServerPlugins(environment);"
} else {
""
},
)
.replace(
"/* noxid-server:live-invalidation */",
if pubsub_options.is_some() {
r#"async function __noxidPublishLiveInvalidations(resources, principal) {
for (const semanticId of resources) {
await __noxidPubSubPublish(__noxidPubSubEvent("invalidation", semanticId, principal));
}
}"#
} else {
"async function __noxidPublishLiveInvalidations() {}"
},
)
.replace(
"/* noxid-server:live-resource-transport-runtime */",
&live_resource_runtime,
)
.replace(
" /* noxid-server:live-resource-request */",
if live_surface {
" const liveResourceResponse = await handleLiveResourceRequest(request, url, environment, executionContext);\n if (liveResourceResponse !== null) return liveResourceResponse;"
} else {
""
},
);
let trace_export_javascript = match runtime_options.tracing_export {
ServerTracingExport::Stdout => {
"if (loggable) { try { console.log(JSON.stringify(record)); } catch {} }"
}
ServerTracingExport::Otlp => {
"if (loggable && event !== \"request.start\") { try { __noxidOtlpExporter.enqueue(Object.freeze({ ...record, traceFlags: trace.traceFlags })); } catch {} }"
}
};
let trace_runtime = TRACE_RUNTIME
.replace(
" /* noxid-server:development-trace-context */",
if runtime_options.development_trace_capture {
" developmentCapture = true;"
} else {
""
},
)
.replace(
" /* noxid-server:development-trace-capture */",
if runtime_options.development_trace_capture {
r#" try {
const capture = globalThis.__NOXID_DEV_TRACE_CAPTURE__;
if (typeof capture === "function") capture(Object.freeze({ ...record }));
} catch {}"#
} else {
""
},
)
.replace(
" /* noxid-server:trace-span-id */",
if runtime_options.tracing_export == ServerTracingExport::Otlp {
" try { return __noxidOtlpExporter.nextSpanId(); } catch {}"
} else {
""
},
)
.replace(" /* noxid-server:trace-export */", trace_export_javascript);
let trace_runtime = if runtime_options.tracing_export == ServerTracingExport::Otlp {
let attribute_mapping = otel_span_attribute_mapping()
.iter()
.map(|(source, target, event)| {
format!(
"Object.freeze({{ source: \"{}\", target: \"{}\", event: {} }})",
js_escape(source),
js_escape(target),
event
.map(|event| format!("\"{}\"", js_escape(event)))
.unwrap_or_else(|| "null".into()),
)
})
.collect::<Vec<_>>()
.join(", ");
format!(
r#"const __noxidOtlpExporter = createOtlpTraceExporter({{
endpoint: __noxidTracingEnvironmentValue(globalThis.process?.env, "OTEL_EXPORTER_OTLP_ENDPOINT", tracingOtlpEndpointSecret),
headers: __noxidTracingEnvironmentValue(globalThis.process?.env, "OTEL_EXPORTER_OTLP_HEADERS", tracingOtlpHeadersSecret),
serviceName: "{}",
disabled: __NOXID_TRACING_SECRET_FAILURE__,
attributeMapping: Object.freeze([{attribute_mapping}]),
}});
export async function flushNoxidTracing() {{ try {{ await __noxidOtlpExporter.flush(); }} catch {{}} }}
export function abandonNoxidTracing() {{ try {{ return __noxidOtlpExporter.abandon(); }} catch {{ return 0; }} }}
export function noxidTracingExporterSnapshot() {{
try {{ return __noxidOtlpExporter.snapshot(); }}
catch {{ return Object.freeze({{ capacity: 0, batchSize: 0, queued: 0, inFlight: 0, dropped: 0, closed: true }}); }}
}}
{trace_runtime}"#,
js_escape(&runtime_options.tracing_service_name),
)
} else {
trace_runtime.to_string()
};
// The models section is emitted only when a model is declared, so a
// model-free project's server graph carries none of this code.
let model_runtime = if runtime_options.models.is_empty() {
String::new()
} else {
let declarations = runtime_options
.models
.models
.iter()
.map(|model| {
format!(
" \"{}\": Object.freeze({{ id: \"{}\", name: \"{}\", provider: \"{}\", modelId: \"{}\", baseUrl: Object.freeze({{ kind: \"{}\", value: \"{}\" }}), temperature: {}, maxTokens: {}, retries: {}, secret: \"{}\" }}),",
js_escape(&model.name),
js_escape(model.id.as_str()),
js_escape(&model.name),
model.provider,
js_escape(&model.model_id),
model.base_url.kind(),
js_escape(model.base_url.value()),
model
.temperature
.clone()
.unwrap_or_else(|| "null".to_string()),
model
.max_tokens
.map(|value| value.to_string())
.unwrap_or_else(|| "null".into()),
model.retries,
js_escape(&model.secret),
)
})
.collect::<Vec<_>>()
.join("\n");
format!(
"\n// noxid-runtime:feature-start:models\nconst modelDeclarations = Object.freeze({{\n{declarations}\n}});\nconst modelTypeSchemas = {};\n{MODEL_SCENARIO_RUNTIME}{MODEL_RUNTIME}// noxid-runtime:feature-end:models\n",
noxid_model_ir::type_schema_registry_javascript(&runtime_options.models.type_schemas),
)
};
// WO-31: the agents section, and the two seams that reach it — the request
// router and the queue worker's startup reconciliation. Both collapse to
// nothing when the build declares no engine agent.
let agent_runtime = agents::agents_runtime_javascript(
&runtime_options.agents,
base_path,
noxid_ir::DEFAULT_ENDPOINT_TIMEOUT_MS,
);
let endpoint_runtime = ENDPOINT_RUNTIME.replace(
" /* noxid-server:agent-run-request */",
if agent_runtime.is_empty() {
""
} else {
" const agentRunResponse = await handleAgentRunRequest(request, url, environment, executionContext);\n if (agentRunResponse !== null) return agentRunResponse;"
},
);
let queue_runtime = QUEUE_RUNTIME.replace(
" /* noxid-server:agent-run-reconcile */",
if agent_runtime.is_empty() {
""
} else {
" void __noxidReconcileAgentRuns().catch((cause) => notify(cause));"
},
);
let (pubsub_configuration, pubsub_runtime) = pubsub_options.map_or_else(
|| (String::new(), ""),
|options| {
(
format!(
"const applicationNamespace = \"{}\";\nconst pubSubDriver = \"{}\";\nconst pubSubCoalescingMs = {};\n",
js_escape(application_namespace),
options.driver.as_str(),
options.coalescing_ms,
),
PUBSUB_RUNTIME,
)
},
);
let validator_symbols = if uses_uploads {
"typeValidators, __noxidCreateFileValidationState, __noxidValidateFileChunk, __noxidFinalizeFileValidation, __noxidCreateFileRef"
} else {
"typeValidators"
};
let handler = format!(
"import * as hostModule from \"{}\";\nimport {{ {} }} from \"{}\";\nimport * as middlewareRegistry from \"{}\";\n{}{}{}\n{}{}{}{}const databasePoolSize = {};\n{}const __noxidConfiguredEnvironmentProxies = new WeakSet();\nfunction __noxidConfiguredServerEnvironment(environment) {{\n environment = __noxidServerEnvironment(environment);\n if (__noxidConfiguredEnvironmentProxies.has(environment)) return environment;\n const pool = Object.getOwnPropertyDescriptor(environment, \"dbPool\");\n if (pool?.value === databasePoolSize && pool.enumerable === false && pool.writable === false && pool.configurable === false) return environment;\n const processEnvironment = globalThis.process?.env;\n if (environment !== processEnvironment && Object.isExtensible(environment) && (pool === undefined || pool.configurable)) {{\n Object.defineProperty(environment, \"dbPool\", {{ value: databasePoolSize, enumerable: false, writable: false, configurable: false }});\n return environment;\n }}\n const enriched = new Proxy(environment, {{\n get(target, property, receiver) {{ return property === \"dbPool\" ? databasePoolSize : Reflect.get(target, property, receiver); }},\n set(target, property, value) {{ return property === \"dbPool\" ? false : Reflect.set(target, property, value, target); }},\n defineProperty(target, property, descriptor) {{ return property === \"dbPool\" ? false : Reflect.defineProperty(target, property, descriptor); }},\n deleteProperty(target, property) {{ return property === \"dbPool\" ? false : Reflect.deleteProperty(target, property); }},\n }});\n __noxidConfiguredEnvironmentProxies.add(enriched);\n return enriched;\n}}\nconst tracingExport = \"{}\";\nconst tracingOtlpEndpointSecret = {};\nconst tracingOtlpHeadersSecret = {};\nfunction __noxidTracingEnvironmentValue(environment, name, secret) {{\n try {{\n const configured = __noxidServerEnvironment(environment);\n const value = secret ? configured?.secrets?.[name] : globalThis.process?.env?.[name];\n return typeof value === \"string\" && value.length > 0 ? value : null;\n }} catch {{ return null; }}\n}}\nconst middlewareHandlers = typeof middlewareRegistry === \"undefined\" ? Object.freeze({{}}) : middlewareRegistry.middleware ?? Object.freeze({{}});\nconst globalMiddlewareHandlers = typeof middlewareRegistry === \"undefined\" ? Object.freeze({{}}) : middlewareRegistry.globalMiddlewareHandlers ?? Object.freeze({{}});\nconst globalMiddleware = typeof middlewareRegistry === \"undefined\" ? Object.freeze([]) : middlewareRegistry.globalMiddleware ?? Object.freeze([]);\nconst hostActions = hostModule.actions ?? hostModule.default ?? Object.create(null);\nconst hostEndpoints = hostModule.endpoints ?? hostActions;\nconst hostTasks = hostModule.tasks ?? Object.create(null);\nconst hostQueues = hostModule.queues ?? Object.create(null);\nconst compiledActions = Object.freeze({{\n {}\n}});\nconst compiledEndpoints = Object.freeze({{\n {}\n}});\nconst compiledTasks = Object.freeze({{\n {}\n}});\nconst compiledQueues = Object.freeze({{\n {}\n}});\nconst endpointSchemas = Object.freeze([\n {}\n]);\nconst taskSchemas = Object.freeze([\n {}\n]);\nconst queueSchemas = Object.freeze([\n {}\n]);\nexport const taskSchedules = Object.freeze(taskSchemas.map((task) => Object.freeze({{ name: task.name, schedule: task.schedule }})));\nexport const closeDatabase = __noxidCloseDatabase;\nconst authorize = hostModule.authorize;\nconst invalidateCache = hostModule.invalidateCache;\nconst schemas = Object.freeze({{\n {}\n}});\nconst endpointPrefix = \"{}\";\nconst invalidationEndpoint = \"{}\";\nconst taskPrefix = \"{}\";\nconst queueDrainPath = \"{}\";\nconst applicationBasePath = \"{}\";\nconst openapiDocument = {};\nconst openapiEnabled = {};\nconst mcpEnabled = {};\nconst tracingMode = \"{}\";\n\n{}{}{}{}{}{}{}{}",
js_escape(host_import),
validator_symbols,
js_escape(validator_import),
js_escape(middleware_import),
storage_import_javascript,
startup_import_javascript,
principal_authority_import_javascript,
server_secrets_prelude_javascript(server_secrets),
date_helpers,
equality_function,
noxid_ir::SERVER_MIDDLEWARE_RESULT_JAVASCRIPT,
runtime_options.db_pool,
pubsub_configuration,
runtime_options.tracing_export.as_str(),
runtime_options.otlp_endpoint_secret,
runtime_options.otlp_headers_secret,
compiled_actions,
compiled_endpoints,
compiled_tasks,
compiled_queues,
endpoint_schemas,
task_schemas,
queue_schemas,
schemas,
js_escape(&endpoint),
js_escape(&invalidation_endpoint),
js_escape(&task_endpoint),
js_escape(&queue_drain_endpoint),
js_escape(base_path),
agent_surfaces
.openapi_json
.map(|document| format!("\"{}\"", js_escape(document)))
.unwrap_or_else(|| "null".into()),
agent_surfaces.serve_openapi,
agent_surfaces.mcp,
tracing_mode.as_str(),
PRINCIPAL_RUNTIME,
trace_runtime,
pubsub_runtime,
endpoint_multipart_limits() + &endpoint_runtime,
queue_runtime,
model_runtime,
agent_runtime,
handler_runtime,
);
let handler = format!("{handler}\nexport {{ __noxidConfiguredServerEnvironment }};\n");
let missing_lifecycle_exports =
missing_server_lifecycle_exports(&handler, runtime_options.tracing_export);
if !missing_lifecycle_exports.is_empty() {
return Err(format!(
"internal error: generated server handler is missing compiler-owned lifecycle exports: {}",
missing_lifecycle_exports.join(", ")
));
}
Ok(ServerJavaScriptOutput {
handler,
manifest: program.to_json(),
server_actions: callable
.iter()
.filter(|boundary| boundary.target.as_str() == "server")
.count(),
edge_actions: callable
.iter()
.filter(|boundary| boundary.target.as_str() == "edge")
.count(),
})
}
/// Lower one compiler-owned remote expression to JavaScript.
///
/// Fail-closed: a construct with no deterministic server lowering returns a
/// stable `error[CODE]` instead of a placeholder, so a remote body semantics
/// failed to refuse stops the build rather than shipping `undefined`.
pub fn compiler_body_javascript(expression: &SemanticExpr) -> Result<String, String> {
Ok(match &expression.kind {
SemanticExprKind::Int(value) => value.to_string(),
SemanticExprKind::Float(value) => value.to_string(),
SemanticExprKind::String(value) => format!("\"{}\"", js_escape(value)),
SemanticExprKind::Boolean(value) => value.to_string(),
SemanticExprKind::Array(values) => format!(
"[{}]",
values
.iter()
.map(compiler_body_javascript)
.collect::<Result<Vec<_>, _>>()?
.join(", ")
),
SemanticExprKind::Struct { fields, .. } => format!(
"Object.freeze({{ {} }})",
fields
.iter()
.map(|field| {
Ok(format!(
"\"{}\": {}",
js_escape(&field.name),
compiler_body_javascript(&field.value)?
))
})
.collect::<Result<Vec<_>, String>>()?
.join(", ")
),
SemanticExprKind::FieldAccess { base, name, .. } => {
format!(
"({})[\"{}\"]",
compiler_body_javascript(base)?,
js_escape(name)
)
}
SemanticExprKind::Reference(id) => {
let name = id.as_str().rsplit('.').next().unwrap_or(id.as_str());
if id.as_str().starts_with("local:") {
name.to_string()
} else {
format!("args[\"{}\"]", js_escape(name))
}
}
SemanticExprKind::Variant {
variant, payload, ..
} => {
let tag = variant
.as_str()
.rsplit('.')
.next()
.unwrap_or(variant.as_str());
match payload {
Some(payload) => format!(
"Object.freeze({{ tag: \"{}\", value: {} }})",
js_escape(tag),
compiler_body_javascript(payload)?
),
None => format!("Object.freeze({{ tag: \"{}\" }})", js_escape(tag)),
}
}
SemanticExprKind::Binary { left, op, right } => {
if matches!(op, SemanticBinaryOp::Equal | SemanticBinaryOp::NotEqual)
&& has_language_value_equality(&left.ty)
{
let equality = format!(
"$noxEqual({}, {})",
compiler_body_javascript(left)?,
compiler_body_javascript(right)?
);
return Ok(if matches!(op, SemanticBinaryOp::NotEqual) {
format!("(!{equality})")
} else {
equality
});
}
let operator = match op {
SemanticBinaryOp::Add => "+",
SemanticBinaryOp::Subtract => "-",
SemanticBinaryOp::Multiply => "*",
SemanticBinaryOp::Divide => "/",
SemanticBinaryOp::Equal => "===",
SemanticBinaryOp::NotEqual => "!==",
SemanticBinaryOp::Less => "<",
SemanticBinaryOp::LessEqual => "<=",
SemanticBinaryOp::Greater => ">",
SemanticBinaryOp::GreaterEqual => ">=",
SemanticBinaryOp::And => "&&",
SemanticBinaryOp::Or => "||",
SemanticBinaryOp::Coalesce => "??",
};
format!(
"({} {operator} {})",
compiler_body_javascript(left)?,
compiler_body_javascript(right)?
)
}
SemanticExprKind::Unary { op, operand } => {
format!("({}{})", op.as_str(), compiler_body_javascript(operand)?)
}
SemanticExprKind::StringTemplate(parts) => {
let mut pieces = vec!["\"\"".to_string()];
for part in parts {
pieces.push(match part {
SemanticTemplatePart::Literal(value) => format!("\"{}\"", js_escape(value)),
SemanticTemplatePart::Expression(expression) => {
format!("({})", compiler_body_javascript(expression)?)
}
});
}
format!("({})", pieces.join(" + "))
}
SemanticExprKind::CollectionQuery {
base,
kind,
field,
value,
} => {
let value = value.as_deref().map(compiler_body_javascript).transpose()?;
noxid_ir::collection_query_javascript(
*kind,
&compiler_body_javascript(base)?,
field.as_ref().map(|segment| segment.name.as_str()),
value.as_deref(),
match &base.ty {
noxid_types::Type::Map(key, _) => Some(key.as_ref()),
_ => None,
},
)
}
SemanticExprKind::FunctionCall {
function,
name,
arguments,
} => match emit_distinct_identity_call(function, arguments)? {
Some(javascript) => javascript,
None => match emit_builtin_call(function, arguments)? {
Some(javascript) => javascript,
None => return Err(rejected_remote_call(name, arguments.len())),
},
},
SemanticExprKind::Call {
name, arguments, ..
} => return Err(rejected_remote_call(name, arguments.len())),
})
}
/// One rule, one message: compiler-owned remote bodies lower only the
/// deterministic expression subset, and a call outside it needs a host body.
fn rejected_remote_call(name: &str, arity: usize) -> String {
noxid_ir::emitter_rejection(
"REMOTE_ACTION_CALL_UNSUPPORTED",
format_args!(
"the call `{name}({} argument(s))` has no compiler-owned server lowering; compiler-owned remote bodies emit only literals, typed parameters, field access, constructors, operators, templates, pure builtins, and collection queries — move this call into a host-implemented body keyed by the action or endpoint, or replace it with that subset",
arity
),
)
}
pub fn compiler_statements_javascript(
statements: &[noxid_ir::SemanticStatement],
indent: usize,
) -> Result<String, String> {
noxid_ir::computational_statements_javascript(statements, indent, &compiler_body_javascript)
}
/// A `distinct` type is erased at every boundary: the wire representation is
/// the base type, so `UserId(value)` and `id.base()` are both the identity on
/// the value. The client and SSR emitters already lower them this way; the
/// server emitter must agree exactly, or the same expression would mean one
/// thing in a client action and another in a compiler-owned remote body.
/// `Ok(None)` means "not a distinct call".
fn emit_distinct_identity_call(
function: &noxid_ir::SemanticId,
arguments: &[SemanticExpr],
) -> Result<Option<String>, String> {
if !function.is_distinct_call() {
return Ok(None);
}
match arguments.first() {
Some(argument) => compiler_body_javascript(argument).map(Some),
None => Ok(Some("undefined".into())),
}
}
/// `Ok(None)` means "not a builtin at all"; `Err` means the id claims to be a
/// builtin the shared lowering table cannot emit, which is a compiler bug the
/// build must not paper over with a bare `name(args)` call.
fn emit_builtin_call(
function: &noxid_ir::SemanticId,
arguments: &[SemanticExpr],
) -> Result<Option<String>, String> {
let Some(name) = function.as_str().strip_prefix("fn:@builtin.") else {
return Ok(None);
};
let emitted = arguments
.iter()
.map(compiler_body_javascript)
.collect::<Result<Vec<_>, _>>()?;
noxid_ir::builtin_javascript(name, &emitted)
.map(Some)
.ok_or_else(|| noxid_ir::rejected_builtin_call(name, emitted.len()))
}
fn has_language_value_equality(ty: &noxid_types::Type) -> bool {
use noxid_types::Type;
match ty {
Type::Array(_)
| Type::Map(_, _)
| Type::MapEntry(_, _)
| Type::Result(_, _)
| Type::Named(_) => true,
Type::Optional(inner)
| Type::Static(inner)
| Type::Reactive(inner)
| Type::Binding(inner) => has_language_value_equality(inner),
// WO-44 stage (a) exhaustiveness only: an upload body field is
// already `FileRef` by the time server codegen sees it, so `File`
// has no value identity here. Stage (c) owns the multipart handler.
Type::File
| Type::Int
| Type::String
| Type::Boolean
| Type::Number
| Type::Float
| Type::Date
| Type::Function(_, _)
| Type::Unknown => false,
}
}
fn schema_javascript(boundary: &ExecutionBoundary) -> String {
let parameters = boundary
.parameters
.iter()
.map(|parameter| {
format!(
"Object.freeze({{ name: \"{}\", type: \"{}\", typeId: {} }})",
js_escape(¶meter.name),
js_escape(¶meter.ty),
optional_js_string(parameter.type_id.as_ref().map(|id| id.as_str())),
)
})
.collect::<Vec<_>>()
.join(", ");
let capabilities = boundary
.capabilities
.iter()
.map(|capability| format!("\"{}\"", js_escape(capability)))
.collect::<Vec<_>>()
.join(", ");
let route_scopes = boundary
.route_scopes
.iter()
.map(|scope| {
let middleware = scope
.middleware
.iter()
.filter_map(|id| id.as_str().strip_prefix("middleware:"))
.map(|name| format!("\"{}\"", js_escape(name)))
.collect::<Vec<_>>()
.join(", ");
format!(
"Object.freeze({{ id: \"{}\", pattern: \"{}\", middleware: Object.freeze([{}]) }})",
js_escape(scope.route.as_str()),
js_escape(&scope.pattern),
middleware,
)
})
.collect::<Vec<_>>()
.join(", ");
let invalidates = semantic_ids_javascript(&boundary.invalidates);
format!(
"\"{}\": Object.freeze({{ id: \"{}\", boundary: \"{}\", target: \"{}\", parameters: Object.freeze([{}]), result: Object.freeze({{ id: \"{}\", type: \"{}\", typeId: {} }}), capabilities: Object.freeze([{}]), routeScopes: Object.freeze([{}]), invalidates: Object.freeze([{}]) }})",
js_escape(boundary.action.as_str()),
js_escape(boundary.action.as_str()),
js_escape(boundary.id.as_str()),
boundary.target.as_str(),
parameters,
js_escape(boundary.result.id.as_str()),
js_escape(&boundary.result.ty),
optional_js_string(boundary.result.type_id.as_ref().map(|id| id.as_str())),
capabilities,
route_scopes,
invalidates,
)
}
fn endpoint_schema_javascript(endpoint: &EndpointExecutionBoundary) -> String {
let fields = |section| {
endpoint
.inputs
.iter()
.filter(|input| input.section == section)
.map(|input| {
let upload = input.file.as_ref().map_or_else(
|| "null".to_string(),
|file| {
let types = file
.types
.iter()
.map(|media_type| format!("\"{}\"", js_escape(media_type)))
.collect::<Vec<_>>()
.join(", ");
format!(
"Object.freeze({{ maxSizeBytes: {}, types: Object.freeze([{}]), multiple: {} }})",
file.max_size_bytes, types, file.multiple,
)
},
);
format!(
"Object.freeze({{ name: \"{}\", type: \"{}\", typeId: {}, upload: {} }})",
js_escape(&input.name),
js_escape(&input.ty),
optional_js_string(input.type_id.as_ref().map(|id| id.as_str())),
upload,
)
})
.collect::<Vec<_>>()
.join(", ")
};
let capabilities = endpoint
.capabilities
.iter()
.map(|capability| format!("\"{}\"", js_escape(capability)))
.collect::<Vec<_>>()
.join(", ");
let middleware = endpoint
.middleware
.iter()
.map(|name| format!("\"{}\"", js_escape(name)))
.collect::<Vec<_>>()
.join(", ");
let limit = endpoint.limit.map_or_else(
|| "null".to_string(),
|limit| {
format!(
"Object.freeze({{ requests: {}, window: \"{}\", scope: \"{}\" }})",
limit.requests,
match limit.window {
EndpointLimitWindow::Minute => "minute",
EndpointLimitWindow::Hour => "hour",
},
match limit.scope {
EndpointLimitScope::Session => "session",
EndpointLimitScope::Ip => "ip",
}
)
},
);
let cache = endpoint.cache.as_ref().map_or_else(
|| "null".to_string(),
|cache| {
let tags = cache
.tags
.iter()
.map(|tag| format!("\"{}\"", js_escape(tag)))
.collect::<Vec<_>>()
.join(", ");
format!(
"Object.freeze({{ id: \"{}\", mode: \"{}\", seconds: {}, tags: Object.freeze([{}]) }})",
js_escape(cache.id.as_str()),
cache.mode.as_str(),
cache.seconds,
tags,
)
},
);
let path = endpoint.path.as_deref().unwrap_or("");
let method = endpoint
.method
.map(|method| method.as_str().to_uppercase())
.unwrap_or_default();
let result_validator = format!("validator:endpoint.{}.result", endpoint.name);
let error_validator = (endpoint.kind == EndpointKind::RequestResponse
&& endpoint.result.ty.starts_with("Result<"))
.then(|| format!("validator:endpoint.{}.error", endpoint.name));
format!(
"Object.freeze({{ id: \"{}\", name: \"{}\", version: {}, description: {}, kind: \"{}\", method: \"{}\", path: \"{}\", params: Object.freeze([{}]), query: Object.freeze([{}]), body: Object.freeze([{}]), result: Object.freeze({{ id: \"{}\", type: \"{}\", typeId: {}, validator: \"{}\", errorValidator: {} }}), capabilities: Object.freeze([{}]), timeoutMs: {}, limit: {}, cache: {}, idempotent: {}, middleware: Object.freeze([{}]), invalidates: Object.freeze([{}]) }})",
js_escape(endpoint.id.as_str()),
js_escape(&endpoint.name),
endpoint.version,
endpoint
.description
.as_deref()
.map(|description| format!("\"{}\"", js_escape(description)))
.unwrap_or_else(|| "null".into()),
endpoint.kind.as_str(),
js_escape(&method),
js_escape(path),
fields(EndpointInputSection::Params),
fields(EndpointInputSection::Query),
fields(EndpointInputSection::Body),
js_escape(endpoint.result.id.as_str()),
js_escape(&endpoint.result.ty),
optional_js_string(endpoint.result.type_id.as_ref().map(|id| id.as_str())),
js_escape(&result_validator),
error_validator
.as_deref()
.map(|value| format!("\"{}\"", js_escape(value)))
.unwrap_or_else(|| "null".into()),
capabilities,
endpoint.timeout_ms,
limit,
cache,
endpoint.idempotent,
middleware,
semantic_ids_javascript(&endpoint.invalidates),
)
}
fn task_schema_javascript(task: &TaskExecutionBoundary) -> String {
format!(
"Object.freeze({{ id: \"{}\", name: \"{}\", schedule: \"{}\", hostKey: {} }})",
js_escape(task.id.as_str()),
js_escape(&task.name),
js_escape(&task.schedule),
optional_js_string(task.host_key.as_ref().map(|id| id.as_str())),
)
}
fn queue_schema_javascript(queue: &QueueExecutionBoundary) -> String {
let payload = queue
.payload
.iter()
.map(|field| {
let type_ids = field
.type_ids
.iter()
.map(|(name, id)| {
format!("\"{}\": \"{}\"", js_escape(name), js_escape(id.as_str()))
})
.collect::<Vec<_>>()
.join(", ");
format!(
"Object.freeze({{ name: \"{}\", type: \"{}\", typeId: {}, typeIds: Object.freeze({{{}}}) }})",
js_escape(&field.name),
js_escape(&field.ty),
optional_js_string(field.type_id.as_ref().map(|id| id.as_str())),
type_ids,
)
})
.collect::<Vec<_>>()
.join(", ");
format!(
"Object.freeze({{ id: \"{}\", name: \"{}\", hostKey: {}, payload: Object.freeze([{}]), retry: {}, backoffMs: {}, invalidates: Object.freeze([{}]) }})",
js_escape(queue.id.as_str()),
js_escape(&queue.name),
optional_js_string(queue.host_key.as_ref().map(|id| id.as_str())),
payload,
queue.retry,
queue.backoff_ms,
semantic_ids_javascript(&queue.invalidates),
)
}
fn semantic_ids_javascript(ids: &[SemanticId]) -> String {
ids.iter()
.map(|id| format!("\"{}\"", js_escape(id.as_str())))
.collect::<Vec<_>>()
.join(", ")
}
fn optional_js_string(value: Option<&str>) -> String {
value
.map(|value| format!("\"{}\"", js_escape(value)))
.unwrap_or_else(|| "null".into())
}
const PRINCIPAL_RUNTIME: &str = r##"const __noxidPrincipalAuthority = typeof __installNoxidPrincipalAuthority === "function" ? __installNoxidPrincipalAuthority(__noxidTraceDataAccess) : null;
const __noxidPrincipalValues = new WeakSet();
function __noxidTrustedPrincipal(value) { __noxidPrincipalValues.add(value); return value; }
const __NOXID_SYSTEM_PRINCIPAL = __noxidTrustedPrincipal(Object.freeze({ kind: "system", canonical: "system", scope: null, agent: null }));
function __noxidPrincipalPart(value) {
return encodeURIComponent(value).replace(/[!'()*]/g, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`);
}
function __noxidPrincipal(middlewareContext, environment, agent = null) {
const identity = middlewareContext?.userId ?? middlewareContext?.sessionId ?? middlewareContext?.session?.id ?? environment?.sessionId;
const scope = typeof identity === "string" && identity.length > 0 ? identity : null;
if (agent !== null) {
const acting = scope === null ? "system" : `session:${__noxidPrincipalPart(scope)}`;
return __noxidTrustedPrincipal(Object.freeze({ kind: "agent", canonical: `agent:${__noxidPrincipalPart(agent)}:acting:${acting}`, scope, agent }));
}
if (scope === null) return __NOXID_SYSTEM_PRINCIPAL;
return __noxidTrustedPrincipal(Object.freeze({ kind: "user", canonical: `session:${__noxidPrincipalPart(scope)}`, scope, agent: null }));
}
export function __noxidLiveConnectionPrincipal(middlewareContext, environment) {
return __noxidPrincipal(middlewareContext, environment);
}
function __noxidPrincipalFromCanonical(value) {
if (value === null || value === "system") return __NOXID_SYSTEM_PRINCIPAL;
if (typeof value !== "string") throw Object.assign(new Error("persisted queue principal is invalid"), { code: "QUEUE_PRINCIPAL_DRIFT" });
try {
if (value.startsWith("session:")) {
const scope = decodeURIComponent(value.slice(8));
const principal = __noxidPrincipal({ userId: scope }, null);
if (principal.canonical === value) return principal;
}
const marker = ":acting:session:";
if (value.startsWith("agent:") && value.includes(marker)) {
const split = value.indexOf(marker);
const agent = decodeURIComponent(value.slice(6, split));
const scope = decodeURIComponent(value.slice(split + marker.length));
const principal = __noxidPrincipal({ userId: scope }, null, agent);
if (principal.canonical === value) return principal;
}
if (value.startsWith("agent:") && value.endsWith(":acting:system")) {
const agent = decodeURIComponent(value.slice(6, -14));
const principal = __noxidPrincipal(null, null, agent);
if (principal.canonical === value) return principal;
}
} catch {}
throw Object.assign(new Error("persisted queue principal is invalid"), { code: "QUEUE_PRINCIPAL_DRIFT" });
}
const __noxidRuntimePrincipals = new WeakMap();
function __noxidDataContext(fields, principal) {
const context = Object.freeze({ ...fields, principal });
__noxidRuntimePrincipals.set(context, principal);
__noxidTraceBindPrincipal(context, principal);
return __noxidPrincipalAuthority === null ? context : __noxidPrincipalAuthority.bind(context, principal);
}
const __noxidAgentRequests = new WeakMap();
function __noxidAgentForRequest(request) { return __noxidAgentRequests.get(request) ?? null; }
"##;
const TRACE_RUNTIME: &str = r##"const NOXID_TRACE_SCHEMA = "noxid.trace.v1";
const NOXID_TRACE_ID = /^[A-Za-z0-9_-]{16,128}$/;
const NOXID_TRACEPARENT = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})(.*)$/i;
const NOXID_DIAGNOSTIC_CODE = /^[A-Z][A-Z0-9_]{0,127}$/;
const NOXID_SEMANTIC_ID = /^[A-Za-z0-9][A-Za-z0-9._:@/+-]{0,255}$/;
const NOXID_CAPABILITY = /^[A-Za-z][A-Za-z0-9._:-]{0,127}$/;
const NOXID_ROUTE = /^\/[A-Za-z0-9._~!$&'()*+,;=:@%/\[\]-]{0,1023}$/;
const NOXID_PRINCIPAL = /^(?:system|session:[A-Za-z0-9._~%!*'()-]{1,768})$/;
const NOXID_DATA_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_$]{0,127}$/;
const NOXID_MODEL_NAME = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;
const NOXID_MODEL_ID = /^[A-Za-z0-9][A-Za-z0-9._:@/-]{0,127}$/;
const NOXID_MODEL_PROVIDERS = new Set(["anthropic", "openai", "openai-compatible"]);
const NOXID_AGENT_NAME = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;
const NOXID_AGENT_RUN = /^[A-Za-z0-9_-]{16,128}$/;
const __noxidRequestTraces = new WeakMap();
const __noxidFailureSpans = new WeakMap();
let __noxidTraceCounter = 0;
function __noxidGeneratedTraceId() {
try {
const value = globalThis.crypto?.randomUUID?.();
if (typeof value === "string" && NOXID_TRACE_ID.test(value)) return value;
} catch {}
__noxidTraceCounter = (__noxidTraceCounter + 1) % Number.MAX_SAFE_INTEGER;
return `noxid_${Date.now().toString(36)}_${__noxidTraceCounter.toString(36).padStart(10, "0")}`;
}
function __noxidRequestTraceContext(request) {
let traceparent = null;
let inbound = null;
try {
traceparent = request.headers.get("traceparent");
inbound = request.headers.get("x-noxid-trace");
} catch {}
const parsed = typeof traceparent === "string" ? NOXID_TRACEPARENT.exec(traceparent) : null;
const futureSuffixValid = parsed !== null && (parsed[1].toLowerCase() === "00" ? parsed[5] === "" : parsed[5] === "" || /^-(?:[0-9a-f]{2})+$/i.test(parsed[5]));
if (parsed !== null && parsed[1].toLowerCase() !== "ff" && futureSuffixValid && !/^0+$/.test(parsed[2]) && !/^0+$/.test(parsed[3])) {
return { id: parsed[2].toLowerCase(), parentSpanId: parsed[3].toLowerCase(), traceFlags: Number.parseInt(parsed[4], 16) };
}
return { id: typeof inbound === "string" && NOXID_TRACE_ID.test(inbound) ? inbound : __noxidGeneratedTraceId() };
}
function __noxidTraceContext(parent = null) {
// One sequence counter per trace, and one deferred `request.start` per trace.
// A nested scope carries a reference to the trace's shared cell instead of
// instantiating its own, so `sequence` starts at one per trace and follows
// emission order across every nested scope, and the agent door's deferred
// start is still the trace's first record even when the first thing the trace
// emits comes from a subrequest scope. docs/language-reference.md states the
// contract; evaluator ruling 2026-09-03.
const inherited = parent !== null && typeof parent === "object" ? parent.shared : null;
const shared = inherited !== null && typeof inherited === "object" ? inherited : { sequence: 0, pendingStartMethod: null, root: null, agentSemanticId: null, actingPrincipal: null };
const trace = { id: typeof parent === "string" ? parent : parent?.id ?? __noxidGeneratedTraceId(), shared };
if (shared.root === null) shared.root = trace;
if (typeof parent?.parentSpanId === "string") trace.parentSpanId = parent.parentSpanId;
if (Number.isInteger(parent?.traceFlags)) trace.traceFlags = parent.traceFlags;
return trace;
}
function __noxidTraceNow() {
try {
const value = globalThis.performance?.now?.();
if (Number.isFinite(value)) return value;
} catch {}
return Date.now();
}
function __noxidTraceNewSpanId() {
/* noxid-server:trace-span-id */
return null;
}
function __noxidTraceDuration(startedAt) {
return Math.max(0, __noxidTraceNow() - startedAt);
}
function __noxidTraceBeginSpan(trace) {
if (trace === null) return null;
return Object.freeze({
trace,
startedAt: __noxidTraceNow(),
spanId: __noxidTraceNewSpanId(),
parentSpanId: trace.requestSpanId ?? trace.parentSpanId,
});
}
function __noxidTraceFinishSpan(span, event, fields = null) {
if (span === null) return;
__noxidTraceEmit(span.trace, event, {
...(fields ?? Object.create(null)),
durationMs: __noxidTraceDuration(span.startedAt),
spanId: span.spanId,
parentSpanId: span.parentSpanId,
});
}
function __noxidTraceEmit(trace, event, fields = null) {
let developmentCapture = false;
/* noxid-server:development-trace-context */
const loggable = tracingMode !== "off" && (tracingMode !== "requests" || event === "request.start" || event === "request.end");
if (trace === null && developmentCapture) trace = __noxidTraceContext();
if (trace === null || !loggable && !developmentCapture) return;
if (event !== "request.start" && typeof trace.shared.pendingStartMethod === "string") {
const method = trace.shared.pendingStartMethod;
trace.shared.pendingStartMethod = null;
// The start belongs to the request root, not to whichever nested scope
// happened to emit first.
__noxidTraceEmit(trace.shared.root ?? trace, "request.start", { method });
}
const record = Object.create(null);
record.schema = NOXID_TRACE_SCHEMA;
record.traceId = trace.id;
record.sequence = ++trace.shared.sequence;
record.event = event;
record.timestampMs = Date.now();
const tracedAgentSemanticId = typeof trace.agentSemanticId === "string" ? trace.agentSemanticId : trace.shared.agentSemanticId;
const tracedActingPrincipal = typeof trace.actingPrincipal === "string" ? trace.actingPrincipal : trace.shared.actingPrincipal;
if (typeof tracedAgentSemanticId === "string" && NOXID_SEMANTIC_ID.test(tracedAgentSemanticId)) record.agentSemanticId = tracedAgentSemanticId;
if (typeof tracedActingPrincipal === "string" && NOXID_PRINCIPAL.test(tracedActingPrincipal)) record.actingPrincipal = tracedActingPrincipal;
if (fields !== null) {
if (typeof fields.semanticId === "string" && NOXID_SEMANTIC_ID.test(fields.semanticId)) record.semanticId = fields.semanticId;
if (typeof fields.code === "string" && NOXID_DIAGNOSTIC_CODE.test(fields.code)) record.code = fields.code;
if (typeof fields.capability === "string" && NOXID_CAPABILITY.test(fields.capability)) record.capability = fields.capability;
if (typeof fields.route === "string" && NOXID_ROUTE.test(fields.route)) {
record.route = fields.route;
trace.route = fields.route;
} else if (typeof trace.route === "string") record.route = trace.route;
if (Number.isInteger(fields.status) && fields.status >= 100 && fields.status <= 599) record.status = fields.status;
if (typeof fields.method === "string" && /^[A-Z]{1,16}$/.test(fields.method)) record.method = fields.method;
if (typeof fields.state === "string" && /^[A-Za-z][A-Za-z-]{0,31}$/.test(fields.state)) record.state = fields.state;
if (typeof fields.transition === "string" && /^[A-Za-z][A-Za-z]{0,31}$/.test(fields.transition)) record.transition = fields.transition;
if (typeof fields.jobId === "string" && /^[A-Za-z0-9_-]{1,128}$/.test(fields.jobId)) record.jobId = fields.jobId;
if (Number.isSafeInteger(fields.attempts) && fields.attempts >= 0) record.attempts = fields.attempts;
if (Number.isFinite(fields.durationMs) && fields.durationMs >= 0) record.durationMs = fields.durationMs;
if (typeof fields.spanId === "string" && /^[0-9a-f]{16}$/.test(fields.spanId) && !/^0+$/.test(fields.spanId)) record.spanId = fields.spanId;
if (typeof fields.parentSpanId === "string" && /^[0-9a-f]{16}$/.test(fields.parentSpanId) && !/^0+$/.test(fields.parentSpanId)) record.parentSpanId = fields.parentSpanId;
if (typeof fields.spanName === "string" && /^[A-Za-z][A-Za-z0-9._:-]{0,127}$/.test(fields.spanName)) record.spanName = fields.spanName;
if (typeof fields.driver === "string" && new Set(["memory", "postgres", "redis"]).has(fields.driver)) record.driver = fields.driver;
if (typeof fields.kind === "string" && new Set(["invalidation", "presence"]).has(fields.kind)) record.kind = fields.kind;
if (typeof fields.agentSemanticId === "string" && NOXID_SEMANTIC_ID.test(fields.agentSemanticId)) record.agentSemanticId = fields.agentSemanticId;
if (typeof fields.actingPrincipal === "string" && NOXID_PRINCIPAL.test(fields.actingPrincipal)) record.actingPrincipal = fields.actingPrincipal;
if (typeof fields.dataTable === "string" && NOXID_DATA_IDENTIFIER.test(fields.dataTable)) record.dataTable = fields.dataTable;
if (typeof fields.scopeColumn === "string" && NOXID_DATA_IDENTIFIER.test(fields.scopeColumn)) record.scopeColumn = fields.scopeColumn;
// WO-30 model spans. Identity, tokens and retries only: a prompt or a
// completion is never presented to this serializer, so it cannot leak.
if (typeof fields.model === "string" && NOXID_MODEL_NAME.test(fields.model)) record.model = fields.model;
if (typeof fields.modelProvider === "string" && NOXID_MODEL_PROVIDERS.has(fields.modelProvider)) record.modelProvider = fields.modelProvider;
if (typeof fields.modelId === "string" && NOXID_MODEL_ID.test(fields.modelId)) record.modelId = fields.modelId;
if (Number.isSafeInteger(fields.tokensInput) && fields.tokensInput >= 0) record.tokensInput = fields.tokensInput;
if (Number.isSafeInteger(fields.tokensOutput) && fields.tokensOutput >= 0) record.tokensOutput = fields.tokensOutput;
if (Number.isSafeInteger(fields.modelRetries) && fields.modelRetries >= 0 && fields.modelRetries <= 5) record.modelRetries = fields.modelRetries;
// WO-31 agent spans. `agent` is the declared agent name (`noxid.agent`),
// `agentRun` the run id (`noxid.agent.run`), `agentTurn` the zero-based
// turn index (`noxid.agent.turn`), and `toolEndpoint` the dispatched
// endpoint's semantic id (`noxid.tool.endpoint`). Token counts reuse the
// model fields above. No prompt, instruction, argument, or tool-result
// content is ever presented to this serializer.
if (typeof fields.agent === "string" && NOXID_AGENT_NAME.test(fields.agent)) record.agent = fields.agent;
if (typeof fields.agentRun === "string" && NOXID_AGENT_RUN.test(fields.agentRun)) record.agentRun = fields.agentRun;
if (Number.isSafeInteger(fields.agentTurn) && fields.agentTurn >= 0) record.agentTurn = fields.agentTurn;
if (typeof fields.toolEndpoint === "string" && NOXID_SEMANTIC_ID.test(fields.toolEndpoint)) record.toolEndpoint = fields.toolEndpoint;
}
if (record.parentSpanId === undefined && event !== "request.start" && event !== "request.end" && typeof trace.requestSpanId === "string") {
record.parentSpanId = trace.requestSpanId;
}
/* noxid-server:trace-export */
/* noxid-server:development-trace-capture */
}
function __noxidActingPrincipal(principal) {
return principal?.scope === null ? "system" : typeof principal?.scope === "string" ? `session:${__noxidPrincipalPart(principal.scope)}` : null;
}
function __noxidTraceBindPrincipal(context, principal) {
if (principal?.kind !== "agent" || typeof principal.agent !== "string") return;
const trace = __noxidTraceForRequest(context?.request);
if (trace === null) return;
trace.agentSemanticId = principal.agent;
trace.actingPrincipal = __noxidActingPrincipal(principal);
// The acting identity belongs to the trace, not to the scope that happened to
// learn it. An agent door binds inside its endpoint subrequest, so without
// this the request's own start and end records would lose the identity the
// door was dispatched under (evaluator ruling 2026-09-03).
trace.shared.agentSemanticId = trace.agentSemanticId;
trace.shared.actingPrincipal = trace.actingPrincipal;
}
function __noxidTraceDataAccess(context, fields) {
if (tracingMode !== "full") return;
const principal = context?.principal;
const requestTrace = __noxidTraceForRequest(context?.request);
const trace = requestTrace ?? __noxidTraceContext(
typeof context?.traceId === "string" && NOXID_TRACE_ID.test(context.traceId) ? context.traceId : null,
);
if (principal?.kind === "agent" && typeof principal.agent === "string") {
trace.agentSemanticId = principal.agent;
trace.actingPrincipal = __noxidActingPrincipal(principal);
}
__noxidTraceEmit(trace, "data.access", {
semanticId: context?.semanticId,
agentSemanticId: principal?.agent,
actingPrincipal: principal?.kind === "agent" ? __noxidActingPrincipal(principal) : null,
dataTable: fields?.table,
scopeColumn: fields?.principalColumn,
});
}
function __noxidTraceForRequest(request) {
return request !== null && typeof request === "object" ? __noxidRequestTraces.get(request) ?? null : null;
}
function __noxidTraceRoute(request, route) {
const trace = __noxidTraceForRequest(request);
if (trace !== null && typeof route === "string" && NOXID_ROUTE.test(route)) trace.route = route;
}
function __noxidTraceIdForRequest(request) {
return __noxidTraceForRequest(request)?.id ?? null;
}
export function noxidTraceId(request) {
return __noxidTraceIdForRequest(request);
}
export function inheritNoxidRequestTrace(parent, child, semanticId = null) {
const parentTrace = __noxidTraceForRequest(parent);
if (parentTrace === null || child === null || typeof child !== "object") return;
const trace = __noxidTraceContext({
id: parentTrace.id,
// The subrequest is a nested scope of the same trace, so it shares the
// parent's sequence counter and deferred start rather than starting its own.
shared: parentTrace.shared,
parentSpanId: parentTrace.requestSpanId ?? parentTrace.parentSpanId,
traceFlags: parentTrace.traceFlags,
});
trace.inheritedRequest = true;
if (typeof semanticId === "string" && NOXID_SEMANTIC_ID.test(semanticId)) trace.subrequestSemanticId = semanticId;
if (typeof parentTrace.agentSemanticId === "string") trace.agentSemanticId = parentTrace.agentSemanticId;
if (typeof parentTrace.actingPrincipal === "string") trace.actingPrincipal = parentTrace.actingPrincipal;
__noxidRequestTraces.set(child, trace);
}
function __noxidTraceBeginSemantic(request) {
let trace = __noxidTraceForRequest(request);
if (trace === null && tracingMode === "full") trace = __noxidTraceContext();
return __noxidTraceBeginSpan(trace);
}
function __noxidTraceFinishSemantic(span, event, semanticId, fields = null) {
__noxidTraceFinishSpan(span, event, fields === null ? { semanticId } : { semanticId, ...fields });
}
function __noxidTraceSemantic(request, event, semanticId, fields = null) {
const span = __noxidTraceBeginSemantic(request);
__noxidTraceFinishSemantic(span, event, semanticId, fields);
return span?.trace?.id ?? null;
}
export function traceNoxidSemantic(request, event, semanticId) {
if (!new Set(["middleware", "endpoint", "action", "task"]).has(event)) return null;
return __noxidTraceSemantic(request, event, semanticId);
}
export function traceNoxidFailure(response, code, semanticId) {
return __noxidTraceFailure(response, code, semanticId);
}
function __noxidTraceFailure(response, code, semanticId, capability = null) {
if (response !== null && typeof response === "object") {
__noxidFailureSpans.set(response, { code, semanticId, capability, emitted: false });
}
return response;
}
function __noxidTraceCopyFailure(source, target) {
const failure = __noxidFailureSpans.get(source);
if (failure !== undefined && target !== null && typeof target === "object") __noxidFailureSpans.set(target, failure);
return target;
}
function __noxidTraceResponseFailure(request, response) {
const failure = __noxidFailureSpans.get(response);
if (failure === undefined || failure.emitted) return;
failure.emitted = true;
const capability = (failure.code.includes("CAPABILITY") && failure.code.endsWith("_DENIED")) || failure.code === "CACHE_INVALIDATION_DENIED";
__noxidTraceEmit(__noxidTraceForRequest(request), capability ? "capability.denied" : "validation.refused", failure);
}
function __noxidTraceFinishRequest(trace, event, status) {
__noxidTraceEmit(trace, event, {
status,
method: trace.requestMethod,
semanticId: trace.subrequestSemanticId,
durationMs: __noxidTraceDuration(trace.requestStartedAt),
spanId: trace.requestSpanId,
parentSpanId: trace.requestParentSpanId,
spanName: event === "request.end" ? "request" : event,
});
}
function __noxidTraceStreamingResponse(request, trace, response, event = "request.end") {
const reader = response.body.getReader();
let finished = false;
const finish = (status) => {
if (finished) return;
finished = true;
__noxidTraceFinishRequest(trace, event, status);
if (request !== null && typeof request === "object") __noxidRequestTraces.delete(request);
};
const body = new ReadableStream({
async pull(controller) {
try {
const chunk = await reader.read();
if (chunk.done) {
finish(response.status);
controller.close();
} else {
controller.enqueue(chunk.value);
}
} catch (cause) {
finish(500);
controller.error(cause);
}
},
async cancel(reason) {
try { await reader.cancel(reason); }
finally { finish(response.status); }
},
});
return __noxidTraceCopyFailure(response, new Response(body, { status: response.status, statusText: response.statusText, headers: response.headers }));
}
export async function withNoxidRequestTrace(request, operation) {
const inherited = __noxidTraceForRequest(request);
if (inherited !== null) {
if (inherited.requestActive === true || inherited.inheritedRequest !== true) {
const response = await operation(inherited);
__noxidTraceResponseFailure(request, response);
return response;
}
inherited.requestActive = true;
inherited.requestStartedAt = __noxidTraceNow();
inherited.requestSpanId = __noxidTraceNewSpanId();
inherited.requestParentSpanId = inherited.parentSpanId;
try { inherited.requestMethod = request.method.toUpperCase(); } catch {}
const event = typeof inherited.subrequestSemanticId === "string" && inherited.subrequestSemanticId.startsWith("route-loader:") ? "loader" : "subrequest";
let streaming = false;
try {
const response = await operation(inherited);
__noxidTraceResponseFailure(request, response);
streaming = response?.body !== null && (response?.headers?.get("x-noxid-ssr-stream") === "1" || response?.headers?.get("content-type")?.toLowerCase().startsWith("text/event-stream"));
if (streaming) return __noxidTraceStreamingResponse(request, inherited, response, event);
__noxidTraceFinishRequest(inherited, event, response?.status);
return response;
} catch (cause) {
__noxidTraceFinishRequest(inherited, event, 500);
throw cause;
} finally {
if (!streaming && request !== null && typeof request === "object") __noxidRequestTraces.delete(request);
}
}
if (tracingMode === "off") return operation(null);
const trace = __noxidTraceContext(__noxidRequestTraceContext(request));
trace.requestActive = true;
trace.requestStartedAt = __noxidTraceNow();
trace.requestSpanId = __noxidTraceNewSpanId();
trace.requestParentSpanId = trace.parentSpanId;
if (request !== null && typeof request === "object") __noxidRequestTraces.set(request, trace);
let method = null;
let deferredAgentStart = false;
let streaming = false;
try { method = request.method.toUpperCase(); } catch {}
trace.requestMethod = method;
try { deferredAgentStart = new URL(request.url).pathname.endsWith("/_noxid/mcp"); } catch {}
if (deferredAgentStart) trace.shared.pendingStartMethod = method;
else __noxidTraceEmit(trace, "request.start", { method });
try {
const response = await operation(trace);
__noxidTraceResponseFailure(request, response);
streaming = response?.body !== null && (response?.headers?.get("x-noxid-ssr-stream") === "1" || response?.headers?.get("content-type")?.toLowerCase().startsWith("text/event-stream"));
if (streaming) return __noxidTraceStreamingResponse(request, trace, response);
__noxidTraceFinishRequest(trace, "request.end", response?.status);
return response;
} catch (cause) {
__noxidTraceFinishRequest(trace, "request.end", 500);
throw cause;
} finally {
// Streaming responses retain request ownership until their body closes or
// is cancelled; ordinary responses release it here.
if (!streaming && request !== null && typeof request === "object") __noxidRequestTraces.delete(request);
}
}
"##;
const PUBSUB_RUNTIME: &str = r##"
const NOXID_PUBSUB_SCHEMA = "noxid.pubsub.v1";
const NOXID_PUBSUB_KINDS = new Set(["invalidation", "presence"]);
const NOXID_PUBSUB_CHANNEL = `noxid_pubsub_v1_${applicationNamespace}`;
const NOXID_PUBSUB_MAX_BYTES = 7_000;
const __noxidMemoryPubSubKey = Symbol.for("noxid.pubsub.memory.v1");
function __noxidPubSubNow() {
try { return performance.now(); } catch { return Date.now(); }
}
function __noxidPubSubDuration(trace, event, startedAt, envelope, state) {
__noxidTraceEmit(trace, event, {
semanticId: envelope.semanticId,
driver: pubSubDriver,
kind: envelope.kind,
state,
durationMs: Math.max(0, __noxidPubSubNow() - startedAt),
});
}
function __noxidPubSubFailure(code, message, cause) {
return Object.assign(new Error(message, cause === undefined ? undefined : { cause }), { code });
}
function __noxidPubSubPrincipal(principal) {
if (principal === null || typeof principal !== "object" || !__noxidPrincipalValues.has(principal)) {
throw __noxidPubSubFailure("PUBSUB_PRINCIPAL_INVALID", "live events require a compiler-owned canonical principal");
}
let canonical;
try { canonical = principal.canonical; } catch {}
return __noxidPubSubCanonical(canonical);
}
function __noxidPubSubCanonical(canonical) {
if (typeof canonical !== "string" || canonical.length === 0 || canonical.length > 1024) {
throw __noxidPubSubFailure("PUBSUB_PRINCIPAL_INVALID", "live events require the stable canonical principal serialization from the request context");
}
return canonical;
}
function __noxidPubSubIdentity(kind, semanticId, principal) {
if (!NOXID_PUBSUB_KINDS.has(kind)) throw __noxidPubSubFailure("PUBSUB_KIND_INVALID", "compiler-owned pub/sub kind is invalid");
if (typeof semanticId !== "string" || !NOXID_SEMANTIC_ID.test(semanticId)) throw __noxidPubSubFailure("PUBSUB_SEMANTIC_ID_INVALID", "compiler-owned pub/sub semantic id is invalid");
return Object.freeze({ kind, semanticId, principal: __noxidPubSubPrincipal(principal) });
}
export function __noxidPubSubTopic(kind, semanticId, principal) {
const identity = __noxidPubSubIdentity(kind, semanticId, principal);
return __noxidPubSubTopicFromCanonical(identity.kind, identity.semanticId, identity.principal);
}
function __noxidPubSubTopicFromCanonical(kind, semanticId, principal) {
__noxidPubSubCanonical(principal);
return `noxid:live:v1:${applicationNamespace}:${kind}:${encodeURIComponent(semanticId)}:${encodeURIComponent(principal)}`;
}
function __noxidPubSubEventId(value) {
if (value === undefined) {
try { value = globalThis.crypto?.randomUUID?.().replaceAll("-", "_"); } catch {}
}
if (typeof value !== "string" || !/^[A-Za-z0-9_-]{1,128}$/.test(value)) {
throw __noxidPubSubFailure("PUBSUB_EVENT_ID_INVALID", "compiler-owned pub/sub event id must be a bounded stable identifier");
}
return value;
}
export function __noxidPubSubEvent(kind, semanticId, principal, body = null, id = undefined) {
const identity = __noxidPubSubIdentity(kind, semanticId, principal);
return __noxidPubSubEventFromCanonical(identity.kind, identity.semanticId, identity.principal, body, id);
}
function __noxidPubSubEventFromCanonical(kind, semanticId, principal, body = null, id = undefined) {
if (!NOXID_PUBSUB_KINDS.has(kind) || typeof semanticId !== "string" || !NOXID_SEMANTIC_ID.test(semanticId)) {
throw __noxidPubSubFailure("PUBSUB_EVENT_DRIFT", "compiler-owned pub/sub event identity is invalid");
}
principal = __noxidPubSubCanonical(principal);
if (kind === "invalidation" && body !== null) {
throw __noxidPubSubFailure("PUBSUB_INVALIDATION_PAYLOAD", "live invalidations carry no payload; publish only the resource identity and refetch through its validated path");
}
const event = Object.freeze({
schema: NOXID_PUBSUB_SCHEMA,
application: applicationNamespace,
id: __noxidPubSubEventId(id),
kind,
semanticId,
principal,
body,
});
let encoded;
try { encoded = JSON.stringify(event); }
catch (cause) { throw __noxidPubSubFailure("PUBSUB_EVENT_INVALID", "compiler-owned pub/sub event must be serializable typed data", cause); }
if (new TextEncoder().encode(encoded).byteLength > NOXID_PUBSUB_MAX_BYTES) throw __noxidPubSubFailure("PUBSUB_EVENT_TOO_LARGE", "compiler-owned pub/sub event exceeds the 7000-byte cross-driver bound");
return event;
}
function __noxidPubSubDecode(raw) {
let value;
try { value = typeof raw === "string" ? JSON.parse(raw) : raw; }
catch (cause) { throw __noxidPubSubFailure("PUBSUB_EVENT_DRIFT", "pub/sub delivered malformed JSON", cause); }
if (value === null || typeof value !== "object" || Array.isArray(value) || value.schema !== NOXID_PUBSUB_SCHEMA || value.application !== applicationNamespace) {
throw __noxidPubSubFailure("PUBSUB_EVENT_DRIFT", "pub/sub delivered an unsupported event envelope");
}
if (!NOXID_PUBSUB_KINDS.has(value.kind) || typeof value.semanticId !== "string" || !NOXID_SEMANTIC_ID.test(value.semanticId)) {
throw __noxidPubSubFailure("PUBSUB_EVENT_DRIFT", "pub/sub delivered an invalid typed event identity");
}
const identity = Object.freeze({ kind: value.kind, semanticId: value.semanticId, principal: __noxidPubSubCanonical(value.principal) });
if (value.kind === "invalidation" && value.body !== null) throw __noxidPubSubFailure("PUBSUB_EVENT_DRIFT", "pub/sub delivered an invalidation payload");
return Object.freeze({ schema: NOXID_PUBSUB_SCHEMA, application: applicationNamespace, id: __noxidPubSubEventId(value.id), ...identity, body: value.body ?? null });
}
function __noxidMemoryPubSub() {
let registry = globalThis[__noxidMemoryPubSubKey];
if (!(registry instanceof Map)) {
registry = new Map();
Object.defineProperty(globalThis, __noxidMemoryPubSubKey, { value: registry, configurable: true });
}
return Object.freeze({
async publish(topic, encoded) {
for (const receive of [...(registry.get(topic) ?? [])]) receive(encoded);
},
async subscribe(topic, receive) {
let subscribers = registry.get(topic);
if (subscribers === undefined) registry.set(topic, subscribers = new Set());
subscribers.add(receive);
return async () => {
subscribers.delete(receive);
if (subscribers.size === 0) registry.delete(topic);
};
},
});
}
let __noxidPubSubPostgresPromise;
async function __noxidPostgresPubSub() {
if (__noxidPubSubPostgresPromise !== undefined) return __noxidPubSubPostgresPromise;
__noxidPubSubPostgresPromise = (async () => {
const url = queueDatabaseUrl();
if (url === null) throw __noxidPubSubFailure("PUBSUB_POSTGRES_URL_REQUIRED", "DATABASE_URL is required for the Postgres live publisher");
let postgres;
try { postgres = (await import("postgres")).default; }
catch { throw __noxidPubSubFailure("PUBSUB_POSTGRES_DRIVER_MISSING", "the admitted Postgres driver is unavailable for live publishing"); }
const sql = postgres(url, { max: Math.max(1, Math.min(databasePoolSize, 2)) });
const subscribers = new Map();
let listening;
const ensureListening = async () => {
if (listening === undefined) {
listening = Promise.resolve(sql.listen(NOXID_PUBSUB_CHANNEL, (encoded) => {
let decoded;
try { decoded = __noxidPubSubDecode(encoded); } catch { return; }
const topic = __noxidPubSubTopicFromCanonical(decoded.kind, decoded.semanticId, decoded.principal);
for (const receive of [...(subscribers.get(topic) ?? [])]) receive(encoded);
}));
}
await listening;
};
const stopListeningIfIdle = async () => {
if (subscribers.size !== 0 || listening === undefined) return;
const active = listening;
listening = undefined;
const listener = await active;
if (typeof listener === "function") await listener();
else if (typeof listener?.unlisten === "function") await listener.unlisten();
};
return Object.freeze({
async publish(_topic, encoded) {
await sql.notify(NOXID_PUBSUB_CHANNEL, encoded);
},
async subscribe(topic, receive) {
await ensureListening();
let listeners = subscribers.get(topic);
if (listeners === undefined) subscribers.set(topic, listeners = new Set());
listeners.add(receive);
return async () => {
listeners.delete(receive);
if (listeners.size === 0) subscribers.delete(topic);
await stopListeningIfIdle();
};
},
});
})();
try { return await __noxidPubSubPostgresPromise; }
catch (cause) { __noxidPubSubPostgresPromise = undefined; throw cause; }
}
function __noxidRedisPubSub() {
if (typeof __noxidRedisPubSubPublish !== "function" || typeof __noxidRedisPubSubSubscribe !== "function") {
throw __noxidPubSubFailure("PUBSUB_REDIS_DRIVER_MISSING", "the admitted WO-39 RESP pub/sub extension is unavailable");
}
return Object.freeze({
publish: (topic, encoded) => __noxidRedisPubSubPublish(topic, encoded),
subscribe: (topic, receive) => __noxidRedisPubSubSubscribe(topic, receive),
});
}
let __noxidPubSubAdapterPromise;
async function __noxidPubSubAdapter() {
if (__noxidPubSubAdapterPromise === undefined) {
__noxidPubSubAdapterPromise = Promise.resolve(
pubSubDriver === "memory" ? __noxidMemoryPubSub()
: pubSubDriver === "postgres" ? __noxidPostgresPubSub()
: pubSubDriver === "redis" ? __noxidRedisPubSub()
: Promise.reject(__noxidPubSubFailure("PUBSUB_DRIVER_INVALID", "compiler emitted an unsupported pub/sub driver")),
);
}
return __noxidPubSubAdapterPromise;
}
export async function __noxidPubSubPublish(event) {
const envelope = __noxidPubSubDecode(event);
const topic = __noxidPubSubTopicFromCanonical(envelope.kind, envelope.semanticId, envelope.principal);
const encoded = JSON.stringify(envelope);
const trace = tracingMode === "full" ? __noxidTraceContext() : null;
const startedAt = __noxidPubSubNow();
try {
await (await __noxidPubSubAdapter()).publish(topic, encoded);
__noxidPubSubDuration(trace, "pubsub.publish", startedAt, envelope, "delivered");
} catch (cause) {
__noxidPubSubDuration(trace, "pubsub.publish", startedAt, envelope, "retry");
throw cause;
}
}
export async function __noxidPubSubSubscribe(kind, semanticId, principal, deliver, options = Object.create(null)) {
if (typeof deliver !== "function") throw __noxidPubSubFailure("PUBSUB_SUBSCRIBER_INVALID", "pub/sub subscriber must be a compiler-owned delivery function");
const identity = __noxidPubSubIdentity(kind, semanticId, principal);
const topic = __noxidPubSubTopic(kind, semanticId, principal);
const schedule = typeof options.schedule === "function" ? options.schedule : globalThis.setTimeout;
const cancel = typeof options.cancel === "function" ? options.cancel : globalThis.clearTimeout;
const coalesceKey = typeof options.coalesceKey === "function"
? options.coalesceKey
: (event) => event.kind === "invalidation" ? `${event.kind}:${event.semanticId}:${event.principal}` : event.id;
const pending = new Map();
let stopped = false;
const run = async (key) => {
const entry = pending.get(key);
if (entry === undefined || stopped) return;
entry.timer = null;
const version = entry.version;
const trace = tracingMode === "full" ? __noxidTraceContext() : null;
const startedAt = __noxidPubSubNow();
try {
await deliver(entry.event);
__noxidPubSubDuration(trace, "pubsub.deliver", startedAt, entry.event, "delivered");
if (entry.version === version) pending.delete(key);
else entry.timer = schedule(() => run(key), pubSubCoalescingMs);
} catch {
__noxidPubSubDuration(trace, "pubsub.deliver", startedAt, entry.event, "retry");
if (!stopped) entry.timer = schedule(() => run(key), pubSubCoalescingMs);
}
};
const receive = (raw) => {
if (stopped) return;
let event;
try { event = __noxidPubSubDecode(raw); } catch { return; }
if (event.kind !== identity.kind || event.semanticId !== identity.semanticId || event.principal !== identity.principal) return;
let key;
try { key = coalesceKey(event); } catch { return; }
if (typeof key !== "string" || key.length === 0 || key.length > 2048) return;
const entry = pending.get(key);
if (entry === undefined) {
const created = { event, version: 1, timer: null };
created.timer = schedule(() => run(key), pubSubCoalescingMs);
pending.set(key, created);
} else {
entry.event = event;
entry.version += 1;
}
};
const unsubscribe = await (await __noxidPubSubAdapter()).subscribe(topic, receive);
return async () => {
if (stopped) return;
stopped = true;
for (const entry of pending.values()) if (entry.timer !== null) cancel(entry.timer);
pending.clear();
await unsubscribe();
};
}
"##;
/// The multipart parser's ceilings, emitted from `noxid_ir` rather than
/// written twice. The security manifest publishes these same constants, so a
/// change to the parser's bound changes the audit artefact in the same
/// commit — there is no way to move one without the other.
fn endpoint_multipart_limits() -> String {
format!(
"const ENDPOINT_MULTIPART_HEADER_MAX_BYTES = {};\nconst ENDPOINT_MULTIPART_SCALAR_MAX_BYTES = {};\nconst ENDPOINT_MULTIPART_MAX_PARTS = {};\nconst ENDPOINT_UPLOAD_NAME_MAX_BYTES = {};\n",
noxid_ir::MULTIPART_PART_HEADER_MAX_BYTES,
noxid_ir::MULTIPART_SCALAR_MAX_BYTES,
noxid_ir::MULTIPART_MAX_PARTS,
noxid_ir::UPLOAD_FILENAME_MAX_BYTES,
)
}
const ENDPOINT_RUNTIME: &str = r##"const endpointRateStorage = typeof __noxidStorage === "function" ? __noxidStorage("noxid:endpoint-rate") : null;
const endpointIdempotencyStorage = typeof __noxidStorage === "function" ? __noxidStorage("noxid:endpoint-idempotency") : null;
const endpointRateLocks = new Map();
const endpointIdempotencyLocks = new Map();
const endpointIdempotencyInFlight = new Map();
const endpointStreamHistories = new Map();
const ENDPOINT_RATE_BUCKET_MAX_ENTRIES = 10_000;
const ENDPOINT_IDEMPOTENCY_MAX_ENTRIES = 1024;
const ENDPOINT_IDEMPOTENCY_TTL_MS = 86_400_000;
const ENDPOINT_STREAM_HEARTBEAT_MS = 15_000;
const ENDPOINT_STREAM_MAX_HISTORIES = 128;
const ENDPOINT_STREAM_MAX_EVENTS = 256;
const ENDPOINT_STREAM_MAX_EVENT_BYTES = 262_144;
const ENDPOINT_STREAM_MAX_HISTORY_BYTES = 1_048_576;
function streamError(schema, code, message, details = null) {
return Object.freeze({ ok: false, error: Object.freeze({ code, message, semanticId: schema.id, details }) });
}
function streamFrame(event, data, id = null) {
const lines = [];
if (id !== null) lines.push(`id: ${id}`);
lines.push(`event: ${event}`);
const encoded = JSON.stringify(data);
for (const line of encoded.split("\n")) lines.push(`data: ${line}`);
return `${lines.join("\n")}\n\n`;
}
function streamErrorFrame(schema, code, message, details = null) {
return streamFrame("noxid-error", streamError(schema, code, message, details));
}
function parseStreamResumeId(value) {
if (value === null) return null;
if (value.length > 256) return Object.freeze({ invalid: true });
const match = /^([A-Za-z0-9_-]{16,128}):([1-9][0-9]{0,15})$/.exec(value);
if (match === null) return Object.freeze({ invalid: true });
const sequence = Number(match[2]);
return Number.isSafeInteger(sequence)
? Object.freeze({ token: match[1], sequence })
: Object.freeze({ invalid: true });
}
function newStreamToken() {
if (typeof globalThis.crypto?.randomUUID !== "function" || typeof globalThis.crypto?.subtle?.digest !== "function") return null;
return globalThis.crypto.randomUUID().replace(/-/g, "_");
}
function stableStreamRequestValue(value, seen = new Set()) {
if (value === null) return "null";
if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
if (typeof value === "number" && Number.isFinite(value)) return JSON.stringify(value);
if (typeof value !== "object" || seen.has(value)) throw new Error("unsupported stream request value");
seen.add(value);
let output;
if (Array.isArray(value)) {
output = `[${value.map((item) => stableStreamRequestValue(item, seen)).join(",")}]`;
} else {
output = `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableStreamRequestValue(value[key], seen)}`).join(",")}}`;
}
seen.delete(value);
return output;
}
function endpointStreamPolicyIdentity(request, environment, middlewareContext) {
const session = middlewareContext?.sessionId ?? middlewareContext?.session?.id ?? environment?.sessionId;
if (typeof session === "string" && session.length > 0) return `session:${session}`;
const ip = environment?.requestIdentity?.ip ?? environment?.ip ?? request.headers.get("cf-connecting-ip") ?? request.headers.get("x-real-ip");
return typeof ip === "string" && ip.length > 0 ? `ip:${ip}` : null;
}
async function endpointStreamRequestBinding(token, request, args, environment, middlewareContext) {
const identity = endpointStreamPolicyIdentity(request, environment, middlewareContext);
const contract = stableStreamRequestValue(args);
const bytes = new TextEncoder().encode(`${token}\n${identity ?? "token-possession"}\n${contract}`);
const digest = new Uint8Array(await globalThis.crypto.subtle.digest("SHA-256", bytes));
let binary = "";
for (const byte of digest) binary += String.fromCharCode(byte);
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
function reserveStreamHistory(schema, token, requestBinding) {
while (endpointStreamHistories.size >= ENDPOINT_STREAM_MAX_HISTORIES) {
const removable = [...endpointStreamHistories.values()].find((history) => history.completed);
if (!removable) return null;
endpointStreamHistories.delete(removable.token);
}
const history = { token, schemaId: schema.id, requestBinding, events: [], bytes: 0, nextSequence: 1, completed: false, terminal: null };
endpointStreamHistories.set(token, history);
return history;
}
function recordStreamEvent(history, frame, bytes) {
const sequence = history.nextSequence;
history.nextSequence += 1;
history.events.push(Object.freeze({ sequence, frame, bytes }));
history.bytes += bytes;
while (history.events.length > ENDPOINT_STREAM_MAX_EVENTS || history.bytes > ENDPOINT_STREAM_MAX_HISTORY_BYTES) {
const removed = history.events.shift();
history.bytes -= removed.bytes;
}
return sequence;
}
function endpointFullPath(schema) {
return applicationBasePath === "/" ? schema.path : `${applicationBasePath.replace(/\/$/, "")}${schema.path}`;
}
function endpointSegments(pathname) {
const segments = pathname.split("/");
if (segments[0] === "") segments.shift();
return segments;
}
function matchEndpointPath(schema, pathname) {
const expected = endpointSegments(endpointFullPath(schema));
const actual = endpointSegments(pathname);
if (expected.length !== actual.length) return Object.freeze({ kind: "miss" });
const params = Object.create(null);
let malformed = false;
for (let index = 0; index < expected.length; index += 1) {
const segment = expected[index];
if (segment.startsWith("[") && segment.endsWith("]")) {
let value;
try { value = decodeURIComponent(actual[index]); }
catch { malformed = true; continue; }
if (value.length === 0) return Object.freeze({ kind: "miss" });
params[segment.slice(1, -1)] = value;
} else {
let value;
try { value = decodeURIComponent(actual[index]); }
catch { return Object.freeze({ kind: "miss" }); }
if (value !== segment) return Object.freeze({ kind: "miss" });
}
}
return malformed
? Object.freeze({ kind: "malformed" })
: Object.freeze({ kind: "match", params: Object.freeze(params) });
}
function endpointMatches(pathname) {
const matches = [];
const malformed = [];
for (const schema of endpointSchemas) {
const candidate = matchEndpointPath(schema, pathname);
if (candidate.kind === "match") matches.push(Object.freeze({ schema, params: candidate.params }));
if (candidate.kind === "malformed") malformed.push(schema);
}
matches.sort((left, right) => {
const leftDynamic = (left.schema.path.match(/\[/g) ?? []).length;
const rightDynamic = (right.schema.path.match(/\[/g) ?? []).length;
return leftDynamic - rightDynamic || left.schema.path.localeCompare(right.schema.path) || left.schema.method.localeCompare(right.schema.method);
});
malformed.sort((left, right) => left.path.localeCompare(right.path) || left.method.localeCompare(right.method));
return Object.freeze({ matches: Object.freeze(matches), malformed: Object.freeze(malformed) });
}
function endpointValidator(id) {
const validator = typeValidators[id];
return typeof validator === "function" ? validator : null;
}
function isStrictUtcIsoDate(value) {
if (typeof value !== "string") return false;
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?Z$/.exec(value);
if (match === null) return false;
const year = Number(match[1]);
const month = Number(match[2]);
const day = Number(match[3]);
const hour = Number(match[4]);
const minute = Number(match[5]);
const second = Number(match[6]);
if (month < 1 || month > 12 || hour > 23 || minute > 59 || second > 59) return false;
const leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
const days = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
return day >= 1 && day <= days[month - 1];
}
function optionalWireType(type) {
return type.startsWith("Optional<") && type.endsWith(">") ? type.slice(9, -1) : null;
}
function arrayWireType(type) {
const optional = optionalWireType(type);
if (optional !== null) return arrayWireType(optional);
return type.startsWith("Array<") && type.endsWith(">") ? type.slice(6, -1) : null;
}
function decodeEndpointScalar(raw, type) {
const optional = optionalWireType(type);
if (optional !== null) return decodeEndpointScalar(raw, optional);
if (type === "String") return raw;
if (type === "Date") {
if (!isStrictUtcIsoDate(raw)) throw new Error("Date");
return raw;
}
if (type === "Boolean") {
if (raw === "true") return true;
if (raw === "false") return false;
throw new Error("Boolean");
}
if (type === "Int") {
if (!/^-?(0|[1-9][0-9]*)$/.test(raw)) throw new Error("Int");
const value = Number(raw);
if (!Number.isSafeInteger(value)) throw new Error("Int");
return value;
}
if (type === "Float") {
if (!/^-?(0|[1-9][0-9]*)\.[0-9]+$/.test(raw)) throw new Error("Float");
const value = Number(raw);
if (!Number.isFinite(value)) throw new Error("Float");
return value;
}
if (type === "Number") {
if (!/^-?(0|[1-9][0-9]*)(\.[0-9]+)?$/.test(raw)) throw new Error("Number");
const value = Number(raw);
if (!Number.isFinite(value)) throw new Error("Number");
return value;
}
try { return JSON.parse(raw); } catch { throw new Error(type); }
}
function validateEndpointSection(schema, section, value) {
const validator = endpointValidator(`validator:endpoint.${schema.name}.${section}`);
if (validator === null) return Object.freeze(value);
try { return validator(value, true); }
catch (cause) {
throw Object.assign(new Error(`Endpoint ${section} violates its declared schema`), {
code: "ENDPOINT_INPUT_TYPE",
details: typeof cause?.toJSON === "function" ? cause.toJSON() : null,
});
}
}
function decodeEndpointParams(schema, raw) {
const values = Object.create(null);
for (const field of schema.params) {
if (!Object.hasOwn(raw, field.name)) throw Object.assign(new Error(`Missing path parameter ${field.name}`), { code: "ENDPOINT_PARAM_MISSING" });
try { values[field.name] = decodeEndpointScalar(raw[field.name], field.type); }
catch { throw Object.assign(new Error(`Path parameter ${field.name} must be ${field.type}`), { code: "ENDPOINT_PARAM_TYPE", details: { field: field.name, expected: field.type } }); }
}
return validateEndpointSection(schema, "params", values);
}
function decodeEndpointQueryPart(raw) {
return decodeURIComponent(raw.replace(/\+/g, " "));
}
function endpointQueryTransport(url) {
const grouped = Object.create(null);
let malformed = false;
const search = url.search.startsWith("?") ? url.search.slice(1) : url.search;
if (search.length > 0) {
for (const pair of search.split("&")) {
if (pair.length === 0) continue;
const separator = pair.indexOf("=");
const rawName = separator < 0 ? pair : pair.slice(0, separator);
const rawValue = separator < 0 ? "" : pair.slice(separator + 1);
let name, value;
try { name = decodeEndpointQueryPart(rawName); }
catch { name = rawName; malformed = true; }
try { value = decodeEndpointQueryPart(rawValue); }
catch { value = rawValue; malformed = true; }
const previous = grouped[name];
if (previous === undefined) grouped[name] = value;
else if (Array.isArray(previous)) grouped[name] = Object.freeze([...previous, value]);
else grouped[name] = Object.freeze([previous, value]);
}
}
return Object.freeze({ malformed, values: Object.freeze(grouped) });
}
function decodeEndpointQuery(schema, transport) {
if (transport.malformed) throw Object.assign(new Error("Endpoint query contains invalid percent encoding or UTF-8"), { status: 400, code: "ENDPOINT_QUERY_ENCODING_INVALID" });
const expected = new Set(schema.query.map((field) => field.name));
for (const name of Object.keys(transport.values)) {
if (!expected.has(name)) throw Object.assign(new Error(`Unknown query field ${name}`), { code: "ENDPOINT_QUERY_UNKNOWN", details: { field: name } });
}
const values = Object.create(null);
for (const field of schema.query) {
const candidate = transport.values[field.name];
const raw = candidate === undefined ? [] : Array.isArray(candidate) ? candidate : [candidate];
const optional = optionalWireType(field.type) !== null;
const inner = arrayWireType(field.type);
if (raw.length === 0) {
if (optional) { values[field.name] = null; continue; }
if (inner !== null) { values[field.name] = Object.freeze([]); continue; }
throw Object.assign(new Error(`Missing query field ${field.name}`), { code: "ENDPOINT_QUERY_MISSING", details: { field: field.name } });
}
try {
if (inner !== null) {
if (raw.length !== 1) throw new Error("repeated-array");
const decoded = JSON.parse(raw[0]);
if (!Array.isArray(decoded)) throw new Error("array");
values[field.name] = decoded;
} else {
if (raw.length !== 1) throw new Error("repeated");
values[field.name] = decodeEndpointScalar(raw[0], field.type);
}
} catch {
throw Object.assign(new Error(`Query field ${field.name} must be ${field.type}`), { code: "ENDPOINT_QUERY_TYPE", details: { field: field.name, expected: field.type } });
}
}
return validateEndpointSection(schema, "query", values);
}
function endpointTimeoutFailure(schema) {
return failure(504, "ENDPOINT_TIMEOUT", "Endpoint exceeded its declared timeout", schema.id, { timeoutMs: schema.timeoutMs });
}
function endpointTimeoutError(schema) {
return Object.assign(new Error("Endpoint exceeded its declared timeout"), { status: 504, code: "ENDPOINT_TIMEOUT", details: { timeoutMs: schema.timeoutMs } });
}
async function readEndpointBodyBytes(request, schema, signal) {
if (request.body === null) return new Uint8Array();
const reader = request.body.getReader();
const chunks = [];
let total = 0;
const cancel = () => { void reader.cancel("endpoint timeout").catch(() => {}); };
signal.addEventListener("abort", cancel, { once: true });
try {
while (true) {
if (signal.aborted) throw endpointTimeoutError(schema);
const { done, value } = await reader.read();
if (signal.aborted) throw endpointTimeoutError(schema);
if (done) break;
if (!(value instanceof Uint8Array)) throw Object.assign(new Error("Endpoint request body stream did not yield bytes"), { status: 400, code: "ENDPOINT_BODY_INVALID" });
total += value.byteLength;
if (total > 1_048_576) {
await reader.cancel("endpoint body too large").catch(() => {});
throw Object.assign(new Error("Endpoint request body exceeds 1 MiB"), { status: 413, code: "ENDPOINT_BODY_TOO_LARGE" });
}
chunks.push(value);
}
} finally {
signal.removeEventListener("abort", cancel);
try { reader.releaseLock(); } catch {}
}
const bytes = new Uint8Array(total);
let offset = 0;
for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.byteLength; }
return bytes;
}
const endpointUploadCleanups = new WeakMap();
function multipartFailure(status, code, message, details = null) {
return Object.assign(new Error(message), { status, code, details });
}
function multipartConcat(left, right) {
if (left.byteLength === 0) return right.slice();
if (right.byteLength === 0) return left;
const joined = new Uint8Array(left.byteLength + right.byteLength);
joined.set(left);
joined.set(right, left.byteLength);
return joined;
}
function multipartIndexOf(haystack, needle, start = 0) {
outer: for (let index = start; index + needle.byteLength <= haystack.byteLength; index += 1) {
for (let offset = 0; offset < needle.byteLength; offset += 1) if (haystack[index + offset] !== needle[offset]) continue outer;
return index;
}
return -1;
}
function multipartParameters(value) {
if (typeof value !== "string" || /[\r\n]/.test(value)) throw multipartFailure(400, "MULTIPART_HEADER_INVALID", "Multipart header parameters are malformed");
const entries = [];
let current = "";
let quoted = false;
let escaped = false;
for (const character of value) {
if (escaped) { current += character; escaped = false; continue; }
if (quoted && character === "\\") { current += character; escaped = true; continue; }
if (character === '"') { quoted = !quoted; current += character; continue; }
if (character === ";" && !quoted) { entries.push(current.trim()); current = ""; continue; }
current += character;
}
if (quoted || escaped) throw multipartFailure(400, "MULTIPART_HEADER_INVALID", "Multipart header quoting is incomplete");
entries.push(current.trim());
const kind = entries.shift()?.toLowerCase() ?? "";
const parameters = Object.create(null);
for (const entry of entries) {
const separator = entry.indexOf("=");
if (separator <= 0) throw multipartFailure(400, "MULTIPART_HEADER_INVALID", "Multipart header parameter requires a name and value");
const name = entry.slice(0, separator).trim().toLowerCase();
let parameter = entry.slice(separator + 1).trim();
if (parameter.startsWith('"')) {
if (!parameter.endsWith('"')) throw multipartFailure(400, "MULTIPART_HEADER_INVALID", "Multipart quoted parameter is incomplete");
parameter = parameter.slice(1, -1).replace(/\\(.)/g, "$1");
}
if (name.length === 0 || Object.hasOwn(parameters, name)) throw multipartFailure(400, "MULTIPART_HEADER_INVALID", "Multipart header parameter is duplicated or unnamed");
parameters[name] = parameter;
}
return { kind, parameters };
}
function endpointMultipartBoundary(contentType) {
const parsed = multipartParameters(contentType);
const boundary = parsed.parameters.boundary;
if (parsed.kind !== "multipart/form-data" || typeof boundary !== "string" || !/^[0-9A-Za-z'()+_,.\/:=?-]{1,70}$/.test(boundary)) {
throw multipartFailure(415, "ENDPOINT_MULTIPART_BOUNDARY", "multipart/form-data requires one valid boundary parameter of at most 70 ASCII characters");
}
return boundary;
}
function endpointMultipartHeaders(bytes) {
let text;
try { text = new TextDecoder("utf-8", { fatal: true }).decode(bytes); }
catch { throw multipartFailure(400, "MULTIPART_HEADER_INVALID", "Multipart part headers are not valid UTF-8"); }
const headers = Object.create(null);
for (const line of text.split("\r\n")) {
const separator = line.indexOf(":");
if (separator <= 0) throw multipartFailure(400, "MULTIPART_HEADER_INVALID", "Multipart part header requires `name: value`");
const name = line.slice(0, separator).trim().toLowerCase();
const value = line.slice(separator + 1).trim();
if (!/^[a-z0-9-]+$/.test(name) || Object.hasOwn(headers, name)) throw multipartFailure(400, "MULTIPART_HEADER_INVALID", "Multipart part header is duplicated or malformed");
headers[name] = value;
}
return headers;
}
// `filenameMaxBytes` is published in bytes, so it is enforced in bytes. The
// cut is moved back to the nearest code-point boundary — UTF-8 continuation
// bytes are 10xxxxxx — so a truncated name is never half a sequence and never
// half a surrogate pair: an astral character is kept whole or dropped whole.
// The limit is a ceiling on metadata, never a refusal.
function truncateUploadNameBytes(value) {
const bytes = new TextEncoder().encode(value);
if (bytes.byteLength <= ENDPOINT_UPLOAD_NAME_MAX_BYTES) return value;
let end = ENDPOINT_UPLOAD_NAME_MAX_BYTES;
while (end > 0 && (bytes[end] & 0xc0) === 0x80) end -= 1;
return new TextDecoder("utf-8").decode(bytes.subarray(0, end));
}
function sanitizeUploadName(value) {
const leaf = String(value).split(/[\\/]/).pop() ?? "";
// Normalize before measuring. NFKC folds compatibility spellings to one
// canonically composed form, so the bytes counted against the ceiling are
// the bytes the name is finally reported as.
const sanitized = truncateUploadNameBytes(leaf.normalize("NFKC").replace(/[\u0000-\u001f\u007f]/g, "_").replace(/^\.+/, ""));
return sanitized.length === 0 ? "upload" : sanitized;
}
function decodeMultipartScalar(bytes, field) {
let text;
try { text = new TextDecoder("utf-8", { fatal: true }).decode(bytes); }
catch { throw multipartFailure(400, "ENDPOINT_BODY_INVALID", `Multipart body field ${field.name} is not valid UTF-8`, { field: field.name }); }
let wireType = field.type;
while (optionalWireType(wireType) !== null) wireType = optionalWireType(wireType);
if (wireType === "String") return text;
if (["Int", "Number", "Float", "Boolean", "Date"].includes(wireType)) {
try { return decodeEndpointScalar(text, wireType); }
catch { throw multipartFailure(422, "ENDPOINT_BODY_TYPE", `Body field ${field.name} must be ${field.type}`, { field: field.name, expected: field.type }); }
}
try { return JSON.parse(text); }
catch { throw multipartFailure(422, "ENDPOINT_BODY_TYPE", `Body field ${field.name} must contain JSON matching ${field.type}`, { field: field.name, expected: field.type }); }
}
async function decodeEndpointMultipartBody(request, schema, signal, contentType) {
const boundary = endpointMultipartBoundary(contentType);
if (request.body === null) throw multipartFailure(400, "ENDPOINT_BODY_MISSING", "Multipart endpoint request body is missing");
const encoder = new TextEncoder();
const firstBoundary = encoder.encode(`--${boundary}`);
const bodyBoundary = encoder.encode(`\r\n--${boundary}`);
const headerTerminator = Uint8Array.from([13, 10, 13, 10]);
const fields = new Map(schema.body.map((field) => [field.name, field]));
const values = Object.create(null);
const seen = new Set();
const activeSinks = new Set();
const completedAccess = [];
let pending = new Uint8Array();
let phase = "start";
let part = null;
let parts = 0;
let scalarBytes = 0;
const beginPart = async (headerBytes) => {
// One completed header block is one part, counted before the block is
// parsed, so the count is a property of the body rather than of how the
// body was delivered.
parts += 1;
if (parts > ENDPOINT_MULTIPART_MAX_PARTS) throw multipartFailure(413, "MULTIPART_PART_LIMIT", `Multipart request exceeds ${ENDPOINT_MULTIPART_MAX_PARTS} parts`);
const headers = endpointMultipartHeaders(headerBytes);
const disposition = multipartParameters(headers["content-disposition"]);
const name = disposition.parameters.name;
if (disposition.kind !== "form-data" || typeof name !== "string" || name.length === 0) throw multipartFailure(400, "MULTIPART_DISPOSITION_INVALID", "Multipart part requires Content-Disposition: form-data with a name");
const field = fields.get(name);
if (!field) throw multipartFailure(400, "ENDPOINT_BODY_UNKNOWN", `Unknown body field ${name}`, { field: name });
const filename = disposition.parameters.filename;
if (field.upload !== null) {
if (typeof filename !== "string") throw multipartFailure(400, "MULTIPART_FILE_REQUIRED", `Body field ${name} requires a file part`, { field: name });
if (!field.upload.multiple && seen.has(name)) throw multipartFailure(400, "ENDPOINT_BODY_DUPLICATE", `Body field ${name} may appear only once`, { field: name });
const sink = await __noxidCreateUploadSink(field.upload.maxSizeBytes);
activeSinks.add(sink);
part = {
kind: "file",
field,
name: sanitizeUploadName(filename),
sink,
validation: __noxidCreateFileValidationState(field.upload.maxSizeBytes, field.upload.types, schema.id, [name]),
};
} else {
if (filename !== undefined) throw multipartFailure(400, "MULTIPART_SCALAR_REQUIRED", `Body field ${name} is scalar and cannot receive a file part`, { field: name });
if (seen.has(name)) throw multipartFailure(400, "ENDPOINT_BODY_DUPLICATE", `Body field ${name} may appear only once`, { field: name });
part = { kind: "scalar", field, chunks: [], size: 0 };
}
};
const writePart = async (chunk) => {
if (chunk.byteLength === 0) return;
if (part.kind === "file") {
__noxidValidateFileChunk(part.validation, chunk);
await part.sink.write(chunk);
return;
}
part.size += chunk.byteLength;
// A running total over the decoded span, so the verdict is the same
// whether the field arrived in one read or a thousand.
scalarBytes += chunk.byteLength;
if (scalarBytes > ENDPOINT_MULTIPART_SCALAR_MAX_BYTES) throw multipartFailure(413, "ENDPOINT_BODY_TOO_LARGE", `Multipart scalar fields exceed ${ENDPOINT_MULTIPART_SCALAR_MAX_BYTES} bytes`);
part.chunks.push(chunk.slice());
};
const finishPart = async () => {
const name = part.field.name;
if (part.kind === "file") {
const verdict = __noxidFinalizeFileValidation(part.validation);
const staged = await part.sink.finish();
activeSinks.delete(part.sink);
completedAccess.push(staged.access);
const file = __noxidCreateFileRef(
{ sniffedType: verdict.sniffedType, size: verdict.size, sha256: staged.sha256, name: part.name, maxSizeBytes: part.field.upload.maxSizeBytes },
{ stream: () => staged.access.stream(), bytes: () => staged.access.bytes(), store: (namespace) => staged.access.store(namespace) },
);
if (part.field.upload.multiple) {
if (!Object.hasOwn(values, name)) values[name] = [];
values[name].push(file);
} else {
values[name] = file;
}
} else {
const bytes = new Uint8Array(part.size);
let offset = 0;
for (const chunk of part.chunks) { bytes.set(chunk, offset); offset += chunk.byteLength; }
values[name] = decodeMultipartScalar(bytes, part.field);
}
seen.add(name);
part = null;
};
const validBoundaryAt = (index) => {
const suffix = index + bodyBoundary.byteLength;
if (pending.byteLength < suffix + 2) return false;
return (pending[suffix] === 13 && pending[suffix + 1] === 10) || (pending[suffix] === 45 && pending[suffix + 1] === 45);
};
const processPending = async (eof) => {
while (true) {
if (phase === "done") {
if (pending.byteLength === 0 || (pending.byteLength === 2 && pending[0] === 13 && pending[1] === 10)) { pending = new Uint8Array(); return; }
throw multipartFailure(400, "MULTIPART_EPILOGUE_INVALID", "Multipart body contains bytes after the closing boundary");
}
if (phase === "start") {
if (pending.byteLength < firstBoundary.byteLength + 2) { if (eof) throw multipartFailure(400, "MULTIPART_TRUNCATED", "Multipart body ended before its first boundary"); return; }
// RFC 2046 permits a preamble before the first boundary. It belongs to
// no part, carries no field, and is discarded — but it is still bytes
// a client can send, so it is bounded exactly like a part header block
// and refused past that with its own code rather than being read
// forever.
if (multipartIndexOf(pending, firstBoundary) !== 0) {
const delimiter = multipartIndexOf(pending, bodyBoundary);
// Measure the span, never the buffer. Once the delimiter is found
// the preamble is exactly `delimiter` bytes; while it is absent
// every buffered byte is preamble except a possible partial
// delimiter at the tail, so the decided-so-far length is
// `byteLength - (needle - 1)`. Counting the whole buffer instead
// would refuse a preamble at the ceiling whenever a read happened
// to stop inside the delimiter.
const preambleBytes = delimiter < 0 ? pending.byteLength - (bodyBoundary.byteLength - 1) : delimiter;
if (preambleBytes > ENDPOINT_MULTIPART_HEADER_MAX_BYTES) throw multipartFailure(413, "MULTIPART_PREAMBLE_TOO_LARGE", `Multipart preamble exceeds ${ENDPOINT_MULTIPART_HEADER_MAX_BYTES} bytes`);
if (delimiter < 0) {
if (eof) throw multipartFailure(400, "MULTIPART_BOUNDARY_INVALID", "Multipart body contains no declared boundary");
return;
}
pending = pending.slice(delimiter + 2);
continue;
}
if (pending[firstBoundary.byteLength] !== 13 || pending[firstBoundary.byteLength + 1] !== 10) throw multipartFailure(400, "MULTIPART_BOUNDARY_INVALID", "Multipart body does not start with its declared boundary");
pending = pending.slice(firstBoundary.byteLength + 2);
phase = "headers";
continue;
}
if (phase === "headers") {
const end = multipartIndexOf(pending, headerTerminator);
// The ceiling belongs to the header block, not to whatever the
// transport handed us. A found terminator makes the block exactly
// `end` bytes, and it is measured before `beginPart` sees it: an
// oversized block that arrives with its terminator in one read is
// the same block as one that arrives in pieces.
const headerBytes = end < 0 ? pending.byteLength - (headerTerminator.byteLength - 1) : end;
if (headerBytes > ENDPOINT_MULTIPART_HEADER_MAX_BYTES) throw multipartFailure(413, "MULTIPART_HEADERS_TOO_LARGE", `Multipart part headers exceed ${ENDPOINT_MULTIPART_HEADER_MAX_BYTES} bytes`);
if (end < 0) {
if (eof) throw multipartFailure(400, "MULTIPART_TRUNCATED", "Multipart body ended inside part headers");
return;
}
await beginPart(pending.subarray(0, end));
pending = pending.slice(end + headerTerminator.byteLength);
phase = "body";
continue;
}
let boundaryIndex = multipartIndexOf(pending, bodyBoundary);
while (boundaryIndex >= 0 && !validBoundaryAt(boundaryIndex)) boundaryIndex = multipartIndexOf(pending, bodyBoundary, boundaryIndex + 1);
if (boundaryIndex < 0) {
const retain = bodyBoundary.byteLength + 2;
const flush = Math.max(0, pending.byteLength - retain);
if (flush > 0) { await writePart(pending.subarray(0, flush)); pending = pending.slice(flush); }
if (eof) throw multipartFailure(400, "MULTIPART_TRUNCATED", "Multipart body ended before a closing boundary");
return;
}
await writePart(pending.subarray(0, boundaryIndex));
await finishPart();
const suffix = boundaryIndex + bodyBoundary.byteLength;
const closing = pending[suffix] === 45;
pending = pending.slice(suffix + 2);
phase = closing ? "done" : "headers";
}
};
const reader = request.body.getReader();
const cancel = () => { void reader.cancel("endpoint timeout").catch(() => {}); };
signal.addEventListener("abort", cancel, { once: true });
try {
while (true) {
if (signal.aborted) throw endpointTimeoutError(schema);
const { done, value } = await reader.read();
if (done) break;
if (!(value instanceof Uint8Array)) throw multipartFailure(400, "ENDPOINT_BODY_INVALID", "Endpoint request body stream did not yield bytes");
for (let offset = 0; offset < value.byteLength; offset += 65_536) {
pending = multipartConcat(pending, value.subarray(offset, Math.min(value.byteLength, offset + 65_536)));
await processPending(false);
}
}
await processPending(true);
for (const field of schema.body) {
if (!Object.hasOwn(values, field.name) && optionalWireType(field.type) === null) throw multipartFailure(400, "ENDPOINT_BODY_MISSING", `Missing body field ${field.name}`, { field: field.name });
if (field.upload?.multiple) values[field.name] = Object.freeze(values[field.name]);
}
endpointUploadCleanups.set(request, async () => {
for (const access of completedAccess) await access.dispose();
});
return validateEndpointSection(schema, "body", values);
} catch (cause) {
await reader.cancel(cause?.code ?? "multipart refused").catch(() => {});
for (const sink of activeSinks) await sink.abort().catch(() => {});
for (const access of completedAccess) await access.dispose().catch(() => {});
throw cause;
} finally {
signal.removeEventListener("abort", cancel);
try { reader.releaseLock(); } catch {}
}
}
async function releaseEndpointUploads(request) {
const cleanup = endpointUploadCleanups.get(request);
endpointUploadCleanups.delete(request);
if (cleanup) await cleanup();
}
async function decodeEndpointBody(request, schema, signal) {
if (schema.body.length === 0 && (schema.method === "GET" || request.body === null)) return Object.freeze(Object.create(null));
const contentTypeHeader = request.headers.get("content-type") ?? "";
const contentType = contentTypeHeader.split(";", 1)[0].trim().toLowerCase();
const uploadFields = schema.body.filter((field) => field.upload !== null);
if (contentType === "multipart/form-data") {
if (uploadFields.length === 0) throw Object.assign(new Error("multipart/form-data is accepted only by endpoints declaring a File body field"), { status: 415, code: "ENDPOINT_MULTIPART_UNDECLARED" });
return decodeEndpointMultipartBody(request, schema, signal, contentTypeHeader);
}
if (uploadFields.length !== 0) throw Object.assign(new Error("Endpoint upload body requires multipart/form-data"), { status: 415, code: "ENDPOINT_CONTENT_TYPE" });
if (contentType !== "application/json") throw Object.assign(new Error("Endpoint request body requires application/json"), { status: 415, code: "ENDPOINT_CONTENT_TYPE" });
const declaredLength = Number(request.headers.get("content-length") ?? 0);
if (Number.isFinite(declaredLength) && declaredLength > 1_048_576) throw Object.assign(new Error("Endpoint request body exceeds 1 MiB"), { status: 413, code: "ENDPOINT_BODY_TOO_LARGE" });
const bytes = await readEndpointBodyBytes(request, schema, signal);
let text;
try { text = new TextDecoder("utf-8", { fatal: true }).decode(bytes); }
catch { throw Object.assign(new Error("Endpoint request body is not valid UTF-8"), { status: 400, code: "ENDPOINT_BODY_INVALID" }); }
let body;
try { body = JSON.parse(text); } catch { throw Object.assign(new Error("Endpoint request body is not valid JSON"), { status: 400, code: "ENDPOINT_BODY_INVALID" }); }
if (!body || typeof body !== "object" || Array.isArray(body)) throw Object.assign(new Error("Endpoint request body must be a JSON object"), { status: 400, code: "ENDPOINT_BODY_INVALID" });
const fields = new Map(schema.body.map((field) => [field.name, field]));
for (const name of Object.keys(body)) if (!fields.has(name)) throw Object.assign(new Error(`Unknown body field ${name}`), { status: 400, code: "ENDPOINT_BODY_UNKNOWN", details: { field: name } });
for (const field of schema.body) if (!Object.hasOwn(body, field.name) && optionalWireType(field.type) === null) throw Object.assign(new Error(`Missing body field ${field.name}`), { status: 400, code: "ENDPOINT_BODY_MISSING", details: { field: field.name } });
return validateEndpointSection(schema, "body", body);
}
function endpointResponseWithHeaders(response, pairs) {
if (!pairs || pairs.length === 0) return response;
const headers = new Headers(response.headers);
for (const [name, value] of pairs) headers.append(name, value);
return __noxidTraceCopyFailure(response, new Response(response.body, { status: response.status, headers }));
}
function endpointCacheResponse(response, schema) {
if (schema.cache === null || response.status !== 200) return response;
const headers = new Headers(response.headers);
const seconds = String(schema.cache.seconds);
headers.set("cache-control", schema.cache.mode === "swr"
? `public, s-maxage=${seconds}, stale-while-revalidate=${seconds}`
: `public, s-maxage=${seconds}, must-revalidate`);
headers.set("x-noxid-cache-mode", schema.cache.mode);
headers.set("x-noxid-cache-revalidate", seconds);
headers.set("x-noxid-cache-stale", schema.cache.mode === "swr" ? seconds : "0");
headers.set("x-noxid-cache-tags", schema.cache.tags.join(","));
return new Response(response.body, { status: response.status, headers });
}
function endpointRedirect(value, external) {
if (external === true) {
if (typeof value !== "string" || !/^https:\/\/[^\s]+$/.test(value) || /[\r\n]/.test(value)) throw new Error("external");
return value;
}
if (typeof value !== "string" || !value.startsWith("/") || value.startsWith("//") || /[\r\n]/.test(value)) throw new Error("relative");
if (applicationBasePath === "/" || value === applicationBasePath || value.startsWith(`${applicationBasePath}/`)) return value;
return `${applicationBasePath.replace(/\/$/, "")}${value}`;
}
async function applyEndpointMiddleware(request, schema, params, query, environment, executionContext, signal) {
const headers = [];
const context = Object.create(null);
const chain = [
...globalMiddleware.map((name) => Object.freeze({ name, handle: globalMiddlewareHandlers[name] })),
...schema.middleware.map((name) => Object.freeze({ name, handle: middlewareHandlers[name] })),
];
const route = Object.freeze({ id: schema.id, pattern: schema.path, method: schema.method, middleware: Object.freeze(chain.map((entry) => entry.name)) });
__noxidTraceRoute(request, route.pattern);
for (const { name, handle } of chain) {
if (signal.aborted) return { response: endpointTimeoutFailure(schema), headers };
if (typeof handle !== "function") return { response: failure(500, "ENDPOINT_MIDDLEWARE_MISSING", "Required endpoint middleware is not available", schema.id, { middleware: name }), headers };
let result;
try {
result = await handle(__noxidDataContext({ middleware: name, semanticId: schema.id, traceId: __noxidTraceIdForRequest(request), boundary: `boundary:endpoint.${schema.name}.request`, target: "endpoint", route, request, url: new URL(request.url), params, query, host: hostModule, environment, executionContext, signal, context: Object.freeze({ ...context }), middlewareContext: Object.freeze({ ...context }) }, __noxidPrincipal(context, environment, __noxidAgentForRequest(request))));
} catch {
__noxidTraceBindPrincipal({ request }, __noxidPrincipal(context, environment, __noxidAgentForRequest(request)));
__noxidTraceSemantic(request, "middleware", name.startsWith("middleware:") ? name : `middleware:${name}`);
return { response: signal.aborted ? endpointTimeoutFailure(schema) : failure(500, "ENDPOINT_MIDDLEWARE_FAILED", "Endpoint middleware failed", schema.id, { middleware: name }), headers };
}
if (signal.aborted) return { response: endpointTimeoutFailure(schema), headers };
const normalized = __noxidNormalizeMiddlewareResult(result);
if (normalized.issue !== null) {
__noxidTraceBindPrincipal({ request }, __noxidPrincipal(context, environment, __noxidAgentForRequest(request)));
__noxidTraceSemantic(request, "middleware", name.startsWith("middleware:") ? name : `middleware:${name}`);
return { response: failure(500, `ENDPOINT_MIDDLEWARE_${normalized.issue.toUpperCase()}`, "Endpoint middleware returned an invalid boundary result", schema.id, { middleware: name, validation: normalized.detail }), headers };
}
headers.push(...normalized.headers);
if (normalized.context !== null) Object.assign(context, normalized.context);
__noxidTraceBindPrincipal({ request }, __noxidPrincipal(context, environment, __noxidAgentForRequest(request)));
__noxidTraceSemantic(request, "middleware", name.startsWith("middleware:") ? name : `middleware:${name}`);
if (normalized.respond !== null) {
const directHeaders = new Headers({ "content-type": `${normalized.respond.contentType}; charset=utf-8`, "cache-control": "no-store", "x-content-type-options": "nosniff" });
for (const [header, value] of headers) directHeaders.append(header, value);
return { response: new Response(normalized.respond.body, { status: normalized.respond.status, headers: directHeaders }), headers: [] };
}
if (normalized.redirect !== null) {
let location;
try { location = endpointRedirect(normalized.redirect, normalized.external); }
catch { return { response: failure(500, "ENDPOINT_MIDDLEWARE_REDIRECT_INVALID", "Endpoint middleware returned an unsafe redirect", schema.id, { middleware: name }), headers }; }
const redirect = new Response(null, { status: 307, headers: { location } });
return { response: endpointResponseWithHeaders(redirect, headers), headers: [] };
}
if (!normalized.allow) return { response: failure(403, "ENDPOINT_MIDDLEWARE_DENIED", "Endpoint middleware denied the request", schema.id, { middleware: name }), headers };
}
return { response: null, headers, context: Object.freeze({ ...context }), route };
}
async function authorizeEndpoint(request, schema, route, environment, executionContext, signal) {
if (schema.capabilities.length === 0) return null;
if (typeof authorize !== "function") return failure(500, "ENDPOINT_AUTHORIZER_MISSING", "Endpoint authorization is not configured", schema.id);
for (const capability of schema.capabilities) {
if (signal.aborted) return endpointTimeoutFailure(schema);
let allowed = false;
try { allowed = await authorize(Object.freeze({ capability, semanticId: schema.id, traceId: __noxidTraceIdForRequest(request), target: "endpoint", route, request, environment, executionContext, signal })) === true; } catch {}
if (signal.aborted) return endpointTimeoutFailure(schema);
if (!allowed) return failure(403, "ENDPOINT_CAPABILITY_DENIED", "Endpoint capability was denied", schema.id, { capability });
}
return null;
}
function endpointRateIdentity(schema, request, environment, middlewareContext) {
if (schema.limit === null) return { identity: null };
if (schema.limit.scope === "session") {
const identity = middlewareContext?.sessionId ?? middlewareContext?.session?.id ?? environment?.sessionId;
return typeof identity === "string" && identity.length > 0 ? { identity: `session:${identity}` } : { error: failure(403, "ENDPOINT_RATE_IDENTITY_REQUIRED", "Session-scoped endpoint limit requires an authenticated session identity", schema.id) };
}
const forwarded = request.headers.get("cf-connecting-ip") ?? request.headers.get("x-real-ip");
const identity = environment?.requestIdentity?.ip ?? environment?.ip ?? forwarded;
return typeof identity === "string" && identity.length > 0 ? { identity: `ip:${identity}` } : { error: failure(403, "ENDPOINT_RATE_IDENTITY_REQUIRED", "IP-scoped endpoint limit requires a trusted client identity", schema.id) };
}
async function withEndpointRateLock(key, operation) {
const previous = endpointRateLocks.get(key) ?? Promise.resolve();
let release;
const current = new Promise((resolve) => { release = resolve; });
endpointRateLocks.set(key, current);
await previous;
try { return await operation(); }
finally {
release();
if (endpointRateLocks.get(key) === current) endpointRateLocks.delete(key);
}
}
function validEndpointRateBucket(bucket) {
return bucket !== null && typeof bucket === "object"
&& typeof bucket.started === "number" && Number.isFinite(bucket.started) && bucket.started >= 0 && bucket.started <= Date.now()
&& typeof bucket.count === "number" && Number.isSafeInteger(bucket.count) && bucket.count >= 0
&& (bucket.windowMs === 60_000 || bucket.windowMs === 3_600_000);
}
async function reserveEndpointRateCapacity(currentKey) {
const keys = await endpointRateStorage.list();
if (keys.includes(currentKey) || keys.length < ENDPOINT_RATE_BUCKET_MAX_ENTRIES) return;
const loaded = await Promise.all(keys.map(async (key) => ({ key, bucket: await endpointRateStorage.get(key) })));
for (const entry of loaded) if (!validEndpointRateBucket(entry.bucket)) await endpointRateStorage.delete(entry.key);
const entries = loaded
.filter((entry) => validEndpointRateBucket(entry.bucket))
.sort((left, right) => left.bucket.started - right.bucket.started || left.key.localeCompare(right.key));
while (entries.length >= ENDPOINT_RATE_BUCKET_MAX_ENTRIES) {
const oldest = entries.shift();
if (oldest) await endpointRateStorage.delete(oldest.key);
}
}
async function enforceEndpointRateLimit(schema, identity) {
if (schema.limit === null) return null;
const windowMs = schema.limit.window === "minute" ? 60_000 : 3_600_000;
const key = `${schema.id}\n${identity}`;
if (typeof __noxidSharedRateLimit === "function") {
const retryAfter = await __noxidSharedRateLimit(key, schema.limit.requests, windowMs);
return retryAfter === null
? null
: failure(429, "ENDPOINT_RATE_LIMITED", "Endpoint rate limit exceeded", schema.id, { limit: schema.limit.requests, window: schema.limit.window }, { "retry-after": String(retryAfter) });
}
return withEndpointRateLock(key, async () => {
const now = Date.now();
let bucket = await endpointRateStorage.get(key);
if (!validEndpointRateBucket(bucket) || bucket.count > schema.limit.requests || now - bucket.started >= windowMs || bucket.windowMs !== windowMs) {
if (bucket !== null) await endpointRateStorage.delete(key);
await reserveEndpointRateCapacity(key);
bucket = { started: now, count: 0, windowMs };
}
if (bucket.count >= schema.limit.requests) {
const retryAfter = Math.max(1, Math.ceil((bucket.started + windowMs - now) / 1000));
return failure(429, "ENDPOINT_RATE_LIMITED", "Endpoint rate limit exceeded", schema.id, { limit: schema.limit.requests, window: schema.limit.window }, { "retry-after": String(retryAfter) });
}
const updated = { started: bucket.started, count: bucket.count + 1, windowMs };
await endpointRateStorage.set(key, updated, { ttl: Math.max(0, (bucket.started + windowMs - now) / 1000) });
return null;
});
}
async function endpointResponseSnapshot(response) {
const failure = __noxidFailureSpans.get(response);
const failureSnapshot = failure === undefined
? null
: Object.freeze({ code: failure.code, semanticId: failure.semanticId });
const copy = response.clone();
let headers = [...copy.headers];
if (typeof copy.headers.getSetCookie === "function") {
headers = headers.filter(([name]) => name.toLowerCase() !== "set-cookie");
headers.push(...copy.headers.getSetCookie().map((value) => ["set-cookie", value]));
}
const bytes = new Uint8Array(await copy.arrayBuffer());
let binary = "";
for (let offset = 0; offset < bytes.length; offset += 0x8000) binary += String.fromCharCode(...bytes.subarray(offset, offset + 0x8000));
return Object.freeze({ created: Date.now(), status: copy.status, headers: Object.freeze(headers.map((entry) => Object.freeze(entry))), body: btoa(binary), failure: failureSnapshot });
}
function replayEndpointResponse(snapshot) {
const binary = atob(snapshot.body);
const body = new Uint8Array(binary.length);
for (let index = 0; index < binary.length; index += 1) body[index] = binary.charCodeAt(index);
const response = new Response(body, { status: snapshot.status, headers: snapshot.headers });
return snapshot.failure === null || snapshot.failure === undefined
? response
: __noxidTraceFailure(response, snapshot.failure.code, snapshot.failure.semanticId);
}
function validEndpointFailureSnapshot(failure) {
if (failure === null) return true;
return typeof failure === "object"
&& Object.keys(failure).length === 2
&& typeof failure.code === "string" && NOXID_DIAGNOSTIC_CODE.test(failure.code)
&& (failure.semanticId === null || (typeof failure.semanticId === "string" && NOXID_SEMANTIC_ID.test(failure.semanticId)));
}
function validEndpointSnapshotBase(snapshot) {
return snapshot !== null && typeof snapshot === "object"
&& typeof snapshot.created === "number" && Number.isFinite(snapshot.created) && snapshot.created >= 0 && snapshot.created <= Date.now() && Date.now() - snapshot.created < ENDPOINT_IDEMPOTENCY_TTL_MS
&& typeof snapshot.status === "number" && Number.isSafeInteger(snapshot.status) && snapshot.status >= 100 && snapshot.status <= 599
&& Array.isArray(snapshot.headers) && snapshot.headers.every((entry) => Array.isArray(entry) && entry.length === 2 && entry.every((value) => typeof value === "string"))
&& typeof snapshot.body === "string";
}
function validEndpointSnapshot(snapshot) {
return validEndpointSnapshotBase(snapshot)
&& Object.hasOwn(snapshot, "failure") && validEndpointFailureSnapshot(snapshot.failure);
}
function endpointSnapshotMatchesSchema(snapshot, schema) {
if (!validEndpointSnapshot(snapshot)) return false;
let body;
try {
const binary = atob(snapshot.body);
const bytes = Uint8Array.from(binary, (value) => value.charCodeAt(0));
body = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
} catch { return false; }
const code = body?.error?.code;
const semanticId = body?.error?.semanticId;
if (snapshot.failure === null) {
return !new Set(["ENDPOINT_IMPLEMENTATION_MISSING", "ENDPOINT_TIMEOUT", "ENDPOINT_RESULT_TYPE", "ENDPOINT_RESULT_VALIDATOR_MISSING"]).has(code);
}
const expected = snapshot.failure.code === "ENDPOINT_RESULT_TYPE" || snapshot.failure.code === "ENDPOINT_RESULT_VALIDATOR_MISSING"
? Object.freeze({ semanticId: schema.result.id, status: 500 })
: snapshot.failure.code === "ENDPOINT_TIMEOUT"
? Object.freeze({ semanticId: schema.id, status: 504 })
: snapshot.failure.code === "ENDPOINT_IMPLEMENTATION_MISSING"
? Object.freeze({ semanticId: schema.id, status: 501 })
: null;
return expected !== null
&& snapshot.status === expected.status
&& snapshot.failure.semanticId === expected.semanticId
&& code === snapshot.failure.code
&& semanticId === snapshot.failure.semanticId;
}
async function reserveEndpointIdempotencySlot(currentKey) {
const keys = await endpointIdempotencyStorage.list();
if (keys.includes(currentKey) || keys.length + endpointIdempotencyInFlight.size < ENDPOINT_IDEMPOTENCY_MAX_ENTRIES) return;
const loaded = await Promise.all(keys.map(async (key) => ({ key, snapshot: await endpointIdempotencyStorage.get(key) })));
for (const entry of loaded) if (!validEndpointSnapshot(entry.snapshot)) await endpointIdempotencyStorage.delete(entry.key);
const entries = loaded
.filter((entry) => validEndpointSnapshot(entry.snapshot))
.sort((left, right) => left.snapshot.created - right.snapshot.created || left.key.localeCompare(right.key));
while (entries.length + endpointIdempotencyInFlight.size >= ENDPOINT_IDEMPOTENCY_MAX_ENTRIES) {
const oldestStored = entries.shift();
if (oldestStored) await endpointIdempotencyStorage.delete(oldestStored.key);
else endpointIdempotencyInFlight.delete(endpointIdempotencyInFlight.keys().next().value);
}
}
async function withEndpointIdempotencyLock(key, operation) {
const previous = endpointIdempotencyLocks.get(key) ?? Promise.resolve();
let release;
const current = new Promise((resolve) => { release = resolve; });
endpointIdempotencyLocks.set(key, current);
await previous;
try { return await operation(); }
finally {
release();
if (endpointIdempotencyLocks.get(key) === current) endpointIdempotencyLocks.delete(key);
}
}
function endpointIdempotencyIdentity(request, environment, middlewareContext) {
const session = middlewareContext?.sessionId ?? middlewareContext?.session?.id ?? environment?.sessionId;
if (typeof session === "string" && session.length > 0) return `session:${session}`;
const ip = environment?.requestIdentity?.ip ?? environment?.ip ?? request.headers.get("cf-connecting-ip") ?? request.headers.get("x-real-ip");
return typeof ip === "string" && ip.length > 0 ? `ip:${ip}` : null;
}
function endpointStorageFailure(schema, cause) {
if (cause?.code === "SERVER_STORAGE_REDIS_UNAVAILABLE") {
return failure(503, "ENDPOINT_STORAGE_UNAVAILABLE", "Endpoint operational storage is temporarily unavailable; retry the request", schema.id, null, { "retry-after": "1" });
}
return failure(500, "ENDPOINT_STORAGE_FAILED", "Endpoint operational storage is unavailable", schema.id);
}
function sharedEndpointIdempotencyAvailable() {
return typeof __noxidSharedIdempotencyPrepare === "function"
&& typeof __noxidSharedIdempotencyComplete === "function"
&& typeof __noxidSharedIdempotencyRelease === "function";
}
async function prepareSharedEndpointIdempotency(schema, key, signal, deadlineAt) {
if (typeof globalThis.crypto?.randomUUID !== "function") throw new Error("secure idempotency claims require crypto.randomUUID");
const claim = globalThis.crypto.randomUUID();
for (;;) {
if (signal.aborted) return { response: endpointTimeoutFailure(schema) };
const leaseMs = Math.max(1, Math.ceil(deadlineAt - Date.now() + 1000));
const prepared = await __noxidSharedIdempotencyPrepare(key, claim, leaseMs);
if (prepared?.state === "owner") return { claim };
if (prepared?.state === "stored") {
const existing = prepared.value;
if (endpointSnapshotMatchesSchema(existing, schema)) return { snapshot: existing };
const untraceableSnapshot = validEndpointSnapshotBase(existing);
await endpointIdempotencyStorage.delete(key);
if (untraceableSnapshot) return { response: endpointStorageFailure(schema) };
continue;
}
if (prepared?.state !== "pending") throw new Error("invalid shared idempotency preparation result");
await new Promise((resolve) => setTimeout(resolve, Math.min(10, Math.max(1, deadlineAt - Date.now()))));
}
}
function endpointStreamHeaders() {
return {
"content-type": "text/event-stream; charset=utf-8",
"cache-control": "no-store",
"connection": "keep-alive",
"x-accel-buffering": "no",
"x-content-type-options": "nosniff",
};
}
function endpointImmediateStreamFailure(schema, code, message, details = null) {
return new Response(streamErrorFrame(schema, code, message, details), { status: 200, headers: endpointStreamHeaders() });
}
function endpointClosedStreamResponse() {
return new Response(null, { status: 200, headers: endpointStreamHeaders() });
}
function resumeEndpointStream(schema, resume, requestBinding) {
if (resume.invalid) return endpointImmediateStreamFailure(schema, "STREAM_RESUME_UNAVAILABLE", "Last-Event-ID is malformed or exceeds the supported length", { reason: "malformed" });
const history = endpointStreamHistories.get(resume.token);
if (!history || history.schemaId !== schema.id) return endpointImmediateStreamFailure(schema, "STREAM_RESUME_UNAVAILABLE", "Last-Event-ID does not name retained history for this stream endpoint", { reason: "unknown" });
if (history.requestBinding !== requestBinding) return endpointImmediateStreamFailure(schema, "STREAM_RESUME_UNAVAILABLE", "Last-Event-ID belongs to a different stream request contract or request identity", { reason: "request-mismatch" });
if (!history.completed) return endpointImmediateStreamFailure(schema, "STREAM_RESUME_UNAVAILABLE", "The named stream history is still active; reconnect after the prior connection closes", { reason: "active" });
const firstRetained = history.events.length > 0 ? history.events[0].sequence : history.nextSequence;
if (resume.sequence >= history.nextSequence) return endpointImmediateStreamFailure(schema, "STREAM_RESUME_UNAVAILABLE", "Last-Event-ID is ahead of the recorded stream", { reason: "future", nextSequence: history.nextSequence });
if (resume.sequence < firstRetained - 1) return endpointImmediateStreamFailure(schema, "STREAM_RESUME_UNAVAILABLE", "Last-Event-ID is older than the bounded replay history", { reason: "evicted", firstRetained });
const frames = history.events.filter((event) => event.sequence > resume.sequence).map((event) => event.frame);
if (history.terminal !== null) frames.push(history.terminal);
return new Response(frames.join(""), { status: 200, headers: endpointStreamHeaders() });
}
async function invokeStreamEndpoint(request, schema, args, middleware, environment, executionContext, parentSignal, deadlineAt, implementation) {
const traceId = __noxidTraceIdForRequest(request);
if (request.signal.aborted) return endpointResponseWithHeaders(endpointClosedStreamResponse(), middleware.headers);
const resume = parseStreamResumeId(request.headers.get("last-event-id"));
if (resume !== null) {
if (resume.invalid) return endpointResponseWithHeaders(resumeEndpointStream(schema, resume, null), middleware.headers);
let requestBinding;
try { requestBinding = await endpointStreamRequestBinding(resume.token, request, args, environment, middleware.context); }
catch { return endpointResponseWithHeaders(endpointImmediateStreamFailure(schema, "STREAM_RESUME_BINDING_UNAVAILABLE", "The stream request contract cannot be bound safely for resume"), middleware.headers); }
if (parentSignal.aborted) return endpointResponseWithHeaders(endpointTimeoutFailure(schema), middleware.headers);
if (request.signal.aborted) return endpointResponseWithHeaders(endpointClosedStreamResponse(), middleware.headers);
return endpointResponseWithHeaders(resumeEndpointStream(schema, resume, requestBinding), middleware.headers);
}
const token = newStreamToken();
if (token === null) return endpointResponseWithHeaders(endpointImmediateStreamFailure(schema, "STREAM_RESUME_TOKEN_UNAVAILABLE", "A secure stream resume token cannot be created in this runtime"), middleware.headers);
let requestBinding;
try { requestBinding = await endpointStreamRequestBinding(token, request, args, environment, middleware.context); }
catch { return endpointResponseWithHeaders(endpointImmediateStreamFailure(schema, "STREAM_RESUME_BINDING_UNAVAILABLE", "The stream request contract cannot be bound safely for resume"), middleware.headers); }
if (parentSignal.aborted) return endpointResponseWithHeaders(endpointTimeoutFailure(schema), middleware.headers);
if (request.signal.aborted) return endpointResponseWithHeaders(endpointClosedStreamResponse(), middleware.headers);
const history = reserveStreamHistory(schema, token, requestBinding);
if (history === null) return endpointResponseWithHeaders(endpointImmediateStreamFailure(schema, "STREAM_REPLAY_CAPACITY", "All bounded stream replay histories are active; retry after a connection closes", { maxHistories: ENDPOINT_STREAM_MAX_HISTORIES }), middleware.headers);
const validator = endpointValidator(schema.result.validator);
if (validator === null) {
history.completed = true;
history.terminal = streamErrorFrame(schema, "STREAM_EVENT_VALIDATOR_MISSING", "Stream event validator is unavailable", { validator: schema.result.validator });
return endpointResponseWithHeaders(new Response(history.terminal, { status: 200, headers: endpointStreamHeaders() }), middleware.headers);
}
const encoder = new TextEncoder();
const controller = new AbortController();
let abortKind = null;
let iterator = null;
let streamController = null;
let open = true;
let timer = null;
const abort = (kind) => {
if (controller.signal.aborted) return;
abortKind = kind;
controller.abort(kind);
};
const onParentAbort = () => abort("timeout");
const onRequestAbort = () => abort("disconnect");
parentSignal.addEventListener("abort", onParentAbort, { once: true });
request.signal.addEventListener("abort", onRequestAbort, { once: true });
if (parentSignal.aborted) abort("timeout");
else if (request.signal.aborted) abort("disconnect");
const remaining = Math.max(0, deadlineAt - Date.now());
timer = setTimeout(() => abort("timeout"), remaining);
const enqueue = (text) => {
if (!open) return false;
try { streamController.enqueue(encoder.encode(text)); return true; }
catch { open = false; abort("disconnect"); return false; }
};
const finish = async (terminal = null) => {
if (history.completed) return;
history.completed = true;
history.terminal = terminal;
if (terminal !== null) enqueue(terminal);
open = false;
try { streamController.close(); } catch {}
if (iterator && typeof iterator.return === "function") {
try { await iterator.return(); } catch {}
}
};
const abortOutcome = controller.signal.aborted
? Promise.resolve(Object.freeze({ kind: "abort" }))
: new Promise((resolve) => controller.signal.addEventListener("abort", () => resolve(Object.freeze({ kind: "abort" })), { once: true }));
const waitWithHeartbeats = async (promise) => {
const pending = Promise.resolve(promise).then(
(value) => Object.freeze({ kind: "value", value }),
(cause) => Object.freeze({ kind: "error", cause }),
);
while (true) {
let heartbeatTimer;
const heartbeat = new Promise((resolve) => { heartbeatTimer = setTimeout(() => resolve(Object.freeze({ kind: "heartbeat" })), ENDPOINT_STREAM_HEARTBEAT_MS); });
const outcome = await Promise.race([pending, abortOutcome, heartbeat]);
clearTimeout(heartbeatTimer);
if (outcome.kind !== "heartbeat") return outcome;
if (!enqueue(": noxid-heartbeat\n\n")) return Object.freeze({ kind: "abort" });
}
};
const body = new ReadableStream({
async start(readableController) {
streamController = readableController;
try {
if (controller.signal.aborted) { await finish(); return; }
const middlewareContext = middleware.context ?? EMPTY_MIDDLEWARE_CONTEXT;
const context = __noxidDataContext({ request, environment, executionContext, signal: controller.signal, semanticId: schema.id, traceId, target: "endpoint", route: middleware.route, capabilities: schema.capabilities, middlewareContext }, __noxidPrincipal(middlewareContext, environment, __noxidAgentForRequest(request)));
const implementationOutcome = await waitWithHeartbeats(Promise.resolve().then(() => implementation(args, context)));
if (implementationOutcome.kind === "abort") {
if (abortKind === "timeout") await finish(streamErrorFrame(schema, "ENDPOINT_TIMEOUT", "Endpoint exceeded its declared timeout", { timeoutMs: schema.timeoutMs }));
else await finish();
return;
}
if (implementationOutcome.kind === "error") {
const cause = implementationOutcome.cause;
const code = typeof cause?.code === "string" ? cause.code : "STREAM_EXECUTION_FAILED";
const message = cause?.expose === true && typeof cause?.message === "string" ? cause.message : "Stream endpoint execution failed";
await finish(streamErrorFrame(schema, code, message));
return;
}
const iterable = implementationOutcome.value;
if (iterable === null || iterable === undefined || typeof iterable[Symbol.asyncIterator] !== "function") {
await finish(streamErrorFrame(schema, "STREAM_ITERABLE_REQUIRED", "Stream endpoint implementation must return an AsyncIterable"));
return;
}
iterator = iterable[Symbol.asyncIterator]();
while (open) {
const next = await waitWithHeartbeats(Promise.resolve().then(() => iterator.next()));
if (next.kind === "abort") {
if (abortKind === "timeout") await finish(streamErrorFrame(schema, "ENDPOINT_TIMEOUT", "Endpoint exceeded its declared timeout", { timeoutMs: schema.timeoutMs }));
else await finish();
return;
}
if (next.kind === "error") {
const cause = next.cause;
const code = typeof cause?.code === "string" ? cause.code : "STREAM_EXECUTION_FAILED";
const message = cause?.expose === true && typeof cause?.message === "string" ? cause.message : "Stream endpoint execution failed";
await finish(streamErrorFrame(schema, code, message));
return;
}
if (!next.value || typeof next.value !== "object" || typeof next.value.done !== "boolean") {
await finish(streamErrorFrame(schema, "STREAM_ITERATOR_RESULT_INVALID", "Stream endpoint iterator returned an invalid result"));
return;
}
if (next.value.done) { await finish(); return; }
let trusted;
try { trusted = validator(next.value.value); }
catch (cause) {
await finish(streamErrorFrame(schema, "STREAM_EVENT_TYPE", "Stream endpoint yielded an event that violates its declared type", { validation: typeof cause?.toJSON === "function" ? cause.toJSON() : null }));
return;
}
const eventValue = trusted === undefined ? null : trusted;
const serialized = JSON.stringify(eventValue);
const dataBytes = encoder.encode(serialized).byteLength;
if (dataBytes > ENDPOINT_STREAM_MAX_EVENT_BYTES) {
await finish(streamErrorFrame(schema, "STREAM_EVENT_TOO_LARGE", "Stream endpoint event exceeds the bounded replay size", { maxBytes: ENDPOINT_STREAM_MAX_EVENT_BYTES, actualBytes: dataBytes }));
return;
}
const sequence = history.nextSequence;
const frame = streamFrame("message", eventValue, `${history.token}:${sequence}`);
recordStreamEvent(history, frame, encoder.encode(frame).byteLength);
if (!enqueue(frame)) { await finish(); return; }
}
} catch {
await finish(streamErrorFrame(schema, "STREAM_EXECUTION_FAILED", "Stream endpoint execution failed"));
} finally {
clearTimeout(timer);
parentSignal.removeEventListener("abort", onParentAbort);
request.signal.removeEventListener("abort", onRequestAbort);
}
},
async cancel() {
open = false;
abort("disconnect");
history.completed = true;
if (iterator && typeof iterator.return === "function") {
try { await iterator.return(); } catch {}
}
},
});
return endpointResponseWithHeaders(new Response(body, { status: 200, headers: endpointStreamHeaders() }), middleware.headers);
}
function endpointResultResponse(schema, value) {
const isResult = schema.result.errorValidator !== null;
if (isResult) {
if (!value || typeof value !== "object" || !matchesResultTag(value.tag)) return failure(500, "ENDPOINT_RESULT_TYPE", "Endpoint returned a value that violates its declared Result type", schema.result.id);
const validatorId = value.tag === "Err" ? schema.result.errorValidator : schema.result.validator;
const validator = endpointValidator(validatorId);
if (validator === null) return failure(500, "ENDPOINT_RESULT_VALIDATOR_MISSING", "Endpoint result validator is unavailable", schema.result.id);
let trusted;
try { trusted = validator(value.value); }
catch (cause) { return failure(500, "ENDPOINT_RESULT_TYPE", "Endpoint returned a value that violates its declared result type", schema.result.id, { validation: typeof cause?.toJSON === "function" ? cause.toJSON() : null }); }
return value.tag === "Err"
? json(422, { ok: false, error: { code: "ENDPOINT_RESULT_ERR", message: "Endpoint returned its declared error result", semanticId: schema.result.id, value: trusted } })
: json(200, { ok: true, value: trusted === undefined ? null : trusted });
}
const validator = endpointValidator(schema.result.validator);
if (validator === null) return failure(500, "ENDPOINT_RESULT_VALIDATOR_MISSING", "Endpoint result validator is unavailable", schema.result.id);
try {
const trusted = validator(value);
return json(200, { ok: true, value: trusted === undefined ? null : trusted });
} catch (cause) { return failure(500, "ENDPOINT_RESULT_TYPE", "Endpoint returned a value that violates its declared result type", schema.result.id, { validation: typeof cause?.toJSON === "function" ? cause.toJSON() : null }); }
}
function matchesResultTag(tag) { return tag === "Ok" || tag === "Err"; }
function endpointAbortResponse(signal, schema) {
if (signal.aborted) return Promise.resolve(endpointTimeoutFailure(schema));
return new Promise((resolve) => signal.addEventListener("abort", () => resolve(endpointTimeoutFailure(schema)), { once: true }));
}
async function invokeEndpoint(request, schema, args, middleware, environment, executionContext, signal, deadlineAt) {
const middlewareContext = middleware.context ?? EMPTY_MIDDLEWARE_CONTEXT;
const endpointPrincipal = __noxidPrincipal(middlewareContext, environment, __noxidAgentForRequest(request));
__noxidTraceBindPrincipal({ request }, endpointPrincipal);
const endpointSpan = __noxidTraceBeginSemantic(request);
try {
const implementation = compiledEndpoints[schema.id] ?? hostEndpoints[schema.id];
if (typeof implementation !== "function") {
return schema.kind === "stream"
? endpointResponseWithHeaders(endpointImmediateStreamFailure(schema, "STREAM_IMPLEMENTATION_MISSING", `No implementation is registered for ${schema.id}`), middleware.headers)
: failure(501, "ENDPOINT_IMPLEMENTATION_MISSING", `No implementation is registered for ${schema.id}`, schema.id);
}
if (signal.aborted) return endpointResponseWithHeaders(endpointTimeoutFailure(schema), middleware.headers);
if (schema.kind === "stream") return invokeStreamEndpoint(request, schema, args, middleware, environment, executionContext, signal, deadlineAt, implementation);
const execution = (async () => {
try {
const context = __noxidDataContext({ request, environment, executionContext, signal, semanticId: schema.id, traceId: __noxidTraceIdForRequest(request), target: "endpoint", route: middleware.route, capabilities: schema.capabilities, middlewareContext }, endpointPrincipal);
const value = await implementation(args, context);
if (signal.aborted) return endpointTimeoutFailure(schema);
const validatedResponse = endpointResultResponse(schema, value);
if (validatedResponse.ok) await __noxidPublishLiveInvalidations(schema.invalidates, endpointPrincipal);
return endpointCacheResponse(validatedResponse, schema);
} catch (cause) {
if (signal.aborted) return endpointTimeoutFailure(schema);
const code = typeof cause?.code === "string" ? cause.code : "ENDPOINT_EXECUTION_FAILED";
const message = cause?.expose === true && typeof cause?.message === "string" ? cause.message : "Endpoint execution failed";
return failure(500, code, message, schema.id, null, {}, false);
}
})();
const response = await Promise.race([execution, endpointAbortResponse(signal, schema)]);
return endpointResponseWithHeaders(response, middleware.headers);
} finally {
__noxidTraceFinishSemantic(endpointSpan, "endpoint", schema.id, { route: middleware.route?.pattern });
}
}
async function withEndpointDeadline(schema, operation) {
const controller = new AbortController();
if (schema.timeoutMs === 0) {
controller.abort();
return endpointTimeoutFailure(schema);
}
let timer;
const deadlineAt = Date.now() + schema.timeoutMs;
const timeout = new Promise((resolve) => {
timer = setTimeout(() => {
controller.abort();
resolve(endpointTimeoutFailure(schema));
}, schema.timeoutMs);
});
try {
return await Promise.race([Promise.resolve().then(() => operation(controller.signal, deadlineAt)), timeout]);
} finally {
clearTimeout(timer);
}
}
async function handleEndpointRequest(request, url, environment, executionContext) {
const candidates = endpointMatches(url.pathname);
const matches = candidates.matches;
if (matches.length === 0 && candidates.malformed.length === 0) return null;
const methodMatches = matches.filter((candidate) => candidate.schema.method === request.method.toUpperCase());
const malformedMethodMatches = candidates.malformed.filter((schema) => schema.method === request.method.toUpperCase());
if (methodMatches.length === 0 && malformedMethodMatches.length > 0) {
const schema = malformedMethodMatches[0];
return failure(400, "ENDPOINT_PATH_ENCODING_INVALID", "Endpoint path contains invalid percent encoding; percent-encode one valid UTF-8 path value", schema.id);
}
if (methodMatches.length === 0) {
const allow = [...new Set([...matches.map((candidate) => candidate.schema.method), ...candidates.malformed.map((schema) => schema.method)])].sort().join(", ");
return failure(405, "ENDPOINT_METHOD_NOT_ALLOWED", "Endpoint path does not accept this method", null, null, { allow });
}
const { schema, params: rawParams } = methodMatches[0];
return withEndpointDeadline(schema, async (signal, deadlineAt) => {
try {
const queryTransport = endpointQueryTransport(url);
const middleware = await applyEndpointMiddleware(request, schema, rawParams, queryTransport.values, environment, executionContext, signal);
if (signal.aborted) return endpointTimeoutFailure(schema);
if (middleware.response) return endpointResponseWithHeaders(middleware.response, middleware.headers);
const authorizationFailure = await authorizeEndpoint(request, schema, middleware.route, environment, executionContext, signal);
if (signal.aborted) return endpointResponseWithHeaders(endpointTimeoutFailure(schema), middleware.headers);
if (authorizationFailure) return endpointResponseWithHeaders(authorizationFailure, middleware.headers);
let params, query, body;
try {
params = decodeEndpointParams(schema, rawParams);
query = decodeEndpointQuery(schema, queryTransport);
body = await decodeEndpointBody(request, schema, signal);
} catch (cause) {
if (signal.aborted) return endpointResponseWithHeaders(endpointTimeoutFailure(schema), middleware.headers);
const response = failure(cause?.status ?? (cause?.code === "ENDPOINT_INPUT_TYPE" || cause?.code?.endsWith("_TYPE") ? 422 : 400), cause?.code ?? "ENDPOINT_INPUT_INVALID", cause?.message ?? "Endpoint request is invalid", schema.id, cause?.details ?? null);
return endpointResponseWithHeaders(response, middleware.headers);
}
if (signal.aborted) return endpointResponseWithHeaders(endpointTimeoutFailure(schema), middleware.headers);
const argumentsRecord = Object.freeze(Object.assign(Object.create(null), params, query, body));
if (schema.kind === "stream" && (schema.cache !== null || schema.idempotent)) return endpointResponseWithHeaders(failure(500, "STREAM_OPERATION_POLICY_INVALID", "Stream endpoints cannot use response cache or idempotent replay policies", schema.id), middleware.headers);
const rateIdentity = endpointRateIdentity(schema, request, environment, middleware.context);
if (rateIdentity.error) return endpointResponseWithHeaders(rateIdentity.error, middleware.headers);
let idempotencyMapKey = null;
if (schema.idempotent) {
const idempotencyKey = request.headers.get("idempotency-key");
if (typeof idempotencyKey !== "string" || idempotencyKey.length === 0 || idempotencyKey.length > 256 || !/^[\x21-\x7e]+$/.test(idempotencyKey)) return endpointResponseWithHeaders(failure(400, "ENDPOINT_IDEMPOTENCY_KEY_REQUIRED", "Idempotent endpoint requests require a valid Idempotency-Key header", schema.id), middleware.headers);
const replayIdentity = endpointIdempotencyIdentity(request, environment, middleware.context);
if (replayIdentity === null) return endpointResponseWithHeaders(failure(403, "ENDPOINT_IDEMPOTENCY_IDENTITY_REQUIRED", "Idempotent endpoint replay requires a session or trusted client identity", schema.id), middleware.headers);
idempotencyMapKey = `${schema.id}\n${replayIdentity}\n${idempotencyKey}`;
}
if (idempotencyMapKey !== null) {
try {
const prepared = await withEndpointIdempotencyLock(idempotencyMapKey, async () => {
if (signal.aborted) return { response: endpointTimeoutFailure(schema) };
const inFlight = endpointIdempotencyInFlight.get(idempotencyMapKey);
if (inFlight) return { promise: inFlight };
const shared = sharedEndpointIdempotencyAvailable();
let sharedClaim = null;
if (shared) {
const distributed = await prepareSharedEndpointIdempotency(schema, idempotencyMapKey, signal, deadlineAt);
if (distributed.response) return { response: endpointResponseWithHeaders(distributed.response, middleware.headers) };
if (distributed.snapshot) return { snapshot: distributed.snapshot };
sharedClaim = distributed.claim;
} else {
const existing = await endpointIdempotencyStorage.get(idempotencyMapKey);
if (existing !== null) {
if (endpointSnapshotMatchesSchema(existing, schema)) return { snapshot: existing };
const untraceableSnapshot = validEndpointSnapshotBase(existing);
await endpointIdempotencyStorage.delete(idempotencyMapKey);
if (untraceableSnapshot) return { response: endpointResponseWithHeaders(endpointStorageFailure(schema), middleware.headers) };
}
}
const rateFailure = await enforceEndpointRateLimit(schema, rateIdentity.identity);
if (rateFailure) {
if (sharedClaim !== null) await __noxidSharedIdempotencyRelease(idempotencyMapKey, sharedClaim);
return { response: endpointResponseWithHeaders(rateFailure, middleware.headers) };
}
if (!shared) await reserveEndpointIdempotencySlot(idempotencyMapKey);
let promise;
promise = (async () => {
try {
const response = await invokeEndpoint(request, schema, argumentsRecord, middleware, environment, executionContext, signal, deadlineAt);
const snapshot = await endpointResponseSnapshot(response);
if (sharedClaim === null) {
await endpointIdempotencyStorage.set(idempotencyMapKey, snapshot, { ttl: ENDPOINT_IDEMPOTENCY_TTL_MS / 1000 });
} else {
await __noxidSharedIdempotencyComplete(idempotencyMapKey, sharedClaim, snapshot, ENDPOINT_IDEMPOTENCY_TTL_MS / 1000);
}
return snapshot;
} catch (cause) {
if (sharedClaim !== null) await __noxidSharedIdempotencyRelease(idempotencyMapKey, sharedClaim);
throw cause;
} finally {
if (endpointIdempotencyInFlight.get(idempotencyMapKey) === promise) endpointIdempotencyInFlight.delete(idempotencyMapKey);
}
})();
endpointIdempotencyInFlight.set(idempotencyMapKey, promise);
return { promise };
});
if (prepared.response) return prepared.response;
if (prepared.snapshot) return replayEndpointResponse(prepared.snapshot);
const snapshot = await Promise.race([prepared.promise, endpointAbortResponse(signal, schema).then(endpointResponseSnapshot)]);
return replayEndpointResponse(snapshot);
} catch (cause) { return endpointResponseWithHeaders(endpointStorageFailure(schema, cause), middleware.headers); }
}
let rateFailure;
try { rateFailure = await enforceEndpointRateLimit(schema, rateIdentity.identity); }
catch (cause) { return endpointResponseWithHeaders(endpointStorageFailure(schema, cause), middleware.headers); }
if (rateFailure) return endpointResponseWithHeaders(rateFailure, middleware.headers);
return await invokeEndpoint(request, schema, argumentsRecord, middleware, environment, executionContext, signal, deadlineAt);
} finally {
await releaseEndpointUploads(request);
}
});
}
const MCP_PROTOCOL_VERSIONS = Object.freeze(["2026-07-28", "2025-11-25", "2025-06-18", "2025-03-26"]);
const MCP_REQUEST_MAX_BYTES = 1_048_576;
const MCP_TOOL_RESULT_MAX_BYTES = 1_048_576;
const MCP_STREAM_MAX_EVENTS = 256;
const mcpOpenApiDocument = openapiDocument === null ? null : JSON.parse(openapiDocument);
function mcpOpenApiOperation(schema) {
for (const pathItem of Object.values(mcpOpenApiDocument?.paths ?? {})) {
const operation = pathItem?.[schema.method.toLowerCase()];
if (operation?.["x-noxid-endpoint-id"] === schema.id && operation?.operationId === schema.name) return operation;
}
throw Object.assign(new Error(`OpenAPI is missing the exact routed operation for ${schema.id}`), { code: "MCP_OPENAPI_OPERATION_MISSING" });
}
function mcpRewriteOpenApiSchema(value) {
if (Array.isArray(value)) return value.map(mcpRewriteOpenApiSchema);
if (value === null || typeof value !== "object") return value;
const output = Object.create(null);
for (const [key, nested] of Object.entries(value)) {
output[key] = key === "$ref" && typeof nested === "string" && nested.startsWith("#/components/schemas/")
? `#/$defs/${nested.slice("#/components/schemas/".length)}`
: mcpRewriteOpenApiSchema(nested);
}
return output;
}
function mcpSchemaDefinitions() {
const definitions = Object.create(null);
for (const [name, schema] of Object.entries(mcpOpenApiDocument?.components?.schemas ?? {})) definitions[name] = mcpRewriteOpenApiSchema(schema);
return definitions;
}
function mcpAttachDefinitions(schema) {
return Object.freeze({ ...schema, $defs: Object.freeze(mcpSchemaDefinitions()) });
}
function mcpInputSchema(operation) {
const properties = Object.create(null);
const required = [];
for (const parameter of operation.parameters ?? []) {
const parameterSchema = parameter.schema ?? parameter.content?.["application/json"]?.schema;
if (!parameterSchema || typeof parameter.name !== "string") throw Object.assign(new Error("OpenAPI endpoint parameter is missing its schema"), { code: "MCP_OPENAPI_SCHEMA_MISSING" });
properties[parameter.name] = mcpRewriteOpenApiSchema(parameterSchema);
if (parameter.required === true) required.push(parameter.name);
}
const bodySchema = operation.requestBody?.content?.["application/json"]?.schema;
if (bodySchema) {
const rewritten = mcpRewriteOpenApiSchema(bodySchema);
for (const [name, schema] of Object.entries(rewritten.properties ?? {})) properties[name] = schema;
for (const name of rewritten.required ?? []) if (!required.includes(name)) required.push(name);
}
return mcpAttachDefinitions({ type: "object", properties: Object.freeze(properties), required: Object.freeze(required), additionalProperties: false });
}
function mcpOutputSchema(schema, operation) {
const response = operation.responses?.["200"];
let body;
if (schema.kind === "stream") {
const eventSchema = response?.content?.["text/event-stream"]?.["x-noxid-event-schema"];
if (!eventSchema) throw Object.assign(new Error(`OpenAPI is missing the stream event schema for ${schema.id}`), { code: "MCP_OPENAPI_SCHEMA_MISSING" });
const errorSchema = mcpOpenApiDocument?.components?.schemas?.NoxidErrorResponse?.properties?.error ?? {};
body = { type: "object", properties: { ok: { type: "boolean" }, events: { type: "array", items: mcpRewriteOpenApiSchema(eventSchema) }, error: mcpRewriteOpenApiSchema(errorSchema) }, required: ["ok", "events"], additionalProperties: false };
} else {
const resultSchema = response?.content?.["application/json"]?.schema;
if (!resultSchema) throw Object.assign(new Error(`OpenAPI is missing the result schema for ${schema.id}`), { code: "MCP_OPENAPI_SCHEMA_MISSING" });
body = mcpRewriteOpenApiSchema(resultSchema);
}
return mcpAttachDefinitions({ type: "object", properties: { status: { type: "integer" }, body }, required: ["status", "body"], additionalProperties: false });
}
const mcpEndpointSchemas = Object.freeze(endpointSchemas.filter((schema) => schema.path.length > 0 && schema.method.length > 0));
const mcpTools = Object.freeze((mcpEnabled ? mcpEndpointSchemas : []).map((schema) => {
const operation = mcpOpenApiOperation(schema);
const tool = { name: schema.name, inputSchema: mcpInputSchema(operation), outputSchema: mcpOutputSchema(schema, operation), "x-noxid-endpoint": Object.freeze({ semanticId: schema.id, version: schema.version, method: schema.method, path: schema.path, kind: schema.kind, signature: operation["x-noxid-signature"] }) };
if (typeof operation.description === "string") tool.description = operation.description;
return Object.freeze(tool);
}));
function mcpRpcResult(id, result) {
return Object.freeze({ jsonrpc: "2.0", id, result });
}
function mcpRpcError(id, code, message, data = null) {
const error = { code, message };
if (data !== null) error.data = data;
return Object.freeze({ jsonrpc: "2.0", id, error: Object.freeze(error) });
}
function mcpJsonResponse(status, payload, headers = {}) {
return new Response(payload === null ? null : JSON.stringify(payload), {
status,
headers: { "content-type": "application/json; charset=utf-8", "cache-control": "no-store", "x-content-type-options": "nosniff", ...headers },
});
}
async function mcpRequestText(request) {
const declared = Number(request.headers.get("content-length") ?? 0);
if (Number.isFinite(declared) && declared > MCP_REQUEST_MAX_BYTES) throw Object.assign(new Error("MCP request body exceeds 1 MiB"), { code: "MCP_REQUEST_TOO_LARGE" });
if (request.body === null) return "";
const reader = request.body.getReader();
const chunks = [];
let total = 0;
try {
while (true) {
const chunk = await reader.read();
if (chunk.done) break;
if (!(chunk.value instanceof Uint8Array)) throw new Error("MCP request body did not yield bytes");
total += chunk.value.byteLength;
if (total > MCP_REQUEST_MAX_BYTES) {
await reader.cancel("MCP request body too large").catch(() => {});
throw Object.assign(new Error("MCP request body exceeds 1 MiB"), { code: "MCP_REQUEST_TOO_LARGE" });
}
chunks.push(chunk.value);
}
} finally {
try { reader.releaseLock(); } catch {}
}
const bytes = new Uint8Array(total);
let offset = 0;
for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.byteLength; }
try { return new TextDecoder("utf-8", { fatal: true }).decode(bytes); }
catch { throw Object.assign(new Error("MCP request body must be UTF-8"), { code: "MCP_REQUEST_UTF8" }); }
}
function mcpWireValue(value, type) {
if (arrayWireType(type) !== null) return JSON.stringify(value);
if (typeof value === "string") return value;
if (typeof value === "number" || typeof value === "boolean") return String(value);
return JSON.stringify(value);
}
function mcpEndpointRequest(outerRequest, schema, args) {
const validArguments = args !== null && typeof args === "object" && !Array.isArray(args) && Object.getPrototypeOf(args) === Object.prototype;
const values = validArguments ? args : Object.freeze({});
const declared = new Set([...schema.params, ...schema.query, ...schema.body].map((field) => field.name));
const unknown = Object.keys(values).filter((name) => !declared.has(name));
const transportErrors = validArguments ? [] : ["__noxid_mcp_arguments_must_be_object__"];
let path = endpointFullPath(schema);
for (const field of schema.params) {
const present = Object.hasOwn(values, field.name);
if (!present) transportErrors.push(`__noxid_mcp_missing_${field.name}__`);
path = path.replace(`[${field.name}]`, encodeURIComponent(present ? mcpWireValue(values[field.name], field.type) : "__noxid_mcp_missing__"));
}
const url = new URL(outerRequest.url);
url.pathname = path;
url.search = "";
for (const field of schema.query) {
if (!Object.hasOwn(values, field.name) || values[field.name] === null) continue;
url.searchParams.set(field.name, mcpWireValue(values[field.name], field.type));
}
const body = Object.create(null);
for (const field of schema.body) if (Object.hasOwn(values, field.name)) body[field.name] = values[field.name];
if (schema.body.length > 0) for (const name of unknown) body[name] = values[name];
else for (const name of unknown) url.searchParams.set(name, mcpWireValue(values[name], "String"));
for (const name of transportErrors) url.searchParams.set(name, "invalid");
const headers = new Headers(outerRequest.headers);
for (const name of ["accept", "content-length", "content-type", "last-event-id", "mcp-protocol-version", "mcp-session-id"]) headers.delete(name);
const hasBody = schema.body.length > 0;
if (hasBody) headers.set("content-type", "application/json");
return new Request(url, { method: schema.method, headers, body: hasBody ? JSON.stringify(body) : undefined, signal: outerRequest.signal });
}
async function mcpBoundedResponseText(response) {
if (response.body === null) return "";
const reader = response.body.getReader();
const chunks = [];
let total = 0;
try {
while (true) {
const chunk = await reader.read();
if (chunk.done) break;
total += chunk.value.byteLength;
if (total > MCP_TOOL_RESULT_MAX_BYTES) {
await reader.cancel("MCP tool result too large").catch(() => {});
throw Object.assign(new Error("MCP tool result exceeds the 1 MiB agent-surface limit"), { code: "MCP_TOOL_RESULT_TOO_LARGE" });
}
chunks.push(chunk.value);
}
} finally {
try { reader.releaseLock(); } catch {}
}
const bytes = new Uint8Array(total);
let offset = 0;
for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.byteLength; }
try { return new TextDecoder("utf-8", { fatal: true }).decode(bytes); }
catch { throw Object.assign(new Error("MCP tool response is not UTF-8"), { code: "MCP_TOOL_RESULT_UTF8" }); }
}
function mcpStreamBody(text) {
const events = [];
let terminal = null;
for (const block of text.replace(/\r\n/g, "\n").split("\n\n")) {
if (block.length === 0 || block.split("\n").every((line) => line.length === 0 || line.startsWith(":"))) continue;
let event = "message";
const data = [];
for (const line of block.split("\n")) {
if (line.startsWith("event:")) event = line.slice(6).trimStart();
if (line.startsWith("data:")) data.push(line.slice(5).replace(/^ /, ""));
}
if (data.length === 0) continue;
let value;
try { value = JSON.parse(data.join("\n")); }
catch { throw Object.assign(new Error("Stream endpoint emitted invalid JSON through MCP"), { code: "MCP_STREAM_EVENT_INVALID" }); }
if (event === "message") {
events.push(value);
if (events.length > MCP_STREAM_MAX_EVENTS) throw Object.assign(new Error("Stream endpoint exceeded the 256-event MCP result limit"), { code: "MCP_STREAM_EVENT_LIMIT" });
} else if (event === "noxid-error") terminal = value?.error ?? Object.freeze({ code: "MCP_STREAM_FAILED", message: "Stream endpoint failed" });
else throw Object.assign(new Error(`Stream endpoint emitted unsupported SSE event ${event}`), { code: "MCP_STREAM_EVENT_INVALID" });
}
return Object.freeze({ ok: terminal === null, events: Object.freeze(events), ...(terminal === null ? {} : { error: terminal }) });
}
function mcpToolResult(status, body, isError) {
const structuredContent = Object.freeze({ status, body });
return Object.freeze({
content: Object.freeze([Object.freeze({ type: "text", text: JSON.stringify(structuredContent) })]),
structuredContent,
isError,
});
}
async function callMcpEndpointTool(outerRequest, schema, args, environment, executionContext) {
let endpointRequest;
try { endpointRequest = mcpEndpointRequest(outerRequest, schema, args); }
catch (cause) {
const error = Object.freeze({ ok: false, error: Object.freeze({ code: cause?.code ?? "MCP_ARGUMENTS_INVALID", message: cause?.message ?? "MCP tool arguments are invalid", semanticId: schema.id, details: cause?.argument ? { argument: cause.argument } : null }) });
return mcpToolResult(400, error, true);
}
inheritNoxidRequestTrace(outerRequest, endpointRequest);
__noxidAgentRequests.set(endpointRequest, schema.id);
const response = await withNoxidRequestTrace(endpointRequest, () => handleEndpointRequest(endpointRequest, new URL(endpointRequest.url), environment, executionContext));
if (response === null) return mcpToolResult(500, Object.freeze({ ok: false, error: Object.freeze({ code: "MCP_ENDPOINT_DISPATCH_FAILED", message: "MCP tool did not resolve to its declared HTTP endpoint", semanticId: schema.id, details: null }) }), true);
__noxidTraceResponseFailure(endpointRequest, response);
try {
const text = await mcpBoundedResponseText(response);
if (schema.kind === "stream") return mcpToolResult(response.status, mcpStreamBody(text), text.includes("event: noxid-error"));
let body;
try { body = text.length === 0 ? null : JSON.parse(text); }
catch { body = Object.freeze({ contentType: response.headers.get("content-type"), text }); }
return mcpToolResult(response.status, body, !response.ok || body?.ok === false);
} catch (cause) {
return mcpToolResult(500, Object.freeze({ ok: false, error: Object.freeze({ code: cause?.code ?? "MCP_TOOL_RESULT_FAILED", message: cause?.message ?? "MCP tool result could not be represented safely", semanticId: schema.id, details: null }) }), true);
}
}
async function handleMcpRequest(request, environment, executionContext) {
if (request.method !== "POST") return mcpJsonResponse(405, mcpRpcError(null, -32600, "The MCP endpoint accepts POST only"), { allow: "POST" });
const contentType = request.headers.get("content-type")?.split(";", 1)[0].trim().toLowerCase();
if (contentType !== "application/json") return mcpJsonResponse(415, mcpRpcError(null, -32600, "Content-Type must be application/json"));
const accept = request.headers.get("accept") ?? "";
if (!(accept.includes("application/json") && accept.includes("text/event-stream"))) return mcpJsonResponse(406, mcpRpcError(null, -32600, "Accept must include application/json and text/event-stream"));
let payload;
try { payload = JSON.parse(await mcpRequestText(request)); }
catch (cause) { return mcpJsonResponse(cause?.code === "MCP_REQUEST_TOO_LARGE" ? 413 : 400, mcpRpcError(null, -32700, cause?.message ?? "MCP request must be valid JSON")); }
if (payload === null || typeof payload !== "object" || Array.isArray(payload) || payload.jsonrpc !== "2.0" || typeof payload.method !== "string") return mcpJsonResponse(400, mcpRpcError(payload?.id ?? null, -32600, "Invalid JSON-RPC request"));
const notification = !Object.hasOwn(payload, "id");
if (notification) {
return payload.method === "notifications/initialized" || payload.method === "notifications/cancelled"
? mcpJsonResponse(202, null)
: mcpJsonResponse(400, mcpRpcError(null, -32600, "Unsupported MCP notification"));
}
const id = payload.id;
const headerVersion = request.headers.get("mcp-protocol-version");
if (headerVersion !== null && !MCP_PROTOCOL_VERSIONS.includes(headerVersion)) return mcpJsonResponse(400, mcpRpcError(id, -32022, `Unsupported MCP protocol version ${headerVersion}`));
if (payload.method === "initialize") {
const version = payload.params?.protocolVersion;
if (typeof version !== "string" || !MCP_PROTOCOL_VERSIONS.includes(version)) return mcpJsonResponse(400, mcpRpcError(id, -32602, "initialize requires a supported params.protocolVersion"));
if (headerVersion !== null && headerVersion !== version) return mcpJsonResponse(400, mcpRpcError(id, -32020, "MCP-Protocol-Version must match initialize params.protocolVersion"));
return mcpJsonResponse(200, mcpRpcResult(id, Object.freeze({ protocolVersion: version, serverInfo: Object.freeze({ name: "noxid-endpoints", version: "0.1.0" }), capabilities: Object.freeze({ tools: Object.freeze({ listChanged: false }) }) })));
}
if (payload.method === "ping") return mcpJsonResponse(200, mcpRpcResult(id, Object.freeze({})));
if (payload.method === "tools/list") return mcpJsonResponse(200, mcpRpcResult(id, Object.freeze({ tools: mcpTools })));
if (payload.method === "tools/call") {
const name = payload.params?.name;
if (typeof name !== "string") return mcpJsonResponse(400, mcpRpcError(id, -32602, "tools/call requires params.name"));
const schema = mcpEndpointSchemas.find((candidate) => candidate.name === name);
if (!schema) return mcpJsonResponse(404, mcpRpcError(id, -32601, `Unknown endpoint tool ${name}`));
const result = await callMcpEndpointTool(request, schema, payload.params?.arguments ?? Object.freeze({}), environment, executionContext);
return mcpJsonResponse(200, mcpRpcResult(id, result));
}
return mcpJsonResponse(404, mcpRpcError(id, -32601, `Unknown MCP method ${payload.method}`));
}
async function handleAgentSurfaceRequest(request, url, environment, executionContext) {
const prefix = applicationBasePath === "/" ? "" : applicationBasePath.replace(/\/$/, "");
/* noxid-server:agent-run-request */
if (url.pathname === `${prefix}/_noxid/openapi.json`) {
if (!openapiEnabled || openapiDocument === null) return failure(404, "AGENT_SURFACE_DISABLED", "OpenAPI serving is disabled");
if (request.method !== "GET") return failure(405, "OPENAPI_METHOD", "OpenAPI serving requires GET", null, null, { allow: "GET" });
return new Response(openapiDocument, { status: 200, headers: { "content-type": "application/json; charset=utf-8", "cache-control": "no-store", "x-content-type-options": "nosniff" } });
}
if (url.pathname === `${prefix}/_noxid/mcp`) {
if (!mcpEnabled) return failure(404, "AGENT_SURFACE_DISABLED", "MCP serving is disabled");
return handleMcpRequest(request, environment, executionContext);
}
return null;
}
"##;
const QUEUE_RUNTIME: &str = r##"
let queueDatabasePromise;
let queueDatabase;
const QUEUE_POLL_INTERVAL_MS = 250;
function queueSchemaByName(name) {
return queueSchemas.find((schema) => schema.name === name) ?? null;
}
function queueDatabaseUrl() {
const node = globalThis.process?.env?.DATABASE_URL;
if (typeof node === "string" && node.length > 0) return node;
try {
const deno = globalThis.Deno?.env?.get?.("DATABASE_URL");
if (typeof deno === "string" && deno.length > 0) return deno;
} catch {}
return null;
}
async function queueSql() {
if (queueDatabasePromise !== undefined) return queueDatabasePromise;
queueDatabasePromise = (async () => {
const url = queueDatabaseUrl();
if (url === null) throw Object.assign(new Error("DATABASE_URL is required for durable queues"), { code: "QUEUE_DATABASE_URL_REQUIRED" });
let postgres;
try { postgres = (await import("postgres")).default; }
catch { throw Object.assign(new Error("the admitted postgres driver is unavailable"), { code: "QUEUE_POSTGRES_DRIVER_MISSING" }); }
const sql = postgres(url, { max: databasePoolSize });
await sql.unsafe(`CREATE TABLE IF NOT EXISTS _noxid_jobs (
id text PRIMARY KEY,
queue text NOT NULL,
payload jsonb NOT NULL,
principal text,
state text NOT NULL CHECK (state IN ('pending','running','completed','dead-letter')),
attempts integer NOT NULL DEFAULT 0 CHECK (attempts >= 0),
run_at timestamptz NOT NULL,
locked_by text,
locked_at timestamptz,
last_error text,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
)`);
await sql`ALTER TABLE _noxid_jobs ADD COLUMN IF NOT EXISTS principal text`;
await sql.unsafe("CREATE INDEX IF NOT EXISTS _noxid_jobs_claim ON _noxid_jobs (queue, state, run_at, created_at)");
queueDatabase = sql;
return sql;
})();
try { return await queueDatabasePromise; }
catch (error) { queueDatabasePromise = undefined; throw error; }
}
function validateQueuePayload(schema, payload, phase) {
let keys;
try {
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) throw new Error("shape");
const prototype = Object.getPrototypeOf(payload);
if (prototype !== Object.prototype && prototype !== null) throw new Error("prototype");
keys = Reflect.ownKeys(payload);
} catch {
throw Object.assign(new TypeError(`queue ${schema.name} ${phase} payload must be an ordinary object`), { code: phase === "claim" ? "QUEUE_PAYLOAD_DRIFT" : "QUEUE_PAYLOAD_TYPE", semanticId: schema.id });
}
if (keys.some((key) => typeof key !== "string") || keys.some((key) => !schema.payload.some((field) => field.name === key))) {
throw Object.assign(new TypeError(`queue ${schema.name} ${phase} payload has undeclared fields`), { code: phase === "claim" ? "QUEUE_PAYLOAD_DRIFT" : "QUEUE_PAYLOAD_TYPE", semanticId: schema.id });
}
const trusted = Object.create(null);
for (const field of schema.payload) {
let descriptor;
try { descriptor = Object.getOwnPropertyDescriptor(payload, field.name); } catch {}
const optional = field.type.startsWith("Optional<");
if (descriptor === undefined) {
if (optional) { trusted[field.name] = null; continue; }
throw Object.assign(new TypeError(`queue ${schema.name} ${phase} payload is missing ${field.name}`), { code: phase === "claim" ? "QUEUE_PAYLOAD_DRIFT" : "QUEUE_PAYLOAD_TYPE", semanticId: schema.id });
}
if (!("value" in descriptor) || !descriptor.enumerable) {
throw Object.assign(new TypeError(`queue ${schema.name} ${phase} payload field ${field.name} is not ordinary data`), { code: phase === "claim" ? "QUEUE_PAYLOAD_DRIFT" : "QUEUE_PAYLOAD_TYPE", semanticId: schema.id });
}
const result = validateType(field.type, descriptor.value, `payload.${field.name}`, field.typeIds, true);
if (result.issue) throw Object.assign(new TypeError(result.issue), { code: phase === "claim" ? "QUEUE_PAYLOAD_DRIFT" : "QUEUE_PAYLOAD_TYPE", semanticId: schema.id, details: result.details ?? null });
trusted[field.name] = result.value;
}
return Object.freeze(trusted);
}
function queueUtcInstant(value) {
if (typeof value !== "string") return null;
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?Z$/.exec(value);
if (match === null) return null;
const instant = new Date(value);
const milliseconds = Number((match[7] ?? "").padEnd(3, "0"));
return !Number.isNaN(instant.getTime())
&& instant.getUTCFullYear() === Number(match[1])
&& instant.getUTCMonth() + 1 === Number(match[2])
&& instant.getUTCDate() === Number(match[3])
&& instant.getUTCHours() === Number(match[4])
&& instant.getUTCMinutes() === Number(match[5])
&& instant.getUTCSeconds() === Number(match[6])
&& instant.getUTCMilliseconds() === milliseconds
? instant
: null;
}
function queueRunAt(value) {
if (value === undefined) return new Date();
if (typeof value === "string") {
const instant = queueUtcInstant(value);
if (instant !== null) return instant;
} else if (value !== null && typeof value === "object") {
try {
const milliseconds = Date.prototype.getTime.call(value);
if (!Number.isNaN(milliseconds)) return new Date(milliseconds);
} catch {}
}
throw Object.assign(new TypeError("queue runAt must be a valid Date or UTC ISO timestamp"), { code: "QUEUE_RUN_AT_INVALID" });
}
function queueJobId() {
if (typeof globalThis.crypto?.randomUUID === "function") return globalThis.crypto.randomUUID();
throw Object.assign(new Error("durable queue enqueue requires crypto.randomUUID"), { code: "QUEUE_ID_UNAVAILABLE" });
}
export async function enqueue(queue, payload, options = Object.create(null)) {
if (typeof queue !== "string") throw Object.assign(new TypeError("queue name must be a string"), { code: "QUEUE_NAME_INVALID" });
const schema = queueSchemaByName(queue);
if (schema === null) throw Object.assign(new Error("Unknown queue " + queue), { code: "QUEUE_NOT_FOUND" });
let optionKeys;
let runAtDescriptor;
let contextDescriptor;
try {
if (options === null || typeof options !== "object" || Array.isArray(options)) throw new Error("shape");
const prototype = Object.getPrototypeOf(options);
if (prototype !== Object.prototype && prototype !== null) throw new Error("prototype");
optionKeys = Reflect.ownKeys(options);
if (optionKeys.some((key) => key !== "runAt" && key !== "context")) throw new Error("field");
runAtDescriptor = Object.getOwnPropertyDescriptor(options, "runAt");
if (runAtDescriptor !== undefined && (!("value" in runAtDescriptor) || !runAtDescriptor.enumerable)) throw new Error("descriptor");
contextDescriptor = Object.getOwnPropertyDescriptor(options, "context");
if (contextDescriptor !== undefined && (!("value" in contextDescriptor) || !contextDescriptor.enumerable)) throw new Error("descriptor");
}
catch { throw Object.assign(new TypeError("queue options must be an ordinary object"), { code: "QUEUE_OPTIONS_INVALID" }); }
const trusted = validateQueuePayload(schema, payload, "enqueue");
const runAt = queueRunAt(runAtDescriptor?.value);
const captured = contextDescriptor === undefined ? __NOXID_SYSTEM_PRINCIPAL : __noxidRuntimePrincipals.get(contextDescriptor.value);
if (contextDescriptor !== undefined && captured === undefined) {
throw Object.assign(new TypeError("queue context must be a runtime-created execution context"), { code: "QUEUE_PRINCIPAL_CONTEXT_INVALID" });
}
const persistedPrincipal = captured?.canonical === "system" ? null : captured?.canonical;
if (persistedPrincipal !== null && typeof persistedPrincipal !== "string") throw Object.assign(new TypeError("queue context has no canonical principal"), { code: "QUEUE_PRINCIPAL_CONTEXT_INVALID" });
const sql = await queueSql();
const id = queueJobId();
await sql`INSERT INTO _noxid_jobs (id, queue, payload, principal, state, attempts, run_at) VALUES (${id}, ${schema.name}, ${sql.json(trusted)}, ${persistedPrincipal}, 'pending', 0, ${runAt})`;
return Object.freeze({ id, queue: schema.name, state: "pending", attempts: 0, runAt: runAt.toISOString() });
}
async function claimQueueJob(worker, queue = null, now = new Date()) {
const sql = await queueSql();
return sql.begin(async (transaction) => {
const rows = queue === null
? await transaction`SELECT id, queue, payload, principal, attempts, run_at FROM _noxid_jobs WHERE state = 'pending' AND run_at <= ${now} ORDER BY run_at, created_at, id FOR UPDATE SKIP LOCKED LIMIT 1`
: await transaction`SELECT id, queue, payload, principal, attempts, run_at FROM _noxid_jobs WHERE state = 'pending' AND queue = ${queue} AND run_at <= ${now} ORDER BY run_at, created_at, id FOR UPDATE SKIP LOCKED LIMIT 1`;
const row = rows[0];
if (row === undefined) return null;
const schema = queueSchemaByName(row.queue);
if (schema === null) {
await transaction`UPDATE _noxid_jobs SET state = 'dead-letter', last_error = 'QUEUE_DECLARATION_MISSING', locked_by = NULL, locked_at = NULL, updated_at = now() WHERE id = ${row.id}`;
return Object.freeze({ drift: true, id: row.id, code: "QUEUE_DECLARATION_MISSING" });
}
let payload;
try { payload = validateQueuePayload(schema, row.payload, "claim"); }
catch (cause) {
await transaction`UPDATE _noxid_jobs SET state = 'dead-letter', last_error = 'QUEUE_PAYLOAD_DRIFT', locked_by = NULL, locked_at = NULL, updated_at = now() WHERE id = ${row.id}`;
return Object.freeze({ drift: true, id: row.id, queue: schema.name, code: cause?.code ?? "QUEUE_PAYLOAD_DRIFT" });
}
const attempts = Number(row.attempts) + 1;
await transaction`UPDATE _noxid_jobs SET state = 'running', attempts = ${attempts}, locked_by = ${worker}, locked_at = ${now}, updated_at = now() WHERE id = ${row.id}`;
let principal;
try { principal = __noxidPrincipalFromCanonical(row.principal); }
catch (cause) {
await transaction`UPDATE _noxid_jobs SET state = 'dead-letter', last_error = 'QUEUE_PRINCIPAL_DRIFT', locked_by = NULL, locked_at = NULL, updated_at = now() WHERE id = ${row.id}`;
return Object.freeze({ drift: true, id: row.id, queue: schema.name, code: cause?.code ?? "QUEUE_PRINCIPAL_DRIFT" });
}
return Object.freeze({ id: row.id, queue: schema.name, schema, payload, principal, attempts, runAt: new Date(row.run_at).toISOString() });
});
}
async function completeQueueJob(id) {
const sql = await queueSql();
await sql`UPDATE _noxid_jobs SET state = 'completed', locked_by = NULL, locked_at = NULL, last_error = NULL, updated_at = now() WHERE id = ${id}`;
}
async function failQueueJob(job, cause, now) {
const sql = await queueSql();
const message = typeof cause?.message === "string" ? cause.message.slice(0, 4096) : "Queue handler failed";
if (job.attempts <= job.schema.retry) {
const next = new Date(now.getTime() + job.schema.backoffMs);
await sql`UPDATE _noxid_jobs SET state = 'pending', run_at = ${next}, locked_by = NULL, locked_at = NULL, last_error = ${message}, updated_at = now() WHERE id = ${job.id}`;
return Object.freeze({ id: job.id, queue: job.queue, state: "pending", attempts: job.attempts, runAt: next.toISOString() });
}
await sql`UPDATE _noxid_jobs SET state = 'dead-letter', locked_by = NULL, locked_at = NULL, last_error = ${message}, updated_at = now() WHERE id = ${job.id}`;
return Object.freeze({ id: job.id, queue: job.queue, state: "dead-letter", attempts: job.attempts, runAt: job.runAt });
}
function queueWorkerFailure(message) {
throw Object.assign(new TypeError(message), { code: "QUEUE_CLOCK_INVALID" });
}
function queueWorkerOptions(options, allowed) {
let trustedOptions;
try {
if (options === null || typeof options !== "object" || Array.isArray(options)) throw new Error("shape");
const prototype = Object.getPrototypeOf(options);
if (prototype !== Object.prototype && prototype !== null) throw new Error("prototype");
trustedOptions = Object.create(null);
for (const key of Reflect.ownKeys(options)) {
if (typeof key !== "string" || !allowed.has(key)) throw new Error("field");
const descriptor = Object.getOwnPropertyDescriptor(options, key);
if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) throw new Error("descriptor");
trustedOptions[key] = descriptor.value;
}
Object.freeze(trustedOptions);
} catch {
throw Object.assign(new TypeError("worker clock options must be ordinary data"), { code: "QUEUE_CLOCK_INVALID" });
}
return trustedOptions;
}
function queueWorkerIdentity(value, label) {
if (value === undefined || value === null) return null;
if (typeof value !== "string") queueWorkerFailure(`worker ${label} must be a string`);
return value;
}
function queueWorkerClock(value) {
if (value === undefined) return new Date();
if (typeof value === "string") {
const instant = queueUtcInstant(value);
if (instant !== null) return instant;
} else if (value !== null && typeof value === "object") {
try {
const milliseconds = Date.prototype.getTime.call(value);
if (!Number.isNaN(milliseconds)) return new Date(milliseconds);
} catch {}
}
queueWorkerFailure("worker clock must be a valid Date or UTC ISO timestamp");
}
async function workQueueOnceWithLifecycle(options, onRunning) {
const trustedOptions = queueWorkerOptions(options, new Set(["queue", "worker", "now"]));
const queue = queueWorkerIdentity(trustedOptions.queue, "queue");
if (queue !== null && queueSchemaByName(queue) === null) throw Object.assign(new Error("Unknown queue " + queue), { code: "QUEUE_NOT_FOUND" });
const now = queueWorkerClock(trustedOptions.now);
const worker = queueWorkerIdentity(trustedOptions.worker, "identity") ?? `noxid-${globalThis.process?.pid ?? "worker"}-${queueJobId()}`;
const job = await claimQueueJob(worker, queue, now);
if (job === null) return null;
if (job.drift) {
const refusalTrace = tracingMode === "full" ? __noxidTraceContext() : null;
__noxidTraceEmit(refusalTrace, "validation.refused", { code: job.code, jobId: job.id });
throw Object.assign(new Error("Persisted queue payload refused at claim"), { code: job.code, jobId: job.id });
}
const queueSpan = __noxidTraceBeginSemantic(null);
const traceId = queueSpan?.trace?.id ?? null;
const implementation = compiledQueues[job.schema.id] ?? hostQueues[job.schema.id];
if (typeof implementation !== "function") {
__noxidTraceFinishSemantic(queueSpan, "queue", job.schema.id, { jobId: job.id, attempts: job.attempts, spanName: "queue.run" });
return failQueueJob(job, Object.assign(new Error("Queue implementation is missing"), { code: "QUEUE_IMPLEMENTATION_MISSING" }), now);
}
if (onRunning !== null) onRunning(job);
let completed = false;
try {
const value = await implementation(job.payload, __noxidDataContext({ semanticId: job.schema.id, traceId, queue: job.queue, jobId: job.id, attempts: job.attempts, runAt: job.runAt }, job.principal));
await completeQueueJob(job.id);
completed = true;
await __noxidPublishLiveInvalidations(job.schema.invalidates, job.principal);
return Object.freeze({ id: job.id, queue: job.queue, state: "completed", attempts: job.attempts, runAt: job.runAt, value: value === undefined ? null : value });
} catch (cause) {
if (completed) throw cause;
return failQueueJob(job, cause, now);
} finally {
__noxidTraceFinishSemantic(queueSpan, "queue", job.schema.id, { jobId: job.id, attempts: job.attempts, spanName: "queue.run" });
}
}
export async function workQueueOnce(options = Object.create(null)) {
return workQueueOnceWithLifecycle(options, null);
}
const QUEUE_DRAIN_SEMANTIC_ID = "queue-drain:on-demand";
const QUEUE_DRAIN_DEFAULT_BUDGET_MS = 25_000;
const QUEUE_DRAIN_MAX_BUDGET_MS = 300_000;
function queueDrainBudget(executionContext) {
let configured;
try { configured = executionContext?.queueDrainBudgetMs; }
catch { return null; }
if (configured === undefined) return QUEUE_DRAIN_DEFAULT_BUDGET_MS;
return Number.isSafeInteger(configured) && configured > 0 && configured <= QUEUE_DRAIN_MAX_BUDGET_MS
? configured
: null;
}
async function handleQueueDrainRequest(request, url, environment, executionContext) {
if (url.pathname !== queueDrainPath) return null;
let enabled = false;
try { enabled = executionContext?.noxidQueueDrain === true; } catch {}
if (!enabled) return failure(404, "QUEUE_DRAIN_DISABLED", "Queue draining is not enabled for this deployment", QUEUE_DRAIN_SEMANTIC_ID);
if (request.method !== "POST") return failure(405, "QUEUE_DRAIN_METHOD", "Queue draining requires POST", QUEUE_DRAIN_SEMANTIC_ID, null, { allow: "POST" });
const budgetMs = queueDrainBudget(executionContext);
if (budgetMs === null) return failure(500, "QUEUE_DRAIN_BUDGET_INVALID", "The deployment supplied an invalid queue drain budget; configure a positive duration no greater than 300000ms", QUEUE_DRAIN_SEMANTIC_ID);
if (queueSchemas.length === 0) return failure(501, "QUEUE_DRAIN_UNAVAILABLE", "Queue draining requires at least one declared queue", QUEUE_DRAIN_SEMANTIC_ID);
if (typeof authorize !== "function") return failure(500, "QUEUE_DRAIN_AUTHORIZER_MISSING", "Queue draining requires a host authorizer for the queue.drain capability", QUEUE_DRAIN_SEMANTIC_ID, { capability: "queue.drain" });
let allowed = false;
try {
allowed = await authorize(Object.freeze({
capability: "queue.drain",
semanticId: QUEUE_DRAIN_SEMANTIC_ID,
traceId: __noxidTraceIdForRequest(request),
target: "server",
route: null,
request,
environment,
executionContext,
})) === true;
} catch {}
if (!allowed) return failure(403, "QUEUE_DRAIN_CAPABILITY_DENIED", "Queue drain capability was denied", QUEUE_DRAIN_SEMANTIC_ID, { capability: "queue.drain" });
const startedAt = Date.now();
const counts = { claimed: 0, completed: 0, retried: 0, deadLettered: 0 };
try {
while (Date.now() - startedAt < budgetMs) {
const result = await workQueueOnce();
if (result === null) break;
counts.claimed += 1;
if (result.state === "completed") counts.completed += 1;
else if (result.state === "pending") counts.retried += 1;
else if (result.state === "dead-letter") counts.deadLettered += 1;
}
} catch (cause) {
const causeCode = typeof cause?.code === "string" ? cause.code : "QUEUE_DRAIN_EXECUTION_FAILED";
return failure(500, "QUEUE_DRAIN_FAILED", "Queue draining failed; inspect the durable queue database and handler configuration", QUEUE_DRAIN_SEMANTIC_ID, { causeCode });
}
return json(200, {
ok: true,
budgetMs,
elapsedMs: Math.max(0, Date.now() - startedAt),
counts: Object.freeze(counts),
});
}
const QUEUE_WORKER_STATE_NAMES = Object.freeze(["Idle", "Scheduled", "Claiming", "Running", "Stopping", "Stopped", "Failed"]);
const QUEUE_WORKER_EVENT_NAMES = Object.freeze(["Start", "Arm", "Deliver", "Claimed", "Settle", "Stop", "ArmFailed", "Notify"]);
const QUEUE_WORKER_TRANSITIONS = Object.freeze({
Idle: Object.freeze({ Start: "Claiming", Arm: "Scheduled", Deliver: "Idle", Claimed: "Idle", Settle: "Idle", Stop: "Stopped", ArmFailed: "Idle", Notify: "Idle" }),
Scheduled: Object.freeze({ Start: "Scheduled", Arm: "Scheduled", Deliver: "Claiming", Claimed: "Scheduled", Settle: "Scheduled", Stop: "Stopped", ArmFailed: "Failed", Notify: "Scheduled" }),
Claiming: Object.freeze({ Start: "Claiming", Arm: "Claiming", Deliver: "Claiming", Claimed: "Running", Settle: "Idle", Stop: "Stopping", ArmFailed: "Failed", Notify: "Claiming" }),
Running: Object.freeze({ Start: "Running", Arm: "Running", Deliver: "Running", Claimed: "Running", Settle: "Idle", Stop: "Stopping", ArmFailed: "Running", Notify: "Running" }),
Stopping: Object.freeze({ Start: "Stopping", Arm: "Stopping", Deliver: "Stopping", Claimed: "Stopping", Settle: "Stopped", Stop: "Stopping", ArmFailed: "Stopping", Notify: "Stopping" }),
Stopped: Object.freeze({ Start: "Stopped", Arm: "Stopped", Deliver: "Stopped", Claimed: "Stopped", Settle: "Stopped", Stop: "Stopped", ArmFailed: "Stopped", Notify: "Stopped" }),
Failed: Object.freeze({ Start: "Failed", Arm: "Failed", Deliver: "Failed", Claimed: "Failed", Settle: "Failed", Stop: "Failed", ArmFailed: "Failed", Notify: "Failed" }),
});
function queueWorkerState(name, detail = null) {
if (!QUEUE_WORKER_STATE_NAMES.includes(name)) throw new Error(`Unknown queue worker state ${name}`);
return Object.freeze({ name, detail });
}
function queueWorkerEvent(name, detail = null) {
if (!QUEUE_WORKER_EVENT_NAMES.includes(name)) throw new Error(`Unknown queue worker event ${name}`);
return Object.freeze({ name, detail });
}
function queueWorkerTransition(state, event) {
const target = QUEUE_WORKER_TRANSITIONS[state.name]?.[event.name];
if (target === undefined) throw new Error(`Unknown queue worker transition ${state.name} x ${event.name}`);
if (state.name === "Scheduled" && (event.name === "Deliver" || event.name === "ArmFailed") && state.detail !== event.detail?.token) return state;
if (target === state.name) return state;
if (target === "Scheduled") return queueWorkerState(target, event.detail?.token ?? null);
if (target === "Running") return queueWorkerState(target, event.detail?.job ?? null);
if (target === "Failed") return queueWorkerState(target, event.detail?.error ?? null);
return queueWorkerState(target);
}
export function startQueueWorker(options = Object.create(null)) {
const trustedOptions = queueWorkerOptions(options, new Set(["queue", "worker", "now", "setTimeout", "clearTimeout", "pollIntervalMs", "onError"]));
const queue = queueWorkerIdentity(trustedOptions.queue, "queue");
if (queue !== null && queueSchemaByName(queue) === null) throw Object.assign(new Error("Unknown queue " + queue), { code: "QUEUE_NOT_FOUND" });
const worker = queueWorkerIdentity(trustedOptions.worker, "identity");
const claimOptions = Object.create(null);
if (queue !== null) claimOptions.queue = queue;
if (worker !== null) claimOptions.worker = worker;
if (trustedOptions.now !== undefined) claimOptions.now = queueWorkerClock(trustedOptions.now);
Object.freeze(claimOptions);
const setTimer = trustedOptions.setTimeout ?? globalThis.setTimeout;
const clearTimer = trustedOptions.clearTimeout ?? globalThis.clearTimeout;
const interval = trustedOptions.pollIntervalMs ?? QUEUE_POLL_INTERVAL_MS;
const onError = trustedOptions.onError ?? console.error;
if (typeof setTimer !== "function") queueWorkerFailure("worker setTimeout must be callable");
if (typeof clearTimer !== "function") queueWorkerFailure("worker clearTimeout must be callable");
if (typeof onError !== "function") queueWorkerFailure("worker onError must be callable");
if (!Number.isSafeInteger(interval) || interval <= 0) queueWorkerFailure("worker pollIntervalMs must be a positive integer");
let state = queueWorkerState("Idle");
let queueSemanticId = queue === null ? null : queueSchemaByName(queue).id;
const workerTrace = tracingMode === "full" ? __noxidTraceContext() : null;
const transition = (event) => {
const previous = state;
const next = queueWorkerTransition(state, event);
if (next === previous) return next;
if (event.name === "Claimed" && typeof event.detail?.job?.schema?.id === "string") queueSemanticId = event.detail.job.schema.id;
__noxidTraceEmit(workerTrace, "queue.state", {
semanticId: queueSemanticId,
state: next.name,
transition: event.name,
jobId: event.detail?.job?.id,
attempts: event.detail?.job?.attempts,
});
return next;
};
let nextTimerToken = 0;
let activeAttempt = null;
let stopJoin = null;
const settledJoin = Promise.resolve();
const hookFailure = (cause) => { try { console.error(cause); } catch {} };
const observeHookResult = (result) => {
Promise.resolve(result).catch(hookFailure);
};
const clearToken = (token) => {
if (token.delivered || token.clearInvoked) return;
token.cancelled = true;
token.consumed = true;
if (!token.handleReady) return;
token.clearInvoked = true;
try { observeHookResult(clearTimer(token.handle)); }
catch (cause) { hookFailure(cause); }
};
const notify = (error) => {
try { observeHookResult(onError(error)); }
catch (cause) { hookFailure(cause); }
};
const settleAttempt = (attempt, error) => {
if (activeAttempt !== attempt || attempt.settled) return;
attempt.settled = true;
state = transition(queueWorkerEvent("Settle"));
activeAttempt = null;
if (error !== null) notify(error);
if (state.name === "Idle") arm();
attempt.resolveJoin();
};
const reserveAttempt = () => {
let resolveJoin;
const attempt = { settled: false, join: new Promise((resolve) => { resolveJoin = resolve; }), resolveJoin: null };
attempt.resolveJoin = resolveJoin;
activeAttempt = attempt;
return attempt;
};
const launchAttempt = (attempt) => {
if (attempt.settled) return;
let result;
try {
result = workQueueOnceWithLifecycle(claimOptions, (job) => {
if (activeAttempt === attempt && !attempt.settled) state = transition(queueWorkerEvent("Claimed", { job }));
});
} catch (cause) {
settleAttempt(attempt, cause);
return;
}
Promise.resolve(result).then(
() => settleAttempt(attempt, null),
(cause) => settleAttempt(attempt, cause),
);
};
const beginAttempt = (event, deferLaunch = false) => {
const previous = state;
state = transition(event);
if (previous === state || state.name !== "Claiming") return null;
const attempt = reserveAttempt();
if (!deferLaunch) launchAttempt(attempt);
return attempt;
};
function arm() {
if (state.name !== "Idle") return;
const token = { id: ++nextTimerToken, consumed: false, delivered: false, cancelled: false, handleReady: false, handle: null, clearInvoked: false };
state = transition(queueWorkerEvent("Arm", { token }));
let synchronousAttempt = null;
let arming = true;
const fire = () => {
if (token.consumed || state.name !== "Scheduled" || state.detail !== token) return;
token.consumed = true;
token.delivered = true;
const attempt = beginAttempt(queueWorkerEvent("Deliver", { token }), arming);
if (arming) synchronousAttempt = attempt;
};
let handle;
try {
handle = setTimer(fire, interval);
observeHookResult(handle);
} catch (cause) {
arming = false;
token.consumed = true;
state = transition(queueWorkerEvent("ArmFailed", { token, error: cause }));
if (synchronousAttempt !== null && state.name === "Failed") {
synchronousAttempt.settled = true;
activeAttempt = null;
synchronousAttempt.resolveJoin();
synchronousAttempt = null;
}
hookFailure(cause);
if (synchronousAttempt !== null) launchAttempt(synchronousAttempt);
return;
}
arming = false;
token.handle = handle;
token.handleReady = true;
if (token.cancelled) clearToken(token);
if (synchronousAttempt !== null) launchAttempt(synchronousAttempt);
}
/* noxid-server:agent-run-reconcile */
beginAttempt(queueWorkerEvent("Start"));
return Object.freeze({
stop() {
if (state.name === "Stopping" || state.name === "Stopped" || state.name === "Failed") return stopJoin ?? settledJoin;
if (state.name === "Scheduled") {
const token = state.detail;
state = transition(queueWorkerEvent("Stop"));
clearToken(token);
stopJoin = settledJoin;
return stopJoin;
}
if (state.name === "Idle") {
state = transition(queueWorkerEvent("Stop"));
stopJoin = settledJoin;
return stopJoin;
}
if (state.name === "Claiming" || state.name === "Running") {
state = transition(queueWorkerEvent("Stop"));
stopJoin = activeAttempt?.join ?? settledJoin;
return stopJoin;
}
return settledJoin;
},
});
}
export async function queueStatus(queue = null) {
if (queue !== null && queueSchemaByName(queue) === null) throw Object.assign(new Error("Unknown queue " + queue), { code: "QUEUE_NOT_FOUND" });
const sql = await queueSql();
const rows = queue === null
? await sql`SELECT queue, state, count(*)::int AS count FROM _noxid_jobs GROUP BY queue, state ORDER BY queue, state`
: await sql`SELECT queue, state, count(*)::int AS count FROM _noxid_jobs WHERE queue = ${queue} GROUP BY queue, state ORDER BY queue, state`;
return Object.freeze(rows.map((row) => Object.freeze({ queue: row.queue, state: row.state, count: Number(row.count) })));
}
export async function closeQueueDatabase() {
if (queueDatabase !== undefined) await queueDatabase.end({ timeout: 1 });
queueDatabase = undefined;
queueDatabasePromise = undefined;
}
globalThis.__NOXID_QUEUE_ENQUEUE__ = enqueue;
"##;
/// The WO-30 model boundary.
///
/// Everything the provider call needs is a compile-time constant emitted above
/// this block: the transport, the model id, the retry cap, the request schema.
/// The only runtime lookup is the declared secret, read one name at a time so a
/// missing model credential fails exactly the request that reached for it
/// instead of every request that touches `environment.secrets`.
///
/// No SDK: two hand-written HTTPS clients over `fetch`, which is the whole
/// dependency surface. Prompt and completion text never reach a span, and a
/// provider error body never reaches an error message.
const MODEL_RUNTIME: &str = r##"
const MODEL_ANTHROPIC_VERSION = "2023-06-01";
const MODEL_DEFAULT_MAX_TOKENS = 1024;
const MODEL_PROVIDER_CODE = /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/;
const MODEL_STRUCTURED_TOOL = "noxid_structured_result";
function modelError(code, message, detail = null) {
const error = new Error(message);
error.code = code;
if (detail !== null) error.detail = detail;
return error;
}
function modelDefinitionFor(handle) {
const name = typeof handle === "string" ? handle : handle?.model ?? null;
if (typeof name === "string" && Object.hasOwn(modelDeclarations, name)) return modelDeclarations[name];
throw modelError(
"MODEL_NOT_DECLARED",
`no model \`${typeof name === "string" ? name : String(handle)}\` is declared; import { models } from "noxid:server" and pass models.<Name> for a model declared under server/models/<name>.nox`,
);
}
// One declared name at a time, never the whole allowlist: an unrelated missing
// secret must not fail a request that never asked for it.
function modelSecret(definition, name) {
const value = globalThis.process?.env?.[name];
if (typeof value !== "string" || value.length === 0) {
throw modelError(
"MODEL_SECRET_MISSING",
`model \`${definition.name}\` requires the declared secret ${name}, which is absent from the environment; only requests that call this model fail`,
);
}
return value;
}
function modelBaseUrl(definition) {
const declared = definition.baseUrl.kind === "secret"
? modelSecret(definition, definition.baseUrl.value)
: definition.baseUrl.value;
let parsed;
try { parsed = new URL(declared); } catch {
throw modelError("MODEL_PROVIDER_ERROR", `model \`${definition.name}\` has a base URL that is not a valid absolute URL`);
}
const loopback = parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1" || parsed.hostname === "[::1]" || parsed.hostname === "::1";
if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && loopback)) {
throw modelError("MODEL_PROVIDER_ERROR", `model \`${definition.name}\` resolved a non-https base URL; a model credential may only travel over https, or over http to a loopback host`);
}
return `${parsed.origin}${parsed.pathname.replace(/\/$/, "")}`;
}
function modelTypeSchemaFor(definition, handle) {
const name = typeof handle === "string" ? handle : handle?.type ?? null;
const key = typeof name === "string" ? `type:${name}` : null;
const entry = key !== null && Object.hasOwn(modelTypeSchemas, key) ? modelTypeSchemas[key] : null;
if (entry === null) {
throw modelError(
"MODEL_OUTPUT_SCHEMA_UNSUPPORTED",
`model \`${definition.name}\` cannot generate \`${typeof name === "string" ? name : String(handle)}\`: it is not a declared type with a strict structured-output schema; import { types } from "noxid:server" and pass types.<TypeName> for a type this build declares`,
);
}
const validator = typeValidators[`type:${name}`] ?? typeValidators[`validator:${name}`] ?? null;
if (validator === null) {
throw modelError(
"MODEL_OUTPUT_SCHEMA_UNSUPPORTED",
`model \`${definition.name}\` cannot generate \`${name}\`: this build emits no boundary validator for it, and model output is never accepted unvalidated`,
);
}
return Object.freeze({ name, schema: entry.schema, validator });
}
function modelUsage(input, output) {
return Object.freeze({
inputTokens: Number.isSafeInteger(input) && input >= 0 ? input : 0,
outputTokens: Number.isSafeInteger(output) && output >= 0 ? output : 0,
});
}
function modelTraceFields(definition, usage, retries, durationMs, code) {
const fields = {
semanticId: definition.id,
model: definition.name,
modelProvider: definition.provider,
modelId: definition.modelId,
tokensInput: usage.inputTokens,
tokensOutput: usage.outputTokens,
modelRetries: retries,
durationMs,
};
if (code !== null) fields.code = code;
return fields;
}
// Prompts, options, and completions are never presented to the serializer:
// only the allowlisted identity, token, retry, and latency fields above.
function modelTrace(request, definition, usage, retries, durationMs, code = null) {
let trace = __noxidTraceForRequest(request ?? null);
if (trace === null && tracingMode === "full") trace = __noxidTraceContext();
__noxidTraceEmit(trace, "model.generate", modelTraceFields(definition, usage, retries, durationMs, code));
}
function modelOptions(options) {
if (options === undefined || options === null) return Object.freeze({});
if (typeof options !== "object") throw modelError("MODEL_OPTIONS_INVALID", "model options must be an object with optional temperature, maxTokens, system, signal, and request");
const unknown = Object.keys(options).filter((key) => !["temperature", "maxTokens", "system", "signal", "request"].includes(key));
if (unknown.length !== 0) throw modelError("MODEL_OPTIONS_INVALID", `model option \`${unknown[0]}\` is unknown; use temperature, maxTokens, system, signal, or request`);
if (options.temperature !== undefined && (typeof options.temperature !== "number" || !Number.isFinite(options.temperature) || options.temperature < 0 || options.temperature > 2)) {
throw modelError("MODEL_OPTIONS_INVALID", "model option `temperature` must be a number between 0 and 2");
}
if (options.maxTokens !== undefined && (!Number.isSafeInteger(options.maxTokens) || options.maxTokens <= 0)) {
throw modelError("MODEL_OPTIONS_INVALID", "model option `maxTokens` must be a positive whole number");
}
if (options.system !== undefined && typeof options.system !== "string") {
throw modelError("MODEL_OPTIONS_INVALID", "model option `system` must be a string");
}
return options;
}
function modelPrompt(definition, prompt) {
if (typeof prompt !== "string" || prompt.length === 0) {
throw modelError("MODEL_PROMPT_INVALID", `model \`${definition.name}\` requires a non-empty string prompt; message-array prompts are not part of this boundary`);
}
return prompt;
}
function modelTemperature(definition, options) {
if (options.temperature !== undefined) return options.temperature;
return definition.temperature === null ? undefined : definition.temperature;
}
function modelMaxTokens(definition, options) {
if (options.maxTokens !== undefined) return options.maxTokens;
return definition.maxTokens === null ? MODEL_DEFAULT_MAX_TOKENS : definition.maxTokens;
}
// Each provider names its own failures in a different field: Anthropic in
// `error.type`, OpenAI-compatible endpoints in `error.code`. Only a value that
// looks like a code survives — an error *message* may quote the prompt back.
function modelProviderCode(definition, payload) {
const code = definition.provider === "anthropic"
? payload?.error?.type ?? null
: payload?.error?.code ?? payload?.error?.type ?? null;
return typeof code === "string" && MODEL_PROVIDER_CODE.test(code) ? code : null;
}
// The provider's response body may quote the prompt back at us, so it never
// reaches the error: status plus the provider's own error code, nothing else.
async function modelRefuseResponse(definition, response) {
let code = null;
try { code = modelProviderCode(definition, await response.json()); } catch {}
throw modelError(
"MODEL_PROVIDER_ERROR",
`model \`${definition.name}\` was refused by its ${definition.provider} endpoint with status ${response.status}${code === null ? "" : ` (${code})`}`,
);
}
async function modelSend(definition, path, headers, body, signal, stream = false) {
const url = `${modelBaseUrl(definition)}${path}`;
let response;
try {
// `globalThis.fetch` explicitly: this module exports its own `fetch` as
// the request handler, and a bare call would reach that instead.
response = await globalThis.fetch(url, {
method: "POST",
headers: { "content-type": "application/json", ...headers },
body: JSON.stringify(body),
signal: signal ?? undefined,
});
} catch (cause) {
if (cause?.name === "AbortError" || cause?.name === "TimeoutError") {
throw modelError("MODEL_TIMEOUT", `model \`${definition.name}\` was cancelled before its ${definition.provider} call completed`);
}
throw modelError("MODEL_PROVIDER_ERROR", `model \`${definition.name}\` could not reach its ${definition.provider} endpoint`);
}
if (!response.ok) await modelRefuseResponse(definition, response);
if (stream) return response;
try { return await response.json(); } catch {
throw modelError("MODEL_PROVIDER_ERROR", `model \`${definition.name}\` returned a body its ${definition.provider} transport could not decode as JSON`);
}
}
function anthropicHeaders(definition) {
return { "x-api-key": modelSecret(definition, definition.secret), "anthropic-version": MODEL_ANTHROPIC_VERSION };
}
function openaiHeaders(definition) {
return { authorization: `Bearer ${modelSecret(definition, definition.secret)}` };
}
function anthropicBody(definition, prompt, options, stream) {
const body = {
model: definition.modelId,
max_tokens: modelMaxTokens(definition, options),
messages: [{ role: "user", content: prompt }],
};
const temperature = modelTemperature(definition, options);
if (temperature !== undefined) body.temperature = temperature;
if (typeof options.system === "string") body.system = options.system;
if (stream) body.stream = true;
return body;
}
function openaiBody(definition, prompt, options, stream) {
const messages = [];
if (typeof options.system === "string") messages.push({ role: "system", content: options.system });
messages.push({ role: "user", content: prompt });
const body = { model: definition.modelId, messages, max_tokens: modelMaxTokens(definition, options) };
const temperature = modelTemperature(definition, options);
if (temperature !== undefined) body.temperature = temperature;
if (stream) {
body.stream = true;
body.stream_options = { include_usage: true };
}
return body;
}
function anthropicText(payload) {
const blocks = Array.isArray(payload?.content) ? payload.content : [];
return blocks.filter((block) => block?.type === "text" && typeof block.text === "string").map((block) => block.text).join("");
}
function anthropicToolInput(payload) {
const blocks = Array.isArray(payload?.content) ? payload.content : [];
const block = blocks.find((candidate) => candidate?.type === "tool_use" && candidate?.name === MODEL_STRUCTURED_TOOL);
return block === undefined ? undefined : block.input;
}
function anthropicUsage(payload) {
return modelUsage(payload?.usage?.input_tokens, payload?.usage?.output_tokens);
}
function openaiUsage(payload) {
return modelUsage(payload?.usage?.prompt_tokens, payload?.usage?.completion_tokens);
}
async function modelProviderText(definition, prompt, options) {
if (definition.provider === "anthropic") {
const payload = await modelSend(definition, "/v1/messages", anthropicHeaders(definition), anthropicBody(definition, prompt, options, false), options.signal);
return Object.freeze({ text: anthropicText(payload), usage: anthropicUsage(payload) });
}
const payload = await modelSend(definition, "/v1/chat/completions", openaiHeaders(definition), openaiBody(definition, prompt, options, false), options.signal);
const content = payload?.choices?.[0]?.message?.content;
return Object.freeze({ text: typeof content === "string" ? content : "", usage: openaiUsage(payload) });
}
// Structured output is a forced tool on Anthropic and a strict `json_schema`
// response format on OpenAI-compatible endpoints. Both are requests, not
// guarantees: the answer still goes through the boundary validator.
async function modelProviderObject(definition, prompt, schema, options) {
if (definition.provider === "anthropic") {
const body = anthropicBody(definition, prompt, options, false);
body.tools = [{ name: MODEL_STRUCTURED_TOOL, description: `Return the ${schema.name} result.`, input_schema: schema.schema }];
body.tool_choice = { type: "tool", name: MODEL_STRUCTURED_TOOL };
const payload = await modelSend(definition, "/v1/messages", anthropicHeaders(definition), body, options.signal);
return Object.freeze({ value: anthropicToolInput(payload), usage: anthropicUsage(payload) });
}
const body = openaiBody(definition, prompt, options, false);
body.response_format = { type: "json_schema", json_schema: { name: schema.name, strict: true, schema: schema.schema } };
const payload = await modelSend(definition, "/v1/chat/completions", openaiHeaders(definition), body, options.signal);
const content = payload?.choices?.[0]?.message?.content;
let value;
try { value = typeof content === "string" ? JSON.parse(content) : undefined; } catch { value = undefined; }
return Object.freeze({ value, usage: openaiUsage(payload) });
}
async function* modelSseEvents(definition, response, signal) {
const reader = response.body?.getReader();
if (reader === undefined) throw modelError("MODEL_PROVIDER_ERROR", `model \`${definition.name}\` returned a stream with no readable body`);
const decoder = new TextDecoder();
let buffer = "";
try {
for (;;) {
if (signal?.aborted) throw modelError("MODEL_TIMEOUT", `model \`${definition.name}\` stream was cancelled`);
const chunk = await reader.read();
if (chunk.done) break;
buffer += decoder.decode(chunk.value, { stream: true });
let boundary = buffer.indexOf("\n\n");
while (boundary !== -1) {
const frame = buffer.slice(0, boundary);
buffer = buffer.slice(boundary + 2);
const data = frame.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim()).join("");
if (data.length !== 0 && data !== "[DONE]") {
try { yield JSON.parse(data); } catch {}
}
boundary = buffer.indexOf("\n\n");
}
}
} finally {
try { await reader.cancel(); } catch {}
}
}
async function* modelProviderStream(definition, prompt, options) {
let input = 0;
let output = 0;
if (definition.provider === "anthropic") {
const response = await modelSend(definition, "/v1/messages", anthropicHeaders(definition), anthropicBody(definition, prompt, options, true), options.signal, true);
for await (const event of modelSseEvents(definition, response, options.signal)) {
if (event?.type === "message_start") input = event?.message?.usage?.input_tokens ?? input;
if (event?.type === "content_block_delta" && typeof event?.delta?.text === "string") yield Object.freeze({ delta: event.delta.text });
if (event?.type === "message_delta") output = event?.usage?.output_tokens ?? output;
}
return modelUsage(input, output);
}
const response = await modelSend(definition, "/v1/chat/completions", openaiHeaders(definition), openaiBody(definition, prompt, options, true), options.signal, true);
for await (const event of modelSseEvents(definition, response, options.signal)) {
const delta = event?.choices?.[0]?.delta?.content;
if (typeof delta === "string" && delta.length !== 0) yield Object.freeze({ delta });
if (event?.usage) {
input = event.usage.prompt_tokens ?? input;
output = event.usage.completion_tokens ?? output;
}
}
return modelUsage(input, output);
}
async function modelGenerateText(handle, prompt, options) {
const definition = modelDefinitionFor(handle);
const resolved = modelOptions(options);
const text = modelPrompt(definition, prompt);
const started = Date.now();
const controller = modelScenarioController();
try {
const result = controller === null
? await modelProviderText(definition, text, resolved)
: controller.text(definition);
modelTrace(resolved.request, definition, result.usage, 0, Date.now() - started);
return Object.freeze({ text: result.text, usage: result.usage });
} catch (cause) {
modelTrace(resolved.request, definition, modelUsage(0, 0), 0, Date.now() - started, cause?.code ?? "MODEL_PROVIDER_ERROR");
throw cause;
}
}
async function modelGenerateObject(handle, prompt, type, options) {
const definition = modelDefinitionFor(handle);
const resolved = modelOptions(options);
const text = modelPrompt(definition, prompt);
const schema = modelTypeSchemaFor(definition, type);
const started = Date.now();
const controller = modelScenarioController();
let input = 0;
let output = 0;
let retries = 0;
let detail = null;
try {
for (;;) {
const result = controller === null
? await modelProviderObject(definition, text, schema, resolved)
: controller.object(definition);
input += result.usage.inputTokens;
output += result.usage.outputTokens;
try {
const value = schema.validator(result.value, true);
const usage = modelUsage(input, output);
modelTrace(resolved.request, definition, usage, retries, Date.now() - started);
return Object.freeze({ value, usage });
} catch (cause) {
detail = cause?.message ?? String(cause);
// The retry cap is declared, not adaptive: past it the shape is wrong,
// not unlucky, and looping would only spend tokens. `retries: N` counts
// re-attempts *after* the first attempt, so a call makes at most N + 1
// provider attempts, and the refusal states both numbers rather than
// leaving the reader to guess which one `retries` meant.
if (retries >= definition.retries) {
const attempts = retries + 1;
throw modelError(
"MODEL_OUTPUT_INVALID",
`model \`${definition.name}\` returned output that failed \`${schema.name}\` validation after ${retries} ${retries === 1 ? "retry" : "retries"} (${attempts} ${attempts === 1 ? "attempt" : "attempts"}); the boundary validator refused it`,
detail,
);
}
retries += 1;
}
}
} catch (cause) {
modelTrace(resolved.request, definition, modelUsage(input, output), retries, Date.now() - started, cause?.code ?? "MODEL_PROVIDER_ERROR");
throw cause;
}
}
function modelStreamText(handle, prompt, options) {
const definition = modelDefinitionFor(handle);
const resolved = modelOptions(options);
const text = modelPrompt(definition, prompt);
const controller = modelScenarioController();
return {
async *[Symbol.asyncIterator]() {
const started = Date.now();
try {
const source = controller === null
? modelProviderStream(definition, text, resolved)
: controller.tokens(definition);
let usage = modelUsage(0, 0);
for (;;) {
const step = await source.next();
if (step.done) {
usage = step.value ?? usage;
break;
}
yield step.value;
}
modelTrace(resolved.request, definition, usage, 0, Date.now() - started);
yield Object.freeze({ usage });
} catch (cause) {
modelTrace(resolved.request, definition, modelUsage(0, 0), 0, Date.now() - started, cause?.code ?? "MODEL_PROVIDER_ERROR");
throw cause;
}
},
};
}
globalThis.__NOXID_MODEL_RUNTIME__ = Object.freeze({
generateText: modelGenerateText,
generateObject: modelGenerateObject,
streamText: modelStreamText,
declarations: modelDeclarations,
});
"##;
/// The scenario side of the boundary. Under `noxid test` the harness installs
/// `globalThis.__NOXID_MODEL_SCENARIO__`; while it is installed the model
/// runtime performs no I/O at all, and a call with no stub fails closed with
/// the stubbing syntax rather than reaching a provider.
const MODEL_SCENARIO_RUNTIME: &str = r##"
function modelScenarioController() {
const controller = globalThis.__NOXID_MODEL_SCENARIO__;
if (controller === undefined || controller === null) return null;
// The refusal names the call site, not just the model: one endpoint may call
// several models, and the same model several times, so "which call" is the
// part a reader cannot reconstruct from the message alone.
const site = typeof controller.callSite === "string" && controller.callSite.length !== 0
? ` at call site \`${controller.callSite}\``
: "";
const take = (definition, kind) => {
const stub = typeof controller.take === "function" ? controller.take(definition.name, kind) : null;
if (stub === null || stub === undefined) {
throw modelError(
"MODEL_STUB_REQUIRED",
`scenario called model \`${definition.name}\`${site} with no stub left; add \`given model ${definition.name} = text "..."\`, \`= object <Type>(field = value)\`, \`= tokens ["a", "b"]\`, or \`= fails MODEL_PROVIDER_ERROR\` to the scenario`,
);
}
if (stub.kind === "fails") throw modelError(stub.code, `scenario stub for model \`${definition.name}\`${site} fails with ${stub.code}`);
if (stub.kind !== kind) {
throw modelError(
"MODEL_STUB_REQUIRED",
`scenario stubbed model \`${definition.name}\`${site} with a ${stub.kind} stub, but the call needs a ${kind} stub; declare the stub shape the call actually consumes`,
);
}
return stub;
};
return Object.freeze({
text(definition) {
const stub = take(definition, "text");
return Object.freeze({ text: stub.text, usage: modelUsage(stub.inputTokens, stub.outputTokens) });
},
object(definition) {
const stub = take(definition, "object");
return Object.freeze({ value: stub.value, usage: modelUsage(stub.inputTokens, stub.outputTokens) });
},
async *tokens(definition) {
const stub = take(definition, "tokens");
for (const token of stub.tokens) yield Object.freeze({ delta: token });
return modelUsage(stub.inputTokens, stub.outputTokens);
},
});
}
"##;
const LIVE_RESOURCE_RUNTIME: &str = r##"
const LIVE_RESOURCE_SCHEMA = Object.freeze({
id: "live-resource:connection",
name: "LiveResourceConnection",
path: liveResourcePath,
method: "GET",
middleware: Object.freeze([]),
timeoutMs: 30_000,
});
const LIVE_RESOURCE_MAX_HISTORIES = 128;
const LIVE_RESOURCE_MAX_EVENTS = 256;
const LIVE_RESOURCE_MAX_HISTORY_BYTES = 1_048_576;
const LIVE_RESOURCE_TOKEN = /^[A-Za-z0-9_-]{16,128}$/;
const liveResourceSchemaById = new Map(liveResourceSchemas.map((schema) => [schema.id, schema]));
const presenceSchemaById = new Map(presenceSchemas.map((schema) => [schema.id, schema]));
const liveResourceHistories = new Map();
const liveResourceEncoder = new TextEncoder();
function liveResourceResetResponse(headers = []) {
const responseHeaders = new Headers({
"content-type": "text/event-stream; charset=utf-8",
"cache-control": "no-store",
"x-content-type-options": "nosniff",
});
for (const [name, value] of headers) responseHeaders.append(name, value);
return new Response("event: noxid-live-reset\ndata: null\n\n", { status: 200, headers: responseHeaders });
}
function liveResourceCursor(value) {
if (typeof value !== "string" || value.length === 0 || value.length > 160) return null;
const separator = value.lastIndexOf(":");
if (separator < 0) return null;
const token = value.slice(0, separator);
const sequenceText = value.slice(separator + 1);
if (!LIVE_RESOURCE_TOKEN.test(token) || !/^[1-9]\d{0,15}$/.test(sequenceText)) return null;
const sequence = Number(sequenceText);
return Number.isSafeInteger(sequence) ? Object.freeze({ token, sequence }) : null;
}
function liveResourceToken() {
let token;
try { token = globalThis.crypto?.randomUUID?.().replaceAll("-", "_"); } catch {}
if (typeof token !== "string" || !LIVE_RESOURCE_TOKEN.test(token)) {
token = `${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}_${Math.random().toString(36).slice(2)}`;
}
return token.padEnd(16, "0").slice(0, 128);
}
const PRESENCE_CREDENTIAL = /^[A-Za-z0-9_-]{16,128}$/;
const PRESENCE_STORAGE_SCHEMA = "noxid.presence.member.v1";
const PRESENCE_INDEX_SCHEMA = "noxid.presence.expiry.v1";
const PRESENCE_MAX_MEMBERS = 256;
const PRESENCE_JOINS_PER_MINUTE = 120;
const PRESENCE_MEMBER_WRITES_PER_MINUTE = 600;
const PRESENCE_ABUSE_ATTEMPTS_PER_MINUTE = 1200;
const PRESENCE_MAX_DELTA_BYTES = 6_000;
const PRESENCE_MAX_SNAPSHOT_BYTES = 65_536;
const PRESENCE_SWEEP_BATCH = 128;
const presenceMemberStorage = presenceSchemas.length === 0 ? null : __noxidStorage(`noxid:presence:${applicationNamespace}:members`);
const presenceExpiryStorage = presenceSchemas.length === 0 ? null : __noxidStorage(`noxid:presence:${applicationNamespace}:expiry`);
const presenceLocalLocks = new Map();
const presenceLocalRates = new Map();
function presenceSseFrame(schema, event) {
return `event: noxid-presence-event\ndata: ${JSON.stringify({ presence: schema.id, event })}\n\n`;
}
function presenceSseFrameBytes(schema, event) {
return liveResourceEncoder.encode(presenceSseFrame(schema, event)).byteLength;
}
async function presenceDigest(...parts) {
if (typeof globalThis.crypto?.subtle?.digest !== "function") {
throw Object.assign(new Error("Presence credentials require Web Crypto SHA-256"), { code: "PRESENCE_CRYPTO_UNAVAILABLE" });
}
const bytes = await globalThis.crypto.subtle.digest("SHA-256", liveResourceEncoder.encode([applicationNamespace, ...parts].join("\n")));
return [...new Uint8Array(bytes)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
}
function presenceDigestEqual(left, right) {
if (typeof left !== "string" || typeof right !== "string" || left.length !== right.length) return false;
let difference = 0;
for (let index = 0; index < left.length; index += 1) difference |= left.charCodeAt(index) ^ right.charCodeAt(index);
return difference === 0;
}
async function presenceLocalLock(key, operation, signal = null) {
const previous = presenceLocalLocks.get(key) ?? Promise.resolve();
let release;
const current = new Promise((resolve) => { release = resolve; });
presenceLocalLocks.set(key, current);
const releaseAfterPrevious = () => previous.finally(() => {
release();
if (presenceLocalLocks.get(key) === current) presenceLocalLocks.delete(key);
});
if (signal?.aborted) {
void releaseAfterPrevious();
throw presenceFailure("PRESENCE_OPERATION_ABORTED", "Presence operation was cancelled while waiting for its partition");
}
if (signal !== null) {
let onAbort;
const aborted = new Promise((resolve) => {
onAbort = () => resolve(false);
signal.addEventListener("abort", onAbort, { once: true });
});
const acquired = await Promise.race([previous.then(() => true), aborted]);
signal.removeEventListener("abort", onAbort);
if (!acquired) {
void releaseAfterPrevious();
throw presenceFailure("PRESENCE_OPERATION_ABORTED", "Presence operation was cancelled while waiting for its partition");
}
} else {
await previous;
}
try { return await operation(); }
finally {
release();
if (presenceLocalLocks.get(key) === current) presenceLocalLocks.delete(key);
}
}
async function presencePartitionLock(schema, canonical, routeId, routePath, operation, signal = null) {
const digest = await presenceDigest(schema.id, canonical, routeId, routePath);
const key = `presence-lock:${digest}`;
return presenceLocalLock(key, async () => {
if (signal?.aborted) throw presenceFailure("PRESENCE_OPERATION_ABORTED", "Presence operation exceeded its bounded lifetime");
if (typeof __noxidSharedIdempotencyPrepare !== "function" || typeof __noxidSharedIdempotencyRelease !== "function") {
const value = await operation();
if (signal?.aborted) throw presenceFailure("PRESENCE_OPERATION_ABORTED", "Presence operation exceeded its bounded lifetime");
return value;
}
if (typeof globalThis.crypto?.randomUUID !== "function") throw presenceFailure("PRESENCE_CRYPTO_UNAVAILABLE", "Presence partition locks require secure random claims");
const claim = globalThis.crypto.randomUUID();
const leaseMilliseconds = LIVE_RESOURCE_SCHEMA.timeoutMs + 5_000;
for (;;) {
if (signal?.aborted) throw presenceFailure("PRESENCE_OPERATION_ABORTED", "Presence operation exceeded its bounded lifetime");
const prepared = await __noxidSharedIdempotencyPrepare(key, claim, leaseMilliseconds);
if (prepared?.state === "owner") break;
if (prepared?.state !== "pending") throw presenceFailure("PRESENCE_LOCK_INVALID", "Presence partition lock returned an invalid shared state");
await new Promise((resolve) => setTimeout(resolve, 5));
}
let lost = false;
let renewing = false;
let renewalPromise = Promise.resolve();
const renewal = setInterval(() => {
if (renewing || lost) return;
renewing = true;
renewalPromise = __noxidSharedIdempotencyPrepare(key, claim, leaseMilliseconds)
.then((value) => { if (value?.state !== "owner") lost = true; }, () => { lost = true; })
.finally(() => { renewing = false; });
}, Math.floor(leaseMilliseconds / 3));
renewal?.unref?.();
try {
const value = await operation();
if (lost || signal?.aborted) throw presenceFailure("PRESENCE_OPERATION_ABORTED", "Presence partition lock ownership was not retained through commit");
return value;
} finally {
clearInterval(renewal);
await renewalPromise;
await __noxidSharedIdempotencyRelease(key, claim);
}
}, signal);
}
async function presencePartition(schema, canonical, routeId, routePath) {
return `partition:${await presenceDigest(schema.id, canonical, routeId, routePath)}:`;
}
async function presenceMemberKey(schema, canonical, routeId, routePath, memberId) {
return `member:${await presencePartition(schema, canonical, routeId, routePath)}${memberId}`;
}
function presenceExpiryKey(memberKey) {
return `expiry:${memberKey}`;
}
function presenceFailure(code, message, cause = undefined) {
return Object.assign(new Error(message, cause === undefined ? undefined : { cause }), { code });
}
async function presenceAdmitRate(identity, kind, budget, parts = []) {
const key = `presence-${kind}-rate:${await presenceDigest(identity, ...parts)}`;
if (typeof __noxidSharedRateLimit === "function") {
let retryAfter;
try { retryAfter = await __noxidSharedRateLimit(key, budget, 60_000); }
catch (cause) { throw presenceFailure("PRESENCE_STORAGE_UNAVAILABLE", "Presence operational rate storage is temporarily unavailable", cause); }
if (retryAfter !== null && retryAfter !== undefined) throw Object.assign(presenceFailure("PRESENCE_RATE_LIMITED", "Presence write rate exceeded its compiler-owned per-principal budget"), { retryAfter });
return;
}
const now = Date.now();
let bucket = presenceLocalRates.get(key);
if (bucket === undefined || now - bucket.started >= 60_000) bucket = { started: now, count: 0 };
if (bucket.count >= budget) throw Object.assign(presenceFailure("PRESENCE_RATE_LIMITED", "Presence write rate exceeded its compiler-owned membership budget"), { retryAfter: Math.max(1, Math.ceil((bucket.started + 60_000 - now) / 1000)) });
bucket.count += 1;
presenceLocalRates.delete(key);
presenceLocalRates.set(key, bucket);
while (presenceLocalRates.size > 1024) presenceLocalRates.delete(presenceLocalRates.keys().next().value);
}
function presenceOperationalIdentity(environment, middlewareContext, principal) {
const session = middlewareContext?.sessionId ?? middlewareContext?.session?.id ?? environment?.sessionId;
if (typeof session === "string" && session.length > 0 && session.length <= 256 && !/[\u0000-\u001f\u007f]/.test(session)) return `session:${session}`;
const trusted = environment?.requestIdentity;
const requestIdentity = trusted?.id ?? trusted?.ip;
if (typeof requestIdentity === "string" && requestIdentity.length > 0 && requestIdentity.length <= 256 && !/[\u0000-\u001f\u007f]/.test(requestIdentity)) return `request:${requestIdentity}`;
return principal.canonical === "system" ? null : `principal:${principal.canonical}`;
}
function presenceValidateType(typeId, value, code) {
const validator = typeValidators[typeId];
if (typeof validator !== "function") throw presenceFailure("PRESENCE_VALIDATOR_MISSING", `Compiled presence validator ${typeId} is unavailable`);
try { return validator(value, true); }
catch (cause) { throw presenceFailure(code, "Presence data did not match its compiler-generated closed type", cause); }
}
function presenceValidateStored(schema, value, key) {
if (value === null || typeof value !== "object" || Array.isArray(value)
|| value.schema !== PRESENCE_STORAGE_SCHEMA || value.presence !== schema.id
|| typeof value.principal !== "string" || typeof value.routeId !== "string" || typeof value.routePath !== "string"
|| typeof value.memberId !== "string" || !PRESENCE_CREDENTIAL.test(value.memberId)
|| typeof value.nonce !== "string" || !PRESENCE_CREDENTIAL.test(value.nonce)
|| typeof value.tokenDigest !== "string" || !/^[a-f0-9]{64}$/.test(value.tokenDigest)
|| !Number.isSafeInteger(value.version) || value.version < 1
|| !Number.isSafeInteger(value.expiresAt) || value.expiresAt < 1
|| Object.keys(value).sort().join("\n") !== "expiresAt\nmemberId\nnonce\npresence\nprincipal\nrecord\nrouteId\nroutePath\nschema\ntokenDigest\nversion") {
throw presenceFailure("PRESENCE_STORAGE_INVALID", `Presence storage record ${key} failed its closed compiler-owned schema`);
}
const record = presenceValidateType(schema.recordType, value.record, "PRESENCE_STORAGE_INVALID");
presenceValidateType(schema.memberType, Object.freeze({ id: value.memberId, ...record }), "PRESENCE_STORAGE_INVALID");
return Object.freeze({ ...value, record });
}
async function presenceWriteStored(schema, stored, memberKey) {
const graceMilliseconds = Math.max(schema.ttlMilliseconds, 30_000);
const ttl = Math.max(1, Math.ceil((schema.ttlMilliseconds + graceMilliseconds) / 1000));
await presenceExpiryStorage.set(presenceExpiryKey(memberKey), Object.freeze({
schema: PRESENCE_INDEX_SCHEMA,
key: memberKey,
presence: schema.id,
principal: stored.principal,
routeId: stored.routeId,
routePath: stored.routePath,
memberId: stored.memberId,
version: stored.version,
expiresAt: stored.expiresAt,
state: "active",
}), { ttl });
await presenceMemberStorage.set(memberKey, stored, { ttl });
}
function presenceValidateIndex(value, indexKey) {
if (value === null || typeof value !== "object" || Array.isArray(value)
|| value.schema !== PRESENCE_INDEX_SCHEMA || typeof value.key !== "string" || presenceExpiryKey(value.key) !== indexKey
|| typeof value.presence !== "string" || typeof value.principal !== "string"
|| typeof value.memberId !== "string" || !PRESENCE_CREDENTIAL.test(value.memberId)
|| !Number.isSafeInteger(value.version) || value.version < 1
|| !Number.isSafeInteger(value.expiresAt) || value.expiresAt < 1
|| typeof value.routeId !== "string" || typeof value.routePath !== "string" || !["active", "left", "left-published"].includes(value.state)
|| Object.keys(value).sort().join("\n") !== "expiresAt\nkey\nmemberId\npresence\nprincipal\nrouteId\nroutePath\nschema\nstate\nversion") {
throw presenceFailure("PRESENCE_INDEX_INVALID", "Presence expiry index failed its metadata-only schema");
}
return Object.freeze(value);
}
async function presenceTopicId(schema, routeId, routePath) {
return `presence-topic:${await presenceDigest(schema.id, routeId, routePath)}`;
}
async function presencePublish(schema, principal, body) {
const startedAt = __noxidPubSubNow();
let state = "delivered";
let code = null;
try { await __noxidPubSubPublish(__noxidPubSubEvent("presence", await presenceTopicId(schema, body.routeId, body.routePath), principal, body)); }
catch (cause) { state = "failed"; code = cause?.code ?? "PRESENCE_PUBLISH_FAILED"; throw cause; }
finally { __noxidTraceEmit(tracingMode === "full" ? __noxidTraceContext() : null, "presence.publish", { semanticId: schema.id, state, event: body.tag, code, durationMs: Math.max(0, __noxidPubSubNow() - startedAt) }); }
}
async function presencePublishCanonical(schema, canonical, body) {
const startedAt = __noxidPubSubNow();
let state = "delivered";
let code = null;
try { await __noxidPubSubPublish(__noxidPubSubEventFromCanonical("presence", await presenceTopicId(schema, body.routeId, body.routePath), canonical, body)); }
catch (cause) { state = "failed"; code = cause?.code ?? "PRESENCE_PUBLISH_FAILED"; throw cause; }
finally { __noxidTraceEmit(tracingMode === "full" ? __noxidTraceContext() : null, "presence.publish", { semanticId: schema.id, state, event: body.tag, code, durationMs: Math.max(0, __noxidPubSubNow() - startedAt) }); }
}
async function presenceClaimExpired(indexKey, expected = null) {
const rawIndex = expected ?? await presenceExpiryStorage.get(indexKey);
if (rawIndex === null) return false;
const index = presenceValidateIndex(rawIndex, indexKey);
const schema = presenceSchemaById.get(index.presence);
if (schema === undefined) throw presenceFailure("PRESENCE_INDEX_INVALID", "Presence expiry index named an unknown compiler contract");
let tombstone = index;
if (index.state === "left-published") return false;
if (index.state === "active") {
if (index.expiresAt > Date.now()) return false;
tombstone = await presencePartitionLock(schema, index.principal, index.routeId, index.routePath, async () => {
const currentIndex = await presenceExpiryStorage.get(indexKey);
if (currentIndex === null || currentIndex.state !== "active" || currentIndex.version !== index.version || currentIndex.expiresAt > Date.now()) return null;
const raw = await presenceMemberStorage.get(index.key);
if (raw === null) {
await presenceExpiryStorage.delete(indexKey);
return null;
}
const stored = presenceValidateStored(schema, raw, index.key);
if (stored.version !== currentIndex.version || stored.expiresAt > Date.now()) return null;
const left = Object.freeze({ ...currentIndex, version: stored.version + 1, state: "left" });
await presenceExpiryStorage.set(indexKey, left);
await presenceMemberStorage.delete(index.key);
return left;
});
if (tombstone === null) return false;
} else if (index.state === "left") {
tombstone = await presencePartitionLock(schema, index.principal, index.routeId, index.routePath, async () => {
const rawCurrent = await presenceExpiryStorage.get(indexKey);
if (rawCurrent === null) return null;
const current = presenceValidateIndex(rawCurrent, indexKey);
if (current.state !== "left" || current.version !== index.version) return null;
const raw = await presenceMemberStorage.get(current.key);
if (raw !== null) {
const stored = presenceValidateStored(schema, raw, current.key);
if (stored.principal !== current.principal || stored.routeId !== current.routeId || stored.routePath !== current.routePath || stored.memberId !== current.memberId || stored.version >= current.version) throw presenceFailure("PRESENCE_STORAGE_INVALID", "Pending Left conflicts with its authored member record");
await presenceMemberStorage.delete(current.key);
}
return current;
});
if (tombstone === null) return false;
}
await presencePublishCanonical(schema, tombstone.principal, Object.freeze({ tag: "Left", value: tombstone.memberId, memberId: tombstone.memberId, version: tombstone.version, routeId: tombstone.routeId, routePath: tombstone.routePath }));
await presencePartitionLock(schema, tombstone.principal, tombstone.routeId, tombstone.routePath, async () => {
const current = await presenceExpiryStorage.get(indexKey);
if (current?.state === "left" && current.version === tombstone.version) {
await presenceExpiryStorage.set(indexKey, Object.freeze({ ...current, state: "left-published" }), { ttl: Math.max(60, Math.ceil(schema.ttlMilliseconds * 2 / 1000)) });
}
});
return true;
}
async function presenceSweep() {
if (presenceExpiryStorage === null) return;
const startedAt = __noxidPubSubNow();
let state = "delivered";
let code = null;
let claim = null;
let ownsClaim = false;
try {
if (typeof __noxidSharedIdempotencyPrepare === "function") {
claim = globalThis.crypto?.randomUUID?.();
if (typeof claim !== "string") throw presenceFailure("PRESENCE_CRYPTO_UNAVAILABLE", "Presence sweep ownership requires secure random claims");
const prepared = await __noxidSharedIdempotencyPrepare(`presence-sweep:${applicationNamespace}`, claim, LIVE_RESOURCE_SCHEMA.timeoutMs + 5_000);
if (prepared?.state === "pending") { state = "retry"; return; }
if (prepared?.state !== "owner") throw presenceFailure("PRESENCE_SWEEP_LOCK_INVALID", "Presence sweep lock returned an invalid shared state");
ownsClaim = true;
}
const keys = await presenceExpiryStorage.list("expiry:");
const cursor = await presenceExpiryStorage.get("sweep:cursor");
const start = typeof cursor?.key === "string" ? Math.max(0, keys.findIndex((key) => key > cursor.key)) : 0;
const batch = [...keys.slice(start), ...keys.slice(0, start)].slice(0, PRESENCE_SWEEP_BATCH);
for (const key of batch) {
try {
const raw = await presenceExpiryStorage.get(key);
if (raw === null) continue;
const index = presenceValidateIndex(raw, key);
if (index.state === "left" || index.state === "active" && index.expiresAt <= Date.now()) await presenceClaimExpired(key, index);
} catch (cause) {
__noxidTraceEmit(null, "presence.sweep.item", { semanticId: null, state: "failed", code: cause?.code ?? "PRESENCE_SWEEP_ITEM_FAILED" });
}
}
if (batch.length > 0) await presenceExpiryStorage.set("sweep:cursor", Object.freeze({ key: batch.at(-1) }));
} catch (cause) {
state = "failed";
code = cause?.code ?? "PRESENCE_SWEEP_FAILED";
} finally {
if (ownsClaim && claim !== null && typeof __noxidSharedIdempotencyRelease === "function") await __noxidSharedIdempotencyRelease(`presence-sweep:${applicationNamespace}`, claim).catch((cause) => { state = "failed"; code = cause?.code ?? "PRESENCE_SWEEP_RELEASE_FAILED"; });
__noxidTraceEmit(null, "presence.sweep", { semanticId: null, state, code, durationMs: Math.max(0, __noxidPubSubNow() - startedAt) });
}
}
if (presenceSchemas.length > 0) {
const interval = Math.max(1000, Math.min(...presenceSchemas.map((schema) => schema.heartbeatMilliseconds)));
const schedule = () => {
const timer = setTimeout(async () => { await presenceSweep(); schedule(); }, interval + Math.floor(Math.random() * Math.max(1, Math.floor(interval / 3))));
timer?.unref?.();
};
schedule();
}
async function presenceSnapshot(schema, principal, routeId, routePath, signal) {
return presencePartitionLock(schema, principal.canonical, routeId, routePath, async () => {
const members = [];
const versions = new Map();
const prefix = `member:${await presencePartition(schema, principal.canonical, routeId, routePath)}`;
for (const key of await presenceMemberStorage.list(prefix)) {
const raw = await presenceMemberStorage.get(key);
if (raw === null) continue;
const stored = presenceValidateStored(schema, raw, key);
if (stored.principal !== principal.canonical || stored.routeId !== routeId || stored.routePath !== routePath) throw presenceFailure("PRESENCE_STORAGE_INVALID", "Presence storage crossed its canonical principal or route partition");
const indexKey = presenceExpiryKey(key);
const rawIndex = await presenceExpiryStorage.get(indexKey);
const index = rawIndex === null ? null : presenceValidateIndex(rawIndex, indexKey);
if (index?.state === "left" || index?.state === "left-published" || stored.expiresAt <= Date.now()) continue;
if (index === null || index.state !== "active" || index.version !== stored.version || index.expiresAt !== stored.expiresAt || index.principal !== stored.principal || index.routeId !== stored.routeId || index.routePath !== stored.routePath) {
await presenceWriteStored(schema, stored, key);
}
const member = presenceValidateType(schema.memberType, Object.freeze({ id: stored.memberId, ...stored.record }), "PRESENCE_STORAGE_INVALID");
members.push(member);
versions.set(stored.memberId, stored.version);
if (members.length > PRESENCE_MAX_MEMBERS) throw presenceFailure("PRESENCE_CAPACITY_EXCEEDED", "Presence snapshot exceeded its bounded compiler-owned member capacity");
}
members.sort((left, right) => left.id.localeCompare(right.id));
const value = presenceValidateType(schema.snapshotType, Object.freeze({ members: Object.freeze(members) }), "PRESENCE_STORAGE_INVALID");
if (presenceSseFrameBytes(schema, Object.freeze({ tag: "Snapshot", value })) > PRESENCE_MAX_SNAPSHOT_BYTES) throw presenceFailure("PRESENCE_SNAPSHOT_TOO_LARGE", "Presence snapshot exceeded its bounded SSE transport budget");
return Object.freeze({ value, versions });
}, signal);
}
function liveRouteSegments(path) {
const normalized = path.length > 1 ? path.replace(/\/+$/, "") : path;
if (normalized === "/") return [];
const values = [];
for (const encoded of normalized.slice(1).split("/")) {
try { values.push(decodeURIComponent(encoded)); }
catch { return null; }
}
return values;
}
function liveRoutePatternSegments(pattern) {
if (pattern === "/") return [];
return pattern.slice(1).split("/");
}
function liveRouteParameter(value, type) {
if (type === "String") return value;
if (type === "Int" && /^-?\d+$/.test(value)) {
const parsed = Number(value);
return Number.isSafeInteger(parsed) ? parsed : null;
}
if (type === "Boolean" && (value === "true" || value === "false")) return value === "true";
return null;
}
function liveRouteInstance(scope, supplied) {
if (typeof supplied !== "string" || !supplied.startsWith("/") || supplied.length > 2048
|| liveResourceEncoder.encode(supplied).byteLength > 2048 || supplied.includes("?") || supplied.includes(String.fromCharCode(35))
|| /[\u0000-\u001f\u007f]/.test(supplied)) return null;
const actual = liveRouteSegments(supplied);
const expected = liveRoutePatternSegments(scope.pattern);
if (actual === null || expected === null) return null;
if (actual.some((segment) => segment === "." || segment === ".." || /[\u0000-\u001f\u007f]/.test(segment))) return null;
const catchAllIndex = expected.findIndex((segment) => segment.startsWith("{*") && segment.endsWith("}"));
if (catchAllIndex === -1 && actual.length !== expected.length) return null;
if (catchAllIndex !== -1 && (catchAllIndex !== expected.length - 1 || actual.length < expected.length)) return null;
const parameters = new Map(scope.parameters.map((parameter) => [parameter.name, parameter]));
const params = Object.create(null);
const canonicalSegments = [];
for (let index = 0; index < expected.length; index += 1) {
const segment = expected[index];
if (segment.startsWith("{*") && segment.endsWith("}")) {
const name = segment.slice(2, -1);
const parameter = parameters.get(name);
if (!parameter?.catchAll || parameter.type !== "Array<String>") return null;
params[name] = Object.freeze(actual.slice(index));
canonicalSegments.push(...actual.slice(index));
break;
}
if (!segment.startsWith("{") || !segment.endsWith("}")) {
if (segment !== actual[index]) return null;
canonicalSegments.push(actual[index]);
continue;
}
const name = segment.slice(1, -1);
const parameter = parameters.get(name);
if (!parameter || parameter.catchAll) return null;
const converted = liveRouteParameter(actual[index], parameter.type);
if (converted === null) return null;
params[name] = converted;
canonicalSegments.push(parameter.type === "String" ? converted : String(converted));
}
const path = canonicalSegments.length === 0 ? "/" : `/${canonicalSegments.map((segment) => encodeURIComponent(segment)).join("/")}`;
if (liveResourceEncoder.encode(path).byteLength > 2048) return null;
return Object.freeze({ path, params: Object.freeze(params) });
}
function liveResourceSubscription(request, url) {
if (request.method !== "GET") return { response: failure(405, "LIVE_RESOURCE_METHOD", "Live resource connections require GET", LIVE_RESOURCE_SCHEMA.id, null, { allow: "GET" }) };
const accept = request.headers.get("accept") ?? "";
if (!accept.toLowerCase().split(",").some((value) => value.trim().startsWith("text/event-stream"))) {
return { response: failure(406, "LIVE_RESOURCE_ACCEPT_REQUIRED", "Live resource connections require Accept: text/event-stream", LIVE_RESOURCE_SCHEMA.id) };
}
for (const key of url.searchParams.keys()) {
if (key !== "resource" && key !== "presence") return { response: failure(400, "LIVE_RESOURCE_QUERY_INVALID", "Live connections accept only repeated compiler-owned resource and presence query fields", LIVE_RESOURCE_SCHEMA.id) };
}
const requested = url.searchParams.getAll("resource");
const requestedPresence = url.searchParams.getAll("presence");
if (requested.length > liveResourceSchemas.length || new Set(requested).size !== requested.length
|| requestedPresence.length > presenceSchemas.length || new Set(requestedPresence).size !== requestedPresence.length
|| requested.length + requestedPresence.length === 0) {
return { response: failure(400, "LIVE_RESOURCE_SET_INVALID", "Live connections require one bounded duplicate-free compiler-owned resource or presence set", LIVE_RESOURCE_SCHEMA.id) };
}
const schemas = [];
const routeId = request.headers.get("x-noxid-route-id");
if (typeof routeId !== "string" || routeId.length === 0 || liveResourceEncoder.encode(routeId).byteLength > 512 || /[\u0000-\u001f\u007f]/.test(routeId)) {
return { response: failure(400, "LIVE_RESOURCE_ROUTE_REQUIRED", "Live resource connections require the compiler-selected route identity", LIVE_RESOURCE_SCHEMA.id) };
}
let routeScope = null;
for (const semanticId of requested) {
const schema = liveResourceSchemaById.get(semanticId);
if (schema === undefined) return { response: failure(403, "LIVE_RESOURCE_NOT_DECLARED", "Live resource subscription is not present in the compiled manifest", semanticId) };
const candidate = schema.routeScopes.find((scope) => scope.id === routeId);
if (candidate === undefined) return { response: failure(403, "LIVE_RESOURCE_ROUTE_DENIED", "Live resource is not exposed by the compiler-selected route", semanticId, { route: routeId }) };
if (routeScope === null) routeScope = candidate;
else if (routeScope.pattern !== candidate.pattern || JSON.stringify(routeScope.parameters) !== JSON.stringify(candidate.parameters) || routeScope.middleware.join("\n") !== candidate.middleware.join("\n")) {
return { response: failure(500, "LIVE_RESOURCE_ROUTE_DRIFT", "Compiled live resources disagree on the selected route middleware contract", semanticId) };
}
schemas.push(schema);
}
const selectedPresence = [];
for (const semanticId of requestedPresence) {
const schema = presenceSchemaById.get(semanticId);
if (schema === undefined) return { response: failure(403, "PRESENCE_NOT_DECLARED", "Presence subscription is not present in the compiled manifest", semanticId) };
const candidate = schema.routeScopes.find((scope) => scope.id === routeId);
if (candidate === undefined) return { response: failure(403, "PRESENCE_ROUTE_DENIED", "Presence is not exposed by the compiler-selected route", semanticId, { route: routeId }) };
if (routeScope === null) routeScope = candidate;
else if (routeScope.pattern !== candidate.pattern || JSON.stringify(routeScope.parameters) !== JSON.stringify(candidate.parameters) || routeScope.middleware.join("\n") !== candidate.middleware.join("\n")) {
return { response: failure(500, "LIVE_RESOURCE_ROUTE_DRIFT", "Compiled live subscriptions disagree on the selected route middleware contract", semanticId) };
}
schemas.push(schema);
selectedPresence.push(schema);
}
schemas.sort((left, right) => left.id.localeCompare(right.id));
selectedPresence.sort((left, right) => left.id.localeCompare(right.id));
const resourceSchemas = Object.freeze(requested.map((id) => liveResourceSchemaById.get(id)).sort((left, right) => left.id.localeCompare(right.id)));
const ids = Object.freeze(resourceSchemas.map((schema) => schema.id));
const presenceIds = Object.freeze(selectedPresence.map((schema) => schema.id));
const route = liveRouteInstance(routeScope, request.headers.get("x-noxid-route-path"));
if (route === null) return { response: failure(400, "LIVE_RESOURCE_ROUTE_PATH_INVALID", "Live connection route path must exactly match its compiled route pattern and typed parameters", LIVE_RESOURCE_SCHEMA.id, { route: routeId }) };
return { schemas: Object.freeze(schemas), resourceSchemas, presenceSchemas: Object.freeze(selectedPresence), ids, presenceIds, routeScope, routePath: route.path, params: route.params, key: `${routeId}\n${route.path}\nresources:${ids.join("\n")}\npresences:${presenceIds.join("\n")}` };
}
function liveResourcePruneHistories() {
if (liveResourceHistories.size < LIVE_RESOURCE_MAX_HISTORIES) return true;
for (const [token, history] of liveResourceHistories) {
if (!history.completed) continue;
liveResourceHistories.delete(token);
if (liveResourceHistories.size < LIVE_RESOURCE_MAX_HISTORIES) return true;
}
return false;
}
function liveResourceFreshHistory(principal, subscriptionKey) {
if (!liveResourcePruneHistories()) return null;
let token = liveResourceToken();
while (liveResourceHistories.has(token)) token = liveResourceToken();
const history = { token, principal, subscriptionKey, events: [], bytes: 0, nextSequence: 1, completed: false };
liveResourceHistories.set(token, history);
return history;
}
function liveResourceResumeHistory(lastEventId, principal, subscriptionKey) {
const cursor = liveResourceCursor(lastEventId);
if (cursor === null) return null;
const history = liveResourceHistories.get(cursor.token);
if (history === undefined || !history.completed || history.principal !== principal || history.subscriptionKey !== subscriptionKey) return null;
const earliest = history.events[0]?.sequence ?? history.nextSequence;
if (cursor.sequence < earliest - 1 || cursor.sequence >= history.nextSequence) return null;
history.completed = false;
liveResourceHistories.delete(history.token);
liveResourceHistories.set(history.token, history);
return Object.freeze({ history, replay: history.events.filter((event) => event.sequence > cursor.sequence) });
}
function liveResourceRecord(history, semanticId) {
const sequence = history.nextSequence++;
const frame = `id: ${history.token}:${sequence}\nevent: noxid-live-invalidation\ndata: ${JSON.stringify(semanticId)}\n\n`;
const bytes = liveResourceEncoder.encode(frame).byteLength;
const event = Object.freeze({ sequence, semanticId, frame, bytes });
history.events.push(event);
history.bytes += bytes;
while (history.events.length > LIVE_RESOURCE_MAX_EVENTS || history.bytes > LIVE_RESOURCE_MAX_HISTORY_BYTES) {
history.bytes -= history.events.shift().bytes;
}
return event;
}
async function liveResourceAuthorize(request, schemas, route, environment, executionContext, signal) {
for (const schema of schemas) {
if (signal.aborted) return endpointTimeoutFailure(LIVE_RESOURCE_SCHEMA);
if (schema.capabilities.length > 0 && typeof authorize !== "function") {
return failure(500, "LIVE_RESOURCE_AUTHORIZER_MISSING", "Live resource authorization is not configured", schema.id);
}
for (const capability of schema.capabilities) {
let allowed = false;
try {
allowed = await authorize(Object.freeze({ capability, semanticId: schema.id, traceId: __noxidTraceIdForRequest(request), target: "live-resource", route, request, environment, executionContext, signal })) === true;
} catch {}
if (signal.aborted) return endpointTimeoutFailure(LIVE_RESOURCE_SCHEMA);
if (!allowed) return failure(403, "LIVE_RESOURCE_CAPABILITY_DENIED", "Live resource capability was denied", schema.id, { capability });
}
}
return null;
}
function presenceValidateEvent(schema, envelope, routeId, routePath) {
const body = envelope?.body;
if (body === null || typeof body !== "object" || Array.isArray(body)
|| !["Joined", "Updated", "Left"].includes(body.tag)
|| typeof body.memberId !== "string" || !PRESENCE_CREDENTIAL.test(body.memberId)
|| !Number.isSafeInteger(body.version) || body.version < 1
|| body.routeId !== routeId || body.routePath !== routePath
|| Object.keys(body).sort().join("\n") !== "memberId\nrouteId\nroutePath\ntag\nvalue\nversion") {
throw presenceFailure("PRESENCE_EVENT_INVALID", "Presence pub/sub delivered an invalid compiler-owned event");
}
if (body.tag === "Left") {
if (typeof body.value !== "string" || !PRESENCE_CREDENTIAL.test(body.value)) throw presenceFailure("PRESENCE_EVENT_INVALID", "Presence Left requires one opaque member identity");
if (body.memberId !== body.value) throw presenceFailure("PRESENCE_EVENT_INVALID", "Presence Left identity metadata drifted");
return Object.freeze({ event: Object.freeze({ tag: "Left", value: body.value }), memberId: body.memberId, version: body.version });
}
const value = presenceValidateType(schema.memberType, body.value, "PRESENCE_EVENT_INVALID");
if (value.id !== body.memberId) throw presenceFailure("PRESENCE_EVENT_INVALID", "Presence event identity metadata drifted");
return Object.freeze({ event: Object.freeze({ tag: body.tag, value }), memberId: body.memberId, version: body.version });
}
function liveResourceStream(request, resourceSchemas, presenceStreamSchemas, principal, routeId, routePath, history, replay, middlewareHeaders, deadline) {
let closed = false;
let controller = null;
let heartbeatTimer = null;
const pending = new Set();
const pendingPresence = [];
const replayQueue = [...replay];
let syncPending = false;
const unsubscribe = [];
const trace = tracingMode === "full" ? __noxidTraceContext() : null;
const cleanup = async (closeStream) => {
if (closed) return;
closed = true;
history.completed = true;
if (heartbeatTimer !== null) clearInterval(heartbeatTimer);
deadline.signal.removeEventListener("abort", onAbort);
deadline.release();
await Promise.allSettled(unsubscribe.splice(0).map((stop) => stop()));
if (closeStream) { try { controller?.close(); } catch {} }
};
const send = (event) => {
const startedAt = __noxidPubSubNow();
controller.enqueue(liveResourceEncoder.encode(event.frame));
__noxidTraceEmit(trace, "live.deliver", { semanticId: event.semanticId, state: "delivered", durationMs: Math.max(0, __noxidPubSubNow() - startedAt) });
};
const sendPresence = (entry) => {
const startedAt = __noxidPubSubNow();
let state = "delivered";
let code = null;
try {
const frame = presenceSseFrame(entry.schema, entry.event);
if (liveResourceEncoder.encode(frame).byteLength > PRESENCE_MAX_SNAPSHOT_BYTES) throw presenceFailure("PRESENCE_SNAPSHOT_TOO_LARGE", "Presence event exceeded its bounded SSE transport budget");
controller.enqueue(liveResourceEncoder.encode(frame));
} catch (cause) {
state = "failed";
code = cause?.code ?? "PRESENCE_DELIVERY_FAILED";
throw cause;
} finally {
__noxidTraceEmit(trace, "presence.deliver", { semanticId: entry.schema.id, state, event: entry.event.tag, code, durationMs: Math.max(0, __noxidPubSubNow() - startedAt) });
}
};
const queuePresence = (schema, event) => {
if (event.tag === "Updated") {
let same = -1;
for (let index = pendingPresence.length - 1; index >= 0; index -= 1) {
const entry = pendingPresence[index];
if (entry.schema.id !== schema.id) continue;
const memberId = entry.event.tag === "Left" ? entry.event.value : entry.event.value?.id;
if ((entry.event.tag === "Joined" || entry.event.tag === "Left") && memberId === event.value.id) break;
if (entry.event.tag === "Updated" && memberId === event.value.id) { same = index; break; }
}
if (same >= 0) { pendingPresence[same] = Object.freeze({ schema, event }); flush(); return; }
}
if (pendingPresence.length >= PRESENCE_MAX_MEMBERS) throw presenceFailure("PRESENCE_DELIVERY_CAPACITY", "Presence delivery exceeded its bounded queue; reconnect for a fresh Snapshot");
pendingPresence.push(Object.freeze({ schema, event }));
flush();
};
const flush = () => {
if (closed || controller === null) return;
try {
while ((controller.desiredSize ?? 1) > 0 && replayQueue.length > 0) send(replayQueue.shift());
while ((controller.desiredSize ?? 1) > 0 && pendingPresence.length > 0) sendPresence(pendingPresence.shift());
if ((controller.desiredSize ?? 1) > 0 && syncPending) {
syncPending = false;
controller.enqueue(liveResourceEncoder.encode("event: noxid-live-sync\ndata: null\n\n"));
}
while ((controller.desiredSize ?? 1) > 0 && pending.size > 0) {
const semanticId = pending.values().next().value;
pending.delete(semanticId);
send(liveResourceRecord(history, semanticId));
}
} catch { void cleanup(false); }
};
const onAbort = () => { void cleanup(true); };
const stream = new ReadableStream({
async start(streamController) {
controller = streamController;
deadline.signal.addEventListener("abort", onAbort, { once: true });
heartbeatTimer = setInterval(() => {
if (closed || (controller.desiredSize ?? 1) <= 0) return;
try { controller.enqueue(liveResourceEncoder.encode(": heartbeat\n\n")); } catch { void cleanup(false); }
}, ENDPOINT_STREAM_HEARTBEAT_MS);
heartbeatTimer?.unref?.();
flush();
try {
for (const schema of resourceSchemas) {
const stop = await __noxidPubSubSubscribe("invalidation", schema.id, principal, () => {
pending.add(schema.id);
flush();
});
if (closed) await stop();
else unsubscribe.push(stop);
}
for (const schema of presenceStreamSchemas) {
const buffered = [];
const versions = new Map();
const present = new Set();
let ready = false;
const reconcileDelta = (delta) => {
const known = versions.get(delta.memberId);
if (known !== undefined && delta.version <= known) return null;
versions.set(delta.memberId, delta.version);
if (delta.event.tag === "Left") {
return present.delete(delta.memberId) ? delta.event : null;
}
if (delta.event.tag === "Joined" && present.has(delta.memberId)) {
throw presenceFailure("PRESENCE_RESYNC_REQUIRED", "Presence structural ordering was incomplete; reconnect for a fresh Snapshot");
}
if (delta.event.tag === "Updated" && !present.has(delta.memberId)) {
present.add(delta.memberId);
return Object.freeze({ tag: "Joined", value: delta.event.value });
}
present.add(delta.memberId);
return delta.event;
};
const topicId = await presenceTopicId(schema, routeId, routePath);
const stop = await __noxidPubSubSubscribe("presence", topicId, principal, (envelope) => {
try {
if (envelope?.body?.routeId !== routeId || envelope?.body?.routePath !== routePath) return;
const delta = presenceValidateEvent(schema, envelope, routeId, routePath);
if (!ready) {
if (delta.event.tag === "Updated") {
let same = -1;
for (let index = buffered.length - 1; index >= 0; index -= 1) {
const item = buffered[index];
if ((item.event.tag === "Joined" || item.event.tag === "Left") && item.memberId === delta.memberId) break;
if (item.event.tag === "Updated" && item.memberId === delta.memberId) { same = index; break; }
}
if (same >= 0 && buffered[same].version <= delta.version) { buffered[same] = delta; return; }
}
if (buffered.length >= PRESENCE_MAX_MEMBERS) throw presenceFailure("PRESENCE_SNAPSHOT_RACE_CAPACITY", "Presence changed too quickly while constructing Snapshot; reconnect to retry");
buffered.push(delta);
} else {
const event = reconcileDelta(delta);
if (event !== null) queuePresence(schema, event);
}
} catch (cause) {
void cleanup(false);
try { controller.error(cause); } catch {}
}
});
if (closed) { await stop(); continue; }
unsubscribe.push(stop);
const snapshot = await presenceSnapshot(schema, principal, routeId, routePath, deadline.signal);
for (const [memberId, version] of snapshot.versions) { versions.set(memberId, version); present.add(memberId); }
queuePresence(schema, Object.freeze({ tag: "Snapshot", value: snapshot.value }));
ready = true;
for (const delta of buffered) {
const event = reconcileDelta(delta);
if (event !== null) queuePresence(schema, event);
}
}
// This fence closes both initial-fetch -> first-subscribe and
// disconnect -> resumed-subscribe gaps. Replay remains strictly after
// the supplied cursor; the fence carries no cursor and asks the client
// to validate current state once after every exact set is installed.
syncPending = resourceSchemas.length > 0;
flush();
} catch (cause) {
await cleanup(false);
try { controller.error(cause); } catch {}
}
},
pull() { flush(); },
cancel() { return cleanup(false); },
});
const headers = new Headers({
"content-type": "text/event-stream; charset=utf-8",
"cache-control": "no-store",
"connection": "keep-alive",
"x-accel-buffering": "no",
"x-content-type-options": "nosniff",
});
for (const [name, value] of middlewareHeaders) headers.append(name, value);
return new Response(stream, { status: 200, headers });
}
function presenceRequestShape(value, operation) {
if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
const allowed = operation === "join"
? "nonce\noperation\npresence\nrecord\ntoken"
: operation === "update"
? "memberId\noperation\npresence\nrecord\ntoken"
: "memberId\noperation\npresence\ntoken";
return Object.keys(value).sort().join("\n") === allowed ? value : null;
}
async function presenceReadRequest(request, signal) {
if (request.headers.get("content-type")?.split(";", 1)[0].trim().toLowerCase() !== "application/json") {
throw presenceFailure("PRESENCE_CONTENT_TYPE_REQUIRED", "Presence writes require Content-Type: application/json");
}
const declared = request.headers.get("content-length");
if (declared !== null && (!/^\d+$/.test(declared) || Number(declared) > 12_288)) throw presenceFailure("PRESENCE_BODY_TOO_LARGE", "Presence writes are bounded to 12288 bytes");
if (request.body === null) throw presenceFailure("PRESENCE_BODY_INVALID", "Presence write body must be valid JSON");
const reader = request.body.getReader();
const chunks = [];
let total = 0;
const cancel = () => { void reader.cancel("presence request cancelled").catch(() => {}); };
signal.addEventListener("abort", cancel, { once: true });
try {
while (true) {
if (signal.aborted) throw presenceFailure("PRESENCE_OPERATION_ABORTED", "Presence request exceeded its bounded lifetime");
const chunk = await reader.read();
if (signal.aborted) throw presenceFailure("PRESENCE_OPERATION_ABORTED", "Presence request exceeded its bounded lifetime");
if (chunk.done) break;
if (!(chunk.value instanceof Uint8Array)) throw presenceFailure("PRESENCE_BODY_INVALID", "Presence request body stream did not yield bytes");
total += chunk.value.byteLength;
if (total > 12_288) {
await reader.cancel("presence request body too large").catch(() => {});
throw presenceFailure("PRESENCE_BODY_TOO_LARGE", "Presence writes are bounded to 12288 bytes");
}
chunks.push(chunk.value);
}
} finally {
signal.removeEventListener("abort", cancel);
try { reader.releaseLock(); } catch {}
}
const bytes = new Uint8Array(total);
let offset = 0;
for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.byteLength; }
let text;
try { text = new TextDecoder("utf-8", { fatal: true }).decode(bytes); }
catch (cause) { throw presenceFailure("PRESENCE_BODY_INVALID", "Presence write body must be UTF-8", cause); }
let value;
try { value = JSON.parse(text); }
catch (cause) { throw presenceFailure("PRESENCE_BODY_INVALID", "Presence write body must be valid JSON", cause); }
const operation = value?.operation;
if (!["join", "update", "heartbeat", "leave"].includes(operation) || presenceRequestShape(value, operation) === null) {
throw presenceFailure("PRESENCE_BODY_INVALID", "Presence writes use only the compiler-owned join, update, heartbeat, and leave shapes");
}
return value;
}
async function presenceEnsureAggregate(schema, canonical, routeId, routePath, candidateId, candidateRecord) {
const members = [];
const prefix = `member:${await presencePartition(schema, canonical, routeId, routePath)}`;
for (const key of await presenceMemberStorage.list(prefix)) {
const raw = await presenceMemberStorage.get(key);
if (raw === null) continue;
const stored = presenceValidateStored(schema, raw, key);
if (stored.principal !== canonical || stored.routeId !== routeId || stored.routePath !== routePath) throw presenceFailure("PRESENCE_STORAGE_INVALID", "Presence aggregate crossed its canonical principal or route partition");
if (stored.expiresAt <= Date.now() || stored.memberId === candidateId) continue;
members.push(presenceValidateType(schema.memberType, Object.freeze({ id: stored.memberId, ...stored.record }), "PRESENCE_STORAGE_INVALID"));
}
members.push(presenceValidateType(schema.memberType, Object.freeze({ id: candidateId, ...candidateRecord }), "PRESENCE_RECORD_INVALID"));
if (members.length > PRESENCE_MAX_MEMBERS) throw presenceFailure("PRESENCE_CAPACITY_EXCEEDED", "Presence partition reached its bounded member capacity");
const snapshot = presenceValidateType(schema.snapshotType, Object.freeze({ members: Object.freeze(members) }), "PRESENCE_RECORD_INVALID");
if (presenceSseFrameBytes(schema, Object.freeze({ tag: "Snapshot", value: snapshot })) > PRESENCE_MAX_SNAPSHOT_BYTES) {
throw presenceFailure("PRESENCE_SNAPSHOT_TOO_LARGE", "Presence write would exceed the bounded aggregate Snapshot transport budget");
}
}
async function presenceDelta(schema, tag, stored) {
const value = tag === "Left"
? stored.memberId
: presenceValidateType(schema.memberType, Object.freeze({ id: stored.memberId, ...stored.record }), "PRESENCE_STORAGE_INVALID");
const body = Object.freeze({ tag, value, memberId: stored.memberId, version: stored.version, routeId: stored.routeId, routePath: stored.routePath });
if (liveResourceEncoder.encode(JSON.stringify(body)).byteLength > PRESENCE_MAX_DELTA_BYTES) {
throw presenceFailure("PRESENCE_RECORD_TOO_LARGE", "Presence record exceeds the bounded cross-driver delta budget");
}
try { __noxidPubSubEventFromCanonical("presence", await presenceTopicId(schema, stored.routeId, stored.routePath), stored.principal, body, "presence_size_probe"); }
catch (cause) {
if (cause?.code === "PUBSUB_EVENT_TOO_LARGE") throw presenceFailure("PRESENCE_RECORD_TOO_LARGE", "Presence record exceeds the bounded cross-driver event budget", cause);
throw cause;
}
return body;
}
async function presencePublishAndClearTombstone(schema, tombstone, signal = null) {
await presencePublishCanonical(schema, tombstone.principal, Object.freeze({ tag: "Left", value: tombstone.memberId, memberId: tombstone.memberId, version: tombstone.version, routeId: tombstone.routeId, routePath: tombstone.routePath }));
await presencePartitionLock(schema, tombstone.principal, tombstone.routeId, tombstone.routePath, async () => {
const key = presenceExpiryKey(tombstone.key);
const current = await presenceExpiryStorage.get(key);
if (current?.state === "left" && current.version === tombstone.version) {
await presenceExpiryStorage.set(key, Object.freeze({ ...current, state: "left-published" }), { ttl: Math.max(60, Math.ceil(schema.ttlMilliseconds * 2 / 1000)) });
}
}, signal);
}
async function presenceMutate(schema, principal, operationalIdentity, routeId, routePath, body, signal) {
const canonical = principal.canonical;
if (body.operation === "join") {
if (!PRESENCE_CREDENTIAL.test(body.nonce) || !PRESENCE_CREDENTIAL.test(body.token)) throw presenceFailure("PRESENCE_CREDENTIAL_INVALID", "Presence join requires bounded cryptographic nonce and credential fields");
const record = presenceValidateType(schema.recordType, body.record, "PRESENCE_RECORD_INVALID");
const memberId = `member_${(await presenceDigest(schema.id, canonical, routePath, body.nonce)).slice(0, 48)}`;
const tokenDigest = await presenceDigest(schema.id, canonical, routePath, memberId, body.token);
for (;;) {
const outcome = await presencePartitionLock(schema, canonical, routeId, routePath, async () => {
const memberKey = await presenceMemberKey(schema, canonical, routeId, routePath, memberId);
const indexKey = presenceExpiryKey(memberKey);
const marker = await presenceExpiryStorage.get(indexKey);
const trustedMarker = marker === null ? null : presenceValidateIndex(marker, indexKey);
if (trustedMarker !== null && (trustedMarker.principal !== canonical || trustedMarker.routeId !== routeId || trustedMarker.routePath !== routePath || trustedMarker.presence !== schema.id || trustedMarker.memberId !== memberId)) throw presenceFailure("PRESENCE_INDEX_INVALID", "Presence join marker crossed its compiler-owned partition");
if (trustedMarker?.state === "left") return Object.freeze({ tombstone: trustedMarker });
const version = trustedMarker?.state === "left-published" ? trustedMarker.version + 1 : trustedMarker?.state === "active" ? trustedMarker.version : 1;
const raw = await presenceMemberStorage.get(memberKey);
if (raw !== null) {
const stored = presenceValidateStored(schema, raw, memberKey);
if (stored.principal !== canonical || stored.routeId !== routeId || stored.routePath !== routePath || stored.nonce !== body.nonce || !presenceDigestEqual(stored.tokenDigest, tokenDigest)) throw presenceFailure("PRESENCE_CREDENTIAL_DENIED", "Presence join credentials do not match the compiler-owned membership");
if (stored.expiresAt <= Date.now()) {
const tombstone = Object.freeze({ schema: PRESENCE_INDEX_SCHEMA, key: memberKey, presence: schema.id, principal: canonical, routeId, routePath, memberId, version: stored.version + 1, expiresAt: stored.expiresAt, state: "left" });
await presenceExpiryStorage.set(presenceExpiryKey(memberKey), tombstone);
await presenceMemberStorage.delete(memberKey);
return Object.freeze({ tombstone, nextVersion: tombstone.version + 1 });
}
await presenceEnsureAggregate(schema, canonical, routeId, routePath, memberId, record);
const changed = JSON.stringify(record) !== JSON.stringify(stored.record);
const resumed = trustedMarker?.state === "left-published";
const interrupted = trustedMarker?.state === "active" && trustedMarker.version > stored.version;
const nextVersion = Math.max(interrupted ? trustedMarker.version : 0, resumed ? version : changed ? stored.version + 1 : stored.version);
const publishTag = resumed || interrupted ? "Joined" : changed ? "Updated" : "Joined";
const next = Object.freeze({ ...stored, record, version: nextVersion, expiresAt: Date.now() + schema.ttlMilliseconds });
await presenceDelta(schema, publishTag, next);
await presenceWriteStored(schema, next, memberKey);
return Object.freeze({ stored: next, publishTag });
}
await presenceEnsureAggregate(schema, canonical, routeId, routePath, memberId, record);
const stored = Object.freeze({ schema: PRESENCE_STORAGE_SCHEMA, presence: schema.id, principal: canonical, routeId, routePath, memberId, nonce: body.nonce, tokenDigest, record, version, expiresAt: Date.now() + schema.ttlMilliseconds });
await presenceDelta(schema, "Joined", stored);
await presenceWriteStored(schema, stored, memberKey);
return Object.freeze({ stored, publishTag: "Joined" });
}, signal);
if (outcome.tombstone) {
await presencePublishAndClearTombstone(schema, outcome.tombstone, signal);
continue;
}
await presencePublish(schema, principal, await presenceDelta(schema, outcome.publishTag, outcome.stored));
return Object.freeze({ memberId });
}
}
if (!PRESENCE_CREDENTIAL.test(body.memberId) || !PRESENCE_CREDENTIAL.test(body.token)) throw presenceFailure("PRESENCE_CREDENTIAL_INVALID", "Presence mutation requires bounded opaque member credentials");
const memberKey = await presenceMemberKey(schema, canonical, routeId, routePath, body.memberId);
const tokenDigest = await presenceDigest(schema.id, canonical, routePath, body.memberId, body.token);
const outcome = await presencePartitionLock(schema, canonical, routeId, routePath, async () => {
const indexKey = presenceExpiryKey(memberKey);
const rawIndex = await presenceExpiryStorage.get(indexKey);
const index = rawIndex === null ? null : presenceValidateIndex(rawIndex, indexKey);
if (index !== null && (index.principal !== canonical || index.routeId !== routeId || index.routePath !== routePath || index.presence !== schema.id || index.memberId !== body.memberId)) throw presenceFailure("PRESENCE_INDEX_INVALID", "Presence mutation marker crossed its compiler-owned partition");
const raw = await presenceMemberStorage.get(memberKey);
if (index?.state === "left" || index?.state === "left-published") {
if (raw !== null) {
const stale = presenceValidateStored(schema, raw, memberKey);
if (!presenceDigestEqual(stale.tokenDigest, tokenDigest)) throw presenceFailure("PRESENCE_CREDENTIAL_DENIED", "Presence credentials do not own this route-bound membership");
await presenceMemberStorage.delete(memberKey);
}
return Object.freeze({ expired: true, tombstone: index.state === "left" ? index : null });
}
if (raw === null) return Object.freeze({ expired: true });
const stored = presenceValidateStored(schema, raw, memberKey);
if (stored.principal !== canonical || stored.routeId !== routeId || stored.routePath !== routePath || !presenceDigestEqual(stored.tokenDigest, tokenDigest)) throw presenceFailure("PRESENCE_CREDENTIAL_DENIED", "Presence credentials do not own this route-bound membership");
await presenceAdmitRate(operationalIdentity, "member", PRESENCE_MEMBER_WRITES_PER_MINUTE, [schema.id, routeId, routePath, stored.memberId]);
if (stored.expiresAt <= Date.now()) {
const tombstone = Object.freeze({ schema: PRESENCE_INDEX_SCHEMA, key: memberKey, presence: schema.id, principal: canonical, routeId, routePath, memberId: stored.memberId, version: stored.version + 1, expiresAt: stored.expiresAt, state: "left" });
await presenceExpiryStorage.set(presenceExpiryKey(memberKey), tombstone);
await presenceMemberStorage.delete(memberKey);
return Object.freeze({ expired: true, tombstone });
}
if (body.operation === "leave") {
const tombstone = Object.freeze({ schema: PRESENCE_INDEX_SCHEMA, key: memberKey, presence: schema.id, principal: canonical, routeId, routePath, memberId: stored.memberId, version: stored.version + 1, expiresAt: stored.expiresAt, state: "left" });
await presenceExpiryStorage.set(presenceExpiryKey(memberKey), tombstone);
await presenceMemberStorage.delete(memberKey);
return Object.freeze({ tombstone });
}
const nextRecord = body.operation === "update"
? presenceValidateType(schema.recordType, body.record, "PRESENCE_RECORD_INVALID")
: stored.record;
if (body.operation === "update") await presenceEnsureAggregate(schema, canonical, routeId, routePath, stored.memberId, nextRecord);
const unchanged = body.operation === "update" && JSON.stringify(nextRecord) === JSON.stringify(stored.record);
const next = Object.freeze({ ...stored, record: nextRecord, version: unchanged ? stored.version : stored.version + 1, expiresAt: Date.now() + schema.ttlMilliseconds });
if (body.operation === "update") await presenceDelta(schema, "Updated", next);
await presenceWriteStored(schema, next, memberKey);
return Object.freeze({ stored: next, publish: body.operation === "update" });
}, signal);
if (outcome.tombstone) await presencePublishAndClearTombstone(schema, outcome.tombstone, signal);
if (outcome.expired) throw presenceFailure("PRESENCE_MEMBERSHIP_EXPIRED", "Presence membership expired; reconnect for a fresh Snapshot and join again");
if (outcome.publish) await presencePublish(schema, principal, await presenceDelta(schema, "Updated", outcome.stored));
return Object.freeze({});
}
async function handlePresenceWriteRequest(request, url, environment, executionContext) {
if (request.method !== "POST") return failure(405, "PRESENCE_METHOD", "Presence writes require POST", LIVE_RESOURCE_SCHEMA.id, null, { allow: "POST" });
if (url.search !== "") return failure(400, "PRESENCE_QUERY_INVALID", "Presence writes do not accept query fields", LIVE_RESOURCE_SCHEMA.id);
const controller = new AbortController();
const abortPresenceRequest = () => controller.abort("Presence request was cancelled");
request.signal.addEventListener("abort", abortPresenceRequest, { once: true });
if (request.signal.aborted) abortPresenceRequest();
const timer = setTimeout(() => controller.abort("Presence write timed out"), LIVE_RESOURCE_SCHEMA.timeoutMs);
timer?.unref?.();
let schema = null;
try {
const body = await presenceReadRequest(request, controller.signal);
schema = presenceSchemaById.get(body.presence) ?? null;
if (schema === null) return failure(403, "PRESENCE_NOT_DECLARED", "Presence write is not present in the compiled manifest", body.presence ?? null);
const routeId = request.headers.get("x-noxid-route-id");
if (typeof routeId !== "string" || routeId.length === 0 || liveResourceEncoder.encode(routeId).byteLength > 512 || /[\u0000-\u001f\u007f]/.test(routeId)) return failure(400, "LIVE_RESOURCE_ROUTE_REQUIRED", "Presence writes require the compiler-selected route identity", schema.id);
const routeScope = schema.routeScopes.find((scope) => scope.id === routeId);
if (routeScope === undefined) return failure(403, "PRESENCE_ROUTE_DENIED", "Presence is not exposed by the compiler-selected route", schema.id, { route: routeId });
const route = liveRouteInstance(routeScope, request.headers.get("x-noxid-route-path"));
if (route === null) return failure(400, "LIVE_RESOURCE_ROUTE_PATH_INVALID", "Presence route path must exactly match its compiled route pattern and typed parameters", schema.id, { route: routeId });
const routeSchema = Object.freeze({ ...LIVE_RESOURCE_SCHEMA, id: routeScope.id, path: routeScope.pattern, method: "POST", middleware: routeScope.middleware });
const middleware = await applyEndpointMiddleware(request, routeSchema, route.params, Object.freeze({ presence: schema.id, operation: body.operation }), environment, executionContext, controller.signal);
if (controller.signal.aborted) return endpointTimeoutFailure(LIVE_RESOURCE_SCHEMA);
if (middleware.response) return endpointResponseWithHeaders(middleware.response, middleware.headers);
const denied = await liveResourceAuthorize(request, [schema], middleware.route, environment, executionContext, controller.signal);
if (denied) return endpointResponseWithHeaders(denied, middleware.headers);
const principal = __noxidLiveConnectionPrincipal(middleware.context, environment);
const operationalIdentity = presenceOperationalIdentity(environment, middleware.context, principal);
if (operationalIdentity === null) return failure(403, "PRESENCE_RATE_IDENTITY_REQUIRED", "Public presence writes require a trusted request identity for operational abuse controls", schema.id);
await presenceAdmitRate(operationalIdentity, "abuse", PRESENCE_ABUSE_ATTEMPTS_PER_MINUTE);
if (body.operation === "join") await presenceAdmitRate(operationalIdentity, "join", PRESENCE_JOINS_PER_MINUTE);
const result = await presenceMutate(schema, principal, operationalIdentity, routeId, route.path, body, controller.signal);
if (controller.signal.aborted) return endpointTimeoutFailure(LIVE_RESOURCE_SCHEMA);
return endpointResponseWithHeaders(json(200, Object.freeze({ ok: true, ...result })), middleware.headers);
} catch (cause) {
if (controller.signal.aborted || cause?.code === "PRESENCE_OPERATION_ABORTED") return endpointTimeoutFailure(LIVE_RESOURCE_SCHEMA);
const clientCodes = new Set(["PRESENCE_CREDENTIAL_INVALID", "PRESENCE_RECORD_INVALID", "PRESENCE_RECORD_TOO_LARGE", "PRESENCE_SNAPSHOT_TOO_LARGE", "PRESENCE_CAPACITY_EXCEEDED"]);
const status = cause?.code === "PRESENCE_BODY_TOO_LARGE" ? 413
: cause?.code === "PRESENCE_BODY_INVALID" || cause?.code === "PRESENCE_CONTENT_TYPE_REQUIRED" ? 400
: cause?.code === "PRESENCE_CREDENTIAL_DENIED" ? 403
: cause?.code === "PRESENCE_MEMBERSHIP_EXPIRED" ? 409
: cause?.code === "PRESENCE_RATE_LIMITED" ? 429
: cause?.code === "PRESENCE_STORAGE_UNAVAILABLE" ? 503
: clientCodes.has(cause?.code) ? 422 : 500;
return failure(status, cause?.code ?? "PRESENCE_WRITE_FAILED", cause?.message ?? "Presence write failed", schema?.id ?? LIVE_RESOURCE_SCHEMA.id, null, cause?.retryAfter === undefined ? {} : { "retry-after": String(cause.retryAfter) });
} finally {
clearTimeout(timer);
request.signal.removeEventListener("abort", abortPresenceRequest);
}
}
async function handleLiveResourceRequest(request, url, environment, executionContext) {
if (url.pathname === presenceWritePath) return handlePresenceWriteRequest(request, url, environment, executionContext);
if (url.pathname !== liveResourcePath) return null;
const subscription = liveResourceSubscription(request, url);
if (subscription.response) return subscription.response;
const deadlineController = new AbortController();
let deadlineReleased = false;
let streamOwnsDeadline = false;
let resolveDeadline;
const deadlineResponse = new Promise((resolve) => { resolveDeadline = resolve; });
const expire = () => {
if (deadlineReleased) return;
deadlineController.abort("Live resource connection lifetime ended");
resolveDeadline(endpointTimeoutFailure(LIVE_RESOURCE_SCHEMA));
};
const deadlineTimer = setTimeout(expire, LIVE_RESOURCE_SCHEMA.timeoutMs);
deadlineTimer?.unref?.();
request.signal.addEventListener("abort", expire, { once: true });
const deadline = Object.freeze({
signal: deadlineController.signal,
release() {
if (deadlineReleased) return;
deadlineReleased = true;
clearTimeout(deadlineTimer);
request.signal.removeEventListener("abort", expire);
},
});
const setup = async () => {
const routeSchema = Object.freeze({ ...LIVE_RESOURCE_SCHEMA, id: subscription.routeScope.id, path: subscription.routeScope.pattern, middleware: subscription.routeScope.middleware });
const middleware = await applyEndpointMiddleware(request, routeSchema, subscription.params, Object.freeze({ resource: subscription.ids, presence: subscription.presenceIds }), environment, executionContext, deadline.signal);
if (deadline.signal.aborted) return endpointTimeoutFailure(LIVE_RESOURCE_SCHEMA);
if (middleware.response) return endpointResponseWithHeaders(middleware.response, middleware.headers);
const authorizationFailure = await liveResourceAuthorize(request, subscription.schemas, middleware.route, environment, executionContext, deadline.signal);
if (deadline.signal.aborted) return endpointTimeoutFailure(LIVE_RESOURCE_SCHEMA);
if (authorizationFailure) return endpointResponseWithHeaders(authorizationFailure, middleware.headers);
const principal = __noxidLiveConnectionPrincipal(middleware.context, environment);
const suppliedCursor = request.headers.get("last-event-id");
if (suppliedCursor !== null) {
const resumed = liveResourceResumeHistory(suppliedCursor, principal.canonical, subscription.key);
if (resumed === null) return liveResourceResetResponse(middleware.headers);
const response = liveResourceStream(request, subscription.resourceSchemas, subscription.presenceSchemas, principal, subscription.routeScope.id, subscription.routePath, resumed.history, resumed.replay, middleware.headers, deadline);
streamOwnsDeadline = true;
return response;
}
const history = liveResourceFreshHistory(principal.canonical, subscription.key);
if (history === null) return failure(503, "LIVE_RESOURCE_CAPACITY", "Live resource replay capacity is temporarily exhausted", LIVE_RESOURCE_SCHEMA.id);
const response = liveResourceStream(request, subscription.resourceSchemas, subscription.presenceSchemas, principal, subscription.routeScope.id, subscription.routePath, history, [], middleware.headers, deadline);
streamOwnsDeadline = true;
return response;
};
try { return await Promise.race([setup(), deadlineResponse]); }
finally { if (!streamOwnsDeadline) deadline.release(); }
}
"##;
const HANDLER_RUNTIME: &str = r#"/* noxid-server:live-invalidation */
function json(status, body, headers = {}) {
return new Response(JSON.stringify(body), {
status,
headers: { "content-type": "application/json; charset=utf-8", "cache-control": "no-store", "x-content-type-options": "nosniff", ...headers },
});
}
function failure(status, code, message, semanticId = null, details = null, headers = {}, traceable = true) {
const response = json(status, { ok: false, error: { code, message, semanticId, details } }, headers);
return traceable ? __noxidTraceFailure(response, code, semanticId, details?.capability) : response;
}
const SSR_MIDDLEWARE_STATE = Symbol.for("noxid.ssr.middleware.state");
const EMPTY_MIDDLEWARE_CONTEXT = Object.freeze({});
function inheritedMiddlewareState(scope, executionContext) {
const state = executionContext?.[SSR_MIDDLEWARE_STATE];
if (!state || state.routeId !== scope.id || !Array.isArray(state.applied)) return null;
const expected = [...globalMiddleware, ...scope.middleware];
if (state.applied.length !== expected.length || !expected.every((name, index) => state.applied[index] === name)) return null;
return state;
}
function splitGeneric(type, prefix) {
if (!type.startsWith(`${prefix}<`) || !type.endsWith(">")) return null;
return type.slice(prefix.length + 1, -1);
}
function splitGenericPair(type, prefix) {
const body = splitGeneric(type, prefix);
if (body === null) return null;
let depth = 0;
for (let index = 0; index < body.length; index += 1) {
if (body[index] === "<") depth += 1;
else if (body[index] === ">") depth -= 1;
else if (body[index] === "," && depth === 0) return [body.slice(0, index).trim(), body.slice(index + 1).trim()];
}
return null;
}
function valid(value) { return { value }; }
function invalid(issue, details = null) { return { issue, details }; }
function validateType(type, value, path, typeId = null, external = false, ancestors = new WeakSet()) {
if (type === "String") return typeof value === "string" ? valid(value) : invalid(`${path} must be String`);
if (type === "Boolean") return typeof value === "boolean" ? valid(value) : invalid(`${path} must be Boolean`);
if (type === "Int") return Number.isSafeInteger(value) ? valid(value) : invalid(`${path} must be Int`);
if (type === "Number" || type === "Float") return typeof value === "number" && Number.isFinite(value) ? valid(value) : invalid(`${path} must be ${type}`);
if (type === "Date") return typeof value === "string" && (external ? queueUtcInstant(value) !== null : !Number.isNaN(Date.parse(value))) ? valid(value) : invalid(`${path} must be a UTC ISO Date string`);
const optional = splitGeneric(type, "Optional");
if (optional !== null) return value == null ? valid(external ? null : value) : validateType(optional, value, path, typeId, external, ancestors);
const array = splitGeneric(type, "Array");
if (array !== null) {
if (!Array.isArray(value)) return invalid(`${path} must be ${type}`);
if (ancestors.has(value)) return invalid(`${path} must be acyclic ordinary data`);
ancestors.add(value);
const trusted = [];
try {
const lengthDescriptor = Object.getOwnPropertyDescriptor(value, "length");
if (!lengthDescriptor || !("value" in lengthDescriptor) || !Number.isSafeInteger(lengthDescriptor.value) || lengthDescriptor.value < 0) return invalid(`${path} must be an ordinary dense Array`);
const length = lengthDescriptor.value;
const keys = Reflect.ownKeys(value);
if (external && keys.some((key) => key !== "length" && (typeof key !== "string" || !/^(0|[1-9]\d*)$/.test(key) || Number(key) >= length))) return invalid(`${path} must not contain undeclared array properties`);
for (let index = 0; index < length; index += 1) {
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
if (descriptor !== undefined && (!("value" in descriptor) || !descriptor.enumerable)) return invalid(`${path}[${index}] must be own enumerable array data`);
const result = validateType(array, descriptor?.value, `${path}[${index}]`, typeId, external, ancestors);
if (result.issue) return result;
trusted.push(result.value);
}
return valid(Object.freeze(trusted));
} catch {
return invalid(`${path} must be an ordinary dense Array`);
} finally {
ancestors.delete(value);
}
}
const map = splitGenericPair(type, "Map");
if (map !== null && map[0] === "String") {
let keys;
try {
if (value === null || typeof value !== "object" || Array.isArray(value)) return invalid(`${path} must be ${type}`);
const prototype = Object.getPrototypeOf(value);
if (prototype !== Object.prototype && prototype !== null) return invalid(`${path} must be ${type}`);
keys = Reflect.ownKeys(value);
} catch { return invalid(`${path} must be ${type}`); }
if (keys.some((key) => typeof key !== "string")) return invalid(`${path} must contain String keys`);
const trusted = Object.create(null);
for (const key of keys.sort()) {
if (key === "__proto__" || key === "constructor" || key === "prototype") return invalid(`${path}.${key} must use a safe String map key`);
let descriptor;
try { descriptor = Object.getOwnPropertyDescriptor(value, key); } catch {}
if (descriptor === undefined || !("value" in descriptor) || !descriptor.enumerable) return invalid(`${path}.${key} must be ordinary data`);
const result = validateType(map[1], descriptor.value, `${path}.${key}`, typeId, external, ancestors);
if (result.issue) return result;
trusted[key] = result.value;
}
return valid(Object.freeze(trusted));
}
const resultType = splitGenericPair(type, "Result");
if (resultType !== null) {
let keys, tag, payload;
try {
if (value === null || typeof value !== "object" || Array.isArray(value)) return invalid(`${path} must be ${type}`);
const prototype = Object.getPrototypeOf(value);
if (prototype !== Object.prototype && prototype !== null) return invalid(`${path} must be ${type}`);
keys = Reflect.ownKeys(value);
const tagDescriptor = Object.getOwnPropertyDescriptor(value, "tag");
const valueDescriptor = Object.getOwnPropertyDescriptor(value, "value");
if (!tagDescriptor || !("value" in tagDescriptor) || !tagDescriptor.enumerable || !valueDescriptor || !("value" in valueDescriptor) || !valueDescriptor.enumerable) return invalid(`${path} must be an Ok(value) or Err(error) result`);
tag = tagDescriptor.value;
payload = valueDescriptor.value;
} catch { return invalid(`${path} must be ${type}`); }
if (!keys.every((key) => key === "tag" || key === "value") || (tag !== "Ok" && tag !== "Err")) return invalid(`${path} must be an Ok(value) or Err(error) result`);
const inner = tag === "Ok" ? resultType[0] : resultType[1];
const checked = validateType(inner, payload, `${path}.${tag}`, typeId, external, ancestors);
return checked.issue ? checked : valid(Object.freeze({ tag, value: checked.value }));
}
const validatorId = typeId !== null && typeof typeId === "object" ? typeId[type] ?? null : typeId;
const validator = validatorId === null ? null : typeValidators[validatorId];
if (typeof validator === "function") {
try { return valid(validator(value, external)); }
catch (cause) {
return invalid(`${path} must satisfy ${type}`, typeof cause?.toJSON === "function" ? cause.toJSON() : null);
}
}
return invalid(`${path} uses unsupported boundary type ${type}`);
}
const ACTION_BODY_MAX_BYTES = 1_048_576;
// The action body is read off the stream with a hard byte ceiling, never
// buffered whole and measured afterwards. `Content-Length` is a claim the
// caller makes: it can be absent (a chunked request) or a lie, so it is only
// ever an early refusal and never the enforcement. Reading stops the moment
// one byte past the cap arrives, and the reader is cancelled, so a request
// that promises 10 bytes and sends 96 MiB costs the cap, not the body.
async function readBoundedActionBody(request) {
if (request.body === null) return { text: "" };
const reader = request.body.getReader();
const chunks = [];
let total = 0;
try {
while (true) {
const chunk = await reader.read();
if (chunk.done) break;
if (!(chunk.value instanceof Uint8Array)) return { invalid: true };
total += chunk.value.byteLength;
if (total > ACTION_BODY_MAX_BYTES) return { tooLarge: true };
chunks.push(chunk.value);
}
}
catch { return { invalid: true }; }
// Never awaited: when the caller cloned the request the body is a `tee`
// branch, and a branch's `cancel()` does not settle until every branch has
// let go. Awaiting it here deadlocks the refusal it exists to deliver.
finally { try { void reader.cancel().catch(() => {}); } catch {} }
const bytes = new Uint8Array(total);
let offset = 0;
for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.byteLength; }
return { text: new TextDecoder().decode(bytes) };
}
async function decodeArguments(request, schema) {
const contentType = request.headers.get("content-type")?.split(";", 1)[0].trim().toLowerCase();
if (contentType !== "application/json") return { error: failure(415, "BOUNDARY_CONTENT_TYPE", "Noxid action requests require application/json", schema.id) };
const declaredLength = Number(request.headers.get("content-length") ?? 0);
if (Number.isFinite(declaredLength) && declaredLength > ACTION_BODY_MAX_BYTES) return { error: failure(413, "BOUNDARY_BODY_TOO_LARGE", "Noxid action request exceeds 1 MiB", schema.id) };
const bounded = await readBoundedActionBody(request);
if (bounded.tooLarge === true) return { error: failure(413, "BOUNDARY_BODY_TOO_LARGE", "Noxid action request exceeds 1 MiB", schema.id) };
if (bounded.invalid === true) return { error: failure(400, "BOUNDARY_BODY_INVALID", "Request body is not valid JSON", schema.id) };
let body;
try { body = JSON.parse(bounded.text); }
catch { return { error: failure(400, "BOUNDARY_BODY_INVALID", "Request body is not valid JSON", schema.id) }; }
if (!body || typeof body !== "object" || Array.isArray(body) || !body.arguments || typeof body.arguments !== "object" || Array.isArray(body.arguments)) {
return { error: failure(400, "BOUNDARY_BODY_INVALID", "Request body must contain an arguments object", schema.id) };
}
const expected = new Set(schema.parameters.map((parameter) => parameter.name));
const unexpected = Object.keys(body.arguments).filter((name) => !expected.has(name));
if (unexpected.length) return { error: failure(400, "BOUNDARY_ARGUMENT_UNKNOWN", `Unknown action argument: ${unexpected[0]}`, schema.id, { argument: unexpected[0] }) };
const values = Object.create(null);
for (const parameter of schema.parameters) {
if (!Object.hasOwn(body.arguments, parameter.name)) return { error: failure(400, "BOUNDARY_ARGUMENT_MISSING", `Missing action argument: ${parameter.name}`, schema.id, { argument: parameter.name }) };
const result = validateType(parameter.type, body.arguments[parameter.name], `arguments.${parameter.name}`, parameter.typeId);
if (result.issue) return { error: failure(422, result.issue.includes("unsupported boundary type") ? "BOUNDARY_SCHEMA_UNSUPPORTED" : "BOUNDARY_ARGUMENT_TYPE", result.issue, schema.id, { argument: parameter.name, expected: parameter.type, validation: result.details }) };
values[parameter.name] = result.value;
}
return { arguments: Object.freeze(values) };
}
function resolveRouteScope(request, schema) {
const routeId = request.headers.get("x-noxid-route-id");
if (typeof routeId !== "string" || routeId.length === 0) {
return { error: failure(400, "BOUNDARY_ROUTE_REQUIRED", "Noxid action requests require a compiled route identity", schema.id) };
}
const scope = schema.routeScopes.find((candidate) => candidate.id === routeId);
if (!scope) {
return { error: failure(403, "BOUNDARY_ROUTE_DENIED", "Action is not exposed by the requested route", schema.id, { route: routeId }) };
}
return { scope };
}
function withMiddlewareHeaders(response, pairs) {
if (!pairs || pairs.length === 0) return response;
const headers = new Headers(response.headers);
for (const [name, value] of pairs) headers.append(name, value);
return __noxidTraceCopyFailure(response, new Response(response.body, { status: response.status, headers }));
}
async function applyMiddleware(request, schema, scope, environment, executionContext) {
const headers = [];
const inherited = inheritedMiddlewareState(scope, executionContext);
if (inherited) return { failure: null, headers, context: inherited.context };
const context = Object.create(null);
const chain = [
...globalMiddleware.map((name) => Object.freeze({ name, handle: globalMiddlewareHandlers[name] })),
...scope.middleware.map((name) => Object.freeze({ name, handle: middlewareHandlers[name] })),
];
const names = chain.map((entry) => entry.name);
const route = Object.freeze({ ...scope, middleware: Object.freeze(names) });
__noxidTraceRoute(request, route.pattern);
for (const { name, handle } of chain) {
__noxidTraceSemantic(request, "middleware", name.startsWith("middleware:") ? name : `middleware:${name}`);
if (typeof handle !== "function") {
return { failure: failure(500, "BOUNDARY_MIDDLEWARE_MISSING", "Required server middleware is not available", schema.id, { middleware: name, route: scope.id }), headers };
}
let result;
try {
result = await handle(__noxidDataContext({
middleware: name,
semanticId: schema.id,
traceId: __noxidTraceIdForRequest(request),
boundary: schema.boundary,
target: schema.target,
route,
request,
url: new URL(request.url),
host: hostModule,
environment,
executionContext,
context: Object.freeze({ ...context }),
middlewareContext: Object.freeze({ ...context }),
}, __noxidPrincipal(context, environment, __noxidAgentForRequest(request))));
} catch {
return { failure: failure(500, "BOUNDARY_MIDDLEWARE_FAILED", "Server middleware failed", schema.id, { middleware: name, route: scope.id }), headers };
}
const normalized = __noxidNormalizeMiddlewareResult(result);
if (normalized.issue === "headers") {
return { failure: failure(500, "BOUNDARY_MIDDLEWARE_HEADERS", "Server middleware returned a disallowed response header", schema.id, { middleware: name, route: scope.id, header: normalized.detail }), headers: [] };
}
if (normalized.issue === "response") {
return { failure: failure(500, "BOUNDARY_MIDDLEWARE_RESPONSE", "Server middleware returned an invalid direct response", schema.id, { middleware: name, route: scope.id, validation: normalized.detail }), headers };
}
if (normalized.issue === "context") {
return { failure: failure(500, "BOUNDARY_MIDDLEWARE_CONTEXT", "Server middleware returned invalid context", schema.id, { middleware: name, route: scope.id, validation: normalized.detail }), headers };
}
headers.push(...normalized.headers);
if (normalized.respond !== null) {
return { failure: failure(409, "BOUNDARY_MIDDLEWARE_RESPONSE", "Server action middleware cannot produce a direct response; respond belongs to SSR routes", schema.id, { middleware: name, route: scope.id }), headers };
}
if (normalized.redirect !== null) {
return { failure: failure(409, "BOUNDARY_MIDDLEWARE_REDIRECT", "Server action middleware requested navigation", schema.id, { middleware: name, route: scope.id, redirect: normalized.redirect }), headers };
}
if (!normalized.allow) {
return { failure: failure(403, "BOUNDARY_MIDDLEWARE_DENIED", "Server middleware denied the action", schema.id, { middleware: name, route: scope.id }), headers };
}
if (normalized.context !== null) Object.assign(context, normalized.context);
}
return { failure: null, headers, context: Object.freeze({ ...context }) };
}
async function authorizeAction(request, schema, scope, environment, executionContext) {
if (schema.capabilities.length === 0) return null;
if (typeof authorize !== "function") {
return failure(500, "BOUNDARY_AUTHORIZER_MISSING", "Action authorization is not configured", schema.id);
}
for (const capability of schema.capabilities) {
let allowed = false;
try {
allowed = await authorize(Object.freeze({
capability,
semanticId: schema.id,
traceId: __noxidTraceIdForRequest(request),
target: schema.target,
route: scope,
request,
environment,
executionContext,
})) === true;
} catch {}
if (!allowed) {
return failure(403, "BOUNDARY_CAPABILITY_DENIED", "Action capability was denied", schema.id, { capability });
}
}
return null;
}
async function handleInvalidation(request, environment, executionContext) {
if (request.method !== "POST") return failure(405, "CACHE_INVALIDATION_METHOD", "Cache invalidation requires POST", null, null, { allow: "POST" });
const contentType = request.headers.get("content-type")?.split(";", 1)[0].trim().toLowerCase();
if (contentType !== "application/json") return failure(415, "CACHE_INVALIDATION_CONTENT_TYPE", "Cache invalidation body requires application/json", "cache-invalidation:on-demand");
const declaredLength = Number(request.headers.get("content-length") ?? 0);
if (Number.isFinite(declaredLength) && declaredLength > 1_048_576) return failure(413, "CACHE_INVALIDATION_BODY_TOO_LARGE", "Cache invalidation body exceeds 1 MiB", "cache-invalidation:on-demand");
const chunks = [];
let total = 0;
if (request.body !== null) {
let reader;
try {
reader = request.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
if (!(value instanceof Uint8Array)) return failure(400, "CACHE_INVALIDATION_BODY_INVALID", "Cache invalidation body stream did not yield bytes", "cache-invalidation:on-demand");
total += value.byteLength;
if (total > 1_048_576) {
await reader.cancel("cache invalidation body too large").catch(() => {});
return failure(413, "CACHE_INVALIDATION_BODY_TOO_LARGE", "Cache invalidation body exceeds 1 MiB", "cache-invalidation:on-demand");
}
chunks.push(value);
}
} catch {
return failure(400, "CACHE_INVALIDATION_BODY_INVALID", "Cache invalidation body stream could not be read", "cache-invalidation:on-demand");
} finally {
try { reader?.releaseLock(); } catch {}
}
}
const bytes = new Uint8Array(total);
let offset = 0;
for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.byteLength; }
let text;
try { text = new TextDecoder("utf-8", { fatal: true }).decode(bytes); }
catch { return failure(400, "CACHE_INVALIDATION_BODY_INVALID", "Cache invalidation body is not valid UTF-8", "cache-invalidation:on-demand"); }
let body;
try { body = JSON.parse(text); }
catch { return failure(400, "CACHE_INVALIDATION_BODY_INVALID", "Cache invalidation body must be JSON", "cache-invalidation:on-demand"); }
let bodyKeys;
let tagsDescriptor;
try {
if (body === null || typeof body !== "object" || Array.isArray(body) || Object.getPrototypeOf(body) !== Object.prototype) {
return failure(400, "CACHE_INVALIDATION_BODY_INVALID", "Cache invalidation body must be an ordinary JSON object containing only tags", "cache-invalidation:on-demand");
}
bodyKeys = Reflect.ownKeys(body);
tagsDescriptor = Object.getOwnPropertyDescriptor(body, "tags");
} catch {
return failure(400, "CACHE_INVALIDATION_BODY_INVALID", "Cache invalidation body shape could not be inspected safely", "cache-invalidation:on-demand");
}
if (bodyKeys.length !== 1 || bodyKeys[0] !== "tags" || tagsDescriptor === undefined || !("value" in tagsDescriptor) || tagsDescriptor.enumerable !== true || tagsDescriptor.configurable !== true || tagsDescriptor.writable !== true) {
return failure(400, "CACHE_INVALIDATION_BODY_INVALID", "Cache invalidation body must declare only an ordinary own tags field", "cache-invalidation:on-demand");
}
const rawTags = tagsDescriptor.value;
if (!Array.isArray(rawTags) || rawTags.length === 0 || rawTags.length > 32) return failure(400, "CACHE_INVALIDATION_TAGS_INVALID", "Cache invalidation requires 1 to 32 tags");
const tags = [...new Set(rawTags)];
if (tags.some((tag) => typeof tag !== "string" || tag.length === 0 || tag.length > 128 || !/^[a-zA-Z0-9_.:@-]+$/.test(tag))) return failure(400, "CACHE_INVALIDATION_TAGS_INVALID", "Cache invalidation tags contain unsafe values");
if (typeof authorize !== "function") return failure(500, "CACHE_INVALIDATION_AUTHORIZER_MISSING", "Cache invalidation authorization is not configured");
let allowed = false;
try {
allowed = await authorize(Object.freeze({ capability: "cache.invalidate", semanticId: "cache-invalidation:on-demand", traceId: __noxidTraceIdForRequest(request), target: "server", route: null, request, environment, executionContext })) === true;
} catch {}
if (!allowed) return failure(403, "CACHE_INVALIDATION_DENIED", "Cache invalidation capability was denied", "cache-invalidation:on-demand");
if (typeof invalidateCache !== "function") return failure(501, "CACHE_INVALIDATION_UNAVAILABLE", "The deployment host has no cache invalidation adapter", "cache-invalidation:on-demand");
try {
const result = await invalidateCache(Object.freeze(tags), Object.freeze({ request, environment, executionContext, semanticId: "cache-invalidation:on-demand", traceId: __noxidTraceIdForRequest(request) }));
return json(200, { ok: true, tags, result: result ?? null });
} catch { return failure(500, "CACHE_INVALIDATION_FAILED", "The deployment cache invalidation adapter failed", "cache-invalidation:on-demand"); }
}
function taskSchemaByName(name) {
return taskSchemas.find((schema) => schema.name === name) ?? null;
}
async function invokeTask(name, context = Object.create(null)) {
const schema = taskSchemaByName(name);
if (schema === null) throw Object.assign(new Error("Unknown scheduled task " + name), { code: "TASK_NOT_FOUND", semanticId: null });
const implementation = compiledTasks[schema.id] ?? hostTasks[schema.id];
if (typeof implementation !== "function") {
throw Object.assign(new Error("No host implementation is registered for " + schema.id), {
code: "TASK_IMPLEMENTATION_MISSING",
semanticId: schema.id,
});
}
const taskSpan = __noxidTraceBeginSemantic(context.request ?? null);
const traceId = taskSpan?.trace?.id ?? null;
try {
return await implementation(
Object.freeze(Object.create(null)),
__noxidDataContext({ ...context, semanticId: schema.id, traceId, task: schema.name, schedule: schema.schedule }, __NOXID_SYSTEM_PRINCIPAL),
);
} finally {
__noxidTraceFinishSemantic(taskSpan, "task", schema.id);
}
}
async function handleTaskRequest(request, url, environment, executionContext) {
if (!url.pathname.startsWith(taskPrefix)) return null;
if (request.method !== "POST") return failure(405, "TASK_METHOD", "Scheduled task triggers require POST", null, null, { allow: "POST" });
let name;
try { name = decodeURIComponent(url.pathname.slice(taskPrefix.length)); }
catch { return failure(400, "TASK_NAME_INVALID", "Task name is not valid URL encoding"); }
const schema = taskSchemaByName(name);
if (schema === null) return failure(404, "TASK_NOT_FOUND", "Unknown scheduled task " + name);
if (typeof authorize !== "function") return failure(500, "TASK_AUTHORIZER_MISSING", "Scheduled task authorization is not configured", schema.id, { capability: "tasks.run" });
let allowed = false;
try {
allowed = await authorize(Object.freeze({
capability: "tasks.run",
semanticId: schema.id,
traceId: __noxidTraceIdForRequest(request),
target: "server",
route: null,
request,
environment,
executionContext,
})) === true;
} catch {}
if (!allowed) return failure(403, "TASK_CAPABILITY_DENIED", "Scheduled task capability was denied", schema.id, { capability: "tasks.run" });
try {
const value = await invokeTask(name, { request, environment, executionContext });
return json(200, { ok: true, value: value === undefined ? null : value });
} catch (cause) {
if (cause?.code === "TASK_IMPLEMENTATION_MISSING") {
return failure(501, cause.code, "Scheduled task host implementation is missing", schema.id);
}
return failure(500, "TASK_EXECUTION_FAILED", "Scheduled task execution failed", schema.id);
}
}
function cronPartMatches(part, value, minimum, maximum) {
const [base, rawStep] = part.split("/");
const step = rawStep === undefined ? 1 : Number(rawStep);
let start = minimum;
let end = maximum;
if (base !== "*") {
if (base.includes("-")) [start, end] = base.split("-").map(Number);
else {
start = Number(base);
end = rawStep === undefined ? start : maximum;
}
}
return value >= start && value <= end && (value - start) % step === 0;
}
function cronFieldMatches(field, value, minimum, maximum) {
return field.split(",").some((part) => cronPartMatches(part, value, minimum, maximum));
}
function cronMatches(schedule, date) {
const fields = schedule.trim().split(/\s+/);
const minute = cronFieldMatches(fields[0], date.getUTCMinutes(), 0, 59);
const hour = cronFieldMatches(fields[1], date.getUTCHours(), 0, 23);
const month = cronFieldMatches(fields[3], date.getUTCMonth() + 1, 1, 12);
const dayOfMonth = cronFieldMatches(fields[2], date.getUTCDate(), 1, 31);
const weekday = date.getUTCDay();
const dayOfWeek = cronFieldMatches(fields[4], weekday, 0, 7)
|| (weekday === 0 && cronFieldMatches(fields[4], 7, 0, 7));
const anyDayOfMonth = fields[2] === "*";
const anyDayOfWeek = fields[4] === "*";
const day = anyDayOfMonth || anyDayOfWeek
? dayOfMonth && dayOfWeek
: dayOfMonth || dayOfWeek;
return minute && hour && month && day;
}
export function startTaskScheduler(environment = Object.create(null), executionContext = Object.create(null), options = Object.create(null)) {
environment = __noxidConfiguredServerEnvironment(environment);
const setTimer = options.setTimeout ?? globalThis.setTimeout;
const clearTimer = options.clearTimeout ?? globalThis.clearTimeout;
const now = options.now ?? (() => new Date());
const origin = options.origin ?? "http://noxid.local";
const report = options.onError ?? ((task, error) => console.error("Noxid scheduled task " + task + " failed", error));
const running = new Map();
let timer = null;
let stopped = false;
let stopJoin = null;
const runDue = (instant) => {
for (const task of taskSchedules) {
if (!cronMatches(task.schedule, instant) || running.has(task.name)) continue;
const request = new Request(origin + taskPrefix + encodeURIComponent(task.name), { method: "POST" });
const execution = Promise.resolve(fetch(request, environment, executionContext))
.then(async (response) => {
if (!response.ok) {
let detail = null;
try { detail = await response.json(); } catch {}
throw Object.assign(new Error("task trigger returned " + response.status), { response: detail });
}
})
.catch((error) => report(task.name, error))
.finally(() => running.delete(task.name));
running.set(task.name, execution);
}
};
const scheduleNext = () => {
if (stopped || taskSchedules.length === 0) return;
const instant = now();
const nextMinute = new Date(Math.floor(instant.getTime() / 60_000) * 60_000 + 60_000);
timer = setTimer(() => {
if (stopped) return;
runDue(nextMinute);
scheduleNext();
}, Math.max(0, nextMinute.getTime() - instant.getTime()));
};
scheduleNext();
return Object.freeze({
stop() {
if (stopJoin !== null) return stopJoin;
stopped = true;
if (timer !== null) clearTimer(timer);
timer = null;
stopJoin = Promise.allSettled([...running.values()]);
return stopJoin;
},
});
}
/* noxid-server:live-resource-transport-runtime */
export async function fetchEndpoint(request, environment = Object.create(null), executionContext = Object.create(null)) {
environment = __noxidConfiguredServerEnvironment(environment);
return withNoxidRequestTrace(request, async () => {
/* noxid-server:startup */
const url = new URL(request.url);
/* noxid-server:live-resource-request */
const queueDrainResponse = await handleQueueDrainRequest(request, url, environment, executionContext);
if (queueDrainResponse !== null) return queueDrainResponse;
const agentSurfaceResponse = await handleAgentSurfaceRequest(request, url, environment, executionContext);
if (agentSurfaceResponse !== null) return agentSurfaceResponse;
return handleEndpointRequest(request, url, environment, executionContext);
});
}
export async function fetch(request, environment = Object.create(null), executionContext = Object.create(null)) {
environment = __noxidConfiguredServerEnvironment(environment);
return withNoxidRequestTrace(request, async () => {
const url = new URL(request.url);
const endpointResponse = await fetchEndpoint(request, environment, executionContext);
if (endpointResponse !== null) return endpointResponse;
const taskResponse = await handleTaskRequest(request, url, environment, executionContext);
if (taskResponse !== null) return taskResponse;
if (url.pathname === invalidationEndpoint) return handleInvalidation(request, environment, executionContext);
if (!url.pathname.startsWith(endpointPrefix)) return failure(404, "BOUNDARY_NOT_FOUND", "No Noxid action exists at this path");
if (request.method !== "POST") return failure(405, "BOUNDARY_METHOD", "Noxid actions require POST", null, null, { allow: "POST" });
let actionId;
try { actionId = decodeURIComponent(url.pathname.slice(endpointPrefix.length)); }
catch { return failure(400, "BOUNDARY_ID_INVALID", "Action identifier is not valid URL encoding"); }
const schema = schemas[actionId];
if (!schema) return failure(404, "BOUNDARY_NOT_FOUND", `Unknown Noxid action ${actionId}`, actionId);
const implementation = compiledActions[actionId] ?? hostActions[actionId];
if (typeof implementation !== "function") return failure(501, "BOUNDARY_IMPLEMENTATION_MISSING", `No host implementation is registered for ${actionId}`, actionId);
const resolvedRoute = resolveRouteScope(request, schema);
if (resolvedRoute.error) return resolvedRoute.error;
const scope = resolvedRoute.scope;
const middlewareOutcome = await applyMiddleware(request, schema, scope, environment, executionContext);
const middlewareHeaders = middlewareOutcome.headers;
if (middlewareOutcome.failure) return withMiddlewareHeaders(middlewareOutcome.failure, middlewareHeaders);
const authorizationFailure = await authorizeAction(request, schema, scope, environment, executionContext);
if (authorizationFailure) return withMiddlewareHeaders(authorizationFailure, middlewareHeaders);
const decoded = await decodeArguments(request, schema);
if (decoded.error) return withMiddlewareHeaders(decoded.error, middlewareHeaders);
const actionSpan = __noxidTraceBeginSemantic(request);
try {
const middlewareContext = middlewareOutcome.context ?? EMPTY_MIDDLEWARE_CONTEXT;
const actionPrincipal = __noxidPrincipal(middlewareContext, environment, __noxidAgentForRequest(request));
const value = await implementation(decoded.arguments, __noxidDataContext({ request, environment, executionContext, semanticId: schema.id, traceId: __noxidTraceIdForRequest(request), target: schema.target, route: scope, capabilities: schema.capabilities, middlewareContext }, actionPrincipal));
const result = validateType(schema.result.type, value, "result", schema.result.typeId);
if (result.issue) return withMiddlewareHeaders(failure(500, "BOUNDARY_RESULT_TYPE", "Action returned a value that violates its declared result type", schema.result.id, { expected: schema.result.type, validation: result.details }), middlewareHeaders);
await __noxidPublishLiveInvalidations(schema.invalidates, actionPrincipal);
return withMiddlewareHeaders(json(200, { ok: true, value: result.value === undefined ? null : result.value }), middlewareHeaders);
} catch (cause) {
const code = typeof cause?.code === "string" ? cause.code : "BOUNDARY_EXECUTION_FAILED";
const message = cause?.expose === true && typeof cause?.message === "string" ? cause.message : "Action execution failed";
return withMiddlewareHeaders(failure(500, code, message, schema.id, null, {}, false), middlewareHeaders);
} finally {
__noxidTraceFinishSemantic(actionSpan, "action", schema.id, { route: scope?.pattern });
}
});
}
globalThis.__NOXID_FETCH_HANDLER__ = fetch;
export default Object.freeze({ fetch });
"#;
#[cfg(test)]
mod tests {
use super::*;
use noxid_execution_ir::{
EndpointExecutionBoundary, EndpointExecutionInput, ExecutionBoundary, ExecutionParameter,
ExecutionResult, ExecutionRouteScope, LiveResourceExecutionContract,
PresenceExecutionContract, PresenceExecutionField, QueueExecutionField,
};
use noxid_ir::{
EndpointCacheMode, EndpointCachePolicy, EndpointInputSection, EndpointKind,
EndpointLimitPolicy, EndpointLimitScope, EndpointLimitWindow, EndpointMethod,
ExecutionTarget, SemanticBinaryOp, SemanticExpr, SemanticExprKind, SemanticId,
};
use noxid_source::Span;
use noxid_types::Type;
use std::process::Command;
use std::time::{SystemTime, UNIX_EPOCH};
// These tests all pass bodies the emitter can lower; a failure here is a
// regression in emission itself, so unwrap at the seam and keep the
// assertions about the generated handler rather than about the Result.
fn generate(
program: &ExecutionProgram,
host_import: &str,
validator_import: &str,
middleware_import: &str,
base_path: &str,
server_secrets: &[String],
) -> ServerJavaScriptOutput {
super::generate(
program,
host_import,
validator_import,
middleware_import,
base_path,
server_secrets,
)
.expect("every fixture body has a compiler-owned server lowering")
}
#[allow(clippy::too_many_arguments)]
fn generate_with_agent_surfaces(
program: &ExecutionProgram,
host_import: &str,
validator_import: &str,
middleware_import: &str,
startup_import: Option<&str>,
base_path: &str,
server_secrets: &[String],
agent_surfaces: AgentSurfaceOptions<'_>,
) -> ServerJavaScriptOutput {
super::generate_with_agent_surfaces(
program,
host_import,
validator_import,
middleware_import,
startup_import,
base_path,
server_secrets,
agent_surfaces,
)
.expect("every fixture body has a compiler-owned server lowering")
}
#[allow(clippy::too_many_arguments)]
fn generate_with_runtime_options(
program: &ExecutionProgram,
host_import: &str,
validator_import: &str,
middleware_import: &str,
startup_import: Option<&str>,
base_path: &str,
server_secrets: &[String],
agent_surfaces: AgentSurfaceOptions<'_>,
tracing_mode: ServerTracingMode,
runtime_options: ServerRuntimeOptions,
) -> ServerJavaScriptOutput {
super::generate_with_runtime_options(
program,
host_import,
validator_import,
middleware_import,
startup_import,
base_path,
server_secrets,
agent_surfaces,
tracing_mode,
runtime_options,
)
.expect("every fixture body has a compiler-owned server lowering")
}
// WO-45 phase 2: a `distinct` type is erased at every boundary, so the
// wire representation is the base value. The client and SSR emitters
// lower construction and `.base()` to the identity; the server emitter
// must produce the byte-identical lowering, or the same expression would
// mean one thing in a client action and another in a compiler-owned
// remote body. The sibling tests in codegen-js and codegen-ssr-js assert
// these same two strings.
#[test]
fn distinct_construct_and_unwrap_erase_to_the_same_plain_server_value() {
let literal = SemanticExpr {
kind: SemanticExprKind::String("u-1".into()),
ty: Type::String,
span: Span::new(0, 1),
};
let constructed = SemanticExpr {
kind: SemanticExprKind::FunctionCall {
function: SemanticId::distinct_construct("UserId"),
name: "UserId".into(),
arguments: vec![literal],
},
ty: Type::Named("UserId".into()),
span: Span::new(0, 1),
};
let unwrapped = SemanticExpr {
kind: SemanticExprKind::FunctionCall {
function: SemanticId::distinct_unwrap("UserId"),
name: "UserId.base".into(),
arguments: vec![constructed.clone()],
},
ty: Type::String,
span: Span::new(0, 1),
};
assert_eq!(
compiler_body_javascript(&constructed).expect("construction lowers"),
"\"u-1\""
);
assert_eq!(
compiler_body_javascript(&unwrapped).expect("unwrap lowers"),
"\"u-1\""
);
}
fn server_builtin(name: &str, arguments: Vec<SemanticExpr>, ty: Type) -> SemanticExpr {
SemanticExpr {
kind: SemanticExprKind::FunctionCall {
function: SemanticId::function(&format!("@builtin.{name}")),
name: name.into(),
arguments,
},
ty,
span: Span::new(0, 1),
}
}
fn endpoint_boundary(
name: &str,
method: EndpointMethod,
path: &str,
inputs: Vec<EndpointExecutionInput>,
result: &str,
) -> EndpointExecutionBoundary {
EndpointExecutionBoundary {
id: SemanticId::endpoint(name),
kind: EndpointKind::RequestResponse,
host_key: Some(SemanticId::endpoint(name)),
name: name.into(),
version: 1,
description: None,
method: Some(method),
path: Some(path.into()),
inputs,
result: ExecutionResult {
id: SemanticId::endpoint_result(name),
ty: result.into(),
type_id: None,
},
statements: vec![],
capabilities: vec![],
timeout_ms: 30_000,
limit: None,
cache: None,
idempotent: false,
middleware: vec![],
invalidates: vec![],
span: Span::new(0, 1),
}
}
fn endpoint_input(
endpoint: &str,
section: EndpointInputSection,
name: &str,
ty: &str,
) -> EndpointExecutionInput {
EndpointExecutionInput {
id: SemanticId::endpoint_field(endpoint, section, name),
section,
name: name.into(),
ty: ty.into(),
type_id: None,
file: None,
}
}
fn presence_program() -> ExecutionProgram {
ExecutionProgram {
presences: vec![PresenceExecutionContract {
id: SemanticId::presence("Cursor"),
component: SemanticId::component("Cursor"),
component_name: "Cursor".into(),
stream: SemanticId::presence_stream("Cursor"),
record_type: SemanticId::type_definition("Cursor", "CursorPresenceRecord"),
member_type: SemanticId::type_definition("Cursor", "CursorPresenceMember"),
snapshot_type: SemanticId::type_definition("Cursor", "CursorPresenceSnapshot"),
fields: vec![PresenceExecutionField {
id: SemanticId::presence_field("Cursor", "name"),
name: "name".into(),
ty: "String".into(),
type_id: None,
}],
capabilities: vec![],
route_scopes: vec![
ExecutionRouteScope {
route: SemanticId::route("/room"),
pattern: "/room".into(),
parameters: vec![],
middleware: vec![],
},
ExecutionRouteScope {
route: SemanticId::route("/other"),
pattern: "/other".into(),
parameters: vec![],
middleware: vec![],
},
],
ttl_ms: 5_000,
heartbeat_ms: 1_000,
}],
..ExecutionProgram::default()
}
}
#[test]
fn generated_presence_handler_is_valid_and_uses_the_shared_live_surface() {
let generated = generate_with_runtime_options(
&presence_program(),
"./host.mjs",
"./validators.mjs",
"./middleware.mjs",
None,
"/app",
&[],
AgentSurfaceOptions::default(),
ServerTracingMode::Requests,
ServerRuntimeOptions {
db_pool: 10,
pubsub: Some(PubSubRuntimeOptions {
driver: PubSubDriver::Memory,
coalescing_ms: 1,
}),
development_trace_capture: true,
application_namespace: Some("codegen_test".into()),
..ServerRuntimeOptions::default()
},
);
assert!(generated.handler.contains("/app/_noxid/live"));
assert!(generated.handler.contains("/app/_noxid/presence"));
assert!(
generated
.handler
.contains("__noxidPubSubEvent(\"presence\"")
);
assert!(generated.handler.contains("developmentCapture = true"));
let root = std::env::temp_dir().join(format!(
"noxid-presence-syntax-{}-{}",
std::process::id(),
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos()
));
std::fs::create_dir_all(&root).unwrap();
let handler = root.join("handler.mjs");
std::fs::write(&handler, generated.handler).unwrap();
let output = Command::new("node")
.args(["--check", handler.to_str().unwrap()])
.output()
.expect("Node.js is required for generated presence syntax tests");
let _ = std::fs::remove_dir_all(root);
assert!(
output.status.success(),
"{}",
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn emits_every_scalar_builtin_in_compiler_owned_remote_bodies() {
let string = || SemanticExpr {
kind: SemanticExprKind::Reference(SemanticId::action_parameter("C", "run", "name")),
ty: Type::String,
span: Span::new(0, 1),
};
let int = |value| SemanticExpr {
kind: SemanticExprKind::Int(value),
ty: Type::Int,
span: Span::new(0, 1),
};
let float = |value| SemanticExpr {
kind: SemanticExprKind::Float(value),
ty: Type::Float,
span: Span::new(0, 1),
};
let cases = [
(
server_builtin("len", vec![string()], Type::Int),
"args[\"name\"].length",
),
(
server_builtin(
"contains",
vec![
string(),
SemanticExpr {
kind: SemanticExprKind::String("a".into()),
ty: Type::String,
span: Span::new(0, 1),
},
],
Type::Boolean,
),
"args[\"name\"].includes(\"a\")",
),
(
server_builtin(
"startsWith",
vec![
string(),
SemanticExpr {
kind: SemanticExprKind::String("A".into()),
ty: Type::String,
span: Span::new(0, 1),
},
],
Type::Boolean,
),
"args[\"name\"].startsWith(\"A\")",
),
(
server_builtin("trim", vec![string()], Type::String),
"args[\"name\"].trim()",
),
(
server_builtin("lower", vec![string()], Type::String),
"args[\"name\"].toLowerCase()",
),
(
server_builtin("upper", vec![string()], Type::String),
"args[\"name\"].toUpperCase()",
),
(
server_builtin("min", vec![int(2), int(3)], Type::Int),
"Math.min(2, 3)",
),
(
server_builtin("max", vec![float(2.5), float(3.5)], Type::Float),
"Math.max(2.5, 3.5)",
),
(
server_builtin("abs", vec![int(-2)], Type::Int),
"Math.abs(-2)",
),
(
server_builtin("round", vec![float(2.5)], Type::Int),
"Math.round(2.5)",
),
(
server_builtin("floor", vec![float(2.5)], Type::Int),
"Math.floor(2.5)",
),
(
server_builtin("ceil", vec![float(2.5)], Type::Int),
"Math.ceil(2.5)",
),
(server_builtin("toFloat", vec![int(2)], Type::Float), "(2)"),
(
server_builtin("toInt", vec![float(2.5)], Type::Int),
"Math.trunc(2.5)",
),
(
server_builtin("toString", vec![int(2)], Type::String),
"String(2)",
),
];
for (expression, expected) in cases {
assert_eq!(
compiler_body_javascript(&expression).expect("builtin body emits"),
expected
);
}
let user_function = SemanticExpr {
kind: SemanticExprKind::FunctionCall {
function: SemanticId::function("len"),
name: "len".into(),
arguments: vec![string()],
},
ty: Type::Int,
span: Span::new(0, 1),
};
let error = compiler_body_javascript(&user_function)
.expect_err("a user function call has no compiler-owned server lowering");
assert!(
error.starts_with(
"error[REMOTE_ACTION_CALL_UNSUPPORTED]: the call `len(1 argument(s))`"
),
"{error}"
);
assert!(error.contains("host-implemented body"), "{error}");
}
/// An external JavaScript call reaching the server emitter used to become
/// the literal string `undefined /* rejected remote call */`, which is
/// valid JavaScript and therefore a silently wrong compile. It now fails
/// closed with the same code the semantic guard uses.
#[test]
fn an_external_call_fails_closed_instead_of_emitting_undefined() {
let call = SemanticExpr {
kind: SemanticExprKind::Call {
function: SemanticId::external_function("./format.js", "shout"),
name: "shout".into(),
arguments: vec![SemanticExpr {
kind: SemanticExprKind::Reference(SemanticId::action_parameter(
"C", "save", "note",
)),
ty: Type::String,
span: Span::new(0, 1),
}],
},
ty: Type::String,
span: Span::new(0, 1),
};
let error = compiler_body_javascript(&call)
.expect_err("an external JavaScript call has no compiler-owned server lowering");
assert!(
error.starts_with(
"error[REMOTE_ACTION_CALL_UNSUPPORTED]: the call `shout(1 argument(s))`"
),
"{error}"
);
assert!(error.contains("host-implemented body"), "{error}");
// The same rule holds one level up, through the statement emitter.
let error = compiler_statements_javascript(
&[noxid_ir::SemanticStatement::Return {
value: call,
span: Span::new(0, 1),
}],
2,
)
.expect_err("the statement emitter propagates the expression rejection");
assert!(
error.starts_with("error[REMOTE_ACTION_CALL_UNSUPPORTED]"),
"{error}"
);
}
/// Semantics refuses a mis-arity builtin with BUILTIN_OVERLOAD_MISMATCH
/// before emission, so this is a defensive backstop: if one ever reaches
/// the emitter, it must not become a bare `len(a, b)` call.
#[test]
fn a_builtin_with_no_lowering_fails_closed_in_the_server_emitter() {
let call = SemanticExpr {
kind: SemanticExprKind::FunctionCall {
function: SemanticId::function("@builtin.len"),
name: "len".into(),
arguments: vec![
SemanticExpr {
kind: SemanticExprKind::String("a".into()),
ty: Type::String,
span: Span::new(0, 1),
},
SemanticExpr {
kind: SemanticExprKind::String("b".into()),
ty: Type::String,
span: Span::new(0, 1),
},
],
},
ty: Type::Int,
span: Span::new(0, 1),
};
let error =
compiler_body_javascript(&call).expect_err("a two-argument `len` has no lowering");
assert!(
error.starts_with("error[BUILTIN_OVERLOAD_MISMATCH]: builtin `len`"),
"{error}"
);
}
#[test]
fn collection_queries_use_shared_emission_in_remote_bodies() {
let query = SemanticExpr {
kind: SemanticExprKind::CollectionQuery {
base: Box::new(SemanticExpr {
kind: SemanticExprKind::Reference(SemanticId::state("C", "items")),
ty: Type::Array(Box::new(Type::Int)),
span: Span::new(0, 1),
}),
kind: noxid_ir::CollectionQueryKind::Count,
field: None,
value: None,
},
ty: Type::Int,
span: Span::new(0, 1),
};
assert_eq!(
compiler_body_javascript(&query).expect("collection query emits"),
"(args[\"items\"]).length"
);
}
#[test]
fn map_queries_use_typed_sorted_shared_emission_in_remote_bodies() {
let query = SemanticExpr {
kind: SemanticExprKind::CollectionQuery {
base: Box::new(SemanticExpr {
kind: SemanticExprKind::Reference(SemanticId::action_parameter(
"C", "read", "counts",
)),
ty: Type::Map(Box::new(Type::Boolean), Box::new(Type::Int)),
span: Span::new(0, 1),
}),
kind: noxid_ir::CollectionQueryKind::MapEntries,
field: None,
value: None,
},
ty: Type::Array(Box::new(Type::MapEntry(
Box::new(Type::Boolean),
Box::new(Type::Int),
))),
span: Span::new(0, 1),
};
let javascript = compiler_body_javascript(&query).expect("map query emits");
let script = format!(
"const args = {{ counts: Object.freeze({{true: 2, false: 1}}) }}; const result = {javascript}; if (JSON.stringify(result) !== JSON.stringify([{{key:false,value:1}},{{key:true,value:2}}])) process.exit(1);"
);
let output = Command::new("node")
.args(["--input-type=module", "-e", &script])
.output()
.expect("node must execute server map query");
assert!(
output.status.success(),
"{}",
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn optional_coalescing_lowers_in_compiler_owned_remote_bodies() {
let expression = SemanticExpr {
kind: SemanticExprKind::Binary {
left: Box::new(SemanticExpr {
kind: SemanticExprKind::Reference(SemanticId::action_parameter(
"C", "read", "value",
)),
ty: Type::Optional(Box::new(Type::Int)),
span: Span::new(0, 1),
}),
op: SemanticBinaryOp::Coalesce,
right: Box::new(SemanticExpr {
kind: SemanticExprKind::Int(1),
ty: Type::Int,
span: Span::new(0, 1),
}),
},
ty: Type::Int,
span: Span::new(0, 1),
};
assert_eq!(
compiler_body_javascript(&expression).expect("coalescing body emits"),
"(args[\"value\"] ?? 1)"
);
}
#[test]
fn server_compound_equality_matches_recursive_language_values() {
let ready = |value| SemanticExpr {
kind: SemanticExprKind::Variant {
machine: SemanticId::machine("C", "Phase"),
variant: SemanticId::variant("C", "Phase", "Ready"),
payload: Some(Box::new(SemanticExpr {
kind: SemanticExprKind::Int(value),
ty: Type::Int,
span: Span::new(0, 1),
})),
},
ty: Type::Named("Phase".into()),
span: Span::new(0, 1),
};
let expression = SemanticExpr {
kind: SemanticExprKind::Binary {
left: Box::new(SemanticExpr {
kind: SemanticExprKind::Array(vec![ready(1), ready(2)]),
ty: Type::Array(Box::new(Type::Named("Phase".into()))),
span: Span::new(0, 1),
}),
op: SemanticBinaryOp::Equal,
right: Box::new(SemanticExpr {
kind: SemanticExprKind::Array(vec![ready(1), ready(2)]),
ty: Type::Array(Box::new(Type::Named("Phase".into()))),
span: Span::new(0, 1),
}),
},
ty: Type::Boolean,
span: Span::new(0, 1),
};
let script = format!(
"{}\nif (!({})) process.exit(1);",
LANGUAGE_VALUE_EQUALITY_FUNCTION,
compiler_body_javascript(&expression).expect("compound equality body emits")
);
let output = std::process::Command::new("node")
.args(["--input-type=module", "-e", &script])
.output()
.expect("node must execute server compound equality");
assert!(
output.status.success(),
"{}",
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn server_handler_uses_fetch_and_never_embeds_host_source() {
let program = ExecutionProgram {
live_resources: vec![],
presences: vec![],
boundaries: vec![ExecutionBoundary {
id: SemanticId::execution_boundary("Account", "save", ExecutionTarget::Server),
action: SemanticId::action("Account", "save"),
component: SemanticId::component("Account"),
component_name: "Account".into(),
action_name: "save".into(),
target: ExecutionTarget::Server,
parameters: vec![ExecutionParameter {
id: SemanticId::action_parameter("Account", "save", "id"),
name: "id".into(),
ty: "Int".into(),
type_id: None,
}],
result: ExecutionResult {
id: SemanticId::action_result("Account", "save"),
ty: "Boolean".into(),
type_id: None,
},
body: Some(SemanticExpr {
kind: SemanticExprKind::Binary {
left: Box::new(SemanticExpr {
kind: SemanticExprKind::Reference(SemanticId::action_parameter(
"Account", "save", "id",
)),
ty: Type::Int,
span: Span::new(0, 1),
}),
op: SemanticBinaryOp::Add,
right: Box::new(SemanticExpr {
kind: SemanticExprKind::Int(1),
ty: Type::Int,
span: Span::new(0, 1),
}),
},
ty: Type::Int,
span: Span::new(0, 1),
}),
capabilities: vec!["account.write".into()],
route_scopes: vec![ExecutionRouteScope {
route: SemanticId::route("/accounts"),
pattern: "/accounts".into(),
parameters: vec![],
middleware: vec![SemanticId::middleware("session")],
}],
invalidates: vec![],
span: Span::new(0, 1),
}],
endpoints: vec![],
tasks: vec![],
queues: vec![],
};
let output = generate(
&program,
"./host.js",
"./validators.js",
"./middleware.js",
"/console",
&[],
);
assert!(
output
.handler
.contains("export async function fetch(request")
);
assert!(output.handler.contains("/console/_noxid/actions/"));
assert!(output.handler.contains("BOUNDARY_ARGUMENT_TYPE"));
assert!(output.handler.contains("BOUNDARY_RESULT_TYPE"));
assert!(output.handler.contains("BOUNDARY_CAPABILITY_DENIED"));
assert!(output.handler.contains("BOUNDARY_MIDDLEWARE_DENIED"));
assert!(output.handler.contains("account.write"));
assert!(output.handler.contains("action:Account.save"));
assert!(output.handler.contains("compiledActions"));
assert!(output.handler.contains("args[\"id\"] + 1"));
assert!(
!output
.handler
.contains("import * as __noxidServerStorageRuntime")
);
assert_eq!(output.server_actions, 1);
assert_eq!(output.edge_actions, 0);
}
#[test]
fn queue_drain_is_adapter_activated_capability_guarded_and_budgeted() {
let queue_id = SemanticId::queue("Drain");
let live_id = SemanticId::resource("DrainStatus");
let program = ExecutionProgram {
live_resources: vec![LiveResourceExecutionContract {
id: live_id.clone(),
name: "DrainStatus".into(),
capabilities: vec![],
route_scopes: vec![],
}],
presences: vec![],
boundaries: vec![],
endpoints: vec![],
tasks: vec![],
queues: vec![QueueExecutionBoundary {
id: queue_id.clone(),
host_key: Some(queue_id),
name: "Drain".into(),
payload: vec![QueueExecutionField {
id: SemanticId::queue_payload("Drain", "fail"),
name: "fail".into(),
ty: "Boolean".into(),
type_id: None,
type_ids: vec![],
}],
retry: 1,
backoff_ms: 60_000,
statements: vec![],
invalidates: vec![live_id],
span: Span::new(0, 1),
}],
};
let generated = generate_with_runtime_options(
&program,
"./host.mjs",
"./validators.mjs",
"./middleware.mjs",
None,
"/console",
&[],
AgentSurfaceOptions::default(),
ServerTracingMode::Requests,
ServerRuntimeOptions {
db_pool: 10,
pubsub: Some(PubSubRuntimeOptions {
driver: PubSubDriver::Memory,
coalescing_ms: 1,
}),
development_trace_capture: false,
application_namespace: Some("codegen_test".into()),
..ServerRuntimeOptions::default()
},
);
let root = std::env::temp_dir().join(format!(
"noxid-queue-drain-handler-{}-{}",
std::process::id(),
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos()
));
std::fs::create_dir_all(root.join("node_modules/postgres")).unwrap();
std::fs::write(root.join("package.json"), "{\"type\":\"module\"}\n").unwrap();
std::fs::write(root.join("handler.mjs"), generated.handler).unwrap();
std::fs::write(
root.join("validators.mjs"),
"export const typeValidators = Object.freeze({});\n",
)
.unwrap();
std::fs::write(
root.join("middleware.mjs"),
"export const globalMiddleware = Object.freeze([]);\nexport const middleware = Object.freeze({});\n",
)
.unwrap();
std::fs::write(
root.join("host.mjs"),
r#"export const queues = Object.freeze({
"queue:Drain": async ({ fail }) => {
await new Promise((resolve) => setTimeout(resolve, 12));
if (fail) throw new Error("retry me");
return "done";
},
});
export async function authorize({ capability, environment }) {
environment.authorized = (environment.authorized ?? 0) + 1;
environment.capability = capability;
return environment.allow === true;
}
"#,
)
.unwrap();
std::fs::write(
root.join("node_modules/postgres/package.json"),
"{\"name\":\"postgres\",\"type\":\"module\",\"exports\":\"./index.js\"}\n",
)
.unwrap();
std::fs::write(
root.join("node_modules/postgres/index.js"),
r#"const jobs = [
{ id: "one", queue: "Drain", payload: { fail: false }, principal: "system", attempts: 0, run_at: new Date(0) },
{ id: "two", queue: "Drain", payload: { fail: true }, principal: "system", attempts: 0, run_at: new Date(0) },
];
let claims = 0;
const text = (strings) => strings.join("?").replace(/\s+/g, " ").trim();
export function observedClaims() { return claims; }
export default function postgres() {
const sql = async () => [];
sql.unsafe = async () => [];
sql.json = (value) => value;
sql.begin = async (operation) => operation(async (strings) => {
if (!text(strings).startsWith("SELECT ")) return [];
const job = jobs.shift();
if (job === undefined) return [];
claims += 1;
return [job];
});
return sql;
}
"#,
)
.unwrap();
let script = r#"import { fetch as handle, fetchEndpoint, __noxidLiveConnectionPrincipal, __noxidPubSubSubscribe } from "./handler.mjs";
import { observedClaims } from "postgres";
const url = "http://noxid.test/console/_noxid/queue/drain";
const principal = __noxidLiveConnectionPrincipal(Object.create(null), Object.create(null));
const events = [];
const stop = await __noxidPubSubSubscribe("invalidation", "resource:DrainStatus", principal, (event) => events.push(event.semanticId), { schedule: (run) => { queueMicrotask(run); return 1; }, cancel: () => {} });
let environment = { allow: true };
let response = await fetchEndpoint(new Request(url, { method: "POST" }), environment);
let body = await response.json();
if (response.status !== 404 || body.error?.code !== "QUEUE_DRAIN_DISABLED" || environment.authorized !== undefined || observedClaims() !== 0) throw new Error(`disabled door was exposed ${response.status} ${JSON.stringify(body)}`);
environment = { allow: true };
response = await handle(new Request(url), environment, { noxidQueueDrain: true });
body = await response.json();
if (response.status !== 405 || response.headers.get("allow") !== "POST" || environment.authorized !== undefined || observedClaims() !== 0) throw new Error(`method guard failed ${response.status} ${JSON.stringify(body)}`);
environment = { allow: true };
response = await fetchEndpoint(new Request(url, { method: "POST" }), environment, { noxidQueueDrain: true, queueDrainBudgetMs: 0 });
body = await response.json();
if (response.status !== 500 || body.error?.code !== "QUEUE_DRAIN_BUDGET_INVALID" || environment.authorized !== undefined || observedClaims() !== 0) throw new Error(`invalid provider budget did not fail closed ${response.status} ${JSON.stringify(body)}`);
environment = { allow: false };
response = await handle(new Request(url, { method: "POST" }), environment, { noxidQueueDrain: true, queueDrainBudgetMs: 50 });
body = await response.json();
if (response.status !== 403 || body.error?.code !== "QUEUE_DRAIN_CAPABILITY_DENIED" || environment.capability !== "queue.drain" || observedClaims() !== 0) throw new Error(`capability guard failed ${response.status} ${JSON.stringify(body)}`);
environment = { allow: true };
response = await handle(new Request(url, { method: "POST" }), environment, { noxidQueueDrain: true, queueDrainBudgetMs: 5 });
body = await response.json();
if (response.status !== 200 || body.budgetMs !== 5 || body.counts?.claimed !== 1 || body.counts?.completed !== 1 || body.counts?.retried !== 0 || observedClaims() !== 1) throw new Error(`time budget did not stop new claims ${response.status} ${JSON.stringify(body)}`);
await new Promise((resolve) => setTimeout(resolve, 5));
if (JSON.stringify(events) !== JSON.stringify(["resource:DrainStatus"])) throw new Error(`queue completion did not publish ${events}`);
environment = { allow: true };
response = await handle(new Request(url, { method: "POST" }), environment, { noxidQueueDrain: true });
body = await response.json();
if (response.status !== 200 || body.budgetMs !== 25000 || body.counts?.claimed !== 1 || body.counts?.completed !== 0 || body.counts?.retried !== 1 || body.counts?.deadLettered !== 0 || observedClaims() !== 2) throw new Error(`default budget or retry counts failed ${response.status} ${JSON.stringify(body)}`);
await new Promise((resolve) => setTimeout(resolve, 5));
if (events.length !== 1) throw new Error(`failed queue delivery published ${events}`);
await stop();
"#;
let output = Command::new("node")
.args(["--input-type=module", "-e", script])
.current_dir(&root)
.env("DATABASE_URL", "postgres://noxid.test/fake")
.output()
.expect("Node.js is required for generated queue-drain tests");
let _ = std::fs::remove_dir_all(&root);
assert!(
output.status.success(),
"{}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn generated_handler_enforces_capabilities_and_result_types() {
let program = ExecutionProgram {
live_resources: vec![],
presences: vec![],
boundaries: vec![ExecutionBoundary {
id: SemanticId::execution_boundary("Account", "save", ExecutionTarget::Server),
action: SemanticId::action("Account", "save"),
component: SemanticId::component("Account"),
component_name: "Account".into(),
action_name: "save".into(),
target: ExecutionTarget::Server,
parameters: vec![ExecutionParameter {
id: SemanticId::action_parameter("Account", "save", "id"),
name: "id".into(),
ty: "Int".into(),
type_id: None,
}],
result: ExecutionResult {
id: SemanticId::action_result("Account", "save"),
ty: "Boolean".into(),
type_id: None,
},
body: None,
capabilities: vec!["account.write".into()],
route_scopes: vec![ExecutionRouteScope {
route: SemanticId::route("/accounts"),
pattern: "/accounts".into(),
parameters: vec![],
middleware: vec![SemanticId::middleware("session")],
}],
invalidates: vec![],
span: Span::new(0, 1),
}],
endpoints: vec![],
tasks: vec![],
queues: vec![],
};
let output = generate(
&program,
"./host.mjs",
"./validators.mjs",
"./middleware.mjs",
"/console",
&[],
);
let no_authorizer = generate(
&program,
"./host-no-authorizer.mjs",
"./validators.mjs",
"./middleware.mjs",
"/console",
&[],
);
let unique = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos();
let root = std::env::temp_dir().join(format!(
"noxid-server-handler-{}-{unique}",
std::process::id()
));
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("handler.mjs"), output.handler).unwrap();
std::fs::write(
root.join("validators.mjs"),
"export const typeValidators = Object.freeze({});\n",
)
.unwrap();
std::fs::write(
root.join("middleware.mjs"),
r#"export const middleware = Object.freeze({
session: async ({ request, environment, host }) => {
environment.trace.push("middleware:session");
if (typeof host?.sessionUser !== "function") throw new Error("action middleware lost the generated host registry");
const userId = host.sessionUser(request);
return userId === null ? { allow: false } : { allow: true, context: { userId } };
},
});"#,
)
.unwrap();
std::fs::write(
root.join("handler-no-authorizer.mjs"),
no_authorizer.handler,
)
.unwrap();
std::fs::write(
root.join("host.mjs"),
r#"export const actions = Object.freeze({
"action:Account.save": async ({ id }, context) => {
if (!Object.isFrozen(context.capabilities)) throw new Error("capabilities were mutable");
if (!Object.isFrozen(context) || context.principal?.kind !== "user" || context.principal?.scope !== "user-a") throw new Error("action context lost the sealed middleware principal");
context.environment.trace.push("action");
return id === 1 ? true : "invalid";
},
});
export function sessionUser(request) { return request.headers.get("x-session") === "active" ? "user-a" : null; }
export async function authorize({ capability, request, environment }) {
environment.trace.push(`capability:${capability}`);
return request.headers.get("x-capability") === capability;
}
export async function invalidateCache(tags, context) {
context.environment.trace.push(`invalidate:${tags.join(",")}`);
return { invalidated: tags.length };
}
"#,
)
.unwrap();
std::fs::write(
root.join("host-no-authorizer.mjs"),
r#"export const actions = Object.freeze({ "action:Account.save": async () => true });
export function sessionUser(request) { return request.headers.get("x-session") === "active" ? "user-a" : null; }"#,
)
.unwrap();
let script = r#"import { fetch as handle } from "./handler.mjs";
import { fetch as handleWithoutAuthorizer } from "./handler-no-authorizer.mjs";
const endpoint = "http://noxid.test/console/_noxid/actions/action%3AAccount.save";
function request(id, allowed = false, session = true, route = "route:/accounts") {
const headers = { "content-type": "application/json" };
if (route !== null) headers["x-noxid-route-id"] = route;
if (session) headers["x-session"] = "active";
if (allowed) headers["x-capability"] = "account.write";
return new Request(endpoint, { method: "POST", headers, body: JSON.stringify({ arguments: { id } }) });
}
let environment = { trace: [] };
let response = await handle(request(1, false, true, null), environment);
let body = await response.json();
if (response.status !== 400 || body.error.code !== "BOUNDARY_ROUTE_REQUIRED") throw new Error("missing route did not fail closed");
environment = { trace: [] };
response = await handle(request(1, false, true, "route:/other"), environment);
body = await response.json();
if (response.status !== 403 || body.error.code !== "BOUNDARY_ROUTE_DENIED" || environment.trace.length !== 0) throw new Error("forged route did not fail closed");
environment = { trace: [] };
response = await handle(request(1, false, false), environment);
body = await response.json();
if (response.status !== 403 || body.error.code !== "BOUNDARY_MIDDLEWARE_DENIED") throw new Error("middleware denial failed");
environment = { trace: [] };
response = await handle(request(1), environment);
body = await response.json();
if (response.status !== 403 || body.error.code !== "BOUNDARY_CAPABILITY_DENIED") throw new Error("denial failed");
environment = { trace: [] };
response = await handle(request(1, true), environment);
body = await response.json();
if (response.status !== 200 || body.value !== true) throw new Error("valid result failed");
if (JSON.stringify(environment.trace) !== JSON.stringify(["middleware:session", "capability:account.write", "action"])) throw new Error(`wrong execution order: ${JSON.stringify(environment.trace)}`);
response = await handle(request(2, true), { trace: [] });
body = await response.json();
if (response.status !== 500 || body.error.code !== "BOUNDARY_RESULT_TYPE" || body.error.semanticId !== "result:Account.save") throw new Error("result validation failed");
response = await handleWithoutAuthorizer(request(1, true), { trace: [] });
body = await response.json();
if (response.status !== 500 || body.error.code !== "BOUNDARY_AUTHORIZER_MISSING") throw new Error("missing authorizer did not fail closed");
const invalidationUrl = "http://noxid.test/console/_noxid/revalidate";
response = await handle(new Request(invalidationUrl, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ tags: ["account"] }) }), { trace: [] });
body = await response.json();
if (response.status !== 403 || body.error.code !== "CACHE_INVALIDATION_DENIED") throw new Error("cache invalidation did not require authority");
environment = { trace: [] };
response = await handle(new Request(invalidationUrl, { method: "POST", headers: { "content-type": "application/json", "x-capability": "cache.invalidate" }, body: JSON.stringify({ tags: ["account", "account"] }) }), environment);
body = await response.json();
if (response.status !== 200 || body.tags.length !== 1 || body.result.invalidated !== 1) throw new Error("cache invalidation failed");
if (JSON.stringify(environment.trace) !== JSON.stringify(["capability:cache.invalidate", "invalidate:account"])) throw new Error("cache invalidation order failed");
for (const invalidBody of [
"null",
"[]",
JSON.stringify({ tags: ["account"], capability: "admin" }),
'{"tags":["account"],"__proto__":{"tags":["forged"]}}',
]) {
environment = { trace: [] };
response = await handle(new Request(invalidationUrl, { method: "POST", headers: { "content-type": "application/json", "x-capability": "cache.invalidate" }, body: invalidBody }), environment);
body = await response.json();
if (response.status !== 400 || body.error.code !== "CACHE_INVALIDATION_BODY_INVALID" || environment.trace.length !== 0) throw new Error(`non-exact cache invalidation body crossed the boundary: ${invalidBody} ${response.status} ${JSON.stringify(body)} ${JSON.stringify(environment.trace)}`);
}
const nativeJsonParse = JSON.parse;
for (const hostileBody of [
() => Object.create({ tags: ["forged"] }),
() => Object.defineProperty({}, "tags", { enumerable: true, configurable: true, get() { throw new Error("CACHE_INVALIDATION_ACCESSOR_RAN"); } }),
() => new Proxy({}, { getPrototypeOf() { throw new Error("CACHE_INVALIDATION_PROXY_TRAP"); } }),
]) {
environment = { trace: [] };
JSON.parse = hostileBody;
try {
response = await handle(new Request(invalidationUrl, { method: "POST", headers: { "content-type": "application/json", "x-capability": "cache.invalidate" }, body: "{}" }), environment);
} finally {
JSON.parse = nativeJsonParse;
}
body = await response.json();
if (response.status !== 400 || body.error.code !== "CACHE_INVALIDATION_BODY_INVALID" || environment.trace.length !== 0) throw new Error(`hostile cache invalidation shape crossed the boundary: ${response.status} ${JSON.stringify(body)} ${JSON.stringify(environment.trace)}`);
}
environment = { trace: [] };
const failedInvalidationStream = new ReadableStream({
start(controller) { controller.error(new Error("transport failed")); },
});
response = await handle(new Request(invalidationUrl, { method: "POST", headers: { "content-type": "application/json", "x-capability": "cache.invalidate" }, body: failedInvalidationStream, duplex: "half" }), environment);
body = await response.json();
if (response.status !== 400 || body.error.code !== "CACHE_INVALIDATION_BODY_INVALID" || environment.trace.length !== 0) throw new Error(`failed cache invalidation stream escaped the structured boundary: ${response.status} ${JSON.stringify(body)} ${JSON.stringify(environment.trace)}`);
environment = { trace: [] };
response = await handle(new Request(invalidationUrl, { method: "POST", headers: { "content-type": "application/json", "x-capability": "cache.invalidate" }, body: JSON.stringify({ tags: ["../../unsafe"] }) }), environment);
body = await response.json();
if (response.status !== 400 || body.error.code !== "CACHE_INVALIDATION_TAGS_INVALID" || environment.trace.length !== 0) throw new Error("unsafe cache tag crossed authorization");
"#;
let status = std::process::Command::new("node")
.args(["--input-type=module", "-e", script])
.current_dir(&root)
.status()
.expect("Node.js is required for generated server handler tests");
let _ = std::fs::remove_dir_all(&root);
assert!(status.success());
}
#[test]
fn generated_endpoint_handler_enforces_typed_routing_limits_timeout_and_replay() {
let mut read = endpoint_boundary(
"ReadItem",
EndpointMethod::Get,
"/api/items/[id]",
vec![
endpoint_input("ReadItem", EndpointInputSection::Params, "id", "Int"),
endpoint_input(
"ReadItem",
EndpointInputSection::Query,
"tags",
"Optional<Array<Int>>",
),
endpoint_input(
"ReadItem",
EndpointInputSection::Query,
"required",
"Array<String>",
),
],
"String",
);
read.capabilities = vec!["items.read".into()];
read.middleware = vec!["audit".into()];
read.limit = Some(EndpointLimitPolicy {
requests: 3,
window: EndpointLimitWindow::Minute,
scope: EndpointLimitScope::Session,
});
read.cache = Some(EndpointCachePolicy {
id: SemanticId::endpoint_cache("ReadItem"),
mode: EndpointCacheMode::Swr,
seconds: 60,
tags: vec!["endpoint:ReadItem@1".into()],
span: Span::new(0, 1),
});
let mut save = endpoint_boundary(
"SaveItem",
EndpointMethod::Post,
"/api/items",
vec![endpoint_input(
"SaveItem",
EndpointInputSection::Body,
"value",
"Int",
)],
"Result<String, String>",
);
save.idempotent = true;
save.middleware = vec!["audit".into()];
let mut slow = endpoint_boundary(
"SlowItem",
EndpointMethod::Delete,
"/api/items/[id]",
vec![endpoint_input(
"SlowItem",
EndpointInputSection::Params,
"id",
"String",
)],
"Boolean",
);
slow.timeout_ms = 10;
let mut middleware_timeout = endpoint_boundary(
"MiddlewareTimeout",
EndpointMethod::Get,
"/api/middleware-timeout",
vec![],
"Boolean",
);
middleware_timeout.timeout_ms = 10;
middleware_timeout.middleware = vec!["slow".into()];
let upload = endpoint_boundary(
"Upload",
EndpointMethod::Post,
"/api/upload",
vec![endpoint_input(
"Upload",
EndpointInputSection::Body,
"text",
"String",
)],
"Int",
);
let bodyless_mutation = endpoint_boundary(
"BodylessMutation",
EndpointMethod::Post,
"/api/bodyless",
vec![],
"Boolean",
);
let measure = endpoint_boundary(
"Measure",
EndpointMethod::Get,
"/api/measure",
vec![endpoint_input(
"Measure",
EndpointInputSection::Query,
"value",
"Float",
)],
"Float",
);
let count = endpoint_boundary(
"Count",
EndpointMethod::Get,
"/api/count",
vec![endpoint_input(
"Count",
EndpointInputSection::Query,
"value",
"Int",
)],
"Int",
);
let mut fast_replay = endpoint_boundary(
"FastReplay",
EndpointMethod::Post,
"/api/fast-replay",
vec![],
"Int",
);
fast_replay.idempotent = true;
let events = endpoint_boundary(
"Events",
EndpointMethod::Get,
"/api/events",
vec![endpoint_input(
"Events",
EndpointInputSection::Query,
"since",
"Date",
)],
"Date",
);
let optional_echo = endpoint_boundary(
"OptionalEcho",
EndpointMethod::Post,
"/api/optional",
vec![endpoint_input(
"OptionalEcho",
EndpointInputSection::Body,
"value",
"Optional<String>",
)],
"OptionalReply",
);
let mut rate_save = endpoint_boundary(
"RateSave",
EndpointMethod::Post,
"/api/rate-save",
vec![endpoint_input(
"RateSave",
EndpointInputSection::Body,
"value",
"Int",
)],
"Int",
);
rate_save.limit = Some(EndpointLimitPolicy {
requests: 1,
window: EndpointLimitWindow::Minute,
scope: EndpointLimitScope::Ip,
});
let put = endpoint_boundary(
"PutItem",
EndpointMethod::Put,
"/api/put",
vec![],
"Boolean",
);
let patch = endpoint_boundary(
"PatchItem",
EndpointMethod::Patch,
"/api/patch",
vec![],
"Boolean",
);
let mut direct = endpoint_boundary(
"DirectResponse",
EndpointMethod::Get,
"/health",
vec![],
"String",
);
direct.middleware = vec!["direct".into()];
let mut redirect = endpoint_boundary(
"RedirectResponse",
EndpointMethod::Get,
"/login",
vec![],
"String",
);
redirect.middleware = vec!["redirect".into()];
let mut denied = endpoint_boundary(
"DeniedWrite",
EndpointMethod::Post,
"/private/[id]",
vec![
endpoint_input("DeniedWrite", EndpointInputSection::Params, "id", "Int"),
endpoint_input("DeniedWrite", EndpointInputSection::Query, "page", "Int"),
endpoint_input("DeniedWrite", EndpointInputSection::Body, "value", "Int"),
],
"Int",
);
denied.middleware = vec!["deny".into()];
let program = ExecutionProgram {
live_resources: vec![],
presences: vec![],
boundaries: vec![],
endpoints: vec![
read,
save,
slow,
middleware_timeout,
upload,
bodyless_mutation,
measure,
count,
fast_replay,
events,
optional_echo,
rate_save,
put,
patch,
direct,
redirect,
denied,
],
tasks: vec![],
queues: vec![],
};
let generated = generate(
&program,
"./host.mjs",
"./validators.mjs",
"./middleware.mjs",
"/console",
&[],
);
for method in ["GET", "POST", "PUT", "PATCH", "DELETE"] {
assert!(generated.handler.contains(&format!("method: \"{method}\"")));
}
assert!(
generated
.handler
.contains("import * as __noxidServerStorageRuntime")
);
assert!(
generated
.handler
.contains("const __noxidStorage = __noxidServerStorageRuntime.storage")
);
let root = std::env::temp_dir().join(format!(
"noxid-endpoint-handler-{}-{}",
std::process::id(),
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos()
));
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("package.json"), "{\"type\":\"module\"}\n").unwrap();
std::fs::write(root.join("handler.mjs"), generated.handler).unwrap();
std::fs::write(
root.join("noxid-server.js"),
r#"const namespaces = new Map();
export function storage(namespace) {
if (!namespaces.has(namespace)) namespaces.set(namespace, new Map());
const records = namespaces.get(namespace);
const read = (key) => {
const record = records.get(key);
if (!record) return null;
if (record.expiresAt !== null && record.expiresAt <= Date.now()) { records.delete(key); return null; }
return structuredClone(record.value);
};
return Object.freeze({
async get(key) { return read(key); },
async set(key, value, options) { records.set(key, { value: structuredClone(value), expiresAt: options?.ttl === undefined ? null : Date.now() + options.ttl * 1000 }); },
async delete(key) { return records.delete(key); },
async list(prefix = "") { for (const key of records.keys()) read(key); return Object.freeze([...records.keys()].filter((key) => key.startsWith(prefix)).sort()); },
});
}
"#,
)
.unwrap();
std::fs::write(
root.join("validators.mjs"),
r#"function record(fields) { return (value) => {
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("record");
const trusted = Object.create(null);
for (const [name, validate] of Object.entries(fields)) trusted[name] = validate(value[name]);
return Object.freeze(trusted);
}; }
const int = (value) => { if (!Number.isSafeInteger(value)) throw new Error("int"); return value; };
const float = (value) => { if (typeof value !== "number" || !Number.isFinite(value)) throw new Error("float"); return value; };
const string = (value) => { if (typeof value !== "string") throw new Error("string"); return value; };
const boolean = (value) => { if (typeof value !== "boolean") throw new Error("boolean"); return value; };
const optional = (validate) => (value) => value == null ? null : validate(value);
const array = (validate) => (value) => {
if (!Array.isArray(value)) throw new Error("array");
const trusted = [];
for (let index = 0; index < value.length; index += 1) trusted.push(validate(value[index]));
return Object.freeze(trusted);
};
const map = (validate) => (value) => {
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("map");
const trusted = Object.create(null);
for (const key of Object.keys(value)) trusted[key] = validate(value[key]);
return Object.freeze(trusted);
};
const date = (value) => { if (typeof value !== "string") throw new Error("date"); return value; };
export const typeValidators = Object.freeze({
"validator:endpoint.ReadItem.params": record({ id: int }),
"validator:endpoint.ReadItem.query": record({ tags: (value) => { if (value !== null && (!Array.isArray(value) || value.some((item) => !Number.isSafeInteger(item)))) throw new Error("tags"); return value === null ? null : Object.freeze([...value]); }, required: (value) => { if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) throw new Error("required"); return Object.freeze([...value]); } }),
"validator:endpoint.ReadItem.result": string,
"validator:endpoint.SaveItem.body": record({ value: int }),
"validator:endpoint.SaveItem.result": string,
"validator:endpoint.SaveItem.error": string,
"validator:endpoint.SlowItem.params": record({ id: string }),
"validator:endpoint.SlowItem.result": boolean,
"validator:endpoint.MiddlewareTimeout.result": boolean,
"validator:endpoint.Upload.body": record({ text: string }),
"validator:endpoint.Upload.result": int,
"validator:endpoint.BodylessMutation.result": boolean,
"validator:endpoint.Measure.query": record({ value: float }),
"validator:endpoint.Measure.result": float,
"validator:endpoint.Count.query": record({ value: int }),
"validator:endpoint.Count.result": int,
"validator:endpoint.FastReplay.result": int,
"validator:endpoint.Events.query": record({ since: date }),
"validator:endpoint.Events.result": date,
"validator:endpoint.OptionalEcho.body": record({ value: optional(string) }),
"validator:endpoint.OptionalEcho.result": record({ value: optional(string), nested: record({ missing: optional(string) }), values: array(optional(string)), labels: map(optional(string)) }),
"validator:endpoint.RateSave.body": record({ value: int }),
"validator:endpoint.RateSave.result": int,
"validator:endpoint.PutItem.result": boolean,
"validator:endpoint.PatchItem.result": boolean,
"validator:endpoint.DirectResponse.result": string,
"validator:endpoint.RedirectResponse.result": string,
"validator:endpoint.DeniedWrite.body": record({ value: int }),
"validator:endpoint.DeniedWrite.params": record({ id: int }),
"validator:endpoint.DeniedWrite.query": record({ page: int }),
"validator:endpoint.DeniedWrite.result": int,
});
"#,
)
.unwrap();
std::fs::write(
root.join("middleware.mjs"),
r#"export const globalMiddleware = Object.freeze(["global"]);
export const globalMiddlewareHandlers = Object.freeze({ global: async ({ environment }) => { environment.trace.push("global"); return { allow: true, headers: { "x-global": "yes", "set-cookie": ["a=1; Path=/; HttpOnly", "b=2; Path=/; HttpOnly"] }, context: { sessionId: "ctx-session" } }; } });
export const middleware = Object.freeze({
audit: async ({ environment }) => { environment.trace.push("audit"); return { allow: true, headers: { "x-audit": "yes" } }; },
slow: async ({ environment }) => { environment.trace.push("slow:start"); await new Promise((resolve) => setTimeout(resolve, 60)); environment.trace.push("slow:end"); return { allow: true }; },
direct: async ({ environment, host }) => { environment.trace.push("direct"); return { respond: { status: 202, contentType: "text/plain", body: await host.endpointHealth() }, headers: { "x-direct": "yes" } }; },
redirect: async ({ environment, host }) => { environment.trace.push("redirect"); return { redirect: await host.afterLoginPath(), headers: { "x-redirect": "yes" } }; },
deny: async ({ environment, params, query }) => { if (params.id !== "not-int" || query.unknown !== "yes") throw new Error("raw candidates missing"); environment.trace.push("deny"); return { allow: false, headers: { "x-deny": "yes" } }; },
});
"#,
)
.unwrap();
std::fs::write(
root.join("host.mjs"),
r#"let saves = 0;
let fastReplays = 0;
export const endpoints = Object.freeze({
"endpoint:ReadItem@1": async ({ id, tags, required }, { environment, signal }) => { if (!(signal instanceof AbortSignal)) throw new Error("signal"); environment.trace.push("read"); return `${id}:${JSON.stringify(tags)}:${JSON.stringify(required)}`; },
"endpoint:SaveItem@1": async ({ value }, { environment }) => { saves += 1; environment.trace.push(`save:${saves}`); await new Promise((resolve) => setTimeout(resolve, 20)); return { tag: value < 0 ? "Err" : "Ok", value: value === 999 ? 999 : value < 0 ? "negative" : `saved:${value}:${saves}` }; },
"endpoint:SlowItem@1": async (_args, { signal, environment }) => new Promise(() => { signal.addEventListener("abort", () => { environment.aborted = signal.aborted; }, { once: true }); }),
"endpoint:MiddlewareTimeout@1": async (_args, { environment }) => { environment.trace.push("middleware-timeout-host"); return true; },
"endpoint:Upload@1": async ({ text }, { environment }) => { environment.uploads = (environment.uploads ?? 0) + 1; return text.length; },
"endpoint:BodylessMutation@1": async (_args, { environment }) => { environment.bodylessCalls = (environment.bodylessCalls ?? 0) + 1; return true; },
"endpoint:Measure@1": async ({ value }, { environment }) => { environment.numericCalls = (environment.numericCalls ?? 0) + 1; return value; },
"endpoint:Count@1": async ({ value }, { environment }) => { environment.numericCalls = (environment.numericCalls ?? 0) + 1; return value; },
"endpoint:FastReplay@1": async () => { fastReplays += 1; return fastReplays; },
"endpoint:Events@1": async ({ since }, { environment }) => { environment.dateCalls = (environment.dateCalls ?? 0) + 1; return since; },
"endpoint:OptionalEcho@1": async ({ value }, { environment }) => { environment.optionalObserved = value; return { value, nested: { missing: undefined }, values: new Array(1), labels: { missing: undefined } }; },
"endpoint:RateSave@1": async ({ value }, { environment }) => { environment.rateCalls = (environment.rateCalls ?? 0) + 1; return value; },
"endpoint:PutItem@1": async () => true,
"endpoint:PatchItem@1": async () => true,
"endpoint:DeniedWrite@1": async () => { throw new Error("DENIED_HOST_MUST_NOT_RUN"); },
});
export async function authorize({ capability, environment }) { environment.trace.push(`cap:${capability}`); return environment.deny !== true; }
export async function endpointHealth() { return "ready-from-host"; }
export async function afterLoginPath() { return "/dashboard"; }
export async function invalidateCache(tags, { environment }) { environment.invalidated = [...tags]; return { invalidated: tags.length }; }
export function fastReplayCalls() { return fastReplays; }
"#,
)
.unwrap();
let script = r#"import { fetch as handle } from "./handler.mjs";
import { fastReplayCalls } from "./host.mjs";
import { storage as testStorage } from "./noxid-server.js";
const base = "http://noxid.test/console";
let env = { trace: [] };
for (const path of ["/console/api//items/7", "/console/api/items//7", "//console/api/items/7", "/console/api/items/7/", "/console/api/items/7///", "/console/health/"]) {
env = { trace: [] };
const unmatched = await handle(new Request(`http://noxid.test${path}`), env);
const unmatchedBody = await unmatched.json();
if (unmatched.status !== 404 || unmatchedBody.error?.code !== "BOUNDARY_NOT_FOUND" || env.trace.length !== 0) throw new Error(`empty path segment aliased an endpoint ${path}: ${unmatched.status} ${JSON.stringify(unmatchedBody)} ${JSON.stringify(env.trace)}`);
}
env = { trace: [] };
let response = await handle(new Request(`${base}/private/not-int?unknown=yes`, { method: "POST", body: "not-json" }), env);
let body = await response.json();
if (response.status !== 403 || body.error.code !== "ENDPOINT_MIDDLEWARE_DENIED" || response.headers.get("x-deny") !== "yes") throw new Error(`middleware denial lost to body decoding ${response.status} ${JSON.stringify(body)}`);
if (JSON.stringify(env.trace) !== JSON.stringify(["global", "deny"])) throw new Error(`deny-before-body order failed ${JSON.stringify(env.trace)}`);
env = { trace: [] };
response = await handle(new Request(`${base}/private/not-int?unknown=yes&bad=%FF`, { method: "POST", body: "not-json" }), env);
body = await response.json();
if (response.status !== 403 || body.error.code !== "ENDPOINT_MIDDLEWARE_DENIED" || JSON.stringify(env.trace) !== JSON.stringify(["global", "deny"])) throw new Error(`middleware denial lost to malformed query ${response.status} ${JSON.stringify(body)} ${JSON.stringify(env.trace)}`);
env = { trace: [] };
response = await handle(new Request(`${base}/api/items/7`, { headers: { "x-noxid-session-id": "one" } }), env);
body = await response.json();
if (response.status !== 200 || body.value !== "7:null:[]") throw new Error(`optional/empty arrays failed ${response.status} ${JSON.stringify(body)}`);
if (response.headers.get("x-global") !== "yes" || response.headers.get("x-audit") !== "yes") throw new Error("middleware headers missing");
if (response.headers.get("x-noxid-cache-mode") !== "swr" || response.headers.get("x-noxid-cache-revalidate") !== "60" || response.headers.get("x-noxid-cache-stale") !== "60" || response.headers.get("x-noxid-cache-tags") !== "endpoint:ReadItem@1" || !response.headers.get("cache-control")?.includes("stale-while-revalidate=60")) throw new Error("endpoint cache headers missing");
if (JSON.stringify(env.trace) !== JSON.stringify(["global", "audit", "cap:items.read", "read"])) throw new Error(`order ${JSON.stringify(env.trace)}`);
env = { trace: [] };
response = await handle(new Request(`${base}/_noxid/revalidate`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ tags: ["endpoint:ReadItem@1"] }) }), env);
body = await response.json();
if (response.status !== 200 || body.result?.invalidated !== 1 || JSON.stringify(env.invalidated) !== JSON.stringify(["endpoint:ReadItem@1"])) throw new Error(`endpoint tag revalidation failed ${response.status} ${JSON.stringify(body)}`);
response = await handle(new Request(`${base}/_noxid/revalidate`, { method: "POST", headers: { "content-type": "text/plain" }, body: JSON.stringify({ tags: ["endpoint:ReadItem@1"] }) }), env);
body = await response.json();
if (response.status !== 415 || body.error?.code !== "CACHE_INVALIDATION_CONTENT_TYPE") throw new Error(`invalidation media type boundary failed ${response.status} ${JSON.stringify(body)}`);
response = await handle(new Request(`${base}/_noxid/revalidate`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ tags: ["endpoint:ReadItem@1"], padding: "x".repeat(1_048_576) }) }), env);
body = await response.json();
if (response.status !== 413 || body.error?.code !== "CACHE_INVALIDATION_BODY_TOO_LARGE") throw new Error(`invalidation byte boundary failed ${response.status} ${JSON.stringify(body)}`);
env = { trace: [] };
response = await handle(new Request(`${base}/api/items/8?tags=%5B%5D&required=%5B%5D`, { headers: { "x-noxid-session-id": "one" } }), env);
body = await response.json();
if (response.status !== 200 || body.value !== "8:[]:[]") throw new Error("optional Some(empty array) collapsed into None");
response = await handle(new Request(`${base}/api/items/9?tags=%5B1%2C2%5D&required=%5B%22%22%5D`, { headers: { "x-noxid-session-id": "one" } }), env);
body = await response.json();
if (response.status !== 200 || body.value !== "9:[1,2]:[\"\"]") throw new Error("JSON array query decoding failed");
for (const query of ["required=%FF", "%FF=value"]) {
env = { trace: [] };
response = await handle(new Request(`${base}/api/items/12?${query}`), env);
body = await response.json();
if (response.status !== 400 || body.error.code !== "ENDPOINT_QUERY_ENCODING_INVALID" || JSON.stringify(env.trace) !== JSON.stringify(["global", "audit", "cap:items.read"])) throw new Error(`malformed query crossed endpoint boundary ${query} ${response.status} ${JSON.stringify(body)} ${JSON.stringify(env.trace)}`);
}
response = await handle(new Request(`${base}/api/items/11`, { headers: { "x-noxid-session-id": "denied" } }), { trace: [], deny: true });
if (response.status !== 403) throw new Error("capability denial failed");
response = await handle(new Request(`${base}/api/items/10`, { headers: { "x-noxid-session-id": "one" } }), { trace: [] });
if (response.status !== 429 || response.headers.get("retry-after") === null) throw new Error("rate limit failed");
response = await handle(new Request(`${base}/api/items/7`, { method: "POST" }), { trace: [] });
if (response.status !== 405 || response.headers.get("allow") !== "DELETE, GET") throw new Error(`method routing failed ${response.status} ${response.headers.get("allow")}`);
const saveRequest = () => new Request(`${base}/api/items`, { method: "POST", headers: { "content-type": "application/json", "idempotency-key": "same" }, body: JSON.stringify({ value: 4 }) });
env = { trace: [] };
response = await handle(new Request(`${base}/api/items`, { method: "POST", body: JSON.stringify({ value: 4 }) }), env);
if (response.status !== 415) throw new Error("content type refusal failed");
if (JSON.stringify(env.trace) !== JSON.stringify(["global", "audit"])) throw new Error(`allowed middleware did not precede body validation ${JSON.stringify(env.trace)}`);
response = await handle(new Request(`${base}/api/items`, { method: "POST", headers: { "content-type": "application/json", "content-length": "1048577", "idempotency-key": "large" }, body: "{}" }), { trace: [] });
if (response.status !== 413) throw new Error("body size refusal failed");
response = await handle(new Request(`${base}/api/items`, { method: "POST", headers: { "content-type": "application/json", "idempotency-key": "typed" }, body: JSON.stringify({ value: "wrong" }) }), { trace: [] });
if (response.status !== 422) throw new Error("body type refusal failed");
response = await handle(new Request(`${base}/api/items`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ value: 4 }) }), { trace: [] });
if (response.status !== 400) throw new Error("idempotency key refusal failed");
env = { trace: [] };
const [first, second] = await Promise.all([handle(saveRequest(), env), handle(saveRequest(), env)]);
const [firstText, secondText] = await Promise.all([first.text(), second.text()]);
if (first.status !== 200 || second.status !== 200 || firstText !== secondText) throw new Error("concurrent replay body/status failed");
if (JSON.parse(firstText).value !== "saved:4:1") throw new Error(`body refusals invoked host before allowed request ${firstText}`);
if ([...first.headers].toString() !== [...second.headers].toString() || first.headers.get("x-global") !== "yes" || first.headers.get("x-audit") !== "yes") throw new Error("full replay headers failed");
if (typeof first.headers.getSetCookie === "function" && (first.headers.getSetCookie().length !== 2 || second.headers.getSetCookie().length !== 2)) throw new Error("full replay set-cookie headers failed");
if (env.trace.filter((entry) => entry.startsWith("save:")).length !== 1) throw new Error(`duplicate implementation ran ${JSON.stringify(env.trace)}`);
response = await handle(saveRequest(), { trace: [] });
if (await response.text() !== firstText) throw new Error("sequential replay failed");
response = await handle(new Request(`${base}/api/items`, { method: "POST", headers: { "content-type": "application/json", "idempotency-key": "err" }, body: JSON.stringify({ value: -1 }) }), { trace: [] });
body = await response.json();
if (response.status !== 422 || body.error.value !== "negative") throw new Error("typed Result Err failed");
response = await handle(new Request(`${base}/api/items`, { method: "POST", headers: { "content-type": "application/json", "idempotency-key": "bad-result" }, body: JSON.stringify({ value: 999 }) }), { trace: [] });
body = await response.json();
if (response.status !== 500 || body.error.code !== "ENDPOINT_RESULT_TYPE") throw new Error("result validation refusal failed");
env = { trace: [] };
response = await handle(new Request(`${base}/api/items/a`, { method: "DELETE" }), env);
body = await response.json();
if (response.status !== 504 || body.error.code !== "ENDPOINT_TIMEOUT" || env.aborted !== true) throw new Error(`timeout did not abort signal ${response.status} ${JSON.stringify(body)} ${env.aborted}`);
env = { trace: [] };
const middlewareStarted = Date.now();
response = await handle(new Request(`${base}/api/middleware-timeout`), env);
body = await response.json();
const middlewareElapsed = Date.now() - middlewareStarted;
if (response.status !== 504 || body.error.code !== "ENDPOINT_TIMEOUT" || middlewareElapsed >= 50) throw new Error(`middleware escaped deadline ${response.status} ${middlewareElapsed} ${JSON.stringify(body)}`);
await new Promise((resolve) => setTimeout(resolve, 70));
if (env.trace.includes("middleware-timeout-host")) throw new Error(`host ran after middleware timeout ${JSON.stringify(env.trace)}`);
const oversizedText = "é".repeat(600_000);
const oversizedWire = JSON.stringify({ text: oversizedText });
if (new TextEncoder().encode(oversizedWire).byteLength <= 1_048_576 || oversizedWire.length >= 1_048_576) throw new Error("UTF-8 byte fixture is invalid");
env = { trace: [], uploads: 0 };
response = await handle(new Request(`${base}/api/upload`, { method: "POST", headers: { "content-type": "application/json" }, body: oversizedWire }), env);
body = await response.json();
if (response.status !== 413 || body.error.code !== "ENDPOINT_BODY_TOO_LARGE" || env.uploads !== 0) throw new Error(`UTF-8 byte limit failed ${response.status} ${JSON.stringify(body)} ${env.uploads}`);
const oversizedUndeclaredWire = JSON.stringify({ ignored: "x".repeat(1_048_576) });
env = { trace: [], bodylessCalls: 0 };
response = await handle(new Request(`${base}/api/bodyless`, { method: "POST", headers: { "content-type": "application/json" }, body: oversizedUndeclaredWire }), env);
body = await response.json();
if (response.status !== 413 || body.error.code !== "ENDPOINT_BODY_TOO_LARGE" || env.bodylessCalls !== 0) throw new Error(`bodyless mutation skipped transport cap ${response.status} ${JSON.stringify(body)} ${env.bodylessCalls}`);
response = await handle(new Request(`${base}/api/bodyless`, { method: "POST" }), env);
if (response.status !== 200 || env.bodylessCalls !== 1) throw new Error(`absent empty body was not accepted ${response.status} ${env.bodylessCalls}`);
response = await handle(new Request(`${base}/api/bodyless`, { method: "POST", headers: { "content-type": "application/json" }, body: "{}" }), env);
if (response.status !== 200 || env.bodylessCalls !== 2) throw new Error(`declared empty JSON body was not accepted ${response.status} ${env.bodylessCalls}`);
response = await handle(new Request(`${base}/api/bodyless`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ ignored: true }) }), env);
body = await response.json();
if (response.status !== 400 || body.error.code !== "ENDPOINT_BODY_UNKNOWN" || env.bodylessCalls !== 2) throw new Error(`undeclared body field reached host ${response.status} ${JSON.stringify(body)} ${env.bodylessCalls}`);
for (const value of ["0x10", "0b10", "0o10", "Infinity", "1e3", "+1.0", "1", ".5", "1.", "01.5", " "]) {
env = { trace: [], numericCalls: 0 };
response = await handle(new Request(`${base}/api/measure?value=${encodeURIComponent(value)}`), env);
body = await response.json();
if (response.status !== 422 || body.error.code !== "ENDPOINT_QUERY_TYPE" || env.numericCalls !== 0) throw new Error(`noncanonical Float passed ${JSON.stringify(value)} ${response.status} ${JSON.stringify(body)} ${env.numericCalls}`);
}
env = { trace: [], numericCalls: 0 };
response = await handle(new Request(`${base}/api/measure?value=-1.25`), env);
body = await response.json();
if (response.status !== 200 || body.value !== -1.25 || env.numericCalls !== 1) throw new Error(`canonical Float failed ${response.status} ${JSON.stringify(body)} ${env.numericCalls}`);
for (const value of ["0x10", "1.0", "1e2", "+1", "01", " "]) {
env = { trace: [], numericCalls: 0 };
response = await handle(new Request(`${base}/api/count?value=${encodeURIComponent(value)}`), env);
body = await response.json();
if (response.status !== 422 || body.error.code !== "ENDPOINT_QUERY_TYPE" || env.numericCalls !== 0) throw new Error(`noncanonical Int passed ${JSON.stringify(value)} ${response.status} ${JSON.stringify(body)} ${env.numericCalls}`);
}
env = { trace: [], numericCalls: 0 };
response = await handle(new Request(`${base}/api/count?value=-12`), env);
body = await response.json();
if (response.status !== 200 || body.value !== -12 || env.numericCalls !== 1) throw new Error(`canonical Int failed ${response.status} ${JSON.stringify(body)} ${env.numericCalls}`);
for (const since of ["01/02/2020", "2021-02-29T00:00:00Z", "2020-01-01T24:00:00Z", "2020-01-01T00:00:00+00:00"]) {
env = { trace: [], dateCalls: 0 };
response = await handle(new Request(`${base}/api/events?since=${encodeURIComponent(since)}`), env);
body = await response.json();
if (response.status !== 422 || body.error.code !== "ENDPOINT_QUERY_TYPE" || env.dateCalls !== 0) throw new Error(`invalid Date crossed endpoint boundary ${since} ${response.status} ${JSON.stringify(body)} ${env.dateCalls}`);
}
env = { trace: [], dateCalls: 0 };
response = await handle(new Request(`${base}/api/events?since=${encodeURIComponent("2020-02-29T23:59:59.123Z")}`), env);
body = await response.json();
if (response.status !== 200 || body.value !== "2020-02-29T23:59:59.123Z" || env.dateCalls !== 1) throw new Error(`valid UTC Date failed ${response.status} ${JSON.stringify(body)} ${env.dateCalls}`);
env = { trace: [], optionalObserved: "unset" };
response = await handle(new Request(`${base}/api/optional`, { method: "POST", headers: { "content-type": "application/json" }, body: "{}" }), env);
body = await response.json();
if (response.status !== 200 || env.optionalObserved !== null || !Object.hasOwn(body.value, "value") || body.value.value !== null || body.value.nested.missing !== null || body.value.values[0] !== null || body.value.labels.missing !== null) throw new Error(`recursive Optional None was not serialized as null ${response.status} ${JSON.stringify(body)} ${String(env.optionalObserved)}`);
env = { trace: [], rateCalls: 0 };
response = await handle(new Request(`${base}/api/rate-save`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ value: "wrong" }) }), env);
body = await response.json();
if (response.status !== 422 || body.error.code !== "ENDPOINT_INPUT_TYPE" || env.rateCalls !== 0) throw new Error(`rate identity preempted invalid input ${response.status} ${JSON.stringify(body)} ${env.rateCalls}`);
response = await handle(new Request(`${base}/api/rate-save`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ value: 1 }) }), env);
body = await response.json();
if (response.status !== 403 || body.error.code !== "ENDPOINT_RATE_IDENTITY_REQUIRED" || env.rateCalls !== 0) throw new Error(`valid input did not reach rate identity boundary ${response.status} ${JSON.stringify(body)} ${env.rateCalls}`);
env = { trace: [] };
response = await handle(new Request(`${base}/api/items/%FF`), env);
body = await response.json();
if (response.status !== 400 || body.error.code !== "ENDPOINT_PATH_ENCODING_INVALID" || env.trace.length !== 0) throw new Error(`malformed dynamic path escaped endpoint ownership ${response.status} ${JSON.stringify(body)} ${JSON.stringify(env.trace)}`);
const fastReplayRequest = (key) => new Request(`${base}/api/fast-replay`, { method: "POST", headers: { "idempotency-key": key } });
for (let index = 0; index < 1024; index += 1) {
response = await handle(fastReplayRequest(`capacity-${index}`), { trace: [] });
if (response.status !== 200) throw new Error(`idempotency capacity fill failed ${index} ${response.status}`);
}
if (fastReplayCalls() !== 1024) throw new Error(`capacity fill executed wrong count ${fastReplayCalls()}`);
response = await handle(fastReplayRequest("capacity-0"), { trace: [] });
body = await response.json();
if (response.status !== 200 || body.value !== 1 || fastReplayCalls() !== 1024) throw new Error(`capacity replay evicted itself ${response.status} ${JSON.stringify(body)} ${fastReplayCalls()}`);
response = await handle(fastReplayRequest("capacity-new"), { trace: [] });
if (response.status !== 200 || fastReplayCalls() !== 1025) throw new Error(`new-key capacity admission failed ${response.status} ${fastReplayCalls()}`);
const idempotencyStorage = testStorage("noxid:endpoint-idempotency");
for (const key of await idempotencyStorage.list()) await idempotencyStorage.delete(key);
for (let index = 0; index < 1024; index += 1) await idempotencyStorage.set(`corrupt-${index}`, { malformed: true });
response = await handle(fastReplayRequest("after-corruption"), { trace: [] });
if (response.status !== 200 || (await idempotencyStorage.list()).length !== 1) throw new Error(`corrupt records defeated idempotency capacity ${response.status} ${(await idempotencyStorage.list()).length}`);
for (const key of await idempotencyStorage.list()) await idempotencyStorage.delete(key);
await idempotencyStorage.set("endpoint:SaveItem@1\nsession:ctx-session\ncorrupt-snapshot", { created: Date.now(), status: 200, headers: [], body: "%%%" });
response = await handle(new Request(`${base}/api/items`, { method: "POST", headers: { "content-type": "application/json", "idempotency-key": "corrupt-snapshot" }, body: JSON.stringify({ value: 10 }) }), { trace: [] });
body = await response.json();
if (response.status !== 500 || body.error.code !== "ENDPOINT_STORAGE_FAILED") throw new Error(`invalid stored response escaped containment ${response.status} ${JSON.stringify(body)}`);
response = await handle(new Request(`${base}/api/put`, { method: "PUT" }), { trace: [] });
if (response.status !== 200) throw new Error("put failed");
response = await handle(new Request(`${base}/api/patch`, { method: "PATCH" }), { trace: [] });
if (response.status !== 200) throw new Error("patch failed");
response = await handle(new Request(`${base}/api/items/nope`, { method: "DELETE" }), { trace: [] });
if (response.status !== 504) throw new Error("delete matcher failed");
response = await handle(new Request(`${base}/api/missing`), { trace: [] });
if (response.status !== 404) throw new Error("unknown endpoint failed");
env = { trace: [] };
response = await handle(new Request(`${base}/health`), env);
if (response.status !== 202 || await response.text() !== "ready-from-host" || response.headers.get("x-global") !== "yes" || response.headers.get("x-direct") !== "yes") throw new Error("host-backed direct middleware response/headers failed");
if (JSON.stringify(env.trace) !== JSON.stringify(["global", "direct"])) throw new Error(`direct middleware order failed ${JSON.stringify(env.trace)}`);
env = { trace: [] };
response = await handle(new Request(`${base}/login`), env);
if (response.status !== 307 || response.headers.get("location") !== "/console/dashboard" || response.headers.get("x-global") !== "yes" || response.headers.get("x-redirect") !== "yes") throw new Error("host-backed middleware redirect/headers failed");
if (JSON.stringify(env.trace) !== JSON.stringify(["global", "redirect"])) throw new Error(`redirect middleware order failed ${JSON.stringify(env.trace)}`);
"#;
let output = Command::new("node")
.args(["--input-type=module", "-e", script])
.current_dir(&root)
.output()
.expect("Node.js is required for generated endpoint handler tests");
let _ = std::fs::remove_dir_all(&root);
assert!(
output.status.success(),
"{}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn generated_stream_endpoint_validates_frames_resumes_times_out_and_cancels() {
let mut events = endpoint_boundary(
"Events",
EndpointMethod::Get,
"/api/events",
vec![endpoint_input(
"Events",
EndpointInputSection::Query,
"project",
"String",
)],
"Int",
);
events.kind = EndpointKind::Stream;
events.capabilities = vec!["events.read".into()];
events.timeout_ms = 500;
let mut invalid = endpoint_boundary(
"InvalidEvents",
EndpointMethod::Get,
"/api/invalid-events",
vec![],
"Int",
);
invalid.kind = EndpointKind::Stream;
invalid.timeout_ms = 500;
let mut slow = endpoint_boundary(
"SlowEvents",
EndpointMethod::Get,
"/api/slow-events",
vec![],
"Int",
);
slow.kind = EndpointKind::Stream;
slow.timeout_ms = 20;
let mut cancellable = endpoint_boundary(
"CancellableEvents",
EndpointMethod::Get,
"/api/cancellable-events",
vec![],
"Int",
);
cancellable.kind = EndpointKind::Stream;
cancellable.timeout_ms = 500;
let mut missing = endpoint_boundary(
"MissingEvents",
EndpointMethod::Get,
"/api/missing-events",
vec![],
"Int",
);
missing.kind = EndpointKind::Stream;
missing.timeout_ms = 500;
let mut result_events = endpoint_boundary(
"ResultEvents",
EndpointMethod::Get,
"/api/result-events",
vec![],
"Result<Int, String>",
);
result_events.kind = EndpointKind::Stream;
result_events.timeout_ms = 500;
let program = ExecutionProgram {
live_resources: vec![],
presences: vec![],
boundaries: vec![],
endpoints: vec![events, invalid, slow, cancellable, missing, result_events],
tasks: vec![],
queues: vec![],
};
let output = generate(
&program,
"./host.mjs",
"./validators.mjs",
"./middleware.mjs",
"/",
&[],
);
assert!(
output
.handler
.contains("ENDPOINT_STREAM_HEARTBEAT_MS = 15_000")
);
assert!(output.handler.contains("ENDPOINT_STREAM_MAX_EVENTS = 256"));
assert!(
!output
.handler
.contains("validator:endpoint.ResultEvents.error")
);
let unique = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
let root = std::env::temp_dir().join(format!(
"noxid-stream-endpoint-handler-{}-{unique}",
std::process::id()
));
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("handler.mjs"), output.handler).unwrap();
std::fs::write(
root.join("validators.mjs"),
r#"const int = (value) => { if (!Number.isSafeInteger(value)) throw new Error("Int"); return value; };
export const typeValidators = Object.freeze({
"validator:endpoint.Events.query": (value) => { if (!value || typeof value.project !== "string") throw new Error("project"); return Object.freeze({ project: value.project }); },
"validator:endpoint.Events.result": int,
"validator:endpoint.InvalidEvents.result": int,
"validator:endpoint.SlowEvents.result": int,
"validator:endpoint.CancellableEvents.result": int,
"validator:endpoint.MissingEvents.result": int,
});
"#,
)
.unwrap();
std::fs::write(
root.join("middleware.mjs"),
"export const middleware = Object.freeze({});\nexport const globalMiddleware = Object.freeze([]);\n",
)
.unwrap();
std::fs::write(
root.join("host.mjs"),
r#"export const endpoints = Object.freeze({
"endpoint:Events@1": async function* (_args, context) {
context.environment.eventCalls = (context.environment.eventCalls ?? 0) + 1;
yield 1; yield 2; yield 3;
},
"endpoint:InvalidEvents@1": async function* () { yield 1; yield "bad"; yield 3; },
"endpoint:SlowEvents@1": async function* () { yield 1; await new Promise((resolve) => setTimeout(resolve, 100)); yield 2; },
"endpoint:CancellableEvents@1": async function* (_args, context) {
try { yield 1; await new Promise((resolve) => setTimeout(resolve, 100)); yield 2; }
finally { context.environment.cancelled = (context.environment.cancelled ?? 0) + 1; }
},
});
export async function authorize({ capability, request }) {
return capability === "events.read" && request.headers.get("x-events") === "yes";
}
"#,
)
.unwrap();
let script = r#"import { fetch as handle } from "./handler.mjs";
const base = "http://noxid.test";
let environment = { eventCalls: 0 };
environment.sessionId = "session-a";
let response = await handle(new Request(`${base}/api/events?project=A`), environment);
let denied = await response.json();
if (response.status !== 403 || denied.error.code !== "ENDPOINT_CAPABILITY_DENIED" || environment.eventCalls !== 0) throw new Error(`stream authorization failed ${response.status} ${JSON.stringify(denied)}`);
response = await handle(new Request(`${base}/api/events?project=A`, { headers: { "x-events": "yes" } }), environment);
if (response.status !== 200 || response.headers.get("content-type") !== "text/event-stream; charset=utf-8" || response.headers.get("cache-control") !== "no-store") throw new Error("SSE headers failed");
const first = await response.text();
if (environment.eventCalls !== 1) throw new Error(`host call count ${environment.eventCalls}`);
const ids = [...first.matchAll(/^id: ([^\n]+)$/gm)].map((match) => match[1]);
if (ids.length !== 3 || !ids.every((id, index) => id.endsWith(`:${index + 1}`))) throw new Error(`SSE ids failed ${JSON.stringify(ids)} ${first}`);
if (!first.includes("event: message\ndata: 1\n\n") || !first.includes("event: message\ndata: 3\n\n")) throw new Error(`typed SSE frames failed ${first}`);
response = await handle(new Request(`${base}/api/events?project=A`, { headers: { "x-events": "yes", "last-event-id": ids[0] } }), environment);
const replay = await response.text();
if (environment.eventCalls !== 1 || replay.includes("data: 1\n") || !replay.includes("data: 2\n") || !replay.includes("data: 3\n")) throw new Error(`resume failed calls=${environment.eventCalls} ${replay}`);
response = await handle(new Request(`${base}/api/events?project=B`, { headers: { "x-events": "yes", "last-event-id": ids[0] } }), environment);
const crossArgument = await response.text();
if (!crossArgument.includes("STREAM_RESUME_UNAVAILABLE") || !crossArgument.includes("request-mismatch") || environment.eventCalls !== 1 || crossArgument.includes("data: 2\n")) throw new Error(`cross-argument replay escaped isolation ${crossArgument}`);
const otherIdentity = { eventCalls: 0, sessionId: "session-b" };
response = await handle(new Request(`${base}/api/events?project=A`, { headers: { "x-events": "yes", "last-event-id": ids[0] } }), otherIdentity);
const crossIdentity = await response.text();
if (!crossIdentity.includes("STREAM_RESUME_UNAVAILABLE") || !crossIdentity.includes("request-mismatch") || otherIdentity.eventCalls !== 0 || crossIdentity.includes("data: 2\n")) throw new Error(`cross-identity replay escaped isolation ${crossIdentity}`);
const disconnected = new AbortController();
disconnected.abort("already disconnected");
const disconnectedEnvironment = { eventCalls: 0, sessionId: "session-a" };
response = await handle(new Request(`${base}/api/events?project=A`, { headers: { "x-events": "yes" }, signal: disconnected.signal }), disconnectedEnvironment);
if (response.status !== 200 || await response.text() !== "" || disconnectedEnvironment.eventCalls !== 0) throw new Error(`already-aborted request invoked stream host ${disconnectedEnvironment.eventCalls}`);
response = await handle(new Request(`${base}/api/events?project=A`, { headers: { "x-events": "yes", "last-event-id": "forged" } }), environment);
const malformed = await response.text();
if (!malformed.includes("event: noxid-error") || !malformed.includes("STREAM_RESUME_UNAVAILABLE") || environment.eventCalls !== 1) throw new Error(`malformed resume did not fail closed ${malformed}`);
response = await handle(new Request(`${base}/api/invalid-events`));
const invalid = await response.text();
if (!invalid.includes("data: 1\n") || invalid.includes("data: 3\n") || !invalid.includes("event: noxid-error") || !invalid.includes("STREAM_EVENT_TYPE")) throw new Error(`invalid event did not terminate ${invalid}`);
response = await handle(new Request(`${base}/api/missing-events`));
const missing = await response.text();
if (response.status !== 200 || !missing.includes("event: noxid-error") || !missing.includes("STREAM_IMPLEMENTATION_MISSING")) throw new Error(`missing implementation was not structured SSE ${response.status} ${missing}`);
const started = Date.now();
response = await handle(new Request(`${base}/api/slow-events`));
const timedOut = await response.text();
const elapsed = Date.now() - started;
if (!timedOut.includes("data: 1\n") || timedOut.includes("data: 2\n") || !timedOut.includes("ENDPOINT_TIMEOUT") || elapsed >= 80) throw new Error(`connection timeout failed elapsed=${elapsed} ${timedOut}`);
environment = { cancelled: 0 };
response = await handle(new Request(`${base}/api/cancellable-events`), environment);
const reader = response.body.getReader();
const firstChunk = await reader.read();
if (firstChunk.done || !new TextDecoder().decode(firstChunk.value).includes("data: 1")) throw new Error("cancellable stream did not start");
await reader.cancel("client disconnected");
await new Promise((resolve) => setTimeout(resolve, 10));
if (environment.cancelled !== 1) throw new Error(`disconnect did not cancel iterator ${environment.cancelled}`);
"#;
let output = Command::new("node")
.args(["--input-type=module", "-e", script])
.current_dir(&root)
.output()
.expect("Node.js is required for generated stream endpoint tests");
let _ = std::fs::remove_dir_all(&root);
assert!(
output.status.success(),
"{}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn generated_mcp_surface_lists_exact_openapi_tools_and_reuses_endpoint_pipeline() {
let mut widget = endpoint_boundary(
"GetWidget",
EndpointMethod::Post,
"/api/widgets/[id]",
vec![
endpoint_input("GetWidget", EndpointInputSection::Params, "id", "String"),
endpoint_input(
"GetWidget",
EndpointInputSection::Query,
"tags",
"Optional<Array<String>>",
),
endpoint_input(
"GetWidget",
EndpointInputSection::Body,
"input",
"WidgetInput",
),
],
"Result<Widget, String>",
);
widget.description = Some("Fetch one typed widget".into());
widget.capabilities = vec!["widgets.read".into()];
widget.middleware = vec!["audit".into()];
widget.inputs[2].type_id = Some(SemanticId::type_definition("Api", "WidgetInput"));
widget.result.type_id = Some(SemanticId::type_definition("Api", "Widget"));
let mut events = endpoint_boundary(
"WidgetEvents",
EndpointMethod::Get,
"/api/widget-events",
vec![],
"Widget",
);
events.kind = EndpointKind::Stream;
events.description = Some("Watch typed widgets".into());
events.timeout_ms = 200;
events.result.type_id = Some(SemanticId::type_definition("Api", "Widget"));
let program = ExecutionProgram {
live_resources: vec![],
presences: vec![],
boundaries: vec![],
endpoints: vec![widget, events],
tasks: vec![],
queues: vec![],
};
let openapi = r##"{"openapi":"3.1.0","info":{"title":"MCP fixture","version":"0.1.0"},"paths":{"/api/widgets/{id}":{"post":{"operationId":"GetWidget","description":"Fetch one typed widget","x-noxid-endpoint-id":"endpoint:GetWidget@1","x-noxid-signature":"GetWidget(params { id: String }, query { tags: Optional<Array<String>> }, body { input: WidgetInput }) -> Result<Widget, String>","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"tags","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"input":{"$ref":"#/components/schemas/WidgetInput"}},"required":["input"],"additionalProperties":false}}}},"responses":{"200":{"description":"Typed endpoint result","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true},"value":{"$ref":"#/components/schemas/Widget"}},"required":["ok","value"],"additionalProperties":false}}}}}}},"/api/widget-events":{"get":{"operationId":"WidgetEvents","description":"Watch typed widgets","x-noxid-endpoint-id":"endpoint:WidgetEvents@1","x-noxid-signature":"WidgetEvents() -> Stream<Widget>","responses":{"200":{"description":"SSE event stream","content":{"text/event-stream":{"schema":{"type":"string"},"x-noxid-event-schema":{"$ref":"#/components/schemas/Widget"}}}}}}}},"components":{"schemas":{"Nested":{"type":"object","properties":{"scores":{"type":"array","items":{"type":"integer"}}},"required":["scores"],"additionalProperties":false},"WidgetInput":{"type":"object","properties":{"label":{"type":"string"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"nested":{"$ref":"#/components/schemas/Nested"}},"required":["label","nested"],"additionalProperties":false},"Widget":{"type":"object","properties":{"name":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"nested":{"$ref":"#/components/schemas/Nested"}},"required":["name","tags","nested"],"additionalProperties":false},"NoxidErrorResponse":{"type":"object","properties":{"ok":{"const":false},"error":{"type":"object"}},"required":["ok","error"]}}}}"##;
let enabled = generate_with_agent_surfaces(
&program,
"./host.mjs",
"./validators.mjs",
"./middleware.mjs",
None,
"/console",
&[],
AgentSurfaceOptions {
openapi_json: Some(openapi),
serve_openapi: false,
mcp: true,
principal_authority_import: None,
},
);
let docs = generate_with_agent_surfaces(
&program,
"./host.mjs",
"./validators.mjs",
"./middleware.mjs",
None,
"/console",
&[],
AgentSurfaceOptions {
openapi_json: Some(openapi),
serve_openapi: true,
mcp: false,
principal_authority_import: None,
},
);
let off = generate(
&program,
"./host.mjs",
"./validators.mjs",
"./middleware.mjs",
"/console",
&[],
);
let unique = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
let root = std::env::temp_dir().join(format!(
"noxid-mcp-endpoint-handler-{}-{unique}",
std::process::id()
));
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("handler.mjs"), enabled.handler).unwrap();
std::fs::write(root.join("handler-docs.mjs"), docs.handler).unwrap();
std::fs::write(root.join("handler-off.mjs"), off.handler).unwrap();
std::fs::write(root.join("openapi.json"), openapi).unwrap();
std::fs::write(
root.join("validators.mjs"),
r#"const fail = (message) => { throw new Error(message); };
const nested = (value) => value && Array.isArray(value.scores) && value.scores.every(Number.isSafeInteger) ? Object.freeze({ scores: Object.freeze([...value.scores]) }) : fail("Nested");
const input = (value) => value && typeof value.label === "string" && (value.note === null || value.note === undefined || typeof value.note === "string") ? Object.freeze({ label: value.label, note: value.note ?? null, nested: nested(value.nested) }) : fail("WidgetInput");
const widget = (value) => value && typeof value.name === "string" && Array.isArray(value.tags) && value.tags.every((tag) => typeof tag === "string") ? Object.freeze({ name: value.name, tags: Object.freeze([...value.tags]), nested: nested(value.nested) }) : fail("Widget");
export const typeValidators = Object.freeze({
"validator:endpoint.GetWidget.params": (value) => typeof value.id === "string" ? Object.freeze({ id: value.id }) : fail("params"),
"validator:endpoint.GetWidget.query": (value) => value.tags === null || (Array.isArray(value.tags) && value.tags.every((tag) => typeof tag === "string")) ? Object.freeze({ tags: value.tags === null ? null : Object.freeze([...value.tags]) }) : fail("query"),
"validator:endpoint.GetWidget.body": (value) => Object.freeze({ input: input(value.input) }),
"validator:endpoint.GetWidget.result": widget,
"validator:endpoint.GetWidget.error": (value) => typeof value === "string" ? value : fail("error"),
"validator:endpoint.WidgetEvents.result": widget,
});
"#,
)
.unwrap();
std::fs::write(
root.join("middleware.mjs"),
r#"export const globalMiddleware = Object.freeze([]);
export const middleware = Object.freeze({ audit: async ({ request, environment }) => {
environment.trace.push(`middleware:${new URL(request.url).pathname}:${request.headers.get("x-session")}`);
return { allow: true, context: { sessionId: request.headers.get("x-session") } };
} });
"#,
)
.unwrap();
std::fs::write(
root.join("host.mjs"),
r#"export const endpoints = Object.freeze({
"endpoint:GetWidget@1": async ({ id, tags, input }, context) => {
context.environment.trace.push(`host:${id}:${context.middlewareContext.sessionId}`);
context.environment.hostCalls = (context.environment.hostCalls ?? 0) + 1;
return { tag: "Ok", value: { name: input.label, tags: tags ?? [], nested: input.nested } };
},
"endpoint:WidgetEvents@1": async function* () {
yield { name: "one", tags: ["live"], nested: { scores: [1] } };
yield { name: "two", tags: [], nested: { scores: [2, 3] } };
},
});
export async function authorize({ capability, request, environment }) {
environment.trace.push(`authorize:${capability}`);
return request.headers.get("x-capability") === capability;
}
"#,
)
.unwrap();
let script = r##"import { readFile } from "node:fs/promises";
import { fetch as handle } from "./handler.mjs";
import { fetch as handleDocs } from "./handler-docs.mjs";
import { fetch as handleOff } from "./handler-off.mjs";
const expectedOpenApi = await readFile("./openapi.json", "utf8");
const url = "http://noxid.test/console/_noxid/mcp";
const request = (id, method, params = {}, headers = {}) => new Request(url, {
method: "POST",
headers: { "content-type": "application/json", accept: "application/json, text/event-stream", "mcp-protocol-version": "2025-11-25", ...headers },
body: JSON.stringify({ jsonrpc: "2.0", id, method, params }),
});
let response = await handleOff(request(1, "tools/list"), { trace: [] });
if (response.status !== 404 || (await response.json()).error.code !== "AGENT_SURFACE_DISABLED") throw new Error("default-off MCP door did not 404");
response = await handleOff(new Request("http://noxid.test/console/_noxid/openapi.json"), { trace: [] });
if (response.status !== 404) throw new Error("default-off OpenAPI door did not 404");
response = await handle(new Request("http://noxid.test/console/_noxid/openapi.json"), { trace: [] });
if (response.status !== 404) throw new Error("MCP-only build exposed OpenAPI");
response = await handleDocs(new Request("http://noxid.test/console/_noxid/openapi.json"), { trace: [] });
if (response.status !== 200 || await response.text() !== expectedOpenApi) throw new Error("OpenAPI document was not served exactly");
response = await handle(request(2, "initialize", { protocolVersion: "2025-11-25", capabilities: {}, clientInfo: { name: "test", version: "1" } }), { trace: [] });
let rpc = await response.json();
if (response.status !== 200 || rpc.result.protocolVersion !== "2025-11-25" || rpc.result.serverInfo.name !== "noxid-endpoints") throw new Error(`initialize failed ${JSON.stringify(rpc)}`);
response = await handle(request(3, "tools/list"), { trace: [] });
rpc = await response.json();
const tools = rpc.result.tools;
if (tools.length !== 2 || new Set(tools.map((tool) => tool.name)).size !== 2 || tools.map((tool) => tool.name).sort().join(",") !== "GetWidget,WidgetEvents") throw new Error(`tool list diverged ${JSON.stringify(tools)}`);
const get = tools.find((tool) => tool.name === "GetWidget");
if (get.description !== "Fetch one typed widget" || get["x-noxid-endpoint"].signature.includes("Result<Widget, String>") !== true) throw new Error("description/signature missing");
if (get.inputSchema.properties.input.$ref !== "#/$defs/WidgetInput" || get.inputSchema.$defs.WidgetInput.properties.nested.$ref !== "#/$defs/Nested" || get.inputSchema.$defs.Nested.properties.scores.items.type !== "integer") throw new Error(`nested input schema drifted ${JSON.stringify(get.inputSchema)}`);
if (get.inputSchema.properties.tags.anyOf[0].items.type !== "string" || !get.inputSchema.required.includes("input") || get.inputSchema.required.includes("tags")) throw new Error("optional/array schema drifted");
if (get.outputSchema.properties.body.properties.value.$ref !== "#/$defs/Widget" || get.outputSchema.$defs.Widget.properties.nested.$ref !== "#/$defs/Nested") throw new Error("Result success schema drifted");
const stream = tools.find((tool) => tool.name === "WidgetEvents");
if (stream.outputSchema.properties.body.properties.events.items.$ref !== "#/$defs/Widget") throw new Error("stream event schema drifted");
let environment = { trace: [], hostCalls: 0, sessionId: "environment-session" };
const args = { id: "w-1", tags: ["a", "b"], input: { label: "ready", note: null, nested: { scores: [7, 8] } } };
response = await handle(request(4, "tools/call", { name: "GetWidget", arguments: args }, { "x-session": "mcp-session" }), environment);
rpc = await response.json();
if (rpc.result.isError !== true || rpc.result.structuredContent.body.error.code !== "ENDPOINT_CAPABILITY_DENIED" || environment.hostCalls !== 0) throw new Error(`capability denial did not reuse endpoint pipeline ${JSON.stringify(rpc)} ${JSON.stringify(environment)}`);
if (JSON.stringify(environment.trace) !== JSON.stringify(["middleware:/console/api/widgets/w-1:mcp-session", "authorize:widgets.read"])) throw new Error(`denial order diverged ${JSON.stringify(environment.trace)}`);
environment = { trace: [], hostCalls: 0 };
response = await handle(request(41, "tools/call", { name: "GetWidget", arguments: {} }, { "x-session": "mcp-session" }), environment);
rpc = await response.json();
if (rpc.result.structuredContent.body.error.code !== "ENDPOINT_CAPABILITY_DENIED" || environment.hostCalls !== 0 || environment.trace[1] !== "authorize:widgets.read") throw new Error(`malformed unauthorized MCP call bypassed endpoint capability order ${JSON.stringify(rpc)} ${JSON.stringify(environment)}`);
environment = { trace: [], hostCalls: 0 };
response = await handle(request(5, "tools/call", { name: "GetWidget", arguments: args }, { "x-session": "mcp-session", "x-capability": "widgets.read" }), environment);
rpc = await response.json();
if (rpc.result.isError !== false || rpc.result.structuredContent.status !== 200 || rpc.result.structuredContent.body.value.name !== "ready" || rpc.result.structuredContent.body.value.nested.scores[1] !== 8 || environment.hostCalls !== 1) throw new Error(`typed tool roundtrip failed ${JSON.stringify(rpc)} ${JSON.stringify(environment)}`);
if (JSON.stringify(environment.trace) !== JSON.stringify(["middleware:/console/api/widgets/w-1:mcp-session", "authorize:widgets.read", "host:w-1:mcp-session"])) throw new Error(`MCP pipeline order/session diverged ${JSON.stringify(environment.trace)}`);
environment = { trace: [], hostCalls: 0 };
const invalid = { ...args, input: { ...args.input, nested: { scores: ["bad"] } } };
response = await handle(request(6, "tools/call", { name: "GetWidget", arguments: invalid }, { "x-session": "mcp-session", "x-capability": "widgets.read" }), environment);
rpc = await response.json();
if (rpc.result.isError !== true || rpc.result.structuredContent.status !== 422 || rpc.result.structuredContent.body.error.code !== "ENDPOINT_INPUT_TYPE" || environment.hostCalls !== 0) throw new Error(`MCP input escaped endpoint validation ${JSON.stringify(rpc)}`);
response = await handle(request(7, "tools/call", { name: "WidgetEvents", arguments: {} }), { trace: [] });
rpc = await response.json();
if (rpc.result.isError !== false || rpc.result.structuredContent.body.events.length !== 2 || rpc.result.structuredContent.body.events[1].nested.scores[1] !== 3) throw new Error(`stream endpoint tool mapping failed ${JSON.stringify(rpc)}`);
"##;
let output = Command::new("node")
.args(["--input-type=module", "-e", script])
.current_dir(&root)
.output()
.expect("Node.js is required for generated MCP endpoint tests");
let _ = std::fs::remove_dir_all(&root);
assert!(
output.status.success(),
"{}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
}