@ac-kit/app-system 0.1.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.
Files changed (95) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +45 -0
  3. package/dist/async/file-lock.d.ts +38 -0
  4. package/dist/async/file-lock.d.ts.map +1 -0
  5. package/dist/async/file-lock.js +67 -0
  6. package/dist/async/file-lock.js.map +1 -0
  7. package/dist/async/udp-bind-lock.d.ts +75 -0
  8. package/dist/async/udp-bind-lock.d.ts.map +1 -0
  9. package/dist/async/udp-bind-lock.js +85 -0
  10. package/dist/async/udp-bind-lock.js.map +1 -0
  11. package/dist/fs/artifact-cache.d.ts +124 -0
  12. package/dist/fs/artifact-cache.d.ts.map +1 -0
  13. package/dist/fs/artifact-cache.js +183 -0
  14. package/dist/fs/artifact-cache.js.map +1 -0
  15. package/dist/fs/rotate-log-files.d.ts +20 -0
  16. package/dist/fs/rotate-log-files.d.ts.map +1 -0
  17. package/dist/fs/rotate-log-files.js +45 -0
  18. package/dist/fs/rotate-log-files.js.map +1 -0
  19. package/dist/fs/rotating-file-sink.d.ts +42 -0
  20. package/dist/fs/rotating-file-sink.d.ts.map +1 -0
  21. package/dist/fs/rotating-file-sink.js +213 -0
  22. package/dist/fs/rotating-file-sink.js.map +1 -0
  23. package/dist/index.d.ts +23 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +23 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/os/get-processes-snapshot.d.ts +56 -0
  28. package/dist/os/get-processes-snapshot.d.ts.map +1 -0
  29. package/dist/os/get-processes-snapshot.js +197 -0
  30. package/dist/os/get-processes-snapshot.js.map +1 -0
  31. package/dist/os/host-metrics.d.ts +43 -0
  32. package/dist/os/host-metrics.d.ts.map +1 -0
  33. package/dist/os/host-metrics.js +78 -0
  34. package/dist/os/host-metrics.js.map +1 -0
  35. package/dist/os/process-kill-by-pid-file.d.ts +35 -0
  36. package/dist/os/process-kill-by-pid-file.d.ts.map +1 -0
  37. package/dist/os/process-kill-by-pid-file.js +48 -0
  38. package/dist/os/process-kill-by-pid-file.js.map +1 -0
  39. package/dist/os/process-wait-pid.d.ts +18 -0
  40. package/dist/os/process-wait-pid.d.ts.map +1 -0
  41. package/dist/os/process-wait-pid.js +26 -0
  42. package/dist/os/process-wait-pid.js.map +1 -0
  43. package/dist/os/ps.d.ts +98 -0
  44. package/dist/os/ps.d.ts.map +1 -0
  45. package/dist/os/ps.js +165 -0
  46. package/dist/os/ps.js.map +1 -0
  47. package/dist/os/sysfs.d.ts +19 -0
  48. package/dist/os/sysfs.d.ts.map +1 -0
  49. package/dist/os/sysfs.js +66 -0
  50. package/dist/os/sysfs.js.map +1 -0
  51. package/dist/process/child-process-message-sink.d.ts +21 -0
  52. package/dist/process/child-process-message-sink.d.ts.map +1 -0
  53. package/dist/process/child-process-message-sink.js +16 -0
  54. package/dist/process/child-process-message-sink.js.map +1 -0
  55. package/dist/process/error-listeners.d.ts +56 -0
  56. package/dist/process/error-listeners.d.ts.map +1 -0
  57. package/dist/process/error-listeners.js +113 -0
  58. package/dist/process/error-listeners.js.map +1 -0
  59. package/dist/process/exit-manager.d.ts +58 -0
  60. package/dist/process/exit-manager.d.ts.map +1 -0
  61. package/dist/process/exit-manager.js +88 -0
  62. package/dist/process/exit-manager.js.map +1 -0
  63. package/dist/process/has-binary.d.ts +25 -0
  64. package/dist/process/has-binary.d.ts.map +1 -0
  65. package/dist/process/has-binary.js +35 -0
  66. package/dist/process/has-binary.js.map +1 -0
  67. package/dist/process/pid-file.d.ts +17 -0
  68. package/dist/process/pid-file.d.ts.map +1 -0
  69. package/dist/process/pid-file.js +25 -0
  70. package/dist/process/pid-file.js.map +1 -0
  71. package/dist/process/process-pid-file.d.ts +37 -0
  72. package/dist/process/process-pid-file.d.ts.map +1 -0
  73. package/dist/process/process-pid-file.js +57 -0
  74. package/dist/process/process-pid-file.js.map +1 -0
  75. package/dist/process/report-process.d.ts +36 -0
  76. package/dist/process/report-process.d.ts.map +1 -0
  77. package/dist/process/report-process.js +121 -0
  78. package/dist/process/report-process.js.map +1 -0
  79. package/dist/shell/shorten-posix-path.d.ts +10 -0
  80. package/dist/shell/shorten-posix-path.d.ts.map +1 -0
  81. package/dist/shell/shorten-posix-path.js +19 -0
  82. package/dist/shell/shorten-posix-path.js.map +1 -0
  83. package/dist/terminal/node-terminal.d.ts +11 -0
  84. package/dist/terminal/node-terminal.d.ts.map +1 -0
  85. package/dist/terminal/node-terminal.js +162 -0
  86. package/dist/terminal/node-terminal.js.map +1 -0
  87. package/dist/text/charset-decode-stream.d.ts +13 -0
  88. package/dist/text/charset-decode-stream.d.ts.map +1 -0
  89. package/dist/text/charset-decode-stream.js +51 -0
  90. package/dist/text/charset-decode-stream.js.map +1 -0
  91. package/dist/text/charset-encode-stream.d.ts +12 -0
  92. package/dist/text/charset-encode-stream.d.ts.map +1 -0
  93. package/dist/text/charset-encode-stream.js +47 -0
  94. package/dist/text/charset-encode-stream.js.map +1 -0
  95. package/package.json +75 -0
