@verdant-web/server 3.3.11 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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} +165 -151
- 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 +2 -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} +205 -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 +2 -4
- 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,54 @@ 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
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
r.
|
|
450
|
-
|
|
451
|
-
|
|
436
|
+
const rawReplicas = await this.storage.replicas.getAll();
|
|
437
|
+
const replicas = rawReplicas.map((r) => {
|
|
438
|
+
var _a, _b;
|
|
439
|
+
return ({
|
|
440
|
+
id: r.id,
|
|
441
|
+
userId: r.clientId,
|
|
442
|
+
ackedLogicalTime: r.ackedLogicalTime,
|
|
443
|
+
ackedServerOrder: r.ackedServerOrder,
|
|
444
|
+
type: r.type,
|
|
445
|
+
truant: !!r.lastSeenWallClockTime &&
|
|
446
|
+
r.lastSeenWallClockTime < this.storage.replicas.truantCutoff,
|
|
447
|
+
profile: (_b = (_a = this.presence.get(r.clientId)) === null || _a === void 0 ? void 0 : _a.profile) !== null && _b !== void 0 ? _b : null,
|
|
448
|
+
});
|
|
449
|
+
});
|
|
452
450
|
const data = {
|
|
453
|
-
id:
|
|
451
|
+
id: this.id,
|
|
454
452
|
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(
|
|
453
|
+
latestServerOrder: await this.storage.operations.getLatestServerOrder(),
|
|
454
|
+
operationsCount: await this.storage.operations.getCount(),
|
|
455
|
+
baselinesCount: await this.storage.baselines.getCount(),
|
|
456
|
+
globalAck: (_a = (await this.storage.replicas.getGlobalAck())) !== null && _a !== void 0 ? _a : null,
|
|
459
457
|
};
|
|
460
458
|
if (data.replicas.length === 0 &&
|
|
461
459
|
data.operationsCount === 0 &&
|
|
@@ -464,30 +462,46 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
464
462
|
}
|
|
465
463
|
return data;
|
|
466
464
|
};
|
|
467
|
-
this.evictUser = async (
|
|
468
|
-
await this.storage.replicas.deleteAllForUser(
|
|
465
|
+
this.evictUser = async (userId) => {
|
|
466
|
+
await this.storage.replicas.deleteAllForUser(userId);
|
|
467
|
+
};
|
|
468
|
+
this.forceTruant = async (replicaId) => {
|
|
469
|
+
await this.storage.replicas.forceTruant(replicaId);
|
|
469
470
|
};
|
|
470
|
-
this.getDocumentSnapshot = (
|
|
471
|
-
return this.hydrateObject(
|
|
471
|
+
this.getDocumentSnapshot = (oid) => {
|
|
472
|
+
return this.hydrateObject(oid);
|
|
472
473
|
};
|
|
473
|
-
this.
|
|
474
|
+
this.getFileInfo = async (fileId) => {
|
|
475
|
+
const rawFile = await this.hydrateFile(fileId);
|
|
476
|
+
if (rawFile) {
|
|
477
|
+
return Object.assign(Object.assign({}, rawFile), { libraryId: this.id });
|
|
478
|
+
}
|
|
479
|
+
else {
|
|
480
|
+
return null;
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
this.putFileInfo = async (info) => {
|
|
484
|
+
this.log('debug', 'Storing file info', info.id, info.fileName);
|
|
485
|
+
await this.storage.fileMetadata.put(info);
|
|
486
|
+
};
|
|
487
|
+
this.getObjectSnapshot = async (oid) => {
|
|
474
488
|
var _a;
|
|
475
489
|
const [baseline, ops] = await Promise.all([
|
|
476
|
-
this.storage.baselines.get(
|
|
477
|
-
this.storage.operations.getAll(
|
|
490
|
+
this.storage.baselines.get(oid),
|
|
491
|
+
this.storage.operations.getAll(oid),
|
|
478
492
|
]);
|
|
479
493
|
const snapshot = applyOperations((_a = baseline === null || baseline === void 0 ? void 0 : baseline.snapshot) !== null && _a !== void 0 ? _a : undefined, ops);
|
|
480
494
|
return snapshot;
|
|
481
495
|
};
|
|
482
|
-
this.hydrateObject = async (
|
|
483
|
-
const snapshot = await this.getObjectSnapshot(
|
|
496
|
+
this.hydrateObject = async (oid) => {
|
|
497
|
+
const snapshot = await this.getObjectSnapshot(oid);
|
|
484
498
|
if (Array.isArray(snapshot)) {
|
|
485
499
|
return Promise.all(snapshot.map(async (item) => {
|
|
486
500
|
if (isObjectRef(item)) {
|
|
487
|
-
return this.hydrateObject(
|
|
501
|
+
return this.hydrateObject(item.id);
|
|
488
502
|
}
|
|
489
503
|
else if (isFileRef(item)) {
|
|
490
|
-
return this.hydrateFile(
|
|
504
|
+
return this.hydrateFile(item.id);
|
|
491
505
|
}
|
|
492
506
|
else {
|
|
493
507
|
return item;
|
|
@@ -498,10 +512,10 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
498
512
|
const hydrated = Object.assign({}, snapshot);
|
|
499
513
|
await Promise.all(Object.entries(snapshot).map(async ([key, value]) => {
|
|
500
514
|
if (isObjectRef(value)) {
|
|
501
|
-
hydrated[key] = await this.hydrateObject(
|
|
515
|
+
hydrated[key] = await this.hydrateObject(value.id);
|
|
502
516
|
}
|
|
503
517
|
else if (isFileRef(value)) {
|
|
504
|
-
hydrated[key] = await this.hydrateFile(
|
|
518
|
+
hydrated[key] = await this.hydrateFile(value.id);
|
|
505
519
|
}
|
|
506
520
|
}));
|
|
507
521
|
return hydrated;
|
|
@@ -510,21 +524,20 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
510
524
|
return snapshot;
|
|
511
525
|
}
|
|
512
526
|
};
|
|
513
|
-
this.hydrateFile = async (
|
|
527
|
+
this.hydrateFile = async (fileId) => {
|
|
514
528
|
var _a, _b;
|
|
515
|
-
const data = await this.storage.fileMetadata.get(
|
|
529
|
+
const data = await this.storage.fileMetadata.get(fileId);
|
|
516
530
|
if (data) {
|
|
517
|
-
const url = (_b = (_a = this.fileStorage) === null || _a === void 0 ? void 0 : _a.getUrl({
|
|
531
|
+
const url = (_b = (await ((_a = this.fileStorage) === null || _a === void 0 ? void 0 : _a.getUrl({
|
|
518
532
|
fileName: data.name,
|
|
519
533
|
id: data.fileId,
|
|
520
|
-
libraryId,
|
|
521
534
|
type: data.type,
|
|
522
|
-
})) !== null && _b !== void 0 ? _b : null;
|
|
535
|
+
})))) !== null && _b !== void 0 ? _b : null;
|
|
523
536
|
return {
|
|
524
|
-
url,
|
|
525
537
|
id: data.fileId,
|
|
526
538
|
name: data.name,
|
|
527
539
|
type: data.type,
|
|
540
|
+
url,
|
|
528
541
|
};
|
|
529
542
|
}
|
|
530
543
|
else {
|
|
@@ -553,14 +566,15 @@ export class ServerLibrary extends EventSubscriber {
|
|
|
553
566
|
}
|
|
554
567
|
return operations;
|
|
555
568
|
};
|
|
569
|
+
this.id = id;
|
|
570
|
+
this.storage = storage;
|
|
571
|
+
this.sender = sender;
|
|
556
572
|
this.log = log;
|
|
557
573
|
this.disableRebasing = !!disableRebasing;
|
|
558
|
-
this.sender = sender;
|
|
559
|
-
this.profiles = profiles;
|
|
560
|
-
this.presences = new Presence(profiles);
|
|
561
|
-
this.storage = storage;
|
|
562
574
|
this.fileStorage = fileStorage;
|
|
563
|
-
this.
|
|
575
|
+
this.events = events;
|
|
576
|
+
this.presence = presence;
|
|
577
|
+
this.presence.subscribe('lost', this.onPresenceLost);
|
|
564
578
|
}
|
|
565
579
|
}
|
|
566
|
-
//# sourceMappingURL=
|
|
580
|
+
//# sourceMappingURL=Library.js.map
|