@pipeline-builder/pipeline-manager 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +74 -0
  3. package/cdk.json +91 -0
  4. package/config.yml +94 -0
  5. package/dist/boilerplate.d.ts +3 -0
  6. package/dist/boilerplate.d.ts.map +1 -0
  7. package/dist/boilerplate.js +58 -0
  8. package/dist/cdk.json +91 -0
  9. package/dist/cli.d.ts +62 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +372 -0
  12. package/dist/commands/bootstrap.d.ts +11 -0
  13. package/dist/commands/bootstrap.d.ts.map +1 -0
  14. package/dist/commands/bootstrap.js +159 -0
  15. package/dist/commands/create-pipeline.d.ts +12 -0
  16. package/dist/commands/create-pipeline.d.ts.map +1 -0
  17. package/dist/commands/create-pipeline.js +291 -0
  18. package/dist/commands/deploy.d.ts +15 -0
  19. package/dist/commands/deploy.d.ts.map +1 -0
  20. package/dist/commands/deploy.js +167 -0
  21. package/dist/commands/get-pipeline.d.ts +13 -0
  22. package/dist/commands/get-pipeline.d.ts.map +1 -0
  23. package/dist/commands/get-pipeline.js +97 -0
  24. package/dist/commands/get-plugin.d.ts +13 -0
  25. package/dist/commands/get-plugin.d.ts.map +1 -0
  26. package/dist/commands/get-plugin.js +98 -0
  27. package/dist/commands/list-pipelines.d.ts +20 -0
  28. package/dist/commands/list-pipelines.d.ts.map +1 -0
  29. package/dist/commands/list-pipelines.js +172 -0
  30. package/dist/commands/list-plugins.d.ts +20 -0
  31. package/dist/commands/list-plugins.d.ts.map +1 -0
  32. package/dist/commands/list-plugins.js +167 -0
  33. package/dist/commands/login.d.ts +21 -0
  34. package/dist/commands/login.d.ts.map +1 -0
  35. package/dist/commands/login.js +179 -0
  36. package/dist/commands/setup-events.d.ts +15 -0
  37. package/dist/commands/setup-events.d.ts.map +1 -0
  38. package/dist/commands/setup-events.js +177 -0
  39. package/dist/commands/status.d.ts +11 -0
  40. package/dist/commands/status.d.ts.map +1 -0
  41. package/dist/commands/status.js +89 -0
  42. package/dist/commands/store-token.d.ts +20 -0
  43. package/dist/commands/store-token.d.ts.map +1 -0
  44. package/dist/commands/store-token.js +233 -0
  45. package/dist/commands/synth.d.ts +21 -0
  46. package/dist/commands/synth.d.ts.map +1 -0
  47. package/dist/commands/synth.js +143 -0
  48. package/dist/commands/upload-plugin.d.ts +21 -0
  49. package/dist/commands/upload-plugin.d.ts.map +1 -0
  50. package/dist/commands/upload-plugin.js +311 -0
  51. package/dist/commands/version.d.ts +12 -0
  52. package/dist/commands/version.d.ts.map +1 -0
  53. package/dist/commands/version.js +223 -0
  54. package/dist/config/cli.constants.d.ts +101 -0
  55. package/dist/config/cli.constants.d.ts.map +1 -0
  56. package/dist/config/cli.constants.js +165 -0
  57. package/dist/config.yml +94 -0
  58. package/dist/templates/events-stack.json +141 -0
  59. package/dist/types/config.d.ts +44 -0
  60. package/dist/types/config.d.ts.map +1 -0
  61. package/dist/types/config.js +5 -0
  62. package/dist/types/error.d.ts +61 -0
  63. package/dist/types/error.d.ts.map +1 -0
  64. package/dist/types/error.js +39 -0
  65. package/dist/types/index.d.ts +8 -0
  66. package/dist/types/index.d.ts.map +1 -0
  67. package/dist/types/index.js +26 -0
  68. package/dist/types/pipeline.d.ts +144 -0
  69. package/dist/types/pipeline.d.ts.map +1 -0
  70. package/dist/types/pipeline.js +5 -0
  71. package/dist/types/plugin.d.ts +160 -0
  72. package/dist/types/plugin.d.ts.map +1 -0
  73. package/dist/types/plugin.js +5 -0
  74. package/dist/utils/api-client.d.ts +26 -0
  75. package/dist/utils/api-client.d.ts.map +1 -0
  76. package/dist/utils/api-client.js +160 -0
  77. package/dist/utils/audit-log.d.ts +8 -0
  78. package/dist/utils/audit-log.d.ts.map +1 -0
  79. package/dist/utils/audit-log.js +53 -0
  80. package/dist/utils/auth-guard.d.ts +16 -0
  81. package/dist/utils/auth-guard.d.ts.map +1 -0
  82. package/dist/utils/auth-guard.js +25 -0
  83. package/dist/utils/aws-secrets.d.ts +21 -0
  84. package/dist/utils/aws-secrets.d.ts.map +1 -0
  85. package/dist/utils/aws-secrets.js +74 -0
  86. package/dist/utils/banner.d.ts +19 -0
  87. package/dist/utils/banner.d.ts.map +1 -0
  88. package/dist/utils/banner.js +59 -0
  89. package/dist/utils/cdk-utils.d.ts +51 -0
  90. package/dist/utils/cdk-utils.d.ts.map +1 -0
  91. package/dist/utils/cdk-utils.js +101 -0
  92. package/dist/utils/command-utils.d.ts +56 -0
  93. package/dist/utils/command-utils.d.ts.map +1 -0
  94. package/dist/utils/command-utils.js +138 -0
  95. package/dist/utils/config-loader.d.ts +27 -0
  96. package/dist/utils/config-loader.d.ts.map +1 -0
  97. package/dist/utils/config-loader.js +166 -0
  98. package/dist/utils/error-handler.d.ts +29 -0
  99. package/dist/utils/error-handler.d.ts.map +1 -0
  100. package/dist/utils/error-handler.js +255 -0
  101. package/dist/utils/list-command-utils.d.ts +23 -0
  102. package/dist/utils/list-command-utils.d.ts.map +1 -0
  103. package/dist/utils/list-command-utils.js +60 -0
  104. package/dist/utils/output-utils.d.ts +60 -0
  105. package/dist/utils/output-utils.d.ts.map +1 -0
  106. package/dist/utils/output-utils.js +320 -0
  107. package/dist/utils/rate-limiter.d.ts +14 -0
  108. package/dist/utils/rate-limiter.d.ts.map +1 -0
  109. package/dist/utils/rate-limiter.js +73 -0
  110. package/package.json +144 -0
