@verdant-web/server 3.3.10 → 4.0.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/bin/server.mjs +110 -107
- package/dist/esm/TokenVerifier.d.ts +1 -0
- package/dist/esm/TokenVerifier.js +3 -0
- package/dist/esm/TokenVerifier.js.map +1 -1
- package/dist/esm/adapters/node/errorHandler.d.ts +2 -0
- package/dist/esm/adapters/node/errorHandler.js +12 -0
- package/dist/esm/adapters/node/errorHandler.js.map +1 -0
- package/dist/esm/adapters/node/getRequestToken.d.ts +1 -0
- package/dist/esm/adapters/node/getRequestToken.js +25 -0
- package/dist/esm/adapters/node/getRequestToken.js.map +1 -0
- package/dist/esm/adapters/node/httpRouter.d.ts +47 -0
- package/dist/esm/adapters/node/httpRouter.js +88 -0
- package/dist/esm/adapters/node/httpRouter.js.map +1 -0
- package/dist/esm/adapters/node/index.d.ts +5 -0
- package/dist/esm/adapters/node/index.js +6 -0
- package/dist/esm/adapters/node/index.js.map +1 -0
- package/dist/esm/adapters/node/tokenMiddleware.d.ts +7 -0
- package/dist/esm/adapters/node/tokenMiddleware.js +22 -0
- package/dist/esm/adapters/node/tokenMiddleware.js.map +1 -0
- package/dist/esm/adapters/node/websocketHandler.d.ts +4 -0
- package/dist/esm/adapters/node/websocketHandler.js +54 -0
- package/dist/esm/adapters/node/websocketHandler.js.map +1 -0
- package/dist/esm/connections/ClientConnection.d.ts +25 -0
- package/dist/esm/{ClientConnection.js → connections/ClientConnection.js} +47 -38
- package/dist/esm/connections/ClientConnection.js.map +1 -0
- package/dist/esm/connections/MessageSender.d.ts +5 -0
- package/dist/esm/connections/MessageSender.js.map +1 -0
- package/dist/esm/connections/Presence.d.ts +23 -0
- package/dist/esm/connections/Presence.js +65 -0
- package/dist/esm/connections/Presence.js.map +1 -0
- package/dist/esm/core.d.ts +15 -0
- package/dist/esm/core.js +15 -0
- package/dist/esm/core.js.map +1 -0
- package/dist/esm/defaults.d.ts +2 -0
- package/dist/esm/defaults.js +3 -0
- package/dist/esm/defaults.js.map +1 -0
- package/dist/esm/files/FileStorage.d.ts +12 -3
- package/dist/esm/files/FileStorage.js +20 -0
- package/dist/esm/files/FileStorage.js.map +1 -1
- package/dist/esm/index.d.ts +7 -7
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internals.d.ts +14 -0
- package/dist/esm/internals.js +12 -0
- package/dist/esm/internals.js.map +1 -0
- package/dist/esm/libraries/Library.d.ts +78 -0
- package/dist/esm/{ServerLibrary.js → libraries/Library.js} +153 -144
- package/dist/esm/libraries/Library.js.map +1 -0
- package/dist/esm/{ServerLibrary.test.js → libraries/Library.test.js} +42 -33
- package/dist/esm/libraries/Library.test.js.map +1 -0
- package/dist/esm/libraries/generic.d.ts +8 -0
- package/dist/esm/libraries/generic.js +2 -0
- package/dist/esm/libraries/generic.js.map +1 -0
- package/dist/esm/libraries/singleNode.d.ts +53 -0
- package/dist/esm/libraries/singleNode.js +88 -0
- package/dist/esm/libraries/singleNode.js.map +1 -0
- package/dist/esm/logger.d.ts +1 -0
- package/dist/esm/logger.js +2 -0
- package/dist/esm/logger.js.map +1 -0
- package/dist/esm/storage/Storage.d.ts +39 -38
- package/dist/esm/storage/StorageManager.d.ts +11 -0
- package/dist/esm/storage/StorageManager.js +32 -0
- package/dist/esm/storage/StorageManager.js.map +1 -0
- package/dist/esm/storage/index.d.ts +1 -2
- package/dist/esm/storage/index.js +1 -2
- package/dist/esm/storage/index.js.map +1 -1
- package/dist/esm/storage/sqlShard/Databases.d.ts +5 -3
- package/dist/esm/storage/sqlShard/Databases.js +11 -7
- package/dist/esm/storage/sqlShard/Databases.js.map +1 -1
- package/dist/esm/storage/sqlShard/SqlBaselines.d.ts +16 -17
- package/dist/esm/storage/sqlShard/SqlBaselines.js +55 -59
- package/dist/esm/storage/sqlShard/SqlBaselines.js.map +1 -1
- package/dist/esm/storage/sqlShard/SqlFileMetadata.d.ts +13 -13
- package/dist/esm/storage/sqlShard/SqlFileMetadata.js +44 -57
- package/dist/esm/storage/sqlShard/SqlFileMetadata.js.map +1 -1
- package/dist/esm/storage/sqlShard/SqlOperations.d.ts +12 -12
- package/dist/esm/storage/sqlShard/SqlOperations.js +38 -73
- package/dist/esm/storage/sqlShard/SqlOperations.js.map +1 -1
- package/dist/esm/storage/sqlShard/SqlReplicas.d.ts +18 -17
- package/dist/esm/storage/sqlShard/SqlReplicas.js +63 -100
- package/dist/esm/storage/sqlShard/SqlReplicas.js.map +1 -1
- package/dist/esm/storage/sqlShard/database.d.ts +25 -5
- package/dist/esm/storage/sqlShard/database.js +47 -15
- package/dist/esm/storage/sqlShard/database.js.map +1 -1
- package/dist/esm/storage/sqlShard/migrations/v1.d.ts +2 -3
- package/dist/esm/storage/sqlShard/migrations/v1.js +42 -47
- package/dist/esm/storage/sqlShard/migrations/v1.js.map +1 -1
- package/dist/esm/storage/sqlShard/migrations/v2.d.ts +2 -3
- package/dist/esm/storage/sqlShard/migrations/v2.js +5 -15
- package/dist/esm/storage/sqlShard/migrations/v2.js.map +1 -1
- package/dist/esm/storage/sqlShard/migrations.d.ts +5 -7
- package/dist/esm/storage/sqlShard/migrations.js +48 -1
- package/dist/esm/storage/sqlShard/migrations.js.map +1 -1
- package/dist/esm/storage/sqlShard/sqlShardStorage.d.ts +25 -4
- package/dist/esm/storage/sqlShard/sqlShardStorage.js +43 -40
- package/dist/esm/storage/sqlShard/sqlShardStorage.js.map +1 -1
- package/dist/esm/storage/sqlShard/tables.d.ts +9 -6
- package/dist/esm/types.d.ts +1 -2
- package/package.json +24 -13
- package/src/TokenVerifier.ts +4 -0
- package/src/adapters/node/errorHandler.ts +18 -0
- package/src/adapters/node/getRequestToken.ts +34 -0
- package/src/adapters/node/httpRouter.ts +139 -0
- package/src/adapters/node/index.ts +5 -0
- package/src/adapters/node/tokenMiddleware.ts +32 -0
- package/src/adapters/node/websocketHandler.ts +79 -0
- package/src/{ClientConnection.ts → connections/ClientConnection.ts} +64 -57
- package/src/connections/MessageSender.ts +6 -0
- package/src/connections/Presence.ts +95 -0
- package/src/core.ts +36 -0
- package/src/defaults.ts +2 -0
- package/src/files/FileStorage.ts +36 -3
- package/src/index.ts +7 -7
- package/src/internals.ts +14 -0
- package/src/{ServerLibrary.test.ts → libraries/Library.test.ts} +51 -49
- package/src/{ServerLibrary.ts → libraries/Library.ts} +203 -206
- package/src/libraries/generic.ts +9 -0
- package/src/libraries/singleNode.ts +145 -0
- package/src/logger.ts +4 -0
- package/src/storage/Storage.ts +37 -66
- package/src/storage/StorageManager.ts +39 -0
- package/src/storage/index.ts +1 -2
- package/src/storage/sqlShard/Databases.ts +26 -13
- package/src/storage/sqlShard/SqlBaselines.ts +58 -67
- package/src/storage/sqlShard/SqlFileMetadata.ts +51 -72
- package/src/storage/sqlShard/SqlOperations.ts +57 -81
- package/src/storage/sqlShard/SqlReplicas.ts +80 -121
- package/src/storage/sqlShard/database.ts +82 -18
- package/src/storage/sqlShard/migrations/v1.ts +42 -52
- package/src/storage/sqlShard/migrations/v2.ts +5 -19
- package/src/storage/sqlShard/migrations.ts +66 -1
- package/src/storage/sqlShard/sqlShardStorage.ts +56 -55
- package/src/storage/sqlShard/tables.ts +6 -6
- package/src/types.ts +1 -2
- package/dist/esm/ClientConnection.d.ts +0 -19
- package/dist/esm/ClientConnection.js.map +0 -1
- package/dist/esm/MessageSender.d.ts +0 -5
- package/dist/esm/MessageSender.js.map +0 -1
- package/dist/esm/Presence.d.ts +0 -18
- package/dist/esm/Presence.js +0 -65
- package/dist/esm/Presence.js.map +0 -1
- package/dist/esm/ReplicaKeepaliveTimers.d.ts +0 -17
- package/dist/esm/ReplicaKeepaliveTimers.js +0 -27
- package/dist/esm/ReplicaKeepaliveTimers.js.map +0 -1
- package/dist/esm/Server.d.ts +0 -166
- package/dist/esm/Server.js +0 -572
- package/dist/esm/Server.js.map +0 -1
- package/dist/esm/ServerLibrary.d.ts +0 -64
- package/dist/esm/ServerLibrary.js.map +0 -1
- package/dist/esm/ServerLibrary.test.js.map +0 -1
- package/dist/esm/storage/sql/SqlBaselines.d.ts +0 -22
- package/dist/esm/storage/sql/SqlBaselines.js +0 -107
- package/dist/esm/storage/sql/SqlBaselines.js.map +0 -1
- package/dist/esm/storage/sql/SqlFileMetadata.d.ts +0 -18
- package/dist/esm/storage/sql/SqlFileMetadata.js +0 -69
- package/dist/esm/storage/sql/SqlFileMetadata.js.map +0 -1
- package/dist/esm/storage/sql/SqlOperations.d.ts +0 -19
- package/dist/esm/storage/sql/SqlOperations.js +0 -122
- package/dist/esm/storage/sql/SqlOperations.js.map +0 -1
- package/dist/esm/storage/sql/SqlReplicas.d.ts +0 -32
- package/dist/esm/storage/sql/SqlReplicas.js +0 -163
- package/dist/esm/storage/sql/SqlReplicas.js.map +0 -1
- package/dist/esm/storage/sql/database.d.ts +0 -9
- package/dist/esm/storage/sql/database.js +0 -24
- package/dist/esm/storage/sql/database.js.map +0 -1
- package/dist/esm/storage/sql/migrations/v1.d.ts +0 -3
- package/dist/esm/storage/sql/migrations/v1.js +0 -59
- package/dist/esm/storage/sql/migrations/v1.js.map +0 -1
- package/dist/esm/storage/sql/migrations/v2.d.ts +0 -3
- package/dist/esm/storage/sql/migrations/v2.js +0 -16
- package/dist/esm/storage/sql/migrations/v2.js.map +0 -1
- package/dist/esm/storage/sql/migrations.d.ts +0 -7
- package/dist/esm/storage/sql/migrations.js +0 -4
- package/dist/esm/storage/sql/migrations.js.map +0 -1
- package/dist/esm/storage/sql/sqlStorage.d.ts +0 -6
- package/dist/esm/storage/sql/sqlStorage.js +0 -35
- package/dist/esm/storage/sql/sqlStorage.js.map +0 -1
- package/dist/esm/storage/sql/tables.d.ts +0 -44
- package/dist/esm/storage/sql/tables.js +0 -2
- package/dist/esm/storage/sql/tables.js.map +0 -1
- package/dist/esm/storage/sqlShard/transfer.d.ts +0 -7
- package/dist/esm/storage/sqlShard/transfer.js +0 -90
- package/dist/esm/storage/sqlShard/transfer.js.map +0 -1
- package/dist/esm/storage/sqlShard/transfer.test.d.ts +0 -1
- package/dist/esm/storage/sqlShard/transfer.test.js +0 -109
- package/dist/esm/storage/sqlShard/transfer.test.js.map +0 -1
- package/src/MessageSender.ts +0 -10
- package/src/Presence.ts +0 -86
- package/src/ReplicaKeepaliveTimers.ts +0 -34
- package/src/Server.ts +0 -859
- package/src/storage/sql/SqlBaselines.ts +0 -147
- package/src/storage/sql/SqlFileMetadata.ts +0 -94
- package/src/storage/sql/SqlOperations.ts +0 -160
- package/src/storage/sql/SqlReplicas.ts +0 -234
- package/src/storage/sql/database.ts +0 -32
- package/src/storage/sql/migrations/v1.ts +0 -64
- package/src/storage/sql/migrations/v2.ts +0 -20
- package/src/storage/sql/migrations.ts +0 -4
- package/src/storage/sql/sqlStorage.ts +0 -57
- package/src/storage/sql/tables.ts +0 -51
- package/src/storage/sqlShard/transfer.test.ts +0 -149
- package/src/storage/sqlShard/transfer.ts +0 -123
- /package/dist/esm/{MessageSender.js → connections/MessageSender.js} +0 -0
- /package/dist/esm/{ServerLibrary.test.d.ts → libraries/Library.test.d.ts} +0 -0
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
constructor({ storage, sender, profiles, log = () => { }, disableRebasing, fileStorage, }) {
|
|
5
|
-
super();
|
|
6
|
-
/**
|
|
7
|
-
* Validates a user's access to a replica. If the replica does not
|
|
8
|
-
* exist, a user may create it. But if it does exist, its user (clientId)
|
|
9
|
-
* must match the user making the request.
|
|
10
|
-
*/
|
|
1
|
+
import { applyOperations, isFileRef, isObjectRef, ReplicaType, rewriteAuthzOriginator, } from '@verdant-web/common';
|
|
2
|
+
export class Library {
|
|
3
|
+
constructor({ storage, sender, log = () => { }, disableRebasing, fileStorage, events, id, presence, }) {
|
|
11
4
|
this.validateReplicaAccess = async (replicaId, clientKey, info) => {
|
|
12
|
-
const replica = await this.storage.replicas.get(
|
|
5
|
+
const replica = await this.storage.replicas.get(replicaId);
|
|
13
6
|
if (replica && replica.clientId !== info.userId) {
|
|
14
|
-
this.sender.
|
|
7
|
+
this.sender.respond(clientKey, {
|
|
15
8
|
type: 'forbidden',
|
|
16
9
|
});
|
|
17
10
|
return false;
|
|
@@ -22,8 +15,11 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
22
15
|
return (info.type !== ReplicaType.ReadOnlyPull &&
|
|
23
16
|
info.type !== ReplicaType.ReadOnlyRealtime);
|
|
24
17
|
};
|
|
25
|
-
this.
|
|
26
|
-
|
|
18
|
+
this.handleMessage = async (message, clientKey, info) => {
|
|
19
|
+
if (message.type === 'heartbeat') {
|
|
20
|
+
this.handleHeartbeat(message, clientKey, info);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
27
23
|
const allowed = await this.validateReplicaAccess(message.replicaId, clientKey, info);
|
|
28
24
|
if (!allowed)
|
|
29
25
|
return;
|
|
@@ -37,14 +33,11 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
37
33
|
case 'ack':
|
|
38
34
|
await this.handleAck(message, clientKey, info);
|
|
39
35
|
break;
|
|
40
|
-
case 'heartbeat':
|
|
41
|
-
await this.handleHeartbeat(message, clientKey, info);
|
|
42
|
-
break;
|
|
43
36
|
case 'presence-update':
|
|
44
37
|
await this.handlePresenceUpdate(message, clientKey, info);
|
|
45
38
|
break;
|
|
46
39
|
default:
|
|
47
|
-
this.log('Unknown message type', message.type);
|
|
40
|
+
this.log('error', 'Unknown message type', message.type);
|
|
48
41
|
break;
|
|
49
42
|
}
|
|
50
43
|
// a bit fragile - skipping presence-update since currently
|
|
@@ -52,17 +45,28 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
52
45
|
// sees a recent last seen for the replica even if it was
|
|
53
46
|
// truant before the presence-update.
|
|
54
47
|
if (message.type !== 'presence-update') {
|
|
55
|
-
await this.storage.replicas.updateLastSeen(
|
|
48
|
+
await this.storage.replicas.updateLastSeen(message.replicaId);
|
|
56
49
|
}
|
|
57
50
|
};
|
|
58
|
-
this.
|
|
59
|
-
|
|
51
|
+
this.rebroadcastOperations = async (libraryId, clientKey, replicaId, ops, baselines) => {
|
|
52
|
+
var _a, _b;
|
|
53
|
+
if (ops.length === 0 && !(baselines === null || baselines === void 0 ? void 0 : baselines.length))
|
|
54
|
+
return;
|
|
55
|
+
this.log('info', 'Rebroadcasting', ops.length, 'operations', (_a = baselines === null || baselines === void 0 ? void 0 : baselines.length) !== null && _a !== void 0 ? _a : 0, 'baselines');
|
|
56
|
+
this.sender.broadcast({
|
|
57
|
+
type: 'op-re',
|
|
58
|
+
operations: ops,
|
|
59
|
+
baselines,
|
|
60
|
+
replicaId,
|
|
61
|
+
globalAckTimestamp: (_b = (await this.storage.replicas.getGlobalAck())) !== null && _b !== void 0 ? _b : undefined,
|
|
62
|
+
}, [clientKey]);
|
|
60
63
|
};
|
|
61
64
|
this.handleOperation = async (message, clientKey, info) => {
|
|
65
|
+
var _a;
|
|
62
66
|
if (!message.operations.length)
|
|
63
67
|
return;
|
|
64
68
|
if (!this.hasWriteAccess(info)) {
|
|
65
|
-
this.sender.
|
|
69
|
+
this.sender.respond(clientKey, {
|
|
66
70
|
type: 'forbidden',
|
|
67
71
|
});
|
|
68
72
|
return;
|
|
@@ -71,20 +75,20 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
71
75
|
this.rebroadcastOperations(info.libraryId, clientKey, message.replicaId, message.operations);
|
|
72
76
|
// insert patches into history
|
|
73
77
|
// first, record the replica's serverOrder before insertion.
|
|
74
|
-
const replicaInfo = await this.storage.replicas.getOrCreate(
|
|
78
|
+
const replicaInfo = await this.storage.replicas.getOrCreate(message.replicaId, {
|
|
75
79
|
userId: info.userId,
|
|
76
80
|
type: info.type,
|
|
77
81
|
});
|
|
78
|
-
const newServerOrder = await this.storage.operations.insertAll(
|
|
82
|
+
const newServerOrder = await this.storage.operations.insertAll(message.replicaId, message.operations);
|
|
79
83
|
this.preemptiveUpdateServerOrder(replicaInfo.replicaInfo, newServerOrder, message.operations.length);
|
|
80
|
-
this.enqueueRebase(
|
|
84
|
+
this.enqueueRebase();
|
|
81
85
|
// tell sender we got and processed their operation
|
|
82
|
-
this.sender.
|
|
86
|
+
this.sender.respond(clientKey, {
|
|
83
87
|
type: 'server-ack',
|
|
84
88
|
timestamp: message.timestamp,
|
|
85
89
|
});
|
|
86
90
|
await this.updateHighwater(message.replicaId, message.operations[message.operations.length - 1].timestamp, info);
|
|
87
|
-
this.emit(`changes`, info, message.operations, []);
|
|
91
|
+
(_a = this.events) === null || _a === void 0 ? void 0 : _a.emit(`changes`, info, message.operations, []);
|
|
88
92
|
};
|
|
89
93
|
/**
|
|
90
94
|
* If a replica inserts operations when it's already
|
|
@@ -94,31 +98,18 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
94
98
|
this.preemptiveUpdateServerOrder = async (replicaInfo, newServerOrder, insertedOperationsCount) => {
|
|
95
99
|
if (newServerOrder - replicaInfo.ackedServerOrder ===
|
|
96
100
|
insertedOperationsCount) {
|
|
97
|
-
await this.storage.replicas.updateAckedServerOrder(replicaInfo.
|
|
101
|
+
await this.storage.replicas.updateAckedServerOrder(replicaInfo.id, newServerOrder);
|
|
98
102
|
this.log('debug', 'Preemptively updated ackedServerOrder for', replicaInfo.id, 'to', newServerOrder);
|
|
99
103
|
}
|
|
100
104
|
};
|
|
101
|
-
this.rebroadcastOperations = async (libraryId, clientKey, replicaId, ops, baselines) => {
|
|
102
|
-
var _a, _b;
|
|
103
|
-
if (ops.length === 0 && !(baselines === null || baselines === void 0 ? void 0 : baselines.length))
|
|
104
|
-
return;
|
|
105
|
-
this.log('info', 'Rebroadcasting', ops.length, 'operations', (_a = baselines === null || baselines === void 0 ? void 0 : baselines.length) !== null && _a !== void 0 ? _a : 0, 'baselines');
|
|
106
|
-
this.sender.broadcast(libraryId, {
|
|
107
|
-
type: 'op-re',
|
|
108
|
-
operations: ops,
|
|
109
|
-
baselines,
|
|
110
|
-
replicaId,
|
|
111
|
-
globalAckTimestamp: (_b = (await this.storage.replicas.getGlobalAck(libraryId))) !== null && _b !== void 0 ? _b : undefined,
|
|
112
|
-
}, [clientKey]);
|
|
113
|
-
};
|
|
114
105
|
this.handleSync = async (message, clientKey, info) => {
|
|
115
|
-
var _a;
|
|
106
|
+
var _a, _b;
|
|
116
107
|
const replicaId = message.replicaId;
|
|
117
108
|
// TODO: is this the right way to do this? should it just ignore
|
|
118
109
|
// read-only changes?
|
|
119
110
|
if (!this.hasWriteAccess(info) &&
|
|
120
111
|
(message.operations.length > 0 || message.baselines.length > 0)) {
|
|
121
|
-
this.sender.
|
|
112
|
+
this.sender.respond(clientKey, {
|
|
122
113
|
type: 'forbidden',
|
|
123
114
|
});
|
|
124
115
|
this.log('warn', 'sync with changes from read-only replica', replicaId);
|
|
@@ -126,22 +117,22 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
126
117
|
}
|
|
127
118
|
if (message.resyncAll) {
|
|
128
119
|
// forget our local understanding of the replica and reset it
|
|
129
|
-
await this.storage.replicas.delete(
|
|
120
|
+
await this.storage.replicas.delete(replicaId);
|
|
130
121
|
}
|
|
131
|
-
const { status, replicaInfo: clientReplicaInfo } = await this.storage.replicas.getOrCreate(
|
|
122
|
+
const { status, replicaInfo: clientReplicaInfo } = await this.storage.replicas.getOrCreate(replicaId, info);
|
|
132
123
|
this.log('info', `Sync from ${replicaId} (user: ${info.userId}) [ackedServerOrder: ${clientReplicaInfo.ackedServerOrder}, status: ${status}}]`);
|
|
133
124
|
// for truant replicas -- if their ackedServerOrder is up-to-date, that's fine,
|
|
134
125
|
// restore them.
|
|
135
126
|
let overrideTruant = false;
|
|
136
127
|
if (status === 'truant') {
|
|
137
|
-
const latestServerOrder = await this.storage.operations.getLatestServerOrder(
|
|
128
|
+
const latestServerOrder = await this.storage.operations.getLatestServerOrder();
|
|
138
129
|
if (clientReplicaInfo.ackedServerOrder >= latestServerOrder) {
|
|
139
130
|
overrideTruant = true;
|
|
140
131
|
this.log('debug', 'Overriding truant reset; truant replica has up-to-date server order');
|
|
141
132
|
}
|
|
142
133
|
}
|
|
143
134
|
// lookup operations after the last ack the client gave us
|
|
144
|
-
const ops = await this.storage.operations.getAfterServerOrder(
|
|
135
|
+
const ops = await this.storage.operations.getAfterServerOrder(clientReplicaInfo.ackedServerOrder);
|
|
145
136
|
// new, unseen replicas should reset their existing storage
|
|
146
137
|
// to that of the server when joining a library.
|
|
147
138
|
// truant replicas should also reset their storage.
|
|
@@ -151,7 +142,7 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
151
142
|
// replica will generate the same baseline locally, so it
|
|
152
143
|
// doesn't need to receive it from the server.
|
|
153
144
|
const baselines = replicaShouldReset
|
|
154
|
-
? await this.storage.baselines.getAll(
|
|
145
|
+
? await this.storage.baselines.getAll()
|
|
155
146
|
: [];
|
|
156
147
|
// We detect that a library is new by checking if it has any history.
|
|
157
148
|
// If there are no existing operations or baselines (and the requested
|
|
@@ -182,7 +173,7 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
182
173
|
// sync after replica has updated us with full history.
|
|
183
174
|
if (isEmptyLibrary && status === 'new' && message.since !== null) {
|
|
184
175
|
this.log('info', 'Detected local data is incomplete, requesting full history from replica', replicaId);
|
|
185
|
-
this.sender.
|
|
176
|
+
this.sender.respond(clientKey, {
|
|
186
177
|
type: 'need-since',
|
|
187
178
|
since: null,
|
|
188
179
|
});
|
|
@@ -202,11 +193,11 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
202
193
|
// we are not overwriting the replica's data
|
|
203
194
|
if (!overwriteReplicaData) {
|
|
204
195
|
// store all incoming operations and baselines
|
|
205
|
-
await this.storage.baselines.insertAll(
|
|
196
|
+
await this.storage.baselines.insertAll(message.baselines);
|
|
206
197
|
this.log('debug', 'Storing', message.baselines.length, 'baselines and', message.operations.length, 'operations');
|
|
207
|
-
const newServerOrder = await this.storage.operations.insertAll(
|
|
198
|
+
const newServerOrder = await this.storage.operations.insertAll(replicaId, message.operations);
|
|
208
199
|
this.preemptiveUpdateServerOrder(clientReplicaInfo, newServerOrder, message.operations.length);
|
|
209
|
-
await this.storage.replicas.updateAcknowledgedLogicalTime(
|
|
200
|
+
await this.storage.replicas.updateAcknowledgedLogicalTime(replicaId, message.timestamp);
|
|
210
201
|
// will include the new global ack
|
|
211
202
|
this.rebroadcastOperations(info.libraryId, clientKey, message.replicaId, message.operations,
|
|
212
203
|
// we only need to broadcast baselines if we just initialized
|
|
@@ -215,7 +206,7 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
215
206
|
// rebasing.test.ts, for example.
|
|
216
207
|
isEmptyLibrary ? message.baselines : undefined);
|
|
217
208
|
if (message.operations.length || message.baselines.length) {
|
|
218
|
-
this.emit(`changes`, info, message.operations, message.baselines);
|
|
209
|
+
(_a = this.events) === null || _a === void 0 ? void 0 : _a.emit(`changes`, info, message.operations, message.baselines);
|
|
219
210
|
}
|
|
220
211
|
}
|
|
221
212
|
if (status === 'truant') {
|
|
@@ -229,22 +220,28 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
229
220
|
? this.createAckNonce(serverOrderToAck)
|
|
230
221
|
: undefined;
|
|
231
222
|
// respond to client
|
|
232
|
-
this.log('info', 'Sending sync response with', ops.length, 'operations and', baselines.length, 'baselines');
|
|
223
|
+
this.log('info', 'Sending sync response with', ops.length, 'operations and', baselines.length, 'baselines', 'to client key', clientKey);
|
|
233
224
|
// mutating baselines/operations to remove extra data -
|
|
234
225
|
// mutating just to save on allocations here.
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
226
|
+
try {
|
|
227
|
+
this.sender.respond(clientKey, {
|
|
228
|
+
type: 'sync-resp',
|
|
229
|
+
operations: this.removeOperationExtras(ops),
|
|
230
|
+
baselines: this.removeBaselineExtras(baselines),
|
|
231
|
+
globalAckTimestamp: (_b = (await this.storage.replicas.getGlobalAck())) !== null && _b !== void 0 ? _b : undefined,
|
|
232
|
+
peerPresence: this.presence.all(),
|
|
233
|
+
// only request the client to overwrite local data if a reset is requested
|
|
234
|
+
// and there is data to overwrite it. otherwise the client may still
|
|
235
|
+
// send its own history to us.
|
|
236
|
+
overwriteLocalData: overwriteReplicaData,
|
|
237
|
+
ackedTimestamp: message.timestamp,
|
|
238
|
+
ackThisNonce,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
this.log('error', err);
|
|
243
|
+
throw err;
|
|
244
|
+
}
|
|
248
245
|
};
|
|
249
246
|
this.createAckNonce = (serverOrder) => {
|
|
250
247
|
return Buffer.from(JSON.stringify(serverOrder)).toString('base64');
|
|
@@ -252,19 +249,19 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
252
249
|
this.handleAck = async (message, clientKey, info) => {
|
|
253
250
|
if (message.nonce) {
|
|
254
251
|
const decodedNonce = JSON.parse(Buffer.from(message.nonce, 'base64').toString('utf8'));
|
|
255
|
-
this.log('Ack from', message.replicaId, '(user', info.userId, ')', 'with order', decodedNonce);
|
|
252
|
+
this.log('debug', 'Ack from', message.replicaId, '(user', info.userId, ')', 'with order', decodedNonce);
|
|
256
253
|
if (typeof decodedNonce !== 'number') {
|
|
257
254
|
this.log('error', 'Invalid nonce', message.nonce);
|
|
258
255
|
return;
|
|
259
256
|
}
|
|
260
257
|
const replicaId = message.replicaId;
|
|
261
|
-
await this.storage.replicas.updateAckedServerOrder(
|
|
258
|
+
await this.storage.replicas.updateAckedServerOrder(replicaId, decodedNonce);
|
|
262
259
|
}
|
|
263
260
|
else if (message.timestamp) {
|
|
264
|
-
await this.storage.replicas.acknowledgeOperation(
|
|
265
|
-
const globalAck = await this.storage.replicas.getGlobalAck(
|
|
261
|
+
await this.storage.replicas.acknowledgeOperation(message.replicaId, message.timestamp);
|
|
262
|
+
const globalAck = await this.storage.replicas.getGlobalAck();
|
|
266
263
|
if (globalAck) {
|
|
267
|
-
this.sender.broadcast(
|
|
264
|
+
this.sender.broadcast({
|
|
268
265
|
type: 'global-ack',
|
|
269
266
|
timestamp: globalAck,
|
|
270
267
|
});
|
|
@@ -272,24 +269,24 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
272
269
|
}
|
|
273
270
|
};
|
|
274
271
|
this.updateHighwater = async (replicaId, timestamp, info, ignoreClientKeys = []) => {
|
|
275
|
-
await this.storage.replicas.updateAcknowledgedLogicalTime(
|
|
276
|
-
const newGlobalAck = await this.storage.replicas.getGlobalAck(
|
|
272
|
+
await this.storage.replicas.updateAcknowledgedLogicalTime(replicaId, timestamp);
|
|
273
|
+
const newGlobalAck = await this.storage.replicas.getGlobalAck();
|
|
277
274
|
if (newGlobalAck) {
|
|
278
|
-
this.sender.broadcast(
|
|
275
|
+
this.sender.broadcast({
|
|
279
276
|
type: 'global-ack',
|
|
280
277
|
timestamp: newGlobalAck,
|
|
281
278
|
}, ignoreClientKeys);
|
|
282
279
|
}
|
|
283
280
|
};
|
|
284
281
|
this.pendingRebaseTimeout = null;
|
|
285
|
-
this.enqueueRebase = (
|
|
282
|
+
this.enqueueRebase = () => {
|
|
286
283
|
if (this.disableRebasing)
|
|
287
284
|
return;
|
|
288
285
|
if (!this.pendingRebaseTimeout) {
|
|
289
|
-
setTimeout(() => this.rebase(
|
|
286
|
+
setTimeout(() => this.rebase(), 0);
|
|
290
287
|
}
|
|
291
288
|
};
|
|
292
|
-
this.rebase = async (
|
|
289
|
+
this.rebase = async () => {
|
|
293
290
|
if (this.disableRebasing)
|
|
294
291
|
return;
|
|
295
292
|
this.log('debug', 'Performing rebase check');
|
|
@@ -308,9 +305,9 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
308
305
|
// for global ack, to determine consensus, also allow
|
|
309
306
|
// for all actively connected replicas to ack regardless of their
|
|
310
307
|
// type.
|
|
311
|
-
const activeReplicaIds = Object.values(this.
|
|
312
|
-
const globalAck = await this.storage.replicas.getGlobalAck(
|
|
313
|
-
const globalServerOrder = await this.storage.replicas.getEarliestAckedServerOrder(
|
|
308
|
+
const activeReplicaIds = Object.values(this.presence.all()).map((p) => p.replicaId);
|
|
309
|
+
const globalAck = await this.storage.replicas.getGlobalAck(activeReplicaIds);
|
|
310
|
+
const globalServerOrder = await this.storage.replicas.getEarliestAckedServerOrder();
|
|
314
311
|
if (!globalAck) {
|
|
315
312
|
this.log('debug', 'No global ack, skipping rebase');
|
|
316
313
|
return;
|
|
@@ -320,7 +317,7 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
320
317
|
return;
|
|
321
318
|
}
|
|
322
319
|
// these are in forward chronological order
|
|
323
|
-
const ops = await this.storage.operations.getBeforeServerOrder(
|
|
320
|
+
const ops = await this.storage.operations.getBeforeServerOrder(globalServerOrder);
|
|
324
321
|
const opsToApply = {};
|
|
325
322
|
// if we encounter a sequential operation in history which does
|
|
326
323
|
// not meet our conditions, we must ignore subsequent operations
|
|
@@ -338,33 +335,33 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
338
335
|
}
|
|
339
336
|
const deletedRefs = new Array();
|
|
340
337
|
for (const [documentId, ops] of Object.entries(opsToApply)) {
|
|
341
|
-
this.log('Rebasing', documentId);
|
|
342
|
-
await this.storage.baselines.applyOperations(
|
|
343
|
-
await this.storage.operations.delete(
|
|
338
|
+
this.log('debug', 'Rebasing', documentId);
|
|
339
|
+
await this.storage.baselines.applyOperations(documentId, ops, deletedRefs);
|
|
340
|
+
await this.storage.operations.delete(ops);
|
|
344
341
|
}
|
|
345
342
|
// hint to clients they can rebase too
|
|
346
|
-
this.sender.broadcast(
|
|
343
|
+
this.sender.broadcast({
|
|
347
344
|
type: 'global-ack',
|
|
348
345
|
timestamp: globalAck,
|
|
349
346
|
});
|
|
350
347
|
// cleanup deleted files
|
|
351
348
|
await Promise.all(deletedRefs
|
|
352
349
|
.filter(isFileRef)
|
|
353
|
-
.map((ref) => this.storage.fileMetadata.markPendingDelete(
|
|
350
|
+
.map((ref) => this.storage.fileMetadata.markPendingDelete(ref.id)));
|
|
354
351
|
};
|
|
355
352
|
this.handleHeartbeat = (_, clientKey, info) => {
|
|
356
|
-
this.sender.
|
|
353
|
+
this.sender.respond(clientKey, {
|
|
357
354
|
type: 'heartbeat-response',
|
|
358
355
|
});
|
|
359
356
|
};
|
|
360
357
|
this.handlePresenceUpdate = async (message, clientKey, info) => {
|
|
361
|
-
const updated = await this.
|
|
358
|
+
const updated = await this.presence.set(clientKey, info.userId, {
|
|
362
359
|
presence: message.presence,
|
|
363
360
|
internal: message.internal,
|
|
364
361
|
replicaId: message.replicaId,
|
|
365
362
|
id: info.userId,
|
|
366
363
|
});
|
|
367
|
-
this.sender.broadcast(
|
|
364
|
+
this.sender.broadcast({
|
|
368
365
|
type: 'presence-changed',
|
|
369
366
|
replicaId: message.replicaId,
|
|
370
367
|
userInfo: updated,
|
|
@@ -372,21 +369,21 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
372
369
|
// mirror back to the replica which sent it so it has profile
|
|
373
370
|
[]);
|
|
374
371
|
};
|
|
375
|
-
this.onPresenceLost = async (
|
|
372
|
+
this.onPresenceLost = async (replicaId, userId) => {
|
|
376
373
|
this.log('info', 'User disconnected from all replicas:', userId);
|
|
377
|
-
this.sender.broadcast(
|
|
374
|
+
this.sender.broadcast({
|
|
378
375
|
type: 'presence-offline',
|
|
379
376
|
replicaId,
|
|
380
377
|
userId,
|
|
381
378
|
});
|
|
382
|
-
if (Object.keys(this.
|
|
383
|
-
this.log('info', `All users have disconnected
|
|
379
|
+
if (Object.keys(this.presence.all()).length === 0) {
|
|
380
|
+
this.log('info', `All users have disconnected`);
|
|
384
381
|
// could happen - if the server is shutting down manually
|
|
385
382
|
if (!this.storage.open) {
|
|
386
383
|
this.log('debug', 'Database not open, skipping cleanup');
|
|
387
384
|
return;
|
|
388
385
|
}
|
|
389
|
-
const pendingDelete = await this.storage.fileMetadata.getPendingDelete(
|
|
386
|
+
const pendingDelete = await this.storage.fileMetadata.getPendingDelete();
|
|
390
387
|
if (pendingDelete.length > 0) {
|
|
391
388
|
if (!this.fileStorage) {
|
|
392
389
|
throw new Error('File storage not configured, cannot delete files');
|
|
@@ -396,12 +393,11 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
396
393
|
var _a;
|
|
397
394
|
try {
|
|
398
395
|
await ((_a = this.fileStorage) === null || _a === void 0 ? void 0 : _a.delete({
|
|
399
|
-
libraryId: fileInfo.libraryId,
|
|
400
396
|
fileName: fileInfo.name,
|
|
401
397
|
id: fileInfo.fileId,
|
|
402
398
|
type: fileInfo.type,
|
|
403
399
|
}));
|
|
404
|
-
this.storage.fileMetadata.delete(
|
|
400
|
+
await this.storage.fileMetadata.delete(fileInfo.fileId);
|
|
405
401
|
}
|
|
406
402
|
catch (e) {
|
|
407
403
|
this.log('error', 'Failed to delete file', fileInfo.fileId, ' the file will remain in a pending delete state', e);
|
|
@@ -410,52 +406,49 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
410
406
|
}
|
|
411
407
|
}
|
|
412
408
|
};
|
|
413
|
-
this.destroy = async (
|
|
409
|
+
this.destroy = async () => {
|
|
414
410
|
var _a;
|
|
415
|
-
this.log('info', 'Destroying library'
|
|
416
|
-
this.
|
|
411
|
+
this.log('info', 'Destroying library');
|
|
412
|
+
this.presence.clear();
|
|
417
413
|
await Promise.all([
|
|
418
|
-
this.storage.replicas.deleteAll(
|
|
419
|
-
this.storage.operations.deleteAll(
|
|
420
|
-
this.storage.baselines.deleteAll(
|
|
414
|
+
this.storage.replicas.deleteAll(),
|
|
415
|
+
this.storage.operations.deleteAll(),
|
|
416
|
+
this.storage.baselines.deleteAll(),
|
|
421
417
|
]);
|
|
422
|
-
const allFiles = await this.storage.fileMetadata.getAll(
|
|
418
|
+
const allFiles = await this.storage.fileMetadata.getAll();
|
|
423
419
|
if (allFiles.length > 0) {
|
|
424
|
-
this.log('info', `Deleting ${allFiles.length} files
|
|
420
|
+
this.log('info', `Deleting ${allFiles.length} files`, allFiles.map((f) => f.fileId).join(', '));
|
|
425
421
|
for (const fileInfo of allFiles) {
|
|
426
422
|
await ((_a = this.fileStorage) === null || _a === void 0 ? void 0 : _a.delete({
|
|
427
|
-
libraryId,
|
|
428
423
|
fileName: fileInfo.name,
|
|
429
424
|
id: fileInfo.fileId,
|
|
430
425
|
type: fileInfo.type,
|
|
431
426
|
}));
|
|
432
427
|
}
|
|
433
|
-
await this.storage.fileMetadata.deleteAll(
|
|
428
|
+
await this.storage.fileMetadata.deleteAll();
|
|
434
429
|
}
|
|
435
430
|
};
|
|
436
|
-
this.getPresence = (
|
|
437
|
-
return this.
|
|
431
|
+
this.getPresence = () => {
|
|
432
|
+
return Promise.resolve(this.presence.all());
|
|
438
433
|
};
|
|
439
|
-
this.getInfo = async (
|
|
434
|
+
this.getInfo = async () => {
|
|
440
435
|
var _a;
|
|
441
|
-
const rawReplicas = await this.storage.replicas.getAll(
|
|
442
|
-
const
|
|
443
|
-
const replicas = rawReplicas.map((r, index) => ({
|
|
436
|
+
const rawReplicas = await this.storage.replicas.getAll();
|
|
437
|
+
const replicas = rawReplicas.map((r) => ({
|
|
444
438
|
id: r.id,
|
|
445
439
|
ackedLogicalTime: r.ackedLogicalTime,
|
|
446
440
|
ackedServerOrder: r.ackedServerOrder,
|
|
447
441
|
type: r.type,
|
|
448
442
|
truant: !!r.lastSeenWallClockTime &&
|
|
449
443
|
r.lastSeenWallClockTime < this.storage.replicas.truantCutoff,
|
|
450
|
-
profile: profiles[index],
|
|
451
444
|
}));
|
|
452
445
|
const data = {
|
|
453
|
-
id:
|
|
446
|
+
id: this.id,
|
|
454
447
|
replicas,
|
|
455
|
-
latestServerOrder: await this.storage.operations.getLatestServerOrder(
|
|
456
|
-
operationsCount: await this.storage.operations.getCount(
|
|
457
|
-
baselinesCount: await this.storage.baselines.getCount(
|
|
458
|
-
globalAck: (_a = (await this.storage.replicas.getGlobalAck(
|
|
448
|
+
latestServerOrder: await this.storage.operations.getLatestServerOrder(),
|
|
449
|
+
operationsCount: await this.storage.operations.getCount(),
|
|
450
|
+
baselinesCount: await this.storage.baselines.getCount(),
|
|
451
|
+
globalAck: (_a = (await this.storage.replicas.getGlobalAck())) !== null && _a !== void 0 ? _a : null,
|
|
459
452
|
};
|
|
460
453
|
if (data.replicas.length === 0 &&
|
|
461
454
|
data.operationsCount === 0 &&
|
|
@@ -464,30 +457,46 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
464
457
|
}
|
|
465
458
|
return data;
|
|
466
459
|
};
|
|
467
|
-
this.evictUser = async (
|
|
468
|
-
await this.storage.replicas.deleteAllForUser(
|
|
460
|
+
this.evictUser = async (userId) => {
|
|
461
|
+
await this.storage.replicas.deleteAllForUser(userId);
|
|
462
|
+
};
|
|
463
|
+
this.forceTruant = async (replicaId) => {
|
|
464
|
+
await this.storage.replicas.forceTruant(replicaId);
|
|
469
465
|
};
|
|
470
|
-
this.getDocumentSnapshot = (
|
|
471
|
-
return this.hydrateObject(
|
|
466
|
+
this.getDocumentSnapshot = (oid) => {
|
|
467
|
+
return this.hydrateObject(oid);
|
|
472
468
|
};
|
|
473
|
-
this.
|
|
469
|
+
this.getFileInfo = async (fileId) => {
|
|
470
|
+
const rawFile = await this.hydrateFile(fileId);
|
|
471
|
+
if (rawFile) {
|
|
472
|
+
return Object.assign(Object.assign({}, rawFile), { libraryId: this.id });
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
this.putFileInfo = async (info) => {
|
|
479
|
+
this.log('debug', 'Storing file info', info.id, info.fileName);
|
|
480
|
+
await this.storage.fileMetadata.put(info);
|
|
481
|
+
};
|
|
482
|
+
this.getObjectSnapshot = async (oid) => {
|
|
474
483
|
var _a;
|
|
475
484
|
const [baseline, ops] = await Promise.all([
|
|
476
|
-
this.storage.baselines.get(
|
|
477
|
-
this.storage.operations.getAll(
|
|
485
|
+
this.storage.baselines.get(oid),
|
|
486
|
+
this.storage.operations.getAll(oid),
|
|
478
487
|
]);
|
|
479
488
|
const snapshot = applyOperations((_a = baseline === null || baseline === void 0 ? void 0 : baseline.snapshot) !== null && _a !== void 0 ? _a : undefined, ops);
|
|
480
489
|
return snapshot;
|
|
481
490
|
};
|
|
482
|
-
this.hydrateObject = async (
|
|
483
|
-
const snapshot = await this.getObjectSnapshot(
|
|
491
|
+
this.hydrateObject = async (oid) => {
|
|
492
|
+
const snapshot = await this.getObjectSnapshot(oid);
|
|
484
493
|
if (Array.isArray(snapshot)) {
|
|
485
494
|
return Promise.all(snapshot.map(async (item) => {
|
|
486
495
|
if (isObjectRef(item)) {
|
|
487
|
-
return this.hydrateObject(
|
|
496
|
+
return this.hydrateObject(item.id);
|
|
488
497
|
}
|
|
489
498
|
else if (isFileRef(item)) {
|
|
490
|
-
return this.hydrateFile(
|
|
499
|
+
return this.hydrateFile(item.id);
|
|
491
500
|
}
|
|
492
501
|
else {
|
|
493
502
|
return item;
|
|
@@ -498,10 +507,10 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
498
507
|
const hydrated = Object.assign({}, snapshot);
|
|
499
508
|
await Promise.all(Object.entries(snapshot).map(async ([key, value]) => {
|
|
500
509
|
if (isObjectRef(value)) {
|
|
501
|
-
hydrated[key] = await this.hydrateObject(
|
|
510
|
+
hydrated[key] = await this.hydrateObject(value.id);
|
|
502
511
|
}
|
|
503
512
|
else if (isFileRef(value)) {
|
|
504
|
-
hydrated[key] = await this.hydrateFile(
|
|
513
|
+
hydrated[key] = await this.hydrateFile(value.id);
|
|
505
514
|
}
|
|
506
515
|
}));
|
|
507
516
|
return hydrated;
|
|
@@ -510,21 +519,20 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
510
519
|
return snapshot;
|
|
511
520
|
}
|
|
512
521
|
};
|
|
513
|
-
this.hydrateFile = async (
|
|
522
|
+
this.hydrateFile = async (fileId) => {
|
|
514
523
|
var _a, _b;
|
|
515
|
-
const data = await this.storage.fileMetadata.get(
|
|
524
|
+
const data = await this.storage.fileMetadata.get(fileId);
|
|
516
525
|
if (data) {
|
|
517
|
-
const url = (_b = (_a = this.fileStorage) === null || _a === void 0 ? void 0 : _a.getUrl({
|
|
526
|
+
const url = (_b = (await ((_a = this.fileStorage) === null || _a === void 0 ? void 0 : _a.getUrl({
|
|
518
527
|
fileName: data.name,
|
|
519
528
|
id: data.fileId,
|
|
520
|
-
libraryId,
|
|
521
529
|
type: data.type,
|
|
522
|
-
})) !== null && _b !== void 0 ? _b : null;
|
|
530
|
+
})))) !== null && _b !== void 0 ? _b : null;
|
|
523
531
|
return {
|
|
524
|
-
url,
|
|
525
532
|
id: data.fileId,
|
|
526
533
|
name: data.name,
|
|
527
534
|
type: data.type,
|
|
535
|
+
url,
|
|
528
536
|
};
|
|
529
537
|
}
|
|
530
538
|
else {
|
|
@@ -553,14 +561,15 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
553
561
|
}
|
|
554
562
|
return operations;
|
|
555
563
|
};
|
|
564
|
+
this.id = id;
|
|
565
|
+
this.storage = storage;
|
|
566
|
+
this.sender = sender;
|
|
556
567
|
this.log = log;
|
|
557
568
|
this.disableRebasing = !!disableRebasing;
|
|
558
|
-
this.sender = sender;
|
|
559
|
-
this.profiles = profiles;
|
|
560
|
-
this.presences = new Presence(profiles);
|
|
561
|
-
this.storage = storage;
|
|
562
569
|
this.fileStorage = fileStorage;
|
|
563
|
-
this.
|
|
570
|
+
this.events = events;
|
|
571
|
+
this.presence = presence;
|
|
572
|
+
this.presence.subscribe('lost', this.onPresenceLost);
|
|
564
573
|
}
|
|
565
574
|
}
|
|
566
|
-
//# sourceMappingURL=
|
|
575
|
+
//# sourceMappingURL=Library.js.map
|