@akala/pm 15.2.9 → 15.3.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/changelog.md +7 -3
- package/dist/esm/ipc-adapter.d.ts +9 -6
- package/dist/esm/ipc-adapter.js +27 -17
- package/dist/esm/ipc-adapter.js.map +1 -1
- package/dist/esm/messageport-adapter.d.ts +10 -6
- package/dist/esm/messageport-adapter.js +48 -15
- package/dist/esm/messageport-adapter.js.map +1 -1
- package/dist/esm/virtual-scroll-prefixer.d.ts +12 -0
- package/dist/esm/virtual-scroll-prefixer.js +47 -0
- package/dist/esm/virtual-scroll-prefixer.js.map +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/src/ipc-adapter.ts +45 -23
- package/src/messageport-adapter.ts +59 -19
- package/src/virtual-scroll-prefixer.ts +67 -0
package/package.json
CHANGED
@@ -4,11 +4,11 @@
|
|
4
4
|
"pm": "dist/esm/cli.js",
|
5
5
|
"pm-fork": "dist/esm/fork.js"
|
6
6
|
},
|
7
|
-
"version": "15.
|
7
|
+
"version": "15.3.0",
|
8
8
|
"scripts": {
|
9
9
|
"test": "echo 1",
|
10
|
-
"generate": "
|
11
|
-
"generate-metadata": "
|
10
|
+
"generate": "akala sdk generate dist/esm/commands commands.json --name pm && akala sdk generate dist/esm/cli-commands cli-commands.json --name pm",
|
11
|
+
"generate-metadata": "akala sdk generate-metadata commands.json src/container.ts && akala sdk generate-metadata cli-commands.json src/cli-container.ts",
|
12
12
|
"prepack": "../../makeCjs.sh",
|
13
13
|
"akala-install": "akala plugins add dist/esm/akala.mjs"
|
14
14
|
},
|
@@ -29,11 +29,11 @@
|
|
29
29
|
"src/fork.ts"
|
30
30
|
],
|
31
31
|
"dependencies": {
|
32
|
-
"@akala/cli": "^5.
|
33
|
-
"@akala/commands": "^16.
|
34
|
-
"@akala/config": "^6.0.
|
35
|
-
"@akala/core": "^39.
|
36
|
-
"@akala/json-rpc-ws": "^
|
32
|
+
"@akala/cli": "^5.10.0",
|
33
|
+
"@akala/commands": "^16.1.0",
|
34
|
+
"@akala/config": "^6.0.75",
|
35
|
+
"@akala/core": "^39.5.0",
|
36
|
+
"@akala/json-rpc-ws": "^12.0.0",
|
37
37
|
"reflect-metadata": "^0.2.2",
|
38
38
|
"source-map-support": "^0.5.21"
|
39
39
|
},
|
package/src/ipc-adapter.ts
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
import { ChildProcess } from "child_process";
|
2
2
|
import * as jsonrpc from '@akala/json-rpc-ws';
|
3
|
-
import {
|
3
|
+
import { AllEventKeys, AllEvents, EventArgs, EventKeys, EventListener, EventOptions, EventReturnType, StatefulSubscription, Subscription, TeardownManager } from "@akala/core";
|
4
4
|
|
5
|
-
export class IpcAdapter implements jsonrpc.SocketAdapter
|
5
|
+
export class IpcAdapter extends TeardownManager implements jsonrpc.SocketAdapter
|
6
6
|
{
|
7
7
|
get open(): boolean { return !!this.cp.pid; }
|
8
8
|
|
9
9
|
|
10
|
-
pipe(socket: jsonrpc.SocketAdapter
|
10
|
+
pipe(socket: jsonrpc.SocketAdapter)
|
11
11
|
{
|
12
12
|
this.on('message', (message) => socket.send(message));
|
13
13
|
this.on('close', () => socket.close());
|
@@ -25,7 +25,11 @@ export class IpcAdapter implements jsonrpc.SocketAdapter
|
|
25
25
|
else
|
26
26
|
console.warn(`process ${this.cp.pid} does not support send over IPC`);
|
27
27
|
}
|
28
|
-
|
28
|
+
|
29
|
+
public off<const TEvent extends AllEventKeys<jsonrpc.SocketAdapterAkalaEventMap>>(
|
30
|
+
event: TEvent,
|
31
|
+
handler: EventListener<AllEvents<jsonrpc.SocketAdapterAkalaEventMap>[TEvent]>
|
32
|
+
): boolean
|
29
33
|
{
|
30
34
|
switch (event)
|
31
35
|
{
|
@@ -39,41 +43,59 @@ export class IpcAdapter implements jsonrpc.SocketAdapter
|
|
39
43
|
this.cp.off('disconnect', handler);
|
40
44
|
break;
|
41
45
|
}
|
46
|
+
return true;
|
42
47
|
}
|
43
|
-
|
48
|
+
|
49
|
+
public on<const TEvent extends AllEventKeys<jsonrpc.SocketAdapterAkalaEventMap>>(
|
50
|
+
event: TEvent,
|
51
|
+
handler: EventListener<AllEvents<jsonrpc.SocketAdapterAkalaEventMap>[TEvent]>,
|
52
|
+
options?: EventOptions<AllEvents<jsonrpc.SocketAdapterAkalaEventMap>[TEvent]>
|
53
|
+
): Subscription
|
44
54
|
{
|
45
55
|
switch (event)
|
46
56
|
{
|
47
57
|
case 'message':
|
48
|
-
|
49
|
-
|
58
|
+
if (options?.once)
|
59
|
+
this.cp.on('message', handler);
|
60
|
+
else
|
61
|
+
this.cp.on('message', handler);
|
62
|
+
return new StatefulSubscription(() => this.cp.off('message', handler)).unsubscribe;
|
50
63
|
case 'open':
|
51
64
|
handler(null);
|
52
65
|
break;
|
53
66
|
case 'close':
|
54
|
-
|
55
|
-
|
67
|
+
if (options?.once)
|
68
|
+
this.cp.once('disconnect', handler);
|
69
|
+
else
|
70
|
+
this.cp.on('disconnect', handler);
|
71
|
+
return new StatefulSubscription(() => this.cp.off('disconnect', handler)).unsubscribe;
|
56
72
|
}
|
57
73
|
}
|
58
74
|
|
59
|
-
once<
|
75
|
+
public once<const TEvent extends AllEventKeys<jsonrpc.SocketAdapterAkalaEventMap>>(
|
76
|
+
event: TEvent,
|
77
|
+
handler: EventListener<AllEvents<jsonrpc.SocketAdapterAkalaEventMap>[TEvent]>,
|
78
|
+
): Subscription
|
60
79
|
{
|
61
|
-
|
62
|
-
{
|
63
|
-
case 'message':
|
64
|
-
this.cp.once('message', handler);
|
65
|
-
break;
|
66
|
-
case 'open':
|
67
|
-
handler(null);
|
68
|
-
break;
|
69
|
-
case 'close':
|
70
|
-
this.cp.once('disconnect', () => handler(null));
|
71
|
-
break;
|
72
|
-
}
|
80
|
+
return this.on(event, handler, { once: true } as EventOptions<AllEvents<jsonrpc.SocketAdapterAkalaEventMap>[TEvent]>)
|
73
81
|
}
|
74
82
|
|
75
83
|
constructor(private cp: ChildProcess | typeof process)
|
76
84
|
{
|
85
|
+
super();
|
86
|
+
}
|
87
|
+
hasListener<const TKey extends AllEventKeys<jsonrpc.SocketAdapterAkalaEventMap>>(name: TKey)
|
88
|
+
{
|
89
|
+
if (name === 'open')
|
90
|
+
return false;
|
91
|
+
return !!this.cp.listenerCount(name);
|
92
|
+
}
|
93
|
+
get definedEvents(): AllEventKeys<jsonrpc.SocketAdapterAkalaEventMap>[]
|
94
|
+
{
|
95
|
+
return (['close', 'error', 'message'] as const).filter(ev => this.hasListener(ev));
|
96
|
+
}
|
97
|
+
emit<const TEvent extends EventKeys<jsonrpc.SocketAdapterAkalaEventMap>>(event: TEvent, ...args: EventArgs<jsonrpc.SocketAdapterAkalaEventMap[TEvent]>): false | EventReturnType<jsonrpc.SocketAdapterAkalaEventMap[TEvent]>
|
98
|
+
{
|
99
|
+
throw new Error("Method not implemented.");
|
77
100
|
}
|
78
|
-
|
79
101
|
}
|
@@ -1,7 +1,8 @@
|
|
1
|
-
import {
|
1
|
+
import { AllEventKeys, AllEvents, EventArgs, EventKeys, EventListener, EventOptions, EventReturnType, StatefulSubscription, Subscription, TeardownManager } from "@akala/core";
|
2
|
+
import { SocketAdapter, SocketAdapterAkalaEventMap } from "@akala/json-rpc-ws";
|
2
3
|
import { MessagePort, Worker } from "worker_threads";
|
3
4
|
|
4
|
-
export class MessagePortAdapter implements SocketAdapter
|
5
|
+
export class MessagePortAdapter extends TeardownManager implements SocketAdapter
|
5
6
|
{
|
6
7
|
private isOpen: boolean = true;
|
7
8
|
|
@@ -17,48 +18,70 @@ export class MessagePortAdapter implements SocketAdapter
|
|
17
18
|
{
|
18
19
|
this.cp.postMessage(data);
|
19
20
|
}
|
20
|
-
|
21
|
+
|
22
|
+
public on<const TEvent extends AllEventKeys<SocketAdapterAkalaEventMap>>(
|
23
|
+
event: TEvent,
|
24
|
+
handler: EventListener<AllEvents<SocketAdapterAkalaEventMap>[TEvent]>,
|
25
|
+
options?: EventOptions<AllEvents<SocketAdapterAkalaEventMap>[TEvent]>
|
26
|
+
): Subscription
|
21
27
|
{
|
22
28
|
switch (event)
|
23
29
|
{
|
24
30
|
case 'message':
|
25
|
-
|
26
|
-
|
31
|
+
if (options?.once)
|
32
|
+
this.cp.on('message', handler);
|
33
|
+
else
|
34
|
+
this.cp.on('message', handler);
|
35
|
+
return new StatefulSubscription(() => this.cp.off('message', handler)).unsubscribe;
|
27
36
|
case 'open':
|
28
37
|
handler(null);
|
29
38
|
break;
|
30
39
|
case 'close':
|
31
|
-
|
32
|
-
|
40
|
+
if (options?.once)
|
41
|
+
this.cp.once('disconnect', handler);
|
42
|
+
else
|
43
|
+
this.cp.on('disconnect', handler);
|
44
|
+
return new StatefulSubscription(() => this.cp.off('disconnect', handler)).unsubscribe;
|
33
45
|
}
|
34
46
|
}
|
35
47
|
|
36
|
-
once<
|
48
|
+
public once<const TEvent extends AllEventKeys<SocketAdapterAkalaEventMap>>(
|
49
|
+
event: TEvent,
|
50
|
+
handler: EventListener<AllEvents<SocketAdapterAkalaEventMap>[TEvent]>,
|
51
|
+
): Subscription
|
52
|
+
{
|
53
|
+
return this.on(event, handler, { once: true } as EventOptions<AllEvents<SocketAdapterAkalaEventMap>[TEvent]>)
|
54
|
+
}
|
55
|
+
|
56
|
+
|
57
|
+
constructor(private cp: MessagePort | Worker)
|
58
|
+
{
|
59
|
+
super();
|
60
|
+
cp.on('close', () => this.isOpen = false);
|
61
|
+
}
|
62
|
+
|
63
|
+
public off<const TEvent extends AllEventKeys<SocketAdapterAkalaEventMap>>(
|
64
|
+
event: TEvent,
|
65
|
+
handler: EventListener<AllEvents<SocketAdapterAkalaEventMap>[TEvent]>
|
66
|
+
): boolean
|
37
67
|
{
|
38
68
|
switch (event)
|
39
69
|
{
|
40
70
|
case 'message':
|
41
|
-
this.cp.
|
71
|
+
this.cp.off('message', handler);
|
42
72
|
break;
|
43
73
|
case 'open':
|
44
74
|
handler(null);
|
45
75
|
break;
|
46
76
|
case 'close':
|
47
|
-
this.cp.
|
77
|
+
this.cp.off('disconnect', handler);
|
48
78
|
break;
|
49
79
|
}
|
80
|
+
return true;
|
50
81
|
}
|
51
82
|
|
52
|
-
constructor(private cp: MessagePort | Worker)
|
53
|
-
{
|
54
|
-
cp.on('close', () => this.isOpen = false);
|
55
|
-
}
|
56
|
-
off<K extends keyof SocketAdapterEventMap>(event: K, handler?: (this: unknown, ev: SocketAdapterEventMap[K]) => void): void
|
57
|
-
{
|
58
|
-
this.cp.off(event, handler);
|
59
|
-
}
|
60
83
|
|
61
|
-
pipe(socket: SocketAdapter
|
84
|
+
pipe(socket: SocketAdapter)
|
62
85
|
{
|
63
86
|
this.on('message', (message) => socket.send(message));
|
64
87
|
this.on('close', () => socket.close());
|
@@ -78,4 +101,21 @@ export class MessagePortAdapter implements SocketAdapter
|
|
78
101
|
// _read()
|
79
102
|
// {
|
80
103
|
// }
|
104
|
+
|
105
|
+
|
106
|
+
hasListener<const TKey extends AllEventKeys<SocketAdapterAkalaEventMap>>(name: TKey)
|
107
|
+
{
|
108
|
+
if (name === 'open')
|
109
|
+
return false;
|
110
|
+
return !!this.cp.listenerCount(name);
|
111
|
+
}
|
112
|
+
get definedEvents(): AllEventKeys<SocketAdapterAkalaEventMap>[]
|
113
|
+
{
|
114
|
+
return (['close', 'error', 'message'] as const).filter(ev => this.hasListener(ev));
|
115
|
+
}
|
116
|
+
|
117
|
+
emit<const TEvent extends EventKeys<SocketAdapterAkalaEventMap>>(event: TEvent, ...args: EventArgs<SocketAdapterAkalaEventMap[TEvent]>): false | EventReturnType<SocketAdapterAkalaEventMap[TEvent]>
|
118
|
+
{
|
119
|
+
throw new Error("Method not implemented.");
|
120
|
+
}
|
81
121
|
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
import { Transform } from 'stream';
|
2
|
+
import { NewLinePrefixer } from './new-line-prefixer.js';
|
3
|
+
|
4
|
+
export class VirtualScrollPrefixer extends Transform
|
5
|
+
{
|
6
|
+
private buffer: string[] = [];
|
7
|
+
private readonly maxLines: number;
|
8
|
+
private readonly prefixer: NewLinePrefixer;
|
9
|
+
|
10
|
+
constructor(prefix: string, options: { maxLines?: number, useColors?: boolean } = {})
|
11
|
+
{
|
12
|
+
super();
|
13
|
+
this.maxLines = options.maxLines || 5;
|
14
|
+
this.prefixer = new NewLinePrefixer(prefix, { useColors: options.useColors });
|
15
|
+
}
|
16
|
+
|
17
|
+
_transform(chunk: Buffer | string, encoding: string, callback: () => void)
|
18
|
+
{
|
19
|
+
// Convert chunk to string if it's a buffer
|
20
|
+
const str = Buffer.isBuffer(chunk) ? chunk.toString() : chunk;
|
21
|
+
|
22
|
+
// Split the input into lines
|
23
|
+
const lines = str.split('\n');
|
24
|
+
|
25
|
+
// Process each line
|
26
|
+
lines.forEach((line, i) =>
|
27
|
+
{
|
28
|
+
if (line || i < lines.length - 1)
|
29
|
+
{ // Skip empty lines at the end
|
30
|
+
// Add the new line to the buffer
|
31
|
+
this.buffer.push(line);
|
32
|
+
|
33
|
+
// If buffer exceeds max lines, remove the oldest line
|
34
|
+
if (this.buffer.length > this.maxLines)
|
35
|
+
{
|
36
|
+
this.buffer.shift();
|
37
|
+
}
|
38
|
+
|
39
|
+
// Clear the terminal and rewrite all lines
|
40
|
+
this.push('\x1b[' + this.maxLines + 'A\x1b[0G\x1b[0J'); // Move cursor up and clear screen below
|
41
|
+
|
42
|
+
// Write each line in the buffer
|
43
|
+
this.buffer.forEach(bufferedLine =>
|
44
|
+
{
|
45
|
+
const prefixed = new Promise<string>((resolve) =>
|
46
|
+
{
|
47
|
+
this.prefixer._transform(bufferedLine, 'utf8', () =>
|
48
|
+
{
|
49
|
+
this.prefixer.once('data', (data) =>
|
50
|
+
{
|
51
|
+
resolve(data);
|
52
|
+
});
|
53
|
+
});
|
54
|
+
});
|
55
|
+
prefixed.then(data => this.push(data + '\n'));
|
56
|
+
});
|
57
|
+
}
|
58
|
+
});
|
59
|
+
|
60
|
+
callback();
|
61
|
+
}
|
62
|
+
|
63
|
+
_flush(callback: () => void)
|
64
|
+
{
|
65
|
+
callback();
|
66
|
+
}
|
67
|
+
}
|