cojson-storage-indexeddb 0.5.0 → 0.6.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/CHANGELOG.md +19 -0
- package/dist/index.js +328 -229
- package/dist/index.js.map +1 -1
- package/dist/index.test.js +4 -4
- package/dist/index.test.js.map +1 -1
- package/dist/syncPromises.js +161 -0
- package/dist/syncPromises.js.map +1 -0
- package/package.json +2 -2
- package/src/index.test.ts +4 -4
- package/src/index.ts +558 -374
- package/src/syncPromises.ts +228 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# cojson-storage-indexeddb
|
|
2
2
|
|
|
3
|
+
## 0.6.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- IndexedDB & timer perf improvements
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- cojson@0.6.4
|
|
10
|
+
|
|
11
|
+
## 0.6.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- Make addMember and removeMember take loaded Accounts instead of just IDs
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Updated dependencies
|
|
20
|
+
- cojson@0.6.0
|
|
21
|
+
|
|
3
22
|
## 0.5.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { cojsonInternals, MAX_RECOMMENDED_TX_SIZE, } from "cojson";
|
|
2
|
+
import { SyncPromise } from "./syncPromises";
|
|
2
3
|
export class IDBStorage {
|
|
3
4
|
constructor(db, fromLocalNode, toLocalNode) {
|
|
5
|
+
this.currentTxID = 0;
|
|
4
6
|
this.db = db;
|
|
5
7
|
this.fromLocalNode = fromLocalNode.getReader();
|
|
6
8
|
this.toLocalNode = toLocalNode.getWriter();
|
|
@@ -10,12 +12,17 @@ export class IDBStorage {
|
|
|
10
12
|
const result = await this.fromLocalNode.read();
|
|
11
13
|
done = result.done;
|
|
12
14
|
if (result.value) {
|
|
13
|
-
await this.handleSyncMessage(result.value);
|
|
14
15
|
// console.log(
|
|
15
16
|
// "IDB: handling msg",
|
|
16
17
|
// result.value.id,
|
|
17
18
|
// result.value.action
|
|
18
19
|
// );
|
|
20
|
+
await this.handleSyncMessage(result.value);
|
|
21
|
+
// console.log(
|
|
22
|
+
// "IDB: handled msg",
|
|
23
|
+
// result.value.id,
|
|
24
|
+
// result.value.action
|
|
25
|
+
// );
|
|
19
26
|
}
|
|
20
27
|
}
|
|
21
28
|
})();
|
|
@@ -63,19 +70,21 @@ export class IDBStorage {
|
|
|
63
70
|
keyPath: ["ses", "idx"],
|
|
64
71
|
});
|
|
65
72
|
}
|
|
66
|
-
if (ev.oldVersion !== 0 && ev.oldVersion <= 3) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
73
|
+
// if (ev.oldVersion !== 0 && ev.oldVersion <= 3) {
|
|
74
|
+
// // fix embarrassing off-by-one error for transaction indices
|
|
75
|
+
// console.log("Migration: fixing off-by-one error");
|
|
76
|
+
// const transaction = (
|
|
77
|
+
// ev.target as unknown as { transaction: IDBTransaction }
|
|
78
|
+
// ).transaction;
|
|
79
|
+
// const txsStore = transaction.objectStore("transactions");
|
|
80
|
+
// const txs = await promised(txsStore.getAll());
|
|
81
|
+
// for (const tx of txs) {
|
|
82
|
+
// await promised(txsStore.delete([tx.ses, tx.idx]));
|
|
83
|
+
// tx.idx -= 1;
|
|
84
|
+
// await promised(txsStore.add(tx));
|
|
85
|
+
// }
|
|
86
|
+
// console.log("Migration: fixing off-by-one error - done");
|
|
87
|
+
// }
|
|
79
88
|
};
|
|
80
89
|
});
|
|
81
90
|
return new IDBStorage(await dbPromise, fromLocalNode, toLocalNode);
|
|
@@ -83,253 +92,343 @@ export class IDBStorage {
|
|
|
83
92
|
async handleSyncMessage(msg) {
|
|
84
93
|
switch (msg.action) {
|
|
85
94
|
case "load":
|
|
86
|
-
await this.handleLoad(msg);
|
|
95
|
+
/*await*/ this.handleLoad(msg);
|
|
87
96
|
break;
|
|
88
97
|
case "content":
|
|
89
98
|
await this.handleContent(msg);
|
|
90
99
|
break;
|
|
91
100
|
case "known":
|
|
92
|
-
await this.handleKnown(msg);
|
|
101
|
+
/*await*/ this.handleKnown(msg);
|
|
93
102
|
break;
|
|
94
103
|
case "done":
|
|
95
|
-
await this.handleDone(msg);
|
|
104
|
+
/*await*/ this.handleDone(msg);
|
|
96
105
|
break;
|
|
97
106
|
}
|
|
98
107
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
108
|
+
makeRequest(handler) {
|
|
109
|
+
return new SyncPromise((resolve, reject) => {
|
|
110
|
+
let txEntry = this.currentTx;
|
|
111
|
+
const requestEntry = ({ stores, }) => {
|
|
112
|
+
const request = handler(stores);
|
|
113
|
+
request.onerror = () => {
|
|
114
|
+
console.error("Error in request", request.error);
|
|
115
|
+
this.currentTx = undefined;
|
|
116
|
+
reject(request.error);
|
|
117
|
+
// TODO: recover pending requests in new tx
|
|
118
|
+
};
|
|
119
|
+
request.onsuccess = () => {
|
|
120
|
+
const value = request.result;
|
|
121
|
+
resolve(value);
|
|
122
|
+
const next = txEntry.pendingRequests.shift();
|
|
123
|
+
if (next) {
|
|
124
|
+
next({ stores });
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
if (this.currentTx === txEntry) {
|
|
128
|
+
this.currentTx = undefined;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
if (!txEntry || performance.now() - txEntry.startedAt > 20) {
|
|
134
|
+
const tx = this.db.transaction(["coValues", "sessions", "transactions", "signatureAfter"], "readwrite");
|
|
135
|
+
txEntry = {
|
|
136
|
+
id: this.currentTxID++,
|
|
137
|
+
tx,
|
|
138
|
+
stores: {
|
|
139
|
+
coValues: tx.objectStore("coValues"),
|
|
140
|
+
sessions: tx.objectStore("sessions"),
|
|
141
|
+
transactions: tx.objectStore("transactions"),
|
|
142
|
+
signatureAfter: tx.objectStore("signatureAfter"),
|
|
143
|
+
},
|
|
144
|
+
startedAt: performance.now(),
|
|
145
|
+
pendingRequests: [],
|
|
146
|
+
};
|
|
147
|
+
console.time("IndexedDB TX" + txEntry.id);
|
|
148
|
+
txEntry.tx.oncomplete = () => {
|
|
149
|
+
console.timeEnd("IndexedDB TX" + txEntry.id);
|
|
150
|
+
};
|
|
151
|
+
this.currentTx = txEntry;
|
|
152
|
+
requestEntry(txEntry);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
txEntry.pendingRequests.push(requestEntry);
|
|
130
156
|
// console.log(
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
// newTxInSession.length
|
|
157
|
+
// "Queued request in TX " + txEntry.id,
|
|
158
|
+
// txEntry.pendingRequests.length
|
|
134
159
|
// );
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
sendNewContentAfter(theirKnown, asDependencyOf) {
|
|
164
|
+
return this.makeRequest(({ coValues }) => coValues.index("coValuesById").get(theirKnown.id))
|
|
165
|
+
.then((coValueRow) => {
|
|
166
|
+
return (coValueRow
|
|
167
|
+
? this.makeRequest(({ sessions }) => sessions
|
|
168
|
+
.index("sessionsByCoValue")
|
|
169
|
+
.getAll(coValueRow.rowID))
|
|
170
|
+
: SyncPromise.resolve([])).then((allOurSessions) => {
|
|
171
|
+
const ourKnown = {
|
|
172
|
+
id: theirKnown.id,
|
|
173
|
+
header: !!coValueRow,
|
|
174
|
+
sessions: {},
|
|
175
|
+
};
|
|
176
|
+
const newContentPieces = [
|
|
177
|
+
{
|
|
178
|
+
action: "content",
|
|
179
|
+
id: theirKnown.id,
|
|
180
|
+
header: theirKnown.header
|
|
181
|
+
? undefined
|
|
182
|
+
: coValueRow?.header,
|
|
183
|
+
new: {},
|
|
184
|
+
},
|
|
185
|
+
];
|
|
186
|
+
return SyncPromise.all(allOurSessions.map((sessionRow) => {
|
|
187
|
+
ourKnown.sessions[sessionRow.sessionID] =
|
|
188
|
+
sessionRow.lastIdx;
|
|
189
|
+
if (sessionRow.lastIdx >
|
|
190
|
+
(theirKnown.sessions[sessionRow.sessionID] || 0)) {
|
|
191
|
+
const firstNewTxIdx = theirKnown.sessions[sessionRow.sessionID] ||
|
|
192
|
+
0;
|
|
193
|
+
return this.makeRequest(({ signatureAfter }) => signatureAfter.getAll(IDBKeyRange.bound([
|
|
194
|
+
sessionRow.rowID,
|
|
195
|
+
firstNewTxIdx,
|
|
196
|
+
], [sessionRow.rowID, Infinity]))).then((signaturesAndIdxs) => {
|
|
197
|
+
// console.log(
|
|
198
|
+
// theirKnown.id,
|
|
199
|
+
// "signaturesAndIdxs",
|
|
200
|
+
// JSON.stringify(signaturesAndIdxs)
|
|
201
|
+
// );
|
|
202
|
+
return this.makeRequest(({ transactions }) => transactions.getAll(IDBKeyRange.bound([
|
|
203
|
+
sessionRow.rowID,
|
|
204
|
+
firstNewTxIdx,
|
|
205
|
+
], [sessionRow.rowID, Infinity]))).then((newTxsInSession) => {
|
|
206
|
+
collectNewTxs(newTxsInSession, newContentPieces, sessionRow, signaturesAndIdxs, theirKnown, firstNewTxIdx);
|
|
207
|
+
});
|
|
155
208
|
});
|
|
156
209
|
}
|
|
157
|
-
else
|
|
158
|
-
|
|
159
|
-
sessionEntry.lastSignature = sessionRow.lastSignature;
|
|
210
|
+
else {
|
|
211
|
+
return SyncPromise.resolve();
|
|
160
212
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
]
|
|
190
|
-
: [];
|
|
191
|
-
for (const dependedOnCoValue of dependedOnCoValues) {
|
|
192
|
-
await this.sendNewContentAfter({ id: dependedOnCoValue, header: false, sessions: {} }, { coValues, sessions, transactions, signatureAfter }, asDependencyOf || theirKnown.id);
|
|
193
|
-
}
|
|
194
|
-
await this.toLocalNode.write({
|
|
195
|
-
action: "known",
|
|
196
|
-
...ourKnown,
|
|
197
|
-
asDependencyOf,
|
|
198
|
-
});
|
|
199
|
-
const nonEmptyNewContentPieces = newContentPieces.filter((piece) => piece.header || Object.keys(piece.new).length > 0);
|
|
200
|
-
// console.log(theirKnown.id, nonEmptyNewContentPieces);
|
|
201
|
-
for (const piece of nonEmptyNewContentPieces) {
|
|
202
|
-
await this.toLocalNode.write(piece);
|
|
203
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
204
|
-
}
|
|
213
|
+
})).then(() => {
|
|
214
|
+
const dependedOnCoValues = getDependedOnCoValues(coValueRow, newContentPieces, theirKnown);
|
|
215
|
+
return SyncPromise.all(dependedOnCoValues.map((dependedOnCoValue) => this.sendNewContentAfter({
|
|
216
|
+
id: dependedOnCoValue,
|
|
217
|
+
header: false,
|
|
218
|
+
sessions: {},
|
|
219
|
+
}, asDependencyOf || theirKnown.id))).then(() => {
|
|
220
|
+
// we're done with IndexedDB stuff here so can use native Promises again
|
|
221
|
+
setTimeout(async () => {
|
|
222
|
+
await this.toLocalNode.write({
|
|
223
|
+
action: "known",
|
|
224
|
+
...ourKnown,
|
|
225
|
+
asDependencyOf,
|
|
226
|
+
});
|
|
227
|
+
const nonEmptyNewContentPieces = newContentPieces.filter((piece) => piece.header ||
|
|
228
|
+
Object.keys(piece.new).length > 0);
|
|
229
|
+
// console.log(theirKnown.id, nonEmptyNewContentPieces);
|
|
230
|
+
for (const piece of nonEmptyNewContentPieces) {
|
|
231
|
+
await this.toLocalNode.write(piece);
|
|
232
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
233
|
+
}
|
|
234
|
+
}, 0);
|
|
235
|
+
return Promise.resolve();
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
})
|
|
240
|
+
.then(() => { });
|
|
205
241
|
}
|
|
206
242
|
handleLoad(msg) {
|
|
207
|
-
return this.sendNewContentAfter(msg
|
|
243
|
+
return this.sendNewContentAfter(msg);
|
|
208
244
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
245
|
+
handleContent(msg) {
|
|
246
|
+
return this.makeRequest(({ coValues }) => coValues.index("coValuesById").get(msg.id))
|
|
247
|
+
.then((coValueRow) => {
|
|
248
|
+
if (coValueRow?.rowID === undefined) {
|
|
249
|
+
const header = msg.header;
|
|
250
|
+
if (!header) {
|
|
251
|
+
console.error("Expected to be sent header first");
|
|
252
|
+
this.toLocalNode.write({
|
|
253
|
+
action: "known",
|
|
254
|
+
id: msg.id,
|
|
255
|
+
header: false,
|
|
256
|
+
sessions: {},
|
|
257
|
+
isCorrection: true,
|
|
258
|
+
});
|
|
259
|
+
throw new Error("Expected to be sent header first");
|
|
260
|
+
}
|
|
261
|
+
return this.makeRequest(({ coValues }) => coValues.put({
|
|
218
262
|
id: msg.id,
|
|
219
|
-
header:
|
|
220
|
-
|
|
221
|
-
isCorrection: true,
|
|
222
|
-
});
|
|
223
|
-
return;
|
|
263
|
+
header: header,
|
|
264
|
+
}));
|
|
224
265
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const allOurSessionsRequest = sessions
|
|
266
|
+
else {
|
|
267
|
+
return SyncPromise.resolve(coValueRow.rowID);
|
|
268
|
+
}
|
|
269
|
+
})
|
|
270
|
+
.then((storedCoValueRowID) => {
|
|
271
|
+
this.makeRequest(({ sessions }) => sessions
|
|
232
272
|
.index("sessionsByCoValue")
|
|
233
|
-
.getAll(storedCoValueRowID)
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
273
|
+
.getAll(storedCoValueRowID)).then((allOurSessionsEntries) => {
|
|
274
|
+
const allOurSessions = Object.fromEntries(allOurSessionsEntries.map((row) => [row.sessionID, row]));
|
|
275
|
+
const ourKnown = {
|
|
276
|
+
id: msg.id,
|
|
277
|
+
header: true,
|
|
278
|
+
sessions: {},
|
|
279
|
+
};
|
|
280
|
+
let invalidAssumptions = false;
|
|
281
|
+
return Promise.all(Object.keys(msg.new).map((sessionID) => {
|
|
282
|
+
const sessionRow = allOurSessions[sessionID];
|
|
283
|
+
if (sessionRow) {
|
|
284
|
+
ourKnown.sessions[sessionRow.sessionID] =
|
|
285
|
+
sessionRow.lastIdx;
|
|
286
|
+
}
|
|
287
|
+
if ((sessionRow?.lastIdx || 0) <
|
|
288
|
+
(msg.new[sessionID]?.after || 0)) {
|
|
289
|
+
invalidAssumptions = true;
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
return this.putNewTxs(msg, sessionID, sessionRow, storedCoValueRowID);
|
|
293
|
+
}
|
|
294
|
+
})).then(() => {
|
|
295
|
+
if (invalidAssumptions) {
|
|
296
|
+
this.toLocalNode.write({
|
|
297
|
+
action: "known",
|
|
298
|
+
...ourKnown,
|
|
299
|
+
isCorrection: invalidAssumptions,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
});
|
|
237
304
|
});
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
305
|
+
}
|
|
306
|
+
putNewTxs(msg, sessionID, sessionRow, storedCoValueRowID) {
|
|
307
|
+
const newTransactions = msg.new[sessionID]?.newTransactions || [];
|
|
308
|
+
const actuallyNewOffset = (sessionRow?.lastIdx || 0) - (msg.new[sessionID]?.after || 0);
|
|
309
|
+
const actuallyNewTransactions = newTransactions.slice(actuallyNewOffset);
|
|
310
|
+
let newBytesSinceLastSignature = (sessionRow?.bytesSinceLastSignature || 0) +
|
|
311
|
+
actuallyNewTransactions.reduce((sum, tx) => sum +
|
|
312
|
+
(tx.privacy === "private"
|
|
313
|
+
? tx.encryptedChanges.length
|
|
314
|
+
: tx.changes.length), 0);
|
|
315
|
+
const newLastIdx = (sessionRow?.lastIdx || 0) + actuallyNewTransactions.length;
|
|
316
|
+
let shouldWriteSignature = false;
|
|
317
|
+
if (newBytesSinceLastSignature > MAX_RECOMMENDED_TX_SIZE) {
|
|
318
|
+
shouldWriteSignature = true;
|
|
319
|
+
newBytesSinceLastSignature = 0;
|
|
320
|
+
}
|
|
321
|
+
const nextIdx = sessionRow?.lastIdx || 0;
|
|
322
|
+
const sessionUpdate = {
|
|
323
|
+
coValue: storedCoValueRowID,
|
|
324
|
+
sessionID: sessionID,
|
|
325
|
+
lastIdx: newLastIdx,
|
|
326
|
+
lastSignature: msg.new[sessionID].lastSignature,
|
|
327
|
+
bytesSinceLastSignature: newBytesSinceLastSignature,
|
|
242
328
|
};
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
ourKnown.sessions[sessionRow.sessionID] = sessionRow.lastIdx;
|
|
329
|
+
return this.makeRequest(({ sessions }) => sessions.put(sessionRow?.rowID
|
|
330
|
+
? {
|
|
331
|
+
rowID: sessionRow.rowID,
|
|
332
|
+
...sessionUpdate,
|
|
248
333
|
}
|
|
249
|
-
|
|
250
|
-
|
|
334
|
+
: sessionUpdate)).then((sessionRowID) => {
|
|
335
|
+
let maybePutRequest;
|
|
336
|
+
if (shouldWriteSignature) {
|
|
337
|
+
maybePutRequest = this.makeRequest(({ signatureAfter }) => signatureAfter.put({
|
|
338
|
+
ses: sessionRowID,
|
|
339
|
+
// TODO: newLastIdx is a misnomer, it's actually more like nextIdx or length
|
|
340
|
+
idx: newLastIdx - 1,
|
|
341
|
+
signature: msg.new[sessionID].lastSignature,
|
|
342
|
+
}));
|
|
251
343
|
}
|
|
252
344
|
else {
|
|
253
|
-
|
|
254
|
-
const actuallyNewOffset = (sessionRow?.lastIdx || 0) -
|
|
255
|
-
(msg.new[sessionID]?.after || 0);
|
|
256
|
-
const actuallyNewTransactions = newTransactions.slice(actuallyNewOffset);
|
|
257
|
-
let newBytesSinceLastSignature = (sessionRow?.bytesSinceLastSignature || 0) +
|
|
258
|
-
actuallyNewTransactions.reduce((sum, tx) => sum +
|
|
259
|
-
(tx.privacy === "private"
|
|
260
|
-
? tx.encryptedChanges.length
|
|
261
|
-
: tx.changes.length), 0);
|
|
262
|
-
const newLastIdx = (sessionRow?.lastIdx || 0) + actuallyNewTransactions.length;
|
|
263
|
-
let shouldWriteSignature = false;
|
|
264
|
-
if (newBytesSinceLastSignature > MAX_RECOMMENDED_TX_SIZE) {
|
|
265
|
-
shouldWriteSignature = true;
|
|
266
|
-
newBytesSinceLastSignature = 0;
|
|
267
|
-
}
|
|
268
|
-
let nextIdx = sessionRow?.lastIdx || 0;
|
|
269
|
-
const sessionUpdate = {
|
|
270
|
-
coValue: storedCoValueRowID,
|
|
271
|
-
sessionID: sessionID,
|
|
272
|
-
lastIdx: newLastIdx,
|
|
273
|
-
lastSignature: msg.new[sessionID].lastSignature,
|
|
274
|
-
bytesSinceLastSignature: newBytesSinceLastSignature,
|
|
275
|
-
};
|
|
276
|
-
const sessionRowID = (await promised(sessions.put(sessionRow?.rowID
|
|
277
|
-
? {
|
|
278
|
-
rowID: sessionRow.rowID,
|
|
279
|
-
...sessionUpdate,
|
|
280
|
-
}
|
|
281
|
-
: sessionUpdate)));
|
|
282
|
-
if (shouldWriteSignature) {
|
|
283
|
-
await promised(signatureAfter.put({
|
|
284
|
-
ses: sessionRowID,
|
|
285
|
-
// TODO: newLastIdx is a misnomer, it's actually more like nextIdx or length
|
|
286
|
-
idx: newLastIdx - 1,
|
|
287
|
-
signature: msg.new[sessionID].lastSignature,
|
|
288
|
-
}));
|
|
289
|
-
}
|
|
290
|
-
for (const newTransaction of actuallyNewTransactions) {
|
|
291
|
-
await promised(transactions.add({
|
|
292
|
-
ses: sessionRowID,
|
|
293
|
-
idx: nextIdx,
|
|
294
|
-
tx: newTransaction,
|
|
295
|
-
}));
|
|
296
|
-
nextIdx++;
|
|
297
|
-
}
|
|
345
|
+
maybePutRequest = SyncPromise.resolve();
|
|
298
346
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
});
|
|
306
|
-
}
|
|
347
|
+
return maybePutRequest.then(() => Promise.all(actuallyNewTransactions.map((newTransaction, i) => {
|
|
348
|
+
return this.makeRequest(({ transactions }) => transactions.add({
|
|
349
|
+
ses: sessionRowID,
|
|
350
|
+
idx: nextIdx + i,
|
|
351
|
+
tx: newTransaction,
|
|
352
|
+
}));
|
|
353
|
+
})));
|
|
354
|
+
});
|
|
307
355
|
}
|
|
308
356
|
handleKnown(msg) {
|
|
309
|
-
return this.sendNewContentAfter(msg
|
|
357
|
+
return this.sendNewContentAfter(msg);
|
|
310
358
|
}
|
|
311
359
|
handleDone(_msg) { }
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
360
|
+
}
|
|
361
|
+
function collectNewTxs(newTxsInSession, newContentPieces, sessionRow, signaturesAndIdxs, theirKnown, firstNewTxIdx) {
|
|
362
|
+
let idx = firstNewTxIdx;
|
|
363
|
+
// console.log(
|
|
364
|
+
// theirKnown.id,
|
|
365
|
+
// "newTxInSession",
|
|
366
|
+
// newTxInSession.length
|
|
367
|
+
// );
|
|
368
|
+
for (const tx of newTxsInSession) {
|
|
369
|
+
let sessionEntry = newContentPieces[newContentPieces.length - 1].new[sessionRow.sessionID];
|
|
370
|
+
if (!sessionEntry) {
|
|
371
|
+
sessionEntry = {
|
|
372
|
+
after: idx,
|
|
373
|
+
lastSignature: "WILL_BE_REPLACED",
|
|
374
|
+
newTransactions: [],
|
|
375
|
+
};
|
|
376
|
+
newContentPieces[newContentPieces.length - 1].new[sessionRow.sessionID] = sessionEntry;
|
|
377
|
+
}
|
|
378
|
+
sessionEntry.newTransactions.push(tx.tx);
|
|
379
|
+
if (signaturesAndIdxs[0] && idx === signaturesAndIdxs[0].idx) {
|
|
380
|
+
sessionEntry.lastSignature = signaturesAndIdxs[0].signature;
|
|
381
|
+
signaturesAndIdxs.shift();
|
|
382
|
+
newContentPieces.push({
|
|
383
|
+
action: "content",
|
|
384
|
+
id: theirKnown.id,
|
|
385
|
+
new: {},
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
else if (idx === firstNewTxIdx + newTxsInSession.length - 1) {
|
|
389
|
+
sessionEntry.lastSignature = sessionRow.lastSignature;
|
|
390
|
+
}
|
|
391
|
+
idx += 1;
|
|
323
392
|
}
|
|
324
393
|
}
|
|
325
|
-
function
|
|
326
|
-
return
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
394
|
+
function getDependedOnCoValues(coValueRow, newContentPieces, theirKnown) {
|
|
395
|
+
return coValueRow?.header.ruleset.type === "group"
|
|
396
|
+
? newContentPieces
|
|
397
|
+
.flatMap((piece) => Object.values(piece.new))
|
|
398
|
+
.flatMap((sessionEntry) => sessionEntry.newTransactions.flatMap((tx) => {
|
|
399
|
+
if (tx.privacy !== "trusting")
|
|
400
|
+
return [];
|
|
401
|
+
// TODO: avoid parse here?
|
|
402
|
+
return cojsonInternals
|
|
403
|
+
.parseJSON(tx.changes)
|
|
404
|
+
.map((change) => change &&
|
|
405
|
+
typeof change === "object" &&
|
|
406
|
+
"op" in change &&
|
|
407
|
+
change.op === "set" &&
|
|
408
|
+
"key" in change &&
|
|
409
|
+
change.key)
|
|
410
|
+
.filter((key) => typeof key === "string" &&
|
|
411
|
+
key.startsWith("co_"));
|
|
412
|
+
}))
|
|
413
|
+
: coValueRow?.header.ruleset.type === "ownedByGroup"
|
|
414
|
+
? [
|
|
415
|
+
coValueRow?.header.ruleset.group,
|
|
416
|
+
...new Set(newContentPieces.flatMap((piece) => Object.keys(piece)
|
|
417
|
+
.map((sessionID) => cojsonInternals.accountOrAgentIDfromSessionID(sessionID))
|
|
418
|
+
.filter((accountID) => cojsonInternals.isAccountID(accountID) &&
|
|
419
|
+
accountID !== theirKnown.id))),
|
|
420
|
+
]
|
|
421
|
+
: [];
|
|
334
422
|
}
|
|
423
|
+
// let lastTx = 0;
|
|
424
|
+
// function promised<T>(request: IDBRequest<T>): Promise<T> {
|
|
425
|
+
// return new Promise<T>((resolve, reject) => {
|
|
426
|
+
// request.onsuccess = () => {
|
|
427
|
+
// resolve(request.result);
|
|
428
|
+
// };
|
|
429
|
+
// request.onerror = () => {
|
|
430
|
+
// reject(request.error);
|
|
431
|
+
// };
|
|
432
|
+
// });
|
|
433
|
+
// }
|
|
335
434
|
//# sourceMappingURL=index.js.map
|