@dxos/client-services 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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
|
@@ -2,15 +2,25 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import * as EffectContext from 'effect/Context';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
8
|
+
import * as Option from 'effect/Option';
|
|
9
|
+
|
|
5
10
|
import { type PushStream, TimeoutError, type Trigger, scheduleTask } from '@dxos/async';
|
|
6
11
|
import { INVITATION_TIMEOUT, getExpirationTime } from '@dxos/client-protocol';
|
|
7
12
|
import { type Context, ContextDisposedError } from '@dxos/context';
|
|
8
13
|
import { createKeyPair, sign } from '@dxos/crypto';
|
|
9
|
-
import { type EdgeHttpClient } from '@dxos/edge-client';
|
|
14
|
+
import { type EdgeHttpClient, EdgeHttpClientService } from '@dxos/edge-client';
|
|
10
15
|
import { invariant } from '@dxos/invariant';
|
|
11
16
|
import { PublicKey } from '@dxos/keys';
|
|
12
17
|
import { log } from '@dxos/log';
|
|
13
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
type SwarmConnection,
|
|
20
|
+
type SwarmNetworkManager,
|
|
21
|
+
SwarmNetworkManagerService,
|
|
22
|
+
createTeleportProtocolFactory,
|
|
23
|
+
} from '@dxos/network-manager';
|
|
14
24
|
import { InvalidInvitationError, InvalidInvitationExtensionRoleError } from '@dxos/protocols';
|
|
15
25
|
import { type AdmissionKeypair, Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
16
26
|
import { type DeviceProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
@@ -64,7 +74,14 @@ export type InvitationConnectionProps = {
|
|
|
64
74
|
* TODO: the flow logic should either be contained in invitations-handler or in extensions, not be split across
|
|
65
75
|
* TODO: potentially re-evaluate host-side API to allow multiple concurrent connection, so that mutex can be removed
|
|
66
76
|
*/
|
|
67
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Effect service tag for {@link InvitationsHandler}.
|
|
79
|
+
*/
|
|
80
|
+
export class InvitationsHandlerService extends EffectContext.Tag('@dxos/client-services/InvitationsHandler')<
|
|
81
|
+
InvitationsHandlerService,
|
|
82
|
+
InvitationsHandler
|
|
83
|
+
>() {}
|
|
84
|
+
|
|
68
85
|
export class InvitationsHandler {
|
|
69
86
|
/**
|
|
70
87
|
* @internal
|
|
@@ -564,3 +581,22 @@ export const createAdmissionKeypair = (): AdmissionKeypair => {
|
|
|
564
581
|
const keypair = createKeyPair();
|
|
565
582
|
return { publicKey: PublicKey.from(keypair.publicKey), privateKey: keypair.secretKey };
|
|
566
583
|
};
|
|
584
|
+
|
|
585
|
+
export type InvitationsHandlerLayerOptions = {
|
|
586
|
+
connectionProps?: InvitationConnectionProps;
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Effect Layer constructing an {@link InvitationsHandler}.
|
|
591
|
+
*/
|
|
592
|
+
export const InvitationsHandlerLayer = (
|
|
593
|
+
options: InvitationsHandlerLayerOptions = {},
|
|
594
|
+
): Layer.Layer<InvitationsHandlerService, never, SwarmNetworkManagerService> =>
|
|
595
|
+
Layer.effect(
|
|
596
|
+
InvitationsHandlerService,
|
|
597
|
+
Effect.gen(function* () {
|
|
598
|
+
const networkManager = yield* SwarmNetworkManagerService;
|
|
599
|
+
const edgeClient = yield* Effect.serviceOption(EdgeHttpClientService);
|
|
600
|
+
return new InvitationsHandler(networkManager, Option.getOrUndefined(edgeClient), options.connectionProps);
|
|
601
|
+
}),
|
|
602
|
+
);
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import * as EffectContext from 'effect/Context';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
8
|
+
|
|
5
9
|
import { Event, PushStream, TimeoutError, Trigger } from '@dxos/async';
|
|
6
10
|
import {
|
|
7
11
|
AuthenticatingInvitation,
|
|
@@ -11,7 +15,6 @@ import {
|
|
|
11
15
|
} from '@dxos/client-protocol';
|
|
12
16
|
import { Context } from '@dxos/context';
|
|
13
17
|
import { generatePasscode } from '@dxos/credentials';
|
|
14
|
-
import { type IMetadataStore, hasInvitationExpired } from '@dxos/echo-host';
|
|
15
18
|
import { invariant } from '@dxos/invariant';
|
|
16
19
|
import { PublicKey } from '@dxos/keys';
|
|
17
20
|
import { log } from '@dxos/log';
|
|
@@ -23,14 +26,22 @@ import {
|
|
|
23
26
|
import { SpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
24
27
|
import { trace } from '@dxos/tracing';
|
|
25
28
|
|
|
29
|
+
import { type IMetadataStore, IMetadataStoreService, hasInvitationExpired } from '../metadata';
|
|
26
30
|
import type { InvitationProtocol } from './invitation-protocol';
|
|
27
|
-
import { type InvitationsHandler, createAdmissionKeypair } from './invitations-handler';
|
|
31
|
+
import { type InvitationsHandler, InvitationsHandlerService, createAdmissionKeypair } from './invitations-handler';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Effect service tag for {@link InvitationsManager}.
|
|
35
|
+
*/
|
|
36
|
+
export class InvitationsManagerService extends EffectContext.Tag('@dxos/client-services/InvitationsManager')<
|
|
37
|
+
InvitationsManagerService,
|
|
38
|
+
InvitationsManager
|
|
39
|
+
>() {}
|
|
28
40
|
|
|
29
41
|
/**
|
|
30
42
|
* Entry point for creating and accepting invitations, keeps track of existing invitation set and
|
|
31
43
|
* emits events when the set changes.
|
|
32
44
|
*/
|
|
33
|
-
@trace.resource()
|
|
34
45
|
export class InvitationsManager {
|
|
35
46
|
private readonly _createInvitations = new Map<string, CancellableInvitation>();
|
|
36
47
|
private readonly _acceptInvitations = new Map<string, AuthenticatingInvitation>();
|
|
@@ -44,12 +55,29 @@ export class InvitationsManager {
|
|
|
44
55
|
private readonly _persistentInvitationsLoadedEvent = new Event();
|
|
45
56
|
private _persistentInvitationsLoaded = false;
|
|
46
57
|
|
|
58
|
+
private _invitationHandlerFactory?: (
|
|
59
|
+
invitation: Partial<Invitation> & Pick<Invitation, 'kind'>,
|
|
60
|
+
) => InvitationProtocol;
|
|
61
|
+
|
|
47
62
|
constructor(
|
|
48
63
|
private readonly _invitationsHandler: InvitationsHandler,
|
|
49
|
-
private readonly _getHandler: (invitation: Partial<Invitation> & Pick<Invitation, 'kind'>) => InvitationProtocol,
|
|
50
64
|
private readonly _metadataStore: IMetadataStore,
|
|
51
65
|
) {}
|
|
52
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Wires the invitation handler factory after the composing stack is fully constructed.
|
|
69
|
+
*/
|
|
70
|
+
setInvitationHandlerFactory(
|
|
71
|
+
getHandler: (invitation: Partial<Invitation> & Pick<Invitation, 'kind'>) => InvitationProtocol,
|
|
72
|
+
): void {
|
|
73
|
+
this._invitationHandlerFactory = getHandler;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private _getHandler(invitation: Partial<Invitation> & Pick<Invitation, 'kind'>): InvitationProtocol {
|
|
77
|
+
invariant(this._invitationHandlerFactory, 'Invitation handler factory not set.');
|
|
78
|
+
return this._invitationHandlerFactory(invitation);
|
|
79
|
+
}
|
|
80
|
+
|
|
53
81
|
@trace.span({ showInBrowserTimeline: true, op: 'lifecycle' })
|
|
54
82
|
async createInvitation(
|
|
55
83
|
ctx: Context,
|
|
@@ -354,3 +382,23 @@ export class InvitationsManager {
|
|
|
354
382
|
);
|
|
355
383
|
}
|
|
356
384
|
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Effect Layer constructing an {@link InvitationsManager}.
|
|
388
|
+
*
|
|
389
|
+
* The invitation handler factory points "up the stack" and is wired via
|
|
390
|
+
* {@link InvitationsManager.setInvitationHandlerFactory} after composition.
|
|
391
|
+
*/
|
|
392
|
+
export const InvitationsManagerLayer = (): Layer.Layer<
|
|
393
|
+
InvitationsManagerService,
|
|
394
|
+
never,
|
|
395
|
+
InvitationsHandlerService | IMetadataStoreService
|
|
396
|
+
> =>
|
|
397
|
+
Layer.effect(
|
|
398
|
+
InvitationsManagerService,
|
|
399
|
+
Effect.gen(function* () {
|
|
400
|
+
const invitationsHandler = yield* InvitationsHandlerService;
|
|
401
|
+
const metadataStore = yield* IMetadataStoreService;
|
|
402
|
+
return new InvitationsManager(invitationsHandler, metadataStore);
|
|
403
|
+
}),
|
|
404
|
+
);
|
|
@@ -2,14 +2,18 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as EffectStream from 'effect/Stream';
|
|
7
|
+
|
|
8
|
+
import { Context } from '@dxos/context';
|
|
6
9
|
import {
|
|
7
10
|
type AcceptInvitationRequest,
|
|
8
11
|
type AuthenticationRequest,
|
|
12
|
+
type CancelInvitationRequest,
|
|
9
13
|
type Invitation,
|
|
10
|
-
type InvitationsService,
|
|
11
14
|
QueryInvitationsResponse,
|
|
12
15
|
} from '@dxos/protocols/proto/dxos/client/services';
|
|
16
|
+
import { type InvitationsService } from '@dxos/protocols/rpc';
|
|
13
17
|
import { trace } from '@dxos/tracing';
|
|
14
18
|
|
|
15
19
|
import { type InvitationsManager } from './invitations-manager';
|
|
@@ -17,48 +21,68 @@ import { type InvitationsManager } from './invitations-manager';
|
|
|
17
21
|
/**
|
|
18
22
|
* Adapts invitation service observable to client/service stream.
|
|
19
23
|
*/
|
|
20
|
-
export class InvitationsServiceImpl implements InvitationsService {
|
|
21
|
-
constructor(private readonly _invitationsManager: InvitationsManager) {}
|
|
24
|
+
export class InvitationsServiceImpl implements InvitationsService.Handlers {
|
|
25
|
+
'constructor'(private readonly _invitationsManager: InvitationsManager) {}
|
|
22
26
|
|
|
23
27
|
// TODO(burdon): Guest/host label.
|
|
24
|
-
getLoggingContext() {
|
|
28
|
+
'getLoggingContext'() {
|
|
25
29
|
return {
|
|
26
30
|
// deviceKey: this._identityManager.identity?.deviceKey
|
|
27
31
|
};
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
createInvitation(request: Invitation
|
|
31
|
-
return
|
|
34
|
+
['InvitationsService.createInvitation'](request: Invitation): EffectStream.Stream<Invitation, Error> {
|
|
35
|
+
return EffectStream.async<Invitation, Error>((emit) => {
|
|
36
|
+
const ctx = Context.default();
|
|
32
37
|
void this._invitationsManager
|
|
33
38
|
.createInvitation(ctx, request)
|
|
34
39
|
.then((invitation) => {
|
|
35
40
|
trace.metrics.increment('dxos.invitation.created');
|
|
36
|
-
invitation.subscribe(
|
|
41
|
+
invitation.subscribe(
|
|
42
|
+
(value) => void emit.single(value),
|
|
43
|
+
(err) => void emit.fail(err),
|
|
44
|
+
() => void emit.end(),
|
|
45
|
+
);
|
|
37
46
|
})
|
|
38
|
-
.catch(
|
|
39
|
-
|
|
47
|
+
.catch((err) => void emit.fail(err));
|
|
48
|
+
return Effect.promise(() => ctx.dispose());
|
|
49
|
+
});
|
|
40
50
|
}
|
|
41
51
|
|
|
42
|
-
acceptInvitation(request: AcceptInvitationRequest
|
|
43
|
-
return
|
|
52
|
+
['InvitationsService.acceptInvitation'](request: AcceptInvitationRequest): EffectStream.Stream<Invitation, Error> {
|
|
53
|
+
return EffectStream.async<Invitation, Error>((emit) => {
|
|
54
|
+
const ctx = Context.default();
|
|
44
55
|
const invitation = this._invitationsManager.acceptInvitation(ctx, request);
|
|
45
|
-
invitation.subscribe(
|
|
46
|
-
|
|
56
|
+
invitation.subscribe(
|
|
57
|
+
(value) => void emit.single(value),
|
|
58
|
+
(err) => void emit.fail(err),
|
|
59
|
+
() => void emit.end(),
|
|
60
|
+
);
|
|
61
|
+
return Effect.promise(() => ctx.dispose());
|
|
62
|
+
});
|
|
47
63
|
}
|
|
48
64
|
|
|
49
|
-
|
|
50
|
-
return
|
|
65
|
+
['InvitationsService.authenticate'](request: AuthenticationRequest): Effect.Effect<void, Error> {
|
|
66
|
+
return Effect.tryPromise({
|
|
67
|
+
try: () => this._invitationsManager.authenticate(request),
|
|
68
|
+
catch: (error) => error as Error,
|
|
69
|
+
});
|
|
51
70
|
}
|
|
52
71
|
|
|
53
|
-
|
|
54
|
-
return
|
|
72
|
+
['InvitationsService.cancelInvitation'](request: CancelInvitationRequest): Effect.Effect<void, Error> {
|
|
73
|
+
return Effect.tryPromise({
|
|
74
|
+
try: () => this._invitationsManager.cancelInvitation(request),
|
|
75
|
+
catch: (error) => error as Error,
|
|
76
|
+
});
|
|
55
77
|
}
|
|
56
78
|
|
|
57
|
-
queryInvitations(): Stream<QueryInvitationsResponse> {
|
|
58
|
-
return
|
|
79
|
+
['InvitationsService.queryInvitations'](): EffectStream.Stream<QueryInvitationsResponse, Error> {
|
|
80
|
+
return EffectStream.async<QueryInvitationsResponse, Error>((emit) => {
|
|
81
|
+
const ctx = Context.default();
|
|
82
|
+
|
|
59
83
|
// Push added invitations to the stream.
|
|
60
84
|
this._invitationsManager.invitationCreated.on(ctx, (invitation) => {
|
|
61
|
-
|
|
85
|
+
void emit.single({
|
|
62
86
|
action: QueryInvitationsResponse.Action.ADDED,
|
|
63
87
|
type: QueryInvitationsResponse.Type.CREATED,
|
|
64
88
|
invitations: [invitation],
|
|
@@ -66,7 +90,7 @@ export class InvitationsServiceImpl implements InvitationsService {
|
|
|
66
90
|
});
|
|
67
91
|
|
|
68
92
|
this._invitationsManager.invitationAccepted.on(ctx, (invitation) => {
|
|
69
|
-
|
|
93
|
+
void emit.single({
|
|
70
94
|
action: QueryInvitationsResponse.Action.ADDED,
|
|
71
95
|
type: QueryInvitationsResponse.Type.ACCEPTED,
|
|
72
96
|
invitations: [invitation],
|
|
@@ -75,7 +99,7 @@ export class InvitationsServiceImpl implements InvitationsService {
|
|
|
75
99
|
|
|
76
100
|
// Push removed invitations to the stream.
|
|
77
101
|
this._invitationsManager.removedCreated.on(ctx, (invitation) => {
|
|
78
|
-
|
|
102
|
+
void emit.single({
|
|
79
103
|
action: QueryInvitationsResponse.Action.REMOVED,
|
|
80
104
|
type: QueryInvitationsResponse.Type.CREATED,
|
|
81
105
|
invitations: [invitation],
|
|
@@ -83,7 +107,7 @@ export class InvitationsServiceImpl implements InvitationsService {
|
|
|
83
107
|
});
|
|
84
108
|
|
|
85
109
|
this._invitationsManager.removedAccepted.on(ctx, (invitation) => {
|
|
86
|
-
|
|
110
|
+
void emit.single({
|
|
87
111
|
action: QueryInvitationsResponse.Action.REMOVED,
|
|
88
112
|
type: QueryInvitationsResponse.Type.ACCEPTED,
|
|
89
113
|
invitations: [invitation],
|
|
@@ -92,7 +116,7 @@ export class InvitationsServiceImpl implements InvitationsService {
|
|
|
92
116
|
|
|
93
117
|
// used only for testing
|
|
94
118
|
this._invitationsManager.saved.on(ctx, (invitation) => {
|
|
95
|
-
|
|
119
|
+
void emit.single({
|
|
96
120
|
action: QueryInvitationsResponse.Action.SAVED,
|
|
97
121
|
type: QueryInvitationsResponse.Type.CREATED,
|
|
98
122
|
invitations: [invitation],
|
|
@@ -100,14 +124,14 @@ export class InvitationsServiceImpl implements InvitationsService {
|
|
|
100
124
|
});
|
|
101
125
|
|
|
102
126
|
// Push existing invitations to the stream.
|
|
103
|
-
|
|
127
|
+
void emit.single({
|
|
104
128
|
action: QueryInvitationsResponse.Action.ADDED,
|
|
105
129
|
type: QueryInvitationsResponse.Type.CREATED,
|
|
106
130
|
invitations: this._invitationsManager.getCreatedInvitations(),
|
|
107
131
|
existing: true,
|
|
108
132
|
});
|
|
109
133
|
|
|
110
|
-
|
|
134
|
+
void emit.single({
|
|
111
135
|
action: QueryInvitationsResponse.Action.ADDED,
|
|
112
136
|
type: QueryInvitationsResponse.Type.ACCEPTED,
|
|
113
137
|
invitations: this._invitationsManager.getAcceptedInvitations(),
|
|
@@ -115,13 +139,15 @@ export class InvitationsServiceImpl implements InvitationsService {
|
|
|
115
139
|
});
|
|
116
140
|
|
|
117
141
|
this._invitationsManager.onPersistentInvitationsLoaded(ctx, () => {
|
|
118
|
-
|
|
142
|
+
void emit.single({
|
|
119
143
|
action: QueryInvitationsResponse.Action.LOAD_COMPLETE,
|
|
120
144
|
type: QueryInvitationsResponse.Type.CREATED,
|
|
121
145
|
// TODO(nf): populate with invitations
|
|
122
146
|
});
|
|
123
147
|
});
|
|
124
148
|
// TODO(nf): expired invitations?
|
|
149
|
+
|
|
150
|
+
return Effect.promise(() => ctx.dispose());
|
|
125
151
|
});
|
|
126
152
|
}
|
|
127
153
|
}
|
|
@@ -2,20 +2,23 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as EffectStream from 'effect/Stream';
|
|
7
|
+
|
|
5
8
|
import { Event } from '@dxos/async';
|
|
6
|
-
import {
|
|
9
|
+
import { Context } from '@dxos/context';
|
|
7
10
|
import { PublicKey } from '@dxos/keys';
|
|
8
11
|
import { type LogLevel, type LogProcessor, type LogEntry as NaturalLogEntry, log } from '@dxos/log';
|
|
9
12
|
import {
|
|
10
13
|
type ControlMetricsRequest,
|
|
11
14
|
type ControlMetricsResponse,
|
|
12
15
|
type LogEntry,
|
|
13
|
-
type LoggingService,
|
|
14
16
|
type Metrics,
|
|
15
17
|
QueryLogsRequest,
|
|
16
18
|
type QueryMetricsRequest,
|
|
17
19
|
type QueryMetricsResponse,
|
|
18
20
|
} from '@dxos/protocols/proto/dxos/client/services';
|
|
21
|
+
import { type LoggingService } from '@dxos/protocols/rpc';
|
|
19
22
|
import { numericalValues, tracer } from '@dxos/util';
|
|
20
23
|
|
|
21
24
|
/**
|
|
@@ -25,45 +28,52 @@ import { numericalValues, tracer } from '@dxos/util';
|
|
|
25
28
|
* seen in the main window console without opening the shared worker DevTools. Shared worker client
|
|
26
29
|
* services is deprecated; dedicated worker logs already show in the main window console.
|
|
27
30
|
*/
|
|
28
|
-
export class LoggingServiceImpl implements LoggingService {
|
|
29
|
-
private readonly _logs = new Event<NaturalLogEntry>();
|
|
30
|
-
private readonly _started = Date.now();
|
|
31
|
-
private readonly _sessionId = PublicKey.random().toHex();
|
|
31
|
+
export class LoggingServiceImpl implements LoggingService.Handlers {
|
|
32
|
+
private readonly '_logs' = new Event<NaturalLogEntry>();
|
|
33
|
+
private readonly '_started' = Date.now();
|
|
34
|
+
private readonly '_sessionId' = PublicKey.random().toHex();
|
|
32
35
|
|
|
33
|
-
async open(): Promise<void> {
|
|
36
|
+
async 'open'(): Promise<void> {
|
|
34
37
|
log.runtimeConfig.processors.push(this._logProcessor);
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
async close(): Promise<void> {
|
|
40
|
+
async 'close'(): Promise<void> {
|
|
38
41
|
const index = log.runtimeConfig.processors.findIndex((processor: LogProcessor) => processor === this._logProcessor);
|
|
39
42
|
log.runtimeConfig.processors.splice(index, 1);
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
45
|
+
['LoggingService.controlMetrics']({
|
|
46
|
+
reset,
|
|
47
|
+
record,
|
|
48
|
+
}: ControlMetricsRequest): Effect.Effect<ControlMetricsResponse, Error> {
|
|
49
|
+
return Effect.sync(() => {
|
|
50
|
+
if (reset) {
|
|
51
|
+
tracer.clear();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (record === true) {
|
|
55
|
+
tracer.start();
|
|
56
|
+
} else if (record === false) {
|
|
57
|
+
tracer.stop();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return { recording: tracer.recording };
|
|
61
|
+
});
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
/**
|
|
57
65
|
* @deprecated (Move to diagnostics).
|
|
58
66
|
*/
|
|
59
|
-
queryMetrics({
|
|
67
|
+
['LoggingService.queryMetrics']({
|
|
68
|
+
interval = 5_000,
|
|
69
|
+
}: QueryMetricsRequest): EffectStream.Stream<QueryMetricsResponse, Error> {
|
|
60
70
|
// TODO(burdon): Map all traces; how to bind to reducer/metrics shape (e.g., numericalValues)?
|
|
61
71
|
const getNumericalValues = (key: string) => {
|
|
62
72
|
const events = tracer.get(key) ?? [];
|
|
63
73
|
return { key, stats: numericalValues(events, 'duration') };
|
|
64
74
|
};
|
|
65
75
|
|
|
66
|
-
return
|
|
76
|
+
return EffectStream.async<QueryMetricsResponse, Error>((emit) => {
|
|
67
77
|
const update = () => {
|
|
68
78
|
const metrics: Metrics = {
|
|
69
79
|
timestamp: new Date(),
|
|
@@ -73,7 +83,7 @@ export class LoggingServiceImpl implements LoggingService {
|
|
|
73
83
|
].filter(Boolean) as Metrics.KeyPair[],
|
|
74
84
|
};
|
|
75
85
|
|
|
76
|
-
|
|
86
|
+
void emit.single({
|
|
77
87
|
timestamp: new Date(),
|
|
78
88
|
metrics,
|
|
79
89
|
});
|
|
@@ -81,14 +91,15 @@ export class LoggingServiceImpl implements LoggingService {
|
|
|
81
91
|
|
|
82
92
|
update();
|
|
83
93
|
const i = setInterval(update, Math.max(interval, 1_000));
|
|
84
|
-
return () => {
|
|
94
|
+
return Effect.sync(() => {
|
|
85
95
|
clearInterval(i);
|
|
86
|
-
};
|
|
96
|
+
});
|
|
87
97
|
});
|
|
88
98
|
}
|
|
89
99
|
|
|
90
|
-
queryLogs(request: QueryLogsRequest): Stream<LogEntry> {
|
|
91
|
-
return
|
|
100
|
+
['LoggingService.queryLogs'](request: QueryLogsRequest): EffectStream.Stream<LogEntry, Error> {
|
|
101
|
+
return EffectStream.async<LogEntry, Error>((emit) => {
|
|
102
|
+
const ctx = Context.default();
|
|
92
103
|
const handler = (entry: NaturalLogEntry) => {
|
|
93
104
|
// This call was caused by the logging service itself.
|
|
94
105
|
if (LOG_PROCESSING > 0) {
|
|
@@ -133,17 +144,18 @@ export class LoggingServiceImpl implements LoggingService {
|
|
|
133
144
|
|
|
134
145
|
try {
|
|
135
146
|
LOG_PROCESSING++;
|
|
136
|
-
|
|
147
|
+
void emit.single(record);
|
|
137
148
|
} finally {
|
|
138
149
|
LOG_PROCESSING--;
|
|
139
150
|
}
|
|
140
151
|
};
|
|
141
152
|
|
|
142
153
|
this._logs.on(ctx, handler);
|
|
154
|
+
return Effect.promise(() => ctx.dispose());
|
|
143
155
|
});
|
|
144
156
|
}
|
|
145
157
|
|
|
146
|
-
private _logProcessor: LogProcessor = (_config, entry) => {
|
|
158
|
+
private '_logProcessor': LogProcessor = (_config, entry) => {
|
|
147
159
|
this._logs.emit(entry);
|
|
148
160
|
};
|
|
149
161
|
}
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as Fiber from 'effect/Fiber';
|
|
7
|
+
import * as Option from 'effect/Option';
|
|
8
|
+
import * as Stream from 'effect/Stream';
|
|
5
9
|
import { afterEach, beforeEach, describe, expect, test } from 'vitest';
|
|
6
10
|
|
|
7
|
-
import {
|
|
11
|
+
import { EffectEx } from '@dxos/effect';
|
|
8
12
|
import { LogLevel, log } from '@dxos/log';
|
|
9
|
-
import { type LogEntry } from '@dxos/protocols/proto/dxos/client/services';
|
|
10
13
|
|
|
11
14
|
import { LoggingServiceImpl } from './logging-service';
|
|
12
15
|
|
|
@@ -23,26 +26,36 @@ describe('LoggingService', () => {
|
|
|
23
26
|
});
|
|
24
27
|
|
|
25
28
|
test('queryLogs streams logs', async () => {
|
|
26
|
-
const trigger = new Trigger<LogEntry>();
|
|
27
|
-
loggingService.queryLogs({}).subscribe((entry) => {
|
|
28
|
-
trigger.wake(entry);
|
|
29
|
-
});
|
|
30
29
|
const message = 'Hello World!';
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
const entry = await EffectEx.runPromise(
|
|
31
|
+
Effect.gen(function* () {
|
|
32
|
+
const fiber = yield* Effect.fork(Stream.runHead(loggingService['LoggingService.queryLogs']({})));
|
|
33
|
+
// Yield so the forked subscription registers its log handler before emitting.
|
|
34
|
+
yield* Effect.yieldNow();
|
|
35
|
+
yield* Effect.sync(() => log(message));
|
|
36
|
+
return Option.getOrThrow(yield* Fiber.join(fiber));
|
|
37
|
+
}),
|
|
38
|
+
);
|
|
33
39
|
expect(entry.message).to.eq(message);
|
|
34
40
|
expect(entry.level).to.eq(LogLevel.DEBUG);
|
|
35
41
|
});
|
|
36
42
|
|
|
37
43
|
test('queryLogs filters logs', async () => {
|
|
38
|
-
const trigger = new Trigger<LogEntry>();
|
|
39
|
-
loggingService.queryLogs({ filters: [{ level: LogLevel.ERROR }] }).subscribe((entry) => {
|
|
40
|
-
trigger.wake(entry);
|
|
41
|
-
});
|
|
42
|
-
log('debugging something');
|
|
43
44
|
const message = 'This is a failure';
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
const entry = await EffectEx.runPromise(
|
|
46
|
+
Effect.gen(function* () {
|
|
47
|
+
const fiber = yield* Effect.fork(
|
|
48
|
+
Stream.runHead(loggingService['LoggingService.queryLogs']({ filters: [{ level: LogLevel.ERROR }] })),
|
|
49
|
+
);
|
|
50
|
+
// Yield so the forked subscription registers its log handler before emitting.
|
|
51
|
+
yield* Effect.yieldNow();
|
|
52
|
+
yield* Effect.sync(() => {
|
|
53
|
+
log('debugging something');
|
|
54
|
+
log.error(message);
|
|
55
|
+
});
|
|
56
|
+
return Option.getOrThrow(yield* Fiber.join(fiber));
|
|
57
|
+
}),
|
|
58
|
+
);
|
|
46
59
|
expect(entry.message).to.eq(message);
|
|
47
60
|
expect(entry.level).to.eq(LogLevel.ERROR);
|
|
48
61
|
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { PublicKey } from '@dxos/keys';
|
|
8
|
+
import { StorageType, createStorage } from '@dxos/random-access-storage';
|
|
9
|
+
|
|
10
|
+
import { MetadataStore } from './metadata-store';
|
|
11
|
+
|
|
12
|
+
describe('MetadataStore', () => {
|
|
13
|
+
describe('deleted spaces', () => {
|
|
14
|
+
test('addDeletedSpace records a tombstone', async ({ expect }) => {
|
|
15
|
+
const store = new MetadataStore(createStorage({ type: StorageType.RAM }).createDirectory());
|
|
16
|
+
const spaceKey = PublicKey.random();
|
|
17
|
+
|
|
18
|
+
expect(store.deletedSpaces).to.have.length(0);
|
|
19
|
+
|
|
20
|
+
await store.addDeletedSpace(spaceKey);
|
|
21
|
+
expect(store.deletedSpaces).to.have.length(1);
|
|
22
|
+
expect(store.deletedSpaces[0].equals(spaceKey)).to.be.true;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('addDeletedSpace is idempotent', async ({ expect }) => {
|
|
26
|
+
const store = new MetadataStore(createStorage({ type: StorageType.RAM }).createDirectory());
|
|
27
|
+
const spaceKey = PublicKey.random();
|
|
28
|
+
|
|
29
|
+
await store.addDeletedSpace(spaceKey);
|
|
30
|
+
await store.addDeletedSpace(spaceKey);
|
|
31
|
+
expect(store.deletedSpaces).to.have.length(1);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('tombstones survive reload', async ({ expect }) => {
|
|
35
|
+
const directory = createStorage({ type: StorageType.RAM }).createDirectory();
|
|
36
|
+
const spaceKey = PublicKey.random();
|
|
37
|
+
|
|
38
|
+
const store = new MetadataStore(directory);
|
|
39
|
+
await store.load();
|
|
40
|
+
await store.addDeletedSpace(spaceKey);
|
|
41
|
+
await store.close();
|
|
42
|
+
|
|
43
|
+
const reloaded = new MetadataStore(directory);
|
|
44
|
+
await reloaded.load();
|
|
45
|
+
expect(reloaded.deletedSpaces).to.have.length(1);
|
|
46
|
+
expect(reloaded.deletedSpaces[0].equals(spaceKey)).to.be.true;
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|