@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.
Files changed (84) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +69 -0
  3. package/lib/cdk.d.ts +38 -0
  4. package/lib/cdk.js +44 -0
  5. package/lib/config/app-config.d.ts +109 -0
  6. package/lib/config/app-config.js +197 -0
  7. package/lib/config/aws-config-cdk.d.ts +49 -0
  8. package/lib/config/aws-config-cdk.js +65 -0
  9. package/lib/config/billing-config.d.ts +24 -0
  10. package/lib/config/billing-config.js +497 -0
  11. package/lib/config/config-types.d.ts +346 -0
  12. package/lib/config/config-types.js +4 -0
  13. package/lib/config/entitlements.d.ts +23 -0
  14. package/lib/config/entitlements.js +46 -0
  15. package/lib/config/handler-constants.d.ts +10 -0
  16. package/lib/config/handler-constants.js +39 -0
  17. package/lib/config/infrastructure-config.d.ts +66 -0
  18. package/lib/config/infrastructure-config.js +197 -0
  19. package/lib/config/server-config.d.ts +53 -0
  20. package/lib/config/server-config.js +175 -0
  21. package/lib/config/service-client.d.ts +13 -0
  22. package/lib/config/service-client.js +20 -0
  23. package/lib/core/artifact-manager.d.ts +62 -0
  24. package/lib/core/artifact-manager.js +83 -0
  25. package/lib/core/id-generator.d.ts +50 -0
  26. package/lib/core/id-generator.js +50 -0
  27. package/lib/core/metadata-builder.d.ts +48 -0
  28. package/lib/core/metadata-builder.js +278 -0
  29. package/lib/core/metadata-helpers.d.ts +31 -0
  30. package/lib/core/metadata-helpers.js +55 -0
  31. package/lib/core/network-types.d.ts +200 -0
  32. package/lib/core/network-types.js +4 -0
  33. package/lib/core/network.d.ts +33 -0
  34. package/lib/core/network.js +112 -0
  35. package/lib/core/pipeline-helpers.d.ts +61 -0
  36. package/lib/core/pipeline-helpers.js +563 -0
  37. package/lib/core/pipeline-types.d.ts +118 -0
  38. package/lib/core/pipeline-types.js +131 -0
  39. package/lib/core/role-types.d.ts +254 -0
  40. package/lib/core/role-types.js +4 -0
  41. package/lib/core/role.d.ts +14 -0
  42. package/lib/core/role.js +117 -0
  43. package/lib/core/security-group-types.d.ts +84 -0
  44. package/lib/core/security-group-types.js +4 -0
  45. package/lib/core/security-group.d.ts +14 -0
  46. package/lib/core/security-group.js +33 -0
  47. package/lib/handlers/plugin-lookup-handler.d.ts +32 -0
  48. package/lib/handlers/plugin-lookup-handler.js +292 -0
  49. package/lib/handlers/pnpm-lock.yaml +12 -0
  50. package/lib/index.d.ts +45 -0
  51. package/lib/index.js +53 -0
  52. package/lib/pipeline/pipeline-builder.d.ts +123 -0
  53. package/lib/pipeline/pipeline-builder.js +476 -0
  54. package/lib/pipeline/pipeline-configuration.d.ts +81 -0
  55. package/lib/pipeline/pipeline-configuration.js +214 -0
  56. package/lib/pipeline/plugin-lookup.d.ts +131 -0
  57. package/lib/pipeline/plugin-lookup.js +316 -0
  58. package/lib/pipeline/plugin-spec.d.ts +138 -0
  59. package/lib/pipeline/plugin-spec.js +4 -0
  60. package/lib/pipeline/source-builder.d.ts +62 -0
  61. package/lib/pipeline/source-builder.js +164 -0
  62. package/lib/pipeline/source-types.d.ts +221 -0
  63. package/lib/pipeline/source-types.js +4 -0
  64. package/lib/pipeline/stage-builder.d.ts +78 -0
  65. package/lib/pipeline/stage-builder.js +129 -0
  66. package/lib/pipeline/step-types.d.ts +222 -0
  67. package/lib/pipeline/step-types.js +4 -0
  68. package/lib/template/evaluator.d.ts +42 -0
  69. package/lib/template/evaluator.js +164 -0
  70. package/lib/template/index.d.ts +34 -0
  71. package/lib/template/index.js +118 -0
  72. package/lib/template/metrics.d.ts +10 -0
  73. package/lib/template/metrics.js +43 -0
  74. package/lib/template/plugin-resolver.d.ts +8 -0
  75. package/lib/template/plugin-resolver.js +48 -0
  76. package/lib/template/tokenizer.d.ts +49 -0
  77. package/lib/template/tokenizer.js +233 -0
  78. package/lib/template/topo-sort.d.ts +17 -0
  79. package/lib/template/topo-sort.js +88 -0
  80. package/lib/template/validate.d.ts +45 -0
  81. package/lib/template/validate.js +96 -0
  82. package/lib/template/walker.d.ts +34 -0
  83. package/lib/template/walker.js +83 -0
  84. 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLWxvb2t1cC1oYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2hhbmRsZXJzL3BsdWdpbi1sb29rdXAtaGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRzlGLE9BQU8sS0FBSyxFQUFFLEVBQXNCLFVBQVUsRUFBRSxNQUFNLE9BQU8sQ0FBQztBQUM5RCxtRkFBbUY7QUFDbkYsbUZBQW1GO0FBQ25GLHFGQUFxRjtBQUNyRixPQUFPLEVBQ0wsa0JBQWtCLEVBQ2xCLG1CQUFtQixFQUNuQixzQkFBc0IsRUFDdEIsd0JBQXdCLEdBQ3pCLE1BQU0sZ0NBQWdDLENBQUM7QUFFeEM7OztHQUdHO0FBQ0gsU0FBUyxRQUFRLENBQUMsS0FBYSxFQUFFLEdBQVcsRUFBRSxPQUFlLEVBQUUsSUFBYztJQUMzRSxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUN6RixRQUFRLEtBQUssRUFBRSxDQUFDO1FBQ2QsS0FBSyxPQUFPO1lBQUUsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUFDLE1BQU07UUFDekMsS0FBSyxPQUFPO1lBQUUsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsS0FBSyxPQUFPO2dCQUFFLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7WUFBQyxNQUFNO1FBQ2hGLFNBQVMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUM3QixDQUFDO0FBQ0gsQ0FBQztBQUVELE1BQU0sU0FBUyxHQUFH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LENBQUMsQ0FBQyxDQUFDLFNBQVM7U0FDeEQsQ0FBQyxDQUFDO1FBRUgsT0FBTztZQUNMLEdBQUcsWUFBWTtZQUNmLE1BQU0sRUFBRSxRQUFRO1lBQ2hCLE1BQU0sRUFBRSxNQUFNO1NBQ3lCLENBQUM7SUFDNUMsQ0FBQztZQUFTLENBQUM7UUFDVCxTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxxQ0FBcUMsQ0FBQyxDQUFDO0lBQy9ELENBQUM7QUFDSCxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgR2V0U2VjcmV0VmFsdWVDb21tYW5kLCBTZWNyZXRzTWFuYWdlckNsaWVudCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1zZWNyZXRzLW1hbmFnZXInO1xuaW1wb3J0IHR5cGUgeyBQbHVnaW5GaWx0ZXIsIFBsdWdpbiB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL3BpcGVsaW5lLWRhdGEnO1xuaW1wb3J0IHR5cGUgeyBDbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQsIENsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VSZXNwb25zZSB9IGZyb20gJ2F3cy1sYW1iZGEnO1xuaW1wb3J0IGF4aW9zLCB7IHR5cGUgQXhpb3NJbnN0YW5jZSwgQXhpb3NFcnJvciB9IGZyb20gJ2F4aW9zJztcbi8vIEltcG9ydCB0aGUgZGVwZW5kZW5jeS1mcmVlIGxlYWYsIE5PVCBgYXBwLWNvbmZpZy5qc2AvYENvcmVDb25zdGFudHNgOiB0aGUgbGF0dGVyXG4vLyB0cmFuc2l0aXZlbHkgcHVsbHMgaW5mcmFzdHJ1Y3R1cmUtY29uZmlnIOKGkiBhd3MtY2RrLWxpYiwgd2hpY2ggZXNidWlsZCB0aGVuIHRyaWVzXG4vLyB0byBidW5kbGUgaW50byB0aGlzIExhbWJkYSAoaHVuZHJlZHMgb2YgTUIg4oaSIE9PTS9TSUdLSUxMIGR1cmluZyBjb2xkLXN0YXJ0IHN5bnRoKS5cbmltcG9ydCB7XG4gIEhBTkRMRVJfVElNRU9VVF9NUyxcbiAgSEFORExFUl9NQVhfUkVUUklFUyxcbiAgSEFORExFUl9SRVRSWV9ERUxBWV9NUyxcbiAgSEFORExFUl9ERUZBVUxUX0JBU0VfVVJMLFxufSBmcm9tICcuLi9jb25maWcvaGFuZGxlci1jb25zdGFudHMuanMnO1xuXG4vKipcbiAqIFN0cnVjdHVyZWQgbG9nZ2VyIGZvciBMYW1iZGEgKG91dHB1dHMgSlNPTiB0byBDbG91ZFdhdGNoKS5cbiAqIERlYnVnIG1lc3NhZ2VzIG9ubHkgZW1pdHRlZCB3aGVuIExPR19MRVZFTD1kZWJ1Zy5cbiAqL1xuZnVuY3Rpb24gbG9nRW50cnkobGV2ZWw6IHN0cmluZywgdGFnOiBzdHJpbmcsIG1lc3NhZ2U6IHN0cmluZywgZGF0YT86IHVua25vd24pIHtcbiAgY29uc3QgbGluZSA9IEpTT04uc3RyaW5naWZ5KHsgbGV2ZWwsIHRhZywgbWVzc2FnZSwgZGF0YSwgdHM6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSB9KTtcbiAgc3dpdGNoIChsZXZlbCkge1xuICAgIGNhc2UgJ0VSUk9SJzogY29uc29sZS5lcnJvcihsaW5lKTsgYnJlYWs7XG4gICAgY2FzZSAnREVCVUcnOiBpZiAocHJvY2Vzcy5lbnYuTE9HX0xFVkVMID09PSAnZGVidWcnKSBjb25zb2xlLmRlYnVnKGxpbmUpOyBicmVhaztcbiAgICBkZWZhdWx0OiBjb25zb2xlLmxvZyhsaW5lKTtcbiAgfVxufVxuXG5jb25zdCBsYW1iZGFMb2cgPSB7XG4gIGluZm86ICh0YWc6IHN0cmluZywgbWVzc2FnZTogc3RyaW5nLCBkYXRhPzogdW5rbm93bikgPT4gbG9nRW50cnkoJ0lORk8nLCB0YWcsIG1lc3NhZ2UsIGRhdGEpLFxuICBlcnJvcjogKHRhZzogc3RyaW5nLCBtZXNzYWdlOiBzdHJpbmcsIGRhdGE/OiB1bmtub3duKSA9PiBsb2dFbnRyeSgnRVJST1InLCB0YWcsIG1lc3NhZ2UsIGRhdGEpLFxuICBkZWJ1ZzogKHRhZzogc3RyaW5nLCBtZXNzYWdlOiBzdHJpbmcsIGRhdGE/OiB1bmtub3duKSA9PiBsb2dFbnRyeSgnREVCVUcnLCB0YWcsIG1lc3NhZ2UsIGRhdGEpLFxufTtcblxuY29uc3QgUkVUUllBQkxFX1NUQVRVU0VTID0gbmV3IFNldChbNDI5LCA1MDIsIDUwMywgNTA0XSk7XG5jb25zdCBSRVRSWUFCTEVfQ09ERVMgPSBuZXcgU2V0KFsnRUNPTk5SRVNFVCcsICdFQ09OTlJFRlVTRUQnLCAnRVRJTUVET1VUJ10pO1xuXG5mdW5jdGlvbiBzbGVlcChtczogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpKTtcbn1cblxuLyoqIFBsYXRmb3JtIHNlY3JldCBuYW1lIOKAlCBpbmplY3RlZCBhcyBQTEFURk9STV9TRUNSRVRfTkFNRSBlbnYgdmFyIGJ5IFBsdWdpbkxvb2t1cCBjb25zdHJ1Y3QuICovXG5jb25zdCBQTEFURk9STV9TRUNSRVRfTkFNRSA9IHByb2Nlc3MuZW52LlBMQVRGT1JNX1NFQ1JFVF9OQU1FO1xuaWYgKCFQTEFURk9STV9TRUNSRVRfTkFNRSkge1xuICB0aHJvdyBuZXcgRXJyb3IoJ1BMQVRGT1JNX1NFQ1JFVF9OQU1FIGVudmlyb25tZW50IHZhcmlhYmxlIGlzIHJlcXVpcmVkJyk7XG59XG5cbi8qKiBDYWNoZWQgdG9rZW4gdG8gYXZvaWQgcmVwZWF0ZWQgU2VjcmV0cyBNYW5hZ2VyIGNhbGxzIHdpdGhpbiBhIHNpbmdsZSBpbnZvY2F0aW9uLiAqL1xubGV0IGNhY2hlZFRva2VuOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcblxuLyoqIEBpbnRlcm5hbCBSZXNldCBjYWNoZWQgdG9rZW4gKGZvciB0ZXN0aW5nIG9ubHkpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIF9yZXNldENyZWRlbnRpYWxzQ2FjaGUoKTogdm9pZCB7IGNhY2hlZFRva2VuID0gbnVsbDsgfVxuXG4vKipcbiAqIEZldGNoIEpXVCB0b2tlbiBmcm9tIEFXUyBTZWNyZXRzIE1hbmFnZXIuXG4gKiBDYWNoZXMgdGhlIHJlc3VsdCBmb3IgdGhlIGxpZmV0aW1lIG9mIHRoZSBMYW1iZGEgZXhlY3V0aW9uIGNvbnRleHQuXG4gKlxuICogVGhlIHNlY3JldCBuYW1lIGlzIHNldCB2aWEgUExBVEZPUk1fU0VDUkVUX05BTUUgZW52IHZhciAoZS5nLiBge3ByZWZpeH0ve29yZ0lkfS9wbGF0Zm9ybWApXG4gKiBDcmVhdGUgaXQgd2l0aDogYHBpcGVsaW5lLW1hbmFnZXIgaW5mcmEgc3RvcmUtdG9rZW5gXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGdldFRva2VuKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGlmIChjYWNoZWRUb2tlbikgcmV0dXJuIGNhY2hlZFRva2VuO1xuXG4gIGxhbWJkYUxvZy5pbmZvKCdBVVRIJywgYEZldGNoaW5nIHRva2VuIGZyb20gU2VjcmV0cyBNYW5hZ2VyOiAke1BMQVRGT1JNX1NFQ1JFVF9OQU1FfWApO1xuXG4gIGNvbnN0IGNsaWVudCA9IG5ldyBTZWNyZXRzTWFuYWdlckNsaWVudCh7fSk7XG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LnNlbmQobmV3IEdldFNlY3JldFZhbHVlQ29tbWFuZCh7IFNlY3JldElkOiBQTEFURk9STV9TRUNSRVRfTkFNRSB9KSk7XG5cbiAgaWYgKCFyZXNwb25zZS5TZWNyZXRTdHJpbmcpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFNlY3JldCBcIiR7UExBVEZPUk1fU0VDUkVUX05BTUV9XCIgaXMgZW1wdHlgKTtcbiAgfVxuXG4gIGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2UocmVzcG9uc2UuU2VjcmV0U3RyaW5nKSBhcyBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICAvLyBTY2hlbWEgaXMgYHsgdXNlcm5hbWUsIHBhc3N3b3JkLCAuLi4gfWAg4oCUIHRoZSBgcGFzc3dvcmRgIGZpZWxkIGlzIHRoZVxuICAvLyBwbGF0Zm9ybSBKV1QuIFNhbWUgc2VjcmV0IGlzIHJlYWQgYnkgQ29kZUJ1aWxkJ3MgYHNlY3JldHNNYW5hZ2VyQ3JlZGVudGlhbHNgXG4gIC8vIGZvciByZWdpc3RyeSBwdWxscyAoQmFzaWMgYXV0aDogdXNlcm5hbWU6cGFzc3dvcmQgPSBvcmdJZDpKV1QpLiBUaGVcbiAgLy8gcGlwZWxpbmUtaW1hZ2UtcmVnaXN0cnkgdG9rZW4gZW5kcG9pbnQgdmFsaWRhdGVzIHRoZSBwYXNzd29yZCBhcyBhIEpXVFxuICAvLyBhbmQgaXNzdWVzIGEgcmVnaXN0cnkgdG9rZW4gc2NvcGVkIHRvIHRoZSBKV1QncyBvcmcuXG4gIGlmICghcGFyc2VkLnBhc3N3b3JkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBTZWNyZXQgXCIke1BMQVRGT1JNX1NFQ1JFVF9OQU1FfVwiIG1pc3NpbmcgcGFzc3dvcmQg4oCUIHJ1biBcInBpcGVsaW5lLW1hbmFnZXIgaW5mcmEgc3RvcmUtdG9rZW5cIiB0byBnZW5lcmF0ZWApO1xuICB9XG5cbiAgY2FjaGVkVG9rZW4gPSBwYXJzZWQucGFzc3dvcmQ7XG4gIGxhbWJkYUxvZy5pbmZvKCdBVVRIJywgJ1Rva2VuIHJldHJpZXZlZCBmcm9tIFNlY3JldHMgTWFuYWdlcicpO1xuICByZXR1cm4gY2FjaGVkVG9rZW47XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIHByZS1jb25maWd1cmVkIEF4aW9zIGluc3RhbmNlIGZvciBBUEkgcmVxdWVzdHMuXG4gKlxuICogQHBhcmFtIGJhc2VVUkwgLSBCYXNlIFVSTCBvZiB0aGUgdGFyZ2V0IEFQSVxuICogQHBhcmFtIHRva2VuIC0gSldUIHRva2VuIGZvciBhdXRob3JpemF0aW9uXG4gKiBAcmV0dXJucyBDb25maWd1cmVkIEF4aW9zIGluc3RhbmNlXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZShiYXNlVVJMOiBzdHJpbmcsIHRva2VuOiBzdHJpbmcpOiBBeGlvc0luc3RhbmNlIHtcbiAgcmV0dXJuIGF4aW9zLmNyZWF0ZSh7XG4gICAgYmFzZVVSTCxcbiAgICB0aW1lb3V0OiBIQU5ETEVSX1RJTUVPVVRfTVMsXG4gICAgaGVhZGVyczoge1xuICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3Rva2VufWAsXG4gICAgfSxcbiAgfSk7XG59XG5cbi8qKlxuICogRmV0Y2hlcyBwbHVnaW4gY29uZmlndXJhdGlvbiBmcm9tIHRoZSBleHRlcm5hbCBBUEkgd2l0aCByZXRyeSBsb2dpYy5cbiAqIFJldHJpZXMgb24gdHJhbnNpZW50IGZhaWx1cmVzICg0MjksIDUwMiwgNTAzLCA1MDQsIG5ldHdvcmsgZXJyb3JzKVxuICogd2l0aCBleHBvbmVudGlhbCBiYWNrb2ZmLlxuICpcbiAqIEBwYXJhbSBhcGkgLSBDb25maWd1cmVkIEF4aW9zIGluc3RhbmNlXG4gKiBAcGFyYW0gcGx1Z2luRmlsdGVyIC0gRmlsdGVyIGNyaXRlcmlhIGZvciB0aGUgcGx1Z2luIGxvb2t1cFxuICogQHJldHVybnMgVGhlIHBsdWdpbiBkYXRhIHJldHVybmVkIGJ5IHRoZSBBUElcbiAqIEB0aHJvd3MgRXJyb3Igb24gcGVyc2lzdGVudCBmYWlsdXJlLCB0aW1lb3V0IG9yIGludmFsaWQgcmVzcG9uc2VcbiAqL1xuYXN5bmMgZnVuY3Rpb24gZmV0Y2goYXBpOiBBeGlvc0luc3RhbmNlLCBwbHVnaW5GaWx0ZXI6IFBsdWdpbkZpbHRlcik6IFByb21pc2U8UGx1Z2luPiB7XG4gIGxhbWJkYUxvZy5kZWJ1ZygnRkVUQ0gnLCAnU3RhcnRpbmcgcGx1Z2luIGZldGNoJywgeyBmaWx0ZXI6IHBsdWdpbkZpbHRlciB9KTtcblxuICBsZXQgbGFzdEVycm9yOiBFcnJvciB8IHVuZGVmaW5lZDtcblxuICBmb3IgKGxldCBhdHRlbXB0ID0gMDsgYXR0ZW1wdCA8PSBIQU5ETEVSX01BWF9SRVRSSUVTOyBhdHRlbXB0KyspIHtcbiAgICBpZiAoYXR0ZW1wdCA+IDApIHtcbiAgICAgIGNvbnN0IGRlbGF5ID0gSEFORExFUl9SRVRSWV9ERUxBWV9NUyAqIE1hdGgucG93KDIsIGF0dGVtcHQgLSAxKTtcbiAgICAgIGxhbWJkYUxvZy5pbmZvKCdSRVRSWScsIGBBdHRlbXB0ICR7YXR0ZW1wdCArIDF9LyR7SEFORExFUl9NQVhfUkVUUklFUyArIDF9IGFmdGVyICR7ZGVsYXl9bXNgKTtcbiAgICAgIGF3YWl0IHNsZWVwKGRlbGF5KTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgeyBkYXRhLCBzdGF0dXMgfSA9IGF3YWl0IGFwaS5wb3N0PFBsdWdpbj4oJy9hcGkvcGx1Z2lucy9sb29rdXAnLCB7XG4gICAgICAgIGZpbHRlcjogcGx1Z2luRmlsdGVyLFxuICAgICAgfSk7XG5cbiAgICAgIGlmICghZGF0YSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0VtcHR5IHJlc3BvbnNlIGRhdGEgZnJvbSBBUEknKTtcbiAgICAgIH1cblxuICAgICAgbGFtYmRhTG9nLmluZm8oJ0ZFVENIJywgJ1BsdWdpbiBmZXRjaGVkIHN1Y2Nlc3NmdWxseScsIHtcbiAgICAgICAgc3RhdHVzLFxuICAgICAgICBwbHVnaW46IGRhdGEubmFtZSxcbiAgICAgICAgdmVyc2lvbjogZGF0YS52ZXJzaW9uLFxuICAgICAgICBpZDogZGF0YS5pZCxcbiAgICAgIH0pO1xuXG4gICAgICByZXR1cm4gZGF0YTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgQXhpb3NFcnJvcikge1xuICAgICAgICBpZiAoZXJyb3IuY29kZSA9PT0gJ0VDT05OQUJPUlRFRCcpIHtcbiAgICAgICAgICBsYW1iZGFMb2cuZXJyb3IoJ0ZFVENIJywgYFBsdWdpbiBsb29rdXAgdGltZWQgb3V0IGFmdGVyICR7SEFORExFUl9USU1FT1VUX01TfW1zYCk7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBQbHVnaW4gbG9va3VwIHRpbWVkIG91dCBhZnRlciAke0hBTkRMRVJfVElNRU9VVF9NU31tc2ApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmV0cnlhYmxlID0gZXJyb3IucmVzcG9uc2VcbiAgICAgICAgICA/IFJFVFJZQUJMRV9TVEFUVVNFUy5oYXMoZXJyb3IucmVzcG9uc2Uuc3RhdHVzKVxuICAgICAgICAgIDogUkVUUllBQkxFX0NPREVTLmhhcyhlcnJvci5jb2RlID8/ICcnKTtcblxuICAgICAgICBjb25zdCBtc2cgPSBlcnJvci5yZXNwb25zZVxuICAgICAgICAgID8gYEFQSSBlcnJvciAke2Vycm9yLnJlc3BvbnNlLnN0YXR1c306ICR7ZXJyb3IucmVzcG9uc2Uuc3RhdHVzVGV4dH1gXG4gICAgICAgICAgOiBlcnJvci5jb2RlIHx8IGVycm9yLm1lc3NhZ2U7XG5cbiAgICAgICAgaWYgKHJldHJ5YWJsZSAmJiBhdHRlbXB0IDwgSEFORExFUl9NQVhfUkVUUklFUykge1xuICAgICAgICAgIGxhbWJkYUxvZy5pbmZvKCdSRVRSWScsIGBSZXRyeWFibGUgZXJyb3I6ICR7bXNnfWAsIHsgYXR0ZW1wdDogYXR0ZW1wdCArIDEgfSk7XG4gICAgICAgICAgbGFzdEVycm9yID0gbmV3IEVycm9yKGBGYWlsZWQgdG8gZmV0Y2ggcGx1Z2luOiAke21zZ31gKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIERvbid0IGxvZyB0aGUgdXBzdHJlYW0gYm9keSB2ZXJiYXRpbSDigJQgaXQgbWF5IGNhcnJ5IGEgc3RhY2sgdHJhY2UsXG4gICAgICAgIC8vIGEgcmVxdWVzdCBwYXlsb2FkIGVjaG8sIG9yIG90aGVyIHNlbnNpdGl2ZSBkYXRhIHdlIHNob3VsZG4ndCBlY2hvXG4gICAgICAgIC8vIGludG8gTGFtYmRhIENsb3VkV2F0Y2ggbG9ncy4gS2VlcCBqdXN0IHRoZSBoaWdoLWxldmVsIHNoYXBlLlxuICAgICAgICBjb25zdCBzYWZlQm9keSA9IGVycm9yLnJlc3BvbnNlPy5kYXRhICYmIHR5cGVvZiBlcnJvci5yZXNwb25zZS5kYXRhID09PSAnb2JqZWN0J1xuICAgICAgICAgID8geyBjb2RlOiAoZXJyb3IucmVzcG9uc2UuZGF0YSBhcyB7IGNvZGU/OiBzdHJpbmcgfSkuY29kZSwgbWVzc2FnZTogKGVycm9yLnJlc3BvbnNlLmRhdGEgYXMgeyBtZXNzYWdlPzogc3RyaW5nIH0pLm1lc3NhZ2UgfVxuICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgICAgICBsYW1iZGFMb2cuZXJyb3IoJ0ZFVENIJywgbXNnLCB7IHJlc3BvbnNlQm9keTogc2FmZUJvZHkgfSk7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIGZldGNoIHBsdWdpbjogJHttc2d9YCk7XG4gICAgICB9XG5cbiAgICAgIHRocm93IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcignVW5rbm93biBlcnJvciBkdXJpbmcgcGx1Z2luIGZldGNoJyk7XG4gICAgfVxuICB9XG5cbiAgdGhyb3cgbGFzdEVycm9yID8/IG5ldyBFcnJvcignRmFpbGVkIHRvIGZldGNoIHBsdWdpbiBhZnRlciByZXRyaWVzJyk7XG59XG5cbi8qKlxuICogVmFsaWRhdGVzIHRoZSBwbHVnaW4gZmlsdGVyIG9iamVjdFxuICpcbiAqIEBwYXJhbSBwbHVnaW5GaWx0ZXIgLSBGaWx0ZXIgdG8gdmFsaWRhdGVcbiAqIEByZXR1cm5zIHRydWUgaWYgdmFsaWRcbiAqIEB0aHJvd3MgRXJyb3IgaWYgaW52YWxpZFxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZVBsdWdpbkZpbHRlcihwbHVnaW5GaWx0ZXI6IHVua25vd24pOiBwbHVnaW5GaWx0ZXIgaXMgUGx1Z2luRmlsdGVyIHtcbiAgaWYgKCFwbHVnaW5GaWx0ZXIgfHwgdHlwZW9mIHBsdWdpbkZpbHRlciAhPT0gJ29iamVjdCcpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ01pc3Npbmcgb3IgaW52YWxpZCBwbHVnaW5GaWx0ZXInKTtcbiAgfVxuXG4gIGNvbnN0IGZpbHRlciA9IHBsdWdpbkZpbHRlciBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgaWYgKCFmaWx0ZXIubmFtZSAmJiAhZmlsdGVyLmlkICYmICFmaWx0ZXIudmVyc2lvbiAmJiAhZmlsdGVyLm9yZ0lkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdQbHVnaW5GaWx0ZXIgbXVzdCBoYXZlIGF0IGxlYXN0IG9uZSBjcml0ZXJpb24gKG5hbWUsIGlkLCB2ZXJzaW9uLCBvciBvcmdJZCknKTtcbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufVxuXG4vKipcbiAqIExhbWJkYSBoYW5kbGVyIGZvciBDbG91ZEZvcm1hdGlvbiBDdXN0b20gUmVzb3VyY2UgdGhhdCBwZXJmb3JtcyBwbHVnaW4gbG9va3VwLlxuICpcbiAqIEF1dGhlbnRpY2F0ZXMgdXNpbmcgSldUIHRva2VuIGZyb20gQVdTIFNlY3JldHMgTWFuYWdlciAoUExBVEZPUk1fU0VDUkVUX05BTUUgZW52IHZhcikuXG4gKiBDcmVhdGUgdGhlIHNlY3JldCB3aXRoOiBgcGlwZWxpbmUtbWFuYWdlciBpbmZyYSBzdG9yZS10b2tlbmBcbiAqXG4gKiBSZXF1ZXN0IFR5cGVzOlxuICogLSBDcmVhdGUvVXBkYXRlOiBmZXRjaGVzIGFuZCByZXR1cm5zIHBsdWdpbiBjb25maWd1cmF0aW9uIGZyb20gQVBJXG4gKiAtIERlbGV0ZTogbm8tb3AgKGFsd2F5cyBzdWNjZWVkcylcbiAqXG4gKiBSZXNwb25zZTpcbiAqIC0gU3VjY2VzczogUmV0dXJucyBiYXNlNjQtZW5jb2RlZCBwbHVnaW4gSlNPTiBpbiBEYXRhLlJlc3VsdFZhbHVlXG4gKiAtIEZhaWx1cmU6IFJldHVybnMgZXJyb3IgbWVzc2FnZSBpbiBSZWFzb25cbiAqXG4gKiBAcGFyYW0gZXZlbnQgLSBDbG91ZEZvcm1hdGlvbiBjdXN0b20gcmVzb3VyY2UgZXZlbnRcbiAqIEByZXR1cm5zIENsb3VkRm9ybWF0aW9uIHJlc3BvbnNlXG4gKlxuICogQGV4YW1wbGVcbiAqIEN1c3RvbSBSZXNvdXJjZSBQcm9wZXJ0aWVzOlxuICogYGBganNvblxuICoge1xuICogICBcImJhc2VVUkxcIjogXCJodHRwczovL2FwaS5leGFtcGxlLmNvbVwiLFxuICogICBcInBsdWdpbkZpbHRlclwiOiB7XG4gKiAgICAgXCJuYW1lXCI6IFwibm9kZWpzLWJ1aWxkXCIsXG4gKiAgICAgXCJ2ZXJzaW9uXCI6IFwiMS4wLjBcIixcbiAqICAgICBcImlzQWN0aXZlXCI6IHRydWVcbiAqICAgfVxuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBjb25zdCBoYW5kbGVyID0gYXN5bmMgKFxuICBldmVudDogQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50LFxuKTogUHJvbWlzZTxDbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlUmVzcG9uc2U+ID0+IHtcbiAgLy8gTk9URTogbmV2ZXIgbG9nIGV2ZW50LlN0YWNrSWQgaGVyZSDigJQgdGhlIENsb3VkRm9ybWF0aW9uIFN0YWNrIEFSTiBlbWJlZHMgdGhlXG4gIC8vIEFXUyBhY2NvdW50IGlkIChhcm46YXdzOmNsb3VkZm9ybWF0aW9uOjxyZWdpb24+OjxBQ0NPVU5UX0lEPjpzdGFjay/igKYpLCB3aGljaFxuICAvLyBtdXN0IG5ldmVyIGJlIHBlcnNpc3RlZCB0byBDbG91ZFdhdGNoLiByZXF1ZXN0SWQgKyBsb2dpY2FsUmVzb3VyY2VJZCBhcmVcbiAgLy8gc3VmZmljaWVudCBmb3IgY29ycmVsYXRpb24uIChTdGFja0lkIGlzIHN0aWxsIHJldHVybmVkIGluIHRoZSBDRk4gcmVzcG9uc2VcbiAgLy8gYm9keSBiZWxvdyDigJQgdGhhdCBpcyB0aGUgbWFuZGF0b3J5IENGTiBwcm90b2NvbCBmaWVsZCBhbmQgaXMgbm90IGEgbG9nLilcbiAgbGFtYmRhTG9nLmluZm8oJ1NUQVJUJywgYCR7ZXZlbnQuUmVxdWVzdFR5cGV9IHJlcXVlc3QgcmVjZWl2ZWRgLCB7XG4gICAgbG9naWNhbFJlc291cmNlSWQ6IGV2ZW50LkxvZ2ljYWxSZXNvdXJjZUlkLFxuICAgIHJlcXVlc3RJZDogZXZlbnQuUmVxdWVzdElkLFxuICB9KTtcblxuICBjb25zdCBiYXNlUmVzcG9uc2U6IFBhcnRpYWw8Q2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVJlc3BvbnNlPiA9IHtcbiAgICBTdGFja0lkOiBldmVudC5TdGFja0lkLFxuICAgIFJlcXVlc3RJZDogZXZlbnQuUmVxdWVzdElkLFxuICAgIExvZ2ljYWxSZXNvdXJjZUlkOiBldmVudC5Mb2dpY2FsUmVzb3VyY2VJZCxcbiAgICBQaHlzaWNhbFJlc291cmNlSWQ6IGV2ZW50LkxvZ2ljYWxSZXNvdXJjZUlkLFxuICB9O1xuXG4gIHRyeSB7XG4gICAgLy8gSGFuZGxlIERlbGV0ZSAtIGFsd2F5cyBzdWNjZWVkIChuby1vcClcbiAgICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnKSB7XG4gICAgICBsYW1iZGFMb2cuaW5mbygnREVMRVRFJywgJ05vLW9wIC0gcmV0dXJuaW5nIFNVQ0NFU1MnKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIC4uLmJhc2VSZXNwb25zZSxcbiAgICAgICAgU3RhdHVzOiAnU1VDQ0VTUycsXG4gICAgICAgIFJlYXNvbjogJ0RlbGV0ZSBjb21wbGV0ZWQgKG5vLW9wKScsXG4gICAgICB9IGFzIENsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VSZXNwb25zZTtcbiAgICB9XG5cbiAgICAvLyBFeHRyYWN0IGFuZCB2YWxpZGF0ZSBwcm9wZXJ0aWVzXG4gICAgY29uc3QgcGx1Z2luRmlsdGVyID0gZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzLnBsdWdpbkZpbHRlcjtcbiAgICBjb25zdCBiYXNlVVJMID0gZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzLmJhc2VVUkwgfHwgSEFORExFUl9ERUZBVUxUX0JBU0VfVVJMO1xuXG4gICAgaWYgKCFiYXNlVVJMLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykgJiYgIWJhc2VVUkwuc3RhcnRzV2l0aCgnaHR0cDovLycpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgYmFzZVVSTDogXCIke2Jhc2VVUkx9XCIg4oCUIG11c3Qgc3RhcnQgd2l0aCBodHRwOi8vIG9yIGh0dHBzOi8vYCk7XG4gICAgfVxuXG4gICAgbGFtYmRhTG9nLmluZm8oJ0NPTkZJRycsICdDb25maWd1cmF0aW9uIGxvYWRlZCcsIHsgYmFzZVVSTCwgcGx1Z2luRmlsdGVyIH0pO1xuXG4gICAgdmFsaWRhdGVQbHVnaW5GaWx0ZXIocGx1Z2luRmlsdGVyKTtcblxuICAgIC8vIEdldCB0b2tlbiBmcm9tIFNlY3JldHMgTWFuYWdlciBhbmQgY3JlYXRlIEFQSSBjbGllbnRcbiAgICBjb25zdCB0b2tlbiA9IGF3YWl0IGdldFRva2VuKCk7XG4gICAgY29uc3QgYXBpID0gY3JlYXRlKGJhc2VVUkwsIHRva2VuKTtcblxuICAgIC8vIEZldGNoIHBsdWdpblxuICAgIGxhbWJkYUxvZy5pbmZvKCdGRVRDSCcsICdJbml0aWF0aW5nIHBsdWdpbiBsb29rdXAuLi4nKTtcbiAgICBjb25zdCBwbHVnaW4gPSBhd2FpdCBmZXRjaChhcGksIHBsdWdpbkZpbHRlcik7XG4gICAgbGFtYmRhTG9nLmluZm8oJ0ZFVENIJywgJ1BsdWdpbiByZXRyaWV2ZWQgc3VjY2Vzc2Z1bGx5Jywge1xuICAgICAgbmFtZTogcGx1Z2luLm5hbWUsXG4gICAgICB2ZXJzaW9uOiBwbHVnaW4udmVyc2lvbixcbiAgICAgIGlkOiBwbHVnaW4uaWQsXG4gICAgfSk7XG5cbiAgICAvLyBTdHJpcCBsYXJnZSBmaWVsZHMgdG8gc3RheSB3aXRoaW4gQ2xvdWRGb3JtYXRpb24ncyA0MDk2LWJ5dGUgRGF0YSBsaW1pdC5cbiAgICAvLyBDREsgY29uc3RydWN0cyBvbmx5IG5lZWQgdGhlIGZpZWxkcyB1c2VkIGJ5IGNyZWF0ZUNvZGVCdWlsZFN0ZXAoKS5cbiAgICBjb25zdCBzbGltID0ge1xuICAgICAgaWQ6IHBsdWdpbi5pZCxcbiAgICAgIG5hbWU6IHBsdWdpbi5uYW1lLFxuICAgICAgdmVyc2lvbjogcGx1Z2luLnZlcnNpb24sXG4gICAgICBwbHVnaW5UeXBlOiBwbHVnaW4ucGx1Z2luVHlwZSxcbiAgICAgIGNvbXB1dGVUeXBlOiBwbHVnaW4uY29tcHV0ZVR5cGUsXG4gICAgICBjb21tYW5kczogcGx1Z2luLmNvbW1hbmRzLFxuICAgICAgaW5zdGFsbENvbW1hbmRzOiBwbHVnaW4uaW5zdGFsbENvbW1hbmRzLFxuICAgICAgZW52OiBwbHVnaW4uZW52LFxuICAgICAgbWV0YWRhdGE6IHBsdWdpbi5tZXRhZGF0YSxcbiAgICAgIHByaW1hcnlPdXRwdXREaXJlY3Rvcnk6IHBsdWdpbi5wcmltYXJ5T3V0cHV0RGlyZWN0b3J5LFxuICAgICAgc2VjcmV0czogcGx1Z2luLnNlY3JldHMsXG4gICAgICBmYWlsdXJlQmVoYXZpb3I6IHBsdWdpbi5mYWlsdXJlQmVoYXZpb3IsXG4gICAgICB0aW1lb3V0OiBwbHVnaW4udGltZW91dCxcbiAgICB9O1xuXG4gICAgY29uc3QgZW5jb2RlZCA9IEJ1ZmZlci5mcm9tKEpTT04uc3RyaW5naWZ5KHNsaW0pLCAndXRmLTgnKS50b1N0cmluZygnYmFzZTY0Jyk7XG4gICAgbGFtYmRhTG9nLmRlYnVnKCdFTkNPREUnLCAnRW5jb2RlZCBwbHVnaW4gZGF0YScsIHsgbGVuZ3RoOiBlbmNvZGVkLmxlbmd0aCB9KTtcblxuICAgIHJldHVybiB7XG4gICAgICAuLi5iYXNlUmVzcG9uc2UsXG4gICAgICBTdGF0dXM6ICdTVUNDRVNTJyxcbiAgICAgIFJlYXNvbjogYFBsdWdpbiAnJHtwbHVnaW4ubmFtZX0nICh2JHtwbHVnaW4udmVyc2lvbn0pIHJldHJpZXZlZCBzdWNjZXNzZnVsbHlgLFxuICAgICAgRGF0YToge1xuICAgICAgICBSZXN1bHRWYWx1ZTogZW5jb2RlZCxcbiAgICAgIH0sXG4gICAgfSBhcyBDbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlUmVzcG9uc2U7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc3QgcmVhc29uID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAnVW5leHBlY3RlZCBlcnJvciBvY2N1cnJlZCc7XG4gICAgbGFtYmRhTG9nLmVycm9yKCdFUlJPUicsICdIYW5kbGVyIGZhaWxlZCcsIHtcbiAgICAgIHJlYXNvbixcbiAgICAgIHN0YWNrOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3Iuc3RhY2sgOiB1bmRlZmluZWQsXG4gICAgfSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4uYmFzZVJlc3BvbnNlLFxuICAgICAgU3RhdHVzOiAnRkFJTEVEJyxcbiAgICAgIFJlYXNvbjogcmVhc29uLFxuICAgIH0gYXMgQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVJlc3BvbnNlO1xuICB9IGZpbmFsbHkge1xuICAgIGxhbWJkYUxvZy5pbmZvKCdFTkQnLCAnQ3VzdG9tIHJlc291cmNlIGV4ZWN1dGlvbiBjb21wbGV0ZWQnKTtcbiAgfVxufTtcbiJdfQ==
@@ -0,0 +1,12 @@
1
+ lockfileVersion: '9.0'
2
+
3
+ settings:
4
+ autoInstallPeers: true
5
+ excludeLinksFromLockfile: false
6
+
7
+ importers:
8
+
9
+ .:
10
+ dependencies: {}
11
+
12
+ packages: {}
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
+ }