@pipeline-builder/pipeline-core 0.0.1
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 +202 -0
- package/README.md +69 -0
- package/lib/cdk.d.ts +38 -0
- package/lib/cdk.js +44 -0
- package/lib/config/app-config.d.ts +109 -0
- package/lib/config/app-config.js +197 -0
- package/lib/config/aws-config-cdk.d.ts +49 -0
- package/lib/config/aws-config-cdk.js +65 -0
- package/lib/config/billing-config.d.ts +24 -0
- package/lib/config/billing-config.js +497 -0
- package/lib/config/config-types.d.ts +346 -0
- package/lib/config/config-types.js +4 -0
- package/lib/config/entitlements.d.ts +23 -0
- package/lib/config/entitlements.js +46 -0
- package/lib/config/handler-constants.d.ts +10 -0
- package/lib/config/handler-constants.js +39 -0
- package/lib/config/infrastructure-config.d.ts +66 -0
- package/lib/config/infrastructure-config.js +197 -0
- package/lib/config/server-config.d.ts +53 -0
- package/lib/config/server-config.js +175 -0
- package/lib/config/service-client.d.ts +13 -0
- package/lib/config/service-client.js +20 -0
- package/lib/core/artifact-manager.d.ts +62 -0
- package/lib/core/artifact-manager.js +83 -0
- package/lib/core/id-generator.d.ts +50 -0
- package/lib/core/id-generator.js +50 -0
- package/lib/core/metadata-builder.d.ts +48 -0
- package/lib/core/metadata-builder.js +278 -0
- package/lib/core/metadata-helpers.d.ts +31 -0
- package/lib/core/metadata-helpers.js +55 -0
- package/lib/core/network-types.d.ts +200 -0
- package/lib/core/network-types.js +4 -0
- package/lib/core/network.d.ts +33 -0
- package/lib/core/network.js +112 -0
- package/lib/core/pipeline-helpers.d.ts +61 -0
- package/lib/core/pipeline-helpers.js +563 -0
- package/lib/core/pipeline-types.d.ts +118 -0
- package/lib/core/pipeline-types.js +131 -0
- package/lib/core/role-types.d.ts +254 -0
- package/lib/core/role-types.js +4 -0
- package/lib/core/role.d.ts +14 -0
- package/lib/core/role.js +117 -0
- package/lib/core/security-group-types.d.ts +84 -0
- package/lib/core/security-group-types.js +4 -0
- package/lib/core/security-group.d.ts +14 -0
- package/lib/core/security-group.js +33 -0
- package/lib/handlers/plugin-lookup-handler.d.ts +32 -0
- package/lib/handlers/plugin-lookup-handler.js +292 -0
- package/lib/handlers/pnpm-lock.yaml +12 -0
- package/lib/index.d.ts +45 -0
- package/lib/index.js +53 -0
- package/lib/pipeline/pipeline-builder.d.ts +123 -0
- package/lib/pipeline/pipeline-builder.js +476 -0
- package/lib/pipeline/pipeline-configuration.d.ts +81 -0
- package/lib/pipeline/pipeline-configuration.js +214 -0
- package/lib/pipeline/plugin-lookup.d.ts +131 -0
- package/lib/pipeline/plugin-lookup.js +316 -0
- package/lib/pipeline/plugin-spec.d.ts +138 -0
- package/lib/pipeline/plugin-spec.js +4 -0
- package/lib/pipeline/source-builder.d.ts +62 -0
- package/lib/pipeline/source-builder.js +164 -0
- package/lib/pipeline/source-types.d.ts +221 -0
- package/lib/pipeline/source-types.js +4 -0
- package/lib/pipeline/stage-builder.d.ts +78 -0
- package/lib/pipeline/stage-builder.js +129 -0
- package/lib/pipeline/step-types.d.ts +222 -0
- package/lib/pipeline/step-types.js +4 -0
- package/lib/template/evaluator.d.ts +42 -0
- package/lib/template/evaluator.js +164 -0
- package/lib/template/index.d.ts +34 -0
- package/lib/template/index.js +118 -0
- package/lib/template/metrics.d.ts +10 -0
- package/lib/template/metrics.js +43 -0
- package/lib/template/plugin-resolver.d.ts +8 -0
- package/lib/template/plugin-resolver.js +48 -0
- package/lib/template/tokenizer.d.ts +49 -0
- package/lib/template/tokenizer.js +233 -0
- package/lib/template/topo-sort.d.ts +17 -0
- package/lib/template/topo-sort.js +88 -0
- package/lib/template/validate.d.ts +45 -0
- package/lib/template/validate.js +96 -0
- package/lib/template/walker.d.ts +34 -0
- package/lib/template/walker.js +83 -0
- package/package.json +184 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { GetSecretValueCommand, SecretsManagerClient } from '@aws-sdk/client-secrets-manager';
|
|
4
|
+
import axios, { AxiosError } from 'axios';
|
|
5
|
+
// Import the dependency-free leaf, NOT `app-config.js`/`CoreConstants`: the latter
|
|
6
|
+
// transitively pulls infrastructure-config → aws-cdk-lib, which esbuild then tries
|
|
7
|
+
// to bundle into this Lambda (hundreds of MB → OOM/SIGKILL during cold-start synth).
|
|
8
|
+
import { HANDLER_TIMEOUT_MS, HANDLER_MAX_RETRIES, HANDLER_RETRY_DELAY_MS, HANDLER_DEFAULT_BASE_URL, } from '../config/handler-constants.js';
|
|
9
|
+
/**
|
|
10
|
+
* Structured logger for Lambda (outputs JSON to CloudWatch).
|
|
11
|
+
* Debug messages only emitted when LOG_LEVEL=debug.
|
|
12
|
+
*/
|
|
13
|
+
function logEntry(level, tag, message, data) {
|
|
14
|
+
const line = JSON.stringify({ level, tag, message, data, ts: new Date().toISOString() });
|
|
15
|
+
switch (level) {
|
|
16
|
+
case 'ERROR':
|
|
17
|
+
console.error(line);
|
|
18
|
+
break;
|
|
19
|
+
case 'DEBUG':
|
|
20
|
+
if (process.env.LOG_LEVEL === 'debug')
|
|
21
|
+
console.debug(line);
|
|
22
|
+
break;
|
|
23
|
+
default: console.log(line);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const lambdaLog = {
|
|
27
|
+
info: (tag, message, data) => logEntry('INFO', tag, message, data),
|
|
28
|
+
error: (tag, message, data) => logEntry('ERROR', tag, message, data),
|
|
29
|
+
debug: (tag, message, data) => logEntry('DEBUG', tag, message, data),
|
|
30
|
+
};
|
|
31
|
+
const RETRYABLE_STATUSES = new Set([429, 502, 503, 504]);
|
|
32
|
+
const RETRYABLE_CODES = new Set(['ECONNRESET', 'ECONNREFUSED', 'ETIMEDOUT']);
|
|
33
|
+
function sleep(ms) {
|
|
34
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
35
|
+
}
|
|
36
|
+
/** Platform secret name — injected as PLATFORM_SECRET_NAME env var by PluginLookup construct. */
|
|
37
|
+
const PLATFORM_SECRET_NAME = process.env.PLATFORM_SECRET_NAME;
|
|
38
|
+
if (!PLATFORM_SECRET_NAME) {
|
|
39
|
+
throw new Error('PLATFORM_SECRET_NAME environment variable is required');
|
|
40
|
+
}
|
|
41
|
+
/** Cached token to avoid repeated Secrets Manager calls within a single invocation. */
|
|
42
|
+
let cachedToken = null;
|
|
43
|
+
/** @internal Reset cached token (for testing only). */
|
|
44
|
+
export function _resetCredentialsCache() { cachedToken = null; }
|
|
45
|
+
/**
|
|
46
|
+
* Fetch JWT token from AWS Secrets Manager.
|
|
47
|
+
* Caches the result for the lifetime of the Lambda execution context.
|
|
48
|
+
*
|
|
49
|
+
* The secret name is set via PLATFORM_SECRET_NAME env var (e.g. `{prefix}/{orgId}/platform`)
|
|
50
|
+
* Create it with: `pipeline-manager infra store-token`
|
|
51
|
+
*/
|
|
52
|
+
async function getToken() {
|
|
53
|
+
if (cachedToken)
|
|
54
|
+
return cachedToken;
|
|
55
|
+
lambdaLog.info('AUTH', `Fetching token from Secrets Manager: ${PLATFORM_SECRET_NAME}`);
|
|
56
|
+
const client = new SecretsManagerClient({});
|
|
57
|
+
const response = await client.send(new GetSecretValueCommand({ SecretId: PLATFORM_SECRET_NAME }));
|
|
58
|
+
if (!response.SecretString) {
|
|
59
|
+
throw new Error(`Secret "${PLATFORM_SECRET_NAME}" is empty`);
|
|
60
|
+
}
|
|
61
|
+
const parsed = JSON.parse(response.SecretString);
|
|
62
|
+
// Schema is `{ username, password, ... }` — the `password` field is the
|
|
63
|
+
// platform JWT. Same secret is read by CodeBuild's `secretsManagerCredentials`
|
|
64
|
+
// for registry pulls (Basic auth: username:password = orgId:JWT). The
|
|
65
|
+
// pipeline-image-registry token endpoint validates the password as a JWT
|
|
66
|
+
// and issues a registry token scoped to the JWT's org.
|
|
67
|
+
if (!parsed.password) {
|
|
68
|
+
throw new Error(`Secret "${PLATFORM_SECRET_NAME}" missing password — run "pipeline-manager infra store-token" to generate`);
|
|
69
|
+
}
|
|
70
|
+
cachedToken = parsed.password;
|
|
71
|
+
lambdaLog.info('AUTH', 'Token retrieved from Secrets Manager');
|
|
72
|
+
return cachedToken;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Creates a pre-configured Axios instance for API requests.
|
|
76
|
+
*
|
|
77
|
+
* @param baseURL - Base URL of the target API
|
|
78
|
+
* @param token - JWT token for authorization
|
|
79
|
+
* @returns Configured Axios instance
|
|
80
|
+
*/
|
|
81
|
+
function create(baseURL, token) {
|
|
82
|
+
return axios.create({
|
|
83
|
+
baseURL,
|
|
84
|
+
timeout: HANDLER_TIMEOUT_MS,
|
|
85
|
+
headers: {
|
|
86
|
+
'Content-Type': 'application/json',
|
|
87
|
+
'Authorization': `Bearer ${token}`,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Fetches plugin configuration from the external API with retry logic.
|
|
93
|
+
* Retries on transient failures (429, 502, 503, 504, network errors)
|
|
94
|
+
* with exponential backoff.
|
|
95
|
+
*
|
|
96
|
+
* @param api - Configured Axios instance
|
|
97
|
+
* @param pluginFilter - Filter criteria for the plugin lookup
|
|
98
|
+
* @returns The plugin data returned by the API
|
|
99
|
+
* @throws Error on persistent failure, timeout or invalid response
|
|
100
|
+
*/
|
|
101
|
+
async function fetch(api, pluginFilter) {
|
|
102
|
+
lambdaLog.debug('FETCH', 'Starting plugin fetch', { filter: pluginFilter });
|
|
103
|
+
let lastError;
|
|
104
|
+
for (let attempt = 0; attempt <= HANDLER_MAX_RETRIES; attempt++) {
|
|
105
|
+
if (attempt > 0) {
|
|
106
|
+
const delay = HANDLER_RETRY_DELAY_MS * Math.pow(2, attempt - 1);
|
|
107
|
+
lambdaLog.info('RETRY', `Attempt ${attempt + 1}/${HANDLER_MAX_RETRIES + 1} after ${delay}ms`);
|
|
108
|
+
await sleep(delay);
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
const { data, status } = await api.post('/api/plugins/lookup', {
|
|
112
|
+
filter: pluginFilter,
|
|
113
|
+
});
|
|
114
|
+
if (!data) {
|
|
115
|
+
throw new Error('Empty response data from API');
|
|
116
|
+
}
|
|
117
|
+
lambdaLog.info('FETCH', 'Plugin fetched successfully', {
|
|
118
|
+
status,
|
|
119
|
+
plugin: data.name,
|
|
120
|
+
version: data.version,
|
|
121
|
+
id: data.id,
|
|
122
|
+
});
|
|
123
|
+
return data;
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
if (error instanceof AxiosError) {
|
|
127
|
+
if (error.code === 'ECONNABORTED') {
|
|
128
|
+
lambdaLog.error('FETCH', `Plugin lookup timed out after ${HANDLER_TIMEOUT_MS}ms`);
|
|
129
|
+
throw new Error(`Plugin lookup timed out after ${HANDLER_TIMEOUT_MS}ms`);
|
|
130
|
+
}
|
|
131
|
+
const retryable = error.response
|
|
132
|
+
? RETRYABLE_STATUSES.has(error.response.status)
|
|
133
|
+
: RETRYABLE_CODES.has(error.code ?? '');
|
|
134
|
+
const msg = error.response
|
|
135
|
+
? `API error ${error.response.status}: ${error.response.statusText}`
|
|
136
|
+
: error.code || error.message;
|
|
137
|
+
if (retryable && attempt < HANDLER_MAX_RETRIES) {
|
|
138
|
+
lambdaLog.info('RETRY', `Retryable error: ${msg}`, { attempt: attempt + 1 });
|
|
139
|
+
lastError = new Error(`Failed to fetch plugin: ${msg}`);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
// Don't log the upstream body verbatim — it may carry a stack trace,
|
|
143
|
+
// a request payload echo, or other sensitive data we shouldn't echo
|
|
144
|
+
// into Lambda CloudWatch logs. Keep just the high-level shape.
|
|
145
|
+
const safeBody = error.response?.data && typeof error.response.data === 'object'
|
|
146
|
+
? { code: error.response.data.code, message: error.response.data.message }
|
|
147
|
+
: undefined;
|
|
148
|
+
lambdaLog.error('FETCH', msg, { responseBody: safeBody });
|
|
149
|
+
throw new Error(`Failed to fetch plugin: ${msg}`);
|
|
150
|
+
}
|
|
151
|
+
throw error instanceof Error ? error : new Error('Unknown error during plugin fetch');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
throw lastError ?? new Error('Failed to fetch plugin after retries');
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Validates the plugin filter object
|
|
158
|
+
*
|
|
159
|
+
* @param pluginFilter - Filter to validate
|
|
160
|
+
* @returns true if valid
|
|
161
|
+
* @throws Error if invalid
|
|
162
|
+
*/
|
|
163
|
+
function validatePluginFilter(pluginFilter) {
|
|
164
|
+
if (!pluginFilter || typeof pluginFilter !== 'object') {
|
|
165
|
+
throw new Error('Missing or invalid pluginFilter');
|
|
166
|
+
}
|
|
167
|
+
const filter = pluginFilter;
|
|
168
|
+
if (!filter.name && !filter.id && !filter.version && !filter.orgId) {
|
|
169
|
+
throw new Error('PluginFilter must have at least one criterion (name, id, version, or orgId)');
|
|
170
|
+
}
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Lambda handler for CloudFormation Custom Resource that performs plugin lookup.
|
|
175
|
+
*
|
|
176
|
+
* Authenticates using JWT token from AWS Secrets Manager (PLATFORM_SECRET_NAME env var).
|
|
177
|
+
* Create the secret with: `pipeline-manager infra store-token`
|
|
178
|
+
*
|
|
179
|
+
* Request Types:
|
|
180
|
+
* - Create/Update: fetches and returns plugin configuration from API
|
|
181
|
+
* - Delete: no-op (always succeeds)
|
|
182
|
+
*
|
|
183
|
+
* Response:
|
|
184
|
+
* - Success: Returns base64-encoded plugin JSON in Data.ResultValue
|
|
185
|
+
* - Failure: Returns error message in Reason
|
|
186
|
+
*
|
|
187
|
+
* @param event - CloudFormation custom resource event
|
|
188
|
+
* @returns CloudFormation response
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* Custom Resource Properties:
|
|
192
|
+
* ```json
|
|
193
|
+
* {
|
|
194
|
+
* "baseURL": "https://api.example.com",
|
|
195
|
+
* "pluginFilter": {
|
|
196
|
+
* "name": "nodejs-build",
|
|
197
|
+
* "version": "1.0.0",
|
|
198
|
+
* "isActive": true
|
|
199
|
+
* }
|
|
200
|
+
* }
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
export const handler = async (event) => {
|
|
204
|
+
// NOTE: never log event.StackId here — the CloudFormation Stack ARN embeds the
|
|
205
|
+
// AWS account id (arn:aws:cloudformation:<region>:<ACCOUNT_ID>:stack/…), which
|
|
206
|
+
// must never be persisted to CloudWatch. requestId + logicalResourceId are
|
|
207
|
+
// sufficient for correlation. (StackId is still returned in the CFN response
|
|
208
|
+
// body below — that is the mandatory CFN protocol field and is not a log.)
|
|
209
|
+
lambdaLog.info('START', `${event.RequestType} request received`, {
|
|
210
|
+
logicalResourceId: event.LogicalResourceId,
|
|
211
|
+
requestId: event.RequestId,
|
|
212
|
+
});
|
|
213
|
+
const baseResponse = {
|
|
214
|
+
StackId: event.StackId,
|
|
215
|
+
RequestId: event.RequestId,
|
|
216
|
+
LogicalResourceId: event.LogicalResourceId,
|
|
217
|
+
PhysicalResourceId: event.LogicalResourceId,
|
|
218
|
+
};
|
|
219
|
+
try {
|
|
220
|
+
// Handle Delete - always succeed (no-op)
|
|
221
|
+
if (event.RequestType === 'Delete') {
|
|
222
|
+
lambdaLog.info('DELETE', 'No-op - returning SUCCESS');
|
|
223
|
+
return {
|
|
224
|
+
...baseResponse,
|
|
225
|
+
Status: 'SUCCESS',
|
|
226
|
+
Reason: 'Delete completed (no-op)',
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
// Extract and validate properties
|
|
230
|
+
const pluginFilter = event.ResourceProperties.pluginFilter;
|
|
231
|
+
const baseURL = event.ResourceProperties.baseURL || HANDLER_DEFAULT_BASE_URL;
|
|
232
|
+
if (!baseURL.startsWith('https://') && !baseURL.startsWith('http://')) {
|
|
233
|
+
throw new Error(`Invalid baseURL: "${baseURL}" — must start with http:// or https://`);
|
|
234
|
+
}
|
|
235
|
+
lambdaLog.info('CONFIG', 'Configuration loaded', { baseURL, pluginFilter });
|
|
236
|
+
validatePluginFilter(pluginFilter);
|
|
237
|
+
// Get token from Secrets Manager and create API client
|
|
238
|
+
const token = await getToken();
|
|
239
|
+
const api = create(baseURL, token);
|
|
240
|
+
// Fetch plugin
|
|
241
|
+
lambdaLog.info('FETCH', 'Initiating plugin lookup...');
|
|
242
|
+
const plugin = await fetch(api, pluginFilter);
|
|
243
|
+
lambdaLog.info('FETCH', 'Plugin retrieved successfully', {
|
|
244
|
+
name: plugin.name,
|
|
245
|
+
version: plugin.version,
|
|
246
|
+
id: plugin.id,
|
|
247
|
+
});
|
|
248
|
+
// Strip large fields to stay within CloudFormation's 4096-byte Data limit.
|
|
249
|
+
// CDK constructs only need the fields used by createCodeBuildStep().
|
|
250
|
+
const slim = {
|
|
251
|
+
id: plugin.id,
|
|
252
|
+
name: plugin.name,
|
|
253
|
+
version: plugin.version,
|
|
254
|
+
pluginType: plugin.pluginType,
|
|
255
|
+
computeType: plugin.computeType,
|
|
256
|
+
commands: plugin.commands,
|
|
257
|
+
installCommands: plugin.installCommands,
|
|
258
|
+
env: plugin.env,
|
|
259
|
+
metadata: plugin.metadata,
|
|
260
|
+
primaryOutputDirectory: plugin.primaryOutputDirectory,
|
|
261
|
+
secrets: plugin.secrets,
|
|
262
|
+
failureBehavior: plugin.failureBehavior,
|
|
263
|
+
timeout: plugin.timeout,
|
|
264
|
+
};
|
|
265
|
+
const encoded = Buffer.from(JSON.stringify(slim), 'utf-8').toString('base64');
|
|
266
|
+
lambdaLog.debug('ENCODE', 'Encoded plugin data', { length: encoded.length });
|
|
267
|
+
return {
|
|
268
|
+
...baseResponse,
|
|
269
|
+
Status: 'SUCCESS',
|
|
270
|
+
Reason: `Plugin '${plugin.name}' (v${plugin.version}) retrieved successfully`,
|
|
271
|
+
Data: {
|
|
272
|
+
ResultValue: encoded,
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
catch (error) {
|
|
277
|
+
const reason = error instanceof Error ? error.message : 'Unexpected error occurred';
|
|
278
|
+
lambdaLog.error('ERROR', 'Handler failed', {
|
|
279
|
+
reason,
|
|
280
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
281
|
+
});
|
|
282
|
+
return {
|
|
283
|
+
...baseResponse,
|
|
284
|
+
Status: 'FAILED',
|
|
285
|
+
Reason: reason,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
finally {
|
|
289
|
+
lambdaLog.info('END', 'Custom resource execution completed');
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLWxvb2t1cC1oYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2hhbmRsZXJzL3BsdWdpbi1sb29rdXAtaGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRzlGLE9BQU8sS0FBSyxFQUFFLEVBQXNCLFVBQVUsRUFBRSxNQUFNLE9BQU8sQ0FBQztBQUM5RCxtRkFBbUY7QUFDbkYsbUZBQW1GO0FBQ25GLHFGQUFxRjtBQUNyRixPQUFPLEVBQ0wsa0JBQWtCLEVBQ2xCLG1CQUFtQixFQUNuQixzQkFBc0IsRUFDdEIsd0JBQXdCLEdBQ3pCLE1BQU0sZ0NBQWdDLENBQUM7QUFFeEM7OztHQUdHO0FBQ0gsU0FBUyxRQUFRLENBQUMsS0FBYSxFQUFFLEdBQVcsRUFBRSxPQUFlLEVBQUUsSUFBYztJQUMzRSxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUN6RixRQUFRLEtBQUssRUFBRSxDQUFDO1FBQ2QsS0FBSyxPQUFPO1lBQUUsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUFDLE1BQU07UUFDekMsS0FBSyxPQUFPO1lBQUUsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsS0FBSyxPQUFPO2dCQUFFLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7WUFBQyxNQUFNO1FBQ2hGLFNBQVMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUM3QixDQUFDO0FBQ0gsQ0FBQztBQUVELE1BQU0sU0FBUyxHQUFHO0lBQ2hCLElBQUksRUFBRSxDQUFDLEdBQVcsRUFBRSxPQUFlLEVBQUUsSUFBYyxFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDO0lBQzVGLEtBQUssRUFBRSxDQUFDLEdBQVcsRUFBRSxPQUFlLEVBQUUsSUFBYyxFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDO0lBQzlGLEtBQUssRUFBRSxDQUFDLEdBQVcsRUFBRSxPQUFlLEVBQUUsSUFBYyxFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDO0NBQy9GLENBQUM7QUFFRixNQUFNLGtCQUFrQixHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztBQUN6RCxNQUFNLGVBQWUsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLFlBQVksRUFBRSxjQUFjLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQztBQUU3RSxTQUFTLEtBQUssQ0FBQyxFQUFVO0lBQ3ZCLE9BQU8sSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDekQsQ0FBQztBQUVELGlHQUFpRztBQUNqRyxNQUFNLG9CQUFvQixHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0JBQW9CLENBQUM7QUFDOUQsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7SUFDMUIsTUFBTSxJQUFJLEtBQUssQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO0FBQzNFLENBQUM7QUFFRCx1RkFBdUY7QUFDdkYsSUFBSSxXQUFXLEdBQWtCLElBQUksQ0FBQztBQUV0Qyx1REFBdUQ7QUFDdkQsTUFBTSxVQUFVLHNCQUFzQixLQUFXLFdBQVcsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO0FBRXRFOzs7Ozs7R0FNRztBQUNILEtBQUssVUFBVSxRQUFRO0lBQ3JCLElBQUksV0FBVztRQUFFLE9BQU8sV0FBVyxDQUFDO0lBRXBDLFNBQVMsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLHdDQUF3QyxvQkFBb0IsRUFBRSxDQUFDLENBQUM7SUFFdkYsTUFBTSxNQUFNLEdBQUcsSUFBSSxvQkFBb0IsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUM1QyxNQUFNLFFBQVEsR0FBRyxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxxQkFBcUIsQ0FBQyxFQUFFLFFBQVEsRUFBRSxvQkFBb0IsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUVsRyxJQUFJLENBQUMsUUFBUSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQzNCLE1BQU0sSUFBSSxLQUFLLENBQUMsV0FBVyxvQkFBb0IsWUFBWSxDQUFDLENBQUM7SUFDL0QsQ0FBQztJQUVELE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBMkIsQ0FBQztJQUMzRSx3RUFBd0U7SUFDeEUsK0VBQStFO0lBQy9FLHNFQUFzRTtJQUN0RSx5RUFBeUU7SUFDekUsdURBQXVEO0lBQ3ZELElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDckIsTUFBTSxJQUFJLEtBQUssQ0FBQyxXQUFXLG9CQUFvQiwyRUFBMkUsQ0FBQyxDQUFDO0lBQzlILENBQUM7SUFFRCxXQUFXLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQztJQUM5QixTQUFTLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxzQ0FBc0MsQ0FBQyxDQUFDO0lBQy9ELE9BQU8sV0FBVyxDQUFDO0FBQ3JCLENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxTQUFTLE1BQU0sQ0FBQyxPQUFlLEVBQUUsS0FBYTtJQUM1QyxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUM7UUFDbEIsT0FBTztRQUNQLE9BQU8sRUFBRSxrQkFBa0I7UUFDM0IsT0FBTyxFQUFFO1lBQ1AsY0FBYyxFQUFFLGtCQUFrQjtZQUNsQyxlQUFlLEVBQUUsVUFBVSxLQUFLLEVBQUU7U0FDbkM7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQ7Ozs7Ozs7OztHQVNHO0FBQ0gsS0FBSyxVQUFVLEtBQUssQ0FBQyxHQUFrQixFQUFFLFlBQTBCO0lBQ2pFLFNBQVMsQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLHVCQUF1QixFQUFFLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxDQUFDLENBQUM7SUFFNUUsSUFBSSxTQUE0QixDQUFDO0lBRWpDLEtBQUssSUFBSSxPQUFPLEdBQUcsQ0FBQyxFQUFFLE9BQU8sSUFBSSxtQkFBbUIsRUFBRSxPQUFPLEVBQUUsRUFBRSxDQUFDO1FBQ2hFLElBQUksT0FBTyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ2hCLE1BQU0sS0FBSyxHQUFHLHNCQUFzQixHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLE9BQU8sR0FBRyxDQUFDLENBQUMsQ0FBQztZQUNoRSxTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxXQUFXLE9BQU8sR0FBRyxDQUFDLElBQUksbUJBQW1CLEdBQUcsQ0FBQyxVQUFVLEtBQUssSUFBSSxDQUFDLENBQUM7WUFDOUYsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDckIsQ0FBQztRQUVELElBQUksQ0FBQztZQUNILE1BQU0sRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxHQUFHLENBQUMsSUFBSSxDQUFTLHFCQUFxQixFQUFFO2dCQUNyRSxNQUFNLEVBQUUsWUFBWTthQUNyQixDQUFDLENBQUM7WUFFSCxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQ1YsTUFBTSxJQUFJLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO1lBQ2xELENBQUM7WUFFRCxTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSw2QkFBNkIsRUFBRTtnQkFDckQsTUFBTTtnQkFDTixNQUFNLEVBQUUsSUFBSSxDQUFDLElBQUk7Z0JBQ2pCLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTztnQkFDckIsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFO2FBQ1osQ0FBQyxDQUFDO1lBRUgsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLElBQUksS0FBSyxZQUFZLFVBQVUsRUFBRSxDQUFDO2dCQUNoQyxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssY0FBYyxFQUFFLENBQUM7b0JBQ2xDLFNBQVMsQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLGlDQUFpQyxrQkFBa0IsSUFBSSxDQUFDLENBQUM7b0JBQ2xGLE1BQU0sSUFBSSxLQUFLLENBQUMsaUNBQWlDLGtCQUFrQixJQUFJLENBQUMsQ0FBQztnQkFDM0UsQ0FBQztnQkFFRCxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsUUFBUTtvQkFDOUIsQ0FBQyxDQUFDLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQztvQkFDL0MsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFFMUMsTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFDLFFBQVE7b0JBQ3hCLENBQUMsQ0FBQyxhQUFhLEtBQUssQ0FBQyxRQUFRLENBQUMsTUFBTSxLQUFLLEtBQUssQ0FBQyxRQUFRLENBQUMsVUFBVSxFQUFFO29CQUNwRSxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDO2dCQUVoQyxJQUFJLFNBQVMsSUFBSSxPQUFPLEdBQUcsbUJBQW1CLEVBQUUsQ0FBQztvQkFDL0MsU0FBUyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsb0JBQW9CLEdBQUcsRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLE9BQU8sR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO29CQUM3RSxTQUFTLEdBQUcsSUFBSSxLQUFLLENBQUMsMkJBQTJCLEdBQUcsRUFBRSxDQUFDLENBQUM7b0JBQ3hELFNBQVM7Z0JBQ1gsQ0FBQztnQkFFRCxxRUFBcUU7Z0JBQ3JFLG9FQUFvRTtnQkFDcEUsK0RBQStEO2dCQUMvRCxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsUUFBUSxFQUFFLElBQUksSUFBSSxPQUFPLEtBQUssQ0FBQyxRQUFRLENBQUMsSUFBSSxLQUFLLFFBQVE7b0JBQzlFLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRyxLQUFLLENBQUMsUUFBUSxDQUFDLElBQTBCLENBQUMsSUFBSSxFQUFFLE9BQU8sRUFBRyxLQUFLLENBQUMsUUFBUSxDQUFDLElBQTZCLENBQUMsT0FBTyxFQUFFO29CQUMzSCxDQUFDLENBQUMsU0FBUyxDQUFDO2dCQUNkLFNBQVMsQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO2dCQUMxRCxNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixHQUFHLEVBQUUsQ0FBQyxDQUFDO1lBQ3BELENBQUM7WUFFRCxNQUFNLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLENBQUMsbUNBQW1DLENBQUMsQ0FBQztRQUN4RixDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU0sU0FBUyxJQUFJLElBQUksS0FBSyxDQUFDLHNDQUFzQyxDQUFDLENBQUM7QUFDdkUsQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILFNBQVMsb0JBQW9CLENBQUMsWUFBcUI7SUFDakQsSUFBSSxDQUFDLFlBQVksSUFBSSxPQUFPLFlBQVksS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUN0RCxNQUFNLElBQUksS0FBSyxDQUFDLGlDQUFpQyxDQUFDLENBQUM7SUFDckQsQ0FBQztJQUVELE1BQU0sTUFBTSxHQUFHLFlBQXVDLENBQUM7SUFDdkQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNuRSxNQUFNLElBQUksS0FBSyxDQUFDLDZFQUE2RSxDQUFDLENBQUM7SUFDakcsQ0FBQztJQUVELE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTZCRztBQUNILE1BQU0sQ0FBQyxNQUFNLE9BQU8sR0FBRyxLQUFLLEVBQzFCLEtBQXdDLEVBQ08sRUFBRTtJQUNqRCwrRUFBK0U7SUFDL0UsK0VBQStFO0lBQy9FLDJFQUEyRTtJQUMzRSw2RUFBNkU7SUFDN0UsMkVBQTJFO0lBQzNFLFNBQVMsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLEdBQUcsS0FBSyxDQUFDLFdBQVcsbUJBQW1CLEVBQUU7UUFDL0QsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLGlCQUFpQjtRQUMxQyxTQUFTLEVBQUUsS0FBSyxDQUFDLFNBQVM7S0FDM0IsQ0FBQyxDQUFDO0lBRUgsTUFBTSxZQUFZLEdBQWtEO1FBQ2xFLE9BQU8sRUFBRSxLQUFLLENBQUMsT0FBTztRQUN0QixTQUFTLEVBQUUsS0FBSyxDQUFDLFNBQVM7UUFDMUIsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLGlCQUFpQjtRQUMxQyxrQkFBa0IsRUFBRSxLQUFLLENBQUMsaUJBQWlCO0tBQzVDLENBQUM7SUFFRixJQUFJLENBQUM7UUFDSCx5Q0FBeUM7UUFDekMsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ25DLFNBQVMsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLDJCQUEyQixDQUFDLENBQUM7WUFDdEQsT0FBTztnQkFDTCxHQUFHLFlBQVk7Z0JBQ2YsTUFBTSxFQUFFLFNBQVM7Z0JBQ2pCLE1BQU0sRUFBRSwwQkFBMEI7YUFDSyxDQUFDO1FBQzVDLENBQUM7UUFFRCxrQ0FBa0M7UUFDbEMsTUFBTSxZQUFZLEdBQUcsS0FBSyxDQUFDLGtCQUFrQixDQUFDLFlBQVksQ0FBQztRQUMzRCxNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsa0JBQWtCLENBQUMsT0FBTyxJQUFJLHdCQUF3QixDQUFDO1FBRTdFLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1lBQ3RFLE1BQU0sSUFBSSxLQUFLLENBQUMscUJBQXFCLE9BQU8seUNBQXlDLENBQUMsQ0FBQztRQUN6RixDQUFDO1FBRUQsU0FBUyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsc0JBQXNCLEVBQUUsRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLENBQUMsQ0FBQztRQUU1RSxvQkFBb0IsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUVuQyx1REFBdUQ7UUFDdkQsTUFBTSxLQUFLLEdBQUcsTUFBTSxRQUFRLEVBQUUsQ0FBQztRQUMvQixNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRW5DLGVBQWU7UUFDZixTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSw2QkFBNkIsQ0FBQyxDQUFDO1FBQ3ZELE1BQU0sTUFBTSxHQUFHLE1BQU0sS0FBSyxDQUFDLEdBQUcsRUFBRSxZQUFZLENBQUMsQ0FBQztRQUM5QyxTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSwrQkFBK0IsRUFBRTtZQUN2RCxJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUk7WUFDakIsT0FBTyxFQUFFLE1BQU0sQ0FBQyxPQUFPO1lBQ3ZCLEVBQUUsRUFBRSxNQUFNLENBQUMsRUFBRTtTQUNkLENBQUMsQ0FBQztRQUVILDJFQUEyRTtRQUMzRSxxRUFBcUU7UUFDckUsTUFBTSxJQUFJLEdBQUc7WUFDWCxFQUFFLEVBQUUsTUFBTSxDQUFDLEVBQUU7WUFDYixJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUk7WUFDakIsT0FBTyxFQUFFLE1BQU0sQ0FBQyxPQUFPO1lBQ3ZCLFVBQVUsRUFBRSxNQUFNLENBQUMsVUFBVTtZQUM3QixXQUFXLEVBQUUsTUFBTSxDQUFDLFdBQVc7WUFDL0IsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRO1lBQ3pCLGVBQWUsRUFBRSxNQUFNLENBQUMsZUFBZTtZQUN2QyxHQUFHLEVBQUUsTUFBTSxDQUFDLEdBQUc7WUFDZixRQUFRLEVBQUUsTUFBTSxDQUFDLFFBQVE7WUFDekIsc0JBQXNCLEVBQUUsTUFBTSxDQUFDLHNCQUFzQjtZQUNyRCxPQUFPLEVBQUUsTUFBTSxDQUFDLE9BQU87WUFDdkIsZUFBZSxFQUFFLE1BQU0sQ0FBQyxlQUFlO1lBQ3ZDLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTztTQUN4QixDQUFDO1FBRUYsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM5RSxTQUFTLENBQUMsS0FBSyxDQUFDLFFBQVEsRUFBRSxxQkFBcUIsRUFBRSxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUU3RSxPQUFPO1lBQ0wsR0FBRyxZQUFZO1lBQ2YsTUFBTSxFQUFFLFNBQVM7WUFDakIsTUFBTSxFQUFFLFdBQVcsTUFBTSxDQUFDLElBQUksT0FBTyxNQUFNLENBQUMsT0FBTywwQkFBMEI7WUFDN0UsSUFBSSxFQUFFO2dCQUNKLFdBQVcsRUFBRSxPQUFPO2FBQ3JCO1NBQ3NDLENBQUM7SUFDNUMsQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDZixNQUFNLE1BQU0sR0FBRyxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQywyQkFBMkIsQ0FBQztRQUNwRixTQUFTLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRTtZQUN6QyxNQUFNO1lBQ04sS0FBSyxFQUFFLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFNBQVM7U0FDeEQsQ0FBQyxDQUFDO1FBRUgsT0FBTztZQUNMLEdBQUcsWUFBWTtZQUNmLE1BQU0sRUFBRSxRQUFRO1lBQ2hCLE1BQU0sRUFBRSxNQUFNO1NBQ3lCLENBQUM7SUFDNUMsQ0FBQztZQUFTLENBQUM7UUFDVCxTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxxQ0FBcUMsQ0FBQyxDQUFDO0lBQy9ELENBQUM7QUFDSCxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgR2V0U2VjcmV0VmFsdWVDb21tYW5kLCBTZWNyZXRzTWFuYWdlckNsaWVudCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1zZWNyZXRzLW1hbmFnZXInO1xuaW1wb3J0IHR5cGUgeyBQbHVnaW5GaWx0ZXIsIFBsdWdpbiB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL3BpcGVsaW5lLWRhdGEnO1xuaW1wb3J0IHR5cGUgeyBDbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQsIENsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VSZXNwb25zZSB9IGZyb20gJ2F3cy1sYW1iZGEnO1xuaW1wb3J0IGF4aW9zLCB7IHR5cGUgQXhpb3NJbnN0YW5jZSwgQXhpb3NFcnJvciB9IGZyb20gJ2F4aW9zJztcbi8vIEltcG9ydCB0aGUgZGVwZW5kZW5jeS1mcmVlIGxlYWYsIE5PVCBgYXBwLWNvbmZpZy5qc2AvYENvcmVDb25zdGFudHNgOiB0aGUgbGF0dGVyXG4vLyB0cmFuc2l0aXZlbHkgcHVsbHMgaW5mcmFzdHJ1Y3R1cmUtY29uZmlnIOKGkiBhd3MtY2RrLWxpYiwgd2hpY2ggZXNidWlsZCB0aGVuIHRyaWVzXG4vLyB0byBidW5kbGUgaW50byB0aGlzIExhbWJkYSAoaHVuZHJlZHMgb2YgTUIg4oaSIE9PTS9TSUdLSUxMIGR1cmluZyBjb2xkLXN0YXJ0IHN5bnRoKS5cbmltcG9ydCB7XG4gIEhBTkRMRVJfVElNRU9VVF9NUyxcbiAgSEFORExFUl9NQVhfUkVUUklFUyxcbiAgSEFORExFUl9SRVRSWV9ERUxBWV9NUyxcbiAgSEFORExFUl9ERUZBVUxUX0JBU0VfVVJMLFxufSBmcm9tICcuLi9jb25maWcvaGFuZGxlci1jb25zdGFudHMuanMnO1xuXG4vKipcbiAqIFN0cnVjdHVyZWQgbG9nZ2VyIGZvciBMYW1iZGEgKG91dHB1dHMgSlNPTiB0byBDbG91ZFdhdGNoKS5cbiAqIERlYnVnIG1lc3NhZ2VzIG9ubHkgZW1pdHRlZCB3aGVuIExPR19MRVZFTD1kZWJ1Zy5cbiAqL1xuZnVuY3Rpb24gbG9nRW50cnkobGV2ZWw6IHN0cmluZywgdGFnOiBzdHJpbmcsIG1lc3NhZ2U6IHN0cmluZywgZGF0YT86IHVua25vd24pIHtcbiAgY29uc3QgbGluZSA9IEpTT04uc3RyaW5naWZ5KHsgbGV2ZWwsIHRhZywgbWVzc2FnZSwgZGF0YSwgdHM6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSB9KTtcbiAgc3dpdGNoIChsZXZlbCkge1xuICAgIGNhc2UgJ0VSUk9SJzogY29uc29sZS5lcnJvcihsaW5lKTsgYnJlYWs7XG4gICAgY2FzZSAnREVCVUcnOiBpZiAocHJvY2Vzcy5lbnYuTE9HX0xFVkVMID09PSAnZGVidWcnKSBjb25zb2xlLmRlYnVnKGxpbmUpOyBicmVhaztcbiAgICBkZWZhdWx0OiBjb25zb2xlLmxvZyhsaW5lKTtcbiAgfVxufVxuXG5jb25zdCBsYW1iZGFMb2cgPSB7XG4gIGluZm86ICh0YWc6IHN0cmluZywgbWVzc2FnZTogc3RyaW5nLCBkYXRhPzogdW5rbm93bikgPT4gbG9nRW50cnkoJ0lORk8nLCB0YWcsIG1lc3NhZ2UsIGRhdGEpLFxuICBlcnJvcjogKHRhZzogc3RyaW5nLCBtZXNzYWdlOiBzdHJpbmcsIGRhdGE/OiB1bmtub3duKSA9PiBsb2dFbnRyeSgnRVJST1InLCB0YWcsIG1lc3NhZ2UsIGRhdGEpLFxuICBkZWJ1ZzogKHRhZzogc3RyaW5nLCBtZXNzYWdlOiBzdHJpbmcsIGRhdGE/OiB1bmtub3duKSA9PiBsb2dFbnRyeSgnREVCVUcnLCB0YWcsIG1lc3NhZ2UsIGRhdGEpLFxufTtcblxuY29uc3QgUkVUUllBQkxFX1NUQVRVU0VTID0gbmV3IFNldChbNDI5LCA1MDIsIDUwMywgNTA0XSk7XG5jb25zdCBSRVRSWUFCTEVfQ09ERVMgPSBuZXcgU2V0KFsnRUNPTk5SRVNFVCcsICdFQ09OTlJFRlVTRUQnLCAnRVRJTUVET1VUJ10pO1xuXG5mdW5jdGlvbiBzbGVlcChtczogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpKTtcbn1cblxuLyoqIFBsYXRmb3JtIHNlY3JldCBuYW1lIOKAlCBpbmplY3RlZCBhcyBQTEFURk9STV9TRUNSRVRfTkFNRSBlbnYgdmFyIGJ5IFBsdWdpbkxvb2t1cCBjb25zdHJ1Y3QuICovXG5jb25zdCBQTEFURk9STV9TRUNSRVRfTkFNRSA9IHByb2Nlc3MuZW52LlBMQVRGT1JNX1NFQ1JFVF9OQU1FO1xuaWYgKCFQTEFURk9STV9TRUNSRVRfTkFNRSkge1xuICB0aHJvdyBuZXcgRXJyb3IoJ1BMQVRGT1JNX1NFQ1JFVF9OQU1FIGVudmlyb25tZW50IHZhcmlhYmxlIGlzIHJlcXVpcmVkJyk7XG59XG5cbi8qKiBDYWNoZWQgdG9rZW4gdG8gYXZvaWQgcmVwZWF0ZWQgU2VjcmV0cyBNYW5hZ2VyIGNhbGxzIHdpdGhpbiBhIHNpbmdsZSBpbnZvY2F0aW9uLiAqL1xubGV0IGNhY2hlZFRva2VuOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcblxuLyoqIEBpbnRlcm5hbCBSZXNldCBjYWNoZWQgdG9rZW4gKGZvciB0ZXN0aW5nIG9ubHkpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIF9yZXNldENyZWRlbnRpYWxzQ2FjaGUoKTogdm9pZCB7IGNhY2hlZFRva2VuID0gbnVsbDsgfVxuXG4vKipcbiAqIEZldGNoIEpXVCB0b2tlbiBmcm9tIEFXUyBTZWNyZXRzIE1hbmFnZXIuXG4gKiBDYWNoZXMgdGhlIHJlc3VsdCBmb3IgdGhlIGxpZmV0aW1lIG9mIHRoZSBMYW1iZGEgZXhlY3V0aW9uIGNvbnRleHQuXG4gKlxuICogVGhlIHNlY3JldCBuYW1lIGlzIHNldCB2aWEgUExBVEZPUk1fU0VDUkVUX05BTUUgZW52IHZhciAoZS5nLiBge3ByZWZpeH0ve29yZ0lkfS9wbGF0Zm9ybWApXG4gKiBDcmVhdGUgaXQgd2l0aDogYHBpcGVsaW5lLW1hbmFnZXIgaW5mcmEgc3RvcmUtdG9rZW5gXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGdldFRva2VuKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGlmIChjYWNoZWRUb2tlbikgcmV0dXJuIGNhY2hlZFRva2VuO1xuXG4gIGxhbWJkYUxvZy5pbmZvKCdBVVRIJywgYEZldGNoaW5nIHRva2VuIGZyb20gU2VjcmV0cyBNYW5hZ2VyOiAke1BMQVRGT1JNX1NFQ1JFVF9OQU1FfWApO1xuXG4gIGNvbnN0IGNsaWVudCA9IG5ldyBTZWNyZXRzTWFuYWdlckNsaWVudCh7fSk7XG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LnNlbmQobmV3IEdldFNlY3JldFZhbHVlQ29tbWFuZCh7IFNlY3JldElkOiBQTEFURk9STV9TRUNSRVRfTkFNRSB9KSk7XG5cbiAgaWYgKCFyZXNwb25zZS5TZWNyZXRTdHJpbmcpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFNlY3JldCBcIiR7UExBVEZPUk1fU0VDUkVUX05BTUV9XCIgaXMgZW1wdHlgKTtcbiAgfVxuXG4gIGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2UocmVzcG9uc2UuU2VjcmV0U3RyaW5nKSBhcyBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICAvLyBTY2hlbWEgaXMgYHsgdXNlcm5hbWUsIHBhc3N3b3JkLCAuLi4gfWAg4oCUIHRoZSBgcGFzc3dvcmRgIGZpZWxkIGlzIHRoZVxuICAvLyBwbGF0Zm9ybSBKV1QuIFNhbWUgc2VjcmV0IGlzIHJlYWQgYnkgQ29kZUJ1aWxkJ3MgYHNlY3JldHNNYW5hZ2VyQ3JlZGVudGlhbHNgXG4gIC8vIGZvciByZWdpc3RyeSBwdWxscyAoQmFzaWMgYXV0aDogdXNlcm5hbWU6cGFzc3dvcmQgPSBvcmdJZDpKV1QpLiBUaGVcbiAgLy8gcGlwZWxpbmUtaW1hZ2UtcmVnaXN0cnkgdG9rZW4gZW5kcG9pbnQgdmFsaWRhdGVzIHRoZSBwYXNzd29yZCBhcyBhIEpXVFxuICAvLyBhbmQgaXNzdWVzIGEgcmVnaXN0cnkgdG9rZW4gc2NvcGVkIHRvIHRoZSBKV1QncyBvcmcuXG4gIGlmICghcGFyc2VkLnBhc3N3b3JkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBTZWNyZXQgXCIke1BMQVRGT1JNX1NFQ1JFVF9OQU1FfVwiIG1pc3NpbmcgcGFzc3dvcmQg4oCUIHJ1biBcInBpcGVsaW5lLW1hbmFnZXIgaW5mcmEgc3RvcmUtdG9rZW5cIiB0byBnZW5lcmF0ZWApO1xuICB9XG5cbiAgY2FjaGVkVG9rZW4gPSBwYXJzZWQucGFzc3dvcmQ7XG4gIGxhbWJkYUxvZy5pbmZvKCdBVVRIJywgJ1Rva2VuIHJldHJpZXZlZCBmcm9tIFNlY3JldHMgTWFuYWdlcicpO1xuICByZXR1cm4gY2FjaGVkVG9rZW47XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIHByZS1jb25maWd1cmVkIEF4aW9zIGluc3RhbmNlIGZvciBBUEkgcmVxdWVzdHMuXG4gKlxuICogQHBhcmFtIGJhc2VVUkwgLSBCYXNlIFVSTCBvZiB0aGUgdGFyZ2V0IEFQSVxuICogQHBhcmFtIHRva2VuIC0gSldUIHRva2VuIGZvciBhdXRob3JpemF0aW9uXG4gKiBAcmV0dXJucyBDb25maWd1cmVkIEF4aW9zIGluc3RhbmNlXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZShiYXNlVVJMOiBzdHJpbmcsIHRva2VuOiBzdHJpbmcpOiBBeGlvc0luc3RhbmNlIHtcbiAgcmV0dXJuIGF4aW9zLmNyZWF0ZSh7XG4gICAgYmFzZVVSTCxcbiAgICB0aW1lb3V0OiBIQU5ETEVSX1RJTUVPVVRfTVMsXG4gICAgaGVhZGVyczoge1xuICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3Rva2VufWAsXG4gICAgfSxcbiAgfSk7XG59XG5cbi8qKlxuICogRmV0Y2hlcyBwbHVnaW4gY29uZmlndXJhdGlvbiBmcm9tIHRoZSBleHRlcm5hbCBBUEkgd2l0aCByZXRyeSBsb2dpYy5cbiAqIFJldHJpZXMgb24gdHJhbnNpZW50IGZhaWx1cmVzICg0MjksIDUwMiwgNTAzLCA1MDQsIG5ldHdvcmsgZXJyb3JzKVxuICogd2l0aCBleHBvbmVudGlhbCBiYWNrb2ZmLlxuICpcbiAqIEBwYXJhbSBhcGkgLSBDb25maWd1cmVkIEF4aW9zIGluc3RhbmNlXG4gKiBAcGFyYW0gcGx1Z2luRmlsdGVyIC0gRmlsdGVyIGNyaXRlcmlhIGZvciB0aGUgcGx1Z2luIGxvb2t1cFxuICogQHJldHVybnMgVGhlIHBsdWdpbiBkYXRhIHJldHVybmVkIGJ5IHRoZSBBUElcbiAqIEB0aHJvd3MgRXJyb3Igb24gcGVyc2lzdGVudCBmYWlsdXJlLCB0aW1lb3V0IG9yIGludmFsaWQgcmVzcG9uc2VcbiAqL1xuYXN5bmMgZnVuY3Rpb24gZmV0Y2goYXBpOiBBeGlvc0luc3RhbmNlLCBwbHVnaW5GaWx0ZXI6IFBsdWdpbkZpbHRlcik6IFByb21pc2U8UGx1Z2luPiB7XG4gIGxhbWJkYUxvZy5kZWJ1ZygnRkVUQ0gnLCAnU3RhcnRpbmcgcGx1Z2luIGZldGNoJywgeyBmaWx0ZXI6IHBsdWdpbkZpbHRlciB9KTtcblxuICBsZXQgbGFzdEVycm9yOiBFcnJvciB8IHVuZGVmaW5lZDtcblxuICBmb3IgKGxldCBhdHRlbXB0ID0gMDsgYXR0ZW1wdCA8PSBIQU5ETEVSX01BWF9SRVRSSUVTOyBhdHRlbXB0KyspIHtcbiAgICBpZiAoYXR0ZW1wdCA+IDApIHtcbiAgICAgIGNvbnN0IGRlbGF5ID0gSEFORExFUl9SRVRSWV9ERUxBWV9NUyAqIE1hdGgucG93KDIsIGF0dGVtcHQgLSAxKTtcbiAgICAgIGxhbWJkYUxvZy5pbmZvKCdSRVRSWScsIGBBdHRlbXB0ICR7YXR0ZW1wdCArIDF9LyR7SEFORExFUl9NQVhfUkVUUklFUyArIDF9IGFmdGVyICR7ZGVsYXl9bXNgKTtcbiAgICAgIGF3YWl0IHNsZWVwKGRlbGF5KTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgeyBkYXRhLCBzdGF0dXMgfSA9IGF3YWl0IGFwaS5wb3N0PFBsdWdpbj4oJy9hcGkvcGx1Z2lucy9sb29rdXAnLCB7XG4gICAgICAgIGZpbHRlcjogcGx1Z2luRmlsdGVyLFxuICAgICAgfSk7XG5cbiAgICAgIGlmICghZGF0YSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0VtcHR5IHJlc3BvbnNlIGRhdGEgZnJvbSBBUEknKTtcbiAgICAgIH1cblxuICAgICAgbGFtYmRhTG9nLmluZm8oJ0ZFVENIJywgJ1BsdWdpbiBmZXRjaGVkIHN1Y2Nlc3NmdWxseScsIHtcbiAgICAgICAgc3RhdHVzLFxuICAgICAgICBwbHVnaW46IGRhdGEubmFtZSxcbiAgICAgICAgdmVyc2lvbjogZGF0YS52ZXJzaW9uLFxuICAgICAgICBpZDogZGF0YS5pZCxcbiAgICAgIH0pO1xuXG4gICAgICByZXR1cm4gZGF0YTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgQXhpb3NFcnJvcikge1xuICAgICAgICBpZiAoZXJyb3IuY29kZSA9PT0gJ0VDT05OQUJPUlRFRCcpIHtcbiAgICAgICAgICBsYW1iZGFMb2cuZXJyb3IoJ0ZFVENIJywgYFBsdWdpbiBsb29rdXAgdGltZWQgb3V0IGFmdGVyICR7SEFORExFUl9USU1FT1VUX01TfW1zYCk7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBQbHVnaW4gbG9va3VwIHRpbWVkIG91dCBhZnRlciAke0hBTkRMRVJfVElNRU9VVF9NU31tc2ApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmV0cnlhYmxlID0gZXJyb3IucmVzcG9uc2VcbiAgICAgICAgICA/IFJFVFJZQUJMRV9TVEFUVVNFUy5oYXMoZXJyb3IucmVzcG9uc2Uuc3RhdHVzKVxuICAgICAgICAgIDogUkVUUllBQkxFX0NPREVTLmhhcyhlcnJvci5jb2RlID8/ICcnKTtcblxuICAgICAgICBjb25zdCBtc2cgPSBlcnJvci5yZXNwb25zZVxuICAgICAgICAgID8gYEFQSSBlcnJvciAke2Vycm9yLnJlc3BvbnNlLnN0YXR1c306ICR7ZXJyb3IucmVzcG9uc2Uuc3RhdHVzVGV4dH1gXG4gICAgICAgICAgOiBlcnJvci5jb2RlIHx8IGVycm9yLm1lc3NhZ2U7XG5cbiAgICAgICAgaWYgKHJldHJ5YWJsZSAmJiBhdHRlbXB0IDwgSEFORExFUl9NQVhfUkVUUklFUykge1xuICAgICAgICAgIGxhbWJkYUxvZy5pbmZvKCdSRVRSWScsIGBSZXRyeWFibGUgZXJyb3I6ICR7bXNnfWAsIHsgYXR0ZW1wdDogYXR0ZW1wdCArIDEgfSk7XG4gICAgICAgICAgbGFzdEVycm9yID0gbmV3IEVycm9yKGBGYWlsZWQgdG8gZmV0Y2ggcGx1Z2luOiAke21zZ31gKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIERvbid0IGxvZyB0aGUgdXBzdHJlYW0gYm9keSB2ZXJiYXRpbSDigJQgaXQgbWF5IGNhcnJ5IGEgc3RhY2sgdHJhY2UsXG4gICAgICAgIC8vIGEgcmVxdWVzdCBwYXlsb2FkIGVjaG8sIG9yIG90aGVyIHNlbnNpdGl2ZSBkYXRhIHdlIHNob3VsZG4ndCBlY2hvXG4gICAgICAgIC8vIGludG8gTGFtYmRhIENsb3VkV2F0Y2ggbG9ncy4gS2VlcCBqdXN0IHRoZSBoaWdoLWxldmVsIHNoYXBlLlxuICAgICAgICBjb25zdCBzYWZlQm9keSA9IGVycm9yLnJlc3BvbnNlPy5kYXRhICYmIHR5cGVvZiBlcnJvci5yZXNwb25zZS5kYXRhID09PSAnb2JqZWN0J1xuICAgICAgICAgID8geyBjb2RlOiAoZXJyb3IucmVzcG9uc2UuZGF0YSBhcyB7IGNvZGU/OiBzdHJpbmcgfSkuY29kZSwgbWVzc2FnZTogKGVycm9yLnJlc3BvbnNlLmRhdGEgYXMgeyBtZXNzYWdlPzogc3RyaW5nIH0pLm1lc3NhZ2UgfVxuICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgICAgICBsYW1iZGFMb2cuZXJyb3IoJ0ZFVENIJywgbXNnLCB7IHJlc3BvbnNlQm9keTogc2FmZUJvZHkgfSk7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIGZldGNoIHBsdWdpbjogJHttc2d9YCk7XG4gICAgICB9XG5cbiAgICAgIHRocm93IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcignVW5rbm93biBlcnJvciBkdXJpbmcgcGx1Z2luIGZldGNoJyk7XG4gICAgfVxuICB9XG5cbiAgdGhyb3cgbGFzdEVycm9yID8/IG5ldyBFcnJvcignRmFpbGVkIHRvIGZldGNoIHBsdWdpbiBhZnRlciByZXRyaWVzJyk7XG59XG5cbi8qKlxuICogVmFsaWRhdGVzIHRoZSBwbHVnaW4gZmlsdGVyIG9iamVjdFxuICpcbiAqIEBwYXJhbSBwbHVnaW5GaWx0ZXIgLSBGaWx0ZXIgdG8gdmFsaWRhdGVcbiAqIEByZXR1cm5zIHRydWUgaWYgdmFsaWRcbiAqIEB0aHJvd3MgRXJyb3IgaWYgaW52YWxpZFxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZVBsdWdpbkZpbHRlcihwbHVnaW5GaWx0ZXI6IHVua25vd24pOiBwbHVnaW5GaWx0ZXIgaXMgUGx1Z2luRmlsdGVyIHtcbiAgaWYgKCFwbHVnaW5GaWx0ZXIgfHwgdHlwZW9mIHBsdWdpbkZpbHRlciAhPT0gJ29iamVjdCcpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ01pc3Npbmcgb3IgaW52YWxpZCBwbHVnaW5GaWx0ZXInKTtcbiAgfVxuXG4gIGNvbnN0IGZpbHRlciA9IHBsdWdpbkZpbHRlciBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgaWYgKCFmaWx0ZXIubmFtZSAmJiAhZmlsdGVyLmlkICYmICFmaWx0ZXIudmVyc2lvbiAmJiAhZmlsdGVyLm9yZ0lkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdQbHVnaW5GaWx0ZXIgbXVzdCBoYXZlIGF0IGxlYXN0IG9uZSBjcml0ZXJpb24gKG5hbWUsIGlkLCB2ZXJzaW9uLCBvciBvcmdJZCknKTtcbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufVxuXG4vKipcbiAqIExhbWJkYSBoYW5kbGVyIGZvciBDbG91ZEZvcm1hdGlvbiBDdXN0b20gUmVzb3VyY2UgdGhhdCBwZXJmb3JtcyBwbHVnaW4gbG9va3VwLlxuICpcbiAqIEF1dGhlbnRpY2F0ZXMgdXNpbmcgSldUIHRva2VuIGZyb20gQVdTIFNlY3JldHMgTWFuYWdlciAoUExBVEZPUk1fU0VDUkVUX05BTUUgZW52IHZhcikuXG4gKiBDcmVhdGUgdGhlIHNlY3JldCB3aXRoOiBgcGlwZWxpbmUtbWFuYWdlciBpbmZyYSBzdG9yZS10b2tlbmBcbiAqXG4gKiBSZXF1ZXN0IFR5cGVzOlxuICogLSBDcmVhdGUvVXBkYXRlOiBmZXRjaGVzIGFuZCByZXR1cm5zIHBsdWdpbiBjb25maWd1cmF0aW9uIGZyb20gQVBJXG4gKiAtIERlbGV0ZTogbm8tb3AgKGFsd2F5cyBzdWNjZWVkcylcbiAqXG4gKiBSZXNwb25zZTpcbiAqIC0gU3VjY2VzczogUmV0dXJucyBiYXNlNjQtZW5jb2RlZCBwbHVnaW4gSlNPTiBpbiBEYXRhLlJlc3VsdFZhbHVlXG4gKiAtIEZhaWx1cmU6IFJldHVybnMgZXJyb3IgbWVzc2FnZSBpbiBSZWFzb25cbiAqXG4gKiBAcGFyYW0gZXZlbnQgLSBDbG91ZEZvcm1hdGlvbiBjdXN0b20gcmVzb3VyY2UgZXZlbnRcbiAqIEByZXR1cm5zIENsb3VkRm9ybWF0aW9uIHJlc3BvbnNlXG4gKlxuICogQGV4YW1wbGVcbiAqIEN1c3RvbSBSZXNvdXJjZSBQcm9wZXJ0aWVzOlxuICogYGBganNvblxuICoge1xuICogICBcImJhc2VVUkxcIjogXCJodHRwczovL2FwaS5leGFtcGxlLmNvbVwiLFxuICogICBcInBsdWdpbkZpbHRlclwiOiB7XG4gKiAgICAgXCJuYW1lXCI6IFwibm9kZWpzLWJ1aWxkXCIsXG4gKiAgICAgXCJ2ZXJzaW9uXCI6IFwiMS4wLjBcIixcbiAqICAgICBcImlzQWN0aXZlXCI6IHRydWVcbiAqICAgfVxuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBjb25zdCBoYW5kbGVyID0gYXN5bmMgKFxuICBldmVudDogQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50LFxuKTogUHJvbWlzZTxDbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlUmVzcG9uc2U+ID0+IHtcbiAgLy8gTk9URTogbmV2ZXIgbG9nIGV2ZW50LlN0YWNrSWQgaGVyZSDigJQgdGhlIENsb3VkRm9ybWF0aW9uIFN0YWNrIEFSTiBlbWJlZHMgdGhlXG4gIC8vIEFXUyBhY2NvdW50IGlkIChhcm46YXdzOmNsb3VkZm9ybWF0aW9uOjxyZWdpb24+OjxBQ0NPVU5UX0lEPjpzdGFjay/igKYpLCB3aGljaFxuICAvLyBtdXN0IG5ldmVyIGJlIHBlcnNpc3RlZCB0byBDbG91ZFdhdGNoLiByZXF1ZXN0SWQgKyBsb2dpY2FsUmVzb3VyY2VJZCBhcmVcbiAgLy8gc3VmZmljaWVudCBmb3IgY29ycmVsYXRpb24uIChTdGFja0lkIGlzIHN0aWxsIHJldHVybmVkIGluIHRoZSBDRk4gcmVzcG9uc2VcbiAgLy8gYm9keSBiZWxvdyDigJQgdGhhdCBpcyB0aGUgbWFuZGF0b3J5IENGTiBwcm90b2NvbCBmaWVsZCBhbmQgaXMgbm90IGEgbG9nLilcbiAgbGFtYmRhTG9nLmluZm8oJ1NUQVJUJywgYCR7ZXZlbnQuUmVxdWVzdFR5cGV9IHJlcXVlc3QgcmVjZWl2ZWRgLCB7XG4gICAgbG9naWNhbFJlc291cmNlSWQ6IGV2ZW50LkxvZ2ljYWxSZXNvdXJjZUlkLFxuICAgIHJlcXVlc3RJZDogZXZlbnQuUmVxdWVzdElkLFxuICB9KTtcblxuICBjb25zdCBiYXNlUmVzcG9uc2U6IFBhcnRpYWw8Q2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVJlc3BvbnNlPiA9IHtcbiAgICBTdGFja0lkOiBldmVudC5TdGFja0lkLFxuICAgIFJlcXVlc3RJZDogZXZlbnQuUmVxdWVzdElkLFxuICAgIExvZ2ljYWxSZXNvdXJjZUlkOiBldmVudC5Mb2dpY2FsUmVzb3VyY2VJZCxcbiAgICBQaHlzaWNhbFJlc291cmNlSWQ6IGV2ZW50LkxvZ2ljYWxSZXNvdXJjZUlkLFxuICB9O1xuXG4gIHRyeSB7XG4gICAgLy8gSGFuZGxlIERlbGV0ZSAtIGFsd2F5cyBzdWNjZWVkIChuby1vcClcbiAgICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnKSB7XG4gICAgICBsYW1iZGFMb2cuaW5mbygnREVMRVRFJywgJ05vLW9wIC0gcmV0dXJuaW5nIFNVQ0NFU1MnKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIC4uLmJhc2VSZXNwb25zZSxcbiAgICAgICAgU3RhdHVzOiAnU1VDQ0VTUycsXG4gICAgICAgIFJlYXNvbjogJ0RlbGV0ZSBjb21wbGV0ZWQgKG5vLW9wKScsXG4gICAgICB9IGFzIENsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VSZXNwb25zZTtcbiAgICB9XG5cbiAgICAvLyBFeHRyYWN0IGFuZCB2YWxpZGF0ZSBwcm9wZXJ0aWVzXG4gICAgY29uc3QgcGx1Z2luRmlsdGVyID0gZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzLnBsdWdpbkZpbHRlcjtcbiAgICBjb25zdCBiYXNlVVJMID0gZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzLmJhc2VVUkwgfHwgSEFORExFUl9ERUZBVUxUX0JBU0VfVVJMO1xuXG4gICAgaWYgKCFiYXNlVVJMLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykgJiYgIWJhc2VVUkwuc3RhcnRzV2l0aCgnaHR0cDovLycpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgYmFzZVVSTDogXCIke2Jhc2VVUkx9XCIg4oCUIG11c3Qgc3RhcnQgd2l0aCBodHRwOi8vIG9yIGh0dHBzOi8vYCk7XG4gICAgfVxuXG4gICAgbGFtYmRhTG9nLmluZm8oJ0NPTkZJRycsICdDb25maWd1cmF0aW9uIGxvYWRlZCcsIHsgYmFzZVVSTCwgcGx1Z2luRmlsdGVyIH0pO1xuXG4gICAgdmFsaWRhdGVQbHVnaW5GaWx0ZXIocGx1Z2luRmlsdGVyKTtcblxuICAgIC8vIEdldCB0b2tlbiBmcm9tIFNlY3JldHMgTWFuYWdlciBhbmQgY3JlYXRlIEFQSSBjbGllbnRcbiAgICBjb25zdCB0b2tlbiA9IGF3YWl0IGdldFRva2VuKCk7XG4gICAgY29uc3QgYXBpID0gY3JlYXRlKGJhc2VVUkwsIHRva2VuKTtcblxuICAgIC8vIEZldGNoIHBsdWdpblxuICAgIGxhbWJkYUxvZy5pbmZvKCdGRVRDSCcsICdJbml0aWF0aW5nIHBsdWdpbiBsb29rdXAuLi4nKTtcbiAgICBjb25zdCBwbHVnaW4gPSBhd2FpdCBmZXRjaChhcGksIHBsdWdpbkZpbHRlcik7XG4gICAgbGFtYmRhTG9nLmluZm8oJ0ZFVENIJywgJ1BsdWdpbiByZXRyaWV2ZWQgc3VjY2Vzc2Z1bGx5Jywge1xuICAgICAgbmFtZTogcGx1Z2luLm5hbWUsXG4gICAgICB2ZXJzaW9uOiBwbHVnaW4udmVyc2lvbixcbiAgICAgIGlkOiBwbHVnaW4uaWQsXG4gICAgfSk7XG5cbiAgICAvLyBTdHJpcCBsYXJnZSBmaWVsZHMgdG8gc3RheSB3aXRoaW4gQ2xvdWRGb3JtYXRpb24ncyA0MDk2LWJ5dGUgRGF0YSBsaW1pdC5cbiAgICAvLyBDREsgY29uc3RydWN0cyBvbmx5IG5lZWQgdGhlIGZpZWxkcyB1c2VkIGJ5IGNyZWF0ZUNvZGVCdWlsZFN0ZXAoKS5cbiAgICBjb25zdCBzbGltID0ge1xuICAgICAgaWQ6IHBsdWdpbi5pZCxcbiAgICAgIG5hbWU6IHBsdWdpbi5uYW1lLFxuICAgICAgdmVyc2lvbjogcGx1Z2luLnZlcnNpb24sXG4gICAgICBwbHVnaW5UeXBlOiBwbHVnaW4ucGx1Z2luVHlwZSxcbiAgICAgIGNvbXB1dGVUeXBlOiBwbHVnaW4uY29tcHV0ZVR5cGUsXG4gICAgICBjb21tYW5kczogcGx1Z2luLmNvbW1hbmRzLFxuICAgICAgaW5zdGFsbENvbW1hbmRzOiBwbHVnaW4uaW5zdGFsbENvbW1hbmRzLFxuICAgICAgZW52OiBwbHVnaW4uZW52LFxuICAgICAgbWV0YWRhdGE6IHBsdWdpbi5tZXRhZGF0YSxcbiAgICAgIHByaW1hcnlPdXRwdXREaXJlY3Rvcnk6IHBsdWdpbi5wcmltYXJ5T3V0cHV0RGlyZWN0b3J5LFxuICAgICAgc2VjcmV0czogcGx1Z2luLnNlY3JldHMsXG4gICAgICBmYWlsdXJlQmVoYXZpb3I6IHBsdWdpbi5mYWlsdXJlQmVoYXZpb3IsXG4gICAgICB0aW1lb3V0OiBwbHVnaW4udGltZW91dCxcbiAgICB9O1xuXG4gICAgY29uc3QgZW5jb2RlZCA9IEJ1ZmZlci5mcm9tKEpTT04uc3RyaW5naWZ5KHNsaW0pLCAndXRmLTgnKS50b1N0cmluZygnYmFzZTY0Jyk7XG4gICAgbGFtYmRhTG9nLmRlYnVnKCdFTkNPREUnLCAnRW5jb2RlZCBwbHVnaW4gZGF0YScsIHsgbGVuZ3RoOiBlbmNvZGVkLmxlbmd0aCB9KTtcblxuICAgIHJldHVybiB7XG4gICAgICAuLi5iYXNlUmVzcG9uc2UsXG4gICAgICBTdGF0dXM6ICdTVUNDRVNTJyxcbiAgICAgIFJlYXNvbjogYFBsdWdpbiAnJHtwbHVnaW4ubmFtZX0nICh2JHtwbHVnaW4udmVyc2lvbn0pIHJldHJpZXZlZCBzdWNjZXNzZnVsbHlgLFxuICAgICAgRGF0YToge1xuICAgICAgICBSZXN1bHRWYWx1ZTogZW5jb2RlZCxcbiAgICAgIH0sXG4gICAgfSBhcyBDbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlUmVzcG9uc2U7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc3QgcmVhc29uID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAnVW5leHBlY3RlZCBlcnJvciBvY2N1cnJlZCc7XG4gICAgbGFtYmRhTG9nLmVycm9yKCdFUlJPUicsICdIYW5kbGVyIGZhaWxlZCcsIHtcbiAgICAgIHJlYXNvbixcbiAgICAgIHN0YWNrOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3Iuc3RhY2sgOiB1bmRlZmluZWQsXG4gICAgfSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4uYmFzZVJlc3BvbnNlLFxuICAgICAgU3RhdHVzOiAnRkFJTEVEJyxcbiAgICAgIFJlYXNvbjogcmVhc29uLFxuICAgIH0gYXMgQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVJlc3BvbnNlO1xuICB9IGZpbmFsbHkge1xuICAgIGxhbWJkYUxvZy5pbmZvKCdFTkQnLCAnQ3VzdG9tIHJlc291cmNlIGV4ZWN1dGlvbiBjb21wbGV0ZWQnKTtcbiAgfVxufTtcbiJdfQ==
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @pipeline-builder/pipeline-core
|
|
3
|
+
*
|
|
4
|
+
* Application configuration, pipeline domain types, and the template engine.
|
|
5
|
+
*
|
|
6
|
+
* This entry point is deliberately FREE of `aws-cdk-lib`. The CDK constructs live
|
|
7
|
+
* behind a separate subpath — `@pipeline-builder/pipeline-core/cdk` — because the
|
|
8
|
+
* API services consume this package for config and domain types only, and an
|
|
9
|
+
* `export *` of the constructs from here put the whole of `aws-cdk-lib` on the
|
|
10
|
+
* import graph of every service that read so much as a port number. Anything that
|
|
11
|
+
* imports `aws-cdk-lib`, at type level or value level, belongs in `cdk.ts`.
|
|
12
|
+
*
|
|
13
|
+
* **Config**
|
|
14
|
+
* - Config — application configuration singleton (environment-driven)
|
|
15
|
+
* - ConfigTypes — typed configuration interfaces
|
|
16
|
+
*
|
|
17
|
+
* **Types**
|
|
18
|
+
* - PipelineType, ComputeType, PluginType, Visibility — pipeline domain enums
|
|
19
|
+
* - RoleTypes, SecurityGroupTypes — infrastructure type definitions
|
|
20
|
+
* - PluginSpec — a plugin's declared contract
|
|
21
|
+
* - IdGenerator — deterministic ID generation
|
|
22
|
+
*
|
|
23
|
+
* **Helpers**
|
|
24
|
+
* - replaceNonAlphanumeric, extractMetadataEnv — string and metadata utilities
|
|
25
|
+
*
|
|
26
|
+
* **Re-exports from api-core**
|
|
27
|
+
* - ErrorCode, createLogger
|
|
28
|
+
*
|
|
29
|
+
* The Postgres/Drizzle data layer (db, schema, CrudService, query builders,
|
|
30
|
+
* filter/compliance types, etc.) is NOT re-exported here — import those
|
|
31
|
+
* directly from `@pipeline-builder/pipeline-data`.
|
|
32
|
+
*/
|
|
33
|
+
export * from './config/app-config.js';
|
|
34
|
+
export * from './config/config-types.js';
|
|
35
|
+
export * from './config/entitlements.js';
|
|
36
|
+
export * from './config/service-client.js';
|
|
37
|
+
export { parsePlatformBaseUrl } from './config/infrastructure-config.js';
|
|
38
|
+
export * from './core/pipeline-types.js';
|
|
39
|
+
export * from './core/role-types.js';
|
|
40
|
+
export * from './core/security-group-types.js';
|
|
41
|
+
export * from './core/id-generator.js';
|
|
42
|
+
export { replaceNonAlphanumeric, extractMetadataEnv } from './core/metadata-helpers.js';
|
|
43
|
+
export * from './pipeline/plugin-spec.js';
|
|
44
|
+
export { ErrorCode, createLogger, } from '@pipeline-builder/api-core';
|
|
45
|
+
export * from './template/index.js';
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* @module @pipeline-builder/pipeline-core
|
|
5
|
+
*
|
|
6
|
+
* Application configuration, pipeline domain types, and the template engine.
|
|
7
|
+
*
|
|
8
|
+
* This entry point is deliberately FREE of `aws-cdk-lib`. The CDK constructs live
|
|
9
|
+
* behind a separate subpath — `@pipeline-builder/pipeline-core/cdk` — because the
|
|
10
|
+
* API services consume this package for config and domain types only, and an
|
|
11
|
+
* `export *` of the constructs from here put the whole of `aws-cdk-lib` on the
|
|
12
|
+
* import graph of every service that read so much as a port number. Anything that
|
|
13
|
+
* imports `aws-cdk-lib`, at type level or value level, belongs in `cdk.ts`.
|
|
14
|
+
*
|
|
15
|
+
* **Config**
|
|
16
|
+
* - Config — application configuration singleton (environment-driven)
|
|
17
|
+
* - ConfigTypes — typed configuration interfaces
|
|
18
|
+
*
|
|
19
|
+
* **Types**
|
|
20
|
+
* - PipelineType, ComputeType, PluginType, Visibility — pipeline domain enums
|
|
21
|
+
* - RoleTypes, SecurityGroupTypes — infrastructure type definitions
|
|
22
|
+
* - PluginSpec — a plugin's declared contract
|
|
23
|
+
* - IdGenerator — deterministic ID generation
|
|
24
|
+
*
|
|
25
|
+
* **Helpers**
|
|
26
|
+
* - replaceNonAlphanumeric, extractMetadataEnv — string and metadata utilities
|
|
27
|
+
*
|
|
28
|
+
* **Re-exports from api-core**
|
|
29
|
+
* - ErrorCode, createLogger
|
|
30
|
+
*
|
|
31
|
+
* The Postgres/Drizzle data layer (db, schema, CrudService, query builders,
|
|
32
|
+
* filter/compliance types, etc.) is NOT re-exported here — import those
|
|
33
|
+
* directly from `@pipeline-builder/pipeline-data`.
|
|
34
|
+
*/
|
|
35
|
+
// Configuration
|
|
36
|
+
export * from './config/app-config.js';
|
|
37
|
+
export * from './config/config-types.js';
|
|
38
|
+
export * from './config/entitlements.js';
|
|
39
|
+
export * from './config/service-client.js';
|
|
40
|
+
export { parsePlatformBaseUrl } from './config/infrastructure-config.js';
|
|
41
|
+
// Core types (public surface)
|
|
42
|
+
export * from './core/pipeline-types.js';
|
|
43
|
+
export * from './core/role-types.js';
|
|
44
|
+
export * from './core/security-group-types.js';
|
|
45
|
+
export * from './core/id-generator.js';
|
|
46
|
+
export { replaceNonAlphanumeric, extractMetadataEnv } from './core/metadata-helpers.js';
|
|
47
|
+
// Plugin domain type (the synth-time authoring types live in the `/cdk` entry)
|
|
48
|
+
export * from './pipeline/plugin-spec.js';
|
|
49
|
+
// Re-export from api-core (only items consumed by external packages)
|
|
50
|
+
export { ErrorCode, createLogger, } from '@pipeline-builder/api-core';
|
|
51
|
+
// Template engine — synth-time scripting for pipeline config + plugin specs
|
|
52
|
+
export * from './template/index.js';
|
|
53
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQStCRztBQUVILGdCQUFnQjtBQUNoQixjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMsMEJBQTBCLENBQUM7QUFDekMsY0FBYywwQkFBMEIsQ0FBQztBQUN6QyxjQUFjLDRCQUE0QixDQUFDO0FBQzNDLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBRXpFLDhCQUE4QjtBQUM5QixjQUFjLDBCQUEwQixDQUFDO0FBQ3pDLGNBQWMsc0JBQXNCLENBQUM7QUFDckMsY0FBYyxnQ0FBZ0MsQ0FBQztBQUMvQyxjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRXhGLCtFQUErRTtBQUMvRSxjQUFjLDJCQUEyQixDQUFDO0FBRTFDLHFFQUFxRTtBQUNyRSxPQUFPLEVBQ0wsU0FBUyxFQUNULFlBQVksR0FDYixNQUFNLDRCQUE0QixDQUFDO0FBRXBDLDRFQUE0RTtBQUM1RSxjQUFjLHFCQUFxQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogQG1vZHVsZSBAcGlwZWxpbmUtYnVpbGRlci9waXBlbGluZS1jb3JlXG4gKlxuICogQXBwbGljYXRpb24gY29uZmlndXJhdGlvbiwgcGlwZWxpbmUgZG9tYWluIHR5cGVzLCBhbmQgdGhlIHRlbXBsYXRlIGVuZ2luZS5cbiAqXG4gKiBUaGlzIGVudHJ5IHBvaW50IGlzIGRlbGliZXJhdGVseSBGUkVFIG9mIGBhd3MtY2RrLWxpYmAuIFRoZSBDREsgY29uc3RydWN0cyBsaXZlXG4gKiBiZWhpbmQgYSBzZXBhcmF0ZSBzdWJwYXRoIOKAlCBgQHBpcGVsaW5lLWJ1aWxkZXIvcGlwZWxpbmUtY29yZS9jZGtgIOKAlCBiZWNhdXNlIHRoZVxuICogQVBJIHNlcnZpY2VzIGNvbnN1bWUgdGhpcyBwYWNrYWdlIGZvciBjb25maWcgYW5kIGRvbWFpbiB0eXBlcyBvbmx5LCBhbmQgYW5cbiAqIGBleHBvcnQgKmAgb2YgdGhlIGNvbnN0cnVjdHMgZnJvbSBoZXJlIHB1dCB0aGUgd2hvbGUgb2YgYGF3cy1jZGstbGliYCBvbiB0aGVcbiAqIGltcG9ydCBncmFwaCBvZiBldmVyeSBzZXJ2aWNlIHRoYXQgcmVhZCBzbyBtdWNoIGFzIGEgcG9ydCBudW1iZXIuIEFueXRoaW5nIHRoYXRcbiAqIGltcG9ydHMgYGF3cy1jZGstbGliYCwgYXQgdHlwZSBsZXZlbCBvciB2YWx1ZSBsZXZlbCwgYmVsb25ncyBpbiBgY2RrLnRzYC5cbiAqXG4gKiAqKkNvbmZpZyoqXG4gKiAtIENvbmZpZyDigJQgYXBwbGljYXRpb24gY29uZmlndXJhdGlvbiBzaW5nbGV0b24gKGVudmlyb25tZW50LWRyaXZlbilcbiAqIC0gQ29uZmlnVHlwZXMg4oCUIHR5cGVkIGNvbmZpZ3VyYXRpb24gaW50ZXJmYWNlc1xuICpcbiAqICoqVHlwZXMqKlxuICogLSBQaXBlbGluZVR5cGUsIENvbXB1dGVUeXBlLCBQbHVnaW5UeXBlLCBWaXNpYmlsaXR5IOKAlCBwaXBlbGluZSBkb21haW4gZW51bXNcbiAqIC0gUm9sZVR5cGVzLCBTZWN1cml0eUdyb3VwVHlwZXMg4oCUIGluZnJhc3RydWN0dXJlIHR5cGUgZGVmaW5pdGlvbnNcbiAqIC0gUGx1Z2luU3BlYyDigJQgYSBwbHVnaW4ncyBkZWNsYXJlZCBjb250cmFjdFxuICogLSBJZEdlbmVyYXRvciDigJQgZGV0ZXJtaW5pc3RpYyBJRCBnZW5lcmF0aW9uXG4gKlxuICogKipIZWxwZXJzKipcbiAqIC0gcmVwbGFjZU5vbkFscGhhbnVtZXJpYywgZXh0cmFjdE1ldGFkYXRhRW52IOKAlCBzdHJpbmcgYW5kIG1ldGFkYXRhIHV0aWxpdGllc1xuICpcbiAqICoqUmUtZXhwb3J0cyBmcm9tIGFwaS1jb3JlKipcbiAqIC0gRXJyb3JDb2RlLCBjcmVhdGVMb2dnZXJcbiAqXG4gKiBUaGUgUG9zdGdyZXMvRHJpenpsZSBkYXRhIGxheWVyIChkYiwgc2NoZW1hLCBDcnVkU2VydmljZSwgcXVlcnkgYnVpbGRlcnMsXG4gKiBmaWx0ZXIvY29tcGxpYW5jZSB0eXBlcywgZXRjLikgaXMgTk9UIHJlLWV4cG9ydGVkIGhlcmUg4oCUIGltcG9ydCB0aG9zZVxuICogZGlyZWN0bHkgZnJvbSBgQHBpcGVsaW5lLWJ1aWxkZXIvcGlwZWxpbmUtZGF0YWAuXG4gKi9cblxuLy8gQ29uZmlndXJhdGlvblxuZXhwb3J0ICogZnJvbSAnLi9jb25maWcvYXBwLWNvbmZpZy5qcyc7XG5leHBvcnQgKiBmcm9tICcuL2NvbmZpZy9jb25maWctdHlwZXMuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9jb25maWcvZW50aXRsZW1lbnRzLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vY29uZmlnL3NlcnZpY2UtY2xpZW50LmpzJztcbmV4cG9ydCB7IHBhcnNlUGxhdGZvcm1CYXNlVXJsIH0gZnJvbSAnLi9jb25maWcvaW5mcmFzdHJ1Y3R1cmUtY29uZmlnLmpzJztcblxuLy8gQ29yZSB0eXBlcyAocHVibGljIHN1cmZhY2UpXG5leHBvcnQgKiBmcm9tICcuL2NvcmUvcGlwZWxpbmUtdHlwZXMuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9jb3JlL3JvbGUtdHlwZXMuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9jb3JlL3NlY3VyaXR5LWdyb3VwLXR5cGVzLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vY29yZS9pZC1nZW5lcmF0b3IuanMnO1xuZXhwb3J0IHsgcmVwbGFjZU5vbkFscGhhbnVtZXJpYywgZXh0cmFjdE1ldGFkYXRhRW52IH0gZnJvbSAnLi9jb3JlL21ldGFkYXRhLWhlbHBlcnMuanMnO1xuXG4vLyBQbHVnaW4gZG9tYWluIHR5cGUgKHRoZSBzeW50aC10aW1lIGF1dGhvcmluZyB0eXBlcyBsaXZlIGluIHRoZSBgL2Nka2AgZW50cnkpXG5leHBvcnQgKiBmcm9tICcuL3BpcGVsaW5lL3BsdWdpbi1zcGVjLmpzJztcblxuLy8gUmUtZXhwb3J0IGZyb20gYXBpLWNvcmUgKG9ubHkgaXRlbXMgY29uc3VtZWQgYnkgZXh0ZXJuYWwgcGFja2FnZXMpXG5leHBvcnQge1xuICBFcnJvckNvZGUsXG4gIGNyZWF0ZUxvZ2dlcixcbn0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuXG4vLyBUZW1wbGF0ZSBlbmdpbmUg4oCUIHN5bnRoLXRpbWUgc2NyaXB0aW5nIGZvciBwaXBlbGluZSBjb25maWcgKyBwbHVnaW4gc3BlY3NcbmV4cG9ydCAqIGZyb20gJy4vdGVtcGxhdGUvaW5kZXguanMnO1xuIl19
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { Plugin } from '@pipeline-builder/pipeline-data';
|
|
2
|
+
import { CodePipeline } from 'aws-cdk-lib/pipelines';
|
|
3
|
+
import { Construct } from 'constructs';
|
|
4
|
+
import { PipelineConfiguration } from './pipeline-configuration.js';
|
|
5
|
+
import type { StageOptions, SynthOptions } from './step-types.js';
|
|
6
|
+
import type { RegistryConfig } from '../config/config-types.js';
|
|
7
|
+
import type { CodeBuildDefaults } from '../core/network-types.js';
|
|
8
|
+
import type { MetaDataType } from '../core/pipeline-types.js';
|
|
9
|
+
import type { RoleConfig } from '../core/role-types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Configuration properties for the PipelineBuilder construct
|
|
12
|
+
*/
|
|
13
|
+
export interface BuilderProps {
|
|
14
|
+
/** Project identifier (will be sanitized to lowercase alphanumeric with underscores) */
|
|
15
|
+
readonly project: string;
|
|
16
|
+
/** Organization identifier (will be sanitized to lowercase alphanumeric with underscores) */
|
|
17
|
+
readonly organization: string;
|
|
18
|
+
/**
|
|
19
|
+
* Optional deploy environment (e.g. `production`, `staging`) for the
|
|
20
|
+
* single-environment case. When set (and no stage declares its own
|
|
21
|
+
* `environment`), pipeline-core derives the `pb.deploys` tag from it, marking
|
|
22
|
+
* the sole stage — or the LAST stage of a multi-stage pipeline (with a synth
|
|
23
|
+
* warning), or a literal `Deploy` stage when there are no stages to name — as
|
|
24
|
+
* the deploy for DORA metrics. For multi-environment pipelines, declare
|
|
25
|
+
* `environment` per stage instead (see `StageOptions.environment`).
|
|
26
|
+
*/
|
|
27
|
+
readonly environment?: string;
|
|
28
|
+
/** Tenant identifier for resolving per-org secrets from AWS Secrets Manager */
|
|
29
|
+
readonly orgId?: string;
|
|
30
|
+
/** Pipeline database record ID — injected as PIPELINE_ID env var for autonomous synth */
|
|
31
|
+
readonly pipelineId?: string;
|
|
32
|
+
/** Optional custom pipeline name. Defaults to: {organization}-{project}-pipeline */
|
|
33
|
+
readonly pipelineName?: string;
|
|
34
|
+
/** Global metadata inherited by all pipeline steps */
|
|
35
|
+
readonly global?: MetaDataType;
|
|
36
|
+
/**
|
|
37
|
+
* Pipeline-level template variables, exposed to `{{ pipeline.vars.* }}` in
|
|
38
|
+
* pipeline configs and plugin specs (see `PluginSpec.requiredVars`). Declared
|
|
39
|
+
* here so the `pipeline.vars` template scope is type-checked end-to-end.
|
|
40
|
+
*/
|
|
41
|
+
readonly vars?: Record<string, unknown>;
|
|
42
|
+
/**
|
|
43
|
+
* Pipeline-level CodeBuild defaults applied to all CodeBuild actions
|
|
44
|
+
* (synth, self-mutation, asset publishing) via `codeBuildDefaults`.
|
|
45
|
+
*/
|
|
46
|
+
readonly defaults?: CodeBuildDefaults;
|
|
47
|
+
/**
|
|
48
|
+
* Optional IAM role for the CodePipeline.
|
|
49
|
+
* When provided, resolves to a CDK IRole and is passed to the CodePipeline construct.
|
|
50
|
+
* When omitted, CDK auto-creates a role with the correct codepipeline.amazonaws.com principal.
|
|
51
|
+
*/
|
|
52
|
+
readonly role?: RoleConfig;
|
|
53
|
+
/** Synthesis configuration including source and plugin details */
|
|
54
|
+
readonly synth: SynthOptions;
|
|
55
|
+
/**
|
|
56
|
+
* Optional pipeline stages, each containing one or more CodeBuild steps.
|
|
57
|
+
* Stages are added as waves to the CodePipeline after the synth step.
|
|
58
|
+
*/
|
|
59
|
+
readonly stages?: StageOptions[];
|
|
60
|
+
/** Optional cron/rate expression for scheduled pipeline execution. */
|
|
61
|
+
readonly schedule?: string;
|
|
62
|
+
/** Custom tags applied to all pipeline resources. */
|
|
63
|
+
readonly tags?: Record<string, string>;
|
|
64
|
+
/**
|
|
65
|
+
* Plugins pre-resolved by `pipeline-manager pipeline synth` from the platform API,
|
|
66
|
+
* keyed by `alias || name`. When present, `PluginLookup.plugin()` returns
|
|
67
|
+
* the matching entry directly and skips the custom resource — so the
|
|
68
|
+
* synthesized CFN template ships with the real CodeBuild image baked in.
|
|
69
|
+
* Populated by the CLI before invoking the boilerplate app; CDK consumers
|
|
70
|
+
* who construct PipelineBuilder directly normally leave this unset.
|
|
71
|
+
*/
|
|
72
|
+
readonly resolvedPlugins?: Record<string, Plugin>;
|
|
73
|
+
/**
|
|
74
|
+
* Platform-sourced registry overrides, applied over the env-loaded `registry`
|
|
75
|
+
* config at synth start. pipeline-manager populates this from the platform URL
|
|
76
|
+
* it deploys against so the CodeBuild image URIs use a pull host AWS CodeBuild
|
|
77
|
+
* can resolve (instead of the in-cluster `registry:5000` default). CDK
|
|
78
|
+
* consumers constructing PipelineBuilder directly normally leave this unset.
|
|
79
|
+
*/
|
|
80
|
+
readonly registry?: Partial<RegistryConfig>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* CDK construct that creates and configures a CodePipeline for continuous deployment.
|
|
84
|
+
*
|
|
85
|
+
* Features:
|
|
86
|
+
* - Multi-source support (S3, GitHub, CodeStar)
|
|
87
|
+
* - Plugin-based build steps
|
|
88
|
+
* - Metadata-driven configuration
|
|
89
|
+
* - Automatic tagging
|
|
90
|
+
* - Automatic sanitization of project and organization names
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* new PipelineBuilder(this, 'MyPipeline', {
|
|
95
|
+
* project: 'my-app',
|
|
96
|
+
* organization: 'my-org',
|
|
97
|
+
* synth: {
|
|
98
|
+
* source: {
|
|
99
|
+
* type: 'github',
|
|
100
|
+
* options: { repo: 'owner/repo', branch: 'main' }
|
|
101
|
+
* },
|
|
102
|
+
* plugin: { name: 'synth' }
|
|
103
|
+
* }
|
|
104
|
+
* });
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export declare class PipelineBuilder extends Construct {
|
|
108
|
+
readonly pipeline: CodePipeline;
|
|
109
|
+
readonly config: PipelineConfiguration;
|
|
110
|
+
constructor(scope: Construct, id: string, props: BuilderProps);
|
|
111
|
+
/**
|
|
112
|
+
* Build a custom artifact bucket when `encryption.kmsKeyArn` and/or
|
|
113
|
+
* `operations.artifactRetentionDays` are set. Returns undefined otherwise so
|
|
114
|
+
* CDK auto-creates the default artifact bucket (unchanged behavior).
|
|
115
|
+
*/
|
|
116
|
+
private buildArtifactBucket;
|
|
117
|
+
/**
|
|
118
|
+
* Resolves CodeBuildDefaults into the shape expected by CDK's codeBuildDefaults.
|
|
119
|
+
* Combines network config, security groups, and pipeline-level environment variables
|
|
120
|
+
* (PIPELINE_ID, EXECUTION_ID, PLATFORM_BASE_URL) available to all CodeBuild actions.
|
|
121
|
+
*/
|
|
122
|
+
private resolveDefaults;
|
|
123
|
+
}
|