@dxos/echo-pipeline 0.1.24-next.6b1f434 → 0.1.27-next.a0dff21

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.
@@ -1,4 +1,4 @@
1
- import { EchoProcessor, ItemDemuxerOptions, ItemManager } from '@dxos/echo-db';
1
+ import { EchoProcessor, ItemManager } from '@dxos/echo-db';
2
2
  import { FeedWriter } from '@dxos/feed-store';
3
3
  import { ModelFactory } from '@dxos/model-factory';
4
4
  import { DataMessage } from '@dxos/protocols/proto/dxos/echo/feed';
@@ -12,11 +12,10 @@ import { DataServiceHost } from './data-service-host';
12
12
  export declare class DatabaseBackendHost {
13
13
  private readonly _outboundStream;
14
14
  private readonly _snapshot?;
15
- private readonly _options;
16
15
  private _echoProcessor;
17
16
  private _itemManager;
18
17
  private _itemDemuxer;
19
- constructor(_outboundStream: FeedWriter<DataMessage> | undefined, _snapshot?: EchoSnapshot | undefined, _options?: ItemDemuxerOptions);
18
+ constructor(_outboundStream: FeedWriter<DataMessage> | undefined, _snapshot?: EchoSnapshot | undefined);
20
19
  get isReadOnly(): boolean;
21
20
  get echoProcessor(): EchoProcessor;
22
21
  open(itemManager: ItemManager, modelFactory: ModelFactory): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"database-backend.d.ts","sourceRoot":"","sources":["../../../../src/dbhost/database-backend.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAe,kBAAkB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5F,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAC;AAExE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD;;;;GAIG;AACH,qBAAa,mBAAmB;IAM5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAP3B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,YAAY,CAAe;gBAGhB,eAAe,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,SAAS,EACpD,SAAS,CAAC,0BAAc,EACxB,QAAQ,GAAE,kBAAuB;IAGpD,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,IAAI,aAAa,kBAEhB;IAEK,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY;IAYzD,KAAK;IAEX,cAAc,IAAI,UAAU,CAAC,WAAW,CAAC,GAAG,SAAS;IAIrD,cAAc;IAId,qBAAqB;CAGtB"}
1
+ {"version":3,"file":"database-backend.d.ts","sourceRoot":"","sources":["../../../../src/dbhost/database-backend.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAe,WAAW,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAC;AAExE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD;;;;GAIG;AACH,qBAAa,mBAAmB;IAM5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IAN7B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,YAAY,CAAe;gBAGhB,eAAe,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,SAAS,EACpD,SAAS,CAAC,0BAAc;IAG3C,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,IAAI,aAAa,kBAEhB;IAEK,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY;IAYzD,KAAK;IAEX,cAAc,IAAI,UAAU,CAAC,WAAW,CAAC,GAAG,SAAS;IAIrD,cAAc;IAId,qBAAqB;CAGtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"data-pipeline-controller.d.ts","sourceRoot":"","sources":["../../../../src/space/data-pipeline-controller.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,EAA4B,MAAM,aAAa,CAAC;AAE9D,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AACzE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,oBAAY,6BAA6B,GAAG;IAC1C,YAAY,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CACvD,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,OAAO,EAAE,6BAA6B,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,qBAAa,0BAA2B,YAAW,sBAAsB;IACjE,IAAI,CAAC,OAAO,EAAE,6BAA6B,GAAG,OAAO,CAAC,IAAI,CAAC;IAE3D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAC7B;AAED,oBAAY,gCAAgC,GAAG;IAC7C,YAAY,EAAE,YAAY,CAAC;IAC3B,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,EAAE,aAAa,CAAC;IAC7B,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;IACpB,gBAAgB,EAAE,CAAC,OAAO,EAAE,SAAS,KAAK,QAAQ,GAAG,SAAS,CAAC;IAC/D,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,CAAC;AAiBF;;;;GAIG;AACH,qBACa,0BAA2B,YAAW,sBAAsB;IAU3D,OAAO,CAAC,QAAQ,CAAC,OAAO;IATpC,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,aAAa,CAAiC;IACtD,OAAO,CAAC,SAAS,CAAC,CAAW;IAC7B,OAAO,CAAC,SAAS,CAAC,CAAgB;IAElC,OAAO,CAAC,+BAA+B,CAAmB;IAE1D,SAAgB,kBAAkB,mBAA0B;gBAE/B,OAAO,EAAE,gCAAgC;IAE/D,YAAY,EAAG,WAAW,CAAC;IAC3B,eAAe,CAAC,EAAE,mBAAmB,CAAC;IAE7C,IAAI,aAAa,6DAEhB;IAED,IAAI,iBAAiB,0BAEpB;IAED,iBAAiB,IAAI,SAAS;IAIxB,IAAI,CAAC,YAAY,EAAE,6BAA6B;IA+BtD,OAAO,CAAC,wBAAwB;YAwBlB,aAAa;YAOb,oBAAoB;IAO5B,KAAK;IAcX,cAAc,IAAI,aAAa;YAQjB,gBAAgB;IA+BxB,kBAAkB,CAAC,SAAS,EAAE,SAAS;CAI9C"}
1
+ {"version":3,"file":"data-pipeline-controller.d.ts","sourceRoot":"","sources":["../../../../src/space/data-pipeline-controller.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,EAA4B,MAAM,aAAa,CAAC;AAE9D,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AACzE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,oBAAY,6BAA6B,GAAG;IAC1C,YAAY,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CACvD,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,OAAO,EAAE,6BAA6B,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,qBAAa,0BAA2B,YAAW,sBAAsB;IACjE,IAAI,CAAC,OAAO,EAAE,6BAA6B,GAAG,OAAO,CAAC,IAAI,CAAC;IAE3D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAC7B;AAED,oBAAY,gCAAgC,GAAG;IAC7C,YAAY,EAAE,YAAY,CAAC;IAC3B,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,EAAE,aAAa,CAAC;IAC7B,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;IACpB,gBAAgB,EAAE,CAAC,OAAO,EAAE,SAAS,KAAK,QAAQ,GAAG,SAAS,CAAC;IAC/D,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,CAAC;AAiBF;;;;GAIG;AACH,qBACa,0BAA2B,YAAW,sBAAsB;IAU3D,OAAO,CAAC,QAAQ,CAAC,OAAO;IATpC,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,aAAa,CAAiC;IACtD,OAAO,CAAC,SAAS,CAAC,CAAW;IAC7B,OAAO,CAAC,SAAS,CAAC,CAAgB;IAElC,OAAO,CAAC,+BAA+B,CAAmB;IAE1D,SAAgB,kBAAkB,mBAA0B;gBAE/B,OAAO,EAAE,gCAAgC;IAE/D,YAAY,EAAG,WAAW,CAAC;IAC3B,eAAe,CAAC,EAAE,mBAAmB,CAAC;IAE7C,IAAI,aAAa,6DAEhB;IAED,IAAI,iBAAiB,0BAEpB;IAED,iBAAiB,IAAI,SAAS;IAIxB,IAAI,CAAC,YAAY,EAAE,6BAA6B;IA6BtD,OAAO,CAAC,wBAAwB;YAwBlB,aAAa;YAOb,oBAAoB;IAO5B,KAAK;IAcX,cAAc,IAAI,aAAa;YAQjB,gBAAgB;IA+BxB,kBAAkB,CAAC,SAAS,EAAE,SAAS;CAI9C"}
@@ -0,0 +1,59 @@
1
+ import { DatabaseBackendProxy, ItemManager } from '@dxos/echo-db';
2
+ import { PublicKey } from '@dxos/keys';
3
+ import { ModelFactory } from '@dxos/model-factory';
4
+ import { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
5
+ import { SpaceSnapshot } from '@dxos/protocols/proto/dxos/echo/snapshot';
6
+ import { Timeframe } from '@dxos/timeframe';
7
+ import { ComplexMap } from '@dxos/util';
8
+ import { DatabaseBackendHost } from '../dbhost';
9
+ export declare class DatabaseTestBuilder {
10
+ readonly peers: ComplexMap<PublicKey, DatabaseTestPeer>;
11
+ createPeer(): Promise<DatabaseTestPeer>;
12
+ }
13
+ export declare class DatabaseTestPeer {
14
+ readonly rig: DatabaseTestBuilder;
15
+ readonly modelFactory: ModelFactory;
16
+ items: ItemManager;
17
+ proxy: DatabaseBackendProxy;
18
+ host: DatabaseBackendHost;
19
+ hostItems: ItemManager;
20
+ readonly key: PublicKey;
21
+ feedMessages: FeedMessage[];
22
+ /**
23
+ * Sequence number of the last mutation confirmed to be written to the feed store.
24
+ */
25
+ confirmed: number;
26
+ /**
27
+ * Current position of the peer's pipeline.
28
+ */
29
+ timeframe: Timeframe;
30
+ snapshot: SpaceSnapshot | undefined;
31
+ private readonly _onConfirm;
32
+ constructor(rig: DatabaseTestBuilder);
33
+ open(): Promise<void>;
34
+ /**
35
+ * Confirm mutations written to the local feed.
36
+ * @param seq Sequence number of the mutation to confirm. If not specified, all mutations will be confirmed.
37
+ */
38
+ confirm(seq?: number): void;
39
+ /**
40
+ * Replicate the database to the specified timeframe.
41
+ * @param to Timeframe to replicate to. If not specified, the database will be replicated to the latest timeframe (based on all other peers).
42
+ */
43
+ replicate(to?: Timeframe): void;
44
+ /**
45
+ * Reload data from the feed. Wipes unconfirmed mutations.
46
+ */
47
+ reload(): Promise<void>;
48
+ /**
49
+ * Create snapshot and use it for the next reload.
50
+ */
51
+ makeSnapshot(): SpaceSnapshot;
52
+ /**
53
+ * Gets all candidate messages according to the current timeframe.
54
+ * Does not take into account the current snapshot, timeframe dependencies, or the confirmed, or replicated state.
55
+ */
56
+ private _getHeads;
57
+ private _processMessages;
58
+ }
59
+ //# sourceMappingURL=database-test-rig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-test-rig.d.ts","sourceRoot":"","sources":["../../../../src/testing/database-test-rig.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AAEzE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAwB,MAAM,YAAY,CAAC;AAE9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAIhD,qBAAa,mBAAmB;IAC9B,SAAgB,KAAK,0CAA+D;IAE9E,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAM9C;AAED,qBAAa,gBAAgB;aA+BC,GAAG,EAAE,mBAAmB;IA9BpD,SAAgB,YAAY,eAA4E;IAEjG,KAAK,EAAG,WAAW,CAAC;IACpB,KAAK,EAAG,oBAAoB,CAAC;IAE7B,IAAI,EAAG,mBAAmB,CAAC;IAC3B,SAAS,EAAG,WAAW,CAAC;IAM/B,SAAgB,GAAG,YAAsB;IAElC,YAAY,EAAE,WAAW,EAAE,CAAM;IAExC;;OAEG;IACI,SAAS,SAAM;IAEtB;;OAEG;IACI,SAAS,YAAmB;IAE5B,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC;IAE3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;gBAEd,GAAG,EAAE,mBAAmB;IAE9C,IAAI;IA6BV;;;OAGG;IACH,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM;IAOpB;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,EAAE,SAAS;IAUxB;;OAEG;IACG,MAAM;IAOZ;;OAEG;IACH,YAAY,IAAI,aAAa;IAS7B;;;OAGG;IACH,OAAO,CAAC,SAAS;IAgBjB,OAAO,CAAC,gBAAgB;CAmCzB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=database-unit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-unit.test.d.ts","sourceRoot":"","sources":["../../../../src/tests/database-unit.test.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/echo-pipeline",
3
- "version": "0.1.24-next.6b1f434",
3
+ "version": "0.1.27-next.a0dff21",
4
4
  "description": "ECHO database.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -20,39 +20,40 @@
20
20
  ],
21
21
  "dependencies": {
22
22
  "debug": "^4.3.3",
23
- "@dxos/async": "0.1.24-next.6b1f434",
24
- "@dxos/codec-protobuf": "0.1.24-next.6b1f434",
25
- "@dxos/context": "0.1.24-next.6b1f434",
26
- "@dxos/credentials": "0.1.24-next.6b1f434",
27
- "@dxos/crypto": "0.1.24-next.6b1f434",
28
- "@dxos/debug": "0.1.24-next.6b1f434",
29
- "@dxos/document-model": "0.1.24-next.6b1f434",
30
- "@dxos/echo-db": "0.1.24-next.6b1f434",
31
- "@dxos/feed-store": "0.1.24-next.6b1f434",
32
- "@dxos/hypercore": "0.1.24-next.6b1f434",
33
- "@dxos/keyring": "0.1.24-next.6b1f434",
34
- "@dxos/keys": "0.1.24-next.6b1f434",
35
- "@dxos/log": "0.1.24-next.6b1f434",
36
- "@dxos/messaging": "0.1.24-next.6b1f434",
37
- "@dxos/model-factory": "0.1.24-next.6b1f434",
38
- "@dxos/network-manager": "0.1.24-next.6b1f434",
39
- "@dxos/node-std": "0.1.24-next.6b1f434",
40
- "@dxos/protocols": "0.1.24-next.6b1f434",
41
- "@dxos/random-access-storage": "0.1.24-next.6b1f434",
42
- "@dxos/rpc": "0.1.24-next.6b1f434",
43
- "@dxos/teleport": "0.1.24-next.6b1f434",
44
- "@dxos/teleport-extension-object-sync": "0.1.24-next.6b1f434",
45
- "@dxos/teleport-extension-presence": "0.1.24-next.6b1f434",
46
- "@dxos/teleport-extension-replicator": "0.1.24-next.6b1f434",
47
- "@dxos/timeframe": "0.1.24-next.6b1f434",
48
- "@dxos/typings": "0.1.24-next.6b1f434",
49
- "@dxos/util": "0.1.24-next.6b1f434"
23
+ "@dxos/async": "0.1.27-next.a0dff21",
24
+ "@dxos/codec-protobuf": "0.1.27-next.a0dff21",
25
+ "@dxos/context": "0.1.27-next.a0dff21",
26
+ "@dxos/credentials": "0.1.27-next.a0dff21",
27
+ "@dxos/crypto": "0.1.27-next.a0dff21",
28
+ "@dxos/debug": "0.1.27-next.a0dff21",
29
+ "@dxos/document-model": "0.1.27-next.a0dff21",
30
+ "@dxos/echo-db": "0.1.27-next.a0dff21",
31
+ "@dxos/feed-store": "0.1.27-next.a0dff21",
32
+ "@dxos/hypercore": "0.1.27-next.a0dff21",
33
+ "@dxos/keyring": "0.1.27-next.a0dff21",
34
+ "@dxos/keys": "0.1.27-next.a0dff21",
35
+ "@dxos/log": "0.1.27-next.a0dff21",
36
+ "@dxos/messaging": "0.1.27-next.a0dff21",
37
+ "@dxos/model-factory": "0.1.27-next.a0dff21",
38
+ "@dxos/network-manager": "0.1.27-next.a0dff21",
39
+ "@dxos/node-std": "0.1.27-next.a0dff21",
40
+ "@dxos/protocols": "0.1.27-next.a0dff21",
41
+ "@dxos/random-access-storage": "0.1.27-next.a0dff21",
42
+ "@dxos/rpc": "0.1.27-next.a0dff21",
43
+ "@dxos/teleport": "0.1.27-next.a0dff21",
44
+ "@dxos/teleport-extension-object-sync": "0.1.27-next.a0dff21",
45
+ "@dxos/teleport-extension-presence": "0.1.27-next.a0dff21",
46
+ "@dxos/teleport-extension-replicator": "0.1.27-next.a0dff21",
47
+ "@dxos/timeframe": "0.1.27-next.a0dff21",
48
+ "@dxos/typings": "0.1.27-next.a0dff21",
49
+ "@dxos/util": "0.1.27-next.a0dff21"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/debug": "^4.1.7",
53
53
  "hypercore-protocol": "^8.0.7",
54
54
  "source-map-support": "^0.5.12",
55
- "wait-for-expect": "^3.0.2"
55
+ "wait-for-expect": "^3.0.2",
56
+ "@dxos/text-model": "0.1.27-next.a0dff21"
56
57
  },
57
58
  "publishConfig": {
58
59
  "access": "public"
@@ -4,7 +4,7 @@
4
4
  // Copyright 2023 DXOS.org
5
5
  //
6
6
 
7
- import { EchoProcessor, ItemDemuxer, ItemDemuxerOptions, ItemManager } from '@dxos/echo-db';
7
+ import { EchoProcessor, ItemDemuxer, ItemManager } from '@dxos/echo-db';
8
8
  import { FeedWriter } from '@dxos/feed-store';
9
9
  import { ModelFactory } from '@dxos/model-factory';
10
10
  import { DataMessage } from '@dxos/protocols/proto/dxos/echo/feed';
@@ -24,8 +24,7 @@ export class DatabaseBackendHost {
24
24
 
25
25
  constructor(
26
26
  private readonly _outboundStream: FeedWriter<DataMessage> | undefined,
27
- private readonly _snapshot?: EchoSnapshot,
28
- private readonly _options: ItemDemuxerOptions = {} // TODO(burdon): Pass in factory instead?
27
+ private readonly _snapshot?: EchoSnapshot
29
28
  ) {}
30
29
 
31
30
  get isReadOnly(): boolean {
@@ -40,11 +39,11 @@ export class DatabaseBackendHost {
40
39
  this._itemManager = itemManager;
41
40
  this._itemManager._debugLabel = 'host';
42
41
 
43
- this._itemDemuxer = new ItemDemuxer(itemManager, modelFactory, this._options);
42
+ this._itemDemuxer = new ItemDemuxer(itemManager, modelFactory);
44
43
  this._echoProcessor = this._itemDemuxer.open();
45
44
 
46
45
  if (this._snapshot) {
47
- await this._itemDemuxer.restoreFromSnapshot(this._snapshot);
46
+ this._itemDemuxer.restoreFromSnapshot(this._snapshot);
48
47
  }
49
48
  }
50
49
 
@@ -113,9 +113,7 @@ export class DataPipelineControllerImpl implements DataPipelineController {
113
113
  this._pipeline.writer ?? failUndefined()
114
114
  );
115
115
 
116
- this.databaseBackend = new DatabaseBackendHost(feedWriter, this._snapshot?.database, {
117
- snapshots: true // TODO(burdon): Config.
118
- });
116
+ this.databaseBackend = new DatabaseBackendHost(feedWriter, this._snapshot?.database);
119
117
  this._itemManager = new ItemManager(this._params.modelFactory);
120
118
 
121
119
  // Connect pipeline to the database.
@@ -0,0 +1,196 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { Event } from '@dxos/async';
6
+ import { DocumentModel } from '@dxos/document-model';
7
+ import { DatabaseBackendProxy, ItemManager } from '@dxos/echo-db';
8
+ import { PublicKey } from '@dxos/keys';
9
+ import { ModelFactory } from '@dxos/model-factory';
10
+ import { FeedMessageBlock } from '@dxos/protocols';
11
+ import { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
12
+ import { SpaceSnapshot } from '@dxos/protocols/proto/dxos/echo/snapshot';
13
+ import { TextModel } from '@dxos/text-model';
14
+ import { Timeframe } from '@dxos/timeframe';
15
+ import { ComplexMap, isNotNullOrUndefined } from '@dxos/util';
16
+
17
+ import { DatabaseBackendHost } from '../dbhost';
18
+
19
+ const SPACE_KEY = PublicKey.random();
20
+
21
+ export class DatabaseTestBuilder {
22
+ public readonly peers = new ComplexMap<PublicKey, DatabaseTestPeer>(PublicKey.hash);
23
+
24
+ async createPeer(): Promise<DatabaseTestPeer> {
25
+ const peer = new DatabaseTestPeer(this);
26
+ this.peers.set(peer.key, peer);
27
+ await peer.open();
28
+ return peer;
29
+ }
30
+ }
31
+
32
+ export class DatabaseTestPeer {
33
+ public readonly modelFactory = new ModelFactory().registerModel(DocumentModel).registerModel(TextModel);
34
+
35
+ public items!: ItemManager;
36
+ public proxy!: DatabaseBackendProxy;
37
+
38
+ public host!: DatabaseBackendHost;
39
+ public hostItems!: ItemManager;
40
+
41
+ //
42
+ // Test state.
43
+ //
44
+
45
+ public readonly key = PublicKey.random();
46
+
47
+ public feedMessages: FeedMessage[] = [];
48
+
49
+ /**
50
+ * Sequence number of the last mutation confirmed to be written to the feed store.
51
+ */
52
+ public confirmed = -1;
53
+
54
+ /**
55
+ * Current position of the peer's pipeline.
56
+ */
57
+ public timeframe = new Timeframe();
58
+
59
+ public snapshot: SpaceSnapshot | undefined;
60
+
61
+ private readonly _onConfirm = new Event();
62
+
63
+ constructor(public readonly rig: DatabaseTestBuilder) {}
64
+
65
+ async open() {
66
+ this.hostItems = new ItemManager(this.modelFactory);
67
+ this.host = new DatabaseBackendHost(
68
+ {
69
+ write: async (message) => {
70
+ const seq =
71
+ this.feedMessages.push({
72
+ timeframe: this.timeframe,
73
+ payload: {
74
+ data: message
75
+ }
76
+ }) - 1;
77
+
78
+ await this._onConfirm.waitFor(() => this.confirmed >= seq);
79
+ return {
80
+ seq,
81
+ feedKey: this.key
82
+ };
83
+ }
84
+ },
85
+ this.snapshot?.database
86
+ );
87
+ await this.host.open(this.hostItems, this.modelFactory);
88
+
89
+ this.proxy = new DatabaseBackendProxy(this.host.createDataServiceHost(), SPACE_KEY);
90
+ this.items = new ItemManager(this.modelFactory);
91
+ await this.proxy.open(this.items, this.modelFactory);
92
+ }
93
+
94
+ /**
95
+ * Confirm mutations written to the local feed.
96
+ * @param seq Sequence number of the mutation to confirm. If not specified, all mutations will be confirmed.
97
+ */
98
+ confirm(seq?: number) {
99
+ this.confirmed = seq ?? this.feedMessages.length - 1;
100
+ this._onConfirm.emit();
101
+
102
+ this._processMessages(Timeframe.merge(this.timeframe, new Timeframe([[this.key, this.confirmed]])));
103
+ }
104
+
105
+ /**
106
+ * Replicate the database to the specified timeframe.
107
+ * @param to Timeframe to replicate to. If not specified, the database will be replicated to the latest timeframe (based on all other peers).
108
+ */
109
+ replicate(to?: Timeframe) {
110
+ const toTimeframe = Timeframe.merge(
111
+ to ?? new Timeframe(Array.from(this.rig.peers.values()).map((peer) => [peer.key, peer.confirmed])),
112
+ this.timeframe
113
+ );
114
+ toTimeframe.set(this.key, this.confirmed);
115
+
116
+ this._processMessages(toTimeframe);
117
+ }
118
+
119
+ /**
120
+ * Reload data from the feed. Wipes unconfirmed mutations.
121
+ */
122
+ async reload() {
123
+ await this.open();
124
+ const timeframe = this.timeframe;
125
+ this.timeframe = this.snapshot?.timeframe ?? new Timeframe();
126
+ this._processMessages(timeframe);
127
+ }
128
+
129
+ /**
130
+ * Create snapshot and use it for the next reload.
131
+ */
132
+ makeSnapshot(): SpaceSnapshot {
133
+ this.snapshot = {
134
+ spaceKey: SPACE_KEY.asUint8Array(),
135
+ database: this.host.createSnapshot(),
136
+ timeframe: this.timeframe
137
+ };
138
+ return this.snapshot;
139
+ }
140
+
141
+ /**
142
+ * Gets all candidate messages according to the current timeframe.
143
+ * Does not take into account the current snapshot, timeframe dependencies, or the confirmed, or replicated state.
144
+ */
145
+ private _getHeads(): FeedMessageBlock[] {
146
+ return Array.from(this.rig.peers.values())
147
+ .map((peer): FeedMessageBlock => {
148
+ const seq = this.timeframe.get(peer.key) ?? -1;
149
+ const message = peer.feedMessages[seq + 1];
150
+ return (
151
+ message && {
152
+ feedKey: peer.key,
153
+ seq: seq + 1,
154
+ data: message
155
+ }
156
+ );
157
+ })
158
+ .filter(isNotNullOrUndefined);
159
+ }
160
+
161
+ private _processMessages(to: Timeframe) {
162
+ let run = true;
163
+ while (run) {
164
+ run = false;
165
+
166
+ const heads = this._getHeads();
167
+ for (const candidate of heads) {
168
+ const toSeq = to.get(candidate.feedKey) ?? -1;
169
+ if (toSeq < candidate.seq) {
170
+ continue;
171
+ }
172
+
173
+ const snapshotSeq = this.snapshot?.timeframe?.get(candidate.feedKey) ?? -1;
174
+ if (candidate.seq <= snapshotSeq) {
175
+ continue;
176
+ }
177
+
178
+ if (!Timeframe.dependencies(candidate.data.timeframe, this.timeframe).isEmpty()) {
179
+ continue;
180
+ }
181
+
182
+ run = true;
183
+ this.host.echoProcessor({
184
+ data: candidate.data.payload.data!.object,
185
+ meta: {
186
+ feedKey: candidate.feedKey,
187
+ seq: candidate.seq,
188
+ memberKey: candidate.feedKey,
189
+ timeframe: candidate.data.timeframe
190
+ }
191
+ });
192
+ this.timeframe = Timeframe.merge(this.timeframe, new Timeframe([[candidate.feedKey, candidate.seq]]));
193
+ }
194
+ }
195
+ }
196
+ }
@@ -16,7 +16,7 @@ import { DataPipelineControllerImpl } from '../space';
16
16
 
17
17
  export const createMemoryDatabase = async (modelFactory: ModelFactory) => {
18
18
  const feed = new MockFeedWriter<DataMessage>();
19
- const backend = new DatabaseBackendHost(feed, undefined, { snapshots: true });
19
+ const backend = new DatabaseBackendHost(feed, undefined);
20
20
 
21
21
  feed.written.on(([data, meta]) =>
22
22
  backend.echoProcessor({
@@ -0,0 +1,82 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import expect from 'expect';
6
+
7
+ import { DocumentModel, MutationBuilder } from '@dxos/document-model';
8
+ import { createModelMutation, encodeModelMutation, genesisMutation } from '@dxos/echo-db';
9
+ import { PublicKey } from '@dxos/keys';
10
+ import { describe, test } from '@dxos/test';
11
+ import { Timeframe } from '@dxos/timeframe';
12
+
13
+ import { DatabaseTestBuilder } from '../testing/database-test-rig';
14
+
15
+ describe('database (unit)', () => {
16
+ test('create object and reload', async () => {
17
+ const builder = new DatabaseTestBuilder();
18
+ const peer = await builder.createPeer();
19
+
20
+ const id = PublicKey.random().toHex();
21
+ peer.proxy.mutate(genesisMutation(id, DocumentModel.meta.type));
22
+ peer.proxy.mutate(
23
+ createModelMutation(id, encodeModelMutation(DocumentModel.meta, new MutationBuilder().set('test', 42).build()))
24
+ );
25
+
26
+ peer.confirm();
27
+ expect(peer.confirmed).toEqual(1);
28
+ expect(peer.timeframe).toEqual(new Timeframe([[peer.key, 1]]));
29
+
30
+ const state = peer.items.getItem(id)!.state;
31
+
32
+ {
33
+ await peer.reload();
34
+ const stateAfterReload = peer.items.getItem(id)!.state;
35
+
36
+ expect(stateAfterReload).toEqual(state);
37
+ }
38
+ });
39
+
40
+ test('create object and reload from snapshot', async () => {
41
+ const builder = new DatabaseTestBuilder();
42
+ const peer = await builder.createPeer();
43
+
44
+ const id = PublicKey.random().toHex();
45
+ peer.proxy.mutate(genesisMutation(id, DocumentModel.meta.type));
46
+ peer.proxy.mutate(
47
+ createModelMutation(id, encodeModelMutation(DocumentModel.meta, new MutationBuilder().set('test', 42).build()))
48
+ );
49
+
50
+ peer.confirm();
51
+ expect(peer.confirmed).toEqual(1);
52
+ expect(peer.timeframe).toEqual(new Timeframe([[peer.key, 1]]));
53
+ peer.makeSnapshot();
54
+
55
+ const state = peer.items.getItem(id)!.state;
56
+
57
+ {
58
+ await peer.reload();
59
+ const stateAfterReload = peer.items.getItem(id)!.state;
60
+
61
+ expect(stateAfterReload).toEqual(state);
62
+ }
63
+ });
64
+
65
+ test('two peers replicate', async () => {
66
+ const builder = new DatabaseTestBuilder();
67
+ const peer1 = await builder.createPeer();
68
+ const peer2 = await builder.createPeer();
69
+
70
+ const id = PublicKey.random().toHex();
71
+ peer1.proxy.mutate(genesisMutation(id, DocumentModel.meta.type));
72
+ peer1.proxy.mutate(
73
+ createModelMutation(id, encodeModelMutation(DocumentModel.meta, new MutationBuilder().set('test', 42).build()))
74
+ );
75
+ peer1.confirm();
76
+
77
+ peer2.replicate(peer1.timeframe);
78
+
79
+ // TODO(dmaretskyi): Helper functions to compare state.
80
+ expect(peer1.items.getItem(id)!.state).toEqual(peer1.items.getItem(id)!.state);
81
+ });
82
+ });