@feltdb/core 0.6.13 → 0.7.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/README.md +32 -0
- package/dist/agent-registry.js +1 -3
- package/dist/agent-runtime.js +8 -7
- package/dist/analytics-backend.js +3 -1
- package/dist/application-contract.js +1 -0
- package/dist/application-manifest.js +1 -0
- package/dist/artifact.js +2 -0
- package/dist/authorization.js +2 -0
- package/dist/bundle.js +2 -0
- package/dist/capability.js +1 -3
- package/dist/cell.js +9 -4
- package/dist/cli/commands.js +26 -2
- package/dist/cli/index.js +1 -1
- package/dist/collection.js +39 -31
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +613 -27
- package/dist/create/server-source/crates/feltdb/src/causal_backlog_bound.rs +452 -0
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +208 -0
- package/dist/create/server-source/crates/feltdb/src/convergence.rs +16 -0
- package/dist/create/server-source/crates/feltdb/src/dedup_bound_investigation.rs +402 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +784 -24
- package/dist/create/server-source/crates/feltdb/src/durable_operation_identity.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/lib.rs +284 -0
- package/dist/create/server-source/crates/feltdb/src/replica_acknowledgements.rs +471 -0
- package/dist/create/server-source/crates/feltdb/src/replica_membership.rs +661 -0
- package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +72 -3
- package/dist/create/server-source/crates/feltdb/src/transaction_preconditions.rs +899 -0
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +116 -4
- package/dist/db.d.ts +2 -2
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +48 -15
- package/dist/development-runtime-bridge.js +1 -1
- package/dist/distributed-indexing.js +7 -5
- package/dist/embedded-transaction.d.ts +9 -0
- package/dist/embedded-transaction.d.ts.map +1 -1
- package/dist/embedded-transaction.js +95 -3
- package/dist/feltdb.d.ts +16 -0
- package/dist/feltdb.d.ts.map +1 -1
- package/dist/file-db.d.ts.map +1 -1
- package/dist/file-db.js +9 -3
- package/dist/flowspec.js +2 -1
- package/dist/http-client.js +2 -0
- package/dist/http-db.d.ts +11 -0
- package/dist/http-db.d.ts.map +1 -1
- package/dist/http-db.js +32 -3
- package/dist/identity.js +1 -0
- package/dist/index-analytics.js +6 -7
- package/dist/index-backend.js +3 -3
- package/dist/index-dashboard.js +10 -13
- package/dist/index-manager.js +12 -11
- package/dist/index-monitoring.js +9 -4
- package/dist/index-store.js +2 -0
- package/dist/indexeddb-db.d.ts.map +1 -1
- package/dist/indexeddb-db.js +32 -23
- package/dist/memory-db.d.ts.map +1 -1
- package/dist/memory-db.js +8 -4
- package/dist/observe.js +2 -0
- package/dist/provider.js +2 -0
- package/dist/query-planner.js +2 -4
- package/dist/reactive-graph.js +6 -8
- package/dist/release.js +2 -0
- package/dist/sharding.js +11 -6
- package/dist/state-contract.js +3 -3
- package/dist/studio-app/assets/{feltdb_wasm-CJv3wHzi.js → feltdb_wasm-CD744e5D.js} +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-CiIXhOLi.wasm +0 -0
- package/dist/studio-app/assets/index-DoROs8yx.js +28 -0
- package/dist/studio-app/index.html +1 -1
- package/dist/sync-contract.js +9 -2
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +32 -12
- package/dist/transaction.d.ts +127 -9
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +91 -5
- package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
- package/dist/worker.js +2 -0
- package/dist/workload.js +2 -0
- package/dist/workspace/development-node.js +11 -10
- package/dist/workspace/investigation-lifecycle-manager.js +2 -0
- package/dist/workspace/investigation-supervisor.js +5 -3
- package/dist/workspace/workspace-connection.js +14 -5
- package/package.json +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-C8TG8r2n.wasm +0 -0
- package/dist/studio-app/assets/index-DospFFYE.js +0 -28
package/README.md
CHANGED
|
@@ -75,6 +75,38 @@ Browser mutations resolve after their IndexedDB transaction commits. The
|
|
|
75
75
|
durable change journal replays after reload and coordinates live collections
|
|
76
76
|
across tabs through `BroadcastChannel` when available.
|
|
77
77
|
|
|
78
|
+
## Atomic conditional transactions
|
|
79
|
+
|
|
80
|
+
Core 0.7.0 can fence a multi-record transaction on the exact version read by
|
|
81
|
+
the caller. The transaction either commits every operation or writes nothing:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { ConditionalConflictError } from '@feltdb/core';
|
|
85
|
+
|
|
86
|
+
const current = await db.collection('accounts').get('primary');
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
await db.transaction({
|
|
90
|
+
transactionId: 'transfer-42',
|
|
91
|
+
preconditions: [
|
|
92
|
+
{ collection: 'accounts', id: 'primary', ifVersion: current.__version },
|
|
93
|
+
],
|
|
94
|
+
operations: [
|
|
95
|
+
{ collection: 'accounts', id: 'primary', value: { balance: 90 } },
|
|
96
|
+
{ collection: 'ledger', id: 'transfer-42', requireAbsent: true, value: { amount: 10 } },
|
|
97
|
+
],
|
|
98
|
+
});
|
|
99
|
+
} catch (error) {
|
|
100
|
+
if (error instanceof ConditionalConflictError) {
|
|
101
|
+
console.log(error.conflict);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Reusing a successful `transactionId` safely replays its result without
|
|
107
|
+
advancing record versions twice. This API requires a FeltDB authority that
|
|
108
|
+
supports transaction-level `ifVersion` preconditions.
|
|
109
|
+
|
|
78
110
|
## Durable Operation Management
|
|
79
111
|
|
|
80
112
|
FeltDB provides atomic operation admission and lifecycle management for systems that need to survive process crashes with guaranteed identity stability.
|
package/dist/agent-registry.js
CHANGED
package/dist/agent-runtime.js
CHANGED
|
@@ -9,10 +9,8 @@ import { AgentExecutionStatus, generateExecutionId } from './agent.js';
|
|
|
9
9
|
* Agent ownership manager for distributed execution
|
|
10
10
|
*/
|
|
11
11
|
export class AgentOwnershipManager {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
this.locks = new Map();
|
|
15
|
-
}
|
|
12
|
+
ownership = new Map(); // executionId -> peerId
|
|
13
|
+
locks = new Map();
|
|
16
14
|
/**
|
|
17
15
|
* Claim ownership of an execution
|
|
18
16
|
*/
|
|
@@ -86,10 +84,13 @@ export class AgentOwnershipManager {
|
|
|
86
84
|
* Manages agent lifecycle and execution across the distributed fabric.
|
|
87
85
|
*/
|
|
88
86
|
export class AgentRuntime {
|
|
87
|
+
config;
|
|
88
|
+
registry;
|
|
89
|
+
handlers = new Map();
|
|
90
|
+
executions = new Map();
|
|
91
|
+
ownership;
|
|
92
|
+
triggers = new Map();
|
|
89
93
|
constructor(registry, config) {
|
|
90
|
-
this.handlers = new Map();
|
|
91
|
-
this.executions = new Map();
|
|
92
|
-
this.triggers = new Map();
|
|
93
94
|
this.registry = registry;
|
|
94
95
|
this.config = config;
|
|
95
96
|
this.ownership = new AgentOwnershipManager();
|
|
@@ -10,8 +10,9 @@ import { IndexAnalytics as TypeScriptIndexAnalytics } from './index-analytics.js
|
|
|
10
10
|
* Analytics backend selector with dynamic WASM loading
|
|
11
11
|
*/
|
|
12
12
|
export class AnalyticsBackend {
|
|
13
|
+
backend;
|
|
14
|
+
wasmLoaded = false;
|
|
13
15
|
constructor() {
|
|
14
|
-
this.wasmLoaded = false;
|
|
15
16
|
// Start with TypeScript backend, attempt WASM load async
|
|
16
17
|
// Create a wrapper that implements the interface
|
|
17
18
|
const tsBackend = new TypeScriptIndexAnalytics();
|
|
@@ -76,6 +77,7 @@ export class AnalyticsBackend {
|
|
|
76
77
|
* Adapter to bridge WASM analytics to TypeScript interface
|
|
77
78
|
*/
|
|
78
79
|
class WasmAnalyticsAdapter {
|
|
80
|
+
wasm;
|
|
79
81
|
constructor(wasm) {
|
|
80
82
|
this.wasm = wasm;
|
|
81
83
|
}
|
package/dist/artifact.js
CHANGED
package/dist/authorization.js
CHANGED
package/dist/bundle.js
CHANGED
package/dist/capability.js
CHANGED
|
@@ -4,9 +4,7 @@
|
|
|
4
4
|
* Capabilities are distributed, pluggable features like search, vector embeddings, etc.
|
|
5
5
|
*/
|
|
6
6
|
export class CapabilityRegistry {
|
|
7
|
-
|
|
8
|
-
this.capabilities = new Map();
|
|
9
|
-
}
|
|
7
|
+
capabilities = new Map();
|
|
10
8
|
register(capability) {
|
|
11
9
|
this.capabilities.set(capability.id, capability);
|
|
12
10
|
}
|
package/dist/cell.js
CHANGED
|
@@ -16,11 +16,16 @@ export const AUTHORITY_CONFLICT = Symbol('FELTDB_AUTHORITY_CONFLICT');
|
|
|
16
16
|
* A replica is read-only: replication transfers knowledge, not authority.
|
|
17
17
|
*/
|
|
18
18
|
export class CellImpl {
|
|
19
|
+
id;
|
|
20
|
+
jsDb;
|
|
21
|
+
cellCollection;
|
|
22
|
+
replicaCollection;
|
|
23
|
+
failureObservationCollection;
|
|
24
|
+
mutationQueue = [];
|
|
25
|
+
isLocked = false;
|
|
26
|
+
changeHandlers = [];
|
|
27
|
+
isReplica = false;
|
|
19
28
|
constructor(jsDb, cellId) {
|
|
20
|
-
this.mutationQueue = [];
|
|
21
|
-
this.isLocked = false;
|
|
22
|
-
this.changeHandlers = [];
|
|
23
|
-
this.isReplica = false;
|
|
24
29
|
this.id = cellId;
|
|
25
30
|
this.jsDb = jsDb;
|
|
26
31
|
this.cellCollection = new Collection(jsDb, '_cells', undefined, undefined, false);
|
package/dist/cli/commands.js
CHANGED
|
@@ -719,7 +719,14 @@ async function handleDev(args) {
|
|
|
719
719
|
throw error;
|
|
720
720
|
}
|
|
721
721
|
let stopping = null;
|
|
722
|
+
// The development session runs until something stops it — a signal, a managed
|
|
723
|
+
// application exiting, or a failure. Its lifetime belongs to this command, so
|
|
724
|
+
// it is represented explicitly rather than borrowed from whichever service
|
|
725
|
+
// happens to be long-running.
|
|
726
|
+
let releaseSession = () => { };
|
|
727
|
+
const sessionStopped = new Promise(resolve => { releaseSession = resolve; });
|
|
722
728
|
const stopAll = () => stopping ?? (stopping = (async () => {
|
|
729
|
+
releaseSession();
|
|
723
730
|
if (developmentSession && developmentSession.state !== 'STOPPING' && developmentSession.state !== 'STOPPED') {
|
|
724
731
|
transitionDevelopmentSession(developmentSession, 'STOPPING');
|
|
725
732
|
}
|
|
@@ -830,13 +837,30 @@ async function handleDev(args) {
|
|
|
830
837
|
}
|
|
831
838
|
transitionDevelopmentSession(developmentSession, 'RUNNING');
|
|
832
839
|
});
|
|
840
|
+
// Studio is one service in the session, not the session itself.
|
|
841
|
+
// `handleStudio` returns immediately when Studio's static assets are absent,
|
|
842
|
+
// and awaiting it as the session's lifetime meant a missing optional
|
|
843
|
+
// artifact tore down the authority, the pairing discovery server, and the
|
|
844
|
+
// workspace transport: the process printed "workspace is ready" and then
|
|
845
|
+
// exited, so anything reaching for the discovery endpoint afterwards got a
|
|
846
|
+
// connection failure. The session now outlives Studio either way.
|
|
847
|
+
void studio.then(() => {
|
|
848
|
+
if (!developmentSession || developmentSession.state === 'RUNNING')
|
|
849
|
+
return;
|
|
850
|
+
console.log('\u26a0\ufe0f Studio is unavailable for this session. The authority, pairing discovery, and workspace transport are unaffected.');
|
|
851
|
+
transitionDevelopmentSession(developmentSession, 'READY');
|
|
852
|
+
console.log(`\n${developmentSessionSummary(developmentSession)}\n`);
|
|
853
|
+
transitionDevelopmentSession(developmentSession, 'RUNNING');
|
|
854
|
+
}).catch(error => {
|
|
855
|
+
console.error(`Studio failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
856
|
+
});
|
|
833
857
|
if (managedApplication) {
|
|
834
|
-
await Promise.race([
|
|
858
|
+
await Promise.race([sessionStopped, managedApplication.exited.then(exit => {
|
|
835
859
|
throw new Error(`Managed application stopped during the development session (command: ${managedApplication.command}; exit: ${exit.code ?? exit.signal})`);
|
|
836
860
|
})]);
|
|
837
861
|
}
|
|
838
862
|
else
|
|
839
|
-
await
|
|
863
|
+
await sessionStopped;
|
|
840
864
|
}
|
|
841
865
|
finally {
|
|
842
866
|
await stopAll();
|
package/dist/cli/index.js
CHANGED
|
@@ -23,7 +23,7 @@ import * as path from 'path';
|
|
|
23
23
|
import * as readline from 'readline';
|
|
24
24
|
import { getClient } from './api-client.js';
|
|
25
25
|
import { loadFeltDBConfig, createDefaultConfig, validateModel, } from './config.js';
|
|
26
|
-
const VERSION = '0.6.
|
|
26
|
+
const VERSION = '0.6.14';
|
|
27
27
|
function prompt(question) {
|
|
28
28
|
const rl = readline.createInterface({
|
|
29
29
|
input: process.stdin,
|
package/dist/collection.js
CHANGED
|
@@ -18,38 +18,42 @@ import { IndexStore } from './index-store.js';
|
|
|
18
18
|
* Uses reactive dependency graph instead of polling for efficient updates.
|
|
19
19
|
*/
|
|
20
20
|
export class Collection {
|
|
21
|
+
db;
|
|
22
|
+
name;
|
|
23
|
+
collectionId; // Unique ID for this collection instance
|
|
24
|
+
predicate = null;
|
|
25
|
+
cache = [];
|
|
26
|
+
subscribers = new Set();
|
|
27
|
+
parent = null;
|
|
28
|
+
parentId = null;
|
|
29
|
+
isInitialized = false;
|
|
30
|
+
unsubscribeFunctions = new Set();
|
|
31
|
+
graphUnsubscribe = null;
|
|
32
|
+
runtimeUnsubscribe = null;
|
|
33
|
+
indexBackend = new IndexBackend();
|
|
34
|
+
indexStore;
|
|
35
|
+
indexesLoaded = false;
|
|
36
|
+
/** Incremented whenever `cache` is replaced, so the index can tell it is stale. */
|
|
37
|
+
cacheGeneration = 0;
|
|
38
|
+
/** The cache generation the index entries currently reflect, or -1 for none. */
|
|
39
|
+
indexedGeneration = -1;
|
|
40
|
+
lastPlan = null;
|
|
41
|
+
/** Cache records addressed by id, valid for `indexedGeneration`. */
|
|
42
|
+
recordsById = null;
|
|
43
|
+
/** Raw payload the cache was parsed from, used to detect that nothing changed. */
|
|
44
|
+
lastRawSnapshot = null;
|
|
45
|
+
/**
|
|
46
|
+
* The runtime revision the cache was built from, when the runtime offers one.
|
|
47
|
+
*
|
|
48
|
+
* Captured *before* the query that produced the cache, never after. A write
|
|
49
|
+
* landing between the two then makes this older than the data it labels,
|
|
50
|
+
* which costs one unnecessary refresh. Capturing it after would make it
|
|
51
|
+
* newer than the data, and the cache would look current forever.
|
|
52
|
+
*/
|
|
53
|
+
cachedRevision = null;
|
|
54
|
+
/** How the last refresh decided the cache was usable. Reporting only. */
|
|
55
|
+
lastFreshness = null;
|
|
21
56
|
constructor(db, name, predicate, parent, loadIndexes = true) {
|
|
22
|
-
this.predicate = null;
|
|
23
|
-
this.cache = [];
|
|
24
|
-
this.subscribers = new Set();
|
|
25
|
-
this.parent = null;
|
|
26
|
-
this.parentId = null;
|
|
27
|
-
this.isInitialized = false;
|
|
28
|
-
this.unsubscribeFunctions = new Set();
|
|
29
|
-
this.graphUnsubscribe = null;
|
|
30
|
-
this.runtimeUnsubscribe = null;
|
|
31
|
-
this.indexBackend = new IndexBackend();
|
|
32
|
-
this.indexesLoaded = false;
|
|
33
|
-
/** Incremented whenever `cache` is replaced, so the index can tell it is stale. */
|
|
34
|
-
this.cacheGeneration = 0;
|
|
35
|
-
/** The cache generation the index entries currently reflect, or -1 for none. */
|
|
36
|
-
this.indexedGeneration = -1;
|
|
37
|
-
this.lastPlan = null;
|
|
38
|
-
/** Cache records addressed by id, valid for `indexedGeneration`. */
|
|
39
|
-
this.recordsById = null;
|
|
40
|
-
/** Raw payload the cache was parsed from, used to detect that nothing changed. */
|
|
41
|
-
this.lastRawSnapshot = null;
|
|
42
|
-
/**
|
|
43
|
-
* The runtime revision the cache was built from, when the runtime offers one.
|
|
44
|
-
*
|
|
45
|
-
* Captured *before* the query that produced the cache, never after. A write
|
|
46
|
-
* landing between the two then makes this older than the data it labels,
|
|
47
|
-
* which costs one unnecessary refresh. Capturing it after would make it
|
|
48
|
-
* newer than the data, and the cache would look current forever.
|
|
49
|
-
*/
|
|
50
|
-
this.cachedRevision = null;
|
|
51
|
-
/** How the last refresh decided the cache was usable. Reporting only. */
|
|
52
|
-
this.lastFreshness = null;
|
|
53
57
|
this.db = db;
|
|
54
58
|
this.name = name;
|
|
55
59
|
this.collectionId = `${name}-${Math.random().toString(36).substr(2, 9)}`;
|
|
@@ -690,6 +694,10 @@ export class Collection {
|
|
|
690
694
|
* Relationship helper for loading related data.
|
|
691
695
|
*/
|
|
692
696
|
export class Relationship {
|
|
697
|
+
parentDb;
|
|
698
|
+
childDb;
|
|
699
|
+
childCollection;
|
|
700
|
+
foreignKey;
|
|
693
701
|
constructor(parentDb, childDb, childCollection, foreignKey) {
|
|
694
702
|
this.parentDb = parentDb;
|
|
695
703
|
this.childDb = childDb;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// One release train keeps generated applications installable. The repository
|
|
2
2
|
// validation script checks these values against every workspace manifest.
|
|
3
|
-
export const FELTDB_PACKAGE_VERSION = '0.6.
|
|
3
|
+
export const FELTDB_PACKAGE_VERSION = '0.6.14';
|
|
4
4
|
export const feltdbPackageRange = `^${FELTDB_PACKAGE_VERSION}`;
|