@@ -0,0 +1,320 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.printSuccess = printSuccess;
9
+ exports.printInfo = printInfo;
10
+ exports.printWarning = printWarning;
11
+ exports.printError = printError;
12
+ exports.printDebug = printDebug;
13
+ exports.outputData = outputData;
14
+ exports.formatTable = formatTable;
15
+ exports.ensureOutputDirectory = ensureOutputDirectory;
16
+ exports.fileExists = fileExists;
17
+ exports.printSection = printSection;
18
+ exports.printKeyValue = printKeyValue;
19
+ exports.printDivider = printDivider;
20
+ exports.unwrapEnvelope = unwrapEnvelope;
21
+ exports.extractSingleResponse = extractSingleResponse;
22
+ exports.extractListResponse = extractListResponse;
23
+ const node_fs_1 = __importDefault(require("node:fs"));
24
+ const node_path_1 = __importDefault(require("node:path"));
25
+ const picocolors_1 = __importDefault(require("picocolors"));
26
+ const yaml_1 = __importDefault(require("yaml"));
27
+ const cli_constants_1 = require("../config/cli.constants");
28
+ const { bold, cyan, green, yellow, red, dim, magenta, white } = picocolors_1.default;
29
+ // --- Logging functions ---
30
+ function logOutput(level, message, data) {
31
+ const colors = { info: cyan, success: green, warn: yellow, error: red, debug: magenta };
32
+ const prefixes = { info: 'ℹ', success: '✓', warn: '⚠', error: '✗', debug: '●' };
33
+ const writers = { error: console.error, warn: console.warn, info: console.log, success: console.log, debug: console.log };
34
+ const styledMessage = `${colors[level](prefixes[level])} ${message}`;
35
+ const write = writers[level];
36
+ write(styledMessage);
37
+ if (data !== undefined)
38
+ write(dim(formatDataForLog(data)));
39
+ }
40
+ function formatDataForLog(data) {
41
+ if (typeof data === 'string')
42
+ return data;
43
+ if (typeof data === 'object' && data !== null) {
44
+ const entries = Object.entries(data);
45
+ if (entries.length <= 5) {
46
+ return '\n' + entries.map(([key, value]) => {
47
+ const valueStr = typeof value === 'object' ? JSON.stringify(value) : String(value);
48
+ return ` ${key}: ${valueStr}`;
49
+ }).join('\n');
50
+ }
51
+ }
52
+ return JSON.stringify(data, null, 2);
53
+ }
54
+ function printSuccess(message, data) { logOutput('success', message, data); }
55
+ function printInfo(message, data) { logOutput('info', message, data); }
56
+ function printWarning(message, data) { logOutput('warn', message, data); }
57
+ function printError(message, data) { logOutput('error', message, data); }
58
+ function printDebug(message, data) {
59
+ if (process.env.DEBUG === 'true')
60
+ logOutput('debug', message, data);
61
+ }
62
+ // --- Data output ---
63
+ /**
64
+ * Output data in specified format (console or file)
65
+ */
66
+ function outputData(data, options = {}) {
67
+ const { format = 'json', file, pretty = true, silent = false, append = false } = options;
68
+ let output;
69
+ switch (format) {
70
+ case 'table':
71
+ if (!silent)
72
+ printInfo('Rendering as table');
73
+ if (Array.isArray(data) && data.length > 0) {
74
+ console.log(formatTable(data));
75
+ }
76
+ else if (typeof data === 'object' && data !== null) {
77
+ console.log(formatTable([data]));
78
+ }
79
+ else {
80
+ console.table(Array.isArray(data) ? data : [data]);
81
+ }
82
+ return;
83
+ case 'csv':
84
+ if (!silent)
85
+ printInfo('Rendering as CSV');
86
+ output = formatCsv(data);
87
+ break;
88
+ case 'yaml':
89
+ if (!silent)
90
+ printInfo('Rendering as YAML');
91
+ output = yaml_1.default.stringify(data);
92
+ break;
93
+ case 'json':
94
+ default:
95
+ if (!silent)
96
+ printInfo('Rendering as JSON');
97
+ output = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
98
+ break;
99
+ }
100
+ if (file) {
101
+ writeToFile(file, output, format, append);
102
+ }
103
+ else {
104
+ console.log(output);
105
+ }
106
+ }
107
+ // --- Table formatting ---
108
+ function formatTable(data, columns) {
109
+ if (!Array.isArray(data) || data.length === 0)
110
+ return dim('(No data to display)');
111
+ const firstItem = data[0];
112
+ if (typeof firstItem !== 'object' || firstItem === null)
113
+ return JSON.stringify(data, null, 2);
114
+ const cols = columns || Object.keys(firstItem).map(key => ({ header: key, key }));
115
+ const colWidths = cols.map(col => {
116
+ if (col.width)
117
+ return col.width;
118
+ const headerWidth = col.header.length;
119
+ const dataWidth = Math.max(...data.map(item => {
120
+ const value = col.formatter
121
+ ? col.formatter(item[col.key])
122
+ : String(item[col.key] ?? '');
123
+ return value.length;
124
+ }));
125
+ return Math.max(headerWidth, dataWidth, 3);
126
+ });
127
+ const { border } = cli_constants_1.TABLE_OPTIONS;
128
+ const horizontalLine = (left, middle, right) => left + colWidths.map(w => border.bodyJoin.repeat((w ?? 0) + 2)).join(middle) + right;
129
+ const topLine = horizontalLine(border.topLeft, border.topJoin, border.topRight);
130
+ const midLine = horizontalLine(border.joinLeft, border.joinJoin, border.joinRight);
131
+ const bottomLine = horizontalLine(border.bottomLeft, border.bottomJoin, border.bottomRight);
132
+ const formatCell = (value, width, align = 'left') => {
133
+ if (value.length > width)
134
+ return value.substring(0, width - 3) + '...';
135
+ if (align === 'center') {
136
+ const leftPad = Math.floor((width - value.length) / 2);
137
+ return ' '.repeat(leftPad) + value + ' '.repeat(width - value.length - leftPad);
138
+ }
139
+ return align === 'right' ? value.padStart(width) : value.padEnd(width);
140
+ };
141
+ const headerRow = border.bodyLeft + ' ' +
142
+ cols.map((col, i) => cyan(bold(formatCell(col.header, colWidths[i] ?? 0)))).join(` ${border.bodyJoin} `) +
143
+ ` ${border.bodyRight}`;
144
+ let table = cyan(topLine) + '\n' + headerRow + '\n' + cyan(midLine) + '\n';
145
+ data.forEach(item => {
146
+ const row = border.bodyLeft + ' ' +
147
+ cols.map((col, i) => {
148
+ const value = col.formatter
149
+ ? col.formatter(item[col.key])
150
+ : String(item[col.key] ?? '');
151
+ return formatCell(value, colWidths[i] ?? 0, col.align);
152
+ }).join(` ${border.bodyJoin} `) +
153
+ ` ${border.bodyRight}`;
154
+ table += row + '\n';
155
+ });
156
+ table += cyan(bottomLine);
157
+ return table;
158
+ }
159
+ // --- CSV formatting ---
160
+ function formatCsv(data) {
161
+ if (!Array.isArray(data) || data.length === 0)
162
+ return '';
163
+ const firstItem = data[0];
164
+ if (typeof firstItem !== 'object' || firstItem === null)
165
+ return data.join(',');
166
+ const headers = Object.keys(firstItem);
167
+ const rows = [headers.map(h => escapeCsvValue(h)).join(',')];
168
+ data.forEach(item => {
169
+ rows.push(headers.map(h => escapeCsvValue(item[h])).join(','));
170
+ });
171
+ return rows.join('\n');
172
+ }
173
+ function escapeCsvValue(value) {
174
+ if (value === null || value === undefined)
175
+ return '';
176
+ const str = String(value);
177
+ if (str.includes(',') || str.includes('"') || str.includes('\n')) {
178
+ return `"${str.replace(/"/g, '""')}"`;
179
+ }
180
+ return str;
181
+ }
182
+ // --- File operations ---
183
+ /**
184
+ * Validate that a file path resolves within the current working directory.
185
+ * Prevents path traversal attacks (e.g., --output ../../etc/passwd).
186
+ */
187
+ function validateOutputPath(filePath) {
188
+ const resolved = node_path_1.default.resolve(filePath);
189
+ const cwd = node_path_1.default.resolve(process.cwd());
190
+ if (!resolved.startsWith(cwd + node_path_1.default.sep) && resolved !== cwd) {
191
+ throw new Error(`Path traversal rejected: "${filePath}" resolves outside the current directory`);
192
+ }
193
+ return resolved;
194
+ }
195
+ function writeToFile(filePath, content, format, append = false) {
196
+ try {
197
+ const safePath = validateOutputPath(filePath);
198
+ const dir = node_path_1.default.dirname(safePath);
199
+ if (dir !== '.')
200
+ ensureOutputDirectory(dir);
201
+ if (append) {
202
+ node_fs_1.default.appendFileSync(safePath, content + '\n', 'utf-8');
203
+ printSuccess('Output appended to file', { path: safePath, format });
204
+ }
205
+ else {
206
+ node_fs_1.default.writeFileSync(safePath, content, 'utf-8');
207
+ const stats = node_fs_1.default.statSync(safePath);
208
+ printSuccess('Output saved to file', { path: safePath, format, size: (0, cli_constants_1.formatFileSize)(stats.size) });
209
+ }
210
+ }
211
+ catch (error) {
212
+ printError('Failed to write file', {
213
+ path: filePath,
214
+ error: error instanceof Error ? error.message : String(error),
215
+ });
216
+ throw error;
217
+ }
218
+ }
219
+ function ensureOutputDirectory(outputPath) {
220
+ if (node_fs_1.default.existsSync(outputPath))
221
+ return;
222
+ try {
223
+ node_fs_1.default.mkdirSync(outputPath, { recursive: true });
224
+ printDebug('Directory created', { path: outputPath });
225
+ }
226
+ catch (error) {
227
+ printError('Failed to create directory', {
228
+ path: outputPath,
229
+ error: error instanceof Error ? error.message : String(error),
230
+ });
231
+ throw error;
232
+ }
233
+ }
234
+ function fileExists(filePath) {
235
+ return node_fs_1.default.existsSync(filePath);
236
+ }
237
+ // --- Display helpers ---
238
+ function printSection(title, subtitle) {
239
+ const width = process.stdout.columns || 80;
240
+ console.log('');
241
+ console.log(cyan('═'.repeat(width)));
242
+ console.log(cyan(bold(title)));
243
+ if (subtitle)
244
+ console.log(dim(subtitle));
245
+ console.log(cyan('═'.repeat(width)));
246
+ }
247
+ function printKeyValue(data, options = {}) {
248
+ const { indent = 0, separator = '│' } = options;
249
+ const maxKeyLength = Math.max(...Object.keys(data).map(k => k.length));
250
+ const indentStr = ' '.repeat(indent);
251
+ Object.entries(data).forEach(([key, value]) => {
252
+ const paddedKey = key.padEnd(maxKeyLength);
253
+ const formattedValue = typeof value === 'object' && value !== null
254
+ ? JSON.stringify(value) : String(value);
255
+ console.log(`${indentStr}${dim(paddedKey)} ${cyan(separator)} ${white(formattedValue)}`);
256
+ });
257
+ }
258
+ function printDivider(char = '─', width) {
259
+ const effectiveWidth = width || process.stdout.columns || 80;
260
+ console.log(dim(char.repeat(effectiveWidth)));
261
+ }
262
+ // --- Response parsing ---
263
+ /**
264
+ * Unwrap a sendSuccess API envelope: { success, statusCode, data: { ... } }
265
+ * Returns the inner `data` object, or the original response if not wrapped.
266
+ */
267
+ function unwrapEnvelope(response) {
268
+ if (response && typeof response === 'object') {
269
+ const obj = response;
270
+ if ('success' in obj && 'data' in obj && obj.data && typeof obj.data === 'object') {
271
+ return obj.data;
272
+ }
273
+ return obj;
274
+ }
275
+ return {};
276
+ }
277
+ /**
278
+ * Extract a single entity from an API response, handling envelope formats.
279
+ * Tries: payload[entityKey], payload directly (if identifierKey exists), or undefined.
280
+ */
281
+ function extractSingleResponse(response, entityKey, identifierKey) {
282
+ const payload = unwrapEnvelope(response);
283
+ // Direct entity: payload has the identifier (e.g. payload.id, payload.props, payload.name)
284
+ if (identifierKey in payload)
285
+ return payload;
286
+ // Nested under entity key: payload.pipeline, payload.plugin
287
+ const nested = payload[entityKey];
288
+ if (nested && typeof nested === 'object' && identifierKey in nested)
289
+ return nested;
290
+ return undefined;
291
+ }
292
+ /**
293
+ * Extract items from an API list response, handling multiple response formats.
294
+ * Supports: `{ <key>: T[] }`, `{ items: T[] }`, `T[]`, or invalid formats.
295
+ */
296
+ function extractListResponse(response, itemsKey) {
297
+ if (Array.isArray(response)) {
298
+ return { items: response, total: undefined, hasMore: false };
299
+ }
300
+ if (response && typeof response === 'object') {
301
+ const obj = unwrapEnvelope(response);
302
+ // Extract pagination metadata if present
303
+ const pagination = obj.pagination;
304
+ const total = (pagination?.total ?? obj.total);
305
+ const hasMore = (pagination?.hasMore ?? obj.hasMore) || false;
306
+ // Try primary key (e.g. 'pipelines', 'plugins')
307
+ if (itemsKey in obj && Array.isArray(obj[itemsKey])) {
308
+ return { items: obj[itemsKey], total, hasMore };
309
+ }
310
+ // Try generic 'items' key
311
+ if ('items' in obj && Array.isArray(obj.items)) {
312
+ return { items: obj.items, total, hasMore };
313
+ }
314
+ printWarning('Unexpected response format, attempting to handle');
315
+ return { items: [], total: undefined, hasMore: false };
316
+ }
317
+ printError('Invalid response format from API');
318
+ throw new Error('Unexpected API response format');
319
+ }
320
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3V0cHV0LXV0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL291dHB1dC11dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsK0NBQStDO0FBQy9DLHNDQUFzQzs7Ozs7QUFrRXRDLG9DQUE0RztBQUM1Ryw4QkFBc0c7QUFDdEcsb0NBQXlHO0FBQ3pHLGdDQUF3RztBQUV4RyxnQ0FFQztBQU9ELGdDQXVDQztBQUlELGtDQTBEQztBQWdFRCxzREFZQztBQUVELGdDQUVDO0FBSUQsb0NBT0M7QUFFRCxzQ0FjQztBQUVELG9DQUdDO0FBUUQsd0NBU0M7QUFNRCxzREFRQztBQVlELGtEQTZCQztBQTNXRCxzREFBeUI7QUFDekIsMERBQTZCO0FBQzdCLDREQUE4QjtBQUM5QixnREFBd0I7QUFDeEIsMkRBSWlDO0FBRWpDLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEdBQUcsb0JBQUksQ0FBQztBQTBCckUsNEJBQTRCO0FBRTVCLFNBQVMsU0FBUyxDQUFDLEtBQWUsRUFBRSxPQUFlLEVBQUUsSUFBYztJQUNqRSxNQUFNLE1BQU0sR0FBRyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxDQUFDO0lBQ3hGLE1BQU0sUUFBUSxHQUFHLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLENBQUM7SUFDaEYsTUFBTSxPQUFPLEdBQUcsRUFBRSxLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsT0FB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LENBQUMsT0FBTyxDQUFhLElBQUksS0FBSyxDQUFDO1FBRTNFLGdEQUFnRDtRQUNoRCxJQUFJLFFBQVEsSUFBSSxHQUFHLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ3BELE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxDQUFDLFFBQVEsQ0FBUSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsQ0FBQztRQUN6RCxDQUFDO1FBRUQsMEJBQTBCO1FBQzFCLElBQUksT0FBTyxJQUFJLEdBQUcsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQy9DLE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxDQUFDLEtBQVksRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUM7UUFDckQsQ0FBQztRQUVELFlBQVksQ0FBQyxrREFBa0QsQ0FBQyxDQUFDO1FBQ2pFLE9BQU8sRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxDQUFDO0lBQ3pELENBQUM7SUFFRCxVQUFVLENBQUMsa0NBQWtDLENBQUMsQ0FBQztJQUMvQyxNQUFNLElBQUksS0FBSyxDQUFDLGdDQUFnQyxDQUFDLENBQUM7QUFDcEQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgZnMgZnJvbSAnbm9kZTpmcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdub2RlOnBhdGgnO1xuaW1wb3J0IHBpY28gZnJvbSAncGljb2NvbG9ycyc7XG5pbXBvcnQgWUFNTCBmcm9tICd5YW1sJztcbmltcG9ydCB7XG4gIE91dHB1dEZvcm1hdCxcbiAgZm9ybWF0RmlsZVNpemUsXG4gIFRBQkxFX09QVElPTlMsXG59IGZyb20gJy4uL2NvbmZpZy9jbGkuY29uc3RhbnRzJztcblxuY29uc3QgeyBib2xkLCBjeWFuLCBncmVlbiwgeWVsbG93LCByZWQsIGRpbSwgbWFnZW50YSwgd2hpdGUgfSA9IHBpY287XG5cbnR5cGUgTG9nTGV2ZWwgPSAnaW5mbycgfCAnc3VjY2VzcycgfCAnd2FybicgfCAnZXJyb3InIHwgJ2RlYnVnJztcblxuLyoqXG4gKiBPcHRpb25zIGZvciBvdXRwdXREYXRhIGZ1bmN0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgT3V0cHV0T3B0aW9ucyB7XG4gIGZvcm1hdD86IE91dHB1dEZvcm1hdDtcbiAgZmlsZT86IHN0cmluZztcbiAgcHJldHR5PzogYm9vbGVhbjtcbiAgc2lsZW50PzogYm9vbGVhbjtcbiAgYXBwZW5kPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBUYWJsZSBjb2x1bW4gY29uZmlndXJhdGlvblxuICovXG5leHBvcnQgaW50ZXJmYWNlIFRhYmxlQ29sdW1uIHtcbiAgaGVhZGVyOiBzdHJpbmc7XG4gIGtleTogc3RyaW5nO1xuICB3aWR0aD86IG51bWJlcjtcbiAgYWxpZ24/OiAnbGVmdCcgfCAnY2VudGVyJyB8ICdyaWdodCc7XG4gIGZvcm1hdHRlcj86ICh2YWx1ZTogdW5rbm93bikgPT4gc3RyaW5nO1xufVxuXG4vLyAtLS0gTG9nZ2luZyBmdW5jdGlvbnMgLS0tXG5cbmZ1bmN0aW9uIGxvZ091dHB1dChsZXZlbDogTG9nTGV2ZWwsIG1lc3NhZ2U6IHN0cmluZywgZGF0YT86IHVua25vd24pOiB2b2lkIHtcbiAgY29uc3QgY29sb3JzID0geyBpbmZvOiBjeWFuLCBzdWNjZXNzOiBncmVlbiwgd2FybjogeWVsbG93LCBlcnJvcjogcmVkLCBkZWJ1ZzogbWFnZW50YSB9O1xuICBjb25zdCBwcmVmaXhlcyA9IHsgaW5mbzogJ+KEuScsIHN1Y2Nlc3M6ICfinJMnLCB3YXJuOiAn4pqgJywgZXJyb3I6ICfinJcnLCBkZWJ1ZzogJ+KXjycgfTtcbiAgY29uc3Qgd3JpdGVycyA9IHsgZXJyb3I6IGNvbnNvbGUuZXJyb3IsIHdhcm46IGNvbnNvbGUud2FybiwgaW5mbzogY29uc29sZS5sb2csIHN1Y2Nlc3M6IGNvbnNvbGUubG9nLCBkZWJ1ZzogY29uc29sZS5sb2cgfTtcblxuICBjb25zdCBzdHlsZWRNZXNzYWdlID0gYCR7Y29sb3JzW2xldmVsXShwcmVmaXhlc1tsZXZlbF0pfSAke21lc3NhZ2V9YDtcbiAgY29uc3Qgd3JpdGUgPSB3cml0ZXJzW2xldmVsXTtcblxuICB3cml0ZShzdHlsZWRNZXNzYWdlKTtcbiAgaWYgKGRhdGEgIT09IHVuZGVmaW5lZCkgd3JpdGUoZGltKGZvcm1hdERhdGFGb3JMb2coZGF0YSkpKTtcbn1cblxuZnVuY3Rpb24gZm9ybWF0RGF0YUZvckxvZyhkYXRhOiB1bmtub3duKTogc3RyaW5nIHtcbiAgaWYgKHR5cGVvZiBkYXRhID09PSAnc3RyaW5nJykgcmV0dXJuIGRhdGE7XG4gIGlmICh0eXBlb2YgZGF0YSA9PT0gJ29iamVjdCcgJiYgZGF0YSAhPT0gbnVsbCkge1xuICAgIGNvbnN0IGVudHJpZXMgPSBPYmplY3QuZW50cmllcyhkYXRhKTtcbiAgICBpZiAoZW50cmllcy5sZW5ndGggPD0gNSkge1xuICAgICAgcmV0dXJuICdcXG4nICsgZW50cmllcy5tYXAoKFtrZXksIHZhbHVlXSkgPT4ge1xuICAgICAgICBjb25zdCB2YWx1ZVN0ciA9IHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgPyBKU09OLnN0cmluZ2lmeSh2YWx1ZSkgOiBTdHJpbmcodmFsdWUpO1xuICAgICAgICByZXR1cm4gYCAgJHtrZXl9OiAke3ZhbHVlU3RyfWA7XG4gICAgICB9KS5qb2luKCdcXG4nKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGRhdGEsIG51bGwsIDIpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRTdWNjZXNzKG1lc3NhZ2U6IHN0cmluZywgZGF0YT86IHVua25vd24pOiB2b2lkIHsgbG9nT3V0cHV0KCdzdWNjZXNzJywgbWVzc2FnZSwgZGF0YSk7IH1cbmV4cG9ydCBmdW5jdGlvbiBwcmludEluZm8obWVzc2FnZTogc3RyaW5nLCBkYXRhPzogdW5rbm93bik6IHZvaWQgeyBsb2dPdXRwdXQoJ2luZm8nLCBtZXNzYWdlLCBkYXRhKTsgfVxuZXhwb3J0IGZ1bmN0aW9uIHByaW50V2FybmluZyhtZXNzYWdlOiBzdHJpbmcsIGRhdGE/OiB1bmtub3duKTogdm9pZCB7IGxvZ091dHB1dCgnd2FybicsIG1lc3NhZ2UsIGRhdGEpOyB9XG5leHBvcnQgZnVuY3Rpb24gcHJpbnRFcnJvcihtZXNzYWdlOiBzdHJpbmcsIGRhdGE/OiB1bmtub3duKTogdm9pZCB7IGxvZ091dHB1dCgnZXJyb3InLCBtZXNzYWdlLCBkYXRhKTsgfVxuXG5leHBvcnQgZnVuY3Rpb24gcHJpbnREZWJ1ZyhtZXNzYWdlOiBzdHJpbmcsIGRhdGE/OiB1bmtub3duKTogdm9pZCB7XG4gIGlmIChwcm9jZXNzLmVudi5ERUJVRyA9PT0gJ3RydWUnKSBsb2dPdXRwdXQoJ2RlYnVnJywgbWVzc2FnZSwgZGF0YSk7XG59XG5cbi8vIC0tLSBEYXRhIG91dHB1dCAtLS1cblxuLyoqXG4gKiBPdXRwdXQgZGF0YSBpbiBzcGVjaWZpZWQgZm9ybWF0IChjb25zb2xlIG9yIGZpbGUpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBvdXRwdXREYXRhKGRhdGE6IHVua25vd24sIG9wdGlvbnM6IE91dHB1dE9wdGlvbnMgPSB7fSk6IHZvaWQge1xuICBjb25zdCB7IGZvcm1hdCA9ICdqc29uJywgZmlsZSwgcHJldHR5ID0gdHJ1ZSwgc2lsZW50ID0gZmFsc2UsIGFwcGVuZCA9IGZhbHNlIH0gPSBvcHRpb25zO1xuXG4gIGxldCBvdXRwdXQ6IHN0cmluZztcblxuICBzd2l0Y2ggKGZvcm1hdCkge1xuICAgIGNhc2UgJ3RhYmxlJzpcbiAgICAgIGlmICghc2lsZW50KSBwcmludEluZm8oJ1JlbmRlcmluZyBhcyB0YWJsZScpO1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkoZGF0YSkgJiYgZGF0YS5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGZvcm1hdFRhYmxlKGRhdGEpKTtcbiAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGRhdGEgPT09ICdvYmplY3QnICYmIGRhdGEgIT09IG51bGwpIHtcbiAgICAgICAgY29uc29sZS5sb2coZm9ybWF0VGFibGUoW2RhdGFdKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLnRhYmxlKEFycmF5LmlzQXJyYXkoZGF0YSkgPyBkYXRhIDogW2RhdGFdKTtcbiAgICAgIH1cbiAgICAgIHJldHVybjtcblxuICAgIGNhc2UgJ2Nzdic6XG4gICAgICBpZiAoIXNpbGVudCkgcHJpbnRJbmZvKCdSZW5kZXJpbmcgYXMgQ1NWJyk7XG4gICAgICBvdXRwdXQgPSBmb3JtYXRDc3YoZGF0YSk7XG4gICAgICBicmVhaztcblxuICAgIGNhc2UgJ3lhbWwnOlxuICAgICAgaWYgKCFzaWxlbnQpIHByaW50SW5mbygnUmVuZGVyaW5nIGFzIFlBTUwnKTtcbiAgICAgIG91dHB1dCA9IFlBTUwuc3RyaW5naWZ5KGRhdGEpO1xuICAgICAgYnJlYWs7XG5cbiAgICBjYXNlICdqc29uJzpcbiAgICBkZWZhdWx0OlxuICAgICAgaWYgKCFzaWxlbnQpIHByaW50SW5mbygnUmVuZGVyaW5nIGFzIEpTT04nKTtcbiAgICAgIG91dHB1dCA9IHByZXR0eSA/IEpTT04uc3RyaW5naWZ5KGRhdGEsIG51bGwsIDIpIDogSlNPTi5zdHJpbmdpZnkoZGF0YSk7XG4gICAgICBicmVhaztcbiAgfVxuXG4gIGlmIChmaWxlKSB7XG4gICAgd3JpdGVUb0ZpbGUoZmlsZSwgb3V0cHV0LCBmb3JtYXQsIGFwcGVuZCk7XG4gIH0gZWxzZSB7XG4gICAgY29uc29sZS5sb2cob3V0cHV0KTtcbiAgfVxufVxuXG4vLyAtLS0gVGFibGUgZm9ybWF0dGluZyAtLS1cblxuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdFRhYmxlKGRhdGE6IHVua25vd25bXSwgY29sdW1ucz86IFRhYmxlQ29sdW1uW10pOiBzdHJpbmcge1xuICBpZiAoIUFycmF5LmlzQXJyYXkoZGF0YSkgfHwgZGF0YS5sZW5ndGggPT09IDApIHJldHVybiBkaW0oJyhObyBkYXRhIHRvIGRpc3BsYXkpJyk7XG5cbiAgY29uc3QgZmlyc3RJdGVtID0gZGF0YVswXTtcbiAgaWYgKHR5cGVvZiBmaXJzdEl0ZW0gIT09ICdvYmplY3QnIHx8IGZpcnN0SXRlbSA9PT0gbnVsbCkgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGRhdGEsIG51bGwsIDIpO1xuXG4gIGNvbnN0IGNvbHM6IFRhYmxlQ29sdW1uW10gPSBjb2x1bW5zIHx8IE9iamVjdC5rZXlzKGZpcnN0SXRlbSkubWFwKGtleSA9PiAoeyBoZWFkZXI6IGtleSwga2V5IH0pKTtcblxuICBjb25zdCBjb2xXaWR0aHM6IG51bWJlcltdID0gY29scy5tYXAoY29sID0+IHtcbiAgICBpZiAoY29sLndpZHRoKSByZXR1cm4gY29sLndpZHRoO1xuICAgIGNvbnN0IGhlYWRlcldpZHRoID0gY29sLmhlYWRlci5sZW5ndGg7XG4gICAgY29uc3QgZGF0YVdpZHRoID0gTWF0aC5tYXgoLi4uZGF0YS5tYXAoaXRlbSA9PiB7XG4gICAgICBjb25zdCB2YWx1ZSA9IGNvbC5mb3JtYXR0ZXJcbiAgICAgICAgPyBjb2wuZm9ybWF0dGVyKChpdGVtIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KVtjb2wua2V5XSlcbiAgICAgICAgOiBTdHJpbmcoKGl0ZW0gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW2NvbC5rZXldID8/ICcnKTtcbiAgICAgIHJldHVybiB2YWx1ZS5sZW5ndGg7XG4gICAgfSkpO1xuICAgIHJldHVybiBNYXRoLm1heChoZWFkZXJXaWR0aCwgZGF0YVdpZHRoLCAzKTtcbiAgfSk7XG5cbiAgY29uc3QgeyBib3JkZXIgfSA9IFRBQkxFX09QVElPTlM7XG5cbiAgY29uc3QgaG9yaXpvbnRhbExpbmUgPSAobGVmdDogc3RyaW5nLCBtaWRkbGU6IHN0cmluZywgcmlnaHQ6IHN0cmluZykgPT5cbiAgICBsZWZ0ICsgY29sV2lkdGhzLm1hcCh3ID0+IGJvcmRlci5ib2R5Sm9pbi5yZXBlYXQoKHcgPz8gMCkgKyAyKSkuam9pbihtaWRkbGUpICsgcmlnaHQ7XG5cbiAgY29uc3QgdG9wTGluZSA9IGhvcml6b250YWxMaW5lKGJvcmRlci50b3BMZWZ0LCBib3JkZXIudG9wSm9pbiwgYm9yZGVyLnRvcFJpZ2h0KTtcbiAgY29uc3QgbWlkTGluZSA9IGhvcml6b250YWxMaW5lKGJvcmRlci5qb2luTGVmdCwgYm9yZGVyLmpvaW5Kb2luLCBib3JkZXIuam9pblJpZ2h0KTtcbiAgY29uc3QgYm90dG9tTGluZSA9IGhvcml6b250YWxMaW5lKGJvcmRlci5ib3R0b21MZWZ0LCBib3JkZXIuYm90dG9tSm9pbiwgYm9yZGVyLmJvdHRvbVJpZ2h0KTtcblxuICBjb25zdCBmb3JtYXRDZWxsID0gKHZhbHVlOiBzdHJpbmcsIHdpZHRoOiBudW1iZXIsIGFsaWduOiAnbGVmdCcgfCAnY2VudGVyJyB8ICdyaWdodCcgPSAnbGVmdCcpOiBzdHJpbmcgPT4ge1xuICAgIGlmICh2YWx1ZS5sZW5ndGggPiB3aWR0aCkgcmV0dXJuIHZhbHVlLnN1YnN0cmluZygwLCB3aWR0aCAtIDMpICsgJy4uLic7XG4gICAgaWYgKGFsaWduID09PSAnY2VudGVyJykge1xuICAgICAgY29uc3QgbGVmdFBhZCA9IE1hdGguZmxvb3IoKHdpZHRoIC0gdmFsdWUubGVuZ3RoKSAvIDIpO1xuICAgICAgcmV0dXJuICcgJy5yZXBlYXQobGVmdFBhZCkgKyB2YWx1ZSArICcgJy5yZXBlYXQod2lkdGggLSB2YWx1ZS5sZW5ndGggLSBsZWZ0UGFkKTtcbiAgICB9XG4gICAgcmV0dXJuIGFsaWduID09PSAncmlnaHQnID8gdmFsdWUucGFkU3RhcnQod2lkdGgpIDogdmFsdWUucGFkRW5kKHdpZHRoKTtcbiAgfTtcblxuICBjb25zdCBoZWFkZXJSb3cgPSBib3JkZXIuYm9keUxlZnQgKyAnICcgK1xuICAgIGNvbHMubWFwKChjb2wsIGkpID0+IGN5YW4oYm9sZChmb3JtYXRDZWxsKGNvbC5oZWFkZXIsIGNvbFdpZHRoc1tpXSA/PyAwKSkpKS5qb2luKGAgJHtib3JkZXIuYm9keUpvaW59IGApICtcbiAgICBgICR7Ym9yZGVyLmJvZHlSaWdodH1gO1xuXG4gIGxldCB0YWJsZSA9IGN5YW4odG9wTGluZSkgKyAnXFxuJyArIGhlYWRlclJvdyArICdcXG4nICsgY3lhbihtaWRMaW5lKSArICdcXG4nO1xuXG4gIGRhdGEuZm9yRWFjaChpdGVtID0+IHtcbiAgICBjb25zdCByb3cgPSBib3JkZXIuYm9keUxlZnQgKyAnICcgK1xuICAgICAgY29scy5tYXAoKGNvbCwgaSkgPT4ge1xuICAgICAgICBjb25zdCB2YWx1ZSA9IGNvbC5mb3JtYXR0ZXJcbiAgICAgICAgICA/IGNvbC5mb3JtYXR0ZXIoKGl0ZW0gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW2NvbC5rZXldKVxuICAgICAgICAgIDogU3RyaW5nKChpdGVtIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KVtjb2wua2V5XSA/PyAnJyk7XG4gICAgICAgIHJldHVybiBmb3JtYXRDZWxsKHZhbHVlLCBjb2xXaWR0aHNbaV0gPz8gMCwgY29sLmFsaWduKTtcbiAgICAgIH0pLmpvaW4oYCAke2JvcmRlci5ib2R5Sm9pbn0gYCkgK1xuICAgICAgYCAke2JvcmRlci5ib2R5UmlnaHR9YDtcbiAgICB0YWJsZSArPSByb3cgKyAnXFxuJztcbiAgfSk7XG5cbiAgdGFibGUgKz0gY3lhbihib3R0b21MaW5lKTtcbiAgcmV0dXJuIHRhYmxlO1xufVxuXG4vLyAtLS0gQ1NWIGZvcm1hdHRpbmcgLS0tXG5cbmZ1bmN0aW9uIGZvcm1hdENzdihkYXRhOiB1bmtub3duKTogc3RyaW5nIHtcbiAgaWYgKCFBcnJheS5pc0FycmF5KGRhdGEpIHx8IGRhdGEubGVuZ3RoID09PSAwKSByZXR1cm4gJyc7XG4gIGNvbnN0IGZpcnN0SXRlbSA9IGRhdGFbMF07XG4gIGlmICh0eXBlb2YgZmlyc3RJdGVtICE9PSAnb2JqZWN0JyB8fCBmaXJzdEl0ZW0gPT09IG51bGwpIHJldHVybiBkYXRhLmpvaW4oJywnKTtcblxuICBjb25zdCBoZWFkZXJzID0gT2JqZWN0LmtleXMoZmlyc3RJdGVtKTtcbiAgY29uc3Qgcm93czogc3RyaW5nW10gPSBbaGVhZGVycy5tYXAoaCA9PiBlc2NhcGVDc3ZWYWx1ZShoKSkuam9pbignLCcpXTtcbiAgZGF0YS5mb3JFYWNoKGl0ZW0gPT4ge1xuICAgIHJvd3MucHVzaChoZWFkZXJzLm1hcChoID0+IGVzY2FwZUNzdlZhbHVlKChpdGVtIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KVtoXSkpLmpvaW4oJywnKSk7XG4gIH0pO1xuICByZXR1cm4gcm93cy5qb2luKCdcXG4nKTtcbn1cblxuZnVuY3Rpb24gZXNjYXBlQ3N2VmFsdWUodmFsdWU6IHVua25vd24pOiBzdHJpbmcge1xuICBpZiAodmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuICcnO1xuICBjb25zdCBzdHIgPSBTdHJpbmcodmFsdWUpO1xuICBpZiAoc3RyLmluY2x1ZGVzKCcsJykgfHwgc3RyLmluY2x1ZGVzKCdcIicpIHx8IHN0ci5pbmNsdWRlcygnXFxuJykpIHtcbiAgICByZXR1cm4gYFwiJHtzdHIucmVwbGFjZSgvXCIvZywgJ1wiXCInKX1cImA7XG4gIH1cbiAgcmV0dXJuIHN0cjtcbn1cblxuLy8gLS0tIEZpbGUgb3BlcmF0aW9ucyAtLS1cblxuLyoqXG4gKiBWYWxpZGF0ZSB0aGF0IGEgZmlsZSBwYXRoIHJlc29sdmVzIHdpdGhpbiB0aGUgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS5cbiAqIFByZXZlbnRzIHBhdGggdHJhdmVyc2FsIGF0dGFja3MgKGUuZy4sIC0tb3V0cHV0IC4uLy4uL2V0Yy9wYXNzd2QpLlxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZU91dHB1dFBhdGgoZmlsZVBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IHJlc29sdmVkID0gcGF0aC5yZXNvbHZlKGZpbGVQYXRoKTtcbiAgY29uc3QgY3dkID0gcGF0aC5yZXNvbHZlKHByb2Nlc3MuY3dkKCkpO1xuICBpZiAoIXJlc29sdmVkLnN0YXJ0c1dpdGgoY3dkICsgcGF0aC5zZXApICYmIHJlc29sdmVkICE9PSBjd2QpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFBhdGggdHJhdmVyc2FsIHJlamVjdGVkOiBcIiR7ZmlsZVBhdGh9XCIgcmVzb2x2ZXMgb3V0c2lkZSB0aGUgY3VycmVudCBkaXJlY3RvcnlgKTtcbiAgfVxuICByZXR1cm4gcmVzb2x2ZWQ7XG59XG5cbmZ1bmN0aW9uIHdyaXRlVG9GaWxlKGZpbGVQYXRoOiBzdHJpbmcsIGNvbnRlbnQ6IHN0cmluZywgZm9ybWF0OiBPdXRwdXRGb3JtYXQsIGFwcGVuZDogYm9vbGVhbiA9IGZhbHNlKTogdm9pZCB7XG4gIHRyeSB7XG4gICAgY29uc3Qgc2FmZVBhdGggPSB2YWxpZGF0ZU91dHB1dFBhdGgoZmlsZVBhdGgpO1xuICAgIGNvbnN0IGRpciA9IHBhdGguZGlybmFtZShzYWZlUGF0aCk7XG4gICAgaWYgKGRpciAhPT0gJy4nKSBlbnN1cmVPdXRwdXREaXJlY3RvcnkoZGlyKTtcblxuICAgIGlmIChhcHBlbmQpIHtcbiAgICAgIGZzLmFwcGVuZEZpbGVTeW5jKHNhZmVQYXRoLCBjb250ZW50ICsgJ1xcbicsICd1dGYtOCcpO1xuICAgICAgcHJpbnRTdWNjZXNzKCdPdXRwdXQgYXBwZW5kZWQgdG8gZmlsZScsIHsgcGF0aDogc2FmZVBhdGgsIGZvcm1hdCB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgZnMud3JpdGVGaWxlU3luYyhzYWZlUGF0aCwgY29udGVudCwgJ3V0Zi04Jyk7XG4gICAgICBjb25zdCBzdGF0cyA9IGZzLnN0YXRTeW5jKHNhZmVQYXRoKTtcbiAgICAgIHByaW50U3VjY2VzcygnT3V0cHV0IHNhdmVkIHRvIGZpbGUnLCB7IHBhdGg6IHNhZmVQYXRoLCBmb3JtYXQsIHNpemU6IGZvcm1hdEZpbGVTaXplKHN0YXRzLnNpemUpIH0pO1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBwcmludEVycm9yKCdGYWlsZWQgdG8gd3JpdGUgZmlsZScsIHtcbiAgICAgIHBhdGg6IGZpbGVQYXRoLFxuICAgICAgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKSxcbiAgICB9KTtcbiAgICB0aHJvdyBlcnJvcjtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZW5zdXJlT3V0cHV0RGlyZWN0b3J5KG91dHB1dFBhdGg6IHN0cmluZyk6IHZvaWQge1xuICBpZiAoZnMuZXhpc3RzU3luYyhvdXRwdXRQYXRoKSkgcmV0dXJuO1xuICB0cnkge1xuICAgIGZzLm1rZGlyU3luYyhvdXRwdXRQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICBwcmludERlYnVnKCdEaXJlY3RvcnkgY3JlYXRlZCcsIHsgcGF0aDogb3V0cHV0UGF0aCB9KTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBwcmludEVycm9yKCdGYWlsZWQgdG8gY3JlYXRlIGRpcmVjdG9yeScsIHtcbiAgICAgIHBhdGg6IG91dHB1dFBhdGgsXG4gICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpLFxuICAgIH0pO1xuICAgIHRocm93IGVycm9yO1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBmaWxlRXhpc3RzKGZpbGVQYXRoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIGZzLmV4aXN0c1N5bmMoZmlsZVBhdGgpO1xufVxuXG4vLyAtLS0gRGlzcGxheSBoZWxwZXJzIC0tLVxuXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRTZWN0aW9uKHRpdGxlOiBzdHJpbmcsIHN1YnRpdGxlPzogc3RyaW5nKTogdm9pZCB7XG4gIGNvbnN0IHdpZHRoID0gcHJvY2Vzcy5zdGRvdXQuY29sdW1ucyB8fCA4MDtcbiAgY29uc29sZS5sb2coJycpO1xuICBjb25zb2xlLmxvZyhjeWFuKCfilZAnLnJlcGVhdCh3aWR0aCkpKTtcbiAgY29uc29sZS5sb2coY3lhbihib2xkKHRpdGxlKSkpO1xuICBpZiAoc3VidGl0bGUpIGNvbnNvbGUubG9nKGRpbShzdWJ0aXRsZSkpO1xuICBjb25zb2xlLmxvZyhjeWFuKCfilZAnLnJlcGVhdCh3aWR0aCkpKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHByaW50S2V5VmFsdWUoXG4gIGRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBvcHRpb25zOiB7IGluZGVudD86IG51bWJlcjsgc2VwYXJhdG9yPzogc3RyaW5nIH0gPSB7fSxcbik6IHZvaWQge1xuICBjb25zdCB7IGluZGVudCA9IDAsIHNlcGFyYXRvciA9ICfilIInIH0gPSBvcHRpb25zO1xuICBjb25zdCBtYXhLZXlMZW5ndGggPSBNYXRoLm1heCguLi5PYmplY3Qua2V5cyhkYXRhKS5tYXAoayA9PiBrLmxlbmd0aCkpO1xuICBjb25zdCBpbmRlbnRTdHIgPSAnICcucmVwZWF0KGluZGVudCk7XG5cbiAgT2JqZWN0LmVudHJpZXMoZGF0YSkuZm9yRWFjaCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgY29uc3QgcGFkZGVkS2V5ID0ga2V5LnBhZEVuZChtYXhLZXlMZW5ndGgpO1xuICAgIGNvbnN0IGZvcm1hdHRlZFZhbHVlID0gdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiB2YWx1ZSAhPT0gbnVsbFxuICAgICAgPyBKU09OLnN0cmluZ2lmeSh2YWx1ZSkgOiBTdHJpbmcodmFsdWUpO1xuICAgIGNvbnNvbGUubG9nKGAke2luZGVudFN0cn0ke2RpbShwYWRkZWRLZXkpfSAke2N5YW4oc2VwYXJhdG9yKX0gJHt3aGl0ZShmb3JtYXR0ZWRWYWx1ZSl9YCk7XG4gIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcHJpbnREaXZpZGVyKGNoYXI6IHN0cmluZyA9ICfilIAnLCB3aWR0aD86IG51bWJlcik6IHZvaWQge1xuICBjb25zdCBlZmZlY3RpdmVXaWR0aCA9IHdpZHRoIHx8IHByb2Nlc3Muc3Rkb3V0LmNvbHVtbnMgfHwgODA7XG4gIGNvbnNvbGUubG9nKGRpbShjaGFyLnJlcGVhdChlZmZlY3RpdmVXaWR0aCkpKTtcbn1cblxuLy8gLS0tIFJlc3BvbnNlIHBhcnNpbmcgLS0tXG5cbi8qKlxuICogVW53cmFwIGEgc2VuZFN1Y2Nlc3MgQVBJIGVudmVsb3BlOiB7IHN1Y2Nlc3MsIHN0YXR1c0NvZGUsIGRhdGE6IHsgLi4uIH0gfVxuICogUmV0dXJucyB0aGUgaW5uZXIgYGRhdGFgIG9iamVjdCwgb3IgdGhlIG9yaWdpbmFsIHJlc3BvbnNlIGlmIG5vdCB3cmFwcGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdW53cmFwRW52ZWxvcGUocmVzcG9uc2U6IHVua25vd24pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIGlmIChyZXNwb25zZSAmJiB0eXBlb2YgcmVzcG9uc2UgPT09ICdvYmplY3QnKSB7XG4gICAgY29uc3Qgb2JqID0gcmVzcG9uc2UgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgaWYgKCdzdWNjZXNzJyBpbiBvYmogJiYgJ2RhdGEnIGluIG9iaiAmJiBvYmouZGF0YSAmJiB0eXBlb2Ygb2JqLmRhdGEgPT09ICdvYmplY3QnKSB7XG4gICAgICByZXR1cm4gb2JqLmRhdGEgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgfVxuICAgIHJldHVybiBvYmo7XG4gIH1cbiAgcmV0dXJuIHt9O1xufVxuXG4vKipcbiAqIEV4dHJhY3QgYSBzaW5nbGUgZW50aXR5IGZyb20gYW4gQVBJIHJlc3BvbnNlLCBoYW5kbGluZyBlbnZlbG9wZSBmb3JtYXRzLlxuICogVHJpZXM6IHBheWxvYWRbZW50aXR5S2V5XSwgcGF5bG9hZCBkaXJlY3RseSAoaWYgaWRlbnRpZmllcktleSBleGlzdHMpLCBvciB1bmRlZmluZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0U2luZ2xlUmVzcG9uc2U8VD4ocmVzcG9uc2U6IHVua25vd24sIGVudGl0eUtleTogc3RyaW5nLCBpZGVudGlmaWVyS2V5OiBzdHJpbmcpOiBUIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgcGF5bG9hZCA9IHVud3JhcEVudmVsb3BlKHJlc3BvbnNlKTtcbiAgLy8gRGlyZWN0IGVudGl0eTogcGF5bG9hZCBoYXMgdGhlIGlkZW50aWZpZXIgKGUuZy4gcGF5bG9hZC5pZCwgcGF5bG9hZC5wcm9wcywgcGF5bG9hZC5uYW1lKVxuICBpZiAoaWRlbnRpZmllcktleSBpbiBwYXlsb2FkKSByZXR1cm4gcGF5bG9hZCBhcyB1bmtub3duIGFzIFQ7XG4gIC8vIE5lc3RlZCB1bmRlciBlbnRpdHkga2V5OiBwYXlsb2FkLnBpcGVsaW5lLCBwYXlsb2FkLnBsdWdpblxuICBjb25zdCBuZXN0ZWQgPSBwYXlsb2FkW2VudGl0eUtleV0gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWQ7XG4gIGlmIChuZXN0ZWQgJiYgdHlwZW9mIG5lc3RlZCA9PT0gJ29iamVjdCcgJiYgaWRlbnRpZmllcktleSBpbiBuZXN0ZWQpIHJldHVybiBuZXN0ZWQgYXMgdW5rbm93biBhcyBUO1xuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIExpc3RSZXNwb25zZVJlc3VsdDxUPiB7XG4gIGl0ZW1zOiBUW107XG4gIHRvdGFsPzogbnVtYmVyO1xuICBoYXNNb3JlOiBib29sZWFuO1xufVxuXG4vKipcbiAqIEV4dHJhY3QgaXRlbXMgZnJvbSBhbiBBUEkgbGlzdCByZXNwb25zZSwgaGFuZGxpbmcgbXVsdGlwbGUgcmVzcG9uc2UgZm9ybWF0cy5cbiAqIFN1cHBvcnRzOiBgeyA8a2V5PjogVFtdIH1gLCBgeyBpdGVtczogVFtdIH1gLCBgVFtdYCwgb3IgaW52YWxpZCBmb3JtYXRzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdExpc3RSZXNwb25zZTxUPihyZXNwb25zZTogdW5rbm93biwgaXRlbXNLZXk6IHN0cmluZyk6IExpc3RSZXNwb25zZVJlc3VsdDxUPiB7XG4gIGlmIChBcnJheS5pc0FycmF5KHJlc3BvbnNlKSkge1xuICAgIHJldHVybiB7IGl0ZW1zOiByZXNwb25zZSwgdG90YWw6IHVuZGVmaW5lZCwgaGFzTW9yZTogZmFsc2UgfTtcbiAgfVxuXG4gIGlmIChyZXNwb25zZSAmJiB0eXBlb2YgcmVzcG9uc2UgPT09ICdvYmplY3QnKSB7XG4gICAgY29uc3Qgb2JqID0gdW53cmFwRW52ZWxvcGUocmVzcG9uc2UpO1xuXG4gICAgLy8gRXh0cmFjdCBwYWdpbmF0aW9uIG1ldGFkYXRhIGlmIHByZXNlbnRcbiAgICBjb25zdCBwYWdpbmF0aW9uID0gb2JqLnBhZ2luYXRpb24gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWQ7XG4gICAgY29uc3QgdG90YWwgPSAocGFnaW5hdGlvbj8udG90YWwgPz8gb2JqLnRvdGFsKSBhcyBudW1iZXIgfCB1bmRlZmluZWQ7XG4gICAgY29uc3QgaGFzTW9yZSA9ICgocGFnaW5hdGlvbj8uaGFzTW9yZSA/PyBvYmouaGFzTW9yZSkgYXMgYm9vbGVhbikgfHwgZmFsc2U7XG5cbiAgICAvLyBUcnkgcHJpbWFyeSBrZXkgKGUuZy4gJ3BpcGVsaW5lcycsICdwbHVnaW5zJylcbiAgICBpZiAoaXRlbXNLZXkgaW4gb2JqICYmIEFycmF5LmlzQXJyYXkob2JqW2l0ZW1zS2V5XSkpIHtcbiAgICAgIHJldHVybiB7IGl0ZW1zOiBvYmpbaXRlbXNLZXldIGFzIFRbXSwgdG90YWwsIGhhc01vcmUgfTtcbiAgICB9XG5cbiAgICAvLyBUcnkgZ2VuZXJpYyAnaXRlbXMnIGtleVxuICAgIGlmICgnaXRlbXMnIGluIG9iaiAmJiBBcnJheS5pc0FycmF5KG9iai5pdGVtcykpIHtcbiAgICAgIHJldHVybiB7IGl0ZW1zOiBvYmouaXRlbXMgYXMgVFtdLCB0b3RhbCwgaGFzTW9yZSB9O1xuICAgIH1cblxuICAgIHByaW50V2FybmluZygnVW5leHBlY3RlZCByZXNwb25zZSBmb3JtYXQsIGF0dGVtcHRpbmcgdG8gaGFuZGxlJyk7XG4gICAgcmV0dXJuIHsgaXRlbXM6IFtdLCB0b3RhbDogdW5kZWZpbmVkLCBoYXNNb3JlOiBmYWxzZSB9O1xuICB9XG5cbiAgcHJpbnRFcnJvcignSW52YWxpZCByZXNwb25zZSBmb3JtYXQgZnJvbSBBUEknKTtcbiAgdGhyb3cgbmV3IEVycm9yKCdVbmV4cGVjdGVkIEFQSSByZXNwb25zZSBmb3JtYXQnKTtcbn1cbiJdfQ==
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Check if auth attempts are currently rate-limited.
3
+ * @returns null if allowed, or a message string if blocked.
4
+ */
5
+ export declare function checkAuthRateLimit(): string | null;
6
+ /**
7
+ * Record a successful auth — resets the failure counter.
8
+ */
9
+ export declare function recordAuthSuccess(): void;
10
+ /**
11
+ * Record a failed auth attempt. After MAX_FAILURES, locks out for COOLDOWN_MS.
12
+ */
13
+ export declare function recordAuthFailure(): void;
14
+ //# sourceMappingURL=rate-limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/utils/rate-limiter.ts"],"names":[],"mappings":"AAsCA;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAelD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAWxC"}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.checkAuthRateLimit = checkAuthRateLimit;
9
+ exports.recordAuthSuccess = recordAuthSuccess;
10
+ exports.recordAuthFailure = recordAuthFailure;
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const os_1 = __importDefault(require("os"));
13
+ const path_1 = __importDefault(require("path"));
14
+ /**
15
+ * Simple file-based rate limiter for auth operations.
16
+ * Tracks failed attempts and enforces a cooldown period after too many failures.
17
+ * State is persisted in a temp file so it survives across CLI invocations.
18
+ */
19
+ const STATE_FILE = path_1.default.join(os_1.default.tmpdir(), '.pipeline-manager-auth-state.json');
20
+ const MAX_FAILURES = 5;
21
+ const COOLDOWN_MS = 60_000; // 1 minute
22
+ function readState() {
23
+ try {
24
+ if (fs_1.default.existsSync(STATE_FILE)) {
25
+ return JSON.parse(fs_1.default.readFileSync(STATE_FILE, 'utf-8'));
26
+ }
27
+ }
28
+ catch { /* ignore corrupt state */ }
29
+ return { failures: 0, lastFailure: 0, lockedUntil: 0 };
30
+ }
31
+ function writeState(state) {
32
+ try {
33
+ fs_1.default.writeFileSync(STATE_FILE, JSON.stringify(state), { mode: 0o600 });
34
+ }
35
+ catch { /* best-effort */ }
36
+ }
37
+ /**
38
+ * Check if auth attempts are currently rate-limited.
39
+ * @returns null if allowed, or a message string if blocked.
40
+ */
41
+ function checkAuthRateLimit() {
42
+ const state = readState();
43
+ const now = Date.now();
44
+ if (state.lockedUntil > now) {
45
+ const waitSec = Math.ceil((state.lockedUntil - now) / 1000);
46
+ return `Too many failed login attempts. Try again in ${waitSec}s.`;
47
+ }
48
+ // Reset if cooldown has passed
49
+ if (now - state.lastFailure > COOLDOWN_MS) {
50
+ writeState({ failures: 0, lastFailure: 0, lockedUntil: 0 });
51
+ }
52
+ return null;
53
+ }
54
+ /**
55
+ * Record a successful auth — resets the failure counter.
56
+ */
57
+ function recordAuthSuccess() {
58
+ writeState({ failures: 0, lastFailure: 0, lockedUntil: 0 });
59
+ }
60
+ /**
61
+ * Record a failed auth attempt. After MAX_FAILURES, locks out for COOLDOWN_MS.
62
+ */
63
+ function recordAuthFailure() {
64
+ const state = readState();
65
+ const now = Date.now();
66
+ state.failures += 1;
67
+ state.lastFailure = now;
68
+ if (state.failures >= MAX_FAILURES) {
69
+ state.lockedUntil = now + COOLDOWN_MS;
70
+ }
71
+ writeState(state);
72
+ }
73
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmF0ZS1saW1pdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL3JhdGUtbGltaXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsK0NBQStDO0FBQy9DLHNDQUFzQzs7Ozs7QUF5Q3RDLGdEQWVDO0FBS0QsOENBRUM7QUFLRCw4Q0FXQztBQTdFRCw0Q0FBb0I7QUFDcEIsNENBQW9CO0FBQ3BCLGdEQUF3QjtBQUV4Qjs7OztHQUlHO0FBRUgsTUFBTSxVQUFVLEdBQUcsY0FBSSxDQUFDLElBQUksQ0FBQyxZQUFFLENBQUMsTUFBTSxFQUFFLEVBQUUsbUNBQW1DLENBQUMsQ0FBQztBQUMvRSxNQUFNLFlBQVksR0FBRyxDQUFDLENBQUM7QUFDdkIsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLENBQUMsV0FBVztBQVF2QyxTQUFTLFNBQVM7SUFDaEIsSUFBSSxDQUFDO1FBQ0gsSUFBSSxZQUFFLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDOUIsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLFlBQUUsQ0FBQyxZQUFZLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFjLENBQUM7UUFDdkUsQ0FBQztJQUNILENBQUM7SUFBQyxNQUFNLENBQUMsQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO0lBQ3RDLE9BQU8sRUFBRSxRQUFRLEVBQUUsQ0FBQyxFQUFFLFdBQVcsRUFBRSxDQUFDLEVBQUUsV0FBVyxFQUFFLENBQUMsRUFBRSxDQUFDO0FBQ3pELENBQUM7QUFFRCxTQUFTLFVBQVUsQ0FBQyxLQUFnQjtJQUNsQyxJQUFJLENBQUM7UUFDSCxZQUFFLENBQUMsYUFBYSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDdkUsQ0FBQztJQUFDLE1BQU0sQ0FBQyxDQUFDLGlCQUFpQixDQUFDLENBQUM7QUFDL0IsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLGtCQUFrQjtJQUNoQyxNQUFNLEtBQUssR0FBRyxTQUFTLEVBQUUsQ0FBQztJQUMxQixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7SUFFdkIsSUFBSSxLQUFLLENBQUMsV0FBVyxHQUFHLEdBQUcsRUFBRSxDQUFDO1FBQzVCLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsV0FBVyxHQUFHLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO1FBQzVELE9BQU8sZ0RBQWdELE9BQU8sSUFBSSxDQUFDO0lBQ3JFLENBQUM7SUFFRCwrQkFBK0I7SUFDL0IsSUFBSSxHQUFHLEdBQUcsS0FBSyxDQUFDLFdBQVcsR0FBRyxXQUFXLEVBQUUsQ0FBQztRQUMxQyxVQUFVLENBQUMsRUFBRSxRQUFRLEVBQUUsQ0FBQyxFQUFFLFdBQVcsRUFBRSxDQUFDLEVBQUUsV0FBVyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDOUQsQ0FBQztJQUVELE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsaUJBQWlCO0lBQy9CLFVBQVUsQ0FBQyxFQUFFLFFBQVEsRUFBRSxDQUFDLEVBQUUsV0FBVyxFQUFFLENBQUMsRUFBRSxXQUFXLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUM5RCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixpQkFBaUI7SUFDL0IsTUFBTSxLQUFLLEdBQUcsU0FBUyxFQUFFLENBQUM7SUFDMUIsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ3ZCLEtBQUssQ0FBQyxRQUFRLElBQUksQ0FBQyxDQUFDO0lBQ3BCLEtBQUssQ0FBQyxXQUFXLEdBQUcsR0FBRyxDQUFDO0lBRXhCLElBQUksS0FBSyxDQUFDLFFBQVEsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUNuQyxLQUFLLENBQUMsV0FBVyxHQUFHLEdBQUcsR0FBRyxXQUFXLENBQUM7SUFDeEMsQ0FBQztJQUVELFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUNwQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCBmcyBmcm9tICdmcyc7XG5pbXBvcnQgb3MgZnJvbSAnb3MnO1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5cbi8qKlxuICogU2ltcGxlIGZpbGUtYmFzZWQgcmF0ZSBsaW1pdGVyIGZvciBhdXRoIG9wZXJhdGlvbnMuXG4gKiBUcmFja3MgZmFpbGVkIGF0dGVtcHRzIGFuZCBlbmZvcmNlcyBhIGNvb2xkb3duIHBlcmlvZCBhZnRlciB0b28gbWFueSBmYWlsdXJlcy5cbiAqIFN0YXRlIGlzIHBlcnNpc3RlZCBpbiBhIHRlbXAgZmlsZSBzbyBpdCBzdXJ2aXZlcyBhY3Jvc3MgQ0xJIGludm9jYXRpb25zLlxuICovXG5cbmNvbnN0IFNUQVRFX0ZJTEUgPSBwYXRoLmpvaW4ob3MudG1wZGlyKCksICcucGlwZWxpbmUtbWFuYWdlci1hdXRoLXN0YXRlLmpzb24nKTtcbmNvbnN0IE1BWF9GQUlMVVJFUyA9IDU7XG5jb25zdCBDT09MRE9XTl9NUyA9IDYwXzAwMDsgLy8gMSBtaW51dGVcblxuaW50ZXJmYWNlIEF1dGhTdGF0ZSB7XG4gIGZhaWx1cmVzOiBudW1iZXI7XG4gIGxhc3RGYWlsdXJlOiBudW1iZXI7XG4gIGxvY2tlZFVudGlsOiBudW1iZXI7XG59XG5cbmZ1bmN0aW9uIHJlYWRTdGF0ZSgpOiBBdXRoU3RhdGUge1xuICB0cnkge1xuICAgIGlmIChmcy5leGlzdHNTeW5jKFNUQVRFX0ZJTEUpKSB7XG4gICAgICByZXR1cm4gSlNPTi5wYXJzZShmcy5yZWFkRmlsZVN5bmMoU1RBVEVfRklMRSwgJ3V0Zi04JykpIGFzIEF1dGhTdGF0ZTtcbiAgICB9XG4gIH0gY2F0Y2ggeyAvKiBpZ25vcmUgY29ycnVwdCBzdGF0ZSAqLyB9XG4gIHJldHVybiB7IGZhaWx1cmVzOiAwLCBsYXN0RmFpbHVyZTogMCwgbG9ja2VkVW50aWw6IDAgfTtcbn1cblxuZnVuY3Rpb24gd3JpdGVTdGF0ZShzdGF0ZTogQXV0aFN0YXRlKTogdm9pZCB7XG4gIHRyeSB7XG4gICAgZnMud3JpdGVGaWxlU3luYyhTVEFURV9GSUxFLCBKU09OLnN0cmluZ2lmeShzdGF0ZSksIHsgbW9kZTogMG82MDAgfSk7XG4gIH0gY2F0Y2ggeyAvKiBiZXN0LWVmZm9ydCAqLyB9XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgYXV0aCBhdHRlbXB0cyBhcmUgY3VycmVudGx5IHJhdGUtbGltaXRlZC5cbiAqIEByZXR1cm5zIG51bGwgaWYgYWxsb3dlZCwgb3IgYSBtZXNzYWdlIHN0cmluZyBpZiBibG9ja2VkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2hlY2tBdXRoUmF0ZUxpbWl0KCk6IHN0cmluZyB8IG51bGwge1xuICBjb25zdCBzdGF0ZSA9IHJlYWRTdGF0ZSgpO1xuICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuXG4gIGlmIChzdGF0ZS5sb2NrZWRVbnRpbCA+IG5vdykge1xuICAgIGNvbnN0IHdhaXRTZWMgPSBNYXRoLmNlaWwoKHN0YXRlLmxvY2tlZFVudGlsIC0gbm93KSAvIDEwMDApO1xuICAgIHJldHVybiBgVG9vIG1hbnkgZmFpbGVkIGxvZ2luIGF0dGVtcHRzLiBUcnkgYWdhaW4gaW4gJHt3YWl0U2VjfXMuYDtcbiAgfVxuXG4gIC8vIFJlc2V0IGlmIGNvb2xkb3duIGhhcyBwYXNzZWRcbiAgaWYgKG5vdyAtIHN0YXRlLmxhc3RGYWlsdXJlID4gQ09PTERPV05fTVMpIHtcbiAgICB3cml0ZVN0YXRlKHsgZmFpbHVyZXM6IDAsIGxhc3RGYWlsdXJlOiAwLCBsb2NrZWRVbnRpbDogMCB9KTtcbiAgfVxuXG4gIHJldHVybiBudWxsO1xufVxuXG4vKipcbiAqIFJlY29yZCBhIHN1Y2Nlc3NmdWwgYXV0aCDigJQgcmVzZXRzIHRoZSBmYWlsdXJlIGNvdW50ZXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWNvcmRBdXRoU3VjY2VzcygpOiB2b2lkIHtcbiAgd3JpdGVTdGF0ZSh7IGZhaWx1cmVzOiAwLCBsYXN0RmFpbHVyZTogMCwgbG9ja2VkVW50aWw6IDAgfSk7XG59XG5cbi8qKlxuICogUmVjb3JkIGEgZmFpbGVkIGF1dGggYXR0ZW1wdC4gQWZ0ZXIgTUFYX0ZBSUxVUkVTLCBsb2NrcyBvdXQgZm9yIENPT0xET1dOX01TLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVjb3JkQXV0aEZhaWx1cmUoKTogdm9pZCB7XG4gIGNvbnN0IHN0YXRlID0gcmVhZFN0YXRlKCk7XG4gIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gIHN0YXRlLmZhaWx1cmVzICs9IDE7XG4gIHN0YXRlLmxhc3RGYWlsdXJlID0gbm93O1xuXG4gIGlmIChzdGF0ZS5mYWlsdXJlcyA+PSBNQVhfRkFJTFVSRVMpIHtcbiAgICBzdGF0ZS5sb2NrZWRVbnRpbCA9IG5vdyArIENPT0xET1dOX01TO1xuICB9XG5cbiAgd3JpdGVTdGF0ZShzdGF0ZSk7XG59XG4iXX0=
package/package.json ADDED
@@ -0,0 +1,144 @@
1
+ {
2
+ "name": "@pipeline-builder/pipeline-manager",
3
+ "description": "CLI for Pipeline Builder — self-service AWS CodePipeline platform with 124 reusable containerized plugins, per-org compliance enforcement, and multi-tenant isolation.",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/mwashburn160/pipeline-builder.git"
7
+ },
8
+ "bin": {
9
+ "pipeline-manager": "./dist/cli.js"
10
+ },
11
+ "devDependencies": {
12
+ "@stylistic/eslint-plugin": "^2",
13
+ "@types/figlet": "1.7.0",
14
+ "@types/jest": "^30.0.0",
15
+ "@types/node": "^24",
16
+ "@types/progress": "2.0.7",
17
+ "@typescript-eslint/eslint-plugin": "^8",
18
+ "@typescript-eslint/parser": "^8",
19
+ "copyfiles": "2.4.1",
20
+ "eslint": "^9",
21
+ "eslint-import-resolver-typescript": "^4.4.4",
22
+ "eslint-plugin-import": "^2.32.0",
23
+ "jest": "^30.2.0",
24
+ "jest-junit": "^16",
25
+ "ts-jest": "^29.4.6",
26
+ "typescript": "5.9.3"
27
+ },
28
+ "dependencies": {
29
+ "@aws-sdk/client-cloudformation": "3.821.0",
30
+ "@aws-sdk/client-lambda": "3.821.0",
31
+ "@aws-sdk/client-secrets-manager": "3.821.0",
32
+ "@aws-sdk/client-sts": "3.821.0",
33
+ "aws-cdk-lib": "2.240.0",
34
+ "axios": "1.13.5",
35
+ "commander": "14.0.3",
36
+ "figlet": "1.10.0",
37
+ "form-data": "4.0.5",
38
+ "ora": "9.3.0",
39
+ "picocolors": "1.1.1",
40
+ "progress": "2.0.3",
41
+ "typescript": "5.9.3",
42
+ "yaml": "2.8.2",
43
+ "@pipeline-builder/pipeline-core": "3.1.0"
44
+ },
45
+ "keywords": [
46
+ "aws",
47
+ "codepipeline",
48
+ "codebuild",
49
+ "cicd",
50
+ "ci-cd",
51
+ "devops",
52
+ "cdk",
53
+ "aws-cdk",
54
+ "cloudformation",
55
+ "pipeline",
56
+ "pipeline-as-code",
57
+ "containerized",
58
+ "docker",
59
+ "kubernetes",
60
+ "plugins",
61
+ "typescript",
62
+ "self-service",
63
+ "multi-tenant",
64
+ "compliance",
65
+ "automation",
66
+ "infrastructure-as-code",
67
+ "iac",
68
+ "cli"
69
+ ],
70
+ "engines": {
71
+ "node": ">= 24.14.0"
72
+ },
73
+ "license": "Apache-2.0",
74
+ "homepage": "https://mwashburn160.github.io/pipeline-builder/",
75
+ "publishConfig": {
76
+ "access": "public",
77
+ "registry": "https://registry.npmjs.org/"
78
+ },
79
+ "version": "3.1.0",
80
+ "bugs": {
81
+ "url": "https://github.com/mwashburn160/pipeline-builder/issues"
82
+ },
83
+ "jest": {
84
+ "coverageProvider": "v8",
85
+ "testMatch": [
86
+ "<rootDir>/@(src|test)/**/*(*.)@(spec|test).[jt]s?(x)",
87
+ "<rootDir>/@(src|test)/**/__tests__/**/*.[jt]s?(x)"
88
+ ],
89
+ "clearMocks": true,
90
+ "collectCoverage": true,
91
+ "coverageReporters": [
92
+ "json",
93
+ "lcov",
94
+ "clover",
95
+ "cobertura",
96
+ "text"
97
+ ],
98
+ "coverageDirectory": "coverage",
99
+ "coveragePathIgnorePatterns": [
100
+ "/node_modules/"
101
+ ],
102
+ "testPathIgnorePatterns": [
103
+ "/node_modules/"
104
+ ],
105
+ "watchPathIgnorePatterns": [
106
+ "/node_modules/"
107
+ ],
108
+ "reporters": [
109
+ "default",
110
+ [
111
+ "jest-junit",
112
+ {
113
+ "outputDirectory": "test-reports"
114
+ }
115
+ ]
116
+ ],
117
+ "transform": {
118
+ "^.+\\.[t]sx?$": [
119
+ "ts-jest",
120
+ {
121
+ "tsconfig": "tsconfig.dev.json"
122
+ }
123
+ ]
124
+ },
125
+ "moduleNameMapper": {
126
+ "^uuid$": "<rootDir>/../../jest-uuid-stub.js"
127
+ }
128
+ },
129
+ "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"pnpm dlx projen\".",
130
+ "scripts": {
131
+ "audit": "pnpm dlx projen audit",
132
+ "build": "pnpm dlx projen build",
133
+ "compile": "pnpm dlx projen compile",
134
+ "default": "pnpm dlx projen default",
135
+ "eslint": "pnpm dlx projen eslint",
136
+ "package": "pnpm dlx projen package",
137
+ "post-compile": "pnpm dlx projen post-compile",
138
+ "pre-compile": "pnpm dlx projen pre-compile",
139
+ "test": "pnpm dlx projen test",
140
+ "test:watch": "pnpm dlx projen test:watch",
141
+ "watch": "pnpm dlx projen watch",
142
+ "projen": "pnpm dlx projen"
143
+ }
144
+ }