@lvce-editor/chat-storage-worker 1.2.0 → 1.4.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/dist/chatStorageWorkerMain.js +338 -343
- package/package.json +1 -1
|
@@ -1,59 +1,3 @@
|
|
|
1
|
-
const normalizeLine = line => {
|
|
2
|
-
if (line.startsWith('Error: ')) {
|
|
3
|
-
return line.slice('Error: '.length);
|
|
4
|
-
}
|
|
5
|
-
if (line.startsWith('VError: ')) {
|
|
6
|
-
return line.slice('VError: '.length);
|
|
7
|
-
}
|
|
8
|
-
return line;
|
|
9
|
-
};
|
|
10
|
-
const getCombinedMessage = (error, message) => {
|
|
11
|
-
const stringifiedError = normalizeLine(`${error}`);
|
|
12
|
-
if (message) {
|
|
13
|
-
return `${message}: ${stringifiedError}`;
|
|
14
|
-
}
|
|
15
|
-
return stringifiedError;
|
|
16
|
-
};
|
|
17
|
-
const NewLine$2 = '\n';
|
|
18
|
-
const getNewLineIndex$1 = (string, startIndex = undefined) => {
|
|
19
|
-
return string.indexOf(NewLine$2, startIndex);
|
|
20
|
-
};
|
|
21
|
-
const mergeStacks = (parent, child) => {
|
|
22
|
-
if (!child) {
|
|
23
|
-
return parent;
|
|
24
|
-
}
|
|
25
|
-
const parentNewLineIndex = getNewLineIndex$1(parent);
|
|
26
|
-
const childNewLineIndex = getNewLineIndex$1(child);
|
|
27
|
-
if (childNewLineIndex === -1) {
|
|
28
|
-
return parent;
|
|
29
|
-
}
|
|
30
|
-
const parentFirstLine = parent.slice(0, parentNewLineIndex);
|
|
31
|
-
const childRest = child.slice(childNewLineIndex);
|
|
32
|
-
const childFirstLine = normalizeLine(child.slice(0, childNewLineIndex));
|
|
33
|
-
if (parentFirstLine.includes(childFirstLine)) {
|
|
34
|
-
return parentFirstLine + childRest;
|
|
35
|
-
}
|
|
36
|
-
return child;
|
|
37
|
-
};
|
|
38
|
-
class VError extends Error {
|
|
39
|
-
constructor(error, message) {
|
|
40
|
-
const combinedMessage = getCombinedMessage(error, message);
|
|
41
|
-
super(combinedMessage);
|
|
42
|
-
this.name = 'VError';
|
|
43
|
-
if (error instanceof Error) {
|
|
44
|
-
this.stack = mergeStacks(this.stack, error.stack);
|
|
45
|
-
}
|
|
46
|
-
if (error.codeFrame) {
|
|
47
|
-
// @ts-ignore
|
|
48
|
-
this.codeFrame = error.codeFrame;
|
|
49
|
-
}
|
|
50
|
-
if (error.code) {
|
|
51
|
-
// @ts-ignore
|
|
52
|
-
this.code = error.code;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
1
|
const isMessagePort = value => {
|
|
58
2
|
return value && value instanceof MessagePort;
|
|
59
3
|
};
|
|
@@ -124,145 +68,6 @@ class Ipc extends EventTarget {
|
|
|
124
68
|
attachEvents(this);
|
|
125
69
|
}
|
|
126
70
|
}
|
|
127
|
-
const E_INCOMPATIBLE_NATIVE_MODULE = 'E_INCOMPATIBLE_NATIVE_MODULE';
|
|
128
|
-
const E_MODULES_NOT_SUPPORTED_IN_ELECTRON = 'E_MODULES_NOT_SUPPORTED_IN_ELECTRON';
|
|
129
|
-
const ERR_MODULE_NOT_FOUND = 'ERR_MODULE_NOT_FOUND';
|
|
130
|
-
const NewLine$1 = '\n';
|
|
131
|
-
const joinLines$1 = lines => {
|
|
132
|
-
return lines.join(NewLine$1);
|
|
133
|
-
};
|
|
134
|
-
const RE_AT = /^\s+at/;
|
|
135
|
-
const RE_AT_PROMISE_INDEX = /^\s*at async Promise.all \(index \d+\)$/;
|
|
136
|
-
const isNormalStackLine = line => {
|
|
137
|
-
return RE_AT.test(line) && !RE_AT_PROMISE_INDEX.test(line);
|
|
138
|
-
};
|
|
139
|
-
const getDetails = lines => {
|
|
140
|
-
const index = lines.findIndex(isNormalStackLine);
|
|
141
|
-
if (index === -1) {
|
|
142
|
-
return {
|
|
143
|
-
actualMessage: joinLines$1(lines),
|
|
144
|
-
rest: []
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
let lastIndex = index - 1;
|
|
148
|
-
while (++lastIndex < lines.length) {
|
|
149
|
-
if (!isNormalStackLine(lines[lastIndex])) {
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
return {
|
|
154
|
-
actualMessage: lines[index - 1],
|
|
155
|
-
rest: lines.slice(index, lastIndex)
|
|
156
|
-
};
|
|
157
|
-
};
|
|
158
|
-
const splitLines$1 = lines => {
|
|
159
|
-
return lines.split(NewLine$1);
|
|
160
|
-
};
|
|
161
|
-
const RE_MESSAGE_CODE_BLOCK_START = /^Error: The module '.*'$/;
|
|
162
|
-
const RE_MESSAGE_CODE_BLOCK_END = /^\s* at/;
|
|
163
|
-
const isMessageCodeBlockStartIndex = line => {
|
|
164
|
-
return RE_MESSAGE_CODE_BLOCK_START.test(line);
|
|
165
|
-
};
|
|
166
|
-
const isMessageCodeBlockEndIndex = line => {
|
|
167
|
-
return RE_MESSAGE_CODE_BLOCK_END.test(line);
|
|
168
|
-
};
|
|
169
|
-
const getMessageCodeBlock = stderr => {
|
|
170
|
-
const lines = splitLines$1(stderr);
|
|
171
|
-
const startIndex = lines.findIndex(isMessageCodeBlockStartIndex);
|
|
172
|
-
const endIndex = startIndex + lines.slice(startIndex).findIndex(isMessageCodeBlockEndIndex, startIndex);
|
|
173
|
-
const relevantLines = lines.slice(startIndex, endIndex);
|
|
174
|
-
const relevantMessage = relevantLines.join(' ').slice('Error: '.length);
|
|
175
|
-
return relevantMessage;
|
|
176
|
-
};
|
|
177
|
-
const isModuleNotFoundMessage = line => {
|
|
178
|
-
return line.includes('[ERR_MODULE_NOT_FOUND]');
|
|
179
|
-
};
|
|
180
|
-
const getModuleNotFoundError = stderr => {
|
|
181
|
-
const lines = splitLines$1(stderr);
|
|
182
|
-
const messageIndex = lines.findIndex(isModuleNotFoundMessage);
|
|
183
|
-
const message = lines[messageIndex];
|
|
184
|
-
return {
|
|
185
|
-
code: ERR_MODULE_NOT_FOUND,
|
|
186
|
-
message
|
|
187
|
-
};
|
|
188
|
-
};
|
|
189
|
-
const isModuleNotFoundError = stderr => {
|
|
190
|
-
if (!stderr) {
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
return stderr.includes('ERR_MODULE_NOT_FOUND');
|
|
194
|
-
};
|
|
195
|
-
const isModulesSyntaxError = stderr => {
|
|
196
|
-
if (!stderr) {
|
|
197
|
-
return false;
|
|
198
|
-
}
|
|
199
|
-
return stderr.includes('SyntaxError: Cannot use import statement outside a module');
|
|
200
|
-
};
|
|
201
|
-
const RE_NATIVE_MODULE_ERROR = /^innerError Error: Cannot find module '.*.node'/;
|
|
202
|
-
const RE_NATIVE_MODULE_ERROR_2 = /was compiled against a different Node.js version/;
|
|
203
|
-
const isUnhelpfulNativeModuleError = stderr => {
|
|
204
|
-
return RE_NATIVE_MODULE_ERROR.test(stderr) && RE_NATIVE_MODULE_ERROR_2.test(stderr);
|
|
205
|
-
};
|
|
206
|
-
const getNativeModuleErrorMessage = stderr => {
|
|
207
|
-
const message = getMessageCodeBlock(stderr);
|
|
208
|
-
return {
|
|
209
|
-
code: E_INCOMPATIBLE_NATIVE_MODULE,
|
|
210
|
-
message: `Incompatible native node module: ${message}`
|
|
211
|
-
};
|
|
212
|
-
};
|
|
213
|
-
const getModuleSyntaxError = () => {
|
|
214
|
-
return {
|
|
215
|
-
code: E_MODULES_NOT_SUPPORTED_IN_ELECTRON,
|
|
216
|
-
message: `ES Modules are not supported in electron`
|
|
217
|
-
};
|
|
218
|
-
};
|
|
219
|
-
const getHelpfulChildProcessError = (stdout, stderr) => {
|
|
220
|
-
if (isUnhelpfulNativeModuleError(stderr)) {
|
|
221
|
-
return getNativeModuleErrorMessage(stderr);
|
|
222
|
-
}
|
|
223
|
-
if (isModulesSyntaxError(stderr)) {
|
|
224
|
-
return getModuleSyntaxError();
|
|
225
|
-
}
|
|
226
|
-
if (isModuleNotFoundError(stderr)) {
|
|
227
|
-
return getModuleNotFoundError(stderr);
|
|
228
|
-
}
|
|
229
|
-
const lines = splitLines$1(stderr);
|
|
230
|
-
const {
|
|
231
|
-
actualMessage,
|
|
232
|
-
rest
|
|
233
|
-
} = getDetails(lines);
|
|
234
|
-
return {
|
|
235
|
-
code: '',
|
|
236
|
-
message: actualMessage,
|
|
237
|
-
stack: rest
|
|
238
|
-
};
|
|
239
|
-
};
|
|
240
|
-
class IpcError extends VError {
|
|
241
|
-
// @ts-ignore
|
|
242
|
-
constructor(betterMessage, stdout = '', stderr = '') {
|
|
243
|
-
if (stdout || stderr) {
|
|
244
|
-
// @ts-ignore
|
|
245
|
-
const {
|
|
246
|
-
code,
|
|
247
|
-
message,
|
|
248
|
-
stack
|
|
249
|
-
} = getHelpfulChildProcessError(stdout, stderr);
|
|
250
|
-
const cause = new Error(message);
|
|
251
|
-
// @ts-ignore
|
|
252
|
-
cause.code = code;
|
|
253
|
-
cause.stack = stack;
|
|
254
|
-
super(cause, betterMessage);
|
|
255
|
-
} else {
|
|
256
|
-
super(betterMessage);
|
|
257
|
-
}
|
|
258
|
-
// @ts-ignore
|
|
259
|
-
this.name = 'IpcError';
|
|
260
|
-
// @ts-ignore
|
|
261
|
-
this.stdout = stdout;
|
|
262
|
-
// @ts-ignore
|
|
263
|
-
this.stderr = stderr;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
71
|
const readyMessage = 'ready';
|
|
267
72
|
const getData$2 = event => {
|
|
268
73
|
return event.data;
|
|
@@ -342,70 +147,11 @@ class IpcChildWithModuleWorker extends Ipc {
|
|
|
342
147
|
const wrap$f = global => {
|
|
343
148
|
return new IpcChildWithModuleWorker(global);
|
|
344
149
|
};
|
|
345
|
-
const
|
|
346
|
-
const {
|
|
347
|
-
promise,
|
|
348
|
-
resolve
|
|
349
|
-
} = Promise.withResolvers();
|
|
350
|
-
port.addEventListener('message', resolve, {
|
|
351
|
-
once: true
|
|
352
|
-
});
|
|
353
|
-
const event = await promise;
|
|
354
|
-
// @ts-ignore
|
|
355
|
-
return event.data;
|
|
356
|
-
};
|
|
357
|
-
const listen$6 = async () => {
|
|
358
|
-
const parentIpcRaw = listen$7();
|
|
359
|
-
signal$8(parentIpcRaw);
|
|
360
|
-
const parentIpc = wrap$f(parentIpcRaw);
|
|
361
|
-
const firstMessage = await waitForFirstMessage(parentIpc);
|
|
362
|
-
if (firstMessage.method !== 'initialize') {
|
|
363
|
-
throw new IpcError('unexpected first message');
|
|
364
|
-
}
|
|
365
|
-
const type = firstMessage.params[0];
|
|
366
|
-
if (type === 'message-port') {
|
|
367
|
-
parentIpc.send({
|
|
368
|
-
id: firstMessage.id,
|
|
369
|
-
jsonrpc: '2.0',
|
|
370
|
-
result: null
|
|
371
|
-
});
|
|
372
|
-
parentIpc.dispose();
|
|
373
|
-
const port = firstMessage.params[1];
|
|
374
|
-
return port;
|
|
375
|
-
}
|
|
376
|
-
return globalThis;
|
|
377
|
-
};
|
|
378
|
-
class IpcChildWithModuleWorkerAndMessagePort extends Ipc {
|
|
379
|
-
getData(event) {
|
|
380
|
-
return getData$2(event);
|
|
381
|
-
}
|
|
382
|
-
send(message) {
|
|
383
|
-
this._rawIpc.postMessage(message);
|
|
384
|
-
}
|
|
385
|
-
sendAndTransfer(message) {
|
|
386
|
-
const transfer = getTransferrables(message);
|
|
387
|
-
this._rawIpc.postMessage(message, transfer);
|
|
388
|
-
}
|
|
389
|
-
dispose() {
|
|
390
|
-
if (this._rawIpc.close) {
|
|
391
|
-
this._rawIpc.close();
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
onClose(callback) {
|
|
395
|
-
// ignore
|
|
396
|
-
}
|
|
397
|
-
onMessage(callback) {
|
|
398
|
-
this._rawIpc.addEventListener('message', callback);
|
|
399
|
-
this._rawIpc.start();
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
const wrap$e = port => {
|
|
403
|
-
return new IpcChildWithModuleWorkerAndMessagePort(port);
|
|
404
|
-
};
|
|
405
|
-
const IpcChildWithModuleWorkerAndMessagePort$1 = {
|
|
150
|
+
const IpcChildWithModuleWorker$1 = {
|
|
406
151
|
__proto__: null,
|
|
407
|
-
listen: listen$
|
|
408
|
-
|
|
152
|
+
listen: listen$7,
|
|
153
|
+
signal: signal$8,
|
|
154
|
+
wrap: wrap$f
|
|
409
155
|
};
|
|
410
156
|
|
|
411
157
|
class CommandNotFoundError extends Error {
|
|
@@ -882,53 +628,267 @@ const create = async ({
|
|
|
882
628
|
}) => {
|
|
883
629
|
// TODO create a commandMap per rpc instance
|
|
884
630
|
register(commandMap);
|
|
885
|
-
const ipc = await listen$1(
|
|
631
|
+
const ipc = await listen$1(IpcChildWithModuleWorker$1);
|
|
886
632
|
handleIpc(ipc);
|
|
887
633
|
const rpc = createRpc(ipc);
|
|
888
634
|
return rpc;
|
|
889
635
|
};
|
|
890
636
|
|
|
891
|
-
const
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
637
|
+
const instanceOfAny = (object, constructors) => constructors.some(c => object instanceof c);
|
|
638
|
+
let idbProxyableTypes;
|
|
639
|
+
let cursorAdvanceMethods;
|
|
640
|
+
// This is a function to prevent it throwing up in node environments.
|
|
641
|
+
function getIdbProxyableTypes() {
|
|
642
|
+
return idbProxyableTypes || (idbProxyableTypes = [IDBDatabase, IDBObjectStore, IDBIndex, IDBCursor, IDBTransaction]);
|
|
643
|
+
}
|
|
644
|
+
// This is a function to prevent it throwing up in node environments.
|
|
645
|
+
function getCursorAdvanceMethods() {
|
|
646
|
+
return cursorAdvanceMethods || (cursorAdvanceMethods = [IDBCursor.prototype.advance, IDBCursor.prototype.continue, IDBCursor.prototype.continuePrimaryKey]);
|
|
647
|
+
}
|
|
648
|
+
const transactionDoneMap = new WeakMap();
|
|
649
|
+
const transformCache = new WeakMap();
|
|
650
|
+
const reverseTransformCache = new WeakMap();
|
|
651
|
+
function promisifyRequest(request) {
|
|
652
|
+
const promise = new Promise((resolve, reject) => {
|
|
653
|
+
const unlisten = () => {
|
|
654
|
+
request.removeEventListener('success', success);
|
|
655
|
+
request.removeEventListener('error', error);
|
|
656
|
+
};
|
|
657
|
+
const success = () => {
|
|
658
|
+
resolve(wrap(request.result));
|
|
659
|
+
unlisten();
|
|
660
|
+
};
|
|
661
|
+
const error = () => {
|
|
662
|
+
reject(request.error);
|
|
663
|
+
unlisten();
|
|
664
|
+
};
|
|
665
|
+
request.addEventListener('success', success);
|
|
666
|
+
request.addEventListener('error', error);
|
|
910
667
|
});
|
|
668
|
+
// This mapping exists in reverseTransformCache but doesn't exist in transformCache. This
|
|
669
|
+
// is because we create many promises from a single IDBRequest.
|
|
670
|
+
reverseTransformCache.set(promise, request);
|
|
911
671
|
return promise;
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
const {
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
672
|
+
}
|
|
673
|
+
function cacheDonePromiseForTransaction(tx) {
|
|
674
|
+
// Early bail if we've already created a done promise for this transaction.
|
|
675
|
+
if (transactionDoneMap.has(tx)) return;
|
|
676
|
+
const done = new Promise((resolve, reject) => {
|
|
677
|
+
const unlisten = () => {
|
|
678
|
+
tx.removeEventListener('complete', complete);
|
|
679
|
+
tx.removeEventListener('error', error);
|
|
680
|
+
tx.removeEventListener('abort', error);
|
|
681
|
+
};
|
|
682
|
+
const complete = () => {
|
|
683
|
+
resolve();
|
|
684
|
+
unlisten();
|
|
685
|
+
};
|
|
686
|
+
const error = () => {
|
|
687
|
+
reject(tx.error || new DOMException('AbortError', 'AbortError'));
|
|
688
|
+
unlisten();
|
|
689
|
+
};
|
|
690
|
+
tx.addEventListener('complete', complete);
|
|
691
|
+
tx.addEventListener('error', error);
|
|
692
|
+
tx.addEventListener('abort', error);
|
|
929
693
|
});
|
|
930
|
-
|
|
694
|
+
// Cache it for later retrieval.
|
|
695
|
+
transactionDoneMap.set(tx, done);
|
|
696
|
+
}
|
|
697
|
+
let idbProxyTraps = {
|
|
698
|
+
get(target, prop, receiver) {
|
|
699
|
+
if (target instanceof IDBTransaction) {
|
|
700
|
+
// Special handling for transaction.done.
|
|
701
|
+
if (prop === 'done') return transactionDoneMap.get(target);
|
|
702
|
+
// Make tx.store return the only store in the transaction, or undefined if there are many.
|
|
703
|
+
if (prop === 'store') {
|
|
704
|
+
return receiver.objectStoreNames[1] ? undefined : receiver.objectStore(receiver.objectStoreNames[0]);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
// Else transform whatever we get back.
|
|
708
|
+
return wrap(target[prop]);
|
|
709
|
+
},
|
|
710
|
+
set(target, prop, value) {
|
|
711
|
+
target[prop] = value;
|
|
712
|
+
return true;
|
|
713
|
+
},
|
|
714
|
+
has(target, prop) {
|
|
715
|
+
if (target instanceof IDBTransaction && (prop === 'done' || prop === 'store')) {
|
|
716
|
+
return true;
|
|
717
|
+
}
|
|
718
|
+
return prop in target;
|
|
719
|
+
}
|
|
931
720
|
};
|
|
721
|
+
function replaceTraps(callback) {
|
|
722
|
+
idbProxyTraps = callback(idbProxyTraps);
|
|
723
|
+
}
|
|
724
|
+
function wrapFunction(func) {
|
|
725
|
+
// Due to expected object equality (which is enforced by the caching in `wrap`), we
|
|
726
|
+
// only create one new func per func.
|
|
727
|
+
// Cursor methods are special, as the behaviour is a little more different to standard IDB. In
|
|
728
|
+
// IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the
|
|
729
|
+
// cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense
|
|
730
|
+
// with real promises, so each advance methods returns a new promise for the cursor object, or
|
|
731
|
+
// undefined if the end of the cursor has been reached.
|
|
732
|
+
if (getCursorAdvanceMethods().includes(func)) {
|
|
733
|
+
return function (...args) {
|
|
734
|
+
// Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
|
|
735
|
+
// the original object.
|
|
736
|
+
func.apply(unwrap(this), args);
|
|
737
|
+
return wrap(this.request);
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
return function (...args) {
|
|
741
|
+
// Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
|
|
742
|
+
// the original object.
|
|
743
|
+
return wrap(func.apply(unwrap(this), args));
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
function transformCachableValue(value) {
|
|
747
|
+
if (typeof value === 'function') return wrapFunction(value);
|
|
748
|
+
// This doesn't return, it just creates a 'done' promise for the transaction,
|
|
749
|
+
// which is later returned for transaction.done (see idbObjectHandler).
|
|
750
|
+
if (value instanceof IDBTransaction) cacheDonePromiseForTransaction(value);
|
|
751
|
+
if (instanceOfAny(value, getIdbProxyableTypes())) return new Proxy(value, idbProxyTraps);
|
|
752
|
+
// Return the same value back if we're not going to transform it.
|
|
753
|
+
return value;
|
|
754
|
+
}
|
|
755
|
+
function wrap(value) {
|
|
756
|
+
// We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because
|
|
757
|
+
// IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.
|
|
758
|
+
if (value instanceof IDBRequest) return promisifyRequest(value);
|
|
759
|
+
// If we've already transformed this value before, reuse the transformed value.
|
|
760
|
+
// This is faster, but it also provides object equality.
|
|
761
|
+
if (transformCache.has(value)) return transformCache.get(value);
|
|
762
|
+
const newValue = transformCachableValue(value);
|
|
763
|
+
// Not all types are transformed.
|
|
764
|
+
// These may be primitive types, so they can't be WeakMap keys.
|
|
765
|
+
if (newValue !== value) {
|
|
766
|
+
transformCache.set(value, newValue);
|
|
767
|
+
reverseTransformCache.set(newValue, value);
|
|
768
|
+
}
|
|
769
|
+
return newValue;
|
|
770
|
+
}
|
|
771
|
+
const unwrap = value => reverseTransformCache.get(value);
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Open a database.
|
|
775
|
+
*
|
|
776
|
+
* @param name Name of the database.
|
|
777
|
+
* @param version Schema version.
|
|
778
|
+
* @param callbacks Additional callbacks.
|
|
779
|
+
*/
|
|
780
|
+
function openDB(name, version, {
|
|
781
|
+
blocked,
|
|
782
|
+
upgrade,
|
|
783
|
+
blocking,
|
|
784
|
+
terminated
|
|
785
|
+
} = {}) {
|
|
786
|
+
const request = indexedDB.open(name, version);
|
|
787
|
+
const openPromise = wrap(request);
|
|
788
|
+
if (upgrade) {
|
|
789
|
+
request.addEventListener('upgradeneeded', event => {
|
|
790
|
+
upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
if (blocked) {
|
|
794
|
+
request.addEventListener('blocked', event => blocked(
|
|
795
|
+
// Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
|
|
796
|
+
event.oldVersion, event.newVersion, event));
|
|
797
|
+
}
|
|
798
|
+
openPromise.then(db => {
|
|
799
|
+
if (terminated) db.addEventListener('close', () => terminated());
|
|
800
|
+
if (blocking) {
|
|
801
|
+
db.addEventListener('versionchange', event => blocking(event.oldVersion, event.newVersion, event));
|
|
802
|
+
}
|
|
803
|
+
}).catch(() => {});
|
|
804
|
+
return openPromise;
|
|
805
|
+
}
|
|
806
|
+
const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];
|
|
807
|
+
const writeMethods = ['put', 'add', 'delete', 'clear'];
|
|
808
|
+
const cachedMethods = new Map();
|
|
809
|
+
function getMethod(target, prop) {
|
|
810
|
+
if (!(target instanceof IDBDatabase && !(prop in target) && typeof prop === 'string')) {
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
if (cachedMethods.get(prop)) return cachedMethods.get(prop);
|
|
814
|
+
const targetFuncName = prop.replace(/FromIndex$/, '');
|
|
815
|
+
const useIndex = prop !== targetFuncName;
|
|
816
|
+
const isWrite = writeMethods.includes(targetFuncName);
|
|
817
|
+
if (
|
|
818
|
+
// Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.
|
|
819
|
+
!(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || !(isWrite || readMethods.includes(targetFuncName))) {
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
const method = async function (storeName, ...args) {
|
|
823
|
+
// isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(
|
|
824
|
+
const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');
|
|
825
|
+
let target = tx.store;
|
|
826
|
+
if (useIndex) target = target.index(args.shift());
|
|
827
|
+
// Must reject if op rejects.
|
|
828
|
+
// If it's a write operation, must reject if tx.done rejects.
|
|
829
|
+
// Must reject with op rejection first.
|
|
830
|
+
// Must resolve with op value.
|
|
831
|
+
// Must handle both promises (no unhandled rejections)
|
|
832
|
+
return (await Promise.all([target[targetFuncName](...args), isWrite && tx.done]))[0];
|
|
833
|
+
};
|
|
834
|
+
cachedMethods.set(prop, method);
|
|
835
|
+
return method;
|
|
836
|
+
}
|
|
837
|
+
replaceTraps(oldTraps => ({
|
|
838
|
+
...oldTraps,
|
|
839
|
+
get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),
|
|
840
|
+
has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop)
|
|
841
|
+
}));
|
|
842
|
+
const advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];
|
|
843
|
+
const methodMap = {};
|
|
844
|
+
const advanceResults = new WeakMap();
|
|
845
|
+
const ittrProxiedCursorToOriginalProxy = new WeakMap();
|
|
846
|
+
const cursorIteratorTraps = {
|
|
847
|
+
get(target, prop) {
|
|
848
|
+
if (!advanceMethodProps.includes(prop)) return target[prop];
|
|
849
|
+
let cachedFunc = methodMap[prop];
|
|
850
|
+
if (!cachedFunc) {
|
|
851
|
+
cachedFunc = methodMap[prop] = function (...args) {
|
|
852
|
+
advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
return cachedFunc;
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
async function* iterate(...args) {
|
|
859
|
+
// tslint:disable-next-line:no-this-assignment
|
|
860
|
+
let cursor = this;
|
|
861
|
+
if (!(cursor instanceof IDBCursor)) {
|
|
862
|
+
cursor = await cursor.openCursor(...args);
|
|
863
|
+
}
|
|
864
|
+
if (!cursor) return;
|
|
865
|
+
cursor = cursor;
|
|
866
|
+
const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
|
|
867
|
+
ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
|
|
868
|
+
// Map this double-proxy back to the original, so other cursor methods work.
|
|
869
|
+
reverseTransformCache.set(proxiedCursor, unwrap(cursor));
|
|
870
|
+
while (cursor) {
|
|
871
|
+
yield proxiedCursor;
|
|
872
|
+
// If one of the advancing methods was not called, call continue().
|
|
873
|
+
cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
|
|
874
|
+
advanceResults.delete(proxiedCursor);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
function isIteratorProp(target, prop) {
|
|
878
|
+
return prop === Symbol.asyncIterator && instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor]) || prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore]);
|
|
879
|
+
}
|
|
880
|
+
replaceTraps(oldTraps => ({
|
|
881
|
+
...oldTraps,
|
|
882
|
+
get(target, prop, receiver) {
|
|
883
|
+
if (isIteratorProp(target, prop)) return iterate;
|
|
884
|
+
return oldTraps.get(target, prop, receiver);
|
|
885
|
+
},
|
|
886
|
+
has(target, prop) {
|
|
887
|
+
return isIteratorProp(target, prop) || oldTraps.has(target, prop);
|
|
888
|
+
}
|
|
889
|
+
}));
|
|
890
|
+
|
|
891
|
+
/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
|
|
932
892
|
|
|
933
893
|
const toChatViewEvent = event => {
|
|
934
894
|
const {
|
|
@@ -1105,68 +1065,52 @@ class IndexedDbChatSessionStorage {
|
|
|
1105
1065
|
if (this.state.databasePromise) {
|
|
1106
1066
|
return this.state.databasePromise;
|
|
1107
1067
|
}
|
|
1108
|
-
const
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
});
|
|
1115
|
-
}
|
|
1116
|
-
if (database.objectStoreNames.contains(this.state.eventStoreName)) {
|
|
1117
|
-
const {
|
|
1118
|
-
transaction
|
|
1119
|
-
} = request;
|
|
1120
|
-
if (!transaction) {
|
|
1121
|
-
return;
|
|
1068
|
+
const databasePromise = openDB(this.state.databaseName, this.state.databaseVersion, {
|
|
1069
|
+
upgrade: (database, _oldVersion, _newVersion, transaction) => {
|
|
1070
|
+
if (!database.objectStoreNames.contains(this.state.storeName)) {
|
|
1071
|
+
database.createObjectStore(this.state.storeName, {
|
|
1072
|
+
keyPath: 'id'
|
|
1073
|
+
});
|
|
1122
1074
|
}
|
|
1123
|
-
|
|
1124
|
-
|
|
1075
|
+
if (database.objectStoreNames.contains(this.state.eventStoreName)) {
|
|
1076
|
+
const eventStore = transaction.objectStore(this.state.eventStoreName);
|
|
1077
|
+
if (!eventStore.indexNames.contains('sessionId')) {
|
|
1078
|
+
eventStore.createIndex('sessionId', 'sessionId', {
|
|
1079
|
+
unique: false
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
} else {
|
|
1083
|
+
const eventStore = database.createObjectStore(this.state.eventStoreName, {
|
|
1084
|
+
autoIncrement: true,
|
|
1085
|
+
keyPath: 'eventId'
|
|
1086
|
+
});
|
|
1125
1087
|
eventStore.createIndex('sessionId', 'sessionId', {
|
|
1126
1088
|
unique: false
|
|
1127
1089
|
});
|
|
1128
1090
|
}
|
|
1129
|
-
} else {
|
|
1130
|
-
const eventStore = database.createObjectStore(this.state.eventStoreName, {
|
|
1131
|
-
autoIncrement: true,
|
|
1132
|
-
keyPath: 'eventId'
|
|
1133
|
-
});
|
|
1134
|
-
eventStore.createIndex('sessionId', 'sessionId', {
|
|
1135
|
-
unique: false
|
|
1136
|
-
});
|
|
1137
1091
|
}
|
|
1138
1092
|
});
|
|
1139
|
-
const databasePromise = requestToPromise(() => request);
|
|
1140
1093
|
this.state.databasePromise = databasePromise;
|
|
1141
1094
|
return databasePromise;
|
|
1142
1095
|
};
|
|
1143
1096
|
listSummaries = async () => {
|
|
1144
1097
|
const database = await this.openDatabase();
|
|
1145
|
-
const
|
|
1146
|
-
const store = transaction.objectStore(this.state.storeName);
|
|
1147
|
-
const summaries = await requestToPromise(() => store.getAll());
|
|
1098
|
+
const summaries = await database.getAll(this.state.storeName);
|
|
1148
1099
|
return summaries;
|
|
1149
1100
|
};
|
|
1150
1101
|
getSummary = async id => {
|
|
1151
1102
|
const database = await this.openDatabase();
|
|
1152
|
-
const
|
|
1153
|
-
const store = transaction.objectStore(this.state.storeName);
|
|
1154
|
-
const summary = await requestToPromise(() => store.get(id));
|
|
1103
|
+
const summary = await database.get(this.state.storeName, id);
|
|
1155
1104
|
return summary;
|
|
1156
1105
|
};
|
|
1157
1106
|
getEventsBySessionId = async sessionId => {
|
|
1158
1107
|
const database = await this.openDatabase();
|
|
1159
|
-
const
|
|
1160
|
-
const store = transaction.objectStore(this.state.eventStoreName);
|
|
1161
|
-
const index = store.index('sessionId');
|
|
1162
|
-
const events = await requestToPromise(() => index.getAll(IDBKeyRange.only(sessionId)));
|
|
1108
|
+
const events = await database.getAllFromIndex(this.state.eventStoreName, 'sessionId', IDBKeyRange.only(sessionId));
|
|
1163
1109
|
return events.map(toChatViewEvent);
|
|
1164
1110
|
};
|
|
1165
1111
|
listEventsInternal = async () => {
|
|
1166
1112
|
const database = await this.openDatabase();
|
|
1167
|
-
const
|
|
1168
|
-
const store = transaction.objectStore(this.state.eventStoreName);
|
|
1169
|
-
const events = await requestToPromise(() => store.getAll());
|
|
1113
|
+
const events = await database.getAll(this.state.eventStoreName);
|
|
1170
1114
|
return events.map(toChatViewEvent);
|
|
1171
1115
|
};
|
|
1172
1116
|
appendEvents = async events => {
|
|
@@ -1178,18 +1122,18 @@ class IndexedDbChatSessionStorage {
|
|
|
1178
1122
|
const summaryStore = transaction.objectStore(this.state.storeName);
|
|
1179
1123
|
const eventStore = transaction.objectStore(this.state.eventStoreName);
|
|
1180
1124
|
for (const event of events) {
|
|
1181
|
-
eventStore.add(event);
|
|
1125
|
+
await eventStore.add(event);
|
|
1182
1126
|
if (event.type === 'chat-session-created' || event.type === 'chat-session-title-updated') {
|
|
1183
|
-
summaryStore.put({
|
|
1127
|
+
await summaryStore.put({
|
|
1184
1128
|
id: event.sessionId,
|
|
1185
1129
|
title: event.title
|
|
1186
1130
|
});
|
|
1187
1131
|
}
|
|
1188
1132
|
if (event.type === 'chat-session-deleted') {
|
|
1189
|
-
summaryStore.delete(event.sessionId);
|
|
1133
|
+
await summaryStore.delete(event.sessionId);
|
|
1190
1134
|
}
|
|
1191
1135
|
}
|
|
1192
|
-
await
|
|
1136
|
+
await transaction.done;
|
|
1193
1137
|
};
|
|
1194
1138
|
async appendEvent(event) {
|
|
1195
1139
|
await this.appendEvents([event]);
|
|
@@ -1197,9 +1141,8 @@ class IndexedDbChatSessionStorage {
|
|
|
1197
1141
|
async clear() {
|
|
1198
1142
|
const database = await this.openDatabase();
|
|
1199
1143
|
const transaction = database.transaction([this.state.storeName, this.state.eventStoreName], 'readwrite');
|
|
1200
|
-
transaction.objectStore(this.state.storeName).clear();
|
|
1201
|
-
transaction.
|
|
1202
|
-
await transactionToPromise(() => transaction);
|
|
1144
|
+
await Promise.all([transaction.objectStore(this.state.storeName).clear(), transaction.objectStore(this.state.eventStoreName).clear()]);
|
|
1145
|
+
await transaction.done;
|
|
1203
1146
|
}
|
|
1204
1147
|
async deleteSession(id) {
|
|
1205
1148
|
await this.appendEvent({
|
|
@@ -1239,11 +1182,11 @@ class IndexedDbChatSessionStorage {
|
|
|
1239
1182
|
const database = await this.openDatabase();
|
|
1240
1183
|
const transaction = database.transaction(this.state.storeName, 'readwrite');
|
|
1241
1184
|
const summaryStore = transaction.objectStore(this.state.storeName);
|
|
1242
|
-
summaryStore.put({
|
|
1185
|
+
await summaryStore.put({
|
|
1243
1186
|
id: session.id,
|
|
1244
1187
|
title: session.title
|
|
1245
1188
|
});
|
|
1246
|
-
await
|
|
1189
|
+
await transaction.done;
|
|
1247
1190
|
}
|
|
1248
1191
|
}
|
|
1249
1192
|
}
|
|
@@ -1520,6 +1463,56 @@ const handleMessagePort = async port => {
|
|
|
1520
1463
|
});
|
|
1521
1464
|
};
|
|
1522
1465
|
|
|
1466
|
+
const setTodosInIndexedDb = async todos => {
|
|
1467
|
+
const todoDbName = 'chat-tool-worker';
|
|
1468
|
+
const todoStoreName = 'state';
|
|
1469
|
+
const todoKey = 'todoList';
|
|
1470
|
+
const db = await new Promise((resolve, reject) => {
|
|
1471
|
+
const openRequest = indexedDB.open(todoDbName, 1);
|
|
1472
|
+
openRequest.onupgradeneeded = () => {
|
|
1473
|
+
const nextDb = openRequest.result;
|
|
1474
|
+
if (!nextDb.objectStoreNames.contains(todoStoreName)) {
|
|
1475
|
+
nextDb.createObjectStore(todoStoreName);
|
|
1476
|
+
}
|
|
1477
|
+
};
|
|
1478
|
+
openRequest.onsuccess = () => {
|
|
1479
|
+
resolve(openRequest.result);
|
|
1480
|
+
};
|
|
1481
|
+
openRequest.onerror = () => {
|
|
1482
|
+
reject(openRequest.error ?? new Error('Failed to open IndexedDB'));
|
|
1483
|
+
};
|
|
1484
|
+
});
|
|
1485
|
+
await new Promise((resolve, reject) => {
|
|
1486
|
+
const transaction = db.transaction(todoStoreName, 'readwrite');
|
|
1487
|
+
transaction.objectStore(todoStoreName).put(todos, todoKey);
|
|
1488
|
+
transaction.oncomplete = () => {
|
|
1489
|
+
db.close();
|
|
1490
|
+
resolve();
|
|
1491
|
+
};
|
|
1492
|
+
transaction.onerror = () => {
|
|
1493
|
+
db.close();
|
|
1494
|
+
reject(transaction.error ?? new Error('Failed to persist todo list'));
|
|
1495
|
+
};
|
|
1496
|
+
transaction.onabort = () => {
|
|
1497
|
+
db.close();
|
|
1498
|
+
reject(transaction.error ?? new Error('Failed to persist todo list'));
|
|
1499
|
+
};
|
|
1500
|
+
});
|
|
1501
|
+
};
|
|
1502
|
+
const setTodosInCacheStorage = async todos => {
|
|
1503
|
+
const todoCacheName = 'chat-tool-worker-todo';
|
|
1504
|
+
const todoCacheRequest = new Request('https://chat-tool-worker.local/todo-list');
|
|
1505
|
+
const cache = await caches.open(todoCacheName);
|
|
1506
|
+
const payload = JSON.stringify({
|
|
1507
|
+
todos
|
|
1508
|
+
});
|
|
1509
|
+
await cache.put(todoCacheRequest, new Response(payload, {
|
|
1510
|
+
headers: {
|
|
1511
|
+
'content-type': 'application/json'
|
|
1512
|
+
}
|
|
1513
|
+
}));
|
|
1514
|
+
};
|
|
1515
|
+
|
|
1523
1516
|
const commandMap = {
|
|
1524
1517
|
'ChatStorage.appendEvent': appendChatViewEvent,
|
|
1525
1518
|
'ChatStorage.clear': clearChatSessions,
|
|
@@ -1528,6 +1521,8 @@ const commandMap = {
|
|
|
1528
1521
|
'ChatStorage.getSession': getChatSession,
|
|
1529
1522
|
'ChatStorage.listSessions': listChatSessions,
|
|
1530
1523
|
'ChatStorage.setSession': setSession,
|
|
1524
|
+
'ChatStorage.setTodosInCacheStorage': setTodosInCacheStorage,
|
|
1525
|
+
'ChatStorage.setTodosInIndexedDb': setTodosInIndexedDb,
|
|
1531
1526
|
'HandleMessagePort.handleMessagePort': handleMessagePort
|
|
1532
1527
|
};
|
|
1533
1528
|
|