@milaboratories/pl-deployments 2.15.16 → 2.15.18

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 (104) hide show
  1. package/dist/_virtual/_rolldown/runtime.cjs +29 -0
  2. package/dist/common/os_and_arch.cjs +22 -28
  3. package/dist/common/os_and_arch.cjs.map +1 -1
  4. package/dist/common/os_and_arch.js +23 -26
  5. package/dist/common/os_and_arch.js.map +1 -1
  6. package/dist/common/pl_binary.cjs +35 -33
  7. package/dist/common/pl_binary.cjs.map +1 -1
  8. package/dist/common/pl_binary.d.ts +13 -18
  9. package/dist/common/pl_binary.js +33 -31
  10. package/dist/common/pl_binary.js.map +1 -1
  11. package/dist/common/pl_binary_download.cjs +143 -155
  12. package/dist/common/pl_binary_download.cjs.map +1 -1
  13. package/dist/common/pl_binary_download.d.ts +15 -48
  14. package/dist/common/pl_binary_download.js +138 -133
  15. package/dist/common/pl_binary_download.js.map +1 -1
  16. package/dist/common/pl_version.cjs +5 -6
  17. package/dist/common/pl_version.cjs.map +1 -1
  18. package/dist/common/pl_version.d.ts +4 -1
  19. package/dist/common/pl_version.js +5 -4
  20. package/dist/common/pl_version.js.map +1 -1
  21. package/dist/index.cjs +21 -25
  22. package/dist/index.d.ts +6 -6
  23. package/dist/index.js +7 -6
  24. package/dist/local/pid.cjs +14 -13
  25. package/dist/local/pid.cjs.map +1 -1
  26. package/dist/local/pid.js +11 -11
  27. package/dist/local/pid.js.map +1 -1
  28. package/dist/local/pl.cjs +194 -223
  29. package/dist/local/pl.cjs.map +1 -1
  30. package/dist/local/pl.d.ts +65 -65
  31. package/dist/local/pl.js +190 -202
  32. package/dist/local/pl.js.map +1 -1
  33. package/dist/local/process.cjs +37 -59
  34. package/dist/local/process.cjs.map +1 -1
  35. package/dist/local/process.d.ts +10 -10
  36. package/dist/local/process.js +36 -57
  37. package/dist/local/process.js.map +1 -1
  38. package/dist/local/trace.cjs +14 -17
  39. package/dist/local/trace.cjs.map +1 -1
  40. package/dist/local/trace.d.ts +6 -7
  41. package/dist/local/trace.js +15 -15
  42. package/dist/local/trace.js.map +1 -1
  43. package/dist/package.cjs +12 -0
  44. package/dist/package.cjs.map +1 -0
  45. package/dist/package.js +6 -0
  46. package/dist/package.js.map +1 -0
  47. package/dist/ssh/connection_info.cjs +36 -53
  48. package/dist/ssh/connection_info.cjs.map +1 -1
  49. package/dist/ssh/connection_info.d.ts +691 -713
  50. package/dist/ssh/connection_info.js +35 -51
  51. package/dist/ssh/connection_info.js.map +1 -1
  52. package/dist/ssh/pl.cjs +551 -638
  53. package/dist/ssh/pl.cjs.map +1 -1
  54. package/dist/ssh/pl.d.ts +120 -117
  55. package/dist/ssh/pl.js +548 -636
  56. package/dist/ssh/pl.js.map +1 -1
  57. package/dist/ssh/pl_paths.cjs +22 -24
  58. package/dist/ssh/pl_paths.cjs.map +1 -1
  59. package/dist/ssh/pl_paths.js +21 -19
  60. package/dist/ssh/pl_paths.js.map +1 -1
  61. package/dist/ssh/ssh.cjs +554 -618
  62. package/dist/ssh/ssh.cjs.map +1 -1
  63. package/dist/ssh/ssh.d.ts +139 -136
  64. package/dist/ssh/ssh.js +548 -616
  65. package/dist/ssh/ssh.js.map +1 -1
  66. package/dist/ssh/ssh_errors.cjs +45 -60
  67. package/dist/ssh/ssh_errors.cjs.map +1 -1
  68. package/dist/ssh/ssh_errors.js +45 -58
  69. package/dist/ssh/ssh_errors.js.map +1 -1
  70. package/dist/ssh/supervisord.cjs +50 -68
  71. package/dist/ssh/supervisord.cjs.map +1 -1
  72. package/dist/ssh/supervisord.d.ts +11 -21
  73. package/dist/ssh/supervisord.js +50 -66
  74. package/dist/ssh/supervisord.js.map +1 -1
  75. package/package.json +11 -11
  76. package/dist/common/os_and_arch.d.ts +0 -9
  77. package/dist/common/os_and_arch.d.ts.map +0 -1
  78. package/dist/common/pl_binary.d.ts.map +0 -1
  79. package/dist/common/pl_binary_download.d.ts.map +0 -1
  80. package/dist/common/pl_version.d.ts.map +0 -1
  81. package/dist/index.cjs.map +0 -1
  82. package/dist/index.d.ts.map +0 -1
  83. package/dist/index.js.map +0 -1
  84. package/dist/local/options.d.ts +0 -31
  85. package/dist/local/options.d.ts.map +0 -1
  86. package/dist/local/pid.d.ts +0 -4
  87. package/dist/local/pid.d.ts.map +0 -1
  88. package/dist/local/pl.d.ts.map +0 -1
  89. package/dist/local/process.d.ts.map +0 -1
  90. package/dist/local/trace.d.ts.map +0 -1
  91. package/dist/package.json.cjs +0 -8
  92. package/dist/package.json.cjs.map +0 -1
  93. package/dist/package.json.js +0 -6
  94. package/dist/package.json.js.map +0 -1
  95. package/dist/ssh/__tests__/common-utils.d.ts +0 -12
  96. package/dist/ssh/__tests__/common-utils.d.ts.map +0 -1
  97. package/dist/ssh/connection_info.d.ts.map +0 -1
  98. package/dist/ssh/pl.d.ts.map +0 -1
  99. package/dist/ssh/pl_paths.d.ts +0 -20
  100. package/dist/ssh/pl_paths.d.ts.map +0 -1
  101. package/dist/ssh/ssh.d.ts.map +0 -1
  102. package/dist/ssh/ssh_errors.d.ts +0 -29
  103. package/dist/ssh/ssh_errors.d.ts.map +0 -1
  104. package/dist/ssh/supervisord.d.ts.map +0 -1
