@workflow/cli 4.0.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +3 -0
- package/bin/run.js +5 -0
- package/dist/base.d.ts +8 -0
- package/dist/base.d.ts.map +1 -0
- package/dist/base.js +14 -0
- package/dist/base.js.map +1 -0
- package/dist/commands/build.d.ts +14 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +78 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/cancel.d.ts +25 -0
- package/dist/commands/cancel.d.ts.map +1 -0
- package/dist/commands/cancel.js +30 -0
- package/dist/commands/cancel.js.map +1 -0
- package/dist/commands/dev.d.ts +11 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +34 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +42 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/inspect.d.ts +31 -0
- package/dist/commands/inspect.d.ts.map +1 -0
- package/dist/commands/inspect.js +209 -0
- package/dist/commands/inspect.js.map +1 -0
- package/dist/commands/start.d.ts +26 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +43 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/validate.d.ts +12 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +45 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/lib/builders/apply-swc-transform.d.ts +24 -0
- package/dist/lib/builders/apply-swc-transform.d.ts.map +1 -0
- package/dist/lib/builders/apply-swc-transform.js +38 -0
- package/dist/lib/builders/apply-swc-transform.js.map +1 -0
- package/dist/lib/builders/base-builder.d.ts +45 -0
- package/dist/lib/builders/base-builder.d.ts.map +1 -0
- package/dist/lib/builders/base-builder.js +466 -0
- package/dist/lib/builders/base-builder.js.map +1 -0
- package/dist/lib/builders/discover-entries-esbuild-plugin.d.ts +11 -0
- package/dist/lib/builders/discover-entries-esbuild-plugin.d.ts.map +1 -0
- package/dist/lib/builders/discover-entries-esbuild-plugin.js +84 -0
- package/dist/lib/builders/discover-entries-esbuild-plugin.js.map +1 -0
- package/dist/lib/builders/next-build.d.ts +11 -0
- package/dist/lib/builders/next-build.d.ts.map +1 -0
- package/dist/lib/builders/next-build.js +331 -0
- package/dist/lib/builders/next-build.js.map +1 -0
- package/dist/lib/builders/node-module-esbuild-plugin.d.ts +3 -0
- package/dist/lib/builders/node-module-esbuild-plugin.d.ts.map +1 -0
- package/dist/lib/builders/node-module-esbuild-plugin.js +24 -0
- package/dist/lib/builders/node-module-esbuild-plugin.js.map +1 -0
- package/dist/lib/builders/node-module-esbuild-plugin.test.d.ts +2 -0
- package/dist/lib/builders/node-module-esbuild-plugin.test.d.ts.map +1 -0
- package/dist/lib/builders/node-module-esbuild-plugin.test.js +128 -0
- package/dist/lib/builders/node-module-esbuild-plugin.test.js.map +1 -0
- package/dist/lib/builders/swc-esbuild-plugin.d.ts +12 -0
- package/dist/lib/builders/swc-esbuild-plugin.d.ts.map +1 -0
- package/dist/lib/builders/swc-esbuild-plugin.js +134 -0
- package/dist/lib/builders/swc-esbuild-plugin.js.map +1 -0
- package/dist/lib/builders/vercel-build-output-api.d.ts +9 -0
- package/dist/lib/builders/vercel-build-output-api.d.ts.map +1 -0
- package/dist/lib/builders/vercel-build-output-api.js +138 -0
- package/dist/lib/builders/vercel-build-output-api.js.map +1 -0
- package/dist/lib/builders/vercel-static.d.ts +7 -0
- package/dist/lib/builders/vercel-static.d.ts.map +1 -0
- package/dist/lib/builders/vercel-static.js +42 -0
- package/dist/lib/builders/vercel-static.js.map +1 -0
- package/dist/lib/builders/webhook-route.test.d.ts +2 -0
- package/dist/lib/builders/webhook-route.test.d.ts.map +1 -0
- package/dist/lib/builders/webhook-route.test.js +199 -0
- package/dist/lib/builders/webhook-route.test.js.map +1 -0
- package/dist/lib/config/log.d.ts +42 -0
- package/dist/lib/config/log.d.ts.map +1 -0
- package/dist/lib/config/log.js +95 -0
- package/dist/lib/config/log.js.map +1 -0
- package/dist/lib/config/types.d.ts +28 -0
- package/dist/lib/config/types.d.ts.map +1 -0
- package/dist/lib/config/types.js +9 -0
- package/dist/lib/config/types.js.map +1 -0
- package/dist/lib/config/workflow-config.d.ts +6 -0
- package/dist/lib/config/workflow-config.d.ts.map +1 -0
- package/dist/lib/config/workflow-config.js +16 -0
- package/dist/lib/config/workflow-config.js.map +1 -0
- package/dist/lib/inspect/auth.d.ts +20 -0
- package/dist/lib/inspect/auth.d.ts.map +1 -0
- package/dist/lib/inspect/auth.js +54 -0
- package/dist/lib/inspect/auth.js.map +1 -0
- package/dist/lib/inspect/env.d.ts +25 -0
- package/dist/lib/inspect/env.d.ts.map +1 -0
- package/dist/lib/inspect/env.js +158 -0
- package/dist/lib/inspect/env.js.map +1 -0
- package/dist/lib/inspect/flags.d.ts +14 -0
- package/dist/lib/inspect/flags.d.ts.map +1 -0
- package/dist/lib/inspect/flags.js +110 -0
- package/dist/lib/inspect/flags.js.map +1 -0
- package/dist/lib/inspect/output.d.ts +31 -0
- package/dist/lib/inspect/output.d.ts.map +1 -0
- package/dist/lib/inspect/output.js +899 -0
- package/dist/lib/inspect/output.js.map +1 -0
- package/dist/lib/inspect/pagination.d.ts +55 -0
- package/dist/lib/inspect/pagination.d.ts.map +1 -0
- package/dist/lib/inspect/pagination.js +193 -0
- package/dist/lib/inspect/pagination.js.map +1 -0
- package/dist/lib/inspect/run.d.ts +9 -0
- package/dist/lib/inspect/run.d.ts.map +1 -0
- package/dist/lib/inspect/run.js +30 -0
- package/dist/lib/inspect/run.js.map +1 -0
- package/dist/lib/inspect/setup.d.ts +10 -0
- package/dist/lib/inspect/setup.d.ts.map +1 -0
- package/dist/lib/inspect/setup.js +33 -0
- package/dist/lib/inspect/setup.js.map +1 -0
- package/dist/lib/inspect/stream.d.ts +7 -0
- package/dist/lib/inspect/stream.d.ts.map +1 -0
- package/dist/lib/inspect/stream.js +50 -0
- package/dist/lib/inspect/stream.js.map +1 -0
- package/dist/lib/inspect/terminal-utils.d.ts +36 -0
- package/dist/lib/inspect/terminal-utils.d.ts.map +1 -0
- package/dist/lib/inspect/terminal-utils.js +109 -0
- package/dist/lib/inspect/terminal-utils.js.map +1 -0
- package/dist/lib/inspect/vercel-api.d.ts +12 -0
- package/dist/lib/inspect/vercel-api.d.ts.map +1 -0
- package/dist/lib/inspect/vercel-api.js +89 -0
- package/dist/lib/inspect/vercel-api.js.map +1 -0
- package/dist/lib/inspect/vercel-link.d.ts +98 -0
- package/dist/lib/inspect/vercel-link.d.ts.map +1 -0
- package/dist/lib/inspect/vercel-link.js +268 -0
- package/dist/lib/inspect/vercel-link.js.map +1 -0
- package/dist/lib/inspect/web.d.ts +9 -0
- package/dist/lib/inspect/web.d.ts.map +1 -0
- package/dist/lib/inspect/web.js +305 -0
- package/dist/lib/inspect/web.js.map +1 -0
- package/dist/lib/runtime.d.ts +2 -0
- package/dist/lib/runtime.d.ts.map +1 -0
- package/dist/lib/runtime.js +5 -0
- package/dist/lib/runtime.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,899 @@
|
|
|
1
|
+
import { hydrateResourceIO } from '@workflow/core/observability';
|
|
2
|
+
import { parseStepName, parseWorkflowName } from '@workflow/core/parse-name';
|
|
3
|
+
import { getRun } from '@workflow/core/runtime';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { formatDistance } from 'date-fns';
|
|
6
|
+
import Table from 'easy-table';
|
|
7
|
+
import { logger } from '../config/log.js';
|
|
8
|
+
import { setupListPagination } from './pagination.js';
|
|
9
|
+
import { streamToConsole } from './stream.js';
|
|
10
|
+
import { formatISODate, formatStatus as formatStatusAbbrev, getDisplaySettings, getTerminalWidth, isCI, } from './terminal-utils.js';
|
|
11
|
+
const DEFAULT_PAGE_SIZE = 20;
|
|
12
|
+
let TABLE_TRUNCATE_IO_LENGTH = 15; // Will be adjusted based on terminal width
|
|
13
|
+
const WORKFLOW_RUN_IO_PROPS = ['input', 'output'];
|
|
14
|
+
const STEP_IO_PROPS = ['input', 'output'];
|
|
15
|
+
const WORKFLOW_RUN_LISTED_PROPS = [
|
|
16
|
+
'runId',
|
|
17
|
+
'workflowName',
|
|
18
|
+
'status',
|
|
19
|
+
'startedAt',
|
|
20
|
+
'completedAt',
|
|
21
|
+
...WORKFLOW_RUN_IO_PROPS,
|
|
22
|
+
];
|
|
23
|
+
const STEP_LISTED_PROPS = [
|
|
24
|
+
'runId',
|
|
25
|
+
'stepId',
|
|
26
|
+
'stepName',
|
|
27
|
+
'status',
|
|
28
|
+
'startedAt',
|
|
29
|
+
'completedAt',
|
|
30
|
+
...STEP_IO_PROPS,
|
|
31
|
+
];
|
|
32
|
+
const EVENT_IO_PROPS = ['eventData'];
|
|
33
|
+
const EVENT_LISTED_PROPS = [
|
|
34
|
+
'eventId',
|
|
35
|
+
'eventType',
|
|
36
|
+
'correlationId',
|
|
37
|
+
'createdAt',
|
|
38
|
+
...EVENT_IO_PROPS,
|
|
39
|
+
];
|
|
40
|
+
// const HOOK_DATA_PROPS: (keyof Hook | 'hasResponse')[] = ['hasResponse'];
|
|
41
|
+
const HOOK_LISTED_PROPS = [
|
|
42
|
+
'runId',
|
|
43
|
+
'hookId',
|
|
44
|
+
'ownerId',
|
|
45
|
+
'createdAt',
|
|
46
|
+
// ...HOOK_DATA_PROPS,
|
|
47
|
+
];
|
|
48
|
+
const STATUS_COLORS = {
|
|
49
|
+
running: chalk.blue,
|
|
50
|
+
completed: chalk.green,
|
|
51
|
+
failed: chalk.red,
|
|
52
|
+
cancelled: chalk.strikethrough.yellow,
|
|
53
|
+
pending: chalk.blue,
|
|
54
|
+
paused: chalk.yellow,
|
|
55
|
+
};
|
|
56
|
+
const isStreamId = (value) => {
|
|
57
|
+
return typeof value === 'string' && value.startsWith('strm_');
|
|
58
|
+
};
|
|
59
|
+
const showStatusLegend = () => {
|
|
60
|
+
logger.log('\nStatus Legend:');
|
|
61
|
+
const statuses = [
|
|
62
|
+
'running',
|
|
63
|
+
'completed',
|
|
64
|
+
'failed',
|
|
65
|
+
'cancelled',
|
|
66
|
+
'pending',
|
|
67
|
+
'paused',
|
|
68
|
+
];
|
|
69
|
+
const legendItems = statuses.map((status) => {
|
|
70
|
+
const colorFunc = STATUS_COLORS[status];
|
|
71
|
+
const abbrev = formatStatusAbbrev(status, true);
|
|
72
|
+
return `${colorFunc(abbrev)} = ${status}`;
|
|
73
|
+
});
|
|
74
|
+
logger.log(` ${legendItems.join(' ')}`);
|
|
75
|
+
logger.log('');
|
|
76
|
+
};
|
|
77
|
+
const isSleepStep = (stepName) => {
|
|
78
|
+
return stepName.includes('-sleep');
|
|
79
|
+
};
|
|
80
|
+
const checkAndHandleVercelAccessError = (error, backend) => {
|
|
81
|
+
if (backend === 'vercel' && error && typeof error === 'object') {
|
|
82
|
+
const err = error;
|
|
83
|
+
if (err.status === 403) {
|
|
84
|
+
logger.error('Your current vercel account does not have access to this workflow run. Please use `vercel login` to login, or use `vercel switch` to ensure you can access the correct team.');
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
};
|
|
90
|
+
const extractErrorMessage = (err) => {
|
|
91
|
+
if (err.message && typeof err.message === 'string') {
|
|
92
|
+
return err.message;
|
|
93
|
+
}
|
|
94
|
+
if (err.body && typeof err.body === 'object') {
|
|
95
|
+
const body = err.body;
|
|
96
|
+
if (body.message && typeof body.message === 'string') {
|
|
97
|
+
return body.message;
|
|
98
|
+
}
|
|
99
|
+
if (body.error && typeof body.error === 'string') {
|
|
100
|
+
return body.error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return undefined;
|
|
104
|
+
};
|
|
105
|
+
const handleApiError = (error, backend) => {
|
|
106
|
+
// First check for Vercel access errors
|
|
107
|
+
if (checkAndHandleVercelAccessError(error, backend)) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
// Handle other HTTP errors
|
|
111
|
+
if (error && typeof error === 'object') {
|
|
112
|
+
const err = error;
|
|
113
|
+
// Handle 400 Bad Request
|
|
114
|
+
if (err.status === 400) {
|
|
115
|
+
logger.error('Bad Request: The request was invalid.');
|
|
116
|
+
const message = extractErrorMessage(err);
|
|
117
|
+
if (message) {
|
|
118
|
+
logger.error(`Details: ${message}`);
|
|
119
|
+
}
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
// Handle other HTTP errors (404, 500, etc.)
|
|
123
|
+
if (typeof err.status === 'number' && err.status >= 400) {
|
|
124
|
+
logger.error(`HTTP Error ${err.status}: ${getStatusText(err.status)}`);
|
|
125
|
+
const message = extractErrorMessage(err);
|
|
126
|
+
if (message) {
|
|
127
|
+
logger.error(`Details: ${message}`);
|
|
128
|
+
}
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return false;
|
|
133
|
+
};
|
|
134
|
+
const getStatusText = (status) => {
|
|
135
|
+
const statusTexts = {
|
|
136
|
+
400: 'Bad Request',
|
|
137
|
+
401: 'Unauthorized',
|
|
138
|
+
403: 'Forbidden',
|
|
139
|
+
404: 'Not Found',
|
|
140
|
+
500: 'Internal Server Error',
|
|
141
|
+
502: 'Bad Gateway',
|
|
142
|
+
503: 'Service Unavailable',
|
|
143
|
+
};
|
|
144
|
+
return statusTexts[status] || 'Unknown Error';
|
|
145
|
+
};
|
|
146
|
+
const truncateNameIfNeeded = (name, maxLength) => {
|
|
147
|
+
return maxLength < name.length ? `${name.substring(0, maxLength)}...` : name;
|
|
148
|
+
};
|
|
149
|
+
const formatNameField = (nameNonUnique, truncateLength, isSleep) => {
|
|
150
|
+
const truncatedName = truncateNameIfNeeded(nameNonUnique, truncateLength);
|
|
151
|
+
if (isSleep) {
|
|
152
|
+
return chalk.yellowBright(truncatedName);
|
|
153
|
+
}
|
|
154
|
+
return chalk.blue.blueBright(truncatedName);
|
|
155
|
+
};
|
|
156
|
+
const formatIdField = (prop, value, shouldTruncateIds) => {
|
|
157
|
+
const valueStr = String(value);
|
|
158
|
+
const idStr = shouldTruncateIds ? truncateIdToLastChars(valueStr) : valueStr;
|
|
159
|
+
if (prop === 'streamId') {
|
|
160
|
+
return chalk.green(idStr);
|
|
161
|
+
}
|
|
162
|
+
return idStr;
|
|
163
|
+
};
|
|
164
|
+
const formatTableValue = (prop, value, opts = {}, displaySettings) => {
|
|
165
|
+
const namesTruncate = displaySettings?.namesTruncateLength ?? 40;
|
|
166
|
+
const shouldTruncateIds = displaySettings?.truncateIdsToLastChars ?? false;
|
|
167
|
+
// Handle IDs with potential truncation
|
|
168
|
+
if ([
|
|
169
|
+
'streamId',
|
|
170
|
+
'runId',
|
|
171
|
+
'stepId',
|
|
172
|
+
'hookId',
|
|
173
|
+
'eventId',
|
|
174
|
+
'correlationId',
|
|
175
|
+
'ownerId',
|
|
176
|
+
].includes(prop)) {
|
|
177
|
+
return formatIdField(prop, value, shouldTruncateIds);
|
|
178
|
+
}
|
|
179
|
+
// Handle names with truncation
|
|
180
|
+
if (prop === 'stepName') {
|
|
181
|
+
const nameNonUnique = parseStepName(String(value))?.shortName || '?';
|
|
182
|
+
return formatNameField(nameNonUnique, namesTruncate, isSleepStep(String(value)));
|
|
183
|
+
}
|
|
184
|
+
if (prop === 'workflowName') {
|
|
185
|
+
const nameNonUnique = parseWorkflowName(String(value))?.shortName || '?';
|
|
186
|
+
const truncatedName = truncateNameIfNeeded(nameNonUnique, namesTruncate);
|
|
187
|
+
return chalk.blue.blueBright(truncatedName);
|
|
188
|
+
}
|
|
189
|
+
if (prop === 'output' || prop === 'input') {
|
|
190
|
+
return inlineFormatIO(value);
|
|
191
|
+
}
|
|
192
|
+
if (prop === 'status') {
|
|
193
|
+
const status = value;
|
|
194
|
+
const colorFunc = STATUS_COLORS[status];
|
|
195
|
+
const formattedStatus = displaySettings?.abbreviateStatus
|
|
196
|
+
? formatStatusAbbrev(status, true)
|
|
197
|
+
: status;
|
|
198
|
+
return colorFunc(formattedStatus);
|
|
199
|
+
}
|
|
200
|
+
if (prop === 'eventData') {
|
|
201
|
+
return truncateString(JSON.stringify(value));
|
|
202
|
+
}
|
|
203
|
+
if (prop === 'hasResponse') {
|
|
204
|
+
return value ? chalk.green('true') : chalk.gray('false');
|
|
205
|
+
}
|
|
206
|
+
if (value instanceof Date) {
|
|
207
|
+
return formatTableTimestamp(value, opts, displaySettings);
|
|
208
|
+
}
|
|
209
|
+
return value;
|
|
210
|
+
};
|
|
211
|
+
const getVisibleProps = (props, displaySettings) => {
|
|
212
|
+
if (displaySettings.hideCompletedAt) {
|
|
213
|
+
return props.filter((prop) => prop !== 'completedAt');
|
|
214
|
+
}
|
|
215
|
+
return props;
|
|
216
|
+
};
|
|
217
|
+
const showTable = (data, props, opts = {}) => {
|
|
218
|
+
// Get display settings based on terminal width
|
|
219
|
+
const terminalWidth = getTerminalWidth();
|
|
220
|
+
const displaySettings = getDisplaySettings(terminalWidth, opts.withData || false, props.includes('runName'));
|
|
221
|
+
// Filter out completedAt column if needed
|
|
222
|
+
const visibleProps = getVisibleProps(props, displaySettings);
|
|
223
|
+
// Update truncate length for IO fields
|
|
224
|
+
const originalTruncateLength = TABLE_TRUNCATE_IO_LENGTH;
|
|
225
|
+
TABLE_TRUNCATE_IO_LENGTH = displaySettings.dataFieldWidth;
|
|
226
|
+
// Show status legend if using abbreviated status
|
|
227
|
+
if (displaySettings.abbreviateStatus && visibleProps.includes('status')) {
|
|
228
|
+
showStatusLegend();
|
|
229
|
+
}
|
|
230
|
+
// Create header mapping for abbreviated status
|
|
231
|
+
const headerMap = {};
|
|
232
|
+
if (displaySettings.abbreviateStatus && visibleProps.includes('status')) {
|
|
233
|
+
headerMap['status'] = 'S';
|
|
234
|
+
}
|
|
235
|
+
// Add a blank line before any table
|
|
236
|
+
const table = new Table();
|
|
237
|
+
if (data && data.length === 0) {
|
|
238
|
+
logger.warn('No data found for this query and resource.\n');
|
|
239
|
+
for (const prop of visibleProps) {
|
|
240
|
+
const header = headerMap[prop] || prop;
|
|
241
|
+
table.cell(header, 'N/A');
|
|
242
|
+
}
|
|
243
|
+
table.newRow();
|
|
244
|
+
// Restore original truncate length
|
|
245
|
+
TABLE_TRUNCATE_IO_LENGTH = originalTruncateLength;
|
|
246
|
+
return table.toString();
|
|
247
|
+
}
|
|
248
|
+
else if (!data) {
|
|
249
|
+
logger.warn('Expecting an array of data, but got null.\n');
|
|
250
|
+
}
|
|
251
|
+
logger.log('');
|
|
252
|
+
for (const item of data) {
|
|
253
|
+
for (const prop of visibleProps) {
|
|
254
|
+
const header = headerMap[prop] || prop;
|
|
255
|
+
const value = item[prop];
|
|
256
|
+
table.cell(header, formatTableValue(prop, value, opts, displaySettings));
|
|
257
|
+
}
|
|
258
|
+
table.newRow();
|
|
259
|
+
}
|
|
260
|
+
// Restore original truncate length
|
|
261
|
+
TABLE_TRUNCATE_IO_LENGTH = originalTruncateLength;
|
|
262
|
+
return table.toString();
|
|
263
|
+
};
|
|
264
|
+
const showJson = (data) => {
|
|
265
|
+
const json = JSON.stringify(data, null, 2);
|
|
266
|
+
process.stdout.write(`${json}\n`);
|
|
267
|
+
};
|
|
268
|
+
const getCursorHint = ({ hasMore, cursor, }) => {
|
|
269
|
+
// Only show cursor hint in non-interactive mode (e.g., CI or when piped)
|
|
270
|
+
if (!isCI() && process.stdout.isTTY) {
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
273
|
+
if (hasMore && cursor) {
|
|
274
|
+
return `More results available. Append\n--cursor "${cursor}"\nto this command to fetch the next page.`;
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* In tables, we want to show a shorter timestamp, YYYY-MM-DD HH:MM:SS
|
|
279
|
+
*/
|
|
280
|
+
const formatTableTimestamp = (value, opts = {}, displaySettings) => {
|
|
281
|
+
// Format ISO time without T and Z
|
|
282
|
+
const isoTime = formatISODate(value);
|
|
283
|
+
// Show relative time only if:
|
|
284
|
+
// - Not in CI mode
|
|
285
|
+
// - Display settings allow it (based on terminal width)
|
|
286
|
+
// - withData is disabled (more space available)
|
|
287
|
+
// - Not in JSON mode
|
|
288
|
+
const shouldShowRelative = !isCI() &&
|
|
289
|
+
displaySettings?.showRelativeDates !== false &&
|
|
290
|
+
!opts.withData &&
|
|
291
|
+
!opts.json;
|
|
292
|
+
if (shouldShowRelative) {
|
|
293
|
+
const relative = formatDistance(value, new Date(), { addSuffix: true });
|
|
294
|
+
return `${isoTime} (${relative})`;
|
|
295
|
+
}
|
|
296
|
+
return isoTime;
|
|
297
|
+
};
|
|
298
|
+
const truncateString = (str, maxLength = TABLE_TRUNCATE_IO_LENGTH) => {
|
|
299
|
+
return str && str.length > maxLength
|
|
300
|
+
? `${str.substring(0, maxLength)}...`
|
|
301
|
+
: str;
|
|
302
|
+
};
|
|
303
|
+
const truncateIdToLastChars = (id, chars = 4) => {
|
|
304
|
+
if (!id || id.length <= chars)
|
|
305
|
+
return id;
|
|
306
|
+
return `...${id.substring(id.length - chars)}`;
|
|
307
|
+
};
|
|
308
|
+
const showInspectInfoBox = (resource) => {
|
|
309
|
+
logger.info(`To view details for a ${resource}, use \`wf i ${resource}\` <id>`);
|
|
310
|
+
logger.info(`To view the content of any stream, use \`wf i stream <stream-id>\``);
|
|
311
|
+
};
|
|
312
|
+
/**
|
|
313
|
+
* Takes hydrated step/workflow input/output and serializes it for inline display.
|
|
314
|
+
*/
|
|
315
|
+
const inlineFormatIO = (io, topLevel = true) => {
|
|
316
|
+
const type = typeof io;
|
|
317
|
+
let value = '';
|
|
318
|
+
if (io === undefined) {
|
|
319
|
+
value = '<empty>';
|
|
320
|
+
}
|
|
321
|
+
else if (io === null) {
|
|
322
|
+
value = '<null>';
|
|
323
|
+
}
|
|
324
|
+
else if (io && Array.isArray(io)) {
|
|
325
|
+
if (io.length === 0) {
|
|
326
|
+
value = '<empty>';
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
const stringified = io
|
|
330
|
+
.map((item) => inlineFormatIO(item, false))
|
|
331
|
+
.join(',');
|
|
332
|
+
if (stringified.length > TABLE_TRUNCATE_IO_LENGTH && topLevel) {
|
|
333
|
+
value = chalk.yellow(`${io.length} args`);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
value = stringified;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
else if (type === 'object') {
|
|
341
|
+
if (isStreamId(io)) {
|
|
342
|
+
value = io.toString();
|
|
343
|
+
}
|
|
344
|
+
else if (io instanceof Date) {
|
|
345
|
+
value = io.toISOString();
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
value = truncateString(JSON.stringify(io));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
else if (['string', 'number', 'boolean'].includes(type)) {
|
|
352
|
+
if (type === 'string' && io.includes('strm_')) {
|
|
353
|
+
value = io;
|
|
354
|
+
}
|
|
355
|
+
value = truncateString(String(io));
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
value = `<${type}>`;
|
|
359
|
+
}
|
|
360
|
+
return value;
|
|
361
|
+
};
|
|
362
|
+
export const listRuns = async (world, opts = {}) => {
|
|
363
|
+
if (opts.stepId || opts.runId) {
|
|
364
|
+
logger.warn('Filtering by step-id or run-id is not supported in list calls, ignoring filter.');
|
|
365
|
+
}
|
|
366
|
+
const resolveData = opts.withData ? 'all' : 'none';
|
|
367
|
+
// Determine which props to show based on withData flag
|
|
368
|
+
const props = opts.withData
|
|
369
|
+
? WORKFLOW_RUN_LISTED_PROPS
|
|
370
|
+
: WORKFLOW_RUN_LISTED_PROPS.filter((prop) => !WORKFLOW_RUN_IO_PROPS.includes(prop));
|
|
371
|
+
// For JSON output, just fetch once and return
|
|
372
|
+
if (opts.json) {
|
|
373
|
+
try {
|
|
374
|
+
const runs = await world.runs.list({
|
|
375
|
+
workflowName: opts.workflowName,
|
|
376
|
+
pagination: {
|
|
377
|
+
sortOrder: opts.sort || 'desc',
|
|
378
|
+
cursor: opts.cursor,
|
|
379
|
+
limit: opts.limit || DEFAULT_PAGE_SIZE,
|
|
380
|
+
},
|
|
381
|
+
resolveData,
|
|
382
|
+
});
|
|
383
|
+
const runsWithHydratedIO = runs.data.map(hydrateResourceIO);
|
|
384
|
+
showJson({ ...runs, data: runsWithHydratedIO });
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
catch (error) {
|
|
388
|
+
if (handleApiError(error, opts.backend)) {
|
|
389
|
+
process.exit(1);
|
|
390
|
+
}
|
|
391
|
+
throw error;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
await setupListPagination({
|
|
395
|
+
initialCursor: opts.cursor,
|
|
396
|
+
fetchPage: async (cursor) => {
|
|
397
|
+
try {
|
|
398
|
+
const runs = await world.runs.list({
|
|
399
|
+
workflowName: opts.workflowName,
|
|
400
|
+
pagination: {
|
|
401
|
+
sortOrder: opts.sort || 'desc',
|
|
402
|
+
cursor,
|
|
403
|
+
limit: opts.limit || DEFAULT_PAGE_SIZE,
|
|
404
|
+
},
|
|
405
|
+
resolveData,
|
|
406
|
+
});
|
|
407
|
+
return {
|
|
408
|
+
data: runs.data,
|
|
409
|
+
cursor: runs.cursor,
|
|
410
|
+
hasMore: runs.hasMore,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
catch (error) {
|
|
414
|
+
if (handleApiError(error, opts.backend)) {
|
|
415
|
+
process.exit(1);
|
|
416
|
+
}
|
|
417
|
+
throw error;
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
displayPage: async (runs) => {
|
|
421
|
+
const runsWithHydratedIO = runs.map(hydrateResourceIO);
|
|
422
|
+
logger.log(showTable(runsWithHydratedIO, props, opts));
|
|
423
|
+
},
|
|
424
|
+
});
|
|
425
|
+
};
|
|
426
|
+
export const getRecentRun = async (world, opts = {}) => {
|
|
427
|
+
logger.warn(`No runId provided, fetching data for latest run instead.`);
|
|
428
|
+
try {
|
|
429
|
+
const runs = await world.runs.list({
|
|
430
|
+
pagination: { limit: 1, sortOrder: opts.sort || 'desc' },
|
|
431
|
+
resolveData: 'none', // Don't need data for just getting the ID
|
|
432
|
+
});
|
|
433
|
+
runs.data = runs.data.map(hydrateResourceIO);
|
|
434
|
+
return runs.data[0];
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
if (handleApiError(error, opts.backend)) {
|
|
438
|
+
process.exit(1);
|
|
439
|
+
}
|
|
440
|
+
throw error;
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
export const showRun = async (world, runId, opts = {}) => {
|
|
444
|
+
if (opts.withData) {
|
|
445
|
+
logger.warn('`withData` flag is ignored when showing individual resources');
|
|
446
|
+
}
|
|
447
|
+
try {
|
|
448
|
+
const run = await world.runs.get(runId, { resolveData: 'all' });
|
|
449
|
+
const runWithHydratedIO = hydrateResourceIO(run);
|
|
450
|
+
if (opts.json) {
|
|
451
|
+
showJson(runWithHydratedIO);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
logger.log(runWithHydratedIO);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
catch (error) {
|
|
459
|
+
if (handleApiError(error, opts.backend)) {
|
|
460
|
+
process.exit(1);
|
|
461
|
+
}
|
|
462
|
+
throw error;
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
export const listSteps = async (world, opts = {
|
|
466
|
+
runId: undefined,
|
|
467
|
+
}) => {
|
|
468
|
+
if (opts.stepId) {
|
|
469
|
+
logger.warn('Filtering by step-id is not supported in list calls, ignoring filter.');
|
|
470
|
+
}
|
|
471
|
+
if (opts.workflowName) {
|
|
472
|
+
logger.warn('Filtering by workflow-name is not supported for steps, ignoring filter.');
|
|
473
|
+
}
|
|
474
|
+
const runId = opts.runId
|
|
475
|
+
? opts.runId
|
|
476
|
+
: (await getRecentRun(world, opts))?.runId;
|
|
477
|
+
if (!runId) {
|
|
478
|
+
logger.error('No run found.');
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
const resolveData = opts.withData ? 'all' : 'none';
|
|
482
|
+
// Determine which props to show based on withData flag
|
|
483
|
+
const props = opts.withData
|
|
484
|
+
? STEP_LISTED_PROPS
|
|
485
|
+
: STEP_LISTED_PROPS.filter((prop) => !STEP_IO_PROPS.includes(prop));
|
|
486
|
+
// For JSON output, just fetch once and return
|
|
487
|
+
if (opts.json) {
|
|
488
|
+
logger.debug(`Fetching steps for run ${runId}`);
|
|
489
|
+
try {
|
|
490
|
+
const stepChunks = await world.steps.list({
|
|
491
|
+
runId,
|
|
492
|
+
pagination: {
|
|
493
|
+
sortOrder: opts.sort || 'desc',
|
|
494
|
+
cursor: opts.cursor,
|
|
495
|
+
limit: opts.limit || DEFAULT_PAGE_SIZE,
|
|
496
|
+
},
|
|
497
|
+
resolveData,
|
|
498
|
+
});
|
|
499
|
+
showJson(stepChunks.data);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
catch (error) {
|
|
503
|
+
if (handleApiError(error, opts.backend)) {
|
|
504
|
+
process.exit(1);
|
|
505
|
+
}
|
|
506
|
+
throw error;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
await setupListPagination({
|
|
510
|
+
initialCursor: opts.cursor,
|
|
511
|
+
fetchPage: async (cursor) => {
|
|
512
|
+
logger.debug(`Fetching steps for run ${runId}`);
|
|
513
|
+
try {
|
|
514
|
+
const stepChunks = await world.steps.list({
|
|
515
|
+
runId,
|
|
516
|
+
pagination: {
|
|
517
|
+
sortOrder: opts.sort || 'desc',
|
|
518
|
+
cursor,
|
|
519
|
+
limit: opts.limit || DEFAULT_PAGE_SIZE,
|
|
520
|
+
},
|
|
521
|
+
resolveData,
|
|
522
|
+
});
|
|
523
|
+
return {
|
|
524
|
+
data: stepChunks.data,
|
|
525
|
+
cursor: stepChunks.cursor,
|
|
526
|
+
hasMore: stepChunks.hasMore,
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
catch (error) {
|
|
530
|
+
if (handleApiError(error, opts.backend)) {
|
|
531
|
+
process.exit(1);
|
|
532
|
+
}
|
|
533
|
+
throw error;
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
displayPage: async (steps) => {
|
|
537
|
+
const stepsWithHydratedIO = steps.map(hydrateResourceIO);
|
|
538
|
+
logger.log(showTable(stepsWithHydratedIO, props, opts));
|
|
539
|
+
showInspectInfoBox('step');
|
|
540
|
+
},
|
|
541
|
+
});
|
|
542
|
+
};
|
|
543
|
+
export const showStep = async (world, stepId, opts = {}) => {
|
|
544
|
+
if (opts.withData) {
|
|
545
|
+
logger.warn('`withData` flag is ignored when showing individual resources');
|
|
546
|
+
}
|
|
547
|
+
if (opts.stepId) {
|
|
548
|
+
logger.warn('Filtering by step-id is not supported in get calls, ignoring filter.');
|
|
549
|
+
}
|
|
550
|
+
try {
|
|
551
|
+
const step = await world.steps.get(opts.runId, stepId, {
|
|
552
|
+
resolveData: 'all',
|
|
553
|
+
});
|
|
554
|
+
const stepWithHydratedIO = hydrateResourceIO(step);
|
|
555
|
+
if (opts.json) {
|
|
556
|
+
showJson(stepWithHydratedIO);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
logger.log(stepWithHydratedIO);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
catch (error) {
|
|
564
|
+
if (handleApiError(error, opts.backend)) {
|
|
565
|
+
process.exit(1);
|
|
566
|
+
}
|
|
567
|
+
throw error;
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
export const showStream = async (_, streamId, opts = {}) => {
|
|
571
|
+
if (opts.runId || opts.stepId) {
|
|
572
|
+
logger.warn('Filtering by run-id or step-id is not supported in get calls, ignoring filter.');
|
|
573
|
+
}
|
|
574
|
+
const run = getRun(streamId);
|
|
575
|
+
const stream = run.readable;
|
|
576
|
+
logger.info('Streaming to stdout, press CTRL+C to abort.');
|
|
577
|
+
logger.info('Use --json to output the stream as newline-delimited JSON without info logs.\n');
|
|
578
|
+
await streamToConsole(stream, streamId, opts);
|
|
579
|
+
};
|
|
580
|
+
/**
|
|
581
|
+
* Listing streams only lists available stream IDs based on run/step passed,
|
|
582
|
+
* and doesn't read any data from the streams.
|
|
583
|
+
*/
|
|
584
|
+
export const listStreams = async (world, opts = {}) => {
|
|
585
|
+
if (opts.withData) {
|
|
586
|
+
logger.warn('`withData` flag is ignored when listing streams');
|
|
587
|
+
}
|
|
588
|
+
if (opts.workflowName) {
|
|
589
|
+
logger.warn('Filtering by workflow-name is not supported for streams, ignoring filter.');
|
|
590
|
+
}
|
|
591
|
+
const steps = [];
|
|
592
|
+
const runs = [];
|
|
593
|
+
if (opts.stepId) {
|
|
594
|
+
try {
|
|
595
|
+
const step = await world.steps.get(undefined, opts.stepId, {
|
|
596
|
+
resolveData: 'all',
|
|
597
|
+
});
|
|
598
|
+
steps.push(step);
|
|
599
|
+
}
|
|
600
|
+
catch (error) {
|
|
601
|
+
if (handleApiError(error, opts.backend)) {
|
|
602
|
+
process.exit(1);
|
|
603
|
+
}
|
|
604
|
+
throw error;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
else if (opts.runId) {
|
|
608
|
+
try {
|
|
609
|
+
const run = await world.runs.get(opts.runId, { resolveData: 'all' });
|
|
610
|
+
runs.push(run);
|
|
611
|
+
const runsSteps = await world.steps.list({
|
|
612
|
+
runId: opts.runId,
|
|
613
|
+
pagination: {
|
|
614
|
+
sortOrder: opts.sort || 'desc',
|
|
615
|
+
cursor: opts.cursor,
|
|
616
|
+
limit: opts.limit || DEFAULT_PAGE_SIZE,
|
|
617
|
+
},
|
|
618
|
+
resolveData: 'all', // Need data to find stream IDs
|
|
619
|
+
});
|
|
620
|
+
runsSteps.data.forEach((step) => {
|
|
621
|
+
steps.push(step);
|
|
622
|
+
});
|
|
623
|
+
logger.info(getCursorHint(runsSteps));
|
|
624
|
+
}
|
|
625
|
+
catch (error) {
|
|
626
|
+
if (handleApiError(error, opts.backend)) {
|
|
627
|
+
process.exit(1);
|
|
628
|
+
}
|
|
629
|
+
throw error;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
logger.warn('No run-id or step-id provided. Listing streams for latest run instead.', 'Use --run=<run-id> or --step=<step-id> to filter streams by run or step.');
|
|
634
|
+
const run = await getRecentRun(world, opts);
|
|
635
|
+
if (!run) {
|
|
636
|
+
logger.warn('No runs found.');
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
try {
|
|
640
|
+
const fullRun = await world.runs.get(run.runId, { resolveData: 'all' });
|
|
641
|
+
runs.push(fullRun);
|
|
642
|
+
const runsSteps = await world.steps.list({
|
|
643
|
+
runId: runs[0].runId,
|
|
644
|
+
pagination: {
|
|
645
|
+
sortOrder: opts.sort || 'desc',
|
|
646
|
+
cursor: opts.cursor,
|
|
647
|
+
limit: opts.limit || DEFAULT_PAGE_SIZE,
|
|
648
|
+
},
|
|
649
|
+
resolveData: 'all', // Need data to find stream IDs
|
|
650
|
+
});
|
|
651
|
+
runsSteps.data.forEach((step) => {
|
|
652
|
+
steps.push(step);
|
|
653
|
+
});
|
|
654
|
+
logger.info(getCursorHint(runsSteps));
|
|
655
|
+
}
|
|
656
|
+
catch (error) {
|
|
657
|
+
if (handleApiError(error, opts.backend)) {
|
|
658
|
+
process.exit(1);
|
|
659
|
+
}
|
|
660
|
+
throw error;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
const runIds = runs.map((item) => item.runId);
|
|
664
|
+
const stepIds = steps.map((item) => item.stepId);
|
|
665
|
+
logger.debug(`Found IO for runs/steps: ${runIds.concat(stepIds).join(', ')}`);
|
|
666
|
+
const runsWithHydratedIO = runs.map(hydrateResourceIO);
|
|
667
|
+
const stepsWithHydratedIO = steps.map(hydrateResourceIO);
|
|
668
|
+
const matchingStreams = [
|
|
669
|
+
...runsWithHydratedIO,
|
|
670
|
+
...stepsWithHydratedIO,
|
|
671
|
+
].flatMap((item) => findAllStreamIdsForObjectWithIO({
|
|
672
|
+
input: item.input,
|
|
673
|
+
output: item.output,
|
|
674
|
+
runId: item.runId,
|
|
675
|
+
stepId: 'stepId' in item ? item.stepId : undefined,
|
|
676
|
+
}));
|
|
677
|
+
if (opts.json) {
|
|
678
|
+
showJson(matchingStreams);
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
logger.log(showTable(matchingStreams, ['runId', 'stepId', 'streamId']));
|
|
682
|
+
};
|
|
683
|
+
const findAllStreamIdsForObjectWithIO = (obj) => {
|
|
684
|
+
const matchingStreams = [];
|
|
685
|
+
const inputStreams = getStreamIdsFromHydratedObject(obj.input);
|
|
686
|
+
for (const streamId of inputStreams) {
|
|
687
|
+
matchingStreams.push({
|
|
688
|
+
runId: obj.runId,
|
|
689
|
+
stepId: obj.stepId || '/',
|
|
690
|
+
streamId,
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
const outputStreams = getStreamIdsFromHydratedObject(obj.output);
|
|
694
|
+
for (const streamId of outputStreams) {
|
|
695
|
+
matchingStreams.push({
|
|
696
|
+
runId: obj.runId,
|
|
697
|
+
stepId: obj.stepId || '/',
|
|
698
|
+
streamId,
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
return matchingStreams;
|
|
702
|
+
};
|
|
703
|
+
const getStreamIdsFromHydratedObject = (io) => {
|
|
704
|
+
const streamIds = [];
|
|
705
|
+
const traverse = (obj) => {
|
|
706
|
+
if (!obj || typeof obj !== 'object')
|
|
707
|
+
return;
|
|
708
|
+
if (isStreamId(obj)) {
|
|
709
|
+
streamIds.push(obj);
|
|
710
|
+
}
|
|
711
|
+
else if (Array.isArray(obj)) {
|
|
712
|
+
obj.forEach(traverse);
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
Object.values(obj).forEach(traverse);
|
|
716
|
+
}
|
|
717
|
+
};
|
|
718
|
+
traverse(io);
|
|
719
|
+
return streamIds;
|
|
720
|
+
};
|
|
721
|
+
export const listEvents = async (world, opts = {}) => {
|
|
722
|
+
if (opts.workflowName) {
|
|
723
|
+
logger.warn('Filtering by workflow-name is not supported for events, ignoring filter.');
|
|
724
|
+
}
|
|
725
|
+
let filterId = opts.hookId || opts.stepId || opts.runId;
|
|
726
|
+
if (!filterId) {
|
|
727
|
+
filterId = (await getRecentRun(world, opts))?.runId;
|
|
728
|
+
if (!filterId) {
|
|
729
|
+
logger.error('No run found.');
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
const isCorrelationId = Boolean(opts.hookId || opts.stepId);
|
|
734
|
+
const params = {
|
|
735
|
+
pagination: {
|
|
736
|
+
sortOrder: opts.sort || 'desc',
|
|
737
|
+
cursor: opts.cursor,
|
|
738
|
+
limit: opts.limit || DEFAULT_PAGE_SIZE,
|
|
739
|
+
},
|
|
740
|
+
resolveData: opts.withData ? 'all' : 'none',
|
|
741
|
+
};
|
|
742
|
+
const listCall = isCorrelationId
|
|
743
|
+
? (correlationId, pagination) => world.events.listByCorrelationId({
|
|
744
|
+
...params,
|
|
745
|
+
correlationId,
|
|
746
|
+
pagination: { ...params.pagination, ...pagination },
|
|
747
|
+
})
|
|
748
|
+
: (runId, pagination) => world.events.list({
|
|
749
|
+
...params,
|
|
750
|
+
runId,
|
|
751
|
+
pagination: { ...params.pagination, ...pagination },
|
|
752
|
+
});
|
|
753
|
+
// Determine which props to show based on withData flag
|
|
754
|
+
const props = opts.withData
|
|
755
|
+
? EVENT_LISTED_PROPS
|
|
756
|
+
: EVENT_LISTED_PROPS.filter((prop) => !EVENT_IO_PROPS.includes(prop));
|
|
757
|
+
// For JSON output, just fetch once and return
|
|
758
|
+
if (opts.json) {
|
|
759
|
+
logger.debug(`Fetching events for run ${filterId}`);
|
|
760
|
+
try {
|
|
761
|
+
const events = await listCall(filterId, {});
|
|
762
|
+
showJson(events.data);
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
catch (error) {
|
|
766
|
+
if (handleApiError(error, opts.backend)) {
|
|
767
|
+
process.exit(1);
|
|
768
|
+
}
|
|
769
|
+
throw error;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
await setupListPagination({
|
|
773
|
+
initialCursor: opts.cursor,
|
|
774
|
+
fetchPage: async (cursor) => {
|
|
775
|
+
logger.debug(`Fetching events for run ${filterId}`);
|
|
776
|
+
try {
|
|
777
|
+
const events = await listCall(filterId, { cursor });
|
|
778
|
+
return {
|
|
779
|
+
data: events.data,
|
|
780
|
+
cursor: events.cursor,
|
|
781
|
+
hasMore: events.hasMore,
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
catch (error) {
|
|
785
|
+
if (handleApiError(error, opts.backend)) {
|
|
786
|
+
process.exit(1);
|
|
787
|
+
}
|
|
788
|
+
throw error;
|
|
789
|
+
}
|
|
790
|
+
},
|
|
791
|
+
displayPage: async (events) => {
|
|
792
|
+
logger.log(showTable(events, props, opts));
|
|
793
|
+
showInspectInfoBox('event');
|
|
794
|
+
},
|
|
795
|
+
});
|
|
796
|
+
};
|
|
797
|
+
export const listHooks = async (world, opts = {}) => {
|
|
798
|
+
if (opts.workflowName) {
|
|
799
|
+
logger.warn('Filtering by workflow-name is not supported for hooks, ignoring filter.');
|
|
800
|
+
}
|
|
801
|
+
if (opts.stepId) {
|
|
802
|
+
logger.warn('Filtering by step-id is not supported for hooks, ignoring filter.');
|
|
803
|
+
}
|
|
804
|
+
const runId = opts.runId;
|
|
805
|
+
const resolveData = opts.withData ? 'all' : 'none';
|
|
806
|
+
// For JSON output, just fetch once and return
|
|
807
|
+
if (opts.json) {
|
|
808
|
+
if (!runId) {
|
|
809
|
+
logger.debug('Fetching all hooks');
|
|
810
|
+
}
|
|
811
|
+
else {
|
|
812
|
+
logger.debug(`Fetching hooks for run ${runId}`);
|
|
813
|
+
}
|
|
814
|
+
try {
|
|
815
|
+
const hooks = await world.hooks.list({
|
|
816
|
+
runId,
|
|
817
|
+
pagination: {
|
|
818
|
+
sortOrder: opts.sort || 'desc',
|
|
819
|
+
cursor: opts.cursor,
|
|
820
|
+
limit: opts.limit || DEFAULT_PAGE_SIZE,
|
|
821
|
+
},
|
|
822
|
+
resolveData,
|
|
823
|
+
});
|
|
824
|
+
const hydratedHooks = hooks.data.map(hydrateResourceIO);
|
|
825
|
+
showJson({ ...hooks, data: hydratedHooks });
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
catch (error) {
|
|
829
|
+
if (handleApiError(error, opts.backend)) {
|
|
830
|
+
process.exit(1);
|
|
831
|
+
}
|
|
832
|
+
throw error;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
// Setup pagination with new mechanism
|
|
836
|
+
await setupListPagination({
|
|
837
|
+
initialCursor: opts.cursor,
|
|
838
|
+
fetchPage: async (cursor) => {
|
|
839
|
+
if (!runId) {
|
|
840
|
+
logger.debug('Fetching all hooks');
|
|
841
|
+
}
|
|
842
|
+
else {
|
|
843
|
+
logger.debug(`Fetching hooks for run ${runId}`);
|
|
844
|
+
}
|
|
845
|
+
try {
|
|
846
|
+
const hooks = await world.hooks.list({
|
|
847
|
+
runId,
|
|
848
|
+
pagination: {
|
|
849
|
+
sortOrder: opts.sort || 'desc',
|
|
850
|
+
cursor,
|
|
851
|
+
limit: opts.limit || DEFAULT_PAGE_SIZE,
|
|
852
|
+
},
|
|
853
|
+
resolveData,
|
|
854
|
+
});
|
|
855
|
+
return {
|
|
856
|
+
data: hooks.data,
|
|
857
|
+
cursor: hooks.cursor,
|
|
858
|
+
hasMore: hooks.hasMore,
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
catch (error) {
|
|
862
|
+
if (handleApiError(error, opts.backend)) {
|
|
863
|
+
process.exit(1);
|
|
864
|
+
}
|
|
865
|
+
throw error;
|
|
866
|
+
}
|
|
867
|
+
},
|
|
868
|
+
displayPage: async (hooks) => {
|
|
869
|
+
const hydratedHooks = hooks.map(hydrateResourceIO);
|
|
870
|
+
logger.log(showTable(hydratedHooks, HOOK_LISTED_PROPS, opts));
|
|
871
|
+
showInspectInfoBox('hook');
|
|
872
|
+
},
|
|
873
|
+
});
|
|
874
|
+
};
|
|
875
|
+
export const showHook = async (world, hookId, opts = {}) => {
|
|
876
|
+
if (opts.withData) {
|
|
877
|
+
logger.warn('`withData` flag is ignored when showing individual resources');
|
|
878
|
+
}
|
|
879
|
+
try {
|
|
880
|
+
const hook = await world.hooks.get(hookId, {
|
|
881
|
+
resolveData: 'all',
|
|
882
|
+
});
|
|
883
|
+
const hydratedHook = hydrateResourceIO(hook);
|
|
884
|
+
if (opts.json) {
|
|
885
|
+
showJson(hydratedHook);
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
else {
|
|
889
|
+
logger.log(hydratedHook);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
catch (error) {
|
|
893
|
+
if (handleApiError(error, opts.backend)) {
|
|
894
|
+
process.exit(1);
|
|
895
|
+
}
|
|
896
|
+
throw error;
|
|
897
|
+
}
|
|
898
|
+
};
|
|
899
|
+
//# sourceMappingURL=output.js.map
|