@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/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.2.9",
7
+ "version": "15.3.0",
8
8
  "scripts": {
9
9
  "test": "echo 1",
10
- "generate": "ac generate dist/esm/commands commands.json --name pm && ac generate dist/esm/cli-commands cli-commands.json --name pm",
11
- "generate-metadata": "ac generate-metadata commands.json src/container.ts && ac generate-metadata cli-commands.json src/cli-container.ts",
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.9.3",
33
- "@akala/commands": "^16.0.0",
34
- "@akala/config": "^6.0.74",
35
- "@akala/core": "^39.4.0",
36
- "@akala/json-rpc-ws": "^11.0.82",
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
  },
@@ -1,13 +1,13 @@
1
1
  import { ChildProcess } from "child_process";
2
2
  import * as jsonrpc from '@akala/json-rpc-ws';
3
- import { SocketAdapterEventMap } from "@akala/json-rpc-ws";
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<unknown>)
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
- off<K extends keyof SocketAdapterEventMap>(event: K, handler: (ev: SocketAdapterEventMap[K]) => void): void
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
- on<K extends keyof SocketAdapterEventMap>(event: K, handler: (ev: SocketAdapterEventMap[K]) => void): void
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
- this.cp.on('message', handler);
49
- break;
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
- this.cp.on('disconnect', handler);
55
- break;
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<K extends keyof SocketAdapterEventMap>(event: K, handler: (ev: SocketAdapterEventMap[K]) => void): void
75
+ public once<const TEvent extends AllEventKeys<jsonrpc.SocketAdapterAkalaEventMap>>(
76
+ event: TEvent,
77
+ handler: EventListener<AllEvents<jsonrpc.SocketAdapterAkalaEventMap>[TEvent]>,
78
+ ): Subscription
60
79
  {
61
- switch (event)
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 { SocketAdapter, SocketAdapterEventMap } from "@akala/json-rpc-ws";
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
- on<K extends keyof SocketAdapterEventMap>(event: K, handler: (ev: SocketAdapterEventMap[K]) => void): void
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
- this.cp.on('message', handler);
26
- break;
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
- this.cp.on('disconnect', handler);
32
- break;
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<K extends keyof SocketAdapterEventMap>(event: K, handler: (ev: SocketAdapterEventMap[K]) => void): void
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.once('message', handler);
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.once('close', () => handler(null));
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<unknown>)
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
+ }