@lvce-editor/api 8.82.0 → 8.83.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.
|
@@ -3,8 +3,8 @@ import type { OutputChannelRegistrySnapshot } from '../OutputChannelRegistrySnap
|
|
|
3
3
|
export declare const activateOutputChannels: () => void;
|
|
4
4
|
export declare const createOutputChannel: (id: string) => OutputChannel;
|
|
5
5
|
export declare const getOutputChannelRegistrySnapshot: () => OutputChannelRegistrySnapshot;
|
|
6
|
-
export declare const getOutputChannelLogs: (id: string) => string | undefined
|
|
7
|
-
export declare const clearOutputChannel: (id: string) => boolean
|
|
6
|
+
export declare const getOutputChannelLogs: (id: string) => Promise<string | undefined>;
|
|
7
|
+
export declare const clearOutputChannel: (id: string) => Promise<boolean>;
|
|
8
8
|
export declare const resetOutputChannelRegistry: () => void;
|
|
9
9
|
export type { OutputChannel } from '../OutputChannelHandle/OutputChannelHandle.ts';
|
|
10
10
|
export type { OutputChannelRegistrySnapshot } from '../OutputChannelRegistrySnapshot/OutputChannelRegistrySnapshot.ts';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as ExtensionApiCommandRegistry from "../ExtensionApiCommandRegistry/ExtensionApiCommandRegistry.js";
|
|
2
2
|
import { ExtensionApiError } from "../ExtensionApiError/ExtensionApiError.js";
|
|
3
|
+
import * as OutputChannelStorage from "../OutputChannelStorage/OutputChannelStorage.js";
|
|
3
4
|
const outputChannels = Object.create(null);
|
|
4
|
-
const
|
|
5
|
+
const outputChannelHandles = Object.create(null);
|
|
5
6
|
let isActivated = false;
|
|
6
7
|
const RE_DASH_CASE = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
7
8
|
const assertOutputChannelId = (id) => {
|
|
@@ -19,28 +20,35 @@ const assertCanWrite = (id) => {
|
|
|
19
20
|
};
|
|
20
21
|
class ExtensionOutputChannel {
|
|
21
22
|
#id;
|
|
22
|
-
|
|
23
|
+
#pendingWrite;
|
|
24
|
+
constructor(id, pendingWrite) {
|
|
23
25
|
this.#id = id;
|
|
26
|
+
this.#pendingWrite = pendingWrite;
|
|
27
|
+
}
|
|
28
|
+
#queueWrite(write) {
|
|
29
|
+
this.#pendingWrite = this.#pendingWrite.then(write);
|
|
30
|
+
return this.#pendingWrite;
|
|
24
31
|
}
|
|
25
32
|
async append(text) {
|
|
26
33
|
assertCanWrite(this.#id);
|
|
27
|
-
|
|
34
|
+
await this.#queueWrite(() => OutputChannelStorage.append(this.#id, text));
|
|
28
35
|
}
|
|
29
36
|
async appendLine(text) {
|
|
30
37
|
assertCanWrite(this.#id);
|
|
31
|
-
|
|
38
|
+
await this.#queueWrite(() => OutputChannelStorage.append(this.#id, `${text}\n`));
|
|
32
39
|
}
|
|
33
40
|
async clear() {
|
|
34
41
|
assertCanWrite(this.#id);
|
|
35
|
-
|
|
42
|
+
await this.#queueWrite(() => OutputChannelStorage.clear(this.#id));
|
|
36
43
|
}
|
|
37
44
|
async getLogs() {
|
|
38
45
|
assertCanWrite(this.#id);
|
|
39
|
-
|
|
46
|
+
await this.#pendingWrite;
|
|
47
|
+
return OutputChannelStorage.getLogs(this.#id);
|
|
40
48
|
}
|
|
41
49
|
async replace(text) {
|
|
42
50
|
assertCanWrite(this.#id);
|
|
43
|
-
|
|
51
|
+
await this.#queueWrite(() => OutputChannelStorage.replace(this.#id, text));
|
|
44
52
|
}
|
|
45
53
|
}
|
|
46
54
|
export const activateOutputChannels = () => {
|
|
@@ -54,23 +62,25 @@ export const createOutputChannel = (id) => {
|
|
|
54
62
|
outputChannels[id] = {
|
|
55
63
|
id,
|
|
56
64
|
};
|
|
57
|
-
outputChannelLogs[id] = '';
|
|
58
65
|
ExtensionApiCommandRegistry.registerCommandMap(commandMap);
|
|
59
|
-
|
|
66
|
+
const handle = new ExtensionOutputChannel(id, OutputChannelStorage.clear(id));
|
|
67
|
+
outputChannelHandles[id] = handle;
|
|
68
|
+
return handle;
|
|
60
69
|
};
|
|
61
70
|
export const getOutputChannelRegistrySnapshot = () => {
|
|
62
71
|
return {
|
|
63
72
|
outputChannels: Object.values(outputChannels),
|
|
64
73
|
};
|
|
65
74
|
};
|
|
66
|
-
export const getOutputChannelLogs = (id) => {
|
|
67
|
-
return
|
|
75
|
+
export const getOutputChannelLogs = async (id) => {
|
|
76
|
+
return outputChannelHandles[id]?.getLogs();
|
|
68
77
|
};
|
|
69
|
-
export const clearOutputChannel = (id) => {
|
|
70
|
-
|
|
78
|
+
export const clearOutputChannel = async (id) => {
|
|
79
|
+
const handle = outputChannelHandles[id];
|
|
80
|
+
if (!handle) {
|
|
71
81
|
return false;
|
|
72
82
|
}
|
|
73
|
-
|
|
83
|
+
await handle.clear();
|
|
74
84
|
return true;
|
|
75
85
|
};
|
|
76
86
|
const commandMap = {
|
|
@@ -82,8 +92,8 @@ export const resetOutputChannelRegistry = () => {
|
|
|
82
92
|
for (const id of Object.keys(outputChannels)) {
|
|
83
93
|
delete outputChannels[id];
|
|
84
94
|
}
|
|
85
|
-
for (const id of Object.keys(
|
|
86
|
-
delete
|
|
95
|
+
for (const id of Object.keys(outputChannelHandles)) {
|
|
96
|
+
delete outputChannelHandles[id];
|
|
87
97
|
}
|
|
88
98
|
isActivated = false;
|
|
89
99
|
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const append: (channelId: string, text: string) => Promise<void>;
|
|
2
|
+
export declare const clear: (channelId: string) => Promise<void>;
|
|
3
|
+
export declare const getLogs: (channelId: string) => Promise<string>;
|
|
4
|
+
export declare const replace: (channelId: string, text: string) => Promise<void>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const databasePrefix = 'lvce-editor-extension-output';
|
|
2
|
+
const databaseVersion = 1;
|
|
3
|
+
const objectStoreName = 'chunks';
|
|
4
|
+
const channelIdIndexName = 'channelId';
|
|
5
|
+
let databasePromise;
|
|
6
|
+
const getDatabaseName = () => {
|
|
7
|
+
const extensionPath = typeof location === 'undefined' ? 'test' : location.pathname;
|
|
8
|
+
return `${databasePrefix}:${extensionPath}`;
|
|
9
|
+
};
|
|
10
|
+
const openDatabase = () => {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const request = indexedDB.open(getDatabaseName(), databaseVersion);
|
|
13
|
+
request.onerror = () => reject(request.error);
|
|
14
|
+
request.onupgradeneeded = () => {
|
|
15
|
+
const database = request.result;
|
|
16
|
+
const objectStore = database.createObjectStore(objectStoreName, {
|
|
17
|
+
autoIncrement: true,
|
|
18
|
+
});
|
|
19
|
+
objectStore.createIndex(channelIdIndexName, 'channelId');
|
|
20
|
+
};
|
|
21
|
+
request.onsuccess = () => resolve(request.result);
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
const getDatabase = () => {
|
|
25
|
+
databasePromise ||= openDatabase();
|
|
26
|
+
return databasePromise;
|
|
27
|
+
};
|
|
28
|
+
const waitForTransaction = (transaction) => {
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
transaction.onabort = () => reject(transaction.error);
|
|
31
|
+
transaction.onerror = () => reject(transaction.error);
|
|
32
|
+
transaction.oncomplete = () => resolve();
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
const deleteChannelChunks = (objectStore, channelId, onComplete = () => { }) => {
|
|
36
|
+
const index = objectStore.index(channelIdIndexName);
|
|
37
|
+
const request = index.openKeyCursor(IDBKeyRange.only(channelId));
|
|
38
|
+
request.onsuccess = () => {
|
|
39
|
+
const cursor = request.result;
|
|
40
|
+
if (!cursor) {
|
|
41
|
+
onComplete();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
objectStore.delete(cursor.primaryKey);
|
|
45
|
+
cursor.continue();
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export const append = async (channelId, text) => {
|
|
49
|
+
const database = await getDatabase();
|
|
50
|
+
const transaction = database.transaction(objectStoreName, 'readwrite');
|
|
51
|
+
transaction.objectStore(objectStoreName).add({ channelId, text });
|
|
52
|
+
await waitForTransaction(transaction);
|
|
53
|
+
};
|
|
54
|
+
export const clear = async (channelId) => {
|
|
55
|
+
const database = await getDatabase();
|
|
56
|
+
const transaction = database.transaction(objectStoreName, 'readwrite');
|
|
57
|
+
deleteChannelChunks(transaction.objectStore(objectStoreName), channelId);
|
|
58
|
+
await waitForTransaction(transaction);
|
|
59
|
+
};
|
|
60
|
+
export const getLogs = async (channelId) => {
|
|
61
|
+
const database = await getDatabase();
|
|
62
|
+
const transaction = database.transaction(objectStoreName, 'readonly');
|
|
63
|
+
const request = transaction.objectStore(objectStoreName).index(channelIdIndexName).getAll(IDBKeyRange.only(channelId));
|
|
64
|
+
const chunks = await new Promise((resolve, reject) => {
|
|
65
|
+
request.onerror = () => reject(request.error);
|
|
66
|
+
request.onsuccess = () => resolve(request.result);
|
|
67
|
+
});
|
|
68
|
+
await waitForTransaction(transaction);
|
|
69
|
+
return chunks.map((chunk) => chunk.text).join('');
|
|
70
|
+
};
|
|
71
|
+
export const replace = async (channelId, text) => {
|
|
72
|
+
const database = await getDatabase();
|
|
73
|
+
const transaction = database.transaction(objectStoreName, 'readwrite');
|
|
74
|
+
const objectStore = transaction.objectStore(objectStoreName);
|
|
75
|
+
deleteChannelChunks(objectStore, channelId, () => {
|
|
76
|
+
objectStore.add({ channelId, text });
|
|
77
|
+
});
|
|
78
|
+
await waitForTransaction(transaction);
|
|
79
|
+
};
|