teraslice-client-js 2.16.2 → 2.17.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 (53) hide show
  1. package/dist/src/executions.d.ts +1 -1
  2. package/dist/src/executions.d.ts.map +1 -1
  3. package/package.json +7 -4
  4. package/dist/test/assets-spec.d.ts +0 -2
  5. package/dist/test/assets-spec.d.ts.map +0 -1
  6. package/dist/test/assets-spec.js +0 -322
  7. package/dist/test/assets-spec.js.map +0 -1
  8. package/dist/test/client-spec.d.ts +0 -2
  9. package/dist/test/client-spec.d.ts.map +0 -1
  10. package/dist/test/client-spec.js +0 -374
  11. package/dist/test/client-spec.js.map +0 -1
  12. package/dist/test/cluster-spec.d.ts +0 -2
  13. package/dist/test/cluster-spec.d.ts.map +0 -1
  14. package/dist/test/cluster-spec.js +0 -143
  15. package/dist/test/cluster-spec.js.map +0 -1
  16. package/dist/test/ex-spec.d.ts +0 -2
  17. package/dist/test/ex-spec.d.ts.map +0 -1
  18. package/dist/test/ex-spec.js +0 -550
  19. package/dist/test/ex-spec.js.map +0 -1
  20. package/dist/test/executions-spec.d.ts +0 -2
  21. package/dist/test/executions-spec.d.ts.map +0 -1
  22. package/dist/test/executions-spec.js +0 -233
  23. package/dist/test/executions-spec.js.map +0 -1
  24. package/dist/test/job-spec.d.ts +0 -2
  25. package/dist/test/job-spec.d.ts.map +0 -1
  26. package/dist/test/job-spec.js +0 -837
  27. package/dist/test/job-spec.js.map +0 -1
  28. package/dist/test/jobs-spec.d.ts +0 -2
  29. package/dist/test/jobs-spec.d.ts.map +0 -1
  30. package/dist/test/jobs-spec.js +0 -241
  31. package/dist/test/jobs-spec.js.map +0 -1
  32. package/dist/tsconfig.tsbuildinfo +0 -1
  33. package/examples/cluster.js +0 -13
  34. package/examples/list.js +0 -16
  35. package/examples/submit.js +0 -48
  36. package/src/assets.ts +0 -99
  37. package/src/client.ts +0 -197
  38. package/src/cluster.ts +0 -48
  39. package/src/ex.ts +0 -223
  40. package/src/executions.ts +0 -82
  41. package/src/index.ts +0 -39
  42. package/src/interfaces.ts +0 -12
  43. package/src/job.ts +0 -260
  44. package/src/jobs.ts +0 -66
  45. package/test/assets-spec.ts +0 -376
  46. package/test/client-spec.ts +0 -416
  47. package/test/cluster-spec.ts +0 -167
  48. package/test/ex-spec.ts +0 -628
  49. package/test/executions-spec.ts +0 -260
  50. package/test/fixtures/test.txt +0 -1
  51. package/test/job-spec.ts +0 -947
  52. package/test/jobs-spec.ts +0 -272
  53. package/tsconfig.json +0 -12
