dspx 1.3.2 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dspx",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "description": "High-performance DSP library with native C++ acceleration and Redis state persistence",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
Binary file
Binary file
@@ -84,9 +84,13 @@ namespace dsp
84
84
  DspPipeline::DspPipeline(const Napi::CallbackInfo &info)
85
85
  : Napi::ObjectWrap<DspPipeline>(info)
86
86
  {
87
+ // std::cout << "[DEBUG] DspPipeline::Constructor - this=" << this
88
+ // << ", creating pipeline" << std::endl;
87
89
  // Initialize the lock
88
90
  m_isBusy = std::make_shared<std::atomic<bool>>(false);
91
+ // std::cout << "[DEBUG] DspPipeline::Constructor - m_isBusy=" << m_isBusy.get() << std::endl;
89
92
  InitializeStageFactories();
93
+ // std::cout << "[DEBUG] DspPipeline::Constructor - complete, this=" << this << std::endl;
90
94
  }
91
95
 
92
96
  /**
@@ -1146,22 +1150,26 @@ namespace dsp
1146
1150
  Napi::Value DspPipeline::AddStage(const Napi::CallbackInfo &info)
1147
1151
  {
1148
1152
  Napi::Env env = info.Env();
1153
+ // std::cout << "[DEBUG] DspPipeline::AddStage - this=" << this << std::endl;
1149
1154
 
1150
1155
  // Check if pipeline is disposed
1151
1156
  if (m_disposed)
1152
1157
  {
1158
+ // std::cout << "[DEBUG] AddStage - pipeline disposed, this=" << this << std::endl;
1153
1159
  Napi::Error::New(env, "Pipeline is disposed").ThrowAsJavaScriptException();
1154
1160
  return env.Undefined();
1155
1161
  }
1156
1162
 
1157
1163
  if (*m_isBusy)
1158
1164
  {
1165
+ // std::cout << "[DEBUG] AddStage - pipeline busy, this=" << this << std::endl;
1159
1166
  Napi::Error::New(env, "Cannot add stage while processing").ThrowAsJavaScriptException();
1160
1167
  return env.Undefined();
1161
1168
  }
1162
1169
 
1163
1170
  // 1. Get arguments from TypeScript
1164
1171
  std::string stageName = info[0].As<Napi::String>();
1172
+ // std::cout << "[DEBUG] AddStage - stageName=" << stageName << ", this=" << this << std::endl;
1165
1173
  Napi::Object params = info[1].As<Napi::Object>();
1166
1174
 
1167
1175
  // 2. Look up the stage factory in the map
@@ -1202,10 +1210,12 @@ namespace dsp
1202
1210
  Napi::Value DspPipeline::AddFilterStage(const Napi::CallbackInfo &info)
1203
1211
  {
1204
1212
  Napi::Env env = info.Env();
1213
+ // std::cout << "[DEBUG] DspPipeline::AddFilterStage - this=" << this << std::endl;
1205
1214
 
1206
1215
  // Check if pipeline is disposed
1207
1216
  if (m_disposed)
1208
1217
  {
1218
+ // std::cout << "[DEBUG] AddFilterStage - pipeline disposed, this=" << this << std::endl;
1209
1219
  Napi::Error::New(env, "Pipeline is disposed").ThrowAsJavaScriptException();
1210
1220
  return env.Undefined();
1211
1221
  }
@@ -1278,34 +1288,46 @@ namespace dsp
1278
1288
  m_timestampRef(std::move(timestampRef)),
1279
1289
  m_busyLock(busyLock)
1280
1290
  {
1291
+ // std::cout << "[DEBUG] ProcessWorker::ProcessWorker - this=" << this << std::endl;
1292
+ m_stageCount = m_stages.size();
1293
+ m_stageTypes.reserve(m_stageCount);
1294
+ for (const auto &stage : m_stages)
1295
+ {
1296
+ m_stageTypes.push_back(stage->getType());
1297
+ }
1281
1298
  }
1282
1299
 
1283
1300
  protected:
1284
1301
  // This runs on a worker thread (not blocking the event loop)
1285
1302
  void Execute() override
1286
1303
  {
1287
- // Local storage for generated timestamps (RAII - automatically freed when function exits)
1304
+ // std::cout << "[DEBUG] ProcessWorker::Execute - START, this=" << this
1305
+ // << ", data=" << m_data << ", numSamples=" << m_numSamples
1306
+ // << ", channels=" << m_channels << std::endl;
1307
+ // std::cout << "[WORKER-" << std::this_thread::get_id() << "] Execute START (stages="
1308
+ // << m_stages.size() << ")" << std::endl;
1309
+
1310
+ // CRITICAL FIX: Use a unique_ptr for timestamp ownership
1288
1311
  std::vector<float> generatedTimestamps;
1312
+ std::unique_ptr<std::vector<float>> allocatedTimestamps;
1289
1313
 
1290
1314
  try
1291
1315
  {
1292
- // 1. Generate Timestamps if missing (Optimization)
1316
+ // 1. Generate Timestamps if missing
1293
1317
  if (m_timestamps == nullptr)
1294
1318
  {
1295
- generatedTimestamps.resize(m_numSamples);
1319
+ // std::cout << "[DEBUG] Execute - generating timestamps, sampleRate=" << m_sampleRate << std::endl;
1296
1320
 
1297
- // Calculate time step (dt) in milliseconds
1298
- // If sampleRate is 0 or invalid, default to 1.0 (treating indices as time)
1321
+ generatedTimestamps.resize(m_numSamples);
1299
1322
  double dt = (m_sampleRate > 0.0) ? (1000.0 / m_sampleRate) : 1.0;
1300
1323
 
1301
- // Fill timestamps linearly: t[i] = i * dt
1302
1324
  for (size_t i = 0; i < m_numSamples; ++i)
1303
1325
  {
1304
1326
  generatedTimestamps[i] = static_cast<float>(i * dt);
1305
1327
  }
1306
1328
 
1307
- // Point the main processing pointer to our locally generated data
1308
1329
  m_timestamps = generatedTimestamps.data();
1330
+ // std::cout << "[DEBUG] Execute - timestamps generated, addr=" << m_timestamps << std::endl;
1309
1331
  }
1310
1332
 
1311
1333
  // 2. Process the buffer through all stages
@@ -1315,35 +1337,75 @@ namespace dsp
1315
1337
  bool usingTempBuffer = false;
1316
1338
 
1317
1339
  const bool debugStageDumps = std::getenv("DSPX_DEBUG_STAGE_DUMPS") != nullptr;
1318
- for (const auto &stage : m_stages)
1340
+
1341
+ // std::cout << "[DEBUG] Execute - processing through " << m_stages.size() << " stages" << std::endl;
1342
+ for (size_t stageIdx = 0; stageIdx < m_stages.size(); ++stageIdx)
1319
1343
  {
1344
+ const auto &stage = m_stages[stageIdx];
1345
+
1346
+ // std::cout << "[DEBUG] Execute - stage " << stageIdx << ", type="
1347
+ // << stage->getType() << ", addr=" << stage.get()
1348
+ // << ", isResizing=" << stage->isResizing() << std::endl;
1349
+
1320
1350
  if (stage->isResizing())
1321
1351
  {
1322
- // Resizing logic (same as before)
1352
+ // Calculate output size
1323
1353
  size_t outputSize = stage->calculateOutputSize(currentSize);
1324
1354
  float *outputBuffer = new float[outputSize];
1325
1355
 
1356
+ // std::cout << "[DEBUG] Execute - allocated output buffer, size=" << outputSize
1357
+ // << ", addr=" << outputBuffer << std::endl;
1358
+
1359
+ // CRITICAL: Save the PREVIOUS size before processResizing updates currentSize
1360
+ size_t prevSize = currentSize;
1361
+
1326
1362
  size_t actualOutputSize = 0;
1327
1363
  stage->processResizing(currentBuffer, currentSize,
1328
1364
  outputBuffer, actualOutputSize,
1329
1365
  m_channels, m_timestamps);
1330
1366
 
1331
- if (usingTempBuffer)
1332
- delete[] currentBuffer;
1367
+ // std::cout << "[DEBUG] Execute - stage " << stageIdx << " resized: "
1368
+ // << prevSize << " -> " << actualOutputSize // Use prevSize!
1369
+ // << ", buffer=" << outputBuffer << std::endl;
1370
+
1371
+ // Free previous temp buffer if we owned it
1372
+ if (usingTempBuffer && tempBuffer != nullptr)
1373
+ {
1374
+ // std::cout << "[DEBUG] Execute - freeing previous temp buffer=" << tempBuffer << std::endl;
1375
+ delete[] tempBuffer;
1376
+ }
1377
+
1378
+ // Update buffer tracking
1379
+ tempBuffer = outputBuffer;
1333
1380
  currentBuffer = outputBuffer;
1334
1381
  currentSize = actualOutputSize;
1335
1382
  usingTempBuffer = true;
1336
1383
 
1384
+ // Save previous channel count BEFORE updating
1385
+ int prevChannels = m_channels;
1386
+
1387
+ // Update channel count if stage changed it
1337
1388
  int outputChannels = stage->getOutputChannels();
1338
1389
  if (outputChannels > 0)
1390
+ {
1391
+ // std::cout << "[DEBUG] Execute - channels changed: " << m_channels
1392
+ // << " -> " << outputChannels << std::endl;
1339
1393
  m_channels = outputChannels;
1394
+ }
1340
1395
 
1341
- // Re-interpolate timestamps if needed (same as before)
1396
+ // Re-interpolate timestamps if needed
1342
1397
  if (m_timestamps != nullptr)
1343
1398
  {
1399
+ // std::cout << "[DEBUG] Execute - reinterpolating timestamps" << std::endl;
1400
+
1344
1401
  double timeScale = stage->getTimeScaleFactor();
1345
1402
  size_t numOutputSamples = actualOutputSize / m_channels;
1346
- float *newTimestamps = new float[actualOutputSize];
1403
+
1404
+ // CRITICAL FIX: Use prevSize and prevChannels!
1405
+ size_t prevNumSamples = prevSize / prevChannels;
1406
+
1407
+ // Create new timestamp vector
1408
+ auto newTimestamps = std::make_unique<std::vector<float>>(actualOutputSize);
1347
1409
 
1348
1410
  for (size_t i = 0; i < numOutputSamples; ++i)
1349
1411
  {
@@ -1352,42 +1414,48 @@ namespace dsp
1352
1414
  double frac = inputTime - inputIdx;
1353
1415
  float timestamp;
1354
1416
 
1355
- if (inputIdx >= (currentSize / m_channels))
1417
+ if (inputIdx >= prevNumSamples)
1356
1418
  {
1357
- size_t lastIdx = (currentSize / m_channels) - 1;
1358
- timestamp = m_timestamps[lastIdx * m_channels] +
1419
+ size_t lastIdx = prevNumSamples - 1;
1420
+ timestamp = m_timestamps[lastIdx * prevChannels] +
1359
1421
  static_cast<float>((inputTime - lastIdx) * timeScale);
1360
1422
  }
1361
- else if (inputIdx + 1 >= (currentSize / m_channels))
1423
+ else if (inputIdx + 1 >= prevNumSamples)
1362
1424
  {
1363
- timestamp = m_timestamps[inputIdx * m_channels];
1425
+ timestamp = m_timestamps[inputIdx * prevChannels];
1364
1426
  }
1365
1427
  else
1366
1428
  {
1367
- float t0 = m_timestamps[inputIdx * m_channels];
1368
- float t1 = m_timestamps[(inputIdx + 1) * m_channels];
1429
+ float t0 = m_timestamps[inputIdx * prevChannels];
1430
+ float t1 = m_timestamps[(inputIdx + 1) * prevChannels];
1369
1431
  timestamp = t0 + static_cast<float>(frac) * (t1 - t0);
1370
1432
  }
1371
1433
 
1372
1434
  for (int ch = 0; ch < m_channels; ++ch)
1373
1435
  {
1374
- newTimestamps[i * m_channels + ch] = timestamp;
1436
+ (*newTimestamps)[i * m_channels + ch] = timestamp;
1375
1437
  }
1376
1438
  }
1377
- m_timestamps = newTimestamps;
1378
- m_timestampBuffer.reset(newTimestamps);
1439
+
1440
+ // CRITICAL FIX: Transfer ownership safely
1441
+ allocatedTimestamps = std::move(newTimestamps);
1442
+ m_timestamps = allocatedTimestamps->data();
1443
+
1444
+ // std::cout << "[DEBUG] Execute - timestamps reinterpolated, new addr="
1445
+ // << m_timestamps << std::endl;
1379
1446
  }
1380
1447
  }
1381
1448
  else
1382
1449
  {
1383
1450
  // In-place processing
1451
+ // std::cout << "[DEBUG] Execute - stage " << stageIdx << " in-place processing" << std::endl;
1384
1452
  stage->process(currentBuffer, currentSize, m_channels, m_timestamps);
1385
1453
 
1386
1454
  if (debugStageDumps)
1387
1455
  {
1388
1456
  const char *stype = stage->getType();
1389
1457
  size_t toShow = std::min<size_t>(8, currentSize);
1390
- std::cout << "[DUMP] after '" << stype << "':";
1458
+ // std::cout << "[DUMP] after '" << stype << "':";
1391
1459
  for (size_t i = 0; i < toShow; ++i)
1392
1460
  {
1393
1461
  std::cout << (i == 0 ? ' ' : ',') << currentBuffer[i];
@@ -1400,16 +1468,22 @@ namespace dsp
1400
1468
  m_finalBuffer = currentBuffer;
1401
1469
  m_finalSize = currentSize;
1402
1470
  m_ownsBuffer = usingTempBuffer;
1471
+
1472
+ // std::cout << "[DEBUG] Execute - COMPLETE, finalBuffer=" << m_finalBuffer
1473
+ // << ", finalSize=" << m_finalSize << ", ownsBuffer=" << m_ownsBuffer << std::endl;
1403
1474
  }
1404
1475
  catch (const std::exception &e)
1405
1476
  {
1477
+ // std::cout << "[DEBUG] Execute - EXCEPTION: " << e.what() << ", this=" << this << std::endl;
1478
+ // std::cout << "[WORKER-" << std::this_thread::get_id() << "] EXCEPTION: " << e.what() << std::endl;
1406
1479
  SetError(e.what());
1407
1480
  }
1408
- }
1481
+ } // This runs on the main thread after Execute() completes
1409
1482
 
1410
- // This runs on the main thread after Execute() completes
1411
1483
  void OnOK() override
1412
1484
  {
1485
+ // std::cout << "[DEBUG] ProcessWorker::OnOK - START, this=" << this
1486
+ // << ", finalBuffer=" << (void *)m_finalBuffer << ", finalSize=" << m_finalSize << std::endl;
1413
1487
  *m_busyLock = false; // unlock the pipeline
1414
1488
 
1415
1489
  Napi::Env env = Env();
@@ -1423,22 +1497,29 @@ namespace dsp
1423
1497
  // Clean up temporary buffer if we allocated one
1424
1498
  if (m_ownsBuffer)
1425
1499
  {
1500
+ // std::cout << "[DEBUG] OnOK - deleting temp buffer=" << (void *)m_finalBuffer << std::endl;
1426
1501
  delete[] m_finalBuffer;
1427
1502
  }
1428
1503
 
1504
+ // std::cout << "[DEBUG] OnOK - COMPLETE, resolving promise, this=" << this << std::endl;
1429
1505
  // Resolve the promise with the processed buffer
1430
1506
  m_deferred.Resolve(outputArray);
1431
1507
  }
1432
1508
 
1433
1509
  void OnError(const Napi::Error &error) override
1434
1510
  {
1511
+ // std::cout << "[DEBUG] ProcessWorker::OnError - this=" << this
1512
+ // << ", error=" << error.Message() << std::endl;
1435
1513
  m_deferred.Reject(error.Value());
1436
1514
  *m_busyLock = false; // unlock the pipeline
1515
+ // std::cout << "[DEBUG] OnError - COMPLETE, this=" << this << std::endl;
1437
1516
  }
1438
1517
 
1439
1518
  private:
1440
1519
  Napi::Promise::Deferred m_deferred;
1441
1520
  std::vector<std::unique_ptr<IDspStage>> &m_stages;
1521
+ size_t m_stageCount;
1522
+ std::vector<std::string> m_stageTypes;
1442
1523
  float *m_data;
1443
1524
  float *m_timestamps;
1444
1525
  double m_sampleRate;
@@ -1469,16 +1550,19 @@ namespace dsp
1469
1550
  Napi::Value DspPipeline::ProcessAsync(const Napi::CallbackInfo &info)
1470
1551
  {
1471
1552
  Napi::Env env = info.Env();
1553
+ // std::cout << "[DEBUG] DspPipeline::ProcessAsync - this=" << this << std::endl;
1472
1554
 
1473
1555
  // Check if pipeline is disposed
1474
1556
  if (m_disposed)
1475
1557
  {
1558
+ // std::cout << "[DEBUG] ProcessAsync - pipeline disposed, this=" << this << std::endl;
1476
1559
  Napi::Error::New(env, "Pipeline is disposed").ThrowAsJavaScriptException();
1477
1560
  return env.Undefined();
1478
1561
  }
1479
1562
 
1480
1563
  if (*m_isBusy)
1481
1564
  {
1565
+ // std::cout << "[DEBUG] ProcessAsync - pipeline busy, this=" << this << std::endl;
1482
1566
  Napi::Error::New(env, "Pipeline is busy: Cannot call process() while another operation is running.").ThrowAsJavaScriptException();
1483
1567
  return env.Undefined();
1484
1568
  }
@@ -1547,8 +1631,13 @@ namespace dsp
1547
1631
  }
1548
1632
 
1549
1633
  *m_isBusy = true; // lock the pipeline
1634
+ // std::cout << "[DEBUG] ProcessAsync - creating worker, data=" << (void *)data
1635
+ // << ", numSamples=" << numSamples << ", channels=" << channels
1636
+ // << ", this=" << this << std::endl;
1550
1637
 
1551
1638
  ProcessWorker *worker = new ProcessWorker(env, std::move(deferred), m_stages, data, timestamps, sampleRate, numSamples, channels, std::move(bufferRef), std::move(timestampRef), m_isBusy);
1639
+ // std::cout << "[DEBUG] ProcessAsync - queuing worker=" << (void *)worker
1640
+ // << ", this=" << this << std::endl;
1552
1641
  worker->Queue();
1553
1642
 
1554
1643
  return promise;
@@ -1566,16 +1655,19 @@ namespace dsp
1566
1655
  Napi::Value DspPipeline::ProcessSync(const Napi::CallbackInfo &info)
1567
1656
  {
1568
1657
  Napi::Env env = info.Env();
1658
+ // std::cout << "[DEBUG] DspPipeline::ProcessSync - this=" << this << std::endl;
1569
1659
 
1570
1660
  // Check if pipeline is disposed
1571
1661
  if (m_disposed)
1572
1662
  {
1663
+ // std::cout << "[DEBUG] ProcessSync - pipeline disposed, this=" << this << std::endl;
1573
1664
  Napi::Error::New(env, "Pipeline is disposed").ThrowAsJavaScriptException();
1574
1665
  return env.Undefined();
1575
1666
  }
1576
1667
 
1577
1668
  if (*m_isBusy)
1578
1669
  {
1670
+ // std::cout << "[DEBUG] ProcessSync - pipeline busy, this=" << this << std::endl;
1579
1671
  Napi::Error::New(env, "Pipeline is busy: Cannot call processSync() while an async operation is running.").ThrowAsJavaScriptException();
1580
1672
  return env.Undefined();
1581
1673
  }
@@ -1702,10 +1794,13 @@ namespace dsp
1702
1794
  Napi::Value DspPipeline::SaveState(const Napi::CallbackInfo &info)
1703
1795
  {
1704
1796
  Napi::Env env = info.Env();
1797
+ // std::cout << "[DEBUG] DspPipeline::SaveState - this=" << this
1798
+ // << ", stages=" << m_stages.size() << std::endl;
1705
1799
 
1706
1800
  // Check if pipeline is disposed
1707
1801
  if (m_disposed)
1708
1802
  {
1803
+ // std::cout << "[DEBUG] SaveState - pipeline disposed, this=" << this << std::endl;
1709
1804
  Napi::Error::New(env, "Pipeline is disposed").ThrowAsJavaScriptException();
1710
1805
  return env.Undefined();
1711
1806
  }
@@ -1799,10 +1894,12 @@ namespace dsp
1799
1894
  Napi::Value DspPipeline::LoadState(const Napi::CallbackInfo &info)
1800
1895
  {
1801
1896
  Napi::Env env = info.Env();
1802
-
1897
+ // std::cout << "[DEBUG] DspPipeline::LoadState - this=" << this
1898
+ // << ", current stages=" << m_stages.size() << std::endl;
1803
1899
  // Check if pipeline is disposed
1804
1900
  if (m_disposed)
1805
1901
  {
1902
+ // std::cout << "[DEBUG] LoadState - pipeline disposed, this=" << this << std::endl;
1806
1903
  Napi::Error::New(env, "Pipeline is disposed").ThrowAsJavaScriptException();
1807
1904
  return env.Undefined();
1808
1905
  }
@@ -2046,21 +2143,27 @@ namespace dsp
2046
2143
  Napi::Value DspPipeline::ClearState(const Napi::CallbackInfo &info)
2047
2144
  {
2048
2145
  Napi::Env env = info.Env();
2146
+ // std::cout << "[DEBUG] DspPipeline::ClearState - this=" << this
2147
+ // << ", stages=" << m_stages.size() << std::endl;
2049
2148
 
2050
2149
  // Check if pipeline is disposed
2051
2150
  if (m_disposed)
2052
2151
  {
2152
+ // std::cout << "[DEBUG] ClearState - pipeline disposed, this=" << this << std::endl;
2053
2153
  Napi::Error::New(env, "Pipeline is disposed").ThrowAsJavaScriptException();
2054
2154
  return env.Undefined();
2055
2155
  }
2056
2156
 
2057
2157
  // Reset all stages
2058
- for (auto &stage : m_stages)
2158
+ for (size_t i = 0; i < m_stages.size(); ++i)
2059
2159
  {
2060
- stage->reset();
2160
+ // std::cout << "[DEBUG] ClearState - resetting stage " << i
2161
+ // << ", addr=" << m_stages[i].get() << std::endl;
2162
+ m_stages[i]->reset();
2061
2163
  }
2062
2164
 
2063
- std::cout << "Pipeline state cleared (" << m_stages.size() << " stages reset)" << std::endl;
2165
+ // std::cout << "[DEBUG] Pipeline state cleared (" << m_stages.size()
2166
+ // << " stages reset), this=" << this << std::endl;
2064
2167
 
2065
2168
  return env.Undefined();
2066
2169
  }
@@ -2156,21 +2259,27 @@ namespace dsp
2156
2259
  Napi::Value DspPipeline::Dispose(const Napi::CallbackInfo &info)
2157
2260
  {
2158
2261
  Napi::Env env = info.Env();
2262
+ // std::cout << "[DEBUG] DspPipeline::Dispose - this=" << this
2263
+ // << ", stages=" << m_stages.size() << ", disposed=" << m_disposed << std::endl;
2159
2264
 
2160
2265
  // Already disposed - silently succeed (idempotent behavior)
2161
2266
  if (m_disposed)
2162
2267
  {
2268
+ // std::cout << "[DEBUG] Dispose - already disposed, this=" << this << std::endl;
2163
2269
  return env.Undefined();
2164
2270
  }
2165
2271
 
2166
2272
  // Cannot dispose while processing is in progress
2167
2273
  if (*m_isBusy)
2168
2274
  {
2275
+ // std::cout << "[DEBUG] Dispose - pipeline busy, cannot dispose, this=" << this << std::endl;
2169
2276
  Napi::Error::New(env, "Cannot dispose pipeline: process() is still running.")
2170
2277
  .ThrowAsJavaScriptException();
2171
2278
  return env.Undefined();
2172
2279
  }
2173
2280
 
2281
+ // std::cout << "[DEBUG] Dispose - clearing " << m_stages.size()
2282
+ // << " stages, this=" << this << std::endl;
2174
2283
  // Clear all stages - triggers RAII cleanup of all stage resources
2175
2284
  // This will:
2176
2285
  // - Free all stage internal buffers
@@ -2179,12 +2288,14 @@ namespace dsp
2179
2288
  // - Free all detachable buffers
2180
2289
  // - Free timestamp and resize buffers
2181
2290
  m_stages.clear();
2291
+ // std::cout << "[DEBUG] Dispose - stages cleared, this=" << this << std::endl;
2182
2292
 
2183
2293
  // Reset busy flag (defensive programming)
2184
2294
  *m_isBusy = false;
2185
2295
 
2186
2296
  // Mark as disposed to prevent further operations
2187
2297
  m_disposed = true;
2298
+ // std::cout << "[DEBUG] Dispose - complete, this=" << this << std::endl;
2188
2299
 
2189
2300
  return env.Undefined();
2190
2301
  }