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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- **All SDKs:** `OrderStatus` gains a `DelayedNotReported` variant (wire value `DelayedNotReported`) — "monitoring", the state a time-conditional order sits in before it is reported to the exchange. Previously this status deserialized to `OrderStatus::Unknown`, so time-conditional orders being monitored were indistinguishable from a genuinely unrecognized status in `today_orders` / `history_orders` / `order_detail` and the order-changed push. The variant is appended **after** `PartialWithdrawal` rather than inserted next to the other `*NotReported` values on purpose: the C/C++/Node.js enums use implicit discriminants, and inserting mid-list would renumber every following value (an ABI break for the C/C++ bindings, and a silent mismatch for TypeScript code that inlined the old `const enum` values)

## [5.0.0] - 2026-09-14

### Changed
Expand Down
4 changes: 4 additions & 0 deletions c/csrc/include/longbridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,10 @@ typedef enum lb_order_status_t {
* Partial Withdrawal
*/
OrderStatusPartialWithdrawal,
/**
* Monitoring (Time-Conditional Order)
*/
OrderStatusDelayedNotReported,
} lb_order_status_t;

/**
Expand Down
3 changes: 3 additions & 0 deletions c/src/trade_context/enum_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ pub enum COrderStatus {
/// Partial Withdrawal
#[c(remote = "PartialWithdrawal")]
OrderStatusPartialWithdrawal,
/// Monitoring (Time-Conditional Order)
#[c(remote = "DelayedNotReported")]
OrderStatusDelayedNotReported,
}

/// Order tag
Expand Down
2 changes: 2 additions & 0 deletions cpp/include/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1480,6 +1480,8 @@ enum class OrderStatus
Expired,
/// Partial Withdrawal
PartialWithdrawal,
/// Monitoring (Time-Conditional Order)
DelayedNotReported,
};

/// Order type
Expand Down
4 changes: 4 additions & 0 deletions cpp/src/convert.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,8 @@ convert(lb_order_status_t status)
return OrderStatus::Expired;
case OrderStatusPartialWithdrawal:
return OrderStatus::PartialWithdrawal;
case OrderStatusDelayedNotReported:
return OrderStatus::DelayedNotReported;
default:
throw std::invalid_argument("unreachable");
}
Expand Down Expand Up @@ -1096,6 +1098,8 @@ convert(OrderStatus status)
return OrderStatusExpired;
case OrderStatus::PartialWithdrawal:
return OrderStatusPartialWithdrawal;
case OrderStatus::DelayedNotReported:
return OrderStatusDelayedNotReported;
default:
throw std::invalid_argument("unreachable");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,6 @@ public enum OrderStatus {
Expired,
/** Partial withdrawal */
PartialWithdrawal,
/** Monitoring (time-conditional order) */
DelayedNotReported,
}
1 change: 1 addition & 0 deletions java/src/types/enum_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ impl_java_enum!(
Canceled,
Expired,
PartialWithdrawal,
DelayedNotReported,
]
);

Expand Down
4 changes: 3 additions & 1 deletion nodejs/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6227,7 +6227,9 @@ export declare const enum OrderStatus {
/** Expired */
Expired = 16,
/** Partial Withdrawal */
PartialWithdrawal = 17
PartialWithdrawal = 17,
/** Monitoring (Time-Conditional Order) */
DelayedNotReported = 18
}

/** Order tag */
Expand Down
186 changes: 155 additions & 31 deletions nodejs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// @ts-nocheck
/* auto-generated by NAPI-RS */

const { readFileSync } = require('node:fs')
const { readFileSync } = require('fs')
let nativeBinding = null
const loadErrors = []

