@dxos/client-services 0.10.0 → 0.11.1
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/dist/lib/chunk-client-services-layer.mjs +11425 -0
- package/dist/lib/chunk-client-services-layer.mjs.map +1 -0
- package/dist/lib/chunk-decorate.mjs +9 -0
- package/dist/lib/index.mjs +731 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/packlets/diagnostics/browser-diagnostics-broadcast.mjs +72 -0
- package/dist/lib/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +1 -0
- package/dist/lib/packlets/diagnostics/diagnostics-broadcast.mjs +14 -0
- package/dist/lib/packlets/diagnostics/diagnostics-broadcast.mjs.map +1 -0
- package/dist/lib/packlets/locks/browser.mjs +105 -0
- package/dist/lib/packlets/locks/browser.mjs.map +1 -0
- package/dist/lib/packlets/locks/node.mjs +53 -0
- package/dist/lib/packlets/locks/node.mjs.map +1 -0
- package/dist/lib/testing.mjs +570 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/packlets/agents/edge-agent-manager.d.ts +21 -4
- package/dist/types/src/packlets/agents/edge-agent-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/agents/edge-agent-service.d.ts +8 -7
- package/dist/types/src/packlets/agents/edge-agent-service.d.ts.map +1 -1
- package/dist/types/src/packlets/devices/devices-service.d.ts +7 -5
- package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/devtools.d.ts +30 -29
- package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/feeds.d.ts +1 -1
- package/dist/types/src/packlets/devtools/feeds.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/network.d.ts +2 -1
- package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/spaces.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts +2 -2
- package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics-collector.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics.d.ts +1 -8
- package/dist/types/src/packlets/diagnostics/diagnostics.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/contacts-service.d.ts +9 -6
- package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts +32 -3
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +23 -4
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-service.d.ts +15 -20
- package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +2 -2
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts +17 -0
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-manager.d.ts +25 -4
- package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-service.d.ts +11 -11
- package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/logging/logging-service.d.ts +14 -12
- package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
- package/dist/types/src/packlets/metadata/index.d.ts +3 -0
- package/dist/types/src/packlets/metadata/index.d.ts.map +1 -0
- package/dist/types/src/packlets/metadata/metadata-store.d.ts +107 -0
- package/dist/types/src/packlets/metadata/metadata-store.d.ts.map +1 -0
- package/dist/types/src/packlets/metadata/metadata-store.test.d.ts +2 -0
- package/dist/types/src/packlets/metadata/metadata-store.test.d.ts.map +1 -0
- package/dist/types/src/packlets/metadata/sqlite-metadata-store.d.ts +65 -0
- package/dist/types/src/packlets/metadata/sqlite-metadata-store.d.ts.map +1 -0
- package/dist/types/src/packlets/network/network-service.d.ts +15 -14
- package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
- package/dist/types/src/packlets/pipeline/codec.d.ts +11 -0
- package/dist/types/src/packlets/pipeline/codec.d.ts.map +1 -0
- package/dist/types/src/packlets/pipeline/feeds.d.ts +7 -0
- package/dist/types/src/packlets/pipeline/feeds.d.ts.map +1 -0
- package/dist/types/src/packlets/pipeline/index.d.ts +5 -0
- package/dist/types/src/packlets/pipeline/index.d.ts.map +1 -0
- package/dist/types/src/packlets/pipeline/message-selector.d.ts +11 -0
- package/dist/types/src/packlets/pipeline/message-selector.d.ts.map +1 -0
- package/dist/types/src/packlets/pipeline/pipeline-stress.test.d.ts +2 -0
- package/dist/types/src/packlets/pipeline/pipeline-stress.test.d.ts.map +1 -0
- package/dist/types/src/packlets/pipeline/pipeline.d.ts +131 -0
- package/dist/types/src/packlets/pipeline/pipeline.d.ts.map +1 -0
- package/dist/types/src/packlets/pipeline/pipeline.test.d.ts +2 -0
- package/dist/types/src/packlets/pipeline/pipeline.test.d.ts.map +1 -0
- package/dist/types/src/packlets/pipeline/testing/index.d.ts +2 -0
- package/dist/types/src/packlets/pipeline/testing/index.d.ts.map +1 -0
- package/dist/types/src/packlets/pipeline/testing/test-feed-builder.d.ts +9 -0
- package/dist/types/src/packlets/pipeline/testing/test-feed-builder.d.ts.map +1 -0
- package/dist/types/src/packlets/pipeline/timeframe-clock.d.ts +31 -0
- package/dist/types/src/packlets/pipeline/timeframe-clock.d.ts.map +1 -0
- package/dist/types/src/packlets/services/client-services-layer.d.ts +21 -0
- package/dist/types/src/packlets/services/client-services-layer.d.ts.map +1 -0
- package/dist/types/src/packlets/services/cross-device-space-synchronizer.d.ts +28 -0
- package/dist/types/src/packlets/services/cross-device-space-synchronizer.d.ts.map +1 -0
- package/dist/types/src/packlets/services/effect-rpc.test.d.ts +2 -0
- package/dist/types/src/packlets/services/effect-rpc.test.d.ts.map +1 -0
- package/dist/types/src/packlets/services/feed-syncer.d.ts +22 -2
- package/dist/types/src/packlets/services/feed-syncer.d.ts.map +1 -1
- package/dist/types/src/packlets/services/index.d.ts +2 -2
- package/dist/types/src/packlets/services/index.d.ts.map +1 -1
- package/dist/types/src/packlets/services/platform.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +38 -57
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +82 -31
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/services/sqlite-storage.d.ts +29 -0
- package/dist/types/src/packlets/services/sqlite-storage.d.ts.map +1 -1
- package/dist/types/src/packlets/services/sqlite-storage.test.d.ts +2 -0
- package/dist/types/src/packlets/services/sqlite-storage.test.d.ts.map +1 -0
- package/dist/types/src/packlets/space/admission-discovery-extension.d.ts +30 -0
- package/dist/types/src/packlets/space/admission-discovery-extension.d.ts.map +1 -0
- package/dist/types/src/packlets/space/auth.d.ts +24 -0
- package/dist/types/src/packlets/space/auth.d.ts.map +1 -0
- package/dist/types/src/packlets/space/control-pipeline.d.ts +46 -0
- package/dist/types/src/packlets/space/control-pipeline.d.ts.map +1 -0
- package/dist/types/src/packlets/space/control-pipeline.test.d.ts +2 -0
- package/dist/types/src/packlets/space/control-pipeline.test.d.ts.map +1 -0
- package/dist/types/src/packlets/space/index.d.ts +6 -0
- package/dist/types/src/packlets/space/index.d.ts.map +1 -0
- package/dist/types/src/packlets/space/replication.browser.test.d.ts +2 -0
- package/dist/types/src/packlets/space/replication.browser.test.d.ts.map +1 -0
- package/dist/types/src/packlets/space/space-manager.browser.test.d.ts +2 -0
- package/dist/types/src/packlets/space/space-manager.browser.test.d.ts.map +1 -0
- package/dist/types/src/packlets/space/space-manager.d.ts +72 -0
- package/dist/types/src/packlets/space/space-manager.d.ts.map +1 -0
- package/dist/types/src/packlets/space/space-protocol.browser.test.d.ts +2 -0
- package/dist/types/src/packlets/space/space-protocol.browser.test.d.ts.map +1 -0
- package/dist/types/src/packlets/space/space-protocol.d.ts +99 -0
- package/dist/types/src/packlets/space/space-protocol.d.ts.map +1 -0
- package/dist/types/src/packlets/space/space-protocol.test.d.ts +2 -0
- package/dist/types/src/packlets/space/space-protocol.test.d.ts.map +1 -0
- package/dist/types/src/packlets/space/space.d.ts +65 -0
- package/dist/types/src/packlets/space/space.d.ts.map +1 -0
- package/dist/types/src/packlets/space/space.test.d.ts +2 -0
- package/dist/types/src/packlets/space/space.test.d.ts.map +1 -0
- package/dist/types/src/packlets/space/testing/change-metadata.d.ts +8 -0
- package/dist/types/src/packlets/space/testing/change-metadata.d.ts.map +1 -0
- package/dist/types/src/packlets/space/testing/index.d.ts +4 -0
- package/dist/types/src/packlets/space/testing/index.d.ts.map +1 -0
- package/dist/types/src/packlets/space/testing/test-agent-builder.d.ts +62 -0
- package/dist/types/src/packlets/space/testing/test-agent-builder.d.ts.map +1 -0
- package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts +1 -1
- package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +40 -7
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +3 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/genesis.d.ts +1 -1
- package/dist/types/src/packlets/spaces/genesis.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +25 -23
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/level.d.ts.map +1 -1
- package/dist/types/src/packlets/system/system-service.d.ts +18 -18
- package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +7 -6
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-runtime.d.ts +41 -58
- package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-session.d.ts +21 -8
- package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +1 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +52 -48
- package/src/index.ts +2 -0
- package/src/packlets/agents/edge-agent-manager.ts +56 -15
- package/src/packlets/agents/edge-agent-service.ts +25 -15
- package/src/packlets/devices/devices-service.test.ts +20 -19
- package/src/packlets/devices/devices-service.ts +17 -17
- package/src/packlets/devtools/devtools.ts +133 -75
- package/src/packlets/devtools/feeds.ts +2 -1
- package/src/packlets/devtools/network.ts +42 -12
- package/src/packlets/devtools/spaces.ts +1 -1
- package/src/packlets/diagnostics/diagnostics-broadcast.ts +4 -2
- package/src/packlets/diagnostics/diagnostics-collector.ts +5 -18
- package/src/packlets/diagnostics/diagnostics.ts +0 -11
- package/src/packlets/identity/authenticator.ts +2 -1
- package/src/packlets/identity/contacts-service.ts +46 -37
- package/src/packlets/identity/identity-manager.test.ts +3 -1
- package/src/packlets/identity/identity-manager.ts +73 -5
- package/src/packlets/identity/identity-recovery-manager.ts +56 -7
- package/src/packlets/identity/identity-service.test.ts +27 -18
- package/src/packlets/identity/identity-service.ts +114 -71
- package/src/packlets/identity/identity.test.ts +4 -9
- package/src/packlets/identity/identity.ts +1 -2
- package/src/packlets/invitations/edge-invitation-handler.ts +0 -1
- package/src/packlets/invitations/invitations-handler.ts +39 -3
- package/src/packlets/invitations/invitations-manager.ts +52 -4
- package/src/packlets/invitations/invitations-service.ts +54 -28
- package/src/packlets/logging/logging-service.ts +41 -29
- package/src/packlets/logging/logging.test.ts +28 -15
- package/src/packlets/metadata/index.ts +6 -0
- package/src/packlets/metadata/metadata-store.test.ts +49 -0
- package/src/packlets/metadata/metadata-store.ts +446 -0
- package/src/packlets/metadata/sqlite-metadata-store.ts +409 -0
- package/src/packlets/network/network-service.test.ts +19 -12
- package/src/packlets/network/network-service.ts +96 -29
- package/src/packlets/pipeline/codec.ts +18 -0
- package/src/packlets/pipeline/feeds.ts +22 -0
- package/src/packlets/pipeline/index.ts +8 -0
- package/src/packlets/pipeline/message-selector.ts +35 -0
- package/src/packlets/pipeline/pipeline-stress.test.ts +230 -0
- package/src/packlets/pipeline/pipeline.test.ts +140 -0
- package/src/packlets/pipeline/pipeline.ts +439 -0
- package/src/packlets/pipeline/testing/index.ts +5 -0
- package/src/packlets/pipeline/testing/test-feed-builder.ts +19 -0
- package/src/packlets/pipeline/timeframe-clock.ts +81 -0
- package/src/packlets/services/client-services-layer.ts +186 -0
- package/src/packlets/services/cross-device-space-synchronizer.ts +132 -0
- package/src/packlets/services/effect-rpc.test.ts +314 -0
- package/src/packlets/services/feed-syncer.ts +57 -3
- package/src/packlets/services/index.ts +2 -2
- package/src/packlets/services/platform.ts +0 -6
- package/src/packlets/services/service-context.ts +219 -522
- package/src/packlets/services/service-host.test.ts +34 -11
- package/src/packlets/services/service-host.ts +693 -213
- package/src/packlets/services/spec.md +106 -0
- package/src/packlets/services/sqlite-storage.test.ts +48 -0
- package/src/packlets/services/sqlite-storage.ts +117 -20
- package/src/packlets/space/admission-discovery-extension.ts +91 -0
- package/src/packlets/space/auth.ts +92 -0
- package/src/packlets/space/control-pipeline.test.ts +165 -0
- package/src/packlets/space/control-pipeline.ts +229 -0
- package/src/packlets/space/index.ts +9 -0
- package/src/packlets/space/replication.browser.test.ts +58 -0
- package/src/packlets/space/space-manager.browser.test.ts +40 -0
- package/src/packlets/space/space-manager.ts +224 -0
- package/src/packlets/space/space-protocol.browser.test.ts +129 -0
- package/src/packlets/space/space-protocol.test.ts +158 -0
- package/src/packlets/space/space-protocol.ts +308 -0
- package/src/packlets/space/space.test.ts +181 -0
- package/src/packlets/space/space.ts +196 -0
- package/src/packlets/space/testing/change-metadata.ts +27 -0
- package/src/packlets/space/testing/index.ts +7 -0
- package/src/packlets/space/testing/test-agent-builder.ts +252 -0
- package/src/packlets/space-export/serialized-space-reader.ts +3 -1
- package/src/packlets/space-export/serialized-space-writer.ts +53 -30
- package/src/packlets/space-export/space-archive.test.ts +30 -0
- package/src/packlets/spaces/data-space-manager.test.ts +1 -1
- package/src/packlets/spaces/data-space-manager.ts +148 -33
- package/src/packlets/spaces/data-space.ts +29 -18
- package/src/packlets/spaces/edge-feed-replicator.test.ts +1 -1
- package/src/packlets/spaces/genesis.ts +1 -1
- package/src/packlets/spaces/spaces-service.test.ts +35 -22
- package/src/packlets/spaces/spaces-service.ts +259 -180
- package/src/packlets/storage/level.ts +3 -1
- package/src/packlets/system/system-service.test.ts +31 -13
- package/src/packlets/system/system-service.ts +65 -37
- package/src/packlets/testing/invitation-utils.ts +3 -3
- package/src/packlets/testing/test-builder.ts +35 -20
- package/src/packlets/worker/worker-runtime.ts +222 -260
- package/src/packlets/worker/worker-session.ts +108 -91
- package/src/testing/index.ts +1 -0
- package/src/version.ts +1 -1
- package/dist/lib/browser/chunk-QCWEHHJW.mjs +0 -24
- package/dist/lib/browser/chunk-QCWEHHJW.mjs.map +0 -7
- package/dist/lib/browser/chunk-XJRPB3GA.mjs +0 -22
- package/dist/lib/browser/chunk-XJRPB3GA.mjs.map +0 -7
- package/dist/lib/browser/chunk-XU5R2BMF.mjs +0 -8837
- package/dist/lib/browser/chunk-XU5R2BMF.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -876
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs +0 -88
- package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +0 -7
- package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs +0 -11
- package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs.map +0 -7
- package/dist/lib/browser/packlets/locks/browser.mjs +0 -86
- package/dist/lib/browser/packlets/locks/browser.mjs.map +0 -7
- package/dist/lib/browser/packlets/locks/node.mjs +0 -48
- package/dist/lib/browser/packlets/locks/node.mjs.map +0 -7
- package/dist/lib/browser/testing/index.mjs +0 -436
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-2DT3MZRL.mjs +0 -22
- package/dist/lib/node-esm/chunk-2DT3MZRL.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-2SZHAWBN.mjs +0 -24
- package/dist/lib/node-esm/chunk-2SZHAWBN.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-H5YTUD35.mjs +0 -8837
- package/dist/lib/node-esm/chunk-H5YTUD35.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -876
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs +0 -88
- package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +0 -7
- package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs +0 -11
- package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs.map +0 -7
- package/dist/lib/node-esm/packlets/locks/browser.mjs +0 -86
- package/dist/lib/node-esm/packlets/locks/browser.mjs.map +0 -7
- package/dist/lib/node-esm/packlets/locks/node.mjs +0 -48
- package/dist/lib/node-esm/packlets/locks/node.mjs.map +0 -7
- package/dist/lib/node-esm/testing/index.mjs +0 -436
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
- package/dist/types/src/packlets/services/client-rpc-server.d.ts +0 -24
- package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +0 -1
- package/dist/types/src/packlets/services/service-registry.d.ts +0 -15
- package/dist/types/src/packlets/services/service-registry.d.ts.map +0 -1
- package/dist/types/src/packlets/services/service-registry.test.d.ts +0 -2
- package/dist/types/src/packlets/services/service-registry.test.d.ts.map +0 -1
- package/dist/types/src/testing/setup.d.ts +0 -3
- package/dist/types/src/testing/setup.d.ts.map +0 -1
- package/src/packlets/services/client-rpc-server.ts +0 -111
- package/src/packlets/services/service-registry.test.ts +0 -78
- package/src/packlets/services/service-registry.ts +0 -36
- package/src/testing/setup.ts +0 -11
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type AutomergeUrl, parseAutomergeUrl } from '@automerge/automerge-repo';
|
|
6
|
+
import * as EffectContext from 'effect/Context';
|
|
7
|
+
import * as Effect from 'effect/Effect';
|
|
8
|
+
import * as Layer from 'effect/Layer';
|
|
9
|
+
|
|
10
|
+
import { Trigger, synchronized, trackLeaks } from '@dxos/async';
|
|
11
|
+
import { Context } from '@dxos/context';
|
|
12
|
+
import { type DelegateInvitationCredential, type MemberInfo, getCredentialAssertion } from '@dxos/credentials';
|
|
13
|
+
import { failUndefined } from '@dxos/debug';
|
|
14
|
+
import { createIdFromSpaceKey } from '@dxos/echo-protocol';
|
|
15
|
+
import { type FeedStore, FeedStoreService } from '@dxos/feed-store';
|
|
16
|
+
import { PublicKey } from '@dxos/keys';
|
|
17
|
+
import { log } from '@dxos/log';
|
|
18
|
+
import { type SwarmNetworkManager, SwarmNetworkManagerService } from '@dxos/network-manager';
|
|
19
|
+
import type { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
20
|
+
import { type SpaceMetadata } from '@dxos/protocols/proto/dxos/echo/metadata';
|
|
21
|
+
import type { Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
22
|
+
import { type Teleport } from '@dxos/teleport';
|
|
23
|
+
import { type BlobStoreApi, BlobStoreApiService } from '@dxos/teleport-extension-object-sync';
|
|
24
|
+
import { ComplexMap } from '@dxos/util';
|
|
25
|
+
|
|
26
|
+
import { type IMetadataStore, IMetadataStoreService } from '../metadata';
|
|
27
|
+
import { CredentialRetrieverExtension } from './admission-discovery-extension';
|
|
28
|
+
import { Space } from './space';
|
|
29
|
+
import { SpaceProtocol, type SwarmIdentity } from './space-protocol';
|
|
30
|
+
|
|
31
|
+
export type SpaceManagerProps = {
|
|
32
|
+
feedStore: FeedStore<FeedMessage>;
|
|
33
|
+
networkManager: SwarmNetworkManager;
|
|
34
|
+
metadataStore: IMetadataStore;
|
|
35
|
+
|
|
36
|
+
blobStore: BlobStoreApi;
|
|
37
|
+
|
|
38
|
+
disableP2pReplication?: boolean;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type ConstructSpaceProps = {
|
|
42
|
+
metadata: SpaceMetadata;
|
|
43
|
+
swarmIdentity: SwarmIdentity;
|
|
44
|
+
memberKey: PublicKey;
|
|
45
|
+
/**
|
|
46
|
+
* Called when connection auth passed successful.
|
|
47
|
+
*/
|
|
48
|
+
onAuthorizedConnection: (session: Teleport) => void;
|
|
49
|
+
onAuthFailure?: (session: Teleport) => void;
|
|
50
|
+
onDelegatedInvitationStatusChange: (invitation: DelegateInvitationCredential, isActive: boolean) => Promise<void>;
|
|
51
|
+
onMemberRolesChanged: (member: MemberInfo[]) => Promise<void>;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type RequestSpaceAdmissionCredentialProps = {
|
|
55
|
+
spaceKey: PublicKey;
|
|
56
|
+
identityKey: PublicKey;
|
|
57
|
+
swarmIdentity: SwarmIdentity;
|
|
58
|
+
timeout: number;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Effect service tag for {@link SpaceManager}.
|
|
63
|
+
*/
|
|
64
|
+
export class SpaceManagerService extends EffectContext.Tag('@dxos/client-services/SpaceManager')<
|
|
65
|
+
SpaceManagerService,
|
|
66
|
+
SpaceManager
|
|
67
|
+
>() {}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Manages a collection of ECHO (Data) Spaces.
|
|
71
|
+
*/
|
|
72
|
+
@trackLeaks('open', 'close')
|
|
73
|
+
export class SpaceManager {
|
|
74
|
+
private readonly _spaces = new ComplexMap<PublicKey, Space>(PublicKey.hash);
|
|
75
|
+
private readonly _feedStore: FeedStore<FeedMessage>;
|
|
76
|
+
private readonly _networkManager: SwarmNetworkManager;
|
|
77
|
+
private readonly _metadataStore: IMetadataStore;
|
|
78
|
+
private readonly _blobStore: BlobStoreApi;
|
|
79
|
+
private readonly _disableP2pReplication: boolean;
|
|
80
|
+
|
|
81
|
+
constructor({ feedStore, networkManager, metadataStore, blobStore, disableP2pReplication }: SpaceManagerProps) {
|
|
82
|
+
// TODO(burdon): Assert.
|
|
83
|
+
this._feedStore = feedStore;
|
|
84
|
+
this._networkManager = networkManager;
|
|
85
|
+
this._metadataStore = metadataStore;
|
|
86
|
+
this._blobStore = blobStore;
|
|
87
|
+
this._disableP2pReplication = disableP2pReplication ?? false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// TODO(burdon): Remove.
|
|
91
|
+
get spaces() {
|
|
92
|
+
return this._spaces;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@synchronized
|
|
96
|
+
async open(): Promise<void> {}
|
|
97
|
+
|
|
98
|
+
@synchronized
|
|
99
|
+
async close(): Promise<void> {
|
|
100
|
+
await Promise.all([...this._spaces.values()].map((space) => space.close()));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async constructSpace({
|
|
104
|
+
metadata,
|
|
105
|
+
swarmIdentity,
|
|
106
|
+
onAuthorizedConnection,
|
|
107
|
+
onAuthFailure,
|
|
108
|
+
onDelegatedInvitationStatusChange,
|
|
109
|
+
onMemberRolesChanged,
|
|
110
|
+
memberKey,
|
|
111
|
+
}: ConstructSpaceProps): Promise<Space> {
|
|
112
|
+
log('constructing space...', { spaceKey: metadata.genesisFeedKey });
|
|
113
|
+
|
|
114
|
+
// The genesis feed will be the same as the control feed if the space was created by the local agent.
|
|
115
|
+
const genesisFeed = await this._feedStore.openFeed(metadata.genesisFeedKey ?? failUndefined());
|
|
116
|
+
|
|
117
|
+
const spaceKey = metadata.key;
|
|
118
|
+
const spaceId = await createIdFromSpaceKey(spaceKey);
|
|
119
|
+
const protocol = new SpaceProtocol({
|
|
120
|
+
topic: spaceKey,
|
|
121
|
+
swarmIdentity,
|
|
122
|
+
networkManager: this._networkManager,
|
|
123
|
+
onSessionAuth: onAuthorizedConnection,
|
|
124
|
+
onAuthFailure,
|
|
125
|
+
blobStore: this._blobStore,
|
|
126
|
+
disableP2pReplication: this._disableP2pReplication,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const space = new Space({
|
|
130
|
+
id: spaceId,
|
|
131
|
+
spaceKey,
|
|
132
|
+
protocol,
|
|
133
|
+
genesisFeed,
|
|
134
|
+
feedProvider: (feedKey, opts) => this._feedStore.openFeed(feedKey, opts),
|
|
135
|
+
metadataStore: this._metadataStore,
|
|
136
|
+
memberKey,
|
|
137
|
+
onDelegatedInvitationStatusChange,
|
|
138
|
+
onMemberRolesChanged,
|
|
139
|
+
});
|
|
140
|
+
this._spaces.set(space.key, space);
|
|
141
|
+
|
|
142
|
+
return space;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public async requestSpaceAdmissionCredential(
|
|
146
|
+
ctx: Context,
|
|
147
|
+
params: RequestSpaceAdmissionCredentialProps,
|
|
148
|
+
): Promise<Credential> {
|
|
149
|
+
log('requesting space admission credential...', { spaceKey: params.spaceKey });
|
|
150
|
+
|
|
151
|
+
const onCredentialResolved = new Trigger<Credential>();
|
|
152
|
+
const protocol = new SpaceProtocol({
|
|
153
|
+
topic: params.spaceKey,
|
|
154
|
+
swarmIdentity: params.swarmIdentity,
|
|
155
|
+
networkManager: this._networkManager,
|
|
156
|
+
onSessionAuth: (session: Teleport) => {
|
|
157
|
+
session.addExtension(
|
|
158
|
+
'dxos.mesh.teleport.admission-discovery',
|
|
159
|
+
new CredentialRetrieverExtension(
|
|
160
|
+
{ spaceKey: params.spaceKey, memberKey: params.identityKey },
|
|
161
|
+
onCredentialResolved,
|
|
162
|
+
),
|
|
163
|
+
);
|
|
164
|
+
},
|
|
165
|
+
onAuthFailure: (session: Teleport) => session.close(),
|
|
166
|
+
blobStore: this._blobStore,
|
|
167
|
+
disableP2pReplication: this._disableP2pReplication,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
await protocol.start(ctx);
|
|
172
|
+
const credential = await onCredentialResolved.wait({ timeout: params.timeout });
|
|
173
|
+
return credential;
|
|
174
|
+
} catch (err: any) {
|
|
175
|
+
throw err;
|
|
176
|
+
} finally {
|
|
177
|
+
await protocol.stop(ctx);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public findSpaceByRootDocumentId(documentId: string): Space | undefined {
|
|
182
|
+
return [...this._spaces.values()].find((space) => {
|
|
183
|
+
return space.spaceState.credentials.some((credential) => {
|
|
184
|
+
const assertion = getCredentialAssertion(credential);
|
|
185
|
+
if (assertion['@type'] !== 'dxos.halo.credentials.Epoch') {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
if (!assertion?.automergeRoot) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
return parseAutomergeUrl(assertion.automergeRoot as AutomergeUrl).documentId === documentId;
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export type SpaceManagerLayerOptions = Pick<SpaceManagerProps, 'disableP2pReplication'>;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Effect Layer constructing a {@link SpaceManager} from ambient service dependencies.
|
|
201
|
+
*/
|
|
202
|
+
export const SpaceManagerLayer = (
|
|
203
|
+
options: SpaceManagerLayerOptions = {},
|
|
204
|
+
): Layer.Layer<
|
|
205
|
+
SpaceManagerService,
|
|
206
|
+
never,
|
|
207
|
+
FeedStoreService | SwarmNetworkManagerService | IMetadataStoreService | BlobStoreApiService
|
|
208
|
+
> =>
|
|
209
|
+
Layer.effect(
|
|
210
|
+
SpaceManagerService,
|
|
211
|
+
Effect.gen(function* () {
|
|
212
|
+
const feedStore = yield* FeedStoreService;
|
|
213
|
+
const networkManager = yield* SwarmNetworkManagerService;
|
|
214
|
+
const metadataStore = yield* IMetadataStoreService;
|
|
215
|
+
const blobStore = yield* BlobStoreApiService;
|
|
216
|
+
return new SpaceManager({
|
|
217
|
+
feedStore,
|
|
218
|
+
networkManager,
|
|
219
|
+
metadataStore,
|
|
220
|
+
blobStore,
|
|
221
|
+
disableP2pReplication: options.disableP2pReplication,
|
|
222
|
+
});
|
|
223
|
+
}),
|
|
224
|
+
);
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, expect, onTestFinished, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { Context } from '@dxos/context';
|
|
8
|
+
import { Keyring } from '@dxos/keyring';
|
|
9
|
+
import { PublicKey } from '@dxos/keys';
|
|
10
|
+
import { createStorage } from '@dxos/random-access-storage';
|
|
11
|
+
import { Timeframe } from '@dxos/timeframe';
|
|
12
|
+
|
|
13
|
+
import { TestAgentBuilder, TestFeedBuilder } from './testing';
|
|
14
|
+
|
|
15
|
+
describe('space/space-protocol', () => {
|
|
16
|
+
// TODO(dmaretskyi): Fails with the vscode test-runner for some reason.
|
|
17
|
+
test('two peers discover each other', async () => {
|
|
18
|
+
const builder = new TestAgentBuilder();
|
|
19
|
+
onTestFinished(async () => {
|
|
20
|
+
await builder.close();
|
|
21
|
+
});
|
|
22
|
+
const topic = PublicKey.random();
|
|
23
|
+
|
|
24
|
+
const peer1 = await builder.createPeer();
|
|
25
|
+
const gossip1 = peer1.createGossip();
|
|
26
|
+
const presence1 = peer1.createPresence(gossip1);
|
|
27
|
+
const protocol1 = peer1.createSpaceProtocol(topic, gossip1);
|
|
28
|
+
|
|
29
|
+
const peer2 = await builder.createPeer();
|
|
30
|
+
const gossip2 = peer2.createGossip();
|
|
31
|
+
const presence2 = peer2.createPresence(gossip2);
|
|
32
|
+
const protocol2 = peer2.createSpaceProtocol(topic, gossip2);
|
|
33
|
+
|
|
34
|
+
await protocol1.start(Context.default());
|
|
35
|
+
await protocol2.start(Context.default());
|
|
36
|
+
|
|
37
|
+
onTestFinished(() => protocol1.stop(Context.default()));
|
|
38
|
+
onTestFinished(() => protocol2.stop(Context.default()));
|
|
39
|
+
|
|
40
|
+
await expect
|
|
41
|
+
.poll(() => presence1.getPeersOnline().some(({ identityKey }) => identityKey.equals(peer2.identityKey)))
|
|
42
|
+
.toBeTruthy();
|
|
43
|
+
await expect
|
|
44
|
+
.poll(() => presence2.getPeersOnline().some(({ identityKey }) => identityKey.equals(peer1.identityKey)))
|
|
45
|
+
.toBeTruthy();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('replicates a feed', async () => {
|
|
49
|
+
const builder = new TestAgentBuilder();
|
|
50
|
+
onTestFinished(async () => {
|
|
51
|
+
await builder.close();
|
|
52
|
+
});
|
|
53
|
+
const topic = PublicKey.random();
|
|
54
|
+
|
|
55
|
+
const peer1 = await builder.createPeer();
|
|
56
|
+
const protocol1 = peer1.createSpaceProtocol(topic);
|
|
57
|
+
|
|
58
|
+
const peer2 = await builder.createPeer();
|
|
59
|
+
const protocol2 = peer2.createSpaceProtocol(topic);
|
|
60
|
+
|
|
61
|
+
await protocol1.start(Context.default());
|
|
62
|
+
await protocol2.start(Context.default());
|
|
63
|
+
|
|
64
|
+
onTestFinished(() => protocol1.stop(Context.default()));
|
|
65
|
+
onTestFinished(() => protocol2.stop(Context.default()));
|
|
66
|
+
|
|
67
|
+
const builder1 = new TestFeedBuilder();
|
|
68
|
+
const feedStore1 = builder1.createFeedStore();
|
|
69
|
+
|
|
70
|
+
const builder2 = new TestFeedBuilder();
|
|
71
|
+
const feedStore2 = builder2.createFeedStore();
|
|
72
|
+
|
|
73
|
+
const feedKey = await builder1.keyring.createKey();
|
|
74
|
+
const feed1 = await feedStore1.openFeed(feedKey, { writable: true });
|
|
75
|
+
const feed2 = await feedStore2.openFeed(feedKey);
|
|
76
|
+
|
|
77
|
+
await protocol1.addFeed(feed1);
|
|
78
|
+
await protocol2.addFeed(feed2);
|
|
79
|
+
|
|
80
|
+
await feed1.append({ timeframe: new Timeframe() });
|
|
81
|
+
await expect.poll(() => feed2.properties.length).toEqual(1);
|
|
82
|
+
|
|
83
|
+
await feed1.append({ timeframe: new Timeframe() });
|
|
84
|
+
await expect.poll(() => feed2.properties.length).toEqual(2);
|
|
85
|
+
|
|
86
|
+
await builder.close();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// TODO: Some storage drivers may break when there are multiple storage instances.
|
|
90
|
+
test.skip('replicates a feed through a webrtc connection', async () => {
|
|
91
|
+
const builder = new TestAgentBuilder({
|
|
92
|
+
storage: createStorage(),
|
|
93
|
+
});
|
|
94
|
+
onTestFinished(async () => {
|
|
95
|
+
await builder.close();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const keyring = new Keyring();
|
|
99
|
+
const topic = await keyring.createKey();
|
|
100
|
+
|
|
101
|
+
const peer1 = await builder.createPeer();
|
|
102
|
+
const protocol1 = peer1.createSpaceProtocol(topic);
|
|
103
|
+
|
|
104
|
+
const peer2 = await builder.createPeer();
|
|
105
|
+
const protocol2 = peer2.createSpaceProtocol(topic);
|
|
106
|
+
|
|
107
|
+
await protocol1.start(Context.default());
|
|
108
|
+
await protocol2.start(Context.default());
|
|
109
|
+
|
|
110
|
+
onTestFinished(() => protocol1.stop(Context.default()));
|
|
111
|
+
onTestFinished(() => protocol2.stop(Context.default()));
|
|
112
|
+
|
|
113
|
+
const feedKey = await peer1.keyring.createKey();
|
|
114
|
+
|
|
115
|
+
const feed1 = await peer1.feedStore.openFeed(feedKey, { writable: true });
|
|
116
|
+
const feed2 = await peer2.feedStore.openFeed(feedKey);
|
|
117
|
+
|
|
118
|
+
await protocol1.addFeed(feed1);
|
|
119
|
+
await protocol2.addFeed(feed2);
|
|
120
|
+
|
|
121
|
+
await feed1.append({ timeframe: new Timeframe() });
|
|
122
|
+
await expect.poll(() => feed2.properties.length).toEqual(1);
|
|
123
|
+
|
|
124
|
+
await feed1.append({ timeframe: new Timeframe() });
|
|
125
|
+
await expect.poll(() => feed2.properties.length).toEqual(2);
|
|
126
|
+
|
|
127
|
+
await builder.close();
|
|
128
|
+
});
|
|
129
|
+
});
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, expect, onTestFinished, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { Context } from '@dxos/context';
|
|
8
|
+
import { PublicKey } from '@dxos/keys';
|
|
9
|
+
import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
|
|
10
|
+
import { MemoryTransportFactory, SwarmNetworkManager } from '@dxos/network-manager';
|
|
11
|
+
import { StorageType, createStorage } from '@dxos/random-access-storage';
|
|
12
|
+
import { BlobStore } from '@dxos/teleport-extension-object-sync';
|
|
13
|
+
import { Timeframe } from '@dxos/timeframe';
|
|
14
|
+
|
|
15
|
+
import { AuthStatus, MOCK_AUTH_PROVIDER, MOCK_AUTH_VERIFIER, SpaceProtocol } from './space-protocol';
|
|
16
|
+
import { TestAgentBuilder, TestFeedBuilder } from './testing';
|
|
17
|
+
|
|
18
|
+
describe('space/space-protocol', () => {
|
|
19
|
+
// Flaky.
|
|
20
|
+
test('two peers discover each other via presence', async () => {
|
|
21
|
+
const builder = new TestAgentBuilder();
|
|
22
|
+
onTestFinished(async () => {
|
|
23
|
+
await builder.close();
|
|
24
|
+
});
|
|
25
|
+
const topic = PublicKey.random();
|
|
26
|
+
|
|
27
|
+
const peer1 = await builder.createPeer();
|
|
28
|
+
const gossip1 = peer1.createGossip();
|
|
29
|
+
const presence1 = peer1.createPresence(gossip1);
|
|
30
|
+
await presence1.open();
|
|
31
|
+
const protocol1 = peer1.createSpaceProtocol(topic, gossip1);
|
|
32
|
+
|
|
33
|
+
const peer2 = await builder.createPeer();
|
|
34
|
+
const gossip2 = peer2.createGossip();
|
|
35
|
+
const presence2 = peer2.createPresence(gossip2);
|
|
36
|
+
await presence2.open();
|
|
37
|
+
const protocol2 = peer2.createSpaceProtocol(topic, gossip2);
|
|
38
|
+
|
|
39
|
+
await protocol1.start(Context.default());
|
|
40
|
+
onTestFinished(() => protocol1.stop(Context.default()));
|
|
41
|
+
|
|
42
|
+
await protocol2.start(Context.default());
|
|
43
|
+
onTestFinished(() => protocol2.stop(Context.default()));
|
|
44
|
+
|
|
45
|
+
await expect
|
|
46
|
+
.poll(() => presence1.getPeersOnline().some(({ identityKey }) => identityKey.equals(peer2.identityKey)), {
|
|
47
|
+
timeout: 1_000,
|
|
48
|
+
})
|
|
49
|
+
.toBeTruthy();
|
|
50
|
+
await expect
|
|
51
|
+
.poll(() => presence2.getPeersOnline().some(({ identityKey }) => identityKey.equals(peer1.identityKey)), {
|
|
52
|
+
timeout: 1_000,
|
|
53
|
+
})
|
|
54
|
+
.toBeTruthy();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('failing authentication', async () => {
|
|
58
|
+
const [topic, peerId1, peerId2] = PublicKey.randomSequence();
|
|
59
|
+
const signalContext = new MemorySignalManagerContext();
|
|
60
|
+
|
|
61
|
+
const protocol1 = new SpaceProtocol({
|
|
62
|
+
topic,
|
|
63
|
+
swarmIdentity: {
|
|
64
|
+
peerKey: peerId1,
|
|
65
|
+
identityKey: peerId1,
|
|
66
|
+
credentialProvider: MOCK_AUTH_PROVIDER,
|
|
67
|
+
credentialAuthenticator: async () => false, // Reject everyone.
|
|
68
|
+
},
|
|
69
|
+
blobStore: new BlobStore(createStorage({ type: StorageType.RAM }).createDirectory()),
|
|
70
|
+
networkManager: new SwarmNetworkManager({
|
|
71
|
+
signalManager: new MemorySignalManager(signalContext),
|
|
72
|
+
transportFactory: MemoryTransportFactory,
|
|
73
|
+
peerInfo: {
|
|
74
|
+
peerKey: peerId1.toHex(),
|
|
75
|
+
identityKey: peerId1.toHex(),
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const protocol2 = new SpaceProtocol({
|
|
81
|
+
topic,
|
|
82
|
+
swarmIdentity: {
|
|
83
|
+
peerKey: peerId2,
|
|
84
|
+
identityKey: peerId2,
|
|
85
|
+
credentialProvider: MOCK_AUTH_PROVIDER,
|
|
86
|
+
credentialAuthenticator: MOCK_AUTH_VERIFIER,
|
|
87
|
+
},
|
|
88
|
+
blobStore: new BlobStore(createStorage({ type: StorageType.RAM }).createDirectory()),
|
|
89
|
+
networkManager: new SwarmNetworkManager({
|
|
90
|
+
signalManager: new MemorySignalManager(signalContext),
|
|
91
|
+
transportFactory: MemoryTransportFactory,
|
|
92
|
+
peerInfo: {
|
|
93
|
+
peerKey: peerId2.toHex(),
|
|
94
|
+
identityKey: peerId2.toHex(),
|
|
95
|
+
},
|
|
96
|
+
}),
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await protocol1.start(Context.default());
|
|
100
|
+
onTestFinished(() => protocol1.stop(Context.default()));
|
|
101
|
+
|
|
102
|
+
await protocol2.start(Context.default());
|
|
103
|
+
onTestFinished(() => protocol2.stop(Context.default()));
|
|
104
|
+
|
|
105
|
+
await expect.poll(() => protocol1.sessions.get(peerId2)?.authStatus).toEqual(AuthStatus.FAILURE);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('replicates a feed', async () => {
|
|
109
|
+
const builder = new TestAgentBuilder();
|
|
110
|
+
onTestFinished(async () => {
|
|
111
|
+
await builder.close();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const topic = PublicKey.random();
|
|
115
|
+
|
|
116
|
+
const peer1 = await builder.createPeer();
|
|
117
|
+
const protocol1 = peer1.createSpaceProtocol(topic);
|
|
118
|
+
|
|
119
|
+
const peer2 = await builder.createPeer();
|
|
120
|
+
const protocol2 = peer2.createSpaceProtocol(topic);
|
|
121
|
+
|
|
122
|
+
await protocol1.start(Context.default());
|
|
123
|
+
await protocol2.start(Context.default());
|
|
124
|
+
|
|
125
|
+
onTestFinished(() => protocol1.stop(Context.default()));
|
|
126
|
+
onTestFinished(() => protocol2.stop(Context.default()));
|
|
127
|
+
|
|
128
|
+
//
|
|
129
|
+
// Create feeds.
|
|
130
|
+
//
|
|
131
|
+
|
|
132
|
+
const builder1 = new TestFeedBuilder();
|
|
133
|
+
const feedStore1 = builder1.createFeedStore();
|
|
134
|
+
|
|
135
|
+
const builder2 = new TestFeedBuilder();
|
|
136
|
+
const feedStore2 = builder2.createFeedStore();
|
|
137
|
+
|
|
138
|
+
const feed1 = await feedStore1.openFeed(await builder1.keyring.createKey(), { writable: true });
|
|
139
|
+
const feed2 = await feedStore2.openFeed(feed1.key);
|
|
140
|
+
|
|
141
|
+
await protocol1.addFeed(feed1);
|
|
142
|
+
await protocol2.addFeed(feed2);
|
|
143
|
+
|
|
144
|
+
//
|
|
145
|
+
// Append message.
|
|
146
|
+
//
|
|
147
|
+
|
|
148
|
+
// TODO(burdon): Append batch of messages.
|
|
149
|
+
await feed1.append({ timeframe: new Timeframe() });
|
|
150
|
+
// Received message appended before replication.
|
|
151
|
+
await expect.poll(() => feed2.properties.length).toEqual(1);
|
|
152
|
+
|
|
153
|
+
// TODO(burdon): Append batch of messages.
|
|
154
|
+
await feed1.append({ timeframe: new Timeframe() });
|
|
155
|
+
// Received message appended after replication.
|
|
156
|
+
await expect.poll(() => feed2.properties.length).toEqual(2);
|
|
157
|
+
});
|
|
158
|
+
});
|