package/dist/os/ps.js ADDED
@@ -0,0 +1,165 @@
1
+ import { EOL } from "node:os";
2
+ import { MS_PER_DAY, MS_PER_HOUR, MS_PER_MINUTE, MS_PER_SECOND, defaults, } from "@ac-kit/core";
3
+ import { escapeCommandArg, execAsync, ProcessExitWithOutputError, } from "@ac-kit/node";
4
+ export const PS_DEFAULT_OPTIONS = {
5
+ selector: "all",
6
+ fields: null,
7
+ extraArgs: null,
8
+ execOptions: null,
9
+ };
10
+ const PS_RESULT_FIELDS = [
11
+ "args",
12
+ "comm",
13
+ "etime",
14
+ "group",
15
+ "nice",
16
+ "pcpu",
17
+ "pgid",
18
+ "pid",
19
+ "ppid",
20
+ "rgroup",
21
+ "ruser",
22
+ "time",
23
+ "tty",
24
+ "user",
25
+ "vsz",
26
+ ];
27
+ /**
28
+ * Get the list of running processes using the `ps` command.
29
+ *
30
+ * @param options Options for filtering and selecting fields.
31
+ * @returns A promise that resolves to an array of process information objects.
32
+ */
33
+ export async function ps(options) {
34
+ const effectiveOptions = defaults(options, PS_DEFAULT_OPTIONS);
35
+ const columns = !effectiveOptions.fields || effectiveOptions.fields.length === 0
36
+ ? PS_RESULT_FIELDS
37
+ : effectiveOptions.fields;
38
+ // Ensure args is the last column, so that splitting by whitespace works correctly
39
+ if (columns.includes("args")) {
40
+ columns.splice(columns.indexOf("args"), 1);
41
+ columns.push("args");
42
+ }
43
+ const commandArgs = [
44
+ "-ww",
45
+ ...buildPsSelectorArgs(effectiveOptions.selector ?? "all"),
46
+ "-o",
47
+ escapeCommandArg(columns.join(",")),
48
+ ];
49
+ let output;
50
+ try {
51
+ const result = await execAsync(`ps ${commandArgs.join(" ")}`, {
52
+ ...effectiveOptions.execOptions,
53
+ encoding: "utf-8",
54
+ env: {
55
+ ...effectiveOptions.execOptions?.env,
56
+ PS_PERSONALITY: "posix",
57
+ LANG: "C",
58
+ LC_ALL: "C",
59
+ },
60
+ });
61
+ output = result.stdout;
62
+ }
63
+ catch (error) {
64
+ // If `ps` fails with exit code 1 but produces output (header), return an empty list
65
+ if (error instanceof ProcessExitWithOutputError &&
66
+ error.code === 1 &&
67
+ error.stdout.length > 0) {
68
+ return [];
69
+ }
70
+ throw error;
71
+ }
72
+ const [_, ...rows] = output.trim().split(EOL);
73
+ return rows.map((row) => {
74
+ const rowColumns = row.trim().split(/\s+/);
75
+ if (rowColumns.length > columns.length) {
76
+ // The args column may contain spaces, so merge any extra cells into the last column
77
+ const args = rowColumns.slice(columns.length - 1).join(" ");
78
+ rowColumns.splice(columns.length - 1, rowColumns.length - columns.length + 1, args);
79
+ }
80
+ const entry = {};
81
+ for (let c = 0; c < rowColumns.length; c++) {
82
+ const field = columns[c];
83
+ if (!field) {
84
+ continue;
85
+ }
86
+ let value = rowColumns[c];
87
+ const intValue = parseInt(value, 10);
88
+ if (!Number.isNaN(intValue) && `${intValue}` === value) {
89
+ // Exact match, use integer value
90
+ value = intValue;
91
+ }
92
+ entry[field] = value;
93
+ }
94
+ return entry;
95
+ });
96
+ }
97
+ function buildPsFiltersArgs(filters) {
98
+ const args = [];
99
+ if (filters.group?.length) {
100
+ args.push("-G", ...filters.group.map((n) => escapeCommandArg(`${n}`)));
101
+ }
102
+ if (filters.pid?.length) {
103
+ args.push("-p", ...filters.pid.map((n) => escapeCommandArg(`${n}`)));
104
+ }
105
+ if (filters.tty?.length) {
106
+ args.push("-t", ...filters.tty.map(escapeCommandArg));
107
+ }
108
+ if (filters.user?.length) {
109
+ args.push("-U", ...filters.user.map((n) => escapeCommandArg(`${n}`)));
110
+ }
111
+ return args;
112
+ }
113
+ function buildPsSelectorArgs(selector) {
114
+ if (typeof selector === "string") {
115
+ if (selector === "all") {
116
+ // Select all processes (argument: -A)
117
+ return ["-A"];
118
+ }
119
+ // Select processes associated with a terminal (argument: -a)
120
+ return ["-a"];
121
+ }
122
+ const args = buildPsFiltersArgs(selector);
123
+ if (args.length === 0) {
124
+ // If no filters are specified, select all processes
125
+ return ["-A"];
126
+ }
127
+ return args;
128
+ }
129
+ /**
130
+ * Parse a duration string in the format [[[dd-]hh:]mm:]ss to milliseconds.
131
+ *
132
+ * @param duration Duration string in the format [[[dd-]hh:]mm:]ss
133
+ * @returns The duration in milliseconds.
134
+ */
135
+ export function psParseDuration(duration) {
136
+ const parts = duration.split("-");
137
+ let days = 0;
138
+ let timePart = duration;
139
+ if (parts.length === 2) {
140
+ days = +parts[0];
141
+ timePart = parts[1];
142
+ }
143
+ const timeParts = timePart.split(":").reverse();
144
+ if ((parts.length === 2 && timeParts.length !== 3) || timeParts.length > 3) {
145
+ throw new Error(`Invalid duration format: ${duration}`);
146
+ }
147
+ const seconds = timeParts[0].length === 2 ? +timeParts[0] : NaN;
148
+ let minutes = 0;
149
+ if (timeParts.length > 1) {
150
+ minutes = timeParts[1].length === 2 ? +timeParts[1] : NaN;
151
+ }
152
+ let hours = 0;
153
+ if (timeParts.length > 2) {
154
+ hours = timeParts[2].length === 2 ? +timeParts[2] : NaN;
155
+ }
156
+ const result = days * MS_PER_DAY +
157
+ hours * MS_PER_HOUR +
158
+ minutes * MS_PER_MINUTE +
159
+ seconds * MS_PER_SECOND;
160
+ if (Number.isNaN(result)) {
161
+ throw new Error(`Invalid duration format: ${duration}`);
162
+ }
163
+ return result;
164
+ }
165
+ //# sourceMappingURL=ps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ps.js","sourceRoot":"","sources":["../../src/os/ps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Raw readers over Linux's sysfs pseudo-filesystem. Every reader answers `null`
3
+ * rather than throwing when the node is absent or unreadable: sysfs layout
4
+ * varies with the kernel configuration, and an absent node is a normal outcome,
5
+ * not a failure. Nothing read here is privileged.
6
+ */
7
+ export declare const SYSFS_DEFAULT_ROOT = "/sys";
8
+ /**
9
+ * `scaling_cur_freq / cpuinfo_max_freq` for every core exposing both, in
10
+ * `/sys/devices/system/cpu/cpu*\/cpufreq`. Empty when `cpufreq` is not
11
+ * configured.
12
+ */
13
+ export declare function sysfsCpuFrequencyRatios(sysfsRoot?: string): Promise<number[]>;
14
+ /**
15
+ * Temperature of every readable zone in `/sys/class/thermal`, converted from
16
+ * the millidegrees Celsius the nodes report. Empty when no zone is exposed.
17
+ */
18
+ export declare function sysfsThermalZoneTemperaturesC(sysfsRoot?: string): Promise<number[]>;
19
+ //# sourceMappingURL=sysfs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sysfs.d.ts","sourceRoot":"","sources":["../../src/os/sysfs.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AAEH,eAAO,MAAM,kBAAkB,SAAS,CAAC;AAczC;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC5C,SAAS,SAAqB,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CAsBnB;AAED;;;GAGG;AACH,wBAAsB,6BAA6B,CAClD,SAAS,SAAqB,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CAgBnB"}
@@ -0,0 +1,66 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { walkPaths } from "@ac-kit/node";
4
+ /**
5
+ * Raw readers over Linux's sysfs pseudo-filesystem. Every reader answers `null`
6
+ * rather than throwing when the node is absent or unreadable: sysfs layout
7
+ * varies with the kernel configuration, and an absent node is a normal outcome,
8
+ * not a failure. Nothing read here is privileged.
9
+ */
10
+ export const SYSFS_DEFAULT_ROOT = "/sys";
11
+ const CPU_DIRECTORY = /^cpu\d+$/;
12
+ const THERMAL_ZONE_DIRECTORY = /^thermal_zone\d+$/;
13
+ async function readNumberNode(path) {
14
+ try {
15
+ const value = Number.parseFloat(await readFile(path, "utf8"));
16
+ return Number.isFinite(value) ? value : null;
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }
22
+ /**
23
+ * `scaling_cur_freq / cpuinfo_max_freq` for every core exposing both, in
24
+ * `/sys/devices/system/cpu/cpu*\/cpufreq`. Empty when `cpufreq` is not
25
+ * configured.
26
+ */
27
+ export async function sysfsCpuFrequencyRatios(sysfsRoot = SYSFS_DEFAULT_ROOT) {
28
+ const cpuRoot = join(sysfsRoot, "devices", "system", "cpu");
29
+ const ratios = [];
30
+ for await (const { path } of walkPaths({
31
+ root: cpuRoot,
32
+ include: CPU_DIRECTORY,
33
+ unreadable: "skip",
34
+ })) {
35
+ const cpufreq = join(cpuRoot, path, "cpufreq");
36
+ const [current, max] = await Promise.all([
37
+ readNumberNode(join(cpufreq, "scaling_cur_freq")),
38
+ readNumberNode(join(cpufreq, "cpuinfo_max_freq")),
39
+ ]);
40
+ if (current === null || max === null || max <= 0) {
41
+ continue;
42
+ }
43
+ ratios.push(current / max);
44
+ }
45
+ return ratios;
46
+ }
47
+ /**
48
+ * Temperature of every readable zone in `/sys/class/thermal`, converted from
49
+ * the millidegrees Celsius the nodes report. Empty when no zone is exposed.
50
+ */
51
+ export async function sysfsThermalZoneTemperaturesC(sysfsRoot = SYSFS_DEFAULT_ROOT) {
52
+ const thermalRoot = join(sysfsRoot, "class", "thermal");
53
+ const temperatures = [];
54
+ for await (const { path } of walkPaths({
55
+ root: thermalRoot,
56
+ include: THERMAL_ZONE_DIRECTORY,
57
+ unreadable: "skip",
58
+ })) {
59
+ const milliDegrees = await readNumberNode(join(thermalRoot, path, "temp"));
60
+ if (milliDegrees !== null) {
61
+ temperatures.push(milliDegrees / 1000);
62
+ }
63
+ }
64
+ return temperatures;
65
+ }
66
+ //# sourceMappingURL=sysfs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sysfs.js","sourceRoot":"","sources":["../../src/os/sysfs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAEzC,MAAM,aAAa,GAAG,UAAU,CAAC;AACjC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAEnD,KAAK,UAAU,cAAc,CAAC,IAAY;IACzC,IAAI,CAAC;QACJ,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QAC9D,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC5C,SAAS,GAAG,kBAAkB;IAE9B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;QACtC,IAAI,EAAE,OAAO;QACb,OAAO,EAAE,aAAa;QACtB,UAAU,EAAE,MAAM;KAClB,CAAC,EAAE,CAAC;QACJ,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;QAC/C,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACxC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;YACjD,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;SACjD,CAAC,CAAC;QAEH,IAAI,OAAO,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;YAClD,SAAS;QACV,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B,CAClD,SAAS,GAAG,kBAAkB;IAE9B,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACxD,MAAM,YAAY,GAAa,EAAE,CAAC;IAElC,IAAI,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;QACtC,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,sBAAsB;QAC/B,UAAU,EAAE,MAAM;KAClB,CAAC,EAAE,CAAC;QACJ,MAAM,YAAY,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QAC3E,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;YAC3B,YAAY,CAAC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;QACxC,CAAC;IACF,CAAC;IAED,OAAO,YAAY,CAAC;AACrB,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { ISink, SerializeReportEventOptions } from "@ac-kit/app-report";
2
+ export type ChildProcessMessageSinkOptions = {
3
+ readonly serialize?: SerializeReportEventOptions;
4
+ /**
5
+ * Called when the IPC channel refuses a message (typically because it has
6
+ * closed). Without it a delivery failure is silent, which for a measurement
7
+ * stream is data loss with no signal.
8
+ */
9
+ readonly onSendError?: (error: unknown) => void;
10
+ };
11
+ /** The subset of `process`/`ChildProcess` a message sink needs. */
12
+ export type MessageTarget = {
13
+ send?: (message: unknown, callback: (error: unknown) => void) => boolean;
14
+ };
15
+ /**
16
+ * Binds a Node IPC channel to `@ac-kit/app-report`'s portable
17
+ * `createMessageSink`: pass `process` in a forked child, or the child handle in
18
+ * the parent.
19
+ */
20
+ export declare function createChildProcessMessageSink<TData>(target: MessageTarget, options?: ChildProcessMessageSinkOptions): ISink<TData>;
21
+ //# sourceMappingURL=child-process-message-sink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"child-process-message-sink.d.ts","sourceRoot":"","sources":["../../src/process/child-process-message-sink.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AAG7E,MAAM,MAAM,8BAA8B,GAAG;IAC5C,QAAQ,CAAC,SAAS,CAAC,EAAE,2BAA2B,CAAC;IACjD;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,mEAAmE;AACnE,MAAM,MAAM,aAAa,GAAG;IAC3B,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,KAAK,OAAO,CAAC;CACzE,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAClD,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,8BAA8B,GACtC,KAAK,CAAC,KAAK,CAAC,CAWd"}
@@ -0,0 +1,16 @@
1
+ import { createMessageSink } from "@ac-kit/app-report";
2
+ /**
3
+ * Binds a Node IPC channel to `@ac-kit/app-report`'s portable
4
+ * `createMessageSink`: pass `process` in a forked child, or the child handle in
5
+ * the parent.
6
+ */
7
+ export function createChildProcessMessageSink(target, options) {
8
+ return createMessageSink((message) => {
9
+ target.send?.(message, (error) => {
10
+ if (error) {
11
+ options?.onSendError?.(error);
12
+ }
13
+ });
14
+ }, { serialize: options?.serialize });
15
+ }
16
+ //# sourceMappingURL=child-process-message-sink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"child-process-message-sink.js","sourceRoot":"","sources":["../../src/process/child-process-message-sink.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAiBvD;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CAC5C,MAAqB,EACrB,OAAwC;IAExC,OAAO,iBAAiB,CACvB,CAAC,OAAO,EAAE,EAAE;QACX,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YAChC,IAAI,KAAK,EAAE,CAAC;gBACX,OAAO,EAAE,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC,EACD,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,CACjC,CAAC;AACH,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The origin of an uncaught exception. Matches Node.js process
3
+ * 'uncaughtException' event callback.
4
+ */
5
+ export type UncaughtExceptionOrigin = "uncaughtException" | "unhandledRejection";
6
+ export declare class UnhandledRejectionError extends Error {
7
+ readonly promise: Promise<unknown> | null;
8
+ constructor(reason: unknown, promise?: Promise<unknown> | null);
9
+ }
10
+ export declare class UncaughtExceptionError extends Error {
11
+ constructor(error: Error);
12
+ }
13
+ export type ErrorListenersOptions = {
14
+ silent?: boolean;
15
+ onError?: ((error: UnhandledRejectionError | UncaughtExceptionError) => void) | null;
16
+ };
17
+ /**
18
+ * A utility class that listens for unhandled promise rejections and uncaught
19
+ * exceptions, logs them to a specified file, or if that fails, to stderr.
20
+ */
21
+ export declare class ErrorListeners {
22
+ private readonly filePath;
23
+ private readonly options;
24
+ private detacher;
25
+ /**
26
+ * Creates a new instance of LoggerErrorListeners.
27
+ *
28
+ * @param filePath The path to the file where errors will be logged.
29
+ * @param options The options for the LoggerErrorListeners.
30
+ */
31
+ constructor(filePath: string, options?: ErrorListenersOptions);
32
+ /**
33
+ * Checks if the listeners are currently attached.
34
+ *
35
+ * @returns True if the listeners are currently attached, false otherwise.
36
+ */
37
+ isAttached(): boolean;
38
+ /**
39
+ * Attaches the listeners for unhandled promise rejections and uncaught
40
+ * exceptions.
41
+ *
42
+ * If the listeners are already attached, this method does nothing.
43
+ */
44
+ attach(): void;
45
+ /**
46
+ * Detaches the listeners for unhandled promise rejections and uncaught
47
+ * exceptions.
48
+ *
49
+ * If the listeners are not attached, this method does nothing.
50
+ */
51
+ detach(): void;
52
+ private handleError;
53
+ private handleUnhandledRejection;
54
+ private handleUncaughtException;
55
+ }
56
+ //# sourceMappingURL=error-listeners.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-listeners.d.ts","sourceRoot":"","sources":["../../src/process/error-listeners.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAChC,mBAAmB,GACnB,oBAAoB,CAAC;AAExB,qBAAa,uBAAwB,SAAQ,KAAK;IAGhD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI;IAF1C,YACC,MAAM,EAAE,OAAO,EACN,OAAO,GAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAW,EAKhD;CACD;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IAChD,YAAY,KAAK,EAAE,KAAK,EAMvB;CACD;AAED,MAAM,MAAM,qBAAqB,GAAG;IACnC,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,OAAO,CAAC,EACL,CAAC,CAAC,KAAK,EAAE,uBAAuB,GAAG,sBAAsB,KAAK,IAAI,CAAC,GACnE,IAAI,CAAC;CACR,CAAC;AAOF;;;GAGG;AACH,qBAAa,cAAc;IAWzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAV1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;IAC1D,OAAO,CAAC,QAAQ,CAAyB;IAEzC;;;;;OAKG;IACH,YACkB,QAAQ,EAAE,MAAM,EACjC,OAAO,CAAC,EAAE,qBAAqB,EAG/B;IAED;;;;OAIG;IACH,UAAU,IAAI,OAAO,CAEpB;IAED;;;;;OAKG;IACH,MAAM,IAAI,IAAI,CAeb;IAED;;;;;OAKG;IACH,MAAM,IAAI,IAAI,CAGb;IAED,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,wBAAwB;IAUhC,OAAO,CAAC,uBAAuB;CAiB/B"}
@@ -0,0 +1,113 @@
1
+ import { writeFileSync } from "node:fs";
2
+ import { EOL } from "node:os";
3
+ import { defaults, formatError } from "@ac-kit/core";
4
+ export class UnhandledRejectionError extends Error {
5
+ promise;
6
+ constructor(reason, promise = null) {
7
+ super("Unhandled rejection", { cause: reason });
8
+ this.promise = promise;
9
+ this.name = "UnhandledRejectionError";
10
+ }
11
+ }
12
+ export class UncaughtExceptionError extends Error {
13
+ constructor(error) {
14
+ super("Uncaught exception", {
15
+ cause: error,
16
+ });
17
+ this.name = "UncaughtExceptionError";
18
+ }
19
+ }
20
+ const ERROR_LISTENERS_DEFAULT_OPTIONS = {
21
+ silent: false,
22
+ onError: null,
23
+ };
24
+ /**
25
+ * A utility class that listens for unhandled promise rejections and uncaught
26
+ * exceptions, logs them to a specified file, or if that fails, to stderr.
27
+ */
28
+ export class ErrorListeners {
29
+ filePath;
30
+ options;
31
+ detacher = null;
32
+ /**
33
+ * Creates a new instance of LoggerErrorListeners.
34
+ *
35
+ * @param filePath The path to the file where errors will be logged.
36
+ * @param options The options for the LoggerErrorListeners.
37
+ */
38
+ constructor(filePath, options) {
39
+ this.filePath = filePath;
40
+ this.options = defaults(options, ERROR_LISTENERS_DEFAULT_OPTIONS);
41
+ }
42
+ /**
43
+ * Checks if the listeners are currently attached.
44
+ *
45
+ * @returns True if the listeners are currently attached, false otherwise.
46
+ */
47
+ isAttached() {
48
+ return this.detacher !== null;
49
+ }
50
+ /**
51
+ * Attaches the listeners for unhandled promise rejections and uncaught
52
+ * exceptions.
53
+ *
54
+ * If the listeners are already attached, this method does nothing.
55
+ */
56
+ attach() {
57
+ if (this.isAttached()) {
58
+ return;
59
+ }
60
+ const unhandledRejectionHandler = this.handleUnhandledRejection.bind(this);
61
+ const uncaughtExceptionHandler = this.handleUncaughtException.bind(this);
62
+ process.on("unhandledRejection", unhandledRejectionHandler);
63
+ process.on("uncaughtException", uncaughtExceptionHandler);
64
+ this.detacher = () => {
65
+ process.removeListener("unhandledRejection", unhandledRejectionHandler);
66
+ process.removeListener("uncaughtException", uncaughtExceptionHandler);
67
+ };
68
+ }
69
+ /**
70
+ * Detaches the listeners for unhandled promise rejections and uncaught
71
+ * exceptions.
72
+ *
73
+ * If the listeners are not attached, this method does nothing.
74
+ */
75
+ detach() {
76
+ this.detacher?.();
77
+ this.detacher = null;
78
+ }
79
+ handleError(error) {
80
+ const message = `[${new Date().toISOString()}] ${formatError(error, { stackTrace: true })}${EOL}`;
81
+ try {
82
+ writeFileSync(this.filePath, message, { flag: "a" });
83
+ }
84
+ catch {
85
+ if (!this.options.silent) {
86
+ process.stderr.write(message);
87
+ }
88
+ }
89
+ }
90
+ handleUnhandledRejection(reason, promise) {
91
+ try {
92
+ const wrappedError = new UnhandledRejectionError(reason, promise);
93
+ this.handleError(wrappedError);
94
+ this.options.onError?.(wrappedError);
95
+ }
96
+ catch { }
97
+ }
98
+ handleUncaughtException(error, origin) {
99
+ try {
100
+ let wrappedError;
101
+ if (origin === "unhandledRejection") {
102
+ wrappedError = new UnhandledRejectionError(error);
103
+ }
104
+ else {
105
+ wrappedError = new UncaughtExceptionError(error);
106
+ }
107
+ this.handleError(wrappedError);
108
+ this.options.onError?.(wrappedError);
109
+ }
110
+ catch { }
111
+ }
112
+ }
113
+ //# sourceMappingURL=error-listeners.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-listeners.js","sourceRoot":"","sources":["../../src/process/error-listeners.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { type Callable, type MaybeAsyncCallable } from "@ac-kit/core";
2
+ export declare enum ExitManagerPriority {
3
+ VERY_EARLY = 300,
4
+ EARLY = 200,
5
+ VERY_HIGH = 100,
6
+ HIGH = 50,
7
+ NORMAL = 0,
8
+ LOW = -50,
9
+ VERY_LOW = -100,
10
+ LATE = -200,
11
+ VERY_LATE = -300
12
+ }
13
+ export declare class ExitManager {
14
+ private static instance;
15
+ static getInstance(): ExitManager;
16
+ private exitHandlers;
17
+ private cleanUpHandlers;
18
+ private constructor();
19
+ /**
20
+ * Register a possibly asynchronous clean-up handler to be called when the
21
+ * process is exiting.
22
+ *
23
+ * Note: The handler can be an asynchronous function. The process will wait
24
+ * for the promise to resolve before exiting.
25
+ *
26
+ * @param handler A function to be called on process exit.
27
+ * @param priority The priority of the clean-up handler.
28
+ */
29
+ registerCleanUpHandler(handler: MaybeAsyncCallable, priority?: ExitManagerPriority): Callable;
30
+ /**
31
+ * Unregister a previously registered clean-up handler.
32
+ *
33
+ * @param handler A function to be removed from the clean-up handlers.
34
+ * @param priority The priority of the clean-up handler. (optional, for
35
+ * disambiguation)
36
+ */
37
+ unregisterCleanUpHandler(handler: MaybeAsyncCallable, priority?: ExitManagerPriority): void;
38
+ /**
39
+ * Registers a synchronous exit handler to be called when the process is
40
+ * exiting.
41
+ *
42
+ * Note: The handler should be a synchronous function. Asynchronous operations
43
+ * may not complete before the process exits.
44
+ *
45
+ * @param handler A synchronous function to be called on process exit.
46
+ * @param priority The priority of the exit handler.
47
+ */
48
+ registerExitHandler(handler: Callable, priority?: ExitManagerPriority): Callable;
49
+ /**
50
+ * Unregister a previously registered exit handler.
51
+ *
52
+ * @param handler A function to be removed from the exit handlers.
53
+ * @param priority The priority of the exit handler. (optional, for
54
+ * disambiguation)
55
+ */
56
+ unregisterExitHandler(handler: Callable, priority?: ExitManagerPriority): void;
57
+ }
58
+ //# sourceMappingURL=exit-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-manager.d.ts","sourceRoot":"","sources":["../../src/process/exit-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,MAAM,cAAc,CAAC;AAGtB,oBAAY,mBAAmB;IAC9B,UAAU,MAAM;IAChB,KAAK,MAAM;IACX,SAAS,MAAM;IACf,IAAI,KAAK;IACT,MAAM,IAAI;IACV,GAAG,MAAM;IACT,QAAQ,OAAO;IACf,IAAI,OAAO;IACX,SAAS,OAAO;CAChB;AAED,qBAAa,WAAW;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA4B;IACnD,MAAM,CAAC,WAAW,IAAI,WAAW,CAKhC;IAED,OAAO,CAAC,YAAY,CAAiC;IACrD,OAAO,CAAC,eAAe,CAA2C;IAElE,OAAO,eAcN;IAED;;;;;;;;;OASG;IACH,sBAAsB,CACrB,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,GAAE,mBAAuB,GAC/B,QAAQ,CAIV;IAED;;;;;;OAMG;IACH,wBAAwB,CACvB,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,CAAC,EAAE,mBAAmB,GAC5B,IAAI,CAIN;IAED;;;;;;;;;OASG;IACH,mBAAmB,CAClB,OAAO,EAAE,QAAQ,EACjB,QAAQ,GAAE,mBAAgD,GACxD,QAAQ,CAIV;IAED;;;;;;OAMG;IACH,qBAAqB,CACpB,OAAO,EAAE,QAAQ,EACjB,QAAQ,CAAC,EAAE,mBAAmB,GAC5B,IAAI,CAIN;CACD"}
@@ -0,0 +1,88 @@
1
+ import { catchOutOfBand, catchOutOfBandAsync, } from "@ac-kit/core";
2
+ import { PriorityQueue } from "@ac-kit/data";
3
+ export var ExitManagerPriority;
4
+ (function (ExitManagerPriority) {
5
+ ExitManagerPriority[ExitManagerPriority["VERY_EARLY"] = 300] = "VERY_EARLY";
6
+ ExitManagerPriority[ExitManagerPriority["EARLY"] = 200] = "EARLY";
7
+ ExitManagerPriority[ExitManagerPriority["VERY_HIGH"] = 100] = "VERY_HIGH";
8
+ ExitManagerPriority[ExitManagerPriority["HIGH"] = 50] = "HIGH";
9
+ ExitManagerPriority[ExitManagerPriority["NORMAL"] = 0] = "NORMAL";
10
+ ExitManagerPriority[ExitManagerPriority["LOW"] = -50] = "LOW";
11
+ ExitManagerPriority[ExitManagerPriority["VERY_LOW"] = -100] = "VERY_LOW";
12
+ ExitManagerPriority[ExitManagerPriority["LATE"] = -200] = "LATE";
13
+ ExitManagerPriority[ExitManagerPriority["VERY_LATE"] = -300] = "VERY_LATE";
14
+ })(ExitManagerPriority || (ExitManagerPriority = {}));
15
+ export class ExitManager {
16
+ static instance = null;
17
+ static getInstance() {
18
+ if (!ExitManager.instance) {
19
+ ExitManager.instance = new ExitManager();
20
+ }
21
+ return ExitManager.instance;
22
+ }
23
+ exitHandlers = new PriorityQueue();
24
+ cleanUpHandlers = new PriorityQueue();
25
+ constructor() {
26
+ process.on("beforeExit", async () => {
27
+ let handler;
28
+ while ((handler = this.cleanUpHandlers.extract()) !== undefined) {
29
+ await catchOutOfBandAsync(handler);
30
+ }
31
+ });
32
+ process.on("exit", () => {
33
+ let handler;
34
+ while ((handler = this.exitHandlers.extract()) !== undefined) {
35
+ catchOutOfBand(handler);
36
+ }
37
+ });
38
+ }
39
+ /**
40
+ * Register a possibly asynchronous clean-up handler to be called when the
41
+ * process is exiting.
42
+ *
43
+ * Note: The handler can be an asynchronous function. The process will wait
44
+ * for the promise to resolve before exiting.
45
+ *
46
+ * @param handler A function to be called on process exit.
47
+ * @param priority The priority of the clean-up handler.
48
+ */
49
+ registerCleanUpHandler(handler, priority = 0) {
50
+ this.cleanUpHandlers.insert(priority, handler);
51
+ return () => this.unregisterCleanUpHandler(handler);
52
+ }
53
+ /**
54
+ * Unregister a previously registered clean-up handler.
55
+ *
56
+ * @param handler A function to be removed from the clean-up handlers.
57
+ * @param priority The priority of the clean-up handler. (optional, for
58
+ * disambiguation)
59
+ */
60
+ unregisterCleanUpHandler(handler, priority) {
61
+ this.cleanUpHandlers.remove((f, p) => f === handler && (priority === undefined || p === priority));
62
+ }
63
+ /**
64
+ * Registers a synchronous exit handler to be called when the process is
65
+ * exiting.
66
+ *
67
+ * Note: The handler should be a synchronous function. Asynchronous operations
68
+ * may not complete before the process exits.
69
+ *
70
+ * @param handler A synchronous function to be called on process exit.
71
+ * @param priority The priority of the exit handler.
72
+ */
73
+ registerExitHandler(handler, priority = ExitManagerPriority.NORMAL) {
74
+ this.exitHandlers.insert(priority, handler);
75
+ return () => this.unregisterExitHandler(handler);
76
+ }
77
+ /**
78
+ * Unregister a previously registered exit handler.
79
+ *
80
+ * @param handler A function to be removed from the exit handlers.
81
+ * @param priority The priority of the exit handler. (optional, for
82
+ * disambiguation)
83
+ */
84
+ unregisterExitHandler(handler, priority) {
85
+ this.exitHandlers.remove((f, p) => f === handler && (priority === undefined || p === priority));
86
+ }
87
+ }
88
+ //# sourceMappingURL=exit-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-manager.js","sourceRoot":"","sources":["../../src/process/exit-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,cAAc,EACd,mBAAmB,GAGnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAN,IAAY,mBAUX;AAVD,WAAY,mBAAmB;IAC9B,2EAAgB,CAAA;IAChB,iEAAW,CAAA;IACX,yEAAe,CAAA;IACf,8DAAS,CAAA;IACT,iEAAU,CAAA;IACV,6DAAS,CAAA;IACT,wEAAe,CAAA;IACf,gEAAW,CAAA;IACX,0EAAgB,CAAA;AACjB,CAAC,EAVW,mBAAmB,KAAnB,mBAAmB,QAU9B;AAED,MAAM,OAAO,WAAW;IACf,MAAM,CAAC,QAAQ,GAAuB,IAAI,CAAC;IACnD,MAAM,CAAC,WAAW;QACjB,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;YAC3B,WAAW,CAAC,QAAQ,GAAG,IAAI,WAAW,EAAE,CAAC;QAC1C,CAAC;QACD,OAAO,WAAW,CAAC,QAAQ,CAAC;IAC7B,CAAC;IAEO,YAAY,GAAG,IAAI,aAAa,EAAY,CAAC;IAC7C,eAAe,GAAG,IAAI,aAAa,EAAsB,CAAC;IAElE;QACC,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;YACnC,IAAI,OAAuC,CAAC;YAC5C,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,KAAK,SAAS,EAAE,CAAC;gBACjE,MAAM,mBAAmB,CAAC,OAAO,CAAC,CAAC;YACpC,CAAC;QACF,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;YACvB,IAAI,OAA6B,CAAC;YAClC,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,KAAK,SAAS,EAAE,CAAC;gBAC9D,cAAc,CAAC,OAAO,CAAC,CAAC;YACzB,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,sBAAsB,CACrB,OAA2B,EAC3B,QAAQ,GAAwB,CAAC;QAEjC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAE/C,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC;IACrD,CAAC;IAED;;;;;;OAMG;IACH,wBAAwB,CACvB,OAA2B,EAC3B,QAA8B;QAE9B,IAAI,CAAC,eAAe,CAAC,MAAM,CAC1B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,OAAO,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,KAAK,QAAQ,CAAC,CACrE,CAAC;IACH,CAAC;IAED;;;;;;;;;OASG;IACH,mBAAmB,CAClB,OAAiB,EACjB,QAAQ,GAAwB,mBAAmB,CAAC,MAAM;QAE1D,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAE5C,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;IAED;;;;;;OAMG;IACH,qBAAqB,CACpB,OAAiB,EACjB,QAA8B;QAE9B,IAAI,CAAC,YAAY,CAAC,MAAM,CACvB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,OAAO,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,KAAK,QAAQ,CAAC,CACrE,CAAC;IACH,CAAC;CACD"}