@dxos/client-services 0.8.4-main.69d29f4 → 0.8.4-main.6fa680abb7
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/browser/{chunk-KBXLEVD5.mjs → chunk-CZN7GX3A.mjs} +386 -121
- package/dist/lib/browser/chunk-CZN7GX3A.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +23 -15
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +1 -1
- package/dist/lib/node-esm/{chunk-G62TR33T.mjs → chunk-F36CDLDY.mjs} +386 -121
- package/dist/lib/node-esm/chunk-F36CDLDY.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +23 -15
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +1 -1
- package/dist/types/src/packlets/logging/logging-service.d.ts +4 -0
- package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
- package/dist/types/src/packlets/services/feed-syncer.d.ts +59 -0
- package/dist/types/src/packlets/services/feed-syncer.d.ts.map +1 -0
- package/dist/types/src/packlets/services/feed-syncer.test.d.ts +2 -0
- package/dist/types/src/packlets/services/feed-syncer.test.d.ts.map +1 -0
- package/dist/types/src/packlets/services/platform.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +1 -2
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-runtime.d.ts +11 -3
- package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +1 -1
- package/dist/types/src/version.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +43 -43
- package/src/packlets/logging/logging-service.ts +4 -0
- package/src/packlets/services/feed-syncer.test.ts +340 -0
- package/src/packlets/services/feed-syncer.ts +330 -0
- package/src/packlets/services/platform.ts +7 -1
- package/src/packlets/services/service-context.ts +29 -8
- package/src/packlets/services/service-host.ts +0 -3
- package/src/packlets/spaces/data-space.ts +3 -0
- package/src/packlets/worker/worker-runtime.ts +13 -5
- package/src/packlets/worker/worker-session.ts +4 -4
- package/src/version.ts +1 -1
- package/dist/lib/browser/chunk-KBXLEVD5.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-G62TR33T.mjs.map +0 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/client-services",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.6fa680abb7",
|
|
4
4
|
"description": "DXOS client services implementation",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -61,56 +61,56 @@
|
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@automerge/automerge": "3.2.3",
|
|
63
63
|
"@automerge/automerge-repo": "2.5.1",
|
|
64
|
-
"@effect/experimental": "0.
|
|
65
|
-
"@effect/sql": "0.
|
|
66
|
-
"@effect/sql-sqlite-node": "0.
|
|
64
|
+
"@effect/experimental": "0.58.0",
|
|
65
|
+
"@effect/sql": "0.49.0",
|
|
66
|
+
"@effect/sql-sqlite-node": "0.50.1",
|
|
67
67
|
"@obsidize/tar-browserify": "^5.2.0",
|
|
68
68
|
"cbor-x": "^1.5.4",
|
|
69
|
-
"effect": "3.19.
|
|
69
|
+
"effect": "3.19.16",
|
|
70
70
|
"platform": "^1.3.6",
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/
|
|
73
|
-
"@dxos/
|
|
74
|
-
"@dxos/
|
|
75
|
-
"@dxos/
|
|
76
|
-
"@dxos/
|
|
77
|
-
"@dxos/
|
|
78
|
-
"@dxos/echo": "0.8.4-main.
|
|
79
|
-
"@dxos/echo-
|
|
80
|
-
"@dxos/
|
|
81
|
-
"@dxos/echo-protocol": "0.8.4-main.
|
|
82
|
-
"@dxos/
|
|
83
|
-
"@dxos/
|
|
84
|
-
"@dxos/
|
|
85
|
-
"@dxos/
|
|
86
|
-
"@dxos/
|
|
87
|
-
"@dxos/
|
|
88
|
-
"@dxos/
|
|
89
|
-
"@dxos/
|
|
90
|
-
"@dxos/
|
|
91
|
-
"@dxos/
|
|
92
|
-
"@dxos/
|
|
93
|
-
"@dxos/
|
|
94
|
-
"@dxos/
|
|
95
|
-
"@dxos/
|
|
96
|
-
"@dxos/protocols": "0.8.4-main.
|
|
97
|
-
"@dxos/
|
|
98
|
-
"@dxos/
|
|
99
|
-
"@dxos/
|
|
100
|
-
"@dxos/teleport": "0.8.4-main.
|
|
101
|
-
"@dxos/teleport-extension-
|
|
102
|
-
"@dxos/
|
|
103
|
-
"@dxos/
|
|
104
|
-
"@dxos/
|
|
105
|
-
"@dxos/
|
|
106
|
-
"@dxos/
|
|
71
|
+
"@dxos/client-protocol": "0.8.4-main.6fa680abb7",
|
|
72
|
+
"@dxos/config": "0.8.4-main.6fa680abb7",
|
|
73
|
+
"@dxos/context": "0.8.4-main.6fa680abb7",
|
|
74
|
+
"@dxos/credentials": "0.8.4-main.6fa680abb7",
|
|
75
|
+
"@dxos/debug": "0.8.4-main.6fa680abb7",
|
|
76
|
+
"@dxos/crypto": "0.8.4-main.6fa680abb7",
|
|
77
|
+
"@dxos/echo": "0.8.4-main.6fa680abb7",
|
|
78
|
+
"@dxos/echo-db": "0.8.4-main.6fa680abb7",
|
|
79
|
+
"@dxos/echo-pipeline": "0.8.4-main.6fa680abb7",
|
|
80
|
+
"@dxos/codec-protobuf": "0.8.4-main.6fa680abb7",
|
|
81
|
+
"@dxos/echo-protocol": "0.8.4-main.6fa680abb7",
|
|
82
|
+
"@dxos/async": "0.8.4-main.6fa680abb7",
|
|
83
|
+
"@dxos/edge-client": "0.8.4-main.6fa680abb7",
|
|
84
|
+
"@dxos/effect": "0.8.4-main.6fa680abb7",
|
|
85
|
+
"@dxos/feed-store": "0.8.4-main.6fa680abb7",
|
|
86
|
+
"@dxos/keyring": "0.8.4-main.6fa680abb7",
|
|
87
|
+
"@dxos/invariant": "0.8.4-main.6fa680abb7",
|
|
88
|
+
"@dxos/keys": "0.8.4-main.6fa680abb7",
|
|
89
|
+
"@dxos/lock-file": "0.8.4-main.6fa680abb7",
|
|
90
|
+
"@dxos/kv-store": "0.8.4-main.6fa680abb7",
|
|
91
|
+
"@dxos/log": "0.8.4-main.6fa680abb7",
|
|
92
|
+
"@dxos/messaging": "0.8.4-main.6fa680abb7",
|
|
93
|
+
"@dxos/network-manager": "0.8.4-main.6fa680abb7",
|
|
94
|
+
"@dxos/random-access-storage": "0.8.4-main.6fa680abb7",
|
|
95
|
+
"@dxos/rpc": "0.8.4-main.6fa680abb7",
|
|
96
|
+
"@dxos/protocols": "0.8.4-main.6fa680abb7",
|
|
97
|
+
"@dxos/node-std": "0.8.4-main.6fa680abb7",
|
|
98
|
+
"@dxos/feed": "0.8.4-main.6fa680abb7",
|
|
99
|
+
"@dxos/sql-sqlite": "0.8.4-main.6fa680abb7",
|
|
100
|
+
"@dxos/teleport": "0.8.4-main.6fa680abb7",
|
|
101
|
+
"@dxos/teleport-extension-gossip": "0.8.4-main.6fa680abb7",
|
|
102
|
+
"@dxos/teleport-extension-object-sync": "0.8.4-main.6fa680abb7",
|
|
103
|
+
"@dxos/tracing": "0.8.4-main.6fa680abb7",
|
|
104
|
+
"@dxos/timeframe": "0.8.4-main.6fa680abb7",
|
|
105
|
+
"@dxos/websocket-rpc": "0.8.4-main.6fa680abb7",
|
|
106
|
+
"@dxos/util": "0.8.4-main.6fa680abb7"
|
|
107
107
|
},
|
|
108
108
|
"devDependencies": {
|
|
109
109
|
"@types/platform": "^1.3.4",
|
|
110
110
|
"@types/readable-stream": "^2.3.9",
|
|
111
111
|
"get-port-please": "^3.1.1",
|
|
112
|
-
"@dxos/test-utils": "0.8.4-main.
|
|
113
|
-
"@dxos/signal": "0.8.4-main.
|
|
112
|
+
"@dxos/test-utils": "0.8.4-main.6fa680abb7",
|
|
113
|
+
"@dxos/signal": "0.8.4-main.6fa680abb7"
|
|
114
114
|
},
|
|
115
115
|
"publishConfig": {
|
|
116
116
|
"access": "public"
|
|
@@ -26,6 +26,10 @@ import { getDebugName, jsonify, numericalValues, tracer } from '@dxos/util';
|
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Logging service used to spy on logs of the host.
|
|
29
|
+
*
|
|
30
|
+
* @deprecated This was created so that logs from the shared worker (WorkerClientServices) could be
|
|
31
|
+
* seen in the main window console without opening the shared worker DevTools. Shared worker client
|
|
32
|
+
* services is deprecated; dedicated worker logs already show in the main window console.
|
|
29
33
|
*/
|
|
30
34
|
export class LoggingServiceImpl implements LoggingService {
|
|
31
35
|
private readonly _logs = new Event<NaturalLogEntry>();
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Encoder, decode as cborDecode } from 'cbor-x';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
8
|
+
import * as ManagedRuntime from 'effect/ManagedRuntime';
|
|
9
|
+
import { describe, expect, onTestFinished, test, vi } from 'vitest';
|
|
10
|
+
|
|
11
|
+
import { Event } from '@dxos/async';
|
|
12
|
+
import { Context } from '@dxos/context';
|
|
13
|
+
import { type EdgeConnection, MessageSchema } from '@dxos/edge-client';
|
|
14
|
+
import { RuntimeProvider } from '@dxos/effect';
|
|
15
|
+
import { FeedStore, SyncServer } from '@dxos/feed';
|
|
16
|
+
import { ObjectId, SpaceId } from '@dxos/keys';
|
|
17
|
+
import { FeedProtocol } from '@dxos/protocols';
|
|
18
|
+
import { EdgeService } from '@dxos/protocols';
|
|
19
|
+
import { createBuf } from '@dxos/protocols/buf';
|
|
20
|
+
import { type Message as RouterMessage } from '@dxos/protocols/buf/dxos/edge/messenger_pb';
|
|
21
|
+
import { EdgeStatus } from '@dxos/protocols/proto/dxos/client/services';
|
|
22
|
+
import { SqlTransaction } from '@dxos/sql-sqlite';
|
|
23
|
+
import { layerMemory } from '@dxos/sql-sqlite/platform';
|
|
24
|
+
import { bufferToArray } from '@dxos/util';
|
|
25
|
+
|
|
26
|
+
import { FeedSyncer } from './feed-syncer';
|
|
27
|
+
|
|
28
|
+
type ProtocolMessage = FeedProtocol.ProtocolMessage;
|
|
29
|
+
|
|
30
|
+
const encoder = new Encoder({ tagUint8Array: false, useRecords: false });
|
|
31
|
+
const syncNamespace = FeedProtocol.WellKnownNamespaces.data;
|
|
32
|
+
const syncNamespaces = [FeedProtocol.WellKnownNamespaces.data, FeedProtocol.WellKnownNamespaces.trace];
|
|
33
|
+
|
|
34
|
+
const createRuntime = () => {
|
|
35
|
+
const baseLayer = layerMemory;
|
|
36
|
+
const transactionLayer = SqlTransaction.layer.pipe(Layer.provide(baseLayer));
|
|
37
|
+
return ManagedRuntime.make(Layer.merge(baseLayer, transactionLayer).pipe(Layer.orDie));
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const createFeedStore = (localActorId: string, assignPositions: boolean) =>
|
|
41
|
+
new FeedStore({ localActorId, assignPositions });
|
|
42
|
+
|
|
43
|
+
const createEdgeConnection = ({
|
|
44
|
+
syncServer,
|
|
45
|
+
serverRuntime,
|
|
46
|
+
messageListeners,
|
|
47
|
+
}: {
|
|
48
|
+
syncServer: SyncServer;
|
|
49
|
+
serverRuntime: ReturnType<typeof createRuntime>;
|
|
50
|
+
messageListeners: Set<(message: RouterMessage) => void>;
|
|
51
|
+
}): EdgeConnection => {
|
|
52
|
+
const reconnectListeners = new Set<() => void>();
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
statusChanged: new Event<any>(),
|
|
56
|
+
info: {},
|
|
57
|
+
identityKey: 'client-identity',
|
|
58
|
+
peerKey: 'client-peer',
|
|
59
|
+
isOpen: true,
|
|
60
|
+
status: {
|
|
61
|
+
state: EdgeStatus.ConnectionState.CONNECTED,
|
|
62
|
+
rtt: 0,
|
|
63
|
+
uptime: 0,
|
|
64
|
+
rateBytesUp: 0,
|
|
65
|
+
rateBytesDown: 0,
|
|
66
|
+
messagesSent: 0,
|
|
67
|
+
messagesReceived: 0,
|
|
68
|
+
},
|
|
69
|
+
setIdentity: () => {},
|
|
70
|
+
open: async () => {},
|
|
71
|
+
close: async () => {},
|
|
72
|
+
send: async (routerMessage: RouterMessage) => {
|
|
73
|
+
const decoded = cborDecode(routerMessage.payload!.value) as ProtocolMessage;
|
|
74
|
+
await syncServer.handleMessage(decoded).pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
|
|
75
|
+
},
|
|
76
|
+
onMessage: (listener: (message: RouterMessage) => void) => {
|
|
77
|
+
messageListeners.add(listener);
|
|
78
|
+
return () => messageListeners.delete(listener);
|
|
79
|
+
},
|
|
80
|
+
onReconnected: (listener: () => void) => {
|
|
81
|
+
reconnectListeners.add(listener);
|
|
82
|
+
return () => reconnectListeners.delete(listener);
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const createFeedSyncHarness = async ({
|
|
88
|
+
spaceId,
|
|
89
|
+
pollingInterval,
|
|
90
|
+
syncNamespaces: namespaces = [syncNamespace],
|
|
91
|
+
}: {
|
|
92
|
+
spaceId: SpaceId;
|
|
93
|
+
pollingInterval?: number;
|
|
94
|
+
syncNamespaces?: string[];
|
|
95
|
+
}) => {
|
|
96
|
+
const serverRuntime = createRuntime();
|
|
97
|
+
const clientRuntime = createRuntime();
|
|
98
|
+
const serverFeedStore = createFeedStore('server', true);
|
|
99
|
+
const clientFeedStore = createFeedStore('client', false);
|
|
100
|
+
|
|
101
|
+
await serverFeedStore.migrate().pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
|
|
102
|
+
await clientFeedStore.migrate().pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
|
|
103
|
+
|
|
104
|
+
const messageListeners = new Set<(message: RouterMessage) => void>();
|
|
105
|
+
const syncServer = new SyncServer({
|
|
106
|
+
peerId: 'server',
|
|
107
|
+
feedStore: serverFeedStore,
|
|
108
|
+
sendMessage: (message) =>
|
|
109
|
+
Effect.promise(async () => {
|
|
110
|
+
const routerMessage = createBuf(MessageSchema, {
|
|
111
|
+
source: {
|
|
112
|
+
identityKey: 'server-identity',
|
|
113
|
+
peerKey: 'server-peer',
|
|
114
|
+
},
|
|
115
|
+
serviceId: `${EdgeService.QUEUE_REPLICATOR}:test`,
|
|
116
|
+
payload: { value: bufferToArray(encoder.encode(message)) },
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
for (const listener of messageListeners) {
|
|
120
|
+
listener(routerMessage);
|
|
121
|
+
}
|
|
122
|
+
}),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const edgeClient = createEdgeConnection({ syncServer, serverRuntime, messageListeners });
|
|
126
|
+
|
|
127
|
+
const syncer = new FeedSyncer({
|
|
128
|
+
runtime: clientRuntime.runtimeEffect,
|
|
129
|
+
feedStore: clientFeedStore,
|
|
130
|
+
edgeClient: edgeClient as any,
|
|
131
|
+
peerId: 'client',
|
|
132
|
+
getSpaceIds: () => [spaceId],
|
|
133
|
+
syncNamespaces: namespaces,
|
|
134
|
+
pollingInterval,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const close = async () => {
|
|
138
|
+
await syncer.close();
|
|
139
|
+
await clientRuntime.dispose();
|
|
140
|
+
await serverRuntime.dispose();
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
onTestFinished(close);
|
|
144
|
+
|
|
145
|
+
return { serverRuntime, clientRuntime, serverFeedStore, clientFeedStore, syncer, close };
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
describe('FeedSyncer', () => {
|
|
149
|
+
test('syncs mixed pull and push traffic', async () => {
|
|
150
|
+
const spaceId = SpaceId.random();
|
|
151
|
+
const { serverRuntime, clientRuntime, serverFeedStore, clientFeedStore, syncer } = await createFeedSyncHarness({
|
|
152
|
+
spaceId,
|
|
153
|
+
});
|
|
154
|
+
const serverFeedId = ObjectId.random();
|
|
155
|
+
const clientFeedId = ObjectId.random();
|
|
156
|
+
|
|
157
|
+
await serverFeedStore
|
|
158
|
+
.appendLocal([
|
|
159
|
+
{
|
|
160
|
+
spaceId,
|
|
161
|
+
feedId: serverFeedId,
|
|
162
|
+
feedNamespace: syncNamespace,
|
|
163
|
+
data: new Uint8Array([1, 2, 3]),
|
|
164
|
+
},
|
|
165
|
+
])
|
|
166
|
+
.pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
|
|
167
|
+
|
|
168
|
+
await syncer.open(new Context());
|
|
169
|
+
|
|
170
|
+
await vi.waitFor(async () => {
|
|
171
|
+
const { blocks } = await clientFeedStore
|
|
172
|
+
.query({
|
|
173
|
+
spaceId,
|
|
174
|
+
feedNamespace: syncNamespace,
|
|
175
|
+
position: -1,
|
|
176
|
+
query: { feedIds: [serverFeedId] },
|
|
177
|
+
})
|
|
178
|
+
.pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
|
|
179
|
+
|
|
180
|
+
expect(blocks).toHaveLength(1);
|
|
181
|
+
expect(blocks[0].data).toEqual(new Uint8Array([1, 2, 3]));
|
|
182
|
+
expect(blocks[0].position).toBeDefined();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
await clientFeedStore
|
|
186
|
+
.appendLocal([
|
|
187
|
+
{
|
|
188
|
+
spaceId,
|
|
189
|
+
feedId: clientFeedId,
|
|
190
|
+
feedNamespace: syncNamespace,
|
|
191
|
+
data: new Uint8Array([9, 8, 7]),
|
|
192
|
+
},
|
|
193
|
+
])
|
|
194
|
+
.pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
|
|
195
|
+
|
|
196
|
+
await vi.waitFor(async () => {
|
|
197
|
+
const { blocks } = await serverFeedStore
|
|
198
|
+
.query({
|
|
199
|
+
spaceId,
|
|
200
|
+
feedNamespace: syncNamespace,
|
|
201
|
+
position: -1,
|
|
202
|
+
query: { feedIds: [clientFeedId] },
|
|
203
|
+
})
|
|
204
|
+
.pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
|
|
205
|
+
|
|
206
|
+
expect(blocks).toHaveLength(1);
|
|
207
|
+
expect(blocks[0].data).toEqual(new Uint8Array([9, 8, 7]));
|
|
208
|
+
expect(blocks[0].position).toBeDefined();
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test('requestPoll triggers best-effort pull for a space', async () => {
|
|
213
|
+
const spaceId = SpaceId.random();
|
|
214
|
+
const { serverRuntime, clientRuntime, serverFeedStore, clientFeedStore, syncer } = await createFeedSyncHarness({
|
|
215
|
+
spaceId,
|
|
216
|
+
pollingInterval: 60_000,
|
|
217
|
+
});
|
|
218
|
+
const serverFeedId = ObjectId.random();
|
|
219
|
+
|
|
220
|
+
await serverFeedStore
|
|
221
|
+
.appendLocal([
|
|
222
|
+
{
|
|
223
|
+
spaceId,
|
|
224
|
+
feedId: serverFeedId,
|
|
225
|
+
feedNamespace: syncNamespace,
|
|
226
|
+
data: new Uint8Array([1, 2, 3]),
|
|
227
|
+
},
|
|
228
|
+
])
|
|
229
|
+
.pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
|
|
230
|
+
|
|
231
|
+
await syncer.open(new Context());
|
|
232
|
+
|
|
233
|
+
await vi.waitFor(async () => {
|
|
234
|
+
const { blocks } = await clientFeedStore
|
|
235
|
+
.query({
|
|
236
|
+
spaceId,
|
|
237
|
+
feedNamespace: syncNamespace,
|
|
238
|
+
position: -1,
|
|
239
|
+
query: { feedIds: [serverFeedId] },
|
|
240
|
+
})
|
|
241
|
+
.pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
|
|
242
|
+
|
|
243
|
+
expect(blocks).toHaveLength(1);
|
|
244
|
+
expect(blocks[0].data).toEqual(new Uint8Array([1, 2, 3]));
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
await serverFeedStore
|
|
248
|
+
.appendLocal([
|
|
249
|
+
{
|
|
250
|
+
spaceId,
|
|
251
|
+
feedId: serverFeedId,
|
|
252
|
+
feedNamespace: syncNamespace,
|
|
253
|
+
data: new Uint8Array([4, 5, 6]),
|
|
254
|
+
},
|
|
255
|
+
])
|
|
256
|
+
.pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
|
|
257
|
+
|
|
258
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
259
|
+
{
|
|
260
|
+
const { blocks } = await clientFeedStore
|
|
261
|
+
.query({
|
|
262
|
+
spaceId,
|
|
263
|
+
feedNamespace: syncNamespace,
|
|
264
|
+
position: -1,
|
|
265
|
+
query: { feedIds: [serverFeedId] },
|
|
266
|
+
})
|
|
267
|
+
.pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
|
|
268
|
+
expect(blocks).toHaveLength(1);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
syncer.schedulePoll();
|
|
272
|
+
|
|
273
|
+
await vi.waitFor(async () => {
|
|
274
|
+
const { blocks } = await clientFeedStore
|
|
275
|
+
.query({
|
|
276
|
+
spaceId,
|
|
277
|
+
feedNamespace: syncNamespace,
|
|
278
|
+
position: -1,
|
|
279
|
+
query: { feedIds: [serverFeedId] },
|
|
280
|
+
})
|
|
281
|
+
.pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
|
|
282
|
+
|
|
283
|
+
expect(blocks).toHaveLength(2);
|
|
284
|
+
expect(blocks[1].data).toEqual(new Uint8Array([4, 5, 6]));
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test('syncs all configured namespaces', async () => {
|
|
289
|
+
const spaceId = SpaceId.random();
|
|
290
|
+
const { serverRuntime, clientRuntime, serverFeedStore, clientFeedStore, syncer } = await createFeedSyncHarness({
|
|
291
|
+
spaceId,
|
|
292
|
+
syncNamespaces,
|
|
293
|
+
});
|
|
294
|
+
const serverDataFeedId = ObjectId.random();
|
|
295
|
+
const serverTraceFeedId = ObjectId.random();
|
|
296
|
+
|
|
297
|
+
await serverFeedStore
|
|
298
|
+
.appendLocal([
|
|
299
|
+
{
|
|
300
|
+
spaceId,
|
|
301
|
+
feedId: serverDataFeedId,
|
|
302
|
+
feedNamespace: FeedProtocol.WellKnownNamespaces.data,
|
|
303
|
+
data: new Uint8Array([1, 2, 3]),
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
spaceId,
|
|
307
|
+
feedId: serverTraceFeedId,
|
|
308
|
+
feedNamespace: FeedProtocol.WellKnownNamespaces.trace,
|
|
309
|
+
data: new Uint8Array([7, 8, 9]),
|
|
310
|
+
},
|
|
311
|
+
])
|
|
312
|
+
.pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
|
|
313
|
+
|
|
314
|
+
await syncer.open(new Context());
|
|
315
|
+
|
|
316
|
+
await vi.waitFor(async () => {
|
|
317
|
+
const dataResult = await clientFeedStore
|
|
318
|
+
.query({
|
|
319
|
+
spaceId,
|
|
320
|
+
feedNamespace: FeedProtocol.WellKnownNamespaces.data,
|
|
321
|
+
position: -1,
|
|
322
|
+
query: { feedIds: [serverDataFeedId] },
|
|
323
|
+
})
|
|
324
|
+
.pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
|
|
325
|
+
const traceResult = await clientFeedStore
|
|
326
|
+
.query({
|
|
327
|
+
spaceId,
|
|
328
|
+
feedNamespace: FeedProtocol.WellKnownNamespaces.trace,
|
|
329
|
+
position: -1,
|
|
330
|
+
query: { feedIds: [serverTraceFeedId] },
|
|
331
|
+
})
|
|
332
|
+
.pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
|
|
333
|
+
|
|
334
|
+
expect(dataResult.blocks).toHaveLength(1);
|
|
335
|
+
expect(traceResult.blocks).toHaveLength(1);
|
|
336
|
+
expect(dataResult.blocks[0].data).toEqual(new Uint8Array([1, 2, 3]));
|
|
337
|
+
expect(traceResult.blocks[0].data).toEqual(new Uint8Array([7, 8, 9]));
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
});
|