@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.
- package/CHANGELOG.md +62 -0
- package/dist/BaseSyncedStore.js +15 -11
- package/dist/Database.js +3 -3
- package/dist/ObjectPool.js +14 -4
- package/dist/SyncClient.js +18 -4
- package/dist/agent/Agent.js +5 -3
- package/dist/agent/session.js +9 -6
- package/dist/ai-sdk/coordinated-tool.d.ts +101 -0
- package/dist/ai-sdk/coordinated-tool.js +129 -0
- package/dist/ai-sdk/index.d.ts +42 -0
- package/dist/ai-sdk/index.js +42 -0
- package/dist/cli.cjs +687 -498
- package/dist/client/Ablo.d.ts +14 -2
- package/dist/client/Ablo.js +23 -9
- package/dist/client/ApiClient.js +28 -6
- package/dist/client/createModelProxy.js +6 -1
- package/dist/client/httpClient.d.ts +6 -1
- package/dist/client/identity.js +1 -1
- package/dist/core/DatabaseManager.js +1 -1
- package/dist/core/StoreManager.js +5 -2
- package/dist/interfaces/index.d.ts +8 -0
- package/dist/mutators/UndoManager.js +7 -6
- package/dist/query/client.js +19 -5
- package/dist/react/useMutators.js +6 -2
- package/dist/sync/BootstrapHelper.d.ts +16 -0
- package/dist/sync/BootstrapHelper.js +29 -2
- package/dist/sync/ConnectionManager.js +7 -7
- package/dist/sync/NetworkProbe.js +2 -2
- package/dist/sync/SyncWebSocket.js +2 -2
- package/dist/sync/schemas.d.ts +1 -0
- package/dist/sync/schemas.js +3 -0
- package/dist/transactions/TransactionQueue.js +37 -7
- package/package.json +1 -1
|
@@ -601,7 +601,9 @@ export class TransactionQueue extends EventEmitter {
|
|
|
601
601
|
}
|
|
602
602
|
if (inFlight.length === 0)
|
|
603
603
|
return;
|
|
604
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
1847
|
+
logger.warn(headline);
|
|
1848
|
+
logger.debug('write rejection — details', details);
|
|
1819
1849
|
}
|
|
1820
1850
|
}
|
|
1821
1851
|
catch { }
|