Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions arete-idl/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -692,13 +692,14 @@ fn codama_account_pda(
for seed in pda_seeds {
match seed {
CodamaPdaSeedNode::Constant { seed_type, value } => {
let bytes = codama_constant_seed_bytes(value, seed_type.as_ref()).or_else(|| {
tracing::warn!(
account = %account.name,
"failed to encode constant PDA seed; degrading to user-provided"
);
None
})?;
let bytes =
codama_constant_seed_bytes(value, seed_type.as_ref()).or_else(|| {
tracing::warn!(
account = %account.name,
"failed to encode constant PDA seed; degrading to user-provided"
);
None
})?;
idl_seeds.push(IdlPdaSeed::Const { value: bytes });
}
CodamaPdaSeedNode::Variable { name, seed_type } => {
Expand Down
4 changes: 4 additions & 0 deletions cli/src/commands/sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,10 @@ fn generate_typescript_sdk_from_source(
let output = arete_interpreter::typescript::compile_stack_spec(stack_spec, Some(config))
.map_err(|e| anyhow::anyhow!("Failed to compile TypeScript: {}", e))?;

for warning in &output.warnings {
println!("{} {}", "⚠".yellow().bold(), warning);
}

arete_interpreter::typescript::write_stack_typescript_to_file(&output, output_path)
.with_context(|| format!("Failed to write TypeScript to {}", output_path.display()))?;

Expand Down
6 changes: 3 additions & 3 deletions examples/ore-rust/src/generated/ore/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ pub struct OreTreasury {
#[serde(default)]
pub state: OreTreasuryState,
#[serde(default)]
pub treasury_snapshot: Option<Option<serde_json::Value>>,
pub treasury_snapshot: Option<Option<Treasury>>,
}


Expand Down Expand Up @@ -232,9 +232,9 @@ pub struct OreMiner {
#[serde(default)]
pub automation: OreMinerAutomation,
#[serde(default)]
pub miner_snapshot: Option<Option<serde_json::Value>>,
pub miner_snapshot: Option<Option<Miner>>,
#[serde(default)]
pub automation_snapshot: Option<Option<serde_json::Value>>,
pub automation_snapshot: Option<Option<Automation>>,
}


Expand Down
1 change: 1 addition & 0 deletions interpreter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub mod scheduler;
pub mod slot_hash_cache;
pub mod spec_trait;
pub mod typescript;
pub mod typescript_instructions;
pub mod versioned;
pub mod vm;
pub mod vm_metrics;
Expand Down
1 change: 1 addition & 0 deletions interpreter/src/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,7 @@ fn normalized_integer_kind(rust_type_name: &str) -> &'static str {
{
"u64"
} else {
// Signed small ints (i16/i8/isize) and anything unknown widen to i64.
"i64"
}
}
Expand Down
75 changes: 67 additions & 8 deletions interpreter/src/typescript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1889,7 +1889,7 @@ fn unique_resolved_type_name_ts(
}

/// Convert snake_case to PascalCase
fn to_pascal_case(s: &str) -> String {
pub(crate) fn to_pascal_case(s: &str) -> String {
s.split(['_', '-', '.'])
.map(|word| {
let mut chars = word.chars();
Expand Down Expand Up @@ -2017,6 +2017,9 @@ pub struct TypeScriptStackOutput {
pub interfaces: String,
pub stack_definition: String,
pub imports: String,
/// Non-fatal codegen warnings (skipped instructions, PDAs degraded to
/// user-provided accounts). Callers should surface these to the user.
pub warnings: Vec<String>,
}

impl TypeScriptStackOutput {
Expand Down Expand Up @@ -2099,9 +2102,47 @@ pub fn compile_stack_spec(
schema_names.extend(output.schema_names);
}

let interfaces = all_interfaces.join("\n\n");
let mut interfaces = all_interfaces.join("\n\n");

// 2. Generate unified stack definition with all entity views
// 2. Generate instruction-construction handlers from the stack spec.
// Program errors live once at the stack level (in the IDL snapshots) and
// are scoped per program by the instruction codegen. Entity interface
// names are reserved so defined-type interfaces cannot collide with them.
let mut reserved_type_names: std::collections::HashSet<String> =
std::collections::HashSet::new();
for line in interfaces.lines() {
for prefix in ["export interface ", "export type "] {
if let Some(rest) = line.strip_prefix(prefix) {
let name: String = rest
.chars()
.take_while(|c| c.is_alphanumeric() || *c == '_')
.collect();
if !name.is_empty() {
reserved_type_names.insert(name);
}
}
}
}
let instructions_codegen = crate::typescript_instructions::generate_instructions_code(
stack_name,
&stack_spec.instructions,
&stack_spec.idls,
&stack_spec.pdas,
&stack_spec.program_ids,
&reserved_type_names,
);
if !instructions_codegen.code.is_empty() {
if interfaces.is_empty() {
interfaces = instructions_codegen.code.clone();
} else {
interfaces = format!("{}\n\n{}", interfaces, instructions_codegen.code);
}
}

// 3. Generate unified stack definition with all entity views and handlers.
let instructions_block = crate::typescript_instructions::render_instructions_stack_block(
&instructions_codegen.stack_entries,
);
let stack_definition = generate_stack_definition_multi(
stack_name,
&stack_kebab,
Expand All @@ -2110,19 +2151,35 @@ pub fn compile_stack_spec(
&stack_spec.pdas,
&stack_spec.program_ids,
&schema_names,
&instructions_block,
&config,
);

let imports = if stack_spec.pdas.values().any(|p| !p.is_empty()) {
"import { z } from 'zod';\nimport { pda, literal, account, arg, bytes } from '@usearete/sdk';".to_string()
} else {
// 4. Assemble `@usearete/sdk` imports based on what was actually emitted.
let mut sdk_named: Vec<String> = Vec::new();
if stack_spec.pdas.values().any(|p| !p.is_empty()) {
for helper in ["pda", "literal", "account", "arg", "bytes"] {
sdk_named.push(helper.to_string());
}
}
if instructions_codegen.needs_runtime_import {
sdk_named.push("createInstructionHandler".to_string());
sdk_named.push("type ErrorMetadata".to_string());
}
let imports = if sdk_named.is_empty() {
"import { z } from 'zod';".to_string()
} else {
format!(
"import {{ z }} from 'zod';\nimport {{ {} }} from '@usearete/sdk';",
sdk_named.join(", ")
)
};

Ok(TypeScriptStackOutput {
imports,
interfaces,
stack_definition,
warnings: instructions_codegen.warnings,
})
}

Expand Down Expand Up @@ -2166,6 +2223,7 @@ fn generate_stack_definition_multi(
pdas: &BTreeMap<String, BTreeMap<String, PdaDefinition>>,
program_ids: &[String],
schema_names: &[String],
instructions_block: &str,
config: &TypeScriptStackConfig,
) -> String {
let export_name = format!(
Expand Down Expand Up @@ -2262,7 +2320,7 @@ export const {export_name} = {{
{url_line}
views: {{
{views_body}
}},{schemas_section}{pdas_section}
}},{schemas_section}{pdas_section}{instructions_section}
}} as const;

/** Type alias for the stack */
Expand All @@ -2282,6 +2340,7 @@ export default {export_name};"#,
views_body = views_body,
schemas_section = schemas_block,
pdas_section = pdas_block,
instructions_section = instructions_block,
entity_union = entity_types.join(" | "),
)
}
Expand Down Expand Up @@ -2375,7 +2434,7 @@ function listView<T>(view: string): ViewDef<T, 'list'> {
}

/// Convert PascalCase to SCREAMING_SNAKE_CASE (e.g., "OreStream" -> "ORE_STREAM")
fn to_screaming_snake_case(s: &str) -> String {
pub(crate) fn to_screaming_snake_case(s: &str) -> String {
let mut result = String::new();
for (i, ch) in s.chars().enumerate() {
if ch.is_uppercase() && i > 0 {
Expand Down
Loading
Loading