@abloatai/ablo 0.22.1 → 0.24.0

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.
@@ -601,7 +601,9 @@ export class TransactionQueue extends EventEmitter {
601
601
  }
602
602
  if (inFlight.length === 0)
603
603
  return;
604
- getContext().logger.warn(`[TransactionQueue] WS disconnected > ${graceMs}ms; failing ${inFlight.length} in-flight commit(s) with AbloConnectionError`, { inFlightIds: inFlight.map((id) => id.slice(0, 8)) });
604
+ // Internal mechanic: each failed commit surfaces to the consumer via its own
605
+ // rejection path, so this aggregate is forensic — debug, not warn.
606
+ getContext().logger.debug(`[TransactionQueue] WS disconnected > ${graceMs}ms; failing ${inFlight.length} in-flight commit(s) with AbloConnectionError`, { inFlightIds: inFlight.map((id) => id.slice(0, 8)) });
605
607
  for (const id of inFlight) {
606
608
  const tx = this.commitStore.get(id);
607
609
  if (!tx)
@@ -1429,7 +1431,9 @@ export class TransactionQueue extends EventEmitter {
1429
1431
  }
1430
1432
  // If disconnected, re-schedule with same timeout (no backoff while offline)
1431
1433
  if (!this.isConnectedFn()) {
1432
- getContext().logger.warn('[TransactionQueue] Timeout fired while disconnected - re-scheduling', {
1434
+ // Self-healing: re-schedule the confirmation wait while offline, no
1435
+ // consumer action needed → debug.
1436
+ getContext().logger.debug('[TransactionQueue] Timeout fired while disconnected - re-scheduling', {
1433
1437
  txId: tx.id.slice(0, 8),
1434
1438
  model: tx.modelName,
1435
1439
  });
@@ -1471,7 +1475,9 @@ export class TransactionQueue extends EventEmitter {
1471
1475
  lastSeenSyncId: this.lastSeenSyncId,
1472
1476
  retryCount: retryCount + 1,
1473
1477
  });
1474
- getContext().logger.warn('[TransactionQueue] Re-scheduling with backoff', {
1478
+ // Self-healing retry with backoff — the server already committed; we're
1479
+ // just waiting on the delta. No consumer action → debug.
1480
+ getContext().logger.debug('[TransactionQueue] Re-scheduling with backoff', {
1475
1481
  txId: tx.id.slice(0, 8),
1476
1482
  model: tx.modelName,
1477
1483
  nextTimeoutMs: nextTimeout,
@@ -1636,7 +1642,9 @@ export class TransactionQueue extends EventEmitter {
1636
1642
  tx.status = 'failed';
1637
1643
  tx.error = error;
1638
1644
  this.commitLane.shift();
1639
- getContext().logger.warn('[TransactionQueue] commit lane permanent error', {
1645
+ // Internal bookkeeping the consumer-facing rejection is emitted via
1646
+ // 'transaction:failed' and surfaced by the permanent-error headline → debug.
1647
+ getContext().logger.debug('[TransactionQueue] commit lane permanent error', {
1640
1648
  txId: tx.id.slice(0, 12),
1641
1649
  attempts: tx.attempts,
1642
1650
  message: error.message,
@@ -1808,14 +1816,36 @@ export class TransactionQueue extends EventEmitter {
1808
1816
  const isRepeat = sig === this.lastPermanentErrorSig;
1809
1817
  this.lastPermanentErrorSig = sig;
1810
1818
  const logger = getContext().logger;
1819
+ // Two registers, one call site, split by log level (the default
1820
+ // consumer logger is gated at `warn`, so `debug` is invisible unless
1821
+ // someone sets ABLO_LOG_LEVEL=debug to debug the engine itself):
1822
+ // • the default-visible line speaks the APP DEVELOPER's language —
1823
+ // their verb (`update`), their model, the typed error's own human
1824
+ // message, and the wire `code` for grep — the way AI SDK / Next.js
1825
+ // surface errors. No engine nouns ("TransactionQueue", "permanent",
1826
+ // "rolling back") and no JSON dump on this line: those alarm and
1827
+ // don't help someone who just installed @abloatai/ablo.
1828
+ // • the forensic `details` ride a companion `debug` line for whoever
1829
+ // is debugging the engine internals.
1830
+ const revertNote = this.config.enableOptimistic
1831
+ ? ' The local change was reverted.'
1832
+ : '';
1833
+ const reason = abloErr?.message ? ` — ${abloErr.message}` : '';
1834
+ const code = abloErr?.code ? ` (code: ${abloErr.code})` : '';
1835
+ const headline = `Your ${transaction.type} to "${transaction.modelName}" was not saved${reason}${code}.${revertNote}`;
1811
1836
  if (isRepeat) {
1812
- logger.debug('[TransactionQueue] Permanent error - rolling back (repeat)', details);
1837
+ // Same write rejected for the same reason on each reconnect replay —
1838
+ // log the forensics once, stay quiet after.
1839
+ logger.debug('write rejected again (same reason)', details);
1813
1840
  }
1814
1841
  else if (isBenignIdempotent) {
1815
- logger.info('[TransactionQueue] Write skipped row already exists', details);
1842
+ // Already-exists on a `create` is expected on replay, not a problem.
1843
+ logger.info(`Your ${transaction.type} to "${transaction.modelName}" was skipped — this row already exists.`);
1844
+ logger.debug('idempotent skip — details', details);
1816
1845
  }
1817
1846
  else {
1818
- logger.warn('[TransactionQueue] Permanent error - rolling back', details);
1847
+ logger.warn(headline);
1848
+ logger.debug('write rejection — details', details);
1819
1849
  }
1820
1850
  }
1821
1851
  catch { }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abloatai/ablo",
3
- "version": "0.22.1",
3
+ "version": "0.24.0",
4
4
  "description": "The Collaboration Layer For AI Agents",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",