@abloatai/ablo 0.35.0 → 0.36.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 +713 -629
- package/README.md +56 -519
- package/bin/ablo.cjs +39 -0
- package/dist/BaseSyncedStore.d.ts +24 -4
- package/dist/BaseSyncedStore.js +53 -37
- package/dist/Database.d.ts +8 -20
- package/dist/Database.js +61 -59
- package/dist/InstanceCache.d.ts +6 -2
- package/dist/InstanceCache.js +18 -16
- package/dist/Model.d.ts +17 -7
- package/dist/Model.js +17 -7
- package/dist/ModelRegistry.d.ts +4 -0
- package/dist/ModelRegistry.js +17 -15
- package/dist/NetworkMonitor.d.ts +3 -1
- package/dist/NetworkMonitor.js +7 -5
- package/dist/SyncClient.d.ts +5 -15
- package/dist/SyncClient.js +60 -57
- package/dist/client/Ablo.js +30 -19
- package/dist/client/createInternalComponents.d.ts +4 -0
- package/dist/client/createInternalComponents.js +8 -2
- package/dist/client/createModelProxy.d.ts +21 -1
- package/dist/client/createModelProxy.js +123 -57
- package/dist/client/humans.d.ts +30 -9
- package/dist/client/humans.js +45 -19
- package/dist/client/reactiveEngine.d.ts +16 -11
- package/dist/client/reactiveEngine.js +113 -335
- package/dist/client/storeCluster.d.ts +47 -0
- package/dist/client/storeCluster.js +118 -0
- package/dist/client/storeLifecycle.d.ts +61 -0
- package/dist/client/storeLifecycle.js +231 -0
- package/dist/context.d.ts +13 -0
- package/dist/context.js +23 -0
- package/dist/core/index.d.ts +1 -1
- package/dist/docs/catalog.js +6 -3
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -2
- package/dist/query/client.d.ts +3 -0
- package/dist/query/client.js +6 -5
- package/dist/react/AbloProvider.d.ts +13 -1
- package/dist/react/AbloProvider.js +5 -2
- package/dist/react/context.d.ts +2 -2
- package/dist/react/createAbloReact.d.ts +56 -0
- package/dist/react/createAbloReact.js +51 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.js +3 -0
- package/dist/react/useAblo.d.ts +9 -2
- package/dist/react/useAblo.js +25 -7
- package/dist/schema/coordination.js +5 -1
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +4 -0
- package/dist/schema/select.js +3 -0
- package/dist/schema/serialize.js +3 -0
- package/dist/source/adapter.d.ts +7 -5
- package/dist/source/adapter.js +7 -5
- package/dist/source/index.d.ts +1 -1
- package/dist/source/index.js +1 -1
- package/dist/{core/storeContract.d.ts → storeContract.d.ts} +5 -5
- package/dist/{core → stores}/DatabaseManager.d.ts +3 -1
- package/dist/{core → stores}/DatabaseManager.js +13 -12
- package/dist/{core → stores}/StoreManager.d.ts +5 -3
- package/dist/{core → stores}/StoreManager.js +24 -22
- package/dist/stores/SyncActionStore.d.ts +3 -1
- package/dist/stores/SyncActionStore.js +9 -7
- package/dist/sync/BootstrapFetcher.d.ts +4 -0
- package/dist/sync/BootstrapFetcher.js +28 -26
- package/dist/sync/OnDemandLoader.d.ts +3 -0
- package/dist/sync/OnDemandLoader.js +1 -0
- package/dist/sync/bootstrapApply.d.ts +3 -0
- package/dist/sync/bootstrapApply.js +2 -2
- package/dist/sync/deltaPipeline.d.ts +13 -12
- package/dist/sync/deltaPipeline.js +21 -4
- package/dist/sync/groupChange.d.ts +3 -0
- package/dist/sync/groupChange.js +16 -14
- package/dist/sync/participants.d.ts +19 -2
- package/dist/sync/participants.js +3 -1
- package/dist/sync/schemas.d.ts +2 -1
- package/dist/sync/schemas.js +3 -3
- package/dist/syncLog/contract.d.ts +20 -0
- package/dist/syncLog/contract.js +19 -0
- package/dist/syncLog/index.d.ts +1 -0
- package/dist/syncLog/index.js +1 -0
- package/dist/transaction/auth/capability.d.ts +35 -0
- package/dist/transaction/auth/capability.js +25 -0
- package/dist/transaction/coordination/awaitClaimGrant.d.ts +7 -0
- package/dist/transaction/coordination/awaitClaimGrant.js +12 -0
- package/dist/transaction/coordination/claimHeartbeatLoop.d.ts +34 -0
- package/dist/transaction/coordination/claimHeartbeatLoop.js +20 -0
- package/dist/transaction/coordination/index.d.ts +4 -4
- package/dist/transaction/coordination/index.js +4 -3
- package/dist/transaction/coordination/locator.d.ts +23 -2
- package/dist/transaction/coordination/locator.js +22 -2
- package/dist/transaction/coordination/schema.d.ts +125 -62
- package/dist/transaction/coordination/schema.js +228 -64
- package/dist/transaction/coordination/targetConflict.js +32 -28
- package/dist/transaction/errorCodes.d.ts +2 -2
- package/dist/transaction/errorCodes.js +13 -9
- package/dist/transaction/plugin.d.ts +95 -2
- package/dist/transaction/plugin.js +21 -2
- package/dist/transaction/resources/httpResources.d.ts +57 -2
- package/dist/transaction/resources/modelOperations.d.ts +148 -40
- package/dist/transaction/resources/where.d.ts +16 -0
- package/dist/transaction/resources/where.js +45 -0
- package/dist/transaction/schema/field.d.ts +12 -18
- package/dist/transaction/schema/fieldRef.d.ts +38 -0
- package/dist/transaction/schema/fieldRef.js +11 -0
- package/dist/transaction/schema/openapi.d.ts +16 -15
- package/dist/transaction/schema/openapi.js +186 -25
- package/dist/transaction/schema/relation.d.ts +7 -2
- package/dist/transaction/schema/schema.d.ts +27 -0
- package/dist/transaction/schema/schema.js +20 -0
- package/dist/transaction/transactions/settlement/commitEnvelope.d.ts +1 -1
- package/dist/transaction/transactions/settlement/pendingWrite.d.ts +1 -1
- package/dist/transaction/transport/httpClient.d.ts +9 -1
- package/dist/transaction/transport/httpClient.js +1 -0
- package/dist/transaction/transport/httpTransport.js +156 -44
- package/dist/transaction/transport/wsTransport.d.ts +2 -4
- package/dist/transaction/transport/wsTransport.js +16 -10
- package/dist/transaction/types/streams.d.ts +10 -0
- package/dist/transaction/utils/duration.d.ts +25 -0
- package/dist/transaction/utils/duration.js +32 -0
- package/dist/transaction/wire/accountResponses.d.ts +69 -0
- package/dist/transaction/wire/accountResponses.js +36 -1
- package/dist/transaction/wire/auth.d.ts +9 -2
- package/dist/transaction/wire/auth.js +7 -1
- package/dist/transaction/wire/claims.d.ts +164 -97
- package/dist/transaction/wire/claims.js +126 -28
- package/dist/transaction/wire/commit.d.ts +1 -1
- package/dist/transaction/wire/feedEvent.d.ts +27 -0
- package/dist/transaction/wire/feedEvent.js +27 -1
- package/dist/transaction/wire/frames.d.ts +2 -2
- package/dist/transaction/wire/inboundFrames.d.ts +12 -2
- package/dist/transaction/wire/index.d.ts +10 -6
- package/dist/transaction/wire/index.js +12 -3
- package/dist/transaction/wire/modelMutations.d.ts +31 -0
- package/dist/transaction/wire/modelMutations.js +52 -0
- package/dist/transaction/wire/modelShape.d.ts +78 -0
- package/dist/transaction/wire/modelShape.js +74 -0
- package/dist/transactions/mutations/MutationQueue.d.ts +6 -0
- package/dist/transactions/mutations/MutationQueue.js +55 -45
- package/dist/transactions/mutations/commitPayload.d.ts +3 -2
- package/dist/transactions/mutations/commitPayload.js +5 -5
- package/dist/transactions/mutations/deltaConfirmation.d.ts +4 -0
- package/dist/transactions/mutations/deltaConfirmation.js +10 -8
- package/dist/transactions/mutations/replayValidation.d.ts +2 -1
- package/dist/transactions/mutations/replayValidation.js +3 -2
- package/dist/{core → views}/QueryView.d.ts +1 -1
- package/dist/{core → views}/QueryView.js +1 -1
- package/dist/{core → views}/ViewRegistry.d.ts +1 -1
- package/dist/{core/queryUtils.d.ts → views/incrementalView.d.ts} +6 -6
- package/dist/{core/queryUtils.js → views/incrementalView.js} +6 -6
- package/docs/agents.md +1 -1
- package/docs/api-keys.md +6 -6
- package/docs/api.md +5 -43
- package/docs/audit.md +4 -3
- package/docs/cli.md +11 -11
- package/docs/client-behavior.md +4 -4
- package/docs/concurrency-convention.md +28 -42
- package/docs/coordination.md +235 -83
- package/docs/data-sources.md +4 -4
- package/docs/debugging.md +34 -12
- package/docs/deployment.md +8 -8
- package/docs/examples/scoped-agent.md +3 -3
- package/docs/groups.md +57 -3
- package/docs/guarantees.md +37 -10
- package/docs/how-it-works.md +29 -5
- package/docs/idempotency.md +6 -6
- package/docs/identity.md +22 -23
- package/docs/index.md +8 -8
- package/docs/integration-guide.md +14 -3
- package/docs/mcp.md +7 -7
- package/docs/migration.md +34 -15
- package/docs/projects.md +1 -1
- package/docs/react.md +19 -8
- package/docs/sessions.md +1 -1
- package/docs/webhooks.md +9 -9
- package/llms.txt +4 -4
- package/package.json +13 -20
- package/dist/cli.cjs +0 -288600
- package/dist/testing/fixtures/bootstrap.d.ts +0 -49
- package/dist/testing/fixtures/bootstrap.js +0 -59
- package/dist/testing/fixtures/deltas.d.ts +0 -83
- package/dist/testing/fixtures/deltas.js +0 -136
- package/dist/testing/fixtures/httpResponses.d.ts +0 -70
- package/dist/testing/fixtures/httpResponses.js +0 -90
- package/dist/testing/fixtures/models.d.ts +0 -83
- package/dist/testing/fixtures/models.js +0 -272
- package/dist/testing/helpers/reactWrapper.d.ts +0 -69
- package/dist/testing/helpers/reactWrapper.js +0 -67
- package/dist/testing/helpers/syncEngineHarness.d.ts +0 -54
- package/dist/testing/helpers/syncEngineHarness.js +0 -73
- package/dist/testing/helpers/wait.d.ts +0 -30
- package/dist/testing/helpers/wait.js +0 -49
- package/dist/testing/index.d.ts +0 -23
- package/dist/testing/index.js +0 -33
- package/dist/testing/mocks/FakeDatabase.d.ts +0 -18
- package/dist/testing/mocks/FakeDatabase.js +0 -10
- package/dist/testing/mocks/MockMutationExecutor.d.ts +0 -87
- package/dist/testing/mocks/MockMutationExecutor.js +0 -186
- package/dist/testing/mocks/MockNetworkMonitor.d.ts +0 -20
- package/dist/testing/mocks/MockNetworkMonitor.js +0 -46
- package/dist/testing/mocks/MockSyncContext.d.ts +0 -51
- package/dist/testing/mocks/MockSyncContext.js +0 -72
- package/dist/testing/mocks/MockSyncStore.d.ts +0 -88
- package/dist/testing/mocks/MockSyncStore.js +0 -171
- package/dist/testing/mocks/MockWebSocket.d.ts +0 -71
- package/dist/testing/mocks/MockWebSocket.js +0 -118
- package/docs/interaction-model.md +0 -99
- /package/dist/{core → query}/QueryProcessor.d.ts +0 -0
- /package/dist/{core → query}/QueryProcessor.js +0 -0
- /package/dist/{core/storeContract.js → storeContract.js} +0 -0
- /package/dist/{core → stores}/openIDBWithTimeout.d.ts +0 -0
- /package/dist/{core → stores}/openIDBWithTimeout.js +0 -0
- /package/dist/{source → transaction}/footprint.d.ts +0 -0
- /package/dist/{source → transaction}/footprint.js +0 -0
- /package/dist/{core → views}/ViewRegistry.js +0 -0
package/dist/Model.d.ts
CHANGED
|
@@ -246,9 +246,16 @@ export declare abstract class Model {
|
|
|
246
246
|
* written, `onWrite(key, oldValue, newValue)` is invoked with the value
|
|
247
247
|
* captured immediately before assignment. `applyChanges` passes a hook
|
|
248
248
|
* that records the change in `modifiedProperties`; `updateFromData`
|
|
249
|
-
* passes none (hydration must not generate outbound mutations).
|
|
250
|
-
*
|
|
251
|
-
*
|
|
249
|
+
* passes none (hydration must not generate outbound mutations).
|
|
250
|
+
*
|
|
251
|
+
* This is not the ONLY tracking path. `mobxSetup`'s `observe()` bridge is
|
|
252
|
+
* live and forwards a DIRECT assignment (`layer.position = next`) to
|
|
253
|
+
* `propertyChanged` as well — product code writes model fields directly in
|
|
254
|
+
* plenty of places (keyboard nudge, formatting, AI tools), and those writes
|
|
255
|
+
* have to reach the server and the undo stream too. The two paths compose:
|
|
256
|
+
* a direct write establishes the first-old-wins baseline, and a later
|
|
257
|
+
* `applyChanges` carrying the value the model already holds is a no-op that
|
|
258
|
+
* leaves that baseline intact.
|
|
252
259
|
*/
|
|
253
260
|
private assignFieldsFromData;
|
|
254
261
|
/**
|
|
@@ -260,10 +267,13 @@ export declare abstract class Model {
|
|
|
260
267
|
* brand-new outbound mutation and the record would echo forever. For a
|
|
261
268
|
* local user edit, use `applyChanges` instead.
|
|
262
269
|
*
|
|
263
|
-
* Suppression
|
|
264
|
-
* clear/restore `modifiedProperties` around the
|
|
265
|
-
*
|
|
266
|
-
*
|
|
270
|
+
* Suppression takes two forms and BOTH are load-bearing: we pass no
|
|
271
|
+
* `onWrite` hook, and we clear/restore `modifiedProperties` around the
|
|
272
|
+
* assignment. The second is what catches `mobxSetup`'s `observe()` bridge,
|
|
273
|
+
* which fires on the assignment itself and would otherwise record an
|
|
274
|
+
* inbound delta as a local edit — queueing an outbound mutation that echoes
|
|
275
|
+
* forever, and putting a collaborator's change on your undo stack. Do not
|
|
276
|
+
* remove it while that bridge exists (`mobxSetup.M1`).
|
|
267
277
|
*/
|
|
268
278
|
updateFromData(data: ModelData): void;
|
|
269
279
|
/**
|
package/dist/Model.js
CHANGED
|
@@ -428,9 +428,16 @@ export class Model {
|
|
|
428
428
|
* written, `onWrite(key, oldValue, newValue)` is invoked with the value
|
|
429
429
|
* captured immediately before assignment. `applyChanges` passes a hook
|
|
430
430
|
* that records the change in `modifiedProperties`; `updateFromData`
|
|
431
|
-
* passes none (hydration must not generate outbound mutations).
|
|
432
|
-
*
|
|
433
|
-
*
|
|
431
|
+
* passes none (hydration must not generate outbound mutations).
|
|
432
|
+
*
|
|
433
|
+
* This is not the ONLY tracking path. `mobxSetup`'s `observe()` bridge is
|
|
434
|
+
* live and forwards a DIRECT assignment (`layer.position = next`) to
|
|
435
|
+
* `propertyChanged` as well — product code writes model fields directly in
|
|
436
|
+
* plenty of places (keyboard nudge, formatting, AI tools), and those writes
|
|
437
|
+
* have to reach the server and the undo stream too. The two paths compose:
|
|
438
|
+
* a direct write establishes the first-old-wins baseline, and a later
|
|
439
|
+
* `applyChanges` carrying the value the model already holds is a no-op that
|
|
440
|
+
* leaves that baseline intact.
|
|
434
441
|
*/
|
|
435
442
|
assignFieldsFromData(data, onWrite) {
|
|
436
443
|
// Update properties with safety checks for read-only/computed accessors
|
|
@@ -489,10 +496,13 @@ export class Model {
|
|
|
489
496
|
* brand-new outbound mutation and the record would echo forever. For a
|
|
490
497
|
* local user edit, use `applyChanges` instead.
|
|
491
498
|
*
|
|
492
|
-
* Suppression
|
|
493
|
-
* clear/restore `modifiedProperties` around the
|
|
494
|
-
*
|
|
495
|
-
*
|
|
499
|
+
* Suppression takes two forms and BOTH are load-bearing: we pass no
|
|
500
|
+
* `onWrite` hook, and we clear/restore `modifiedProperties` around the
|
|
501
|
+
* assignment. The second is what catches `mobxSetup`'s `observe()` bridge,
|
|
502
|
+
* which fires on the assignment itself and would otherwise record an
|
|
503
|
+
* inbound delta as a local edit — queueing an outbound mutation that echoes
|
|
504
|
+
* forever, and putting a collaborator's change on your undo stack. Do not
|
|
505
|
+
* remove it while that bridge exists (`mobxSetup.M1`).
|
|
496
506
|
*/
|
|
497
507
|
updateFromData(data) {
|
|
498
508
|
if (this.isDisposed) {
|
package/dist/ModelRegistry.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* another model that is registered later.
|
|
9
9
|
*/
|
|
10
10
|
import { type ModelMetadata, type PropertyMetadata, type ReferenceMetadata, LoadStrategy } from './transaction/types/index.js';
|
|
11
|
+
import type { RuntimeContext } from './RuntimeContext.js';
|
|
11
12
|
import type { Model } from './Model.js';
|
|
12
13
|
import type { ConcreteModelConstructor } from './BaseSyncedStore.js';
|
|
13
14
|
/**
|
|
@@ -61,6 +62,8 @@ export interface BackReferenceMetadata {
|
|
|
61
62
|
interface RegistryConfig {
|
|
62
63
|
validateOnRegister?: boolean;
|
|
63
64
|
allowLateReferences?: boolean;
|
|
65
|
+
/** The owning client's runtime. Defaults to the module-global bridge. */
|
|
66
|
+
runtime?: RuntimeContext;
|
|
64
67
|
}
|
|
65
68
|
/** Set the active ModelRegistry instance (called by createSyncEngine) */
|
|
66
69
|
export declare function setActiveRegistry(registry: ModelRegistry): void;
|
|
@@ -80,6 +83,7 @@ export declare class ModelRegistry {
|
|
|
80
83
|
private backReferences;
|
|
81
84
|
private schemaHash?;
|
|
82
85
|
private config;
|
|
86
|
+
private readonly runtime;
|
|
83
87
|
private registeredModels;
|
|
84
88
|
private pendingHashUpdate;
|
|
85
89
|
constructor(config?: RegistryConfig);
|
package/dist/ModelRegistry.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
// Removed Node.js crypto import for browser compatibility
|
|
11
11
|
import { PropertyType, LoadStrategy, } from './transaction/types/index.js';
|
|
12
|
-
import {
|
|
12
|
+
import { globalRuntime } from './context.js';
|
|
13
13
|
import { AbloValidationError } from './transaction/errors.js';
|
|
14
14
|
/**
|
|
15
15
|
* Module-level active registry. Set by createSyncEngine so that Model instances
|
|
@@ -51,6 +51,7 @@ export class ModelRegistry {
|
|
|
51
51
|
backReferences = new Map();
|
|
52
52
|
schemaHash;
|
|
53
53
|
config;
|
|
54
|
+
runtime;
|
|
54
55
|
registeredModels = new Set();
|
|
55
56
|
pendingHashUpdate = false;
|
|
56
57
|
constructor(config = {}) {
|
|
@@ -58,6 +59,7 @@ export class ModelRegistry {
|
|
|
58
59
|
validateOnRegister: config.validateOnRegister ?? true,
|
|
59
60
|
allowLateReferences: config.allowLateReferences ?? true,
|
|
60
61
|
};
|
|
62
|
+
this.runtime = config.runtime ?? globalRuntime;
|
|
61
63
|
}
|
|
62
64
|
validateModelConstructor(name, constructor) {
|
|
63
65
|
if (typeof constructor !== 'function') {
|
|
@@ -71,7 +73,7 @@ export class ModelRegistry {
|
|
|
71
73
|
const required = ['updateFromData', 'toJSON', 'getModelName'];
|
|
72
74
|
for (const method of required) {
|
|
73
75
|
if (typeof prototype[method] !== 'function') {
|
|
74
|
-
|
|
76
|
+
this.runtime.logger.debug('Model missing required method', name, { method });
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
}
|
|
@@ -99,7 +101,7 @@ export class ModelRegistry {
|
|
|
99
101
|
this.pendingReferences.set(targetName, pending);
|
|
100
102
|
}
|
|
101
103
|
pending.push({ modelName, propertyName, metadata });
|
|
102
|
-
|
|
104
|
+
this.runtime.logger.debug('Reference deferred', `${modelName}.${propertyName}`, { targetModel: targetName });
|
|
103
105
|
}
|
|
104
106
|
resolvePendingReferences(targetModelName) {
|
|
105
107
|
const pending = this.pendingReferences.get(targetModelName);
|
|
@@ -108,12 +110,12 @@ export class ModelRegistry {
|
|
|
108
110
|
for (const ref of pending) {
|
|
109
111
|
try {
|
|
110
112
|
this.completeReferenceRegistration(ref.modelName, ref.propertyName, ref.metadata);
|
|
111
|
-
|
|
113
|
+
this.runtime.logger.debug('Reference resolved', `${ref.modelName}.${ref.propertyName}`, {
|
|
112
114
|
targetModel: targetModelName,
|
|
113
115
|
});
|
|
114
116
|
}
|
|
115
117
|
catch (error) {
|
|
116
|
-
|
|
118
|
+
this.runtime.observability.breadcrumb(`Failed to resolve reference ${ref.modelName}.${ref.propertyName}`, 'sync.database', 'error', {
|
|
117
119
|
error: error instanceof Error ? error.message : String(error),
|
|
118
120
|
});
|
|
119
121
|
}
|
|
@@ -154,10 +156,10 @@ export class ModelRegistry {
|
|
|
154
156
|
}
|
|
155
157
|
// Check for duplicate
|
|
156
158
|
if (this.models.has(name)) {
|
|
157
|
-
|
|
159
|
+
this.runtime.logger.debug('Model already registered, skipping', name);
|
|
158
160
|
return;
|
|
159
161
|
}
|
|
160
|
-
|
|
162
|
+
this.runtime.logger.debug('Registering model', name);
|
|
161
163
|
// Register. The one cast in this file: input is any Model-subclass
|
|
162
164
|
// constructor (validated above); registered classes are concrete
|
|
163
165
|
// subclasses constructible with `data?` and carrying Model's statics —
|
|
@@ -180,7 +182,7 @@ export class ModelRegistry {
|
|
|
180
182
|
this.resolvePendingReferences(name);
|
|
181
183
|
// Invalidate schema hash
|
|
182
184
|
this.schemaHash = undefined;
|
|
183
|
-
|
|
185
|
+
this.runtime.logger.debug('Model registered', name, metadata);
|
|
184
186
|
}
|
|
185
187
|
/**
|
|
186
188
|
* Register property with validation
|
|
@@ -201,7 +203,7 @@ export class ModelRegistry {
|
|
|
201
203
|
if (existing) {
|
|
202
204
|
if (this.arePropertiesCompatible(existing, metadata)) {
|
|
203
205
|
// Properties are compatible, skip re-registration
|
|
204
|
-
|
|
206
|
+
this.runtime.logger.debug('Property already registered (compatible)', `${modelName}.${propertyName}`);
|
|
205
207
|
return;
|
|
206
208
|
}
|
|
207
209
|
else {
|
|
@@ -210,7 +212,7 @@ export class ModelRegistry {
|
|
|
210
212
|
}
|
|
211
213
|
props.set(propertyName, metadata);
|
|
212
214
|
this.schemaHash = undefined;
|
|
213
|
-
|
|
215
|
+
this.runtime.logger.debug('Property registered', `${modelName}.${propertyName}`, metadata);
|
|
214
216
|
}
|
|
215
217
|
/**
|
|
216
218
|
* Register reference with lazy resolution
|
|
@@ -265,7 +267,7 @@ export class ModelRegistry {
|
|
|
265
267
|
}
|
|
266
268
|
// Reverse lookup (parent → children) is derived on demand by
|
|
267
269
|
// `getChildModels`, which scans this map.
|
|
268
|
-
|
|
270
|
+
this.runtime.logger.debug('BackReference registered', `${childModelName} -> ${metadata.parentModel}`, {
|
|
269
271
|
foreignKey: metadata.foreignKey,
|
|
270
272
|
cascadeDelete: metadata.cascadeDelete,
|
|
271
273
|
});
|
|
@@ -365,7 +367,7 @@ export class ModelRegistry {
|
|
|
365
367
|
const sorted = JSON.stringify(schema, Object.keys(schema).sort());
|
|
366
368
|
// Create hash - browser-compatible simple hash
|
|
367
369
|
this.schemaHash = this.simpleHash(sorted);
|
|
368
|
-
|
|
370
|
+
this.runtime.logger.debug('Schema hash updated', this.schemaHash);
|
|
369
371
|
return this.schemaHash;
|
|
370
372
|
}
|
|
371
373
|
/**
|
|
@@ -410,10 +412,10 @@ export class ModelRegistry {
|
|
|
410
412
|
}
|
|
411
413
|
const isValid = errors.length === 0;
|
|
412
414
|
if (isValid) {
|
|
413
|
-
|
|
415
|
+
this.runtime.logger.info('All model references are valid');
|
|
414
416
|
}
|
|
415
417
|
else {
|
|
416
|
-
|
|
418
|
+
this.runtime.observability.breadcrumb('Reference validation failed', 'sync.database', 'error');
|
|
417
419
|
}
|
|
418
420
|
return {
|
|
419
421
|
valid: isValid,
|
|
@@ -458,7 +460,7 @@ export class ModelRegistry {
|
|
|
458
460
|
this.constructorToModelName.clear();
|
|
459
461
|
this.schemaHash = undefined;
|
|
460
462
|
this.pendingHashUpdate = false;
|
|
461
|
-
|
|
463
|
+
this.runtime.logger.info('ModelRegistry cleared');
|
|
462
464
|
}
|
|
463
465
|
/**
|
|
464
466
|
* Static wrapper for backward compatibility
|
package/dist/NetworkMonitor.d.ts
CHANGED
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
* firing, so returning to the tab emits a recovery signal the store can act on.
|
|
7
7
|
*/
|
|
8
8
|
import { EventEmitter } from 'events';
|
|
9
|
+
import type { RuntimeContext } from './RuntimeContext.js';
|
|
9
10
|
export declare class NetworkMonitor extends EventEmitter {
|
|
11
|
+
private readonly runtime;
|
|
10
12
|
private isOnline;
|
|
11
13
|
private lastOnlineCheck;
|
|
12
|
-
constructor();
|
|
14
|
+
constructor(runtime?: RuntimeContext);
|
|
13
15
|
private handleOnline;
|
|
14
16
|
private handleOffline;
|
|
15
17
|
/**
|
package/dist/NetworkMonitor.js
CHANGED
|
@@ -6,15 +6,17 @@
|
|
|
6
6
|
* firing, so returning to the tab emits a recovery signal the store can act on.
|
|
7
7
|
*/
|
|
8
8
|
import { EventEmitter } from 'events';
|
|
9
|
-
import {
|
|
9
|
+
import { globalRuntime } from './context.js';
|
|
10
10
|
export class NetworkMonitor extends EventEmitter {
|
|
11
|
+
runtime;
|
|
11
12
|
// Only `navigator.onLine === false` means offline. Node 18+ exposes a global
|
|
12
13
|
// `navigator` with `onLine === undefined`, so the naive `navigator.onLine`
|
|
13
14
|
// would seed `false` (offline) on every server client — start optimistic.
|
|
14
15
|
isOnline = !(typeof navigator !== 'undefined' && navigator.onLine === false);
|
|
15
16
|
lastOnlineCheck = new Date();
|
|
16
|
-
constructor() {
|
|
17
|
+
constructor(runtime = globalRuntime) {
|
|
17
18
|
super();
|
|
19
|
+
this.runtime = runtime;
|
|
18
20
|
this.setupListeners();
|
|
19
21
|
}
|
|
20
22
|
handleOnline = () => {
|
|
@@ -22,7 +24,7 @@ export class NetworkMonitor extends EventEmitter {
|
|
|
22
24
|
this.isOnline = true;
|
|
23
25
|
this.lastOnlineCheck = new Date();
|
|
24
26
|
if (wasOffline) {
|
|
25
|
-
|
|
27
|
+
this.runtime.logger.info('Network connection restored');
|
|
26
28
|
this.emit('online');
|
|
27
29
|
}
|
|
28
30
|
};
|
|
@@ -32,7 +34,7 @@ export class NetworkMonitor extends EventEmitter {
|
|
|
32
34
|
if (wasOnline) {
|
|
33
35
|
// Symmetric with 'Network connection restored' (info) — expected,
|
|
34
36
|
// transient connectivity state, not an actionable warning.
|
|
35
|
-
|
|
37
|
+
this.runtime.logger.info('Network connection lost');
|
|
36
38
|
this.emit('offline');
|
|
37
39
|
}
|
|
38
40
|
};
|
|
@@ -49,7 +51,7 @@ export class NetworkMonitor extends EventEmitter {
|
|
|
49
51
|
this.isOnline = navigator.onLine;
|
|
50
52
|
this.lastOnlineCheck = new Date();
|
|
51
53
|
if (this.isOnline) {
|
|
52
|
-
|
|
54
|
+
this.runtime.logger.info('Tab became visible with network available — emitting visibility_online');
|
|
53
55
|
this.emit('visibility_online');
|
|
54
56
|
}
|
|
55
57
|
};
|
package/dist/SyncClient.d.ts
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { InstanceCache } from './InstanceCache.js';
|
|
11
11
|
import { Model } from './Model.js';
|
|
12
|
+
import type { AppliedChange } from './transaction/plugin.js';
|
|
13
|
+
import type { RuntimeContext } from './RuntimeContext.js';
|
|
12
14
|
import { EventEmitter } from 'events';
|
|
13
15
|
import { MutationQueue } from './transactions/mutations/MutationQueue.js';
|
|
14
16
|
import { type CommitLatencySample } from './transactions/mutations/commitLatency.js';
|
|
@@ -42,6 +44,7 @@ export interface RehydrationStats {
|
|
|
42
44
|
elapsedMs: number;
|
|
43
45
|
}
|
|
44
46
|
export declare class SyncClient extends EventEmitter {
|
|
47
|
+
private readonly runtime;
|
|
45
48
|
private objectPool;
|
|
46
49
|
private database;
|
|
47
50
|
private get mutationExecutor();
|
|
@@ -77,7 +80,7 @@ export declare class SyncClient extends EventEmitter {
|
|
|
77
80
|
* responses, and snapshots and claims read `readFloor`.
|
|
78
81
|
*/
|
|
79
82
|
readonly position: LogPosition;
|
|
80
|
-
constructor(objectPool: InstanceCache, database: Database, commitOutbox?: DurableWriteStore, commitOutboxNamespace?: string);
|
|
83
|
+
constructor(objectPool: InstanceCache, database: Database, commitOutbox?: DurableWriteStore, commitOutboxNamespace?: string, runtime?: RuntimeContext);
|
|
81
84
|
/**
|
|
82
85
|
* Setup network monitoring handlers
|
|
83
86
|
*/
|
|
@@ -508,20 +511,7 @@ export declare class SyncClient extends EventEmitter {
|
|
|
508
511
|
* consumers; `Ablo` is the public surface.
|
|
509
512
|
*/
|
|
510
513
|
getMutationQueue(): MutationQueue;
|
|
511
|
-
applyDeltaBatchToPool(dbResults:
|
|
512
|
-
action: string;
|
|
513
|
-
modelName: string;
|
|
514
|
-
modelId: string;
|
|
515
|
-
data?: Record<string, unknown> | null;
|
|
516
|
-
/**
|
|
517
|
-
* Server-stamped transaction id, echoing the client's commit op
|
|
518
|
-
* id. Used by echo detection to recognize "this is the
|
|
519
|
-
* confirmation of a mutation I've already applied locally."
|
|
520
|
-
* Optional because system-emitted deltas (sync_group changes,
|
|
521
|
-
* schema-derived deltas, etc.) don't have a client transaction.
|
|
522
|
-
*/
|
|
523
|
-
transactionId?: string;
|
|
524
|
-
}[], enrichRelations: (modelName: string, data: Record<string, unknown>) => Record<string, unknown>): void;
|
|
514
|
+
applyDeltaBatchToPool(dbResults: readonly AppliedChange[], enrichRelations: (modelName: string, data: Record<string, unknown>) => Record<string, unknown>): void;
|
|
525
515
|
/**
|
|
526
516
|
* Apply bootstrap data to the InstanceCache with ghost removal.
|
|
527
517
|
* Owns: model creation, batch upsert, ghost detection + removal.
|