@rljson/db 0.0.13 → 0.0.14
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.architecture.md +62 -0
- package/README.public.md +73 -0
- package/dist/README.architecture.md +62 -0
- package/dist/README.public.md +73 -0
- package/dist/connector/connector.d.ts +71 -10
- package/dist/db.d.ts +23 -1
- package/dist/db.js +250 -24
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/package.json +17 -17
package/README.architecture.md
CHANGED
|
@@ -777,6 +777,68 @@ describe('Tree WHERE clause fix', () => {
|
|
|
777
777
|
});
|
|
778
778
|
```
|
|
779
779
|
|
|
780
|
+
## Connector (Sync Protocol)
|
|
781
|
+
|
|
782
|
+
The `Connector` class implements the client side of the RLJSON sync protocol. It sits between a local `Db` and a socket, enriching outgoing refs with protocol metadata and processing incoming refs with safety guarantees.
|
|
783
|
+
|
|
784
|
+
### Responsibilities
|
|
785
|
+
|
|
786
|
+
```
|
|
787
|
+
┌────────────────────────────────────────────────┐
|
|
788
|
+
│ Connector │
|
|
789
|
+
│ │
|
|
790
|
+
│ Outgoing path (Db → socket): │
|
|
791
|
+
│ 1. Db.notify fires with InsertHistoryRow │
|
|
792
|
+
│ 2. Auto-populate predecessors from │
|
|
793
|
+
│ InsertHistoryRow.previous │
|
|
794
|
+
│ 3. Enrich with seq, c, t, p (per config) │
|
|
795
|
+
│ 4. Add to sent-refs dedup set │
|
|
796
|
+
│ 5. Emit ConnectorPayload on socket │
|
|
797
|
+
│ │
|
|
798
|
+
│ Incoming path (socket → callbacks): │
|
|
799
|
+
│ 1. Receive ConnectorPayload from socket │
|
|
800
|
+
│ 2. Reject self-echo (origin === own origin) │
|
|
801
|
+
│ 3. Reject duplicate (ref already received) │
|
|
802
|
+
│ 4. Detect sequence gaps → request gap-fill │
|
|
803
|
+
│ 5. Emit client ACK (if requireAck) │
|
|
804
|
+
│ 6. Invoke listen() callbacks │
|
|
805
|
+
└────────────────────────────────────────────────┘
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
### Bounded dedup strategy
|
|
809
|
+
|
|
810
|
+
The Connector tracks recently sent and received refs to prevent duplicates. Both sets use **two-generation eviction**:
|
|
811
|
+
|
|
812
|
+
1. A `current` Set accumulates refs.
|
|
813
|
+
2. When `current.size ≥ maxDedupSetSize`, it rotates: `previous = current`, `current = new Set()`.
|
|
814
|
+
3. Lookups check **both** `current` and `previous`.
|
|
815
|
+
4. This caps memory at ≈ 2 × `maxDedupSetSize` entries (default 10 000 per generation).
|
|
816
|
+
|
|
817
|
+
The eviction is O(1) — no per-entry bookkeeping — and avoids the overhead of a full LRU cache.
|
|
818
|
+
|
|
819
|
+
### Auto-predecessor from InsertHistory
|
|
820
|
+
|
|
821
|
+
When `causalOrdering` is enabled, the Connector's Db observer reads the `previous` field from each `InsertHistoryRow` emitted by `Db.notify`. These `InsertHistoryTimeId` values become the `p` (predecessors) array in the outgoing `ConnectorPayload`. This eliminates the need for manual `setPredecessors()` calls in normal database-driven workflows.
|
|
822
|
+
|
|
823
|
+
### listen()
|
|
824
|
+
|
|
825
|
+
`listen()` registers callbacks that receive incoming refs through the full sync pipeline: origin filtering, dedup, gap detection, and ACK. All protocol safeguards are applied before callbacks are invoked.
|
|
826
|
+
|
|
827
|
+
### sendWithAck ordering
|
|
828
|
+
|
|
829
|
+
The `sendWithAck()` method registers the ACK listener **before** emitting the ref on the socket. This prevents a race condition with synchronous transports (e.g., in-memory sockets used in tests) where the ACK fires during `send()` and would be lost if the listener were registered after.
|
|
830
|
+
|
|
831
|
+
### Bootstrap handler
|
|
832
|
+
|
|
833
|
+
The Connector registers a listener on `events.bootstrap` in `_init()` via `_registerBootstrapHandler()`. When the server sends a bootstrap message (latest ref on connect, or periodic heartbeat), the handler feeds the `ConnectorPayload` directly into `_processIncoming()`. This means:
|
|
834
|
+
|
|
835
|
+
- **Dedup**: Refs already received via multicast are filtered out automatically
|
|
836
|
+
- **Gap detection**: If `causalOrdering` is enabled, bootstrap refs participate in sequence tracking
|
|
837
|
+
- **Callbacks**: `listen()` callbacks fire for genuinely new refs
|
|
838
|
+
- **ACK**: If `requireAck` is enabled, client ACKs are sent back
|
|
839
|
+
|
|
840
|
+
The `tearDown()` method cleans up the bootstrap listener alongside all other socket listeners.
|
|
841
|
+
|
|
780
842
|
## Future Enhancements
|
|
781
843
|
|
|
782
844
|
### Planned Features
|
package/README.public.md
CHANGED
|
@@ -906,6 +906,79 @@ const db = new Db(multi);
|
|
|
906
906
|
// Priority: io1 > io2 > io3
|
|
907
907
|
```
|
|
908
908
|
|
|
909
|
+
## Connector (sync protocol)
|
|
910
|
+
|
|
911
|
+
The `Connector` bridges a local `Db` with a remote server via socket events. It enriches outgoing refs with protocol metadata and processes incoming refs with dedup, origin filtering, and gap detection.
|
|
912
|
+
|
|
913
|
+
### Creating a Connector
|
|
914
|
+
|
|
915
|
+
```typescript
|
|
916
|
+
import { Connector } from '@rljson/db';
|
|
917
|
+
import { Route } from '@rljson/rljson';
|
|
918
|
+
import type { SyncConfig } from '@rljson/rljson';
|
|
919
|
+
|
|
920
|
+
const route = Route.fromFlat('/sharedTree');
|
|
921
|
+
|
|
922
|
+
// Minimal — no enrichment
|
|
923
|
+
const connector = new Connector(db, route, socket);
|
|
924
|
+
|
|
925
|
+
// With sync config — enables enriched payloads
|
|
926
|
+
const syncConfig: SyncConfig = {
|
|
927
|
+
causalOrdering: true,
|
|
928
|
+
requireAck: true,
|
|
929
|
+
ackTimeoutMs: 5_000,
|
|
930
|
+
includeClientIdentity: true,
|
|
931
|
+
maxDedupSetSize: 10_000,
|
|
932
|
+
};
|
|
933
|
+
const connector = new Connector(db, route, socket, { syncConfig });
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
### Sending refs
|
|
937
|
+
|
|
938
|
+
```typescript
|
|
939
|
+
// Fire-and-forget
|
|
940
|
+
connector.send(ref);
|
|
941
|
+
|
|
942
|
+
// Wait for server ACK (requires requireAck: true)
|
|
943
|
+
const ack = await connector.sendWithAck(ref);
|
|
944
|
+
// ack: { r, ok, receivedBy, totalClients }
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
### Receiving refs
|
|
948
|
+
|
|
949
|
+
```typescript
|
|
950
|
+
// Safe callback with dedup, origin filtering, gap detection
|
|
951
|
+
connector.listen(async (ref) => {
|
|
952
|
+
console.log('New ref:', ref);
|
|
953
|
+
});
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
### Predecessors
|
|
957
|
+
|
|
958
|
+
When `causalOrdering` is enabled, the Connector automatically populates the `p` (predecessors) field from the `InsertHistoryRow.previous` array whenever the local Db notifies about a new insert. No manual call to `setPredecessors()` is needed for standard database-driven sends.
|
|
959
|
+
|
|
960
|
+
```typescript
|
|
961
|
+
// Manual override (advanced) — sets predecessors for the NEXT send only
|
|
962
|
+
connector.setPredecessors(['1700000000000:AbCd']);
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
### Bounded dedup
|
|
966
|
+
|
|
967
|
+
The Connector tracks recently sent and received refs to prevent duplicates. The dedup sets use **two-generation eviction**: when the current set reaches `maxDedupSetSize` (default 10 000), it rotates to previous and a new current set starts. Lookups check both generations. This caps memory usage at ≈ 2 × `maxDedupSetSize` entries.
|
|
968
|
+
|
|
969
|
+
### Bootstrap handling
|
|
970
|
+
|
|
971
|
+
The Connector automatically listens for `${route}:bootstrap` events from the server. When a client joins after data has already been sent, the server pushes the latest ref via this event. The Connector feeds it into `_processIncoming()`, so dedup, gap detection, and `listen()` callbacks all work identically to regular multicast refs.
|
|
972
|
+
|
|
973
|
+
No additional setup is needed — the bootstrap handler is registered in `_init()` and cleaned up in `tearDown()`.
|
|
974
|
+
|
|
975
|
+
### Cleanup
|
|
976
|
+
|
|
977
|
+
```typescript
|
|
978
|
+
connector.tearDown();
|
|
979
|
+
// Removes all socket listeners and clears internal state
|
|
980
|
+
```
|
|
981
|
+
|
|
909
982
|
## Examples
|
|
910
983
|
|
|
911
984
|
See [src/example.ts](src/example.ts) for a complete working example demonstrating:
|
|
@@ -777,6 +777,68 @@ describe('Tree WHERE clause fix', () => {
|
|
|
777
777
|
});
|
|
778
778
|
```
|
|
779
779
|
|
|
780
|
+
## Connector (Sync Protocol)
|
|
781
|
+
|
|
782
|
+
The `Connector` class implements the client side of the RLJSON sync protocol. It sits between a local `Db` and a socket, enriching outgoing refs with protocol metadata and processing incoming refs with safety guarantees.
|
|
783
|
+
|
|
784
|
+
### Responsibilities
|
|
785
|
+
|
|
786
|
+
```
|
|
787
|
+
┌────────────────────────────────────────────────┐
|
|
788
|
+
│ Connector │
|
|
789
|
+
│ │
|
|
790
|
+
│ Outgoing path (Db → socket): │
|
|
791
|
+
│ 1. Db.notify fires with InsertHistoryRow │
|
|
792
|
+
│ 2. Auto-populate predecessors from │
|
|
793
|
+
│ InsertHistoryRow.previous │
|
|
794
|
+
│ 3. Enrich with seq, c, t, p (per config) │
|
|
795
|
+
│ 4. Add to sent-refs dedup set │
|
|
796
|
+
│ 5. Emit ConnectorPayload on socket │
|
|
797
|
+
│ │
|
|
798
|
+
│ Incoming path (socket → callbacks): │
|
|
799
|
+
│ 1. Receive ConnectorPayload from socket │
|
|
800
|
+
│ 2. Reject self-echo (origin === own origin) │
|
|
801
|
+
│ 3. Reject duplicate (ref already received) │
|
|
802
|
+
│ 4. Detect sequence gaps → request gap-fill │
|
|
803
|
+
│ 5. Emit client ACK (if requireAck) │
|
|
804
|
+
│ 6. Invoke listen() callbacks │
|
|
805
|
+
└────────────────────────────────────────────────┘
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
### Bounded dedup strategy
|
|
809
|
+
|
|
810
|
+
The Connector tracks recently sent and received refs to prevent duplicates. Both sets use **two-generation eviction**:
|
|
811
|
+
|
|
812
|
+
1. A `current` Set accumulates refs.
|
|
813
|
+
2. When `current.size ≥ maxDedupSetSize`, it rotates: `previous = current`, `current = new Set()`.
|
|
814
|
+
3. Lookups check **both** `current` and `previous`.
|
|
815
|
+
4. This caps memory at ≈ 2 × `maxDedupSetSize` entries (default 10 000 per generation).
|
|
816
|
+
|
|
817
|
+
The eviction is O(1) — no per-entry bookkeeping — and avoids the overhead of a full LRU cache.
|
|
818
|
+
|
|
819
|
+
### Auto-predecessor from InsertHistory
|
|
820
|
+
|
|
821
|
+
When `causalOrdering` is enabled, the Connector's Db observer reads the `previous` field from each `InsertHistoryRow` emitted by `Db.notify`. These `InsertHistoryTimeId` values become the `p` (predecessors) array in the outgoing `ConnectorPayload`. This eliminates the need for manual `setPredecessors()` calls in normal database-driven workflows.
|
|
822
|
+
|
|
823
|
+
### listen()
|
|
824
|
+
|
|
825
|
+
`listen()` registers callbacks that receive incoming refs through the full sync pipeline: origin filtering, dedup, gap detection, and ACK. All protocol safeguards are applied before callbacks are invoked.
|
|
826
|
+
|
|
827
|
+
### sendWithAck ordering
|
|
828
|
+
|
|
829
|
+
The `sendWithAck()` method registers the ACK listener **before** emitting the ref on the socket. This prevents a race condition with synchronous transports (e.g., in-memory sockets used in tests) where the ACK fires during `send()` and would be lost if the listener were registered after.
|
|
830
|
+
|
|
831
|
+
### Bootstrap handler
|
|
832
|
+
|
|
833
|
+
The Connector registers a listener on `events.bootstrap` in `_init()` via `_registerBootstrapHandler()`. When the server sends a bootstrap message (latest ref on connect, or periodic heartbeat), the handler feeds the `ConnectorPayload` directly into `_processIncoming()`. This means:
|
|
834
|
+
|
|
835
|
+
- **Dedup**: Refs already received via multicast are filtered out automatically
|
|
836
|
+
- **Gap detection**: If `causalOrdering` is enabled, bootstrap refs participate in sequence tracking
|
|
837
|
+
- **Callbacks**: `listen()` callbacks fire for genuinely new refs
|
|
838
|
+
- **ACK**: If `requireAck` is enabled, client ACKs are sent back
|
|
839
|
+
|
|
840
|
+
The `tearDown()` method cleans up the bootstrap listener alongside all other socket listeners.
|
|
841
|
+
|
|
780
842
|
## Future Enhancements
|
|
781
843
|
|
|
782
844
|
### Planned Features
|
package/dist/README.public.md
CHANGED
|
@@ -906,6 +906,79 @@ const db = new Db(multi);
|
|
|
906
906
|
// Priority: io1 > io2 > io3
|
|
907
907
|
```
|
|
908
908
|
|
|
909
|
+
## Connector (sync protocol)
|
|
910
|
+
|
|
911
|
+
The `Connector` bridges a local `Db` with a remote server via socket events. It enriches outgoing refs with protocol metadata and processes incoming refs with dedup, origin filtering, and gap detection.
|
|
912
|
+
|
|
913
|
+
### Creating a Connector
|
|
914
|
+
|
|
915
|
+
```typescript
|
|
916
|
+
import { Connector } from '@rljson/db';
|
|
917
|
+
import { Route } from '@rljson/rljson';
|
|
918
|
+
import type { SyncConfig } from '@rljson/rljson';
|
|
919
|
+
|
|
920
|
+
const route = Route.fromFlat('/sharedTree');
|
|
921
|
+
|
|
922
|
+
// Minimal — no enrichment
|
|
923
|
+
const connector = new Connector(db, route, socket);
|
|
924
|
+
|
|
925
|
+
// With sync config — enables enriched payloads
|
|
926
|
+
const syncConfig: SyncConfig = {
|
|
927
|
+
causalOrdering: true,
|
|
928
|
+
requireAck: true,
|
|
929
|
+
ackTimeoutMs: 5_000,
|
|
930
|
+
includeClientIdentity: true,
|
|
931
|
+
maxDedupSetSize: 10_000,
|
|
932
|
+
};
|
|
933
|
+
const connector = new Connector(db, route, socket, { syncConfig });
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
### Sending refs
|
|
937
|
+
|
|
938
|
+
```typescript
|
|
939
|
+
// Fire-and-forget
|
|
940
|
+
connector.send(ref);
|
|
941
|
+
|
|
942
|
+
// Wait for server ACK (requires requireAck: true)
|
|
943
|
+
const ack = await connector.sendWithAck(ref);
|
|
944
|
+
// ack: { r, ok, receivedBy, totalClients }
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
### Receiving refs
|
|
948
|
+
|
|
949
|
+
```typescript
|
|
950
|
+
// Safe callback with dedup, origin filtering, gap detection
|
|
951
|
+
connector.listen(async (ref) => {
|
|
952
|
+
console.log('New ref:', ref);
|
|
953
|
+
});
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
### Predecessors
|
|
957
|
+
|
|
958
|
+
When `causalOrdering` is enabled, the Connector automatically populates the `p` (predecessors) field from the `InsertHistoryRow.previous` array whenever the local Db notifies about a new insert. No manual call to `setPredecessors()` is needed for standard database-driven sends.
|
|
959
|
+
|
|
960
|
+
```typescript
|
|
961
|
+
// Manual override (advanced) — sets predecessors for the NEXT send only
|
|
962
|
+
connector.setPredecessors(['1700000000000:AbCd']);
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
### Bounded dedup
|
|
966
|
+
|
|
967
|
+
The Connector tracks recently sent and received refs to prevent duplicates. The dedup sets use **two-generation eviction**: when the current set reaches `maxDedupSetSize` (default 10 000), it rotates to previous and a new current set starts. Lookups check both generations. This caps memory usage at ≈ 2 × `maxDedupSetSize` entries.
|
|
968
|
+
|
|
969
|
+
### Bootstrap handling
|
|
970
|
+
|
|
971
|
+
The Connector automatically listens for `${route}:bootstrap` events from the server. When a client joins after data has already been sent, the server pushes the latest ref via this event. The Connector feeds it into `_processIncoming()`, so dedup, gap detection, and `listen()` callbacks all work identically to regular multicast refs.
|
|
972
|
+
|
|
973
|
+
No additional setup is needed — the bootstrap handler is registered in `_init()` and cleaned up in `tearDown()`.
|
|
974
|
+
|
|
975
|
+
### Cleanup
|
|
976
|
+
|
|
977
|
+
```typescript
|
|
978
|
+
connector.tearDown();
|
|
979
|
+
// Removes all socket listeners and clears internal state
|
|
980
|
+
```
|
|
981
|
+
|
|
909
982
|
## Examples
|
|
910
983
|
|
|
911
984
|
See [src/example.ts](src/example.ts) for a complete working example demonstrating:
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { Socket } from '@rljson/io';
|
|
2
|
-
import { Route } from '@rljson/rljson';
|
|
2
|
+
import { AckPayload, ClientId, InsertHistoryTimeId, Route, SyncConfig, SyncEventNames } from '@rljson/rljson';
|
|
3
3
|
import { Db } from '../db.ts';
|
|
4
|
-
export type ConnectorPayload
|
|
5
|
-
o: string;
|
|
6
|
-
r: string;
|
|
7
|
-
};
|
|
4
|
+
export type { ConnectorPayload } from '@rljson/rljson';
|
|
8
5
|
export type ConnectorCallback = (ref: string) => Promise<any>;
|
|
9
6
|
export declare class Connector {
|
|
10
7
|
private readonly _db;
|
|
@@ -13,15 +10,79 @@ export declare class Connector {
|
|
|
13
10
|
private _origin;
|
|
14
11
|
private _callbacks;
|
|
15
12
|
private _isListening;
|
|
16
|
-
private
|
|
17
|
-
private
|
|
18
|
-
|
|
13
|
+
private _sentRefsCurrent;
|
|
14
|
+
private _sentRefsPrevious;
|
|
15
|
+
private _receivedRefsCurrent;
|
|
16
|
+
private _receivedRefsPrevious;
|
|
17
|
+
private readonly _maxDedup;
|
|
18
|
+
private readonly _syncConfig;
|
|
19
|
+
private readonly _clientId;
|
|
20
|
+
private readonly _events;
|
|
21
|
+
private _seq;
|
|
22
|
+
private _lastPredecessors;
|
|
23
|
+
private _peerSeqs;
|
|
24
|
+
constructor(_db: Db, _route: Route, _socket: Socket, syncConfig?: SyncConfig, clientIdentity?: ClientId);
|
|
25
|
+
/**
|
|
26
|
+
* Sends a ref to the server via the socket.
|
|
27
|
+
* Enriches the payload based on SyncConfig flags.
|
|
28
|
+
* @param ref - The ref to send
|
|
29
|
+
*/
|
|
19
30
|
send(ref: string): void;
|
|
20
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Sends a ref and waits for server acknowledgment.
|
|
33
|
+
* Only meaningful when `syncConfig.requireAck` is `true`.
|
|
34
|
+
* @param ref - The ref to send
|
|
35
|
+
* @returns A promise that resolves with the AckPayload
|
|
36
|
+
*/
|
|
37
|
+
sendWithAck(ref: string): Promise<AckPayload>;
|
|
38
|
+
/**
|
|
39
|
+
* Sets the causal predecessors for the next send.
|
|
40
|
+
* @param predecessors - The InsertHistory timeIds of causal predecessors
|
|
41
|
+
*/
|
|
42
|
+
setPredecessors(predecessors: InsertHistoryTimeId[]): void;
|
|
43
|
+
/**
|
|
44
|
+
* Registers a callback for incoming refs on this route.
|
|
45
|
+
*
|
|
46
|
+
* Incoming refs are processed through the full sync pipeline:
|
|
47
|
+
* origin filtering, dedup, gap detection, and ACK.
|
|
48
|
+
*
|
|
49
|
+
* @param callback - The callback to invoke with each deduplicated incoming ref
|
|
50
|
+
*/
|
|
51
|
+
listen(callback: ConnectorCallback): void;
|
|
52
|
+
/**
|
|
53
|
+
* Returns the current sequence number.
|
|
54
|
+
* Only meaningful when `causalOrdering` is enabled.
|
|
55
|
+
*/
|
|
56
|
+
get seq(): number;
|
|
57
|
+
/**
|
|
58
|
+
* Returns the stable client identity.
|
|
59
|
+
* Only available when `includeClientIdentity` is enabled.
|
|
60
|
+
*/
|
|
61
|
+
get clientIdentity(): ClientId | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Returns the sync configuration, if any.
|
|
64
|
+
*/
|
|
65
|
+
get syncConfig(): SyncConfig | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Returns the typed event names for this connector's route.
|
|
68
|
+
*/
|
|
69
|
+
get events(): SyncEventNames;
|
|
21
70
|
private _init;
|
|
22
|
-
|
|
71
|
+
tearDown(): void;
|
|
72
|
+
private _hasSentRef;
|
|
73
|
+
private _addSentRef;
|
|
74
|
+
private _hasReceivedRef;
|
|
75
|
+
private _addReceivedRef;
|
|
23
76
|
private _notifyCallbacks;
|
|
77
|
+
private _processIncoming;
|
|
24
78
|
private _registerSocketObserver;
|
|
79
|
+
private _registerGapFillHandler;
|
|
80
|
+
/**
|
|
81
|
+
* Listens for bootstrap messages from the server.
|
|
82
|
+
* The server sends the latest ref on connect and optionally via heartbeat.
|
|
83
|
+
* _processIncoming handles dedup so already-seen refs are filtered out.
|
|
84
|
+
*/
|
|
85
|
+
private _registerBootstrapHandler;
|
|
25
86
|
private _registerDbObserver;
|
|
26
87
|
get socket(): Socket;
|
|
27
88
|
get route(): Route;
|
package/dist/db.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Io } from '@rljson/io';
|
|
2
2
|
import { Json, JsonValue } from '@rljson/json';
|
|
3
|
-
import { Edit, EditHistory, InsertHistoryRow, InsertHistoryTimeId, MultiEdit, Ref, Rljson, Route, SliceId, TableType } from '@rljson/rljson';
|
|
3
|
+
import { Edit, EditHistory, InsertHistoryRow, InsertHistoryTimeId, MultiEdit, Ref, Rljson, Route, SliceId, TableType, Tree } from '@rljson/rljson';
|
|
4
4
|
import { Controller, ControllerChildProperty, ControllerRefs } from './controller/controller.ts';
|
|
5
5
|
import { Core } from './core.ts';
|
|
6
6
|
import { Join } from './join/join.ts';
|
|
@@ -90,6 +90,28 @@ export declare class Db {
|
|
|
90
90
|
skipNotification?: boolean;
|
|
91
91
|
skipHistory?: boolean;
|
|
92
92
|
}): Promise<InsertHistoryRow<any>[]>;
|
|
93
|
+
/**
|
|
94
|
+
* Insert pre-decomposed tree nodes into a tree table.
|
|
95
|
+
*
|
|
96
|
+
* Unlike `insert()`, which expects a plain nested object and decomposes it
|
|
97
|
+
* via `treeFromObject()`, this method accepts an array of already-decomposed
|
|
98
|
+
* `Tree` nodes (e.g. from FsScanner). The **root node must be the last
|
|
99
|
+
* element** in the array.
|
|
100
|
+
*
|
|
101
|
+
* The method goes through the full insert pipeline:
|
|
102
|
+
* 1. Writes each node via TreeController
|
|
103
|
+
* 2. Creates an InsertHistoryRow automatically
|
|
104
|
+
* 3. Calls `notify.notify()` so Connector observers fire
|
|
105
|
+
*
|
|
106
|
+
* @param treeKey - The tree table key (must end with "Tree")
|
|
107
|
+
* @param trees - Pre-decomposed Tree nodes, root LAST
|
|
108
|
+
* @param options - Optional: skip notification or history
|
|
109
|
+
* @returns The InsertHistoryRow for the root node
|
|
110
|
+
*/
|
|
111
|
+
insertTrees(treeKey: string, trees: Tree[], options?: {
|
|
112
|
+
skipNotification?: boolean;
|
|
113
|
+
skipHistory?: boolean;
|
|
114
|
+
}): Promise<InsertHistoryRow<any>[]>;
|
|
93
115
|
/**
|
|
94
116
|
* Recursively runs controllers based on the route of the Insert
|
|
95
117
|
* @param insert - The Insert to run
|