document-drive 1.8.4 → 1.9.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "document-drive",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"license": "AGPL-3.0-only",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./src/index.ts",
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
"nanoevents": "^9.0.0",
|
|
34
34
|
"sanitize-filename": "^1.6.3",
|
|
35
35
|
"uuid": "^9.0.1",
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"document-model-libs": "1.
|
|
36
|
+
"@powerhousedao/scalars": "1.13.0",
|
|
37
|
+
"document-model": "2.11.0",
|
|
38
|
+
"document-model-libs": "1.121.0"
|
|
39
39
|
},
|
|
40
40
|
"optionalDependencies": {
|
|
41
41
|
"@prisma/client": "^5.18.0",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"redis": "^4.6.15",
|
|
45
45
|
"sequelize": "^6.37.3",
|
|
46
46
|
"sqlite3": "^5.1.7",
|
|
47
|
-
"@powerhousedao/scalars": "1.
|
|
47
|
+
"@powerhousedao/scalars": "1.13.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@prisma/client": "5.17.0",
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
"nanoevents": "^9.0.0",
|
|
67
67
|
"sanitize-filename": "^1.6.3",
|
|
68
68
|
"uuid": "^9.0.1",
|
|
69
|
-
"document-model": "2.
|
|
70
|
-
"document-model-libs": "1.
|
|
69
|
+
"document-model": "2.11.0",
|
|
70
|
+
"document-model-libs": "1.121.0"
|
|
71
71
|
},
|
|
72
72
|
"scripts": {
|
|
73
73
|
"check-types": "tsc --build",
|
|
@@ -79,6 +79,6 @@
|
|
|
79
79
|
"test:watch": "vitest watch",
|
|
80
80
|
"clean": "rimraf dist",
|
|
81
81
|
"clean:node_modules": "rimraf node_modules",
|
|
82
|
-
"
|
|
82
|
+
"postinstall": "prisma generate"
|
|
83
83
|
}
|
|
84
84
|
}
|
package/src/index.ts
CHANGED
|
@@ -102,6 +102,8 @@ export class ListenerManager extends BaseListenerManager {
|
|
|
102
102
|
const driveTransmitters = this.transmitters[drive] || {};
|
|
103
103
|
driveTransmitters[listener.listenerId] = transmitter;
|
|
104
104
|
this.transmitters[drive] = driveTransmitters;
|
|
105
|
+
|
|
106
|
+
this.triggerUpdate(true, { type: "local" });
|
|
105
107
|
return Promise.resolve(transmitter);
|
|
106
108
|
}
|
|
107
109
|
|
|
@@ -1,30 +1,40 @@
|
|
|
1
|
-
import { Document, OperationScope } from "document-model/document";
|
|
1
|
+
import { Document, Operation, OperationScope } from "document-model/document";
|
|
2
2
|
import { logger } from "../../../utils/logger";
|
|
3
3
|
import {
|
|
4
4
|
IBaseDocumentDriveServer,
|
|
5
5
|
Listener,
|
|
6
6
|
ListenerRevision,
|
|
7
|
-
OperationUpdate,
|
|
8
7
|
StrandUpdate,
|
|
9
8
|
} from "../../types";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
9
|
+
import { ITransmitter, StrandUpdateSource } from "./types";
|
|
10
|
+
import { InferDocumentOperation } from "../../../read-mode/types";
|
|
12
11
|
|
|
13
|
-
export interface IReceiver
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
export interface IReceiver<
|
|
13
|
+
T extends Document = Document,
|
|
14
|
+
S extends OperationScope = OperationScope,
|
|
15
|
+
> {
|
|
16
|
+
onStrands: (strands: InternalTransmitterUpdate<T, S>[]) => Promise<void>;
|
|
17
|
+
onDisconnect: () => Promise<void>;
|
|
16
18
|
}
|
|
17
19
|
|
|
20
|
+
export type InternalOperationUpdate<
|
|
21
|
+
D extends Document = Document,
|
|
22
|
+
S extends OperationScope = OperationScope,
|
|
23
|
+
> = Omit<Operation<InferDocumentOperation<D>>, "scope"> & {
|
|
24
|
+
state: D["state"][S];
|
|
25
|
+
previousState: D["state"][S];
|
|
26
|
+
};
|
|
27
|
+
|
|
18
28
|
export type InternalTransmitterUpdate<
|
|
19
|
-
|
|
29
|
+
D extends Document = Document,
|
|
20
30
|
S extends OperationScope = OperationScope,
|
|
21
31
|
> = {
|
|
22
32
|
driveId: string;
|
|
23
33
|
documentId: string;
|
|
24
34
|
scope: S;
|
|
25
35
|
branch: string;
|
|
26
|
-
operations:
|
|
27
|
-
state:
|
|
36
|
+
operations: InternalOperationUpdate<D, S>[];
|
|
37
|
+
state: D["state"][S];
|
|
28
38
|
};
|
|
29
39
|
|
|
30
40
|
export interface IInternalTransmitter extends ITransmitter {
|
|
@@ -32,52 +42,75 @@ export interface IInternalTransmitter extends ITransmitter {
|
|
|
32
42
|
}
|
|
33
43
|
|
|
34
44
|
export class InternalTransmitter implements ITransmitter {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
45
|
+
protected drive: IBaseDocumentDriveServer;
|
|
46
|
+
protected listener: Listener;
|
|
47
|
+
protected receiver: IReceiver | undefined;
|
|
38
48
|
|
|
39
49
|
constructor(listener: Listener, drive: IBaseDocumentDriveServer) {
|
|
40
50
|
this.listener = listener;
|
|
41
51
|
this.drive = drive;
|
|
42
52
|
}
|
|
43
53
|
|
|
54
|
+
async #buildInternalOperationUpdate(strand: StrandUpdate) {
|
|
55
|
+
const operations: InternalOperationUpdate[] = [];
|
|
56
|
+
const stateByIndex = new Map<number, unknown>();
|
|
57
|
+
const getStateByIndex = async (index: number) => {
|
|
58
|
+
const state = stateByIndex.get(index);
|
|
59
|
+
if (state) {
|
|
60
|
+
return state;
|
|
61
|
+
}
|
|
62
|
+
const document = await this.drive.getDocument(
|
|
63
|
+
strand.driveId,
|
|
64
|
+
strand.documentId,
|
|
65
|
+
{
|
|
66
|
+
revisions: {
|
|
67
|
+
[strand.scope]: index,
|
|
68
|
+
},
|
|
69
|
+
checkHashes: false,
|
|
70
|
+
},
|
|
71
|
+
);
|
|
72
|
+
if (index < 0) {
|
|
73
|
+
stateByIndex.set(index, document.initialState.state[strand.scope]);
|
|
74
|
+
} else {
|
|
75
|
+
stateByIndex.set(index, document.state[strand.scope]);
|
|
76
|
+
}
|
|
77
|
+
return stateByIndex.get(index);
|
|
78
|
+
};
|
|
79
|
+
for (const operation of strand.operations) {
|
|
80
|
+
operations.push({
|
|
81
|
+
...operation,
|
|
82
|
+
state: await getStateByIndex(operation.index),
|
|
83
|
+
previousState: await getStateByIndex(operation.index - 1),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return operations;
|
|
87
|
+
}
|
|
88
|
+
|
|
44
89
|
async transmit(
|
|
45
|
-
strands:
|
|
90
|
+
strands: StrandUpdate[],
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
92
|
+
_source: StrandUpdateSource,
|
|
46
93
|
): Promise<ListenerRevision[]> {
|
|
47
94
|
if (!this.receiver) {
|
|
48
95
|
return [];
|
|
49
96
|
}
|
|
50
97
|
|
|
51
|
-
const retrievedDocuments = new Map<string, Document>();
|
|
52
98
|
const updates: InternalTransmitterUpdate[] = [];
|
|
53
99
|
for (const strand of strands) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
strand.documentId,
|
|
62
|
-
);
|
|
63
|
-
document = await (strand.documentId
|
|
64
|
-
? this.drive.getDocument(strand.driveId, strand.documentId, {
|
|
65
|
-
revisions,
|
|
66
|
-
})
|
|
67
|
-
: this.drive.getDrive(strand.driveId, { revisions }));
|
|
68
|
-
retrievedDocuments.set(
|
|
69
|
-
`${strand.driveId}:${strand.documentId}`,
|
|
70
|
-
document,
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
updates.push({ ...strand, state: document.state[strand.scope] });
|
|
100
|
+
const operations = await this.#buildInternalOperationUpdate(strand);
|
|
101
|
+
const state = operations.at(-1)?.state ?? {};
|
|
102
|
+
updates.push({
|
|
103
|
+
...strand,
|
|
104
|
+
operations,
|
|
105
|
+
state,
|
|
106
|
+
});
|
|
74
107
|
}
|
|
75
108
|
try {
|
|
76
|
-
await this.receiver.
|
|
109
|
+
await this.receiver.onStrands(updates);
|
|
77
110
|
return strands.map(({ operations, ...s }) => ({
|
|
78
111
|
...s,
|
|
79
112
|
status: "SUCCESS",
|
|
80
|
-
revision: operations
|
|
113
|
+
revision: operations.at(operations.length - 1)?.index ?? -1,
|
|
81
114
|
}));
|
|
82
115
|
} catch (error) {
|
|
83
116
|
logger.error(error);
|
|
@@ -85,7 +118,7 @@ export class InternalTransmitter implements ITransmitter {
|
|
|
85
118
|
return strands.map(({ operations, ...s }) => ({
|
|
86
119
|
...s,
|
|
87
120
|
status: "ERROR",
|
|
88
|
-
revision: (operations
|
|
121
|
+
revision: (operations.at(0)?.index ?? 0) - 1,
|
|
89
122
|
}));
|
|
90
123
|
}
|
|
91
124
|
}
|
|
@@ -95,6 +128,10 @@ export class InternalTransmitter implements ITransmitter {
|
|
|
95
128
|
}
|
|
96
129
|
|
|
97
130
|
async disconnect(): Promise<void> {
|
|
98
|
-
await this.receiver?.
|
|
131
|
+
await this.receiver?.onDisconnect();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
getListener(): Listener {
|
|
135
|
+
return this.listener;
|
|
99
136
|
}
|
|
100
137
|
}
|