@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,22 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type FeedWriter } from '@dxos/feed-store';
|
|
6
|
+
import { invariant } from '@dxos/invariant';
|
|
7
|
+
import { type MaybePromise } from '@dxos/util';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Maps the written arguments onto a different message type.
|
|
11
|
+
*/
|
|
12
|
+
export const createMappedFeedWriter = <Source extends {}, Target extends {}>(
|
|
13
|
+
mapper: (arg: Source) => MaybePromise<Target>,
|
|
14
|
+
writer: FeedWriter<Target>,
|
|
15
|
+
): FeedWriter<Source> => {
|
|
16
|
+
invariant(mapper);
|
|
17
|
+
invariant(writer);
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
write: async (data: Source, options) => await writer.write(await mapper(data), options),
|
|
21
|
+
};
|
|
22
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2020 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type FeedBlock, type FeedBlockSelector } from '@dxos/feed-store';
|
|
6
|
+
import { invariant } from '@dxos/invariant';
|
|
7
|
+
import { log } from '@dxos/log';
|
|
8
|
+
import type { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
9
|
+
|
|
10
|
+
import { type TimeframeClock } from './timeframe-clock';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The MessageSelector makes sure that we read in a trusted order.
|
|
14
|
+
* The first message we wish to process is the SpaceGenesis, which will admit a Feed.
|
|
15
|
+
* As we encounter and process FeedAdmit messages those are added to the Space's trust,
|
|
16
|
+
* and we begin processing messages from them as well.
|
|
17
|
+
*/
|
|
18
|
+
export const createMessageSelector = (timeframeClock: TimeframeClock): FeedBlockSelector<FeedMessage> => {
|
|
19
|
+
return (messages: FeedBlock<FeedMessage>[]) => {
|
|
20
|
+
// Pick the first candidate with a valid timeframe that has no gaps.
|
|
21
|
+
for (let i = 0; i < messages.length; i++) {
|
|
22
|
+
const {
|
|
23
|
+
data: { timeframe },
|
|
24
|
+
} = messages[i];
|
|
25
|
+
invariant(timeframe);
|
|
26
|
+
|
|
27
|
+
if (!timeframeClock.hasGaps(timeframe)) {
|
|
28
|
+
return i;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Not ready for this message yet.
|
|
33
|
+
log('Skipping...');
|
|
34
|
+
};
|
|
35
|
+
};
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as fc from 'fast-check';
|
|
6
|
+
import { inspect } from 'node:util';
|
|
7
|
+
import { describe, expect, test } from 'vitest';
|
|
8
|
+
|
|
9
|
+
import { asyncTimeout } from '@dxos/async';
|
|
10
|
+
import { type FeedStore, type FeedWrapper } from '@dxos/feed-store';
|
|
11
|
+
import { PublicKey } from '@dxos/keys';
|
|
12
|
+
import { log } from '@dxos/log';
|
|
13
|
+
import { type FeedMessageBlock } from '@dxos/protocols';
|
|
14
|
+
import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
15
|
+
import { Timeframe } from '@dxos/timeframe';
|
|
16
|
+
import { range } from '@dxos/util';
|
|
17
|
+
|
|
18
|
+
import { Pipeline } from './pipeline';
|
|
19
|
+
import { TestFeedBuilder } from './testing';
|
|
20
|
+
|
|
21
|
+
const NUM_AGENTS = 2;
|
|
22
|
+
const NUM_MESSAGES = 10;
|
|
23
|
+
|
|
24
|
+
// TODO(burdon): Describe test.
|
|
25
|
+
describe('pipeline/stress test', () => {
|
|
26
|
+
test.skip('stress', { timeout: 60_000 }, async () => {
|
|
27
|
+
const builder = new TestFeedBuilder();
|
|
28
|
+
|
|
29
|
+
const agentIds = range(NUM_AGENTS).map(() => PublicKey.random().toHex().slice(0, 8));
|
|
30
|
+
const anAgentId = fc.constantFrom(...agentIds);
|
|
31
|
+
|
|
32
|
+
const commands = fc.commands(
|
|
33
|
+
[
|
|
34
|
+
fc.tuple(anAgentId, fc.integer({ min: 1, max: 10 })).map(([agent, count]) => new WriteCommand(agent, count)),
|
|
35
|
+
fc.constant(new SyncCommand()),
|
|
36
|
+
anAgentId.map((agent) => new RestartCommand(agent)),
|
|
37
|
+
],
|
|
38
|
+
{ size: 'large' },
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const model = fc.asyncProperty(commands, async (commands) => {
|
|
42
|
+
const feedStore = builder.createFeedStore();
|
|
43
|
+
|
|
44
|
+
const agents = new Map(agentIds.map((id) => [id, new Agent(builder, feedStore, id)]));
|
|
45
|
+
await Promise.all(Array.from(agents.values()).map((agent) => agent.open()));
|
|
46
|
+
await Promise.all(Array.from(agents.values()).map((agent) => agent.start()));
|
|
47
|
+
|
|
48
|
+
const setup: fc.ModelRunSetup<Model, Real> = () => ({
|
|
49
|
+
model: {},
|
|
50
|
+
real: {
|
|
51
|
+
feedStore,
|
|
52
|
+
agents,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
await fc.asyncModelRun(setup, [...commands, new SyncCommand()]);
|
|
58
|
+
} finally {
|
|
59
|
+
await Promise.all(Array.from(agents.values()).map((agent) => agent.stop()));
|
|
60
|
+
await Promise.all(Array.from(agents.values()).map((agent) => agent.close()));
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const examples: [commands: Iterable<fc.AsyncCommand<Model, Real, boolean>>][] = [
|
|
65
|
+
[[new WriteCommand(agentIds[0], 10), new WriteCommand(agentIds[1], 10), new SyncCommand()]],
|
|
66
|
+
[[new WriteCommand(agentIds[0], 4), new RestartCommand(agentIds[0]), new SyncCommand()]],
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
await fc.assert(model, { examples });
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
class Agent {
|
|
74
|
+
public startingTimeframe = new Timeframe();
|
|
75
|
+
public pipeline!: Pipeline;
|
|
76
|
+
public feed!: FeedWrapper<FeedMessage>;
|
|
77
|
+
public messages: FeedMessageBlock[] = [];
|
|
78
|
+
public writePromise: Promise<any> = Promise.resolve();
|
|
79
|
+
|
|
80
|
+
constructor(
|
|
81
|
+
private readonly builder: TestFeedBuilder,
|
|
82
|
+
public feedStore: FeedStore<FeedMessage>,
|
|
83
|
+
public id: string,
|
|
84
|
+
) {}
|
|
85
|
+
|
|
86
|
+
async open(): Promise<void> {
|
|
87
|
+
const key = await this.builder.keyring.createKey();
|
|
88
|
+
this.feed = await this.feedStore.openFeed(key, { writable: true });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async start(): Promise<void> {
|
|
92
|
+
this.pipeline = new Pipeline();
|
|
93
|
+
await this.pipeline.setCursor(this.startingTimeframe);
|
|
94
|
+
await this.pipeline.start();
|
|
95
|
+
|
|
96
|
+
// NOTE: not awaiting here breaks the test.
|
|
97
|
+
await Promise.all(this.feedStore.feeds.map((feed) => this.pipeline.addFeed(feed)));
|
|
98
|
+
this.pipeline.setWriteFeed(this.feed);
|
|
99
|
+
|
|
100
|
+
// consume in async task.
|
|
101
|
+
void this.consume();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async stop(): Promise<void> {
|
|
105
|
+
await this.pipeline.stop();
|
|
106
|
+
this.startingTimeframe = this.pipeline.state.timeframe;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async close(): Promise<void> {
|
|
110
|
+
await this.feed.close();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
write(message: FeedMessage.Payload): void {
|
|
114
|
+
const prev = this.writePromise;
|
|
115
|
+
const promise = this.pipeline.writer!.write(message);
|
|
116
|
+
this.writePromise = Promise.all([prev, promise]);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async consume(): Promise<void> {
|
|
120
|
+
for await (const msg of this.pipeline.consume()) {
|
|
121
|
+
this.messages.push(msg);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
log('stopped consuming');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
type Model = {};
|
|
129
|
+
type Real = {
|
|
130
|
+
feedStore: FeedStore<FeedMessage>;
|
|
131
|
+
agents: Map<string, Agent>;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
class WriteCommand implements fc.AsyncCommand<Model, Real> {
|
|
135
|
+
constructor(
|
|
136
|
+
public agent: string,
|
|
137
|
+
public count: number,
|
|
138
|
+
) {}
|
|
139
|
+
|
|
140
|
+
check = () => true;
|
|
141
|
+
|
|
142
|
+
async run(model: Model, real: Real): Promise<void> {
|
|
143
|
+
// console.log(`WriteCommand(${this.agent}, ${this.count})`);
|
|
144
|
+
const agent = real.agents.get(this.agent)!;
|
|
145
|
+
const toWrite = Math.min(this.count, NUM_MESSAGES - agent.feed.length);
|
|
146
|
+
if (toWrite > 0) {
|
|
147
|
+
for (const _ of range(toWrite)) {
|
|
148
|
+
agent.write({}); // Content is not important.
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
toString = () => `WriteCommand(${this.agent}, ${this.count})`;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
class SyncCommand implements fc.AsyncCommand<Model, Real> {
|
|
157
|
+
check = () => true;
|
|
158
|
+
|
|
159
|
+
async run(model: Model, real: Real): Promise<void> {
|
|
160
|
+
// console.log('SyncCommand()');
|
|
161
|
+
const targets: any = {};
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
for (const agent of real.agents.values()) {
|
|
165
|
+
await agent.writePromise;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
for (const agent of real.agents.values()) {
|
|
169
|
+
targets[agent.id] = agent.pipeline.state.endTimeframe;
|
|
170
|
+
if (agent.pipeline.state.endTimeframe.isEmpty()) {
|
|
171
|
+
log('empty endtimeframe', {
|
|
172
|
+
id: agent.id,
|
|
173
|
+
endTimeframe: agent.pipeline.state.endTimeframe,
|
|
174
|
+
feeds: agent.pipeline.getFeeds().map((feed) => [feed.key.toString(), feed.length]),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
await asyncTimeout(agent.pipeline.state.waitUntilTimeframe(agent.pipeline.state.endTimeframe), 1000);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const tf: Timeframe = real.agents.values().next().value!.pipeline.state.timeframe;
|
|
181
|
+
for (const agent of real.agents.values()) {
|
|
182
|
+
expect(agent.pipeline.state.timeframe.equals(tf)).toEqual(true);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const totalMessages = real.feedStore.feeds.reduce((acc, feed) => acc + feed.length, 0);
|
|
186
|
+
for (const agent of real.agents.values()) {
|
|
187
|
+
expect(agent.messages.length).toEqual(totalMessages);
|
|
188
|
+
}
|
|
189
|
+
} catch (err) {
|
|
190
|
+
log(
|
|
191
|
+
inspect(
|
|
192
|
+
{
|
|
193
|
+
agents: Array.from(real.agents.values()).map((agent) => ({
|
|
194
|
+
id: agent.id,
|
|
195
|
+
messages: agent.messages.length,
|
|
196
|
+
feeds: agent.pipeline.getFeeds().map((feed) => [feed.key, feed.length]),
|
|
197
|
+
timeframe: agent.pipeline.state.timeframe,
|
|
198
|
+
endTimeframe: agent.pipeline.state.endTimeframe,
|
|
199
|
+
})),
|
|
200
|
+
feeds: real.feedStore.feeds.map((feed) => [feed.key, feed.length]),
|
|
201
|
+
targets,
|
|
202
|
+
},
|
|
203
|
+
false,
|
|
204
|
+
null,
|
|
205
|
+
true,
|
|
206
|
+
),
|
|
207
|
+
);
|
|
208
|
+
throw err;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
toString = () => 'SyncCommand()';
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
class RestartCommand implements fc.AsyncCommand<Model, Real> {
|
|
216
|
+
constructor(public agent: string) {}
|
|
217
|
+
|
|
218
|
+
check = () => true;
|
|
219
|
+
|
|
220
|
+
async run(model: Model, real: Real): Promise<void> {
|
|
221
|
+
log(`RestartCommand(${this.agent})`);
|
|
222
|
+
|
|
223
|
+
const agent = real.agents.get(this.agent)!;
|
|
224
|
+
await agent.writePromise;
|
|
225
|
+
await agent.stop();
|
|
226
|
+
await agent.start();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
toString = () => `RestartCommand(${this.agent})`;
|
|
230
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, expect, onTestFinished, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { Event, sleep } from '@dxos/async';
|
|
8
|
+
import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
9
|
+
import { Timeframe } from '@dxos/timeframe';
|
|
10
|
+
import { range } from '@dxos/util';
|
|
11
|
+
|
|
12
|
+
import { Pipeline } from './pipeline';
|
|
13
|
+
import { TestFeedBuilder } from './testing';
|
|
14
|
+
|
|
15
|
+
const TEST_MESSAGE: FeedMessage = {
|
|
16
|
+
timeframe: new Timeframe(),
|
|
17
|
+
payload: {},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
describe('pipeline/Pipeline', () => {
|
|
21
|
+
test('asynchronous reader & writer without ordering', async () => {
|
|
22
|
+
const pipeline = new Pipeline();
|
|
23
|
+
|
|
24
|
+
const builder = new TestFeedBuilder();
|
|
25
|
+
const feedStore = builder.createFeedStore();
|
|
26
|
+
|
|
27
|
+
// Remote feeds from other peers.
|
|
28
|
+
const numFeeds = 5;
|
|
29
|
+
const messagesPerFeed = 10;
|
|
30
|
+
for (const _ in range(numFeeds)) {
|
|
31
|
+
const key = await builder.keyring.createKey();
|
|
32
|
+
const feed = await feedStore.openFeed(key, { writable: true });
|
|
33
|
+
void pipeline.addFeed(feed);
|
|
34
|
+
|
|
35
|
+
setTimeout(async () => {
|
|
36
|
+
for (const _ in range(messagesPerFeed)) {
|
|
37
|
+
await feed.append(TEST_MESSAGE);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Local feed.
|
|
43
|
+
const key = await builder.keyring.createKey();
|
|
44
|
+
const feed = await feedStore.openFeed(key, { writable: true });
|
|
45
|
+
void pipeline.addFeed(feed);
|
|
46
|
+
pipeline.setWriteFeed(feed);
|
|
47
|
+
|
|
48
|
+
for (const _ in range(messagesPerFeed)) {
|
|
49
|
+
await pipeline.writer!.write({});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
await pipeline.start();
|
|
53
|
+
|
|
54
|
+
let msgCount = 0;
|
|
55
|
+
for await (const _ of pipeline.consume()) {
|
|
56
|
+
if (++msgCount === numFeeds * messagesPerFeed) {
|
|
57
|
+
void pipeline.stop();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('reading and writing with cursor changes', async () => {
|
|
63
|
+
const pipeline = new Pipeline();
|
|
64
|
+
onTestFinished(() => pipeline.stop());
|
|
65
|
+
|
|
66
|
+
const builder = new TestFeedBuilder();
|
|
67
|
+
const feedStore = builder.createFeedStore();
|
|
68
|
+
const key = await builder.keyring.createKey();
|
|
69
|
+
const feed = await feedStore.openFeed(key, { writable: true });
|
|
70
|
+
await pipeline.addFeed(feed);
|
|
71
|
+
|
|
72
|
+
const numMessages = 30;
|
|
73
|
+
const sequenceNumbers: number[] = [];
|
|
74
|
+
for (const _ of range(numMessages)) {
|
|
75
|
+
const { seq } = await feed.appendWithReceipt(TEST_MESSAGE);
|
|
76
|
+
sequenceNumbers.push(seq);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const processedSequenceNumbers: number[] = [];
|
|
80
|
+
|
|
81
|
+
// Skip first 10, process the rest, and the repeat the last 10.
|
|
82
|
+
const expectedSequenceNumbers = [...sequenceNumbers.slice(10, 30), ...sequenceNumbers.slice(20, 30)];
|
|
83
|
+
|
|
84
|
+
await pipeline.setCursor(new Timeframe([[feed.key, 9]]));
|
|
85
|
+
await pipeline.start();
|
|
86
|
+
|
|
87
|
+
for await (const block of pipeline.consume()) {
|
|
88
|
+
processedSequenceNumbers.push(block.seq);
|
|
89
|
+
|
|
90
|
+
if (processedSequenceNumbers.length === 20) {
|
|
91
|
+
// not awaited to avoid a deadlock.
|
|
92
|
+
void pipeline.pause().then(async () => {
|
|
93
|
+
await pipeline.setCursor(new Timeframe([[feed.key, 19]]));
|
|
94
|
+
await pipeline.unpause();
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (processedSequenceNumbers.length === 30) {
|
|
98
|
+
void pipeline.stop();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
expect(processedSequenceNumbers).toEqual(expectedSequenceNumbers);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('cursor change while polling', async () => {
|
|
106
|
+
const pipeline = new Pipeline();
|
|
107
|
+
onTestFinished(() => pipeline.stop());
|
|
108
|
+
|
|
109
|
+
const builder = new TestFeedBuilder();
|
|
110
|
+
const feedStore = builder.createFeedStore();
|
|
111
|
+
const key = await builder.keyring.createKey();
|
|
112
|
+
const feed = await feedStore.openFeed(key, { writable: true });
|
|
113
|
+
await pipeline.addFeed(feed);
|
|
114
|
+
|
|
115
|
+
for (const _ of range(20)) {
|
|
116
|
+
await feed.appendWithReceipt(TEST_MESSAGE);
|
|
117
|
+
}
|
|
118
|
+
await feed.clear(0, 10);
|
|
119
|
+
|
|
120
|
+
const processedSequenceNumbers: number[] = [];
|
|
121
|
+
const expectedSequenceNumbers = range(20).slice(10);
|
|
122
|
+
const processedEvent = new Event();
|
|
123
|
+
setTimeout(async () => {
|
|
124
|
+
for await (const block of pipeline.consume()) {
|
|
125
|
+
processedSequenceNumbers.push(block.seq);
|
|
126
|
+
processedEvent.emit();
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
await pipeline.start();
|
|
131
|
+
await sleep(1000);
|
|
132
|
+
|
|
133
|
+
await pipeline.pause();
|
|
134
|
+
await pipeline.setCursor(new Timeframe([[feed.key, 9]]));
|
|
135
|
+
await pipeline.unpause();
|
|
136
|
+
|
|
137
|
+
await processedEvent.waitForCondition(() => processedSequenceNumbers.length === 10);
|
|
138
|
+
expect(processedSequenceNumbers).toEqual(expectedSequenceNumbers);
|
|
139
|
+
});
|
|
140
|
+
});
|