///|
/// Exact native mappings. The selected mapping is retained by the page session.
#derive(Eq)
pub(all) enum Contract {
Executions
CapabilityChecks
}
///|
pub extend Contract with Eq::{equal, not_equal}
///|
pub fn Contract::version(self : Contract) -> String {
match self {
Executions => "0.2.0-draft.1"
CapabilityChecks => "0.2.0-draft.2"
}
}
///|
pub fn Contract::from_string(value : String) -> Contract raise Invalid {
match value {
"0.2.0-draft.1" => Executions
"0.2.0-draft.2" => CapabilityChecks
_ => raise Invalid("native.frame.shape")
}
}
///|
pub fn Request::contract(self : Request) -> Contract {
match self.value {
Object(fields) =>
match fields["contractVersion"] {
String("0.2.0-draft.2") => CapabilityChecks
_ => Executions
}
_ => abort("Admitted native request")
}
}
///|
/// This validates the compatibility wire selection, not model capabilities.
fn checking_selection(value : Json) -> Unit raise Invalid {
let fields = closed(value, ["profile", "contractVersion", "policy"])
guard fields["profile"] == Json::string("morphir/workbench/admission") &&
fields["contractVersion"] == Json::string("0.1.0-draft.1") &&
[Json::string("strict"), Json::string("permissive")].contains(
fields["policy"],
) else {
raise Invalid("native.frame.shape")
}
}
///|
/// New exact mapping. The frozen decoder remains closed to all policy fields.
pub fn decode_policy(bytes : Bytes) -> Request raise Invalid {
guard bytes.length() <= 1048576 else { raise Invalid("native.frame.limit") }
let source = @utf8.decode(bytes[:], ignore_bom=false) catch {
_ => raise Invalid("native.frame.utf8")
}
let value = @wire.parse_bounded(source) catch {
@wire.Invalid("json_limit", _) => raise Invalid("native.frame.limit")
_ => raise Invalid("native.frame.json")
}
guard value is Object(fields) &&
fields.get("contractVersion") == Some(Json::string("0.2.0-draft.2")) else {
raise Invalid("native.frame.shape")
}
if fields.get("operation") is Some(String(operation)) &&
[
"workspace.choose", "workspace.cancel-picker", "workspace.revoke", "workspace.open",
"workspace.read", "workspace.release",
].contains(operation) &&
bytes.length() > 4096 {
raise Invalid("native.frame.limit")
}
// Project a separate copy through unchanged common framing and nested-source
// checks. Never remove fields from the original admitted request.
let common = @wire.parse_bounded(value.stringify()) catch {
_ => raise Invalid("native.frame.limit")
}
guard common is Object(projected) else { abort("Native request object") }
projected["contractVersion"] = Json::string("0.2.0-draft.1")
if fields.get("operation") == Some(Json::string("execution.submit")) {
guard fields.get("payload") is Some(Object(payload)) else {
raise Invalid("native.frame.shape")
}
let names = [
"contractVersion", "model", "entry", "inputs", "runtime", "providerId",
]
if payload.contains("admission") {
names.push("admission")
checking_selection(payload["admission"])
}
ignore(closed(fields["payload"], names))
guard payload["runtime"] == Json::string("scheme") else {
raise Invalid("native.frame.shape")
}
let provider = text(payload["providerId"], 1, 128)
guard provider.length() <= 128 else { raise Invalid("native.frame.shape") }
guard projected["payload"] is Object(body) else { abort("Native payload") }
body.remove("runtime") |> ignore
body.remove("providerId") |> ignore
body.remove("admission") |> ignore
}
ignore(decode(@utf8.encode(common.stringify())))
{ value, }
}
///|
/// Host dispatch selects an explicit mapping before effects or caller admission.
pub fn decode_current(bytes : Bytes) -> Request raise Invalid {
guard bytes.length() <= 1048576 else { raise Invalid("native.frame.limit") }
let source = @utf8.decode(bytes[:], ignore_bom=false) catch {
_ => raise Invalid("native.frame.utf8")
}
let value = @wire.parse_bounded(source) catch {
@wire.Invalid("json_limit", _) => raise Invalid("native.frame.limit")
_ => raise Invalid("native.frame.json")
}
match value {
Object(fields) if fields.get("contractVersion") ==
Some(Json::string("0.2.0-draft.2")) => decode_policy(bytes)
_ => decode(bytes)
}
}