package/dist/local/pl.cjs CHANGED
@@ -1,246 +1,217 @@
1
- 'use strict';
2
-
3
- var process$1 = require('./process.cjs');
4
- var pl_binary = require('../common/pl_binary.cjs');
5
- var tsHelpers = require('@milaboratories/ts-helpers');
6
- var pid = require('./pid.cjs');
7
- var trace = require('./trace.cjs');
8
- var upath = require('upath');
9
- var fsp = require('node:fs/promises');
10
- var os = require('node:os');
11
- var plHttp = require('@milaboratories/pl-http');
12
- var plModelCommon = require('@milaboratories/pl-model-common');
13
-
14
- function _interopNamespaceDefault(e) {
15
- var n = Object.create(null);
16
- if (e) {
17
- Object.keys(e).forEach(function (k) {
18
- if (k !== 'default') {
19
- var d = Object.getOwnPropertyDescriptor(e, k);
20
- Object.defineProperty(n, k, d.get ? d : {
21
- enumerable: true,
22
- get: function () { return e[k]; }
23
- });
24
- }
25
- });
26
- }
27
- n.default = e;
28
- return Object.freeze(n);
29
- }
30
-
31
- var os__namespace = /*#__PURE__*/_interopNamespaceDefault(os);
1
+ const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
2
+ const require_process = require('./process.cjs');
3
+ const require_pl_binary = require('../common/pl_binary.cjs');
4
+ const require_pid = require('./pid.cjs');
5
+ const require_trace = require('./trace.cjs');
6
+ let _milaboratories_ts_helpers = require("@milaboratories/ts-helpers");
7
+ let node_fs_promises = require("node:fs/promises");
8
+ node_fs_promises = require_runtime.__toESM(node_fs_promises);
9
+ let upath = require("upath");
10
+ upath = require_runtime.__toESM(upath);
11
+ let node_os = require("node:os");
12
+ node_os = require_runtime.__toESM(node_os);
13
+ let _milaboratories_pl_http = require("@milaboratories/pl-http");
14
+ let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
32
15
 
16
+ //#region src/local/pl.ts
33
17
  const LocalConfigYaml = "config-local.yaml";
34
18
  /**
35
- * Represents a local running pl-core,
36
- * and has methods to start, check if it's running, stop and wait for stopping it.
37
- * Also, a hook on pl-core closed can be provided.
38
- */
39
- class LocalPl {
40
- logger;
41
- workingDir;
42
- startOptions;
43
- initialStartHistory;
44
- onClose;
45
- onError;
46
- onCloseAndError;
47
- onCloseAndErrorNoStop;
48
- instance;
49
- pid;
50
- nRuns = 0;
51
- lastRunHistory = {};
52
- wasStopped = false;
53
- constructor(logger, workingDir, startOptions, initialStartHistory, onClose, onError, onCloseAndError, onCloseAndErrorNoStop) {
54
- this.logger = logger;
55
- this.workingDir = workingDir;
56
- this.startOptions = startOptions;
57
- this.initialStartHistory = initialStartHistory;
58
- this.onClose = onClose;
59
- this.onError = onError;
60
- this.onCloseAndError = onCloseAndError;
61
- this.onCloseAndErrorNoStop = onCloseAndErrorNoStop;
62
- }
63
- async start() {
64
- await trace.withTrace(this.logger, async (trace, t) => {
65
- this.wasStopped = false;
66
- const instance = process$1.processRun(this.logger, this.startOptions);
67
- instance.on("error", (e) => {
68
- this.logger.error(`error '${e}', while running platforma, started opts: ${JSON.stringify(this.debugInfo())}`);
69
- // keep in mind there are no awaits here, it will be asynchronous
70
- if (this.onError !== undefined)
71
- void this.onError(this);
72
- if (this.onCloseAndError !== undefined)
73
- void this.onCloseAndError(this);
74
- if (this.onCloseAndErrorNoStop !== undefined && !this.wasStopped)
75
- void this.onCloseAndErrorNoStop(this);
76
- });
77
- instance.on("close", () => {
78
- this.logger.warn(`platforma was closed, started opts: ${JSON.stringify(this.debugInfo())}`);
79
- // keep in mind there are no awaits here, it will be asynchronous
80
- if (this.onClose !== undefined)
81
- void this.onClose(this);
82
- if (this.onCloseAndError !== undefined)
83
- void this.onCloseAndError(this);
84
- if (this.onCloseAndErrorNoStop !== undefined && !this.wasStopped)
85
- void this.onCloseAndErrorNoStop(this);
86
- });
87
- trace("started", true);
88
- const pidFile = trace("pidFile", pid.filePid(this.workingDir));
89
- trace("pid", tsHelpers.notEmpty(instance.pid));
90
- trace("pidWritten", await pid.writePid(pidFile, tsHelpers.notEmpty(instance.pid)));
91
- this.nRuns++;
92
- this.instance = instance;
93
- this.pid = instance.pid;
94
- this.lastRunHistory = t;
95
- });
96
- }
97
- stop() {
98
- // TODO use this.instance to stop the process
99
- this.wasStopped = true;
100
- process$1.processStop(tsHelpers.notEmpty(this.pid));
101
- }
102
- async waitStopped() {
103
- await process$1.processWaitStopped(tsHelpers.notEmpty(this.pid), 15000);
104
- }
105
- stopped() {
106
- return this.wasStopped;
107
- }
108
- async isAlive() {
109
- return await process$1.isProcessAlive(tsHelpers.notEmpty(this.pid));
110
- }
111
- debugInfo() {
112
- return {
113
- lastRunHistory: this.lastRunHistory,
114
- nRuns: this.nRuns,
115
- pid: this.pid,
116
- workingDir: this.workingDir,
117
- initialStartHistory: this.initialStartHistory,
118
- wasStopped: this.wasStopped,
119
- };
120
- }
121
- }
19
+ * Represents a local running pl-core,
20
+ * and has methods to start, check if it's running, stop and wait for stopping it.
21
+ * Also, a hook on pl-core closed can be provided.
22
+ */
23
+ var LocalPl = class {
24
+ instance;
25
+ pid;
26
+ nRuns = 0;
27
+ lastRunHistory = {};
28
+ wasStopped = false;
29
+ constructor(logger, workingDir, startOptions, initialStartHistory, onClose, onError, onCloseAndError, onCloseAndErrorNoStop) {
30
+ this.logger = logger;
31
+ this.workingDir = workingDir;
32
+ this.startOptions = startOptions;
33
+ this.initialStartHistory = initialStartHistory;
34
+ this.onClose = onClose;
35
+ this.onError = onError;
36
+ this.onCloseAndError = onCloseAndError;
37
+ this.onCloseAndErrorNoStop = onCloseAndErrorNoStop;
38
+ }
39
+ async start() {
40
+ await require_trace.withTrace(this.logger, async (trace, t) => {
41
+ this.wasStopped = false;
42
+ const instance = require_process.processRun(this.logger, this.startOptions);
43
+ instance.on("error", (e) => {
44
+ this.logger.error(`error '${e}', while running platforma, started opts: ${JSON.stringify(this.debugInfo())}`);
45
+ if (this.onError !== void 0) this.onError(this);
46
+ if (this.onCloseAndError !== void 0) this.onCloseAndError(this);
47
+ if (this.onCloseAndErrorNoStop !== void 0 && !this.wasStopped) this.onCloseAndErrorNoStop(this);
48
+ });
49
+ instance.on("close", () => {
50
+ this.logger.warn(`platforma was closed, started opts: ${JSON.stringify(this.debugInfo())}`);
51
+ if (this.onClose !== void 0) this.onClose(this);
52
+ if (this.onCloseAndError !== void 0) this.onCloseAndError(this);
53
+ if (this.onCloseAndErrorNoStop !== void 0 && !this.wasStopped) this.onCloseAndErrorNoStop(this);
54
+ });
55
+ trace("started", true);
56
+ const pidFile = trace("pidFile", require_pid.filePid(this.workingDir));
57
+ trace("pid", (0, _milaboratories_ts_helpers.notEmpty)(instance.pid));
58
+ trace("pidWritten", await require_pid.writePid(pidFile, (0, _milaboratories_ts_helpers.notEmpty)(instance.pid)));
59
+ this.nRuns++;
60
+ this.instance = instance;
61
+ this.pid = instance.pid;
62
+ this.lastRunHistory = t;
63
+ });
64
+ }
65
+ stop() {
66
+ this.wasStopped = true;
67
+ require_process.processStop((0, _milaboratories_ts_helpers.notEmpty)(this.pid));
68
+ }
69
+ async waitStopped() {
70
+ await require_process.processWaitStopped((0, _milaboratories_ts_helpers.notEmpty)(this.pid), 15e3);
71
+ }
72
+ stopped() {
73
+ return this.wasStopped;
74
+ }
75
+ async isAlive() {
76
+ return await require_process.isProcessAlive((0, _milaboratories_ts_helpers.notEmpty)(this.pid));
77
+ }
78
+ debugInfo() {
79
+ return {
80
+ lastRunHistory: this.lastRunHistory,
81
+ nRuns: this.nRuns,
82
+ pid: this.pid,
83
+ workingDir: this.workingDir,
84
+ initialStartHistory: this.initialStartHistory,
85
+ wasStopped: this.wasStopped
86
+ };
87
+ }
88
+ };
122
89
  /**
123
- * Starts pl-core, if the option was provided downloads a binary, reads license environments etc.
124
- */
90
+ * Starts pl-core, if the option was provided downloads a binary, reads license environments etc.
91
+ */
125
92
  async function localPlatformaInit(logger, _ops) {
126
- // filling-in default values
127
- // Backend could consume a lot of CPU power,
128
- // we want to keep at least a couple for UI and other apps to work.
129
- const numCpu = Math.max(os__namespace.cpus().length - 2, 1);
130
- const ops = mergeDefaultOps(_ops, numCpu);
131
- return await trace.withTrace(logger, async (trace, t) => {
132
- trace("startOptions", { ...ops, config: "too wordy" });
133
- const workDir = upath.resolve(ops.workingDir);
134
- if (ops.closeOld) {
135
- trace("closeOld", await localPlatformaReadPidAndStop(logger, workDir));
136
- }
137
- const configPath = upath.join(workDir, LocalConfigYaml);
138
- logger.info(`writing configuration '${configPath}'...`);
139
- await fsp.writeFile(configPath, ops.config);
140
- const plBinPath = upath.join(workDir, "binaries");
141
- const baseBinaryPath = await pl_binary.resolveLocalPlBinaryPath({
142
- logger,
143
- downloadDir: plBinPath,
144
- src: ops.plBinary,
145
- dispatcher: plHttp.defaultHttpDispatcher(ops.proxy),
146
- });
147
- const binaryPath = trace("binaryPath", upath.join("binaries", baseBinaryPath));
148
- const env = { ...process.env };
149
- if (ops.proxy?.url) {
150
- const url = new URL(ops.proxy.url);
151
- if (ops.proxy.auth) {
152
- const parsed = plModelCommon.parseHttpAuth(ops.proxy.auth);
153
- if (parsed.scheme !== "Basic") {
154
- throw new Error(`\
93
+ const ops = mergeDefaultOps(_ops, Math.max(node_os.cpus().length - 2, 1));
94
+ return await require_trace.withTrace(logger, async (trace, t) => {
95
+ trace("startOptions", {
96
+ ...ops,
97
+ config: "too wordy"
98
+ });
99
+ const workDir = upath.default.resolve(ops.workingDir);
100
+ if (ops.closeOld) trace("closeOld", await localPlatformaReadPidAndStop(logger, workDir));
101
+ const configPath = upath.default.join(workDir, LocalConfigYaml);
102
+ logger.info(`writing configuration '${configPath}'...`);
103
+ await node_fs_promises.default.writeFile(configPath, ops.config);
104
+ const baseBinaryPath = await require_pl_binary.resolveLocalPlBinaryPath({
105
+ logger,
106
+ downloadDir: upath.default.join(workDir, "binaries"),
107
+ src: ops.plBinary,
108
+ dispatcher: (0, _milaboratories_pl_http.defaultHttpDispatcher)(ops.proxy)
109
+ });
110
+ const binaryPath = trace("binaryPath", upath.default.join("binaries", baseBinaryPath));
111
+ const env = { ...process.env };
112
+ if (ops.proxy?.url) {
113
+ const url = new URL(ops.proxy.url);
114
+ if (ops.proxy.auth) {
115
+ const parsed = (0, _milaboratories_pl_model_common.parseHttpAuth)(ops.proxy.auth);
116
+ if (parsed.scheme !== "Basic") throw new Error(`\
155
117
  Unsupported auth scheme: ${parsed.scheme}. \
156
118
  Only Basic auth is supported by the backend.`);
157
- }
158
- url.username = parsed.username;
159
- url.password = parsed.password;
160
- }
161
- env.http_proxy = url.toString();
162
- env.https_proxy = url.toString();
163
- }
164
- const processOpts = plProcessOps(binaryPath, configPath, ops, workDir, env);
165
- trace("processOpts", {
166
- cmd: processOpts.cmd,
167
- args: processOpts.args,
168
- cwd: processOpts.opts.cwd,
169
- });
170
- const pl = new LocalPl(logger, ops.workingDir, processOpts, t, ops.onClose, ops.onError, ops.onCloseAndError, ops.onCloseAndErrorNoStop);
171
- await pl.start();
172
- return pl;
173
- });
119
+ url.username = parsed.username;
120
+ url.password = parsed.password;
121
+ }
122
+ env.http_proxy = url.toString();
123
+ env.https_proxy = url.toString();
124
+ }
125
+ const processOpts = plProcessOps(binaryPath, configPath, ops, workDir, env);
126
+ trace("processOpts", {
127
+ cmd: processOpts.cmd,
128
+ args: processOpts.args,
129
+ cwd: processOpts.opts.cwd
130
+ });
131
+ const pl = new LocalPl(logger, ops.workingDir, processOpts, t, ops.onClose, ops.onError, ops.onCloseAndError, ops.onCloseAndErrorNoStop);
132
+ await pl.start();
133
+ return pl;
134
+ });
174
135
  }
175
136
  /** Reads a pid of the old pl-core if it was started in the same working directory,
176
- * and closes it. */
137
+ * and closes it. */
177
138
  async function localPlatformaReadPidAndStop(logger, workingDir) {
178
- return await trace.withTrace(logger, async (trace, t) => {
179
- const file = trace("pidFilePath", pid.filePid(workingDir));
180
- const oldPid = trace("pid", await pid.readPid(file));
181
- const alive = trace("wasAlive", await process$1.isProcessAlive(oldPid));
182
- if (oldPid !== undefined && alive) {
183
- trace("stopped", process$1.processStop(oldPid));
184
- try {
185
- trace("waitStopped", await process$1.processWaitStopped(oldPid, 15_000)); // larger, that 10s we provide to backend in config.
186
- }
187
- catch {
188
- trace("forceStopped", process$1.processStop(oldPid, true));
189
- trace("waitForceStopped", await process$1.processWaitStopped(oldPid, 5_000));
190
- }
191
- }
192
- return t;
193
- });
139
+ return await require_trace.withTrace(logger, async (trace, t) => {
140
+ const oldPid = trace("pid", await require_pid.readPid(trace("pidFilePath", require_pid.filePid(workingDir))));
141
+ const alive = trace("wasAlive", await require_process.isProcessAlive(oldPid));
142
+ if (oldPid !== void 0 && alive) {
143
+ trace("stopped", require_process.processStop(oldPid));
144
+ try {
145
+ trace("waitStopped", await require_process.processWaitStopped(oldPid, 15e3));
146
+ } catch {
147
+ trace("forceStopped", require_process.processStop(oldPid, true));
148
+ trace("waitForceStopped", await require_process.processWaitStopped(oldPid, 5e3));
149
+ }
150
+ }
151
+ return t;
152
+ });
194
153
  }
195
154
  /** Gets default options for the whole init process
196
- * and overrides them with the provided options. */
155
+ * and overrides them with the provided options. */
197
156
  function mergeDefaultOps(ops, numCpu) {
198
- const result = {
199
- plBinary: pl_binary.newDefaultPlBinarySource(),
200
- spawnOptions: {
201
- env: {
202
- GOMAXPROCS: String(numCpu),
203
- },
204
- },
205
- closeOld: true,
206
- };
207
- if (ops.spawnOptions?.env) {
208
- result.spawnOptions.env = { ...result.spawnOptions.env, ...ops.spawnOptions.env };
209
- }
210
- if (ops.spawnOptions) {
211
- const withoutEnv = { ...ops.spawnOptions };
212
- delete withoutEnv["env"];
213
- result.spawnOptions = { ...result.spawnOptions, ...withoutEnv };
214
- }
215
- const withoutSpawnOps = { ...ops };
216
- delete withoutSpawnOps["spawnOptions"];
217
- return { ...result, ...withoutSpawnOps };
157
+ const result = {
158
+ plBinary: require_pl_binary.newDefaultPlBinarySource(),
159
+ spawnOptions: { env: { GOMAXPROCS: String(numCpu) } },
160
+ closeOld: true
161
+ };
162
+ if (ops.spawnOptions?.env) result.spawnOptions.env = {
163
+ ...result.spawnOptions.env,
164
+ ...ops.spawnOptions.env
165
+ };
166
+ if (ops.spawnOptions) {
167
+ const withoutEnv = { ...ops.spawnOptions };
168
+ delete withoutEnv["env"];
169
+ result.spawnOptions = {
170
+ ...result.spawnOptions,
171
+ ...withoutEnv
172
+ };
173
+ }
174
+ const withoutSpawnOps = { ...ops };
175
+ delete withoutSpawnOps["spawnOptions"];
176
+ return {
177
+ ...result,
178
+ ...withoutSpawnOps
179
+ };
218
180
  }
219
181
  /** Gets default options for a platforma local binary
220
- * and overrides them with the provided options. */
182
+ * and overrides them with the provided options. */
221
183
  function plProcessOps(binaryPath, configPath, ops, workDir, defaultEnv) {
222
- const result = {
223
- cmd: binaryPath,
224
- args: ["--config", configPath],
225
- opts: {
226
- env: { ...defaultEnv },
227
- cwd: workDir,
228
- stdio: ["pipe", "ignore", "inherit"],
229
- windowsHide: true, // hide a terminal on Windows
230
- },
231
- };
232
- if (ops.spawnOptions?.env) {
233
- result.opts.env = { ...result.opts.env, ...ops.spawnOptions.env };
234
- }
235
- const withoutEnv = { ...ops.spawnOptions };
236
- delete withoutEnv["env"];
237
- result.opts = { ...result.opts, ...withoutEnv };
238
- return result;
184
+ const result = {
185
+ cmd: binaryPath,
186
+ args: ["--config", configPath],
187
+ opts: {
188
+ env: { ...defaultEnv },
189
+ cwd: workDir,
190
+ stdio: [
191
+ "pipe",
192
+ "ignore",
193
+ "inherit"
194
+ ],
195
+ windowsHide: true
196
+ }
197
+ };
198
+ if (ops.spawnOptions?.env) result.opts.env = {
199
+ ...result.opts.env,
200
+ ...ops.spawnOptions.env
201
+ };
202
+ const withoutEnv = { ...ops.spawnOptions };
203
+ delete withoutEnv["env"];
204
+ result.opts = {
205
+ ...result.opts,
206
+ ...withoutEnv
207
+ };
208
+ return result;
239
209
  }
240
210
 
211
+ //#endregion
241
212
  exports.LocalConfigYaml = LocalConfigYaml;
242
213
  exports.LocalPl = LocalPl;
243
214
  exports.localPlatformaInit = localPlatformaInit;
244
215
  exports.mergeDefaultOps = mergeDefaultOps;
245
216
  exports.plProcessOps = plProcessOps;
246
- //# sourceMappingURL=pl.cjs.map
217
+ //# sourceMappingURL=pl.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"pl.cjs","sources":["../../src/local/pl.ts"],"sourcesContent":["import type { ProcessOptions } from \"./process\";\nimport { isProcessAlive, processStop, processWaitStopped, processRun } from \"./process\";\nimport type { PlBinarySource } from \"../common/pl_binary\";\nimport { newDefaultPlBinarySource, resolveLocalPlBinaryPath } from \"../common/pl_binary\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { ChildProcess, SpawnOptions } from \"node:child_process\";\nimport { filePid, readPid, writePid } from \"./pid\";\nimport type { Trace } from \"./trace\";\nimport { withTrace } from \"./trace\";\nimport upath from \"upath\";\nimport fsp from \"node:fs/promises\";\nimport type { Required } from \"utility-types\";\nimport * as os from \"node:os\";\nimport type { ProxySettings } from \"@milaboratories/pl-http\";\nimport { defaultHttpDispatcher } from \"@milaboratories/pl-http\";\nimport { parseHttpAuth } from \"@milaboratories/pl-model-common\";\n\nexport const LocalConfigYaml = \"config-local.yaml\";\n\n/**\n * Represents a local running pl-core,\n * and has methods to start, check if it's running, stop and wait for stopping it.\n * Also, a hook on pl-core closed can be provided.\n */\nexport class LocalPl {\n private instance?: ChildProcess;\n public pid?: number;\n private nRuns: number = 0;\n private lastRunHistory: Trace = {};\n private wasStopped = false;\n\n constructor(\n private readonly logger: MiLogger,\n private readonly workingDir: string,\n private readonly startOptions: ProcessOptions,\n private readonly initialStartHistory: Trace,\n private readonly onClose?: (pl: LocalPl) => Promise<void>,\n private readonly onError?: (pl: LocalPl) => Promise<void>,\n private readonly onCloseAndError?: (pl: LocalPl) => Promise<void>,\n private readonly onCloseAndErrorNoStop?: (pl: LocalPl) => Promise<void>,\n ) {}\n\n async start() {\n await withTrace(this.logger, async (trace, t) => {\n this.wasStopped = false;\n const instance = processRun(this.logger, this.startOptions);\n instance.on(\"error\", (e: any) => {\n this.logger.error(\n `error '${e}', while running platforma, started opts: ${JSON.stringify(this.debugInfo())}`,\n );\n\n // keep in mind there are no awaits here, it will be asynchronous\n if (this.onError !== undefined) void this.onError(this);\n if (this.onCloseAndError !== undefined) void this.onCloseAndError(this);\n if (this.onCloseAndErrorNoStop !== undefined && !this.wasStopped)\n void this.onCloseAndErrorNoStop(this);\n });\n instance.on(\"close\", () => {\n this.logger.warn(`platforma was closed, started opts: ${JSON.stringify(this.debugInfo())}`);\n\n // keep in mind there are no awaits here, it will be asynchronous\n if (this.onClose !== undefined) void this.onClose(this);\n if (this.onCloseAndError !== undefined) void this.onCloseAndError(this);\n if (this.onCloseAndErrorNoStop !== undefined && !this.wasStopped)\n void this.onCloseAndErrorNoStop(this);\n });\n\n trace(\"started\", true);\n\n const pidFile = trace(\"pidFile\", filePid(this.workingDir));\n trace(\"pid\", notEmpty(instance.pid));\n trace(\"pidWritten\", await writePid(pidFile, notEmpty(instance.pid)));\n\n this.nRuns++;\n this.instance = instance;\n this.pid = instance.pid;\n this.lastRunHistory = t;\n });\n }\n\n stop() {\n // TODO use this.instance to stop the process\n this.wasStopped = true;\n processStop(notEmpty(this.pid));\n }\n\n async waitStopped() {\n await processWaitStopped(notEmpty(this.pid), 15000);\n }\n\n stopped() {\n return this.wasStopped;\n }\n\n async isAlive(): Promise<boolean> {\n return await isProcessAlive(notEmpty(this.pid));\n }\n\n debugInfo() {\n return {\n lastRunHistory: this.lastRunHistory,\n nRuns: this.nRuns,\n pid: this.pid,\n workingDir: this.workingDir,\n initialStartHistory: this.initialStartHistory,\n wasStopped: this.wasStopped,\n };\n }\n}\n\n/** Options to start a local pl-core. */\nexport type LocalPlOptions = {\n /** From what directory start a process. */\n readonly workingDir: string;\n /** A string representation of yaml config. */\n readonly config: string;\n /** How to get a binary, download it or get an existing one (default: download latest version) */\n readonly plBinary?: PlBinarySource;\n /** Additional options for a process, environments, stdout, stderr etc. */\n readonly spawnOptions?: SpawnOptions;\n /**\n * If the previous pl-core was started from the same directory,\n * we can check if it's still running and then stop it before starting a new one.\n * (default: true)\n */\n readonly closeOld?: boolean;\n /**\n * Proxy settings to use to fetch the binary and pass it down\n * as a HTTPS_PROXY/HTTP_PROXY environment variable;\n * Backend only supports Basic auth.\n */\n readonly proxy?: ProxySettings;\n\n readonly onClose?: (pl: LocalPl) => Promise<void>;\n readonly onError?: (pl: LocalPl) => Promise<void>;\n readonly onCloseAndError?: (pl: LocalPl) => Promise<void>;\n readonly onCloseAndErrorNoStop?: (pl: LocalPl) => Promise<void>;\n};\n\nexport type LocalPlOptionsFull = Required<LocalPlOptions, \"plBinary\" | \"spawnOptions\" | \"closeOld\">;\n\n/**\n * Starts pl-core, if the option was provided downloads a binary, reads license environments etc.\n */\nexport async function localPlatformaInit(logger: MiLogger, _ops: LocalPlOptions): Promise<LocalPl> {\n // filling-in default values\n\n // Backend could consume a lot of CPU power,\n // we want to keep at least a couple for UI and other apps to work.\n const numCpu = Math.max(os.cpus().length - 2, 1);\n const ops = mergeDefaultOps(_ops, numCpu);\n\n return await withTrace(logger, async (trace, t) => {\n trace(\"startOptions\", { ...ops, config: \"too wordy\" });\n\n const workDir = upath.resolve(ops.workingDir);\n\n if (ops.closeOld) {\n trace(\"closeOld\", await localPlatformaReadPidAndStop(logger, workDir));\n }\n\n const configPath = upath.join(workDir, LocalConfigYaml);\n\n logger.info(`writing configuration '${configPath}'...`);\n await fsp.writeFile(configPath, ops.config);\n\n const plBinPath = upath.join(workDir, \"binaries\");\n const baseBinaryPath = await resolveLocalPlBinaryPath({\n logger,\n downloadDir: plBinPath,\n src: ops.plBinary,\n dispatcher: defaultHttpDispatcher(ops.proxy),\n });\n const binaryPath = trace(\"binaryPath\", upath.join(\"binaries\", baseBinaryPath));\n\n const env = { ...process.env };\n\n if (ops.proxy?.url) {\n const url = new URL(ops.proxy.url);\n if (ops.proxy.auth) {\n const parsed = parseHttpAuth(ops.proxy.auth);\n if (parsed.scheme !== \"Basic\") {\n throw new Error(`\\\nUnsupported auth scheme: ${parsed.scheme}. \\\nOnly Basic auth is supported by the backend.`);\n }\n url.username = parsed.username;\n url.password = parsed.password;\n }\n env.http_proxy = url.toString();\n env.https_proxy = url.toString();\n }\n\n const processOpts = plProcessOps(binaryPath, configPath, ops, workDir, env);\n trace(\"processOpts\", {\n cmd: processOpts.cmd,\n args: processOpts.args,\n cwd: processOpts.opts.cwd,\n });\n\n const pl = new LocalPl(\n logger,\n ops.workingDir,\n processOpts,\n t,\n ops.onClose,\n ops.onError,\n ops.onCloseAndError,\n ops.onCloseAndErrorNoStop,\n );\n await pl.start();\n\n return pl;\n });\n}\n\n/** Reads a pid of the old pl-core if it was started in the same working directory,\n * and closes it. */\nasync function localPlatformaReadPidAndStop(\n logger: MiLogger,\n workingDir: string,\n): Promise<Record<string, any>> {\n return await withTrace(logger, async (trace, t) => {\n const file = trace(\"pidFilePath\", filePid(workingDir));\n\n const oldPid = trace(\"pid\", await readPid(file));\n const alive = trace(\"wasAlive\", await isProcessAlive(oldPid));\n\n if (oldPid !== undefined && alive) {\n trace(\"stopped\", processStop(oldPid));\n try {\n trace(\"waitStopped\", await processWaitStopped(oldPid, 15_000)); // larger, that 10s we provide to backend in config.\n } catch {\n trace(\"forceStopped\", processStop(oldPid, true));\n trace(\"waitForceStopped\", await processWaitStopped(oldPid, 5_000));\n }\n }\n\n return t;\n });\n}\n\n/** Gets default options for the whole init process\n * and overrides them with the provided options. */\nexport function mergeDefaultOps(ops: LocalPlOptions, numCpu: number): LocalPlOptionsFull {\n const result: {\n plBinary: PlBinarySource;\n spawnOptions: SpawnOptions;\n closeOld: boolean;\n } = {\n plBinary: newDefaultPlBinarySource(),\n spawnOptions: {\n env: {\n GOMAXPROCS: String(numCpu),\n },\n },\n closeOld: true,\n };\n\n if (ops.spawnOptions?.env) {\n result.spawnOptions.env = { ...result.spawnOptions.env, ...ops.spawnOptions.env };\n }\n\n if (ops.spawnOptions) {\n const withoutEnv = { ...ops.spawnOptions };\n delete withoutEnv[\"env\"];\n result.spawnOptions = { ...result.spawnOptions, ...withoutEnv };\n }\n\n const withoutSpawnOps = { ...ops };\n delete withoutSpawnOps[\"spawnOptions\"];\n\n return { ...result, ...withoutSpawnOps };\n}\n\n/** Gets default options for a platforma local binary\n * and overrides them with the provided options. */\nexport function plProcessOps(\n binaryPath: any,\n configPath: string,\n ops: LocalPlOptionsFull,\n workDir: string,\n defaultEnv: Record<string, string | undefined>,\n): ProcessOptions {\n const result: ProcessOptions = {\n cmd: binaryPath,\n args: [\"--config\", configPath],\n opts: {\n env: { ...defaultEnv },\n cwd: workDir,\n stdio: [\"pipe\", \"ignore\", \"inherit\"],\n windowsHide: true, // hide a terminal on Windows\n },\n };\n\n if (ops.spawnOptions?.env) {\n result.opts.env = { ...result.opts.env, ...ops.spawnOptions.env };\n }\n\n const withoutEnv = { ...ops.spawnOptions };\n delete withoutEnv[\"env\"];\n result.opts = { ...result.opts, ...withoutEnv };\n\n return result;\n}\n"],"names":["withTrace","processRun","filePid","notEmpty","writePid","processStop","processWaitStopped","isProcessAlive","os","resolveLocalPlBinaryPath","defaultHttpDispatcher","parseHttpAuth","readPid","newDefaultPlBinarySource"],"mappings":"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"}
1
+ {"version":3,"file":"pl.cjs","names":["withTrace","processRun","filePid","writePid","processWaitStopped","isProcessAlive","os","fsp","resolveLocalPlBinaryPath","readPid","processStop","newDefaultPlBinarySource"],"sources":["../../src/local/pl.ts"],"sourcesContent":["import type { ProcessOptions } from \"./process\";\nimport { isProcessAlive, processStop, processWaitStopped, processRun } from \"./process\";\nimport type { PlBinarySource } from \"../common/pl_binary\";\nimport { newDefaultPlBinarySource, resolveLocalPlBinaryPath } from \"../common/pl_binary\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { ChildProcess, SpawnOptions } from \"node:child_process\";\nimport { filePid, readPid, writePid } from \"./pid\";\nimport type { Trace } from \"./trace\";\nimport { withTrace } from \"./trace\";\nimport upath from \"upath\";\nimport fsp from \"node:fs/promises\";\nimport type { Required } from \"utility-types\";\nimport * as os from \"node:os\";\nimport type { ProxySettings } from \"@milaboratories/pl-http\";\nimport { defaultHttpDispatcher } from \"@milaboratories/pl-http\";\nimport { parseHttpAuth } from \"@milaboratories/pl-model-common\";\n\nexport const LocalConfigYaml = \"config-local.yaml\";\n\n/**\n * Represents a local running pl-core,\n * and has methods to start, check if it's running, stop and wait for stopping it.\n * Also, a hook on pl-core closed can be provided.\n */\nexport class LocalPl {\n private instance?: ChildProcess;\n public pid?: number;\n private nRuns: number = 0;\n private lastRunHistory: Trace = {};\n private wasStopped = false;\n\n constructor(\n private readonly logger: MiLogger,\n private readonly workingDir: string,\n private readonly startOptions: ProcessOptions,\n private readonly initialStartHistory: Trace,\n private readonly onClose?: (pl: LocalPl) => Promise<void>,\n private readonly onError?: (pl: LocalPl) => Promise<void>,\n private readonly onCloseAndError?: (pl: LocalPl) => Promise<void>,\n private readonly onCloseAndErrorNoStop?: (pl: LocalPl) => Promise<void>,\n ) {}\n\n async start() {\n await withTrace(this.logger, async (trace, t) => {\n this.wasStopped = false;\n const instance = processRun(this.logger, this.startOptions);\n instance.on(\"error\", (e: any) => {\n this.logger.error(\n `error '${e}', while running platforma, started opts: ${JSON.stringify(this.debugInfo())}`,\n );\n\n // keep in mind there are no awaits here, it will be asynchronous\n if (this.onError !== undefined) void this.onError(this);\n if (this.onCloseAndError !== undefined) void this.onCloseAndError(this);\n if (this.onCloseAndErrorNoStop !== undefined && !this.wasStopped)\n void this.onCloseAndErrorNoStop(this);\n });\n instance.on(\"close\", () => {\n this.logger.warn(`platforma was closed, started opts: ${JSON.stringify(this.debugInfo())}`);\n\n // keep in mind there are no awaits here, it will be asynchronous\n if (this.onClose !== undefined) void this.onClose(this);\n if (this.onCloseAndError !== undefined) void this.onCloseAndError(this);\n if (this.onCloseAndErrorNoStop !== undefined && !this.wasStopped)\n void this.onCloseAndErrorNoStop(this);\n });\n\n trace(\"started\", true);\n\n const pidFile = trace(\"pidFile\", filePid(this.workingDir));\n trace(\"pid\", notEmpty(instance.pid));\n trace(\"pidWritten\", await writePid(pidFile, notEmpty(instance.pid)));\n\n this.nRuns++;\n this.instance = instance;\n this.pid = instance.pid;\n this.lastRunHistory = t;\n });\n }\n\n stop() {\n // TODO use this.instance to stop the process\n this.wasStopped = true;\n processStop(notEmpty(this.pid));\n }\n\n async waitStopped() {\n await processWaitStopped(notEmpty(this.pid), 15000);\n }\n\n stopped() {\n return this.wasStopped;\n }\n\n async isAlive(): Promise<boolean> {\n return await isProcessAlive(notEmpty(this.pid));\n }\n\n debugInfo() {\n return {\n lastRunHistory: this.lastRunHistory,\n nRuns: this.nRuns,\n pid: this.pid,\n workingDir: this.workingDir,\n initialStartHistory: this.initialStartHistory,\n wasStopped: this.wasStopped,\n };\n }\n}\n\n/** Options to start a local pl-core. */\nexport type LocalPlOptions = {\n /** From what directory start a process. */\n readonly workingDir: string;\n /** A string representation of yaml config. */\n readonly config: string;\n /** How to get a binary, download it or get an existing one (default: download latest version) */\n readonly plBinary?: PlBinarySource;\n /** Additional options for a process, environments, stdout, stderr etc. */\n readonly spawnOptions?: SpawnOptions;\n /**\n * If the previous pl-core was started from the same directory,\n * we can check if it's still running and then stop it before starting a new one.\n * (default: true)\n */\n readonly closeOld?: boolean;\n /**\n * Proxy settings to use to fetch the binary and pass it down\n * as a HTTPS_PROXY/HTTP_PROXY environment variable;\n * Backend only supports Basic auth.\n */\n readonly proxy?: ProxySettings;\n\n readonly onClose?: (pl: LocalPl) => Promise<void>;\n readonly onError?: (pl: LocalPl) => Promise<void>;\n readonly onCloseAndError?: (pl: LocalPl) => Promise<void>;\n readonly onCloseAndErrorNoStop?: (pl: LocalPl) => Promise<void>;\n};\n\nexport type LocalPlOptionsFull = Required<LocalPlOptions, \"plBinary\" | \"spawnOptions\" | \"closeOld\">;\n\n/**\n * Starts pl-core, if the option was provided downloads a binary, reads license environments etc.\n */\nexport async function localPlatformaInit(logger: MiLogger, _ops: LocalPlOptions): Promise<LocalPl> {\n // filling-in default values\n\n // Backend could consume a lot of CPU power,\n // we want to keep at least a couple for UI and other apps to work.\n const numCpu = Math.max(os.cpus().length - 2, 1);\n const ops = mergeDefaultOps(_ops, numCpu);\n\n return await withTrace(logger, async (trace, t) => {\n trace(\"startOptions\", { ...ops, config: \"too wordy\" });\n\n const workDir = upath.resolve(ops.workingDir);\n\n if (ops.closeOld) {\n trace(\"closeOld\", await localPlatformaReadPidAndStop(logger, workDir));\n }\n\n const configPath = upath.join(workDir, LocalConfigYaml);\n\n logger.info(`writing configuration '${configPath}'...`);\n await fsp.writeFile(configPath, ops.config);\n\n const plBinPath = upath.join(workDir, \"binaries\");\n const baseBinaryPath = await resolveLocalPlBinaryPath({\n logger,\n downloadDir: plBinPath,\n src: ops.plBinary,\n dispatcher: defaultHttpDispatcher(ops.proxy),\n });\n const binaryPath = trace(\"binaryPath\", upath.join(\"binaries\", baseBinaryPath));\n\n const env = { ...process.env };\n\n if (ops.proxy?.url) {\n const url = new URL(ops.proxy.url);\n if (ops.proxy.auth) {\n const parsed = parseHttpAuth(ops.proxy.auth);\n if (parsed.scheme !== \"Basic\") {\n throw new Error(`\\\nUnsupported auth scheme: ${parsed.scheme}. \\\nOnly Basic auth is supported by the backend.`);\n }\n url.username = parsed.username;\n url.password = parsed.password;\n }\n env.http_proxy = url.toString();\n env.https_proxy = url.toString();\n }\n\n const processOpts = plProcessOps(binaryPath, configPath, ops, workDir, env);\n trace(\"processOpts\", {\n cmd: processOpts.cmd,\n args: processOpts.args,\n cwd: processOpts.opts.cwd,\n });\n\n const pl = new LocalPl(\n logger,\n ops.workingDir,\n processOpts,\n t,\n ops.onClose,\n ops.onError,\n ops.onCloseAndError,\n ops.onCloseAndErrorNoStop,\n );\n await pl.start();\n\n return pl;\n });\n}\n\n/** Reads a pid of the old pl-core if it was started in the same working directory,\n * and closes it. */\nasync function localPlatformaReadPidAndStop(\n logger: MiLogger,\n workingDir: string,\n): Promise<Record<string, any>> {\n return await withTrace(logger, async (trace, t) => {\n const file = trace(\"pidFilePath\", filePid(workingDir));\n\n const oldPid = trace(\"pid\", await readPid(file));\n const alive = trace(\"wasAlive\", await isProcessAlive(oldPid));\n\n if (oldPid !== undefined && alive) {\n trace(\"stopped\", processStop(oldPid));\n try {\n trace(\"waitStopped\", await processWaitStopped(oldPid, 15_000)); // larger, that 10s we provide to backend in config.\n } catch {\n trace(\"forceStopped\", processStop(oldPid, true));\n trace(\"waitForceStopped\", await processWaitStopped(oldPid, 5_000));\n }\n }\n\n return t;\n });\n}\n\n/** Gets default options for the whole init process\n * and overrides them with the provided options. */\nexport function mergeDefaultOps(ops: LocalPlOptions, numCpu: number): LocalPlOptionsFull {\n const result: {\n plBinary: PlBinarySource;\n spawnOptions: SpawnOptions;\n closeOld: boolean;\n } = {\n plBinary: newDefaultPlBinarySource(),\n spawnOptions: {\n env: {\n GOMAXPROCS: String(numCpu),\n },\n },\n closeOld: true,\n };\n\n if (ops.spawnOptions?.env) {\n result.spawnOptions.env = { ...result.spawnOptions.env, ...ops.spawnOptions.env };\n }\n\n if (ops.spawnOptions) {\n const withoutEnv = { ...ops.spawnOptions };\n delete withoutEnv[\"env\"];\n result.spawnOptions = { ...result.spawnOptions, ...withoutEnv };\n }\n\n const withoutSpawnOps = { ...ops };\n delete withoutSpawnOps[\"spawnOptions\"];\n\n return { ...result, ...withoutSpawnOps };\n}\n\n/** Gets default options for a platforma local binary\n * and overrides them with the provided options. */\nexport function plProcessOps(\n binaryPath: any,\n configPath: string,\n ops: LocalPlOptionsFull,\n workDir: string,\n defaultEnv: Record<string, string | undefined>,\n): ProcessOptions {\n const result: ProcessOptions = {\n cmd: binaryPath,\n args: [\"--config\", configPath],\n opts: {\n env: { ...defaultEnv },\n cwd: workDir,\n stdio: [\"pipe\", \"ignore\", \"inherit\"],\n windowsHide: true, // hide a terminal on Windows\n },\n };\n\n if (ops.spawnOptions?.env) {\n result.opts.env = { ...result.opts.env, ...ops.spawnOptions.env };\n }\n\n const withoutEnv = { ...ops.spawnOptions };\n delete withoutEnv[\"env\"];\n result.opts = { ...result.opts, ...withoutEnv };\n\n return result;\n}\n"],"mappings":"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"}