ronantakizawa/codereview-bench huggingface dataset:
Repository: n8n-io/n8n
File: packages/cli/src/executions/execution.service.ts (TypeScript)

Code before:
		}

		return execution;
	}

	async getLastSuccessfulExecution(workflowId: string): Promise<IExecutionResponse | undefined> {
		const executions = await this.executionRepository.findMultipleExecutions(
			{
				select: ['id', 'mode', 'startedAt', 'stoppedAt', 'workflowId'],
				where: {
					workflowId,
					status: 'success',
				},
				order: { id: 'DESC' },
				take: 1,
			},
			{
				includeData: true,
				unflattenData: true,
			},
		);

		return executions[0];
	}

	async retry(
		req: ExecutionRequest.Retry,
		sharedWorkflowIds: string[],
	): Promise<Omit<IExecutionResponse, 'createdAt'>> {
		const { id: executionId } = req.params;
		const execution = await this.executionRepository.findWithUnflattenedData(
			executionId,
			sharedWorkflowIds,
		);

		if (!execution) {
			this.logger.info(
				'Attempt to retry an execution was blocked due to insufficient permissions',
				{
					userId: req.user.id,
					executionId,
				},
			);
			throw new NotFoundError(`The execution with the ID "${executionId}" does not exist.`);
		}

		if (execution.status === 'new') throw new QueuedExecutionRetryError();

		if (!execution.data.executionData) throw new AbortedExecutionRetryError();

		if (execution.finished) {

Review comment (suggestion):
I thought we would try and do the redaction inside the flattening / stringifying process to prevent full parsing / redacting / stringifying. But maybe that was before we decided to redact the full output and not field values

Code after:

		if (!execution) {
			this.logger.info('Attempt to read execution was blocked due to insufficient permissions', {
				userId: req.user.id,
				executionId,
			});
			return undefined;
		}

		let redactExecutionData: boolean | undefined;
		const redactQuery = ExecutionRedactionQueryDtoSchema.safeParse(req.query);
		if (redactQuery.success) {
			redactExecutionData = redactQuery.data.redactExecutionData;
		}

		const processedExecution = await this.executionRedactionServiceProxy.processExecution(
			execution,
			{
				user: req.user,
				redactExecutionData,
			},
		);

		return {
			...execution,
			data: stringify(processedExecution.data),
		};
	}

	async getLastSuccessfulExecution(workflowId: string): Promise<IExecutionResponse | undefined> {
		const executions = await this.executionRepository.findMultipleExecutions(
			{
				select: ['id', 'mode', 'startedAt', 'stoppedAt', 'workflowId'],
				where: {
					workflowId,
					status: 'success',
				},
				order: { id: 'DESC' },
				take: 1,
			},
			{
				includeData: true,
				unflattenData: true,
			},
		);

		return executions[0];
	}

	async retry(
		req: ExecutionRequest.Retry,
Repository: napi-rs/napi-rs
File: cli/src/api/templates/js-binding.ts (TypeScript)

Code before:
const isMusl = () => {
  let musl = false
  if (process.platform === 'linux') {
    musl = isMuslFromFilesystem()
    if (musl === null) {
      musl = isMuslFromReport()
    }
    if (musl === null) {
      musl = isMuslFromChildProcess()
    }
  }
  return musl
}

const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-')

const isMuslFromFilesystem = () => {
  try {
    return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl')
  } catch {
    return null
  }
}

const isMuslFromReport = () => {
  const report = typeof process.report?.getReport === 'function' ? (process.report.excludeNetwork = true, process.report.getReport()) : null
  if (!report) {
    return null
  }
  if (report.header && report.header.glibcVersionRuntime) {
    return false
  }
  if (Array.isArray(report.sharedObjects)) {
    if (report.sharedObjects.some(isFileMusl)) {
      return true
    }
  }
  return false
}

const isMuslFromChildProcess = () => {
  try {
    return require('child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl')
  } catch (e) {
    // If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false
    return false
  }
}

function requireNative() {
  if (process.env.NAPI_RS_NATIVE_LIBRARY_PATH) {

Review comment (suggestion):
[nitpick] Inline assignment using the comma operator might obscure intent and could lead to maintenance challenges. Consider separating the assignment of process.report.excludeNetwork from the report retrieval for improved readability.
```suggestion
  let report = null;
  if (typeof process.report?.getReport === 'function') {
    process.report.excludeNetwork = true;
    report = process.report.getReport();
  }
```

Code after:
const isMusl = () => {
  let musl = false
  if (process.platform === 'linux') {
    musl = isMuslFromFilesystem()
    if (musl === null) {
      musl = isMuslFromReport()
    }
    if (musl === null) {
      musl = isMuslFromChildProcess()
    }
  }
  return musl
}

const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-')

const isMuslFromFilesystem = () => {
  try {
    return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl')
  } catch {
    return null
  }
}

const isMuslFromReport = () => {
  let report = null
  if (typeof process.report?.getReport === 'function') {
    process.report.excludeNetwork = true
    report = process.report.getReport()
  }
  if (!report) {
    return null
  }
  if (report.header && report.header.glibcVersionRuntime) {
    return false
  }
  if (Array.isArray(report.sharedObjects)) {
    if (report.sharedObjects.some(isFileMusl)) {
      return true
    }
  }
  return false
}

const isMuslFromChildProcess = () => {
  try {
    return require('child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl')
  } catch (e) {
    // If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false
    return false
  }
Repository: napi-rs/napi-rs
File: crates/napi/src/tokio_runtime.rs (Rust)

Code before:
#[cfg(not(feature = "noop"))]
use std::sync::{LazyLock, OnceLock, RwLock};
use std::{future::Future, marker::PhantomData};

use tokio::runtime::Runtime;

use crate::{bindgen_runtime::ToNapiValue, sys, Env, Error, Result};
#[cfg(not(feature = "noop"))]
use crate::{JsDeferred, Unknown};

#[cfg(not(feature = "noop"))]
fn create_runtime() -> Runtime {
  // Check if we're supposed to use a user-defined runtime
  if matches!(IS_USER_DEFINED_RT.get(), Some(true)) {
    // Try to take the user-defined runtime if it's still available
    if let Some(user_defined_rt) = USER_DEFINED_RT
      .get()
      .and_then(|rt| rt.write().ok().and_then(|mut rt| rt.take()))
    {
      return user_defined_rt;
    }
    // If the user-defined runtime was already taken, fall back to creating a default runtime
    // This handles the case where the runtime was shutdown and needs to be restarted
  }

  #[cfg(any(
    all(target_family = "wasm", tokio_unstable),
    not(target_family = "wasm")
  ))]
  {
    tokio::runtime::Builder::new_multi_thread()
      .enable_all()
      .build()
      .expect("Create tokio runtime failed")
  }
  #[cfg(all(target_family = "wasm", not(tokio_unstable)))]
  {
    tokio::runtime::Builder::new_current_thread()
      .enable_all()

Review comment (suggestion):
The logic is inverted. This condition will execute the user-defined runtime path even when no user-defined runtime was set. The check should be `if IS_USER_DEFINED_RT.get().unwrap_or(false)` or handle the `None` case explicitly.
```suggestion
  if IS_USER_DEFINED_RT.get().unwrap_or(false) {
```

Code after:
#[cfg(not(feature = "noop"))]
use std::sync::{LazyLock, OnceLock, RwLock};
use std::{future::Future, marker::PhantomData};

use tokio::runtime::Runtime;

use crate::{bindgen_runtime::ToNapiValue, sys, Env, Error, Result};
#[cfg(not(feature = "noop"))]
use crate::{JsDeferred, Unknown};

#[cfg(not(feature = "noop"))]
fn create_runtime() -> Runtime {
  // Check if we're supposed to use a user-defined runtime
  if IS_USER_DEFINED_RT.get().copied().unwrap_or(false) {
    // Try to take the user-defined runtime if it's still available
    if let Some(user_defined_rt) = USER_DEFINED_RT
      .get()
      .and_then(|rt| rt.write().ok().and_then(|mut rt| rt.take()))
    {
      return user_defined_rt;
    }
    // If the user-defined runtime was already taken, fall back to creating a default runtime
    // This handles the case where the runtime was shutdown and needs to be restarted
  }

  #[cfg(any(
    all(target_family = "wasm", tokio_unstable),
    not(target_family = "wasm")
  ))]
  {
    tokio::runtime::Builder::new_multi_thread()
      .enable_all()
      .build()
      .expect("Create tokio runtime failed")
  }
  #[cfg(all(target_family = "wasm", not(tokio_unstable)))]
  {
    tokio::runtime::Builder::new_current_thread()
      .enable_all()
Repository: napi-rs/napi-rs
File: cli/src/utils/target.ts (TypeScript)

Code before:
  'x86_64-unknown-freebsd',
  'i686-pc-windows-msvc',
  'armv7-unknown-linux-gnueabihf',
  'armv7-unknown-linux-musleabihf',
  'armv7-linux-androideabi',
  'universal-apple-darwin',
  'loongarch64-unknown-linux-gnu',
  'riscv64gc-unknown-linux-gnu',
  'powerpc64le-unknown-linux-gnu',
  's390x-unknown-linux-gnu',
  'wasm32-wasi-preview1-threads',
  'wasm32-wasip1-threads',
] as const

export type TargetTriple = (typeof AVAILABLE_TARGETS)[number]

export const DEFAULT_TARGETS = [
  'x86_64-apple-darwin',
  'aarch64-apple-darwin',
  'x86_64-pc-windows-msvc',
  'x86_64-unknown-linux-gnu',
] as const

export const TARGET_LINKER: Record<string, string> = {
  'aarch64-unknown-linux-musl': 'aarch64-linux-musl-gcc',
  // TODO: Switch to loongarch64-linux-gnu-gcc when avaliable
  'loongarch64-unknown-linux-gnu': 'loongarch64-linux-gnu-gcc-13',
  'riscv64gc-unknown-linux-gnu': 'riscv64-linux-gnu-gcc',
  'powerpc64le-unknown-linux-gnu': 'powerpc64le-linux-gnu-gcc',
  's390x-unknown-linux-gnu': 's390x-linux-gnu-gcc',
}

// https://nodejs.org/api/process.html#process_process_arch
type NodeJSArch =
  | 'arm'
  | 'arm64'
  | 'ia32'
  | 'loong64'
  | 'mips'
  | 'mipsel'
  | 'ppc'
  | 'ppc64'
  | 'riscv64'
  | 's390'
  | 's390x'
  | 'x32'
  | 'x64'
  | 'universal'
  | 'wasm32'

const CpuToNodeArch: Record<string, NodeJSArch> = {

Review comment (suggestion):
There's a spelling error in 'avaliable'. It should be 'available'.
```suggestion
  // TODO: Switch to loongarch64-linux-gnu-gcc when available
```

Code after:
  'x86_64-unknown-freebsd',
  'i686-pc-windows-msvc',
  'armv7-unknown-linux-gnueabihf',
  'armv7-unknown-linux-musleabihf',
  'armv7-linux-androideabi',
  'universal-apple-darwin',
  'loongarch64-unknown-linux-gnu',
  'riscv64gc-unknown-linux-gnu',
  'powerpc64le-unknown-linux-gnu',
  's390x-unknown-linux-gnu',
  'wasm32-wasi-preview1-threads',
  'wasm32-wasip1-threads',
] as const

export type TargetTriple = (typeof AVAILABLE_TARGETS)[number]

export const DEFAULT_TARGETS = [
  'x86_64-apple-darwin',
  'aarch64-apple-darwin',
  'x86_64-pc-windows-msvc',
  'x86_64-unknown-linux-gnu',
] as const

export const TARGET_LINKER: Record<string, string> = {
  'aarch64-unknown-linux-musl': 'aarch64-linux-musl-gcc',
  // TODO: Switch to loongarch64-linux-gnu-gcc when available
  'loongarch64-unknown-linux-gnu': 'loongarch64-linux-gnu-gcc-13',
  'riscv64gc-unknown-linux-gnu': 'riscv64-linux-gnu-gcc',
  'powerpc64le-unknown-linux-gnu': 'powerpc64le-linux-gnu-gcc',
  's390x-unknown-linux-gnu': 's390x-linux-gnu-gcc',
}

// https://nodejs.org/api/process.html#process_process_arch
type NodeJSArch =
  | 'arm'
  | 'arm64'
  | 'ia32'
  | 'loong64'
  | 'mips'
  | 'mipsel'
  | 'ppc'
  | 'ppc64'
  | 'riscv64'
  | 's390'
  | 's390x'
  | 'x32'
  | 'x64'
  | 'universal'
  | 'wasm32'

const CpuToNodeArch: Record<string, NodeJSArch> = {
Repository: napi-rs/napi-rs
File: examples/napi/src/task.rs (Rust)

Code before:
use std::{sync::mpsc, thread::sleep};

use napi::{bindgen_prelude::*, ScopedTask};

pub struct SimpleTask {
  receiver: mpsc::Receiver<i32>,
}

#[napi]
impl napi::Task for SimpleTask {
  type Output = i32;
  type JsValue = i32;

  fn compute(&mut self) -> Result<Self::Output> {
    Ok(self.receiver.recv().unwrap())
  }

  fn resolve(&mut self, _env: napi::Env, output: Self::Output) -> Result<Self::JsValue> {
    Ok(output)
  }

  fn finally(self, _env: napi::Env) -> Result<()> {
    Ok(())
  }
}

pub struct DelaySum(u32, u32);

#[napi]
impl napi::Task for DelaySum {
  type Output = u32;
  type JsValue = u32;

  fn compute(&mut self) -> Result<Self::Output> {
    sleep(std::time::Duration::from_millis(100));
    Ok(self.0 + self.1)
  }

  fn resolve(&mut self, _env: napi::Env, output: Self::Output) -> Result<Self::JsValue> {
    Ok(output)

Review comment (bug):
Using `unwrap()` on `recv()` will panic if the channel is disconnected or if there's an error. This could cause the task to crash unexpectedly. Consider using proper error handling with `map_err()` or matching on the result.
```suggestion
    self.receiver.recv().map_err(|e| {
      Error::new(Status::GenericFailure, format!("Channel receive error: {}", e))
    })
```

Code after:
use std::{sync::mpsc, thread::sleep};

use napi::{bindgen_prelude::*, ScopedTask};

pub struct SimpleTask {
  receiver: mpsc::Receiver<i32>,
}

#[napi]
impl napi::Task for SimpleTask {
  type Output = i32;
  type JsValue = i32;

  fn compute(&mut self) -> Result<Self::Output> {
    self.receiver.recv().map_err(|e| {
      Error::new(
        Status::GenericFailure,
        format!("Channel receive error: {}", e),
      )
    })
  }

  fn resolve(&mut self, _env: napi::Env, output: Self::Output) -> Result<Self::JsValue> {
    Ok(output)
  }

  fn finally(self, _env: napi::Env) -> Result<()> {
    Ok(())
  }
}

pub struct DelaySum(u32, u32);

#[napi]
impl napi::Task for DelaySum {
  type Output = u32;
  type JsValue = u32;

  fn compute(&mut self) -> Result<Self::Output> {
    sleep(std::time::Duration::from_millis(100));
Repository: napi-rs/napi-rs
File: examples/napi/src/task.rs (Rust)

Code before:
  }

  fn finally(self, _env: Env) -> Result<()> {
    Ok(())
  }
}

#[napi]
pub fn without_abort_controller(a: u32, b: u32) -> AsyncTask<DelaySum> {
  AsyncTask::new(DelaySum(a, b))
}

#[napi]
pub fn with_abort_controller(a: u32, b: u32, signal: AbortSignal) -> AsyncTask<DelaySum> {
  AsyncTask::with_signal(DelaySum(a, b), signal)
}

#[napi]
fn with_abort_signal_handle(signal: AbortSignal) -> AsyncTask<SimpleTask> {
  let (sender, receiver) = mpsc::channel::<i32>();
  signal.on_abort(move || sender.send(999).unwrap());
  AsyncTask::with_signal(SimpleTask { receiver }, signal)
}

struct AsyncTaskVoidReturn {}

#[napi]
impl Task for AsyncTaskVoidReturn {
  type JsValue = ();
  type Output = ();

  fn compute(&mut self) -> Result<Self::Output> {
    Ok(())
  }

  fn resolve(&mut self, _env: Env, output: Self::Output) -> Result<Self::JsValue> {
    Ok(output)
  }
}

#[napi]
fn async_task_void_return() -> AsyncTask<AsyncTaskVoidReturn> {
  AsyncTask::new(AsyncTaskVoidReturn {})
}

pub struct AsyncTaskOptionalReturn {}

#[napi]
impl Task for AsyncTaskOptionalReturn {
  type JsValue = Option<u32>;
  type Output = ();

Review comment (suggestion):
Using `unwrap()` on `send()` will panic if the receiver has been dropped. Consider using `let _ = sender.send(999);` to ignore the error or handle it gracefully.
```suggestion
  signal.on_abort(move || { let _ = sender.send(999); });
```

Code after:
    Ok(self.0 + self.1)
  }

  fn resolve(&mut self, _env: napi::Env, output: Self::Output) -> Result<Self::JsValue> {
    Ok(output)
  }

  fn finally(self, _env: Env) -> Result<()> {
    Ok(())
  }
}

#[napi]
pub fn without_abort_controller(a: u32, b: u32) -> AsyncTask<DelaySum> {
  AsyncTask::new(DelaySum(a, b))
}

#[napi]
pub fn with_abort_controller(a: u32, b: u32, signal: AbortSignal) -> AsyncTask<DelaySum> {
  AsyncTask::with_signal(DelaySum(a, b), signal)
}

#[napi]
fn with_abort_signal_handle(signal: AbortSignal) -> AsyncTask<SimpleTask> {
  let (sender, receiver) = mpsc::channel::<i32>();
  signal.on_abort(move || sender.send(999).unwrap());
  AsyncTask::with_signal(SimpleTask { receiver }, signal)
}

struct AsyncTaskVoidReturn {}

#[napi]
impl Task for AsyncTaskVoidReturn {
  type JsValue = ();
  type Output = ();

  fn compute(&mut self) -> Result<Self::Output> {
    Ok(())
  }

  fn resolve(&mut self, _env: Env, output: Self::Output) -> Result<Self::JsValue> {
    Ok(output)
  }
}

#[napi]
fn async_task_void_return() -> AsyncTask<AsyncTaskVoidReturn> {
  AsyncTask::new(AsyncTaskVoidReturn {})
}

pub struct AsyncTaskOptionalReturn {}
Repository: napi-rs/napi-rs
File: crates/napi/src/error.rs (Rust)

Code before:
  fn from(error: std::io::Error) -> Self {
    Error {
      status: Status::GenericFailure,
      reason: format!("{error}"),
      cause: None,
      maybe_raw: ptr::null_mut(),
      maybe_env: ptr::null_mut(),
    }
  }
}

#[derive(Clone, Debug)]
pub struct ExtendedErrorInfo {
  pub message: String,
  pub engine_reserved: *mut c_void,
  pub engine_error_code: u32,
  pub error_code: Status,
}

impl TryFrom<sys::napi_extended_error_info> for ExtendedErrorInfo {
  type Error = Error;

  fn try_from(value: sys::napi_extended_error_info) -> Result<Self> {
    Ok(Self {
      message: unsafe {
        CStr::from_ptr(value.error_message as *mut c_char)
          .to_str()
          .map_err(|e| Error::new(Status::GenericFailure, format!("{e}")))?
          .to_owned()
      },
      engine_error_code: value.engine_error_code,
      engine_reserved: value.engine_reserved,
      error_code: Status::from(value.error_code),
    })
  }
}

pub struct JsError<S: AsRef<str> = Status>(Error<S>);

#[cfg(feature = "anyhow")]
impl From<anyhow::Error> for JsError {
  fn from(value: anyhow::Error) -> Self {
    JsError(Error::new(Status::GenericFailure, value.to_string()))
  }
}

pub struct JsTypeError<S: AsRef<str> = Status>(Error<S>);

pub struct JsRangeError<S: AsRef<str> = Status>(Error<S>);

#[cfg(feature = "napi9")]

Review comment (suggestion):
The cast from `*mut c_char` to `*const c_char` (expected by `CStr::from_ptr`) could be unsafe if the pointer is used for mutation elsewhere. Consider using `as *const c_char` explicitly to make the intent clear.
```suggestion
        CStr::from_ptr(value.error_message as *const c_char)
```

Code after:
  fn from(error: std::io::Error) -> Self {
    Error {
      status: Status::GenericFailure,
      reason: format!("{error}"),
      cause: None,
      maybe_raw: ptr::null_mut(),
      maybe_env: ptr::null_mut(),
    }
  }
}

#[derive(Clone, Debug)]
pub struct ExtendedErrorInfo {
  pub message: String,
  pub engine_reserved: *mut c_void,
  pub engine_error_code: u32,
  pub error_code: Status,
}

impl TryFrom<sys::napi_extended_error_info> for ExtendedErrorInfo {
  type Error = Error;

  fn try_from(value: sys::napi_extended_error_info) -> Result<Self> {
    Ok(Self {
      message: unsafe {
        CStr::from_ptr(value.error_message.cast())
          .to_str()
          .map_err(|e| Error::new(Status::GenericFailure, format!("{e}")))?
          .to_owned()
      },
      engine_error_code: value.engine_error_code,
      engine_reserved: value.engine_reserved,
      error_code: Status::from(value.error_code),
    })
  }
}

pub struct JsError<S: AsRef<str> = Status>(Error<S>);

#[cfg(feature = "anyhow")]
impl From<anyhow::Error> for JsError {
  fn from(value: anyhow::Error) -> Self {
    JsError(Error::new(Status::GenericFailure, value.to_string()))
  }
}

pub struct JsTypeError<S: AsRef<str> = Status>(Error<S>);

pub struct JsRangeError<S: AsRef<str> = Status>(Error<S>);

#[cfg(feature = "napi9")]
Repository: napi-rs/napi-rs
File: crates/napi/src/lib.rs (Rust)

Code before:
#[cfg(feature = "napi8")]
mod async_cleanup_hook;
#[cfg(feature = "napi8")]
pub use async_cleanup_hook::AsyncCleanupHook;
mod async_work;
mod bindgen_runtime;
#[cfg(feature = "compat-mode")]
mod call_context;
#[cfg(feature = "napi3")]
mod cleanup_env;
mod env;
mod error;
mod js_values;
mod status;
mod task;
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
mod tokio_runtime;
mod value_type;
#[cfg(feature = "napi3")]
pub use cleanup_env::CleanupEnvHook;
#[cfg(feature = "napi4")]
pub mod threadsafe_function;

mod version;

pub use napi_sys as sys;

pub use async_work::AsyncWorkPromise;
#[cfg(feature = "compat-mode")]
pub use call_context::CallContext;

pub use bindgen_runtime::iterator;
pub use env::*;
pub use error::*;
pub use js_values::*;
pub use status::Status;
pub use task::{ScopedTask, Task};
pub use value_type::*;
pub use version::NodeVersion;
#[cfg(feature = "serde-json")]
#[macro_use]
extern crate serde;

pub type ContextlessResult<T> = Result<Option<T>>;

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! type_of {
  ($env:expr, $value:expr) => {{
    let mut value_type = 0;
    #[allow(unused_unsafe)]

Review comment (suggestion):
The module declarations (mod) and public re-exports (pub use) are interleaved inconsistently. Following Rust conventions, all module declarations should be grouped together before public re-exports. Move lines 98-99 up to group with other mod declarations (around line 94-95), and move lines 102-103 down to group with other pub use statements (around line 109-120).

Code after:
#[cfg(feature = "napi8")]
mod async_cleanup_hook;
#[cfg(feature = "napi8")]
pub use async_cleanup_hook::AsyncCleanupHook;
mod async_work;
mod bindgen_runtime;
#[cfg(feature = "compat-mode")]
mod call_context;
#[cfg(feature = "napi3")]
mod cleanup_env;
mod env;
mod error;
mod js_values;
mod status;
mod task;
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
mod tokio_runtime;
mod value_type;
#[cfg(feature = "napi3")]
pub use cleanup_env::CleanupEnvHook;
#[cfg(not(feature = "noop"))]
mod sendable_resolver;
#[cfg(feature = "napi4")]
pub mod threadsafe_function;
#[cfg(not(feature = "noop"))]
pub use sendable_resolver::SendableResolver;

mod version;

pub use napi_sys as sys;

pub use async_work::AsyncWorkPromise;
#[cfg(feature = "compat-mode")]
pub use call_context::CallContext;

pub use bindgen_runtime::iterator;
pub use env::*;
pub use error::*;
pub use js_values::*;
pub use status::Status;
pub use task::{ScopedTask, Task};
pub use value_type::*;
pub use version::NodeVersion;
#[cfg(feature = "serde-json")]
#[macro_use]
extern crate serde;

pub type ContextlessResult<T> = Result<Option<T>>;

#[doc(hidden)]
#[macro_export(local_inner_macros)]