export namespace {{ name }} {
{%- for constructor in constructors %}

{{ crate::render::typescript::templates::ts_doc_block(constructor.doc, "  ") }}  export const {{ constructor.ts_name }} = ({% for param in constructor.params %}{{ param.name }}: {{ param.ts_type }}{% if !loop.last %}, {% endif %}{% endfor %}): {{ constructor.return_type }} => {
{%- if !constructor.wrapper_code().is_empty() %}
    {{ constructor.wrapper_code() }}
{%- endif %}
{%- if constructor.cleanup_code().is_empty() %}
{%- if constructor.return_route.is_void() %}
    (_exports.{{ constructor.ffi_name }} as Function)({{ constructor.ffi_call_args() }});
{%- elif constructor.return_route.is_direct() %}
    return (_exports.{{ constructor.ffi_name }} as Function)({{ constructor.ffi_call_args() }}){{ constructor.return_route.ts_cast() }};
{%- elif constructor.return_route.is_struct_return_slot() %}
    const __outPtr = _module.exports.boltffi_wasm_alloc({{ constructor.return_route.return_slot_size().unwrap() }});
    try {
      (_exports.{{ constructor.ffi_name }} as Function)({% if constructor.ffi_call_args().is_empty() %}__outPtr{% else %}__outPtr, {{ constructor.ffi_call_args() }}{% endif %});
      return {{ constructor.return_route.decode_expr() }};
    } finally {
      _module.exports.boltffi_wasm_free(__outPtr, {{ constructor.return_route.return_slot_size().unwrap() }});
    }
{%- elif constructor.return_route.is_void_slot() %}
    (_exports.{{ constructor.ffi_name }} as Function)({{ constructor.ffi_call_args() }});
    return {{ constructor.return_route.decode_expr() }};
{%- elif constructor.return_route.is_packed() %}
    const packed = (_exports.{{ constructor.ffi_name }} as Function)({{ constructor.ffi_call_args() }}) as bigint;
    const reader = _module.takePackedBuffer(packed);
    return {{ constructor.return_route.decode_expr() }};
{%- else %}
    const packed = (_exports.{{ constructor.ffi_name }} as Function)({{ constructor.ffi_call_args() }}) as bigint;
    return {{ constructor.return_route.decode_expr() }};
{%- endif %}
{%- else %}
    try {
{%- if constructor.return_route.is_void() %}
      (_exports.{{ constructor.ffi_name }} as Function)({{ constructor.ffi_call_args() }});
{%- elif constructor.return_route.is_direct() %}
      return (_exports.{{ constructor.ffi_name }} as Function)({{ constructor.ffi_call_args() }}){{ constructor.return_route.ts_cast() }};
{%- elif constructor.return_route.is_struct_return_slot() %}
      const __outPtr = _module.exports.boltffi_wasm_alloc({{ constructor.return_route.return_slot_size().unwrap() }});
      try {
        (_exports.{{ constructor.ffi_name }} as Function)({% if constructor.ffi_call_args().is_empty() %}__outPtr{% else %}__outPtr, {{ constructor.ffi_call_args() }}{% endif %});
        return {{ constructor.return_route.decode_expr() }};
      } finally {
        _module.exports.boltffi_wasm_free(__outPtr, {{ constructor.return_route.return_slot_size().unwrap() }});
      }
{%- elif constructor.return_route.is_void_slot() %}
      (_exports.{{ constructor.ffi_name }} as Function)({{ constructor.ffi_call_args() }});
      return {{ constructor.return_route.decode_expr() }};
{%- elif constructor.return_route.is_packed() %}
      const packed = (_exports.{{ constructor.ffi_name }} as Function)({{ constructor.ffi_call_args() }}) as bigint;
      const reader = _module.takePackedBuffer(packed);
      return {{ constructor.return_route.decode_expr() }};
{%- else %}
      const packed = (_exports.{{ constructor.ffi_name }} as Function)({{ constructor.ffi_call_args() }}) as bigint;
      return {{ constructor.return_route.decode_expr() }};
{%- endif %}
    } finally {
      {{ constructor.cleanup_code() }}
    }
{%- endif %}
  };
{%- endfor %}
{%- for method in methods %}

{{ crate::render::typescript::templates::ts_doc_block(method.doc, "  ") }}  export const {{ method.ts_name }} = {% if method.is_async() %}async {% endif %}({% for param in method.params %}{{ param.name }}: {{ param.ts_type }}{% if !loop.last %}, {% endif %}{% endfor %}): {% if method.is_async() %}Promise<{% match method.return_type %}{% when Some with (t) %}{{ t }}{% when None %}void{% endmatch %}>{% else %}{% match method.return_type %}{% when Some with (t) %}{{ t }}{% when None %}void{% endmatch %}{% endif %} => {
{%- if !method.wrapper_code().is_empty() %}
    {{ method.wrapper_code() }}
{%- endif %}
{%- if method.cleanup_code().is_empty() %}
{%- match method.mode %}
{%- when TsValueTypeMethodMode::Sync with (sync_method) %}
{%- if sync_method.return_route.is_void() %}
    (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }});
{%- elif sync_method.return_route.is_direct() %}
{%- if let Some(handle_return) = method.return_handle %}
    const result = (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }});
{%- if handle_return.nullable %}
    if (result === 0) {
      return null;
    }
{%- endif %}
    return {{ handle_return.class_name }}._fromHandle(result);
{%- elif let Some(callback_return) = method.return_callback %}
    const result = (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }});
{%- if callback_return.nullable %}
    if (result === 0) {
      return null;
    }
{%- endif %}
    return {{ callback_return.wrap_fn }}(result);
{%- else %}
    return (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }}){{ sync_method.return_route.ts_cast() }};
{%- endif %}
{%- elif sync_method.return_route.is_struct_return_slot() %}
    const __outPtr = _module.exports.boltffi_wasm_alloc({{ sync_method.return_route.return_slot_size().unwrap() }});
    try {
      (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args_with_out() }});
      return {{ sync_method.return_route.decode_expr() }};
    } finally {
      _module.exports.boltffi_wasm_free(__outPtr, {{ sync_method.return_route.return_slot_size().unwrap() }});
    }
{%- elif sync_method.return_route.is_void_slot() %}
    (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }});
    return {{ sync_method.return_route.decode_expr() }};
{%- elif sync_method.return_route.is_packed() %}
    const packed = (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }}) as bigint;
    const reader = _module.takePackedBuffer(packed);
    return {{ sync_method.return_route.decode_expr() }};
{%- else %}
    const packed = (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }}) as bigint;
    return {{ sync_method.return_route.decode_expr() }};
{%- endif %}
{%- when TsValueTypeMethodMode::Async with (async_method) %}
    const handle = (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }});
    const awaitedHandle = await _module.asyncManager.pollAsync(
      handle,
      (futureHandle: number) => (_exports.{{ async_method.poll_sync_ffi_name }} as Function)(futureHandle),
      (futureHandle: number) => (_exports.{{ async_method.panic_message_ffi_name }} as Function)(futureHandle),
      (futureHandle: number) => (_exports.{{ async_method.free_ffi_name }} as Function)(futureHandle)
    );
{%- if async_method.return_route.is_async_scalar() %}
    const result = (_exports.{{ async_method.complete_ffi_name }} as Function)(awaitedHandle){{ async_method.return_route.ts_cast() }};
    (_exports.{{ async_method.free_ffi_name }} as Function)(awaitedHandle);
{%- if let Some(handle_return) = method.return_handle %}
{%- if handle_return.nullable %}
    if (result === 0) {
      return null;
    }
{%- endif %}
    return {{ handle_return.class_name }}._fromHandle(result);
{%- elif let Some(callback_return) = method.return_callback %}
{%- if callback_return.nullable %}
    if (result === 0) {
      return null;
    }
{%- endif %}
    return {{ callback_return.wrap_fn }}(result);
{%- else %}
    return result;
{%- endif %}
{%- elif async_method.return_route.is_packed() %}
    const outPtr = _module.allocBufDescriptor();
    let completeCompleted = false;
    try {
      (_exports.{{ async_method.complete_ffi_name }} as Function)(outPtr, awaitedHandle, 0);
      completeCompleted = true;
      const reader = _module.readerFromBuf(outPtr);
      return {{ async_method.return_route.decode_expr() }};
    } finally {
      if (completeCompleted) {
        _module.freeBuf(outPtr);
      } else {
        _module.freeBufDescriptor(outPtr);
      }
      (_exports.{{ async_method.free_ffi_name }} as Function)(awaitedHandle);
    }
{%- elif async_method.return_route.is_void() %}
    (_exports.{{ async_method.free_ffi_name }} as Function)(awaitedHandle);
{%- elif async_method.return_route.is_direct() %}
    (_exports.{{ async_method.free_ffi_name }} as Function)(awaitedHandle);
    throw new Error("Unsupported async return route: Direct{{ async_method.return_route.ts_cast() }}");
{%- else %}
    (_exports.{{ async_method.free_ffi_name }} as Function)(awaitedHandle);
    throw new Error("Unsupported async return route: RawPacked {{ async_method.return_route.decode_expr() }}");
{%- endif %}
{%- endmatch %}
{%- else %}
{%- match method.mode %}
{%- when TsValueTypeMethodMode::Sync with (sync_method) %}
    try {
{%- if sync_method.return_route.is_void() %}
      (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }});
{%- elif sync_method.return_route.is_direct() %}
{%- if let Some(handle_return) = method.return_handle %}
      const result = (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }});
{%- if handle_return.nullable %}
      if (result === 0) {
        return null;
      }
{%- endif %}
      return {{ handle_return.class_name }}._fromHandle(result);
{%- elif let Some(callback_return) = method.return_callback %}
      const result = (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }});
{%- if callback_return.nullable %}
      if (result === 0) {
        return null;
      }
{%- endif %}
      return {{ callback_return.wrap_fn }}(result);
{%- else %}
      return (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }}){{ sync_method.return_route.ts_cast() }};
{%- endif %}
{%- elif sync_method.return_route.is_struct_return_slot() %}
      const __outPtr = _module.exports.boltffi_wasm_alloc({{ sync_method.return_route.return_slot_size().unwrap() }});
      try {
        (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args_with_out() }});
        return {{ sync_method.return_route.decode_expr() }};
      } finally {
        _module.exports.boltffi_wasm_free(__outPtr, {{ sync_method.return_route.return_slot_size().unwrap() }});
      }
{%- elif sync_method.return_route.is_void_slot() %}
      (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }});
      return {{ sync_method.return_route.decode_expr() }};
{%- elif sync_method.return_route.is_packed() %}
      const packed = (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }}) as bigint;
      const reader = _module.takePackedBuffer(packed);
      return {{ sync_method.return_route.decode_expr() }};
{%- else %}
      const packed = (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }}) as bigint;
      return {{ sync_method.return_route.decode_expr() }};
{%- endif %}
    } finally {
      {{ method.cleanup_code() }}
    }
{%- when TsValueTypeMethodMode::Async with (async_method) %}
    try {
      const handle = (_exports.{{ method.ffi_name }} as Function)({{ method.ffi_call_args() }});
      const awaitedHandle = await _module.asyncManager.pollAsync(
        handle,
        (futureHandle: number) => (_exports.{{ async_method.poll_sync_ffi_name }} as Function)(futureHandle),
        (futureHandle: number) => (_exports.{{ async_method.panic_message_ffi_name }} as Function)(futureHandle),
        (futureHandle: number) => (_exports.{{ async_method.free_ffi_name }} as Function)(futureHandle)
      );
{%- if async_method.return_route.is_async_scalar() %}
      const result = (_exports.{{ async_method.complete_ffi_name }} as Function)(awaitedHandle){{ async_method.return_route.ts_cast() }};
      (_exports.{{ async_method.free_ffi_name }} as Function)(awaitedHandle);
{%- if let Some(handle_return) = method.return_handle %}
{%- if handle_return.nullable %}
      if (result === 0) {
        return null;
      }
{%- endif %}
      return {{ handle_return.class_name }}._fromHandle(result);
{%- elif let Some(callback_return) = method.return_callback %}
{%- if callback_return.nullable %}
      if (result === 0) {
        return null;
      }
{%- endif %}
      return {{ callback_return.wrap_fn }}(result);
{%- else %}
      return result;
{%- endif %}
{%- elif async_method.return_route.is_packed() %}
      const outPtr = _module.allocBufDescriptor();
      let completeCompleted = false;
      try {
        (_exports.{{ async_method.complete_ffi_name }} as Function)(outPtr, awaitedHandle, 0);
        completeCompleted = true;
        const reader = _module.readerFromBuf(outPtr);
        return {{ async_method.return_route.decode_expr() }};
      } finally {
        if (completeCompleted) {
          _module.freeBuf(outPtr);
        } else {
          _module.freeBufDescriptor(outPtr);
        }
        (_exports.{{ async_method.free_ffi_name }} as Function)(awaitedHandle);
      }
{%- elif async_method.return_route.is_void() %}
      (_exports.{{ async_method.free_ffi_name }} as Function)(awaitedHandle);
{%- elif async_method.return_route.is_direct() %}
      (_exports.{{ async_method.free_ffi_name }} as Function)(awaitedHandle);
      throw new Error("Unsupported async return route: Direct{{ async_method.return_route.ts_cast() }}");
{%- else %}
      (_exports.{{ async_method.free_ffi_name }} as Function)(awaitedHandle);
      throw new Error("Unsupported async return route: RawPacked {{ async_method.return_route.decode_expr() }}");
{%- endif %}
    } finally {
      {{ method.cleanup_code() }}
    }
{%- endmatch %}
{%- endif %}
  };
{%- endfor %}
}