Expand Down Expand Up @@ -33,7 +33,7 @@ const isMuslFromFilesystem = () => {

const isMuslFromReport = () => {
let report = null
if (typeof process.report?.getReport === 'function') {
if (process.report && typeof process.report.getReport === 'function') {
process.report.excludeNetwork = true
report = process.report.getReport()
}
Expand Down Expand Up @@ -105,7 +105,7 @@ function requireNative() {
}
} else if (process.platform === 'win32') {
if (process.arch === 'x64') {
if (process.config?.variables?.shlib_suffix === 'dll.a' || process.config?.variables?.node_target_type === 'shared_library') {
if ((process.config && process.config.variables && process.config.variables.shlib_suffix === 'dll.a') || (process.config && process.config.variables && process.config.variables.node_target_type === 'shared_library')) {
try {
return require('./longbridge.win32-x64-gnu.node')
} catch (e) {
Expand Down Expand Up @@ -523,54 +523,178 @@ function requireNative() {
}
}

nativeBinding = requireNative()
function createLoadErrorChain(errors) {
return errors.reduce((previous, current) => {
let message
try {
message =
current && typeof current.message === 'string'
? current.message
: String(current)
} catch {
message = 'Unknown error'
}
const error = new Error(message)
error.cause = previous
return error
}, null)
}

// NAPI_RS_FORCE_WASI is a tri-state flag:
// unset / any other value → native binding preferred, WASI is only a fallback
// 'true' → prefer WASI, but retain native as a lazy fallback
// 'error' → require WASI without initializing a native fallback
// Treating any non-empty string as truthy (the historical behavior) meant
// NAPI_RS_FORCE_WASI=false, NAPI_RS_FORCE_WASI=0, etc. inadvertently triggered
// the WASI path, causing ENOENT for packages shipped without a .wasi.cjs file.
//
// NAPI_RS_WASI_FLAVOR selects one exact generated flavor and implies strict
// WASI loading. It never crosses into another flavor or falls back to native.
const __napiWasiFlavors = ["wasm32-wasi"]
const __napiWasiFlavor = process.env.NAPI_RS_WASI_FLAVOR
const __napiWasiFlavorRequested =
typeof __napiWasiFlavor === 'string' && __napiWasiFlavor.length > 0
if (
__napiWasiFlavorRequested &&
__napiWasiFlavors.indexOf(__napiWasiFlavor) === -1
) {
throw new Error(
'Unsupported WASI flavor "' +
__napiWasiFlavor +
'". Available flavors: ' +
__napiWasiFlavors.join(', '),
)
}
const forceWasiError = process.env.NAPI_RS_FORCE_WASI === 'error'
const forceWasi =
process.env.NAPI_RS_FORCE_WASI === 'true' ||
forceWasiError ||
__napiWasiFlavorRequested

if (!forceWasi) {
nativeBinding = requireNative()
}

if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) {
if (!nativeBinding || forceWasi) {
let wasiBinding = null
let wasiBindingError = null
try {
wasiBinding = require('./longbridge.wasi.cjs')
nativeBinding = wasiBinding
} catch (err) {
if (process.env.NAPI_RS_FORCE_WASI) {
wasiBindingError = err
let wasiBindingLoaded = false
const wasiBindingErrors = []
const __napiWasiResolveCandidate = (specifier, isPackage, localArtifacts) => {
try {
require.resolve(specifier)
} catch (resolveError) {
if (!resolveError || resolveError.code !== 'MODULE_NOT_FOUND') {
throw resolveError
}
if (isPackage) {
try {
require.resolve(specifier + '/package.json')
} catch (packageError) {
if (packageError && packageError.code === 'MODULE_NOT_FOUND') {
return resolveError
}
// An exports restriction proves the package exists even when its
// package.json is not public. Preserve the root resolution failure.
throw resolveError
}
// The package exists but its main/export target is broken.
throw resolveError
}
return resolveError
}
if (localArtifacts) {
let artifactError = null
for (let i = 0; i < localArtifacts.length; i++) {
try {
require.resolve(localArtifacts[i])
return null
} catch (resolveError) {
if (!resolveError || resolveError.code !== 'MODULE_NOT_FOUND') {
throw resolveError
}
artifactError = resolveError
}
}
return artifactError
}
return null
}
if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) {
if (!wasiBindingLoaded && (!__napiWasiFlavorRequested || __napiWasiFlavor === "wasm32-wasi")) {
let candidateError = null
let candidateFailed = false
try {
wasiBinding = require('longbridge-wasm32-wasi')
nativeBinding = wasiBinding
candidateError = __napiWasiResolveCandidate('./longbridge.wasi.cjs', false, ["./longbridge.wasm32-wasi.debug.wasm","./longbridge.wasm32-wasi.wasm"])
candidateFailed = candidateError !== null
if (!candidateFailed) {
wasiBinding = require('./longbridge.wasi.cjs')
nativeBinding = wasiBinding
wasiBindingLoaded = true
}
} catch (err) {
if (process.env.NAPI_RS_FORCE_WASI) {
if (!wasiBindingError) {
wasiBindingError = err
} else {
wasiBindingError.cause = err
candidateError = err
candidateFailed = true
}
if (candidateFailed) {
wasiBindingErrors.push(candidateError)
loadErrors.push(candidateError)
}
}
if (!wasiBindingLoaded && (!__napiWasiFlavorRequested || __napiWasiFlavor === "wasm32-wasi")) {
let candidateError = null
let candidateFailed = false
try {
candidateError = __napiWasiResolveCandidate('longbridge-wasm32-wasi', true, undefined)
candidateFailed = candidateError !== null
if (!candidateFailed) {
if (process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
const bindingPackageVersion = require('longbridge-wasm32-wasi/package.json').version
if (bindingPackageVersion !== '0.0.0') {
throw new Error(`WASI binding package version mismatch, expected 0.0.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
}
loadErrors.push(err)
wasiBinding = require('longbridge-wasm32-wasi')
nativeBinding = wasiBinding
wasiBindingLoaded = true
}
} catch (err) {
candidateError = err
candidateFailed = true
}
if (candidateFailed) {
wasiBindingErrors.push(candidateError)
loadErrors.push(candidateError)
}
}
if (process.env.NAPI_RS_FORCE_WASI === 'error' && !wasiBinding) {
const error = new Error('WASI binding not found and NAPI_RS_FORCE_WASI is set to error')
error.cause = wasiBindingError
if (
!wasiBindingLoaded &&
forceWasi &&
!forceWasiError &&
!__napiWasiFlavorRequested
) {
nativeBinding = requireNative()
}
if ((forceWasiError || __napiWasiFlavorRequested) && !wasiBindingLoaded) {
const error = new Error(
__napiWasiFlavorRequested
? 'WASI binding for flavor "' + __napiWasiFlavor + '" not found'
: 'WASI binding not found and NAPI_RS_FORCE_WASI is set to error',
)
error.cause = createLoadErrorChain(wasiBindingErrors)
throw error
}
}

if (!nativeBinding) {
if (loadErrors.length > 0) {
throw new Error(
const error = new Error(
`Cannot find native binding. ` +
`npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). ` +
'Please try `npm i` again after removing both package-lock.json and node_modules directory.',
{
cause: loadErrors.reduce((err, cur) => {
cur.cause = err
return cur
}),
},
)
// assign instead of the `new Error(message, { cause })` options form,
// which Node < 16.9 silently ignores
error.cause = createLoadErrorChain(loadErrors)
throw error
}
throw new Error(`Failed to load native binding`)
}
Expand Down
2 changes: 2 additions & 0 deletions nodejs/src/trade/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ pub enum OrderStatus {
Expired,
/// Partial Withdrawal
PartialWithdrawal,
/// Monitoring (Time-Conditional Order)
DelayedNotReported,
}

#[napi_derive::napi]
Expand Down
5 changes: 5 additions & 0 deletions python/pysrc/longbridge/openapi.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -5704,6 +5704,11 @@ class OrderStatus:
PartialWithdrawal
"""

class DelayedNotReported(OrderStatus):
"""
Monitoring (Time-Conditional Order)
"""

class OrderTag:
"""
Order tag
Expand Down
2 changes: 2 additions & 0 deletions python/src/trade/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ pub(crate) enum OrderStatus {
Expired,
/// Partial Withdrawal
PartialWithdrawal,
/// Monitoring (Time-Conditional Order)
DelayedNotReported,
}

#[pyclass(eq, eq_int, from_py_object)]
Expand Down
3 changes: 3 additions & 0 deletions rust/src/trade/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ pub enum OrderStatus {
/// Partial Withdrawal
#[strum(serialize = "PartialWithdrawal")]
PartialWithdrawal,
/// Monitoring (Time-Conditional Order)
#[strum(serialize = "DelayedNotReported")]
DelayedNotReported,
}

/// Execution
Expand Down
Loading