@@ -1,13 +0,0 @@
1
- /* eslint-disable no-console */
2
-
3
- import { TerasliceClient } from 'teraslice-client-js';
4
-
5
- const client = new TerasliceClient({
6
- host: 'http://localhost:5678'
7
- });
8
-
9
- const state = await client.cluster.state();
10
-
11
- const controllers = await client.cluster.controllers();
12
-
13
- console.dir({ state, controllers }, { depth: 40 });
package/examples/list.js DELETED
@@ -1,16 +0,0 @@
1
- /* eslint-disable no-console */
2
-
3
- import { TerasliceClient } from 'teraslice-client-js';
4
-
5
- const client = new TerasliceClient({
6
- host: 'http://localhost:5678'
7
- });
8
-
9
- const jobs = await client.jobs.list();
10
- const executionsCompleted = await client.executions.list('completed');
11
- const executionsRunning = await client.executions.list('running');
12
- const executionsPending = await client.executions.list('pending');
13
-
14
- console.dir({
15
- jobs, executionsCompleted, executionsRunning, executionsPending
16
- }, { depth: 40 });
@@ -1,48 +0,0 @@
1
- /* eslint-disable no-console */
2
- import { TerasliceClient } from 'teraslice-client-js';
3
-
4
- const client = new TerasliceClient({
5
- host: 'http://localhost:5678'
6
- });
7
-
8
- const exampleJob = {
9
- name: 'Data Generator',
10
- lifecycle: 'once',
11
- workers: 1,
12
- assets: ['elasticsearch', 'standard'],
13
- apis: [
14
- {
15
- _name: 'elasticsearch_sender_api',
16
- index: 'client-test-logs',
17
- type: 'events',
18
- size: 50
19
- }
20
- ],
21
- operations: [
22
- {
23
- _op: 'data_generator',
24
- size: 1
25
- },
26
- {
27
- _op: 'elasticsearch_bulk',
28
- _api_name: 'elasticsearch_sender_api'
29
- }
30
- ]
31
- };
32
-
33
- async function main() {
34
- const job = await client.jobs.submit(exampleJob);
35
-
36
- console.log(job.id());
37
-
38
- const job2 = client.jobs.wrap(job.id());
39
- const status = await job2.status();
40
-
41
- console.log(status);
42
-
43
- console.log('Waiting for the job to finish.');
44
- await job2.waitForStatus('completed');
45
- console.log('Job completed');
46
- }
47
-
48
- main();
package/src/assets.ts DELETED
@@ -1,99 +0,0 @@
1
- import { TSError, isEmpty, isString } from '@terascope/core-utils';
2
- import { Teraslice } from '@terascope/types';
3
- import path from 'node:path';
4
- import autoBind from 'auto-bind';
5
- import Client from './client.js';
6
- import { PostData, RequestOptions, ClientConfig } from './interfaces.js';
7
-
8
- export default class Assets extends Client {
9
- constructor(config: ClientConfig) {
10
- super(config);
11
- autoBind(this);
12
- }
13
-
14
- async upload(
15
- data: PostData,
16
- query: Teraslice.AssetUploadQuery = {}
17
- ): Promise<Teraslice.AssetIDResponse> {
18
- if (isEmpty(data)) {
19
- throw new TSError('Asset stream must not be empty', {
20
- statusCode: 400
21
- });
22
- }
23
-
24
- const results = await this.post('/assets', data, {
25
- searchParams: query as Record<string, any>
26
- });
27
-
28
- return this.parse(results);
29
- }
30
-
31
- async remove(
32
- id: string,
33
- searchOptions: RequestOptions = {}
34
- ): Promise<Teraslice.AssetIDResponse> {
35
- if (isEmpty(id)) {
36
- throw new TSError('Asset delete requires a ID', {
37
- statusCode: 400
38
- });
39
- }
40
-
41
- const results = await this.delete<Teraslice.AssetIDResponse>(`/assets/${id}`, searchOptions);
42
-
43
- return this.parse(results);
44
- }
45
-
46
- async list(
47
- query: Teraslice.SearchQuery = {},
48
- searchOptions: RequestOptions = {}
49
- ): Promise<Teraslice.AssetRecord[]> {
50
- const options = { ...searchOptions, searchParams: query };
51
- return this.get('/assets', options);
52
- }
53
-
54
- async getAsset(
55
- name: string,
56
- version = '',
57
- searchOptions: RequestOptions = {}
58
- ): Promise<Teraslice.AssetRecord[]> {
59
- if (!name || !isString(name)) {
60
- throw new TSError('Name is required, and must be of type string', {
61
- statusCode: 400
62
- });
63
- }
64
- if (version && !isString(version)) {
65
- throw new TSError('Version if provided must be of type string', {
66
- statusCode: 400
67
- });
68
- }
69
-
70
- const assetUrl = path.join('/assets', name, version);
71
-
72
- return this.get(assetUrl, searchOptions);
73
- }
74
-
75
- async txt(
76
- name = '',
77
- version = '',
78
- query: Teraslice.TxtSearchParams = {},
79
- searchOptions: RequestOptions = {}
80
- ): Promise<string> {
81
- if (name && !isString(name)) {
82
- throw new TSError('Name must be of type string', {
83
- statusCode: 400
84
- });
85
- }
86
- if (version && !isString(version)) {
87
- throw new TSError('Version must be of type string', {
88
- statusCode: 400
89
- });
90
- }
91
-
92
- const options = Object.assign({ responseType: 'text' }, searchOptions, {
93
- searchParams: query
94
- });
95
- const pathing = path.join('/txt/assets', name, version);
96
-
97
- return super.get(pathing, options);
98
- }
99
- }
package/src/client.ts DELETED
@@ -1,197 +0,0 @@
1
- import {
2
- isString, TSError, isPlainObject,
3
- isTest, trimStart, tryParseJSON,
4
- withoutNil,
5
- } from '@terascope/core-utils';
6
- import { STATUS_CODES } from 'node:http';
7
- import { URL } from 'node:url';
8
- import got, { type Got, HTTPError } from 'got';
9
- import { ClientConfig, RequestOptions } from './interfaces.js';
10
-
11
- export default class Client {
12
- private readonly _apiVersion: string;
13
- private readonly _request: Got;
14
- protected readonly _config: ClientConfig;
15
-
16
- constructor(config: ClientConfig = {}) {
17
- const configUrl = new URL(config.host || config.baseUrl || 'http://localhost:5678');
18
- configUrl.pathname = '';
19
- configUrl.hash = '';
20
- const prefixUrl = configUrl.toString();
21
- const { apiVersion = '/v1' } = config;
22
-
23
- this._config = config;
24
- this._apiVersion = apiVersion;
25
- this._request = got.extend({
26
- prefixUrl,
27
- headers: {
28
- 'User-Agent': 'Teraslice Client',
29
- Accept: 'application/json',
30
- },
31
- retry: {
32
- limit: isTest ? 0 : 3,
33
- maxRetryAfter: 15000 // 15 seconds
34
- },
35
- timeout: {
36
- request: config.timeout
37
- },
38
- responseType: 'json'
39
- });
40
- }
41
-
42
- async get<T = any>(endpoint: string, options?: RequestOptions): Promise<T> {
43
- return this._makeRequest<T>('get', endpoint, options);
44
- }
45
-
46
- async post<T = any>(endpoint: string, data?: unknown, options?: RequestOptions): Promise<T> {
47
- return this._makeRequest<T>('post', endpoint, options, data);
48
- }
49
-
50
- async put<T = any>(endpoint: string, data: unknown, options?: RequestOptions): Promise<T> {
51
- return this._makeRequest<T>('put', endpoint, options, data);
52
- }
53
-
54
- async delete<T = any>(endpoint: string, options?: RequestOptions): Promise<T> {
55
- return this._makeRequest<T>('delete', endpoint, options);
56
- }
57
-
58
- private async _makeRequest<T = any>(
59
- method: 'get' | 'post' | 'put' | 'delete',
60
- endpoint: string,
61
- searchOptions?: RequestOptions,
62
- data?: any
63
- ): Promise<T> {
64
- const errorMsg = validateRequestOptions(endpoint, searchOptions);
65
- if (errorMsg) {
66
- return Promise.reject(new TSError(errorMsg, {
67
- statusCode: 422
68
- }));
69
- }
70
-
71
- let options: RequestOptions;
72
- if (data != null && method.toLowerCase() !== 'get') {
73
- options = getRequestOptionsWithData(data, searchOptions ?? {});
74
- } else {
75
- options = { ...searchOptions };
76
- }
77
-
78
- // migrate to using searchParams
79
- if ((options as any).query) {
80
- options.searchParams = (options as any).query;
81
- delete (options as any).query;
82
- }
83
-
84
- // got doesn't like `undefined` values in the search params
85
- // so we need to remove them
86
- if (isPlainObject(options.searchParams)) {
87
- options.searchParams = withoutNil(options.searchParams as any);
88
- }
89
-
90
- const newEndpoint = getAPIEndpoint(endpoint, this._apiVersion);
91
- try {
92
- return await this._request[method](newEndpoint, {
93
- resolveBodyOnly: true,
94
- throwHttpErrors: true,
95
- ...options,
96
- } as any) as any as T;
97
- } catch (err) {
98
- if (err instanceof HTTPError) {
99
- throw makeErrorFromResponse(err.response);
100
- }
101
-
102
- throw err;
103
- }
104
- }
105
-
106
- protected parse(results: unknown): any {
107
- return tryParseJSON(results);
108
- }
109
-
110
- protected makeOptions(
111
- searchParams: Record<string, any> | undefined, options: RequestOptions
112
- ): RequestOptions {
113
- return { ...options, searchParams };
114
- }
115
- }
116
-
117
- function getAPIEndpoint(uri: string, apiVersion: string) {
118
- // remove start and ending slash
119
- const endpoint = uri ? uri.trim().replace(/(^\/)|(\/$)/, '') : '';
120
- if (!apiVersion) return endpoint;
121
-
122
- const txtIndex = endpoint.indexOf('txt');
123
- const isTxt = txtIndex < 2 && txtIndex > -1;
124
- if (isTxt) return endpoint;
125
-
126
- const versionPrefix = trimStart(apiVersion, '/');
127
- if (endpoint.startsWith(versionPrefix)) return endpoint;
128
- return `${versionPrefix}/${endpoint}`;
129
- }
130
-
131
- function getErrorFromResponse(response: any) {
132
- let { body } = response;
133
-
134
- if (body && isString(body)) {
135
- try {
136
- body = JSON.parse(body);
137
- } catch (err) {
138
- return { message: body };
139
- }
140
- }
141
-
142
- if (body && isPlainObject(body)) {
143
- if (isString(body.error)) {
144
- return {
145
- message: body.error
146
- };
147
- }
148
- return {
149
- message: body.message,
150
- code: body.error
151
- };
152
- }
153
- return {};
154
- }
155
-
156
- interface OldErrorOutput extends TSError {
157
- error: number;
158
- code: string;
159
- statusCode: number;
160
- }
161
-
162
- function makeErrorFromResponse(response: any): OldErrorOutput {
163
- const { statusCode } = response;
164
- const parsedError = getErrorFromResponse(response);
165
- const {
166
- message = STATUS_CODES[statusCode],
167
- code = statusCode
168
- } = parsedError;
169
-
170
- const error: Partial<OldErrorOutput> = new Error(message);
171
-
172
- error.error = code; // for legacy support
173
- error.code = code;
174
- error.statusCode = code;
175
-
176
- return error as OldErrorOutput;
177
- }
178
-
179
- // TODO: do more validations
180
- function validateRequestOptions(endpoint: string, _options?: RequestOptions) {
181
- if (!endpoint) {
182
- return 'endpoint must not be empty';
183
- }
184
- if (!isString(endpoint)) {
185
- return 'endpoint must be a string';
186
- }
187
- return null;
188
- }
189
-
190
- function getRequestOptionsWithData(
191
- data: any, options: RequestOptions
192
- ): RequestOptions {
193
- if (isPlainObject(data) || Array.isArray(data)) {
194
- return { ...options, json: data };
195
- }
196
- return { ...options, body: data };
197
- }
package/src/cluster.ts DELETED
@@ -1,48 +0,0 @@
1
- import { startsWith } from '@terascope/core-utils';
2
- import { Teraslice } from '@terascope/types';
3
- import util from 'node:util';
4
- import autoBind from 'auto-bind';
5
- import Client from './client.js';
6
-
7
- function _deprecateSlicerName(fn: () => Promise<Teraslice.ExecutionList>) {
8
- const msg = 'api endpoints with /slicers are being deprecated in favor of the semantically correct term of /controllers';
9
- return util.deprecate(fn, msg);
10
- }
11
-
12
- export default class Cluster extends Client {
13
- constructor(config: Record<string, any>) {
14
- super(config);
15
- this.slicers = _deprecateSlicerName(this.slicers);
16
- autoBind(this);
17
- }
18
-
19
- async info(): Promise<Teraslice.ApiRootResponse> {
20
- return this.get('/');
21
- }
22
-
23
- async state(): Promise<Teraslice.ClusterState> {
24
- return this.get('/cluster/state');
25
- }
26
-
27
- async stats(): Promise<Teraslice.ClusterStats> {
28
- return this.get('/cluster/stats');
29
- }
30
-
31
- async slicers(): Promise<Teraslice.ExecutionList> {
32
- return this.get('/cluster/slicers');
33
- }
34
-
35
- async controllers(): Promise<Teraslice.ExecutionList> {
36
- return this.get('/cluster/controllers');
37
- }
38
-
39
- async txt(type: string): Promise<string> {
40
- const validTypes = ['assets', 'slicers', 'ex', 'jobs', 'nodes', 'workers'];
41
- const isValid = validTypes.some((validType) => startsWith(type, validType));
42
- if (!isValid) {
43
- const error = new Error(`"${type}" is not a valid type. Must be one of ${JSON.stringify(validTypes)}`);
44
- return Promise.reject(error);
45
- }
46
- return this.get(`/txt/${type}`, { responseType: 'text' });
47
- }
48
- }
package/src/ex.ts DELETED
@@ -1,223 +0,0 @@
1
- import {
2
- isString, TSError, toString,
3
- pDelay, toHumanTime
4
- } from '@terascope/core-utils';
5
- import { Teraslice } from '@terascope/types';
6
- import autoBind from 'auto-bind';
7
- import Client from './client.js';
8
- import { ClientConfig, RequestOptions } from './interfaces.js';
9
-
10
- export default class Ex extends Client {
11
- private readonly _exId: string;
12
-
13
- constructor(config: ClientConfig, exId: string) {
14
- validateExId(exId);
15
-
16
- super(config);
17
- autoBind(this);
18
-
19
- this._exId = exId;
20
- }
21
-
22
- id(): string {
23
- return this._exId;
24
- }
25
-
26
- async stop(
27
- query?: Teraslice.StopQuery,
28
- searchOptions: RequestOptions = {}
29
- ): Promise<Teraslice.ApiStoppedResponse> {
30
- const options = this.makeOptions(query, searchOptions);
31
- return this.post(`/ex/${this._exId}/_stop`, null, options);
32
- }
33
-
34
- async pause(
35
- query?: Teraslice.SearchQuery,
36
- searchOptions: RequestOptions = {}
37
- ): Promise<Teraslice.ApiPausedResponse> {
38
- const options = this.makeOptions(query, searchOptions);
39
- return this.post(`/ex/${this._exId}/_pause`, null, options);
40
- }
41
-
42
- async resume(
43
- query?: Teraslice.SearchQuery,
44
- searchOptions: RequestOptions = {}
45
- ): Promise<Teraslice.ApiResumeResponse> {
46
- const options = this.makeOptions(query, searchOptions);
47
- return this.post(`/ex/${this._exId}/_resume`, null, options);
48
- }
49
-
50
- async recover(
51
- query: Teraslice.RecoverQuery = {},
52
- searchOptions: RequestOptions = {}
53
- ): Promise<Ex> {
54
- const options = this.makeOptions(query, searchOptions);
55
- const result: Teraslice.ApiJobCreateResponse = await this.post(`/ex/${this._exId}/_recover`, null, options);
56
-
57
- // support older version of teraslice
58
- if (!result.ex_id) {
59
- const { ex_id: exId } = await this.get(`/jobs/${result.job_id}/ex`);
60
- return new Ex(this._config, exId);
61
- }
62
-
63
- return new Ex(this._config, result.ex_id);
64
- }
65
-
66
- async status(requestOptions?: RequestOptions): Promise<Teraslice.ExecutionStatus> {
67
- const { _status: status } = await this.config(requestOptions);
68
- return status;
69
- }
70
-
71
- async slicer(requestOptions: RequestOptions = {}): Promise<Teraslice.ExecutionList> {
72
- return this.get(`/ex/${this._exId}/slicer`, requestOptions);
73
- }
74
-
75
- async controller(requestOptions: RequestOptions = {}): Promise<Teraslice.ExecutionList> {
76
- return this.get(`/ex/${this._exId}/controller`, requestOptions);
77
- }
78
-
79
- async config(requestOptions: RequestOptions = {}): Promise<Teraslice.ExecutionConfig> {
80
- return this.get(`/ex/${this._exId}`, requestOptions);
81
- }
82
-
83
- async workers(requestOptions: RequestOptions = {}): Promise<Teraslice.WorkerNode[]> {
84
- const state: Teraslice.ClusterState = await this.get('/cluster/state', requestOptions);
85
- return filterProcesses<Teraslice.WorkerNode>(state, this._exId, 'worker');
86
- }
87
-
88
- async errors(options?: Teraslice.SearchQuery): Promise<Teraslice.ErrorRecord[]> {
89
- return this.get(`/ex/${this._exId}/errors`, {
90
- searchParams: options,
91
- });
92
- }
93
-
94
- async changeWorkers(
95
- action: Teraslice.ChangeWorkerQueryParams,
96
- workerNum: number,
97
- requestOptions: RequestOptions = {}
98
- ): Promise<Teraslice.ChangeWorkerResponse | string> {
99
- if (action == null || workerNum == null) {
100
- throw new TSError('Change workers requires action and count', {
101
- statusCode: 400
102
- });
103
- }
104
- if (!['add', 'remove', 'total'].includes(action)) {
105
- throw new TSError('Change workers requires action to be one of add, remove, or total', {
106
- statusCode: 400
107
- });
108
- }
109
-
110
- const query = { [action]: workerNum };
111
- requestOptions.responseType = 'text';
112
- const options = this.makeOptions(query, requestOptions);
113
-
114
- const response = await this.post(`/ex/${this._exId}/_workers`, null, options);
115
- // for backwards compatibility
116
- if (typeof response === 'string') {
117
- try {
118
- return this.parse(response);
119
- } catch (err) {
120
- // do nothing
121
- }
122
- }
123
-
124
- return response;
125
- }
126
-
127
- async waitForStatus(
128
- target: Teraslice.ExecutionStatus,
129
- intervalMs = 1000,
130
- timeoutMs = 0,
131
- requestOptions: RequestOptions = {}
132
- ): Promise<Teraslice.ExecutionStatus> {
133
- const terminal = {
134
- [Teraslice.ExecutionStatusEnum.terminated]: true,
135
- [Teraslice.ExecutionStatusEnum.failed]: true,
136
- [Teraslice.ExecutionStatusEnum.rejected]: true,
137
- [Teraslice.ExecutionStatusEnum.completed]: true,
138
- [Teraslice.ExecutionStatusEnum.stopped]: true,
139
- };
140
-
141
- const startTime = Date.now();
142
- const options = Object.assign({}, {
143
- responseType: 'json',
144
- timeout: {
145
- request: intervalMs < 1000 ? 1000 : intervalMs
146
- },
147
- }, requestOptions);
148
-
149
- const checkStatus = async (): Promise<Teraslice.ExecutionStatus> => {
150
- let result;
151
- try {
152
- result = await this.status(options);
153
- } catch (err) {
154
- if (/(timeout|timedout)/i.test(toString(err))) {
155
- await pDelay(intervalMs);
156
- return checkStatus();
157
- }
158
- throw err;
159
- }
160
-
161
- if (result === target) {
162
- return result;
163
- }
164
-
165
- // These are terminal states for a job so if we're not explicitly
166
- // watching for these then we need to stop waiting as the job
167
- // status won't change further.
168
- if (result in terminal) {
169
- throw new TSError(
170
- `Execution cannot reach the target status, "${target}", because it is in the terminal state, "${result}"`,
171
- { context: { lastStatus: result } }
172
- );
173
- }
174
-
175
- const elapsed = Date.now() - startTime;
176
- if (timeoutMs > 0 && elapsed >= timeoutMs) {
177
- throw new TSError(
178
- `Execution status failed to change from status "${result}" to "${target}" within ${toHumanTime(timeoutMs)}`,
179
- { context: { lastStatus: result } }
180
- );
181
- }
182
-
183
- await pDelay(intervalMs);
184
- return checkStatus();
185
- };
186
-
187
- return checkStatus();
188
- }
189
- }
190
-
191
- function validateExId(exId?: string) {
192
- if (!exId) {
193
- throw new TSError('Ex requires exId', {
194
- statusCode: 400
195
- });
196
- }
197
- if (!isString(exId)) {
198
- throw new TSError('Ex requires exId to be a string', {
199
- statusCode: 400
200
- });
201
- }
202
- }
203
-
204
- function filterProcesses<T>(
205
- state: Teraslice.ClusterState,
206
- exId: string,
207
- type: Teraslice.Assignment
208
- ) {
209
- const results: T[] = [];
210
-
211
- for (const node of Object.values(state)) {
212
- // TODO: fixme
213
- node.active.forEach((child: any) => {
214
- const { assignment, ex_id: procExId } = child;
215
- if ((assignment && assignment === type) && (procExId && procExId === exId)) {
216
- const jobProcess = Object.assign({}, child, { node_id: node.node_id });
217
- results.push(jobProcess as any);
218
- }
219
- });
220
- }
221
-
222
- return results;
223
- }