@pipeline-builder/pipeline-core 3.1.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 (54) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +32 -0
  3. package/lib/config/app-config.d.ts +81 -0
  4. package/lib/config/app-config.js +151 -0
  5. package/lib/config/billing-config.d.ts +17 -0
  6. package/lib/config/billing-config.js +95 -0
  7. package/lib/config/config-types.d.ts +213 -0
  8. package/lib/config/config-types.js +5 -0
  9. package/lib/config/infrastructure-config.d.ts +55 -0
  10. package/lib/config/infrastructure-config.js +200 -0
  11. package/lib/config/server-config.d.ts +53 -0
  12. package/lib/config/server-config.js +180 -0
  13. package/lib/core/artifact-manager.d.ts +62 -0
  14. package/lib/core/artifact-manager.js +86 -0
  15. package/lib/core/id-generator.d.ts +26 -0
  16. package/lib/core/id-generator.js +44 -0
  17. package/lib/core/metadata-builder.d.ts +13 -0
  18. package/lib/core/metadata-builder.js +81 -0
  19. package/lib/core/network-types.d.ts +200 -0
  20. package/lib/core/network-types.js +5 -0
  21. package/lib/core/network.d.ts +20 -0
  22. package/lib/core/network.js +84 -0
  23. package/lib/core/pipeline-helpers.d.ts +53 -0
  24. package/lib/core/pipeline-helpers.js +273 -0
  25. package/lib/core/pipeline-types.d.ts +136 -0
  26. package/lib/core/pipeline-types.js +140 -0
  27. package/lib/core/role-types.d.ts +254 -0
  28. package/lib/core/role-types.js +5 -0
  29. package/lib/core/role.d.ts +14 -0
  30. package/lib/core/role.js +118 -0
  31. package/lib/core/security-group-types.d.ts +84 -0
  32. package/lib/core/security-group-types.js +5 -0
  33. package/lib/core/security-group.d.ts +14 -0
  34. package/lib/core/security-group.js +34 -0
  35. package/lib/handlers/plugin-lookup-handler.d.ts +32 -0
  36. package/lib/handlers/plugin-lookup-handler.js +313 -0
  37. package/lib/handlers/pnpm-lock.yaml +12 -0
  38. package/lib/index.d.ts +54 -0
  39. package/lib/index.js +112 -0
  40. package/lib/pipeline/pipeline-builder.d.ts +82 -0
  41. package/lib/pipeline/pipeline-builder.js +292 -0
  42. package/lib/pipeline/pipeline-configuration.d.ts +72 -0
  43. package/lib/pipeline/pipeline-configuration.js +196 -0
  44. package/lib/pipeline/plugin-lookup.d.ts +100 -0
  45. package/lib/pipeline/plugin-lookup.js +247 -0
  46. package/lib/pipeline/source-builder.d.ts +47 -0
  47. package/lib/pipeline/source-builder.js +111 -0
  48. package/lib/pipeline/source-types.d.ts +191 -0
  49. package/lib/pipeline/source-types.js +5 -0
  50. package/lib/pipeline/stage-builder.d.ts +71 -0
  51. package/lib/pipeline/stage-builder.js +118 -0
  52. package/lib/pipeline/step-types.d.ts +307 -0
  53. package/lib/pipeline/step-types.js +5 -0
  54. package/package.json +137 -0
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.loadServerConfig = loadServerConfig;
6
+ exports.loadAuthConfig = loadAuthConfig;
7
+ exports.loadRateLimitConfig = loadRateLimitConfig;
8
+ exports.validateServerConfig = validateServerConfig;
9
+ exports.validateAuthConfig = validateAuthConfig;
10
+ const api_core_1 = require("@pipeline-builder/api-core");
11
+ const app_config_1 = require("./app-config");
12
+ const log = (0, api_core_1.createLogger)('ServerConfig');
13
+ /**
14
+ * Load server configuration from environment variables.
15
+ *
16
+ * Environment variables:
17
+ * - `PORT` — HTTP listen port (default: `3000`)
18
+ * - `CORS_ORIGIN` — Comma-separated allowed origins (default: `PLATFORM_BASE_URL`)
19
+ * - `CORS_CREDENTIALS` — Allow credentials; set to `'false'` to disable (default: `true`)
20
+ * - `TRUST_PROXY` — Express trust proxy hops (default: `1`)
21
+ * - `PLATFORM_BASE_URL` — Frontend URL used as CORS fallback (default: `'https://localhost:8443'`)
22
+ *
23
+ * @returns Server configuration with port, CORS, trust proxy, and platform URL
24
+ */
25
+ function loadServerConfig() {
26
+ return {
27
+ port: parseInt(process.env.PORT || '3000', 10),
28
+ cors: {
29
+ credentials: process.env.CORS_CREDENTIALS !== 'false',
30
+ origin: process.env.CORS_ORIGIN
31
+ ? process.env.CORS_ORIGIN.split(',').map(o => o.trim())
32
+ : [process.env.PLATFORM_BASE_URL || app_config_1.CoreConstants.DEFAULT_PLATFORM_URL],
33
+ },
34
+ trustProxy: parseInt(process.env.TRUST_PROXY || '1', 10),
35
+ platformUrl: process.env.PLATFORM_BASE_URL || app_config_1.CoreConstants.DEFAULT_PLATFORM_URL,
36
+ httpClient: {
37
+ timeout: parseInt(process.env.HTTP_CLIENT_TIMEOUT || '5000', 10),
38
+ maxRetries: parseInt(process.env.HTTP_CLIENT_MAX_RETRIES || '2', 10),
39
+ retryDelayMs: parseInt(process.env.HTTP_CLIENT_RETRY_DELAY_MS || '200', 10),
40
+ },
41
+ sse: {
42
+ maxClientsPerRequest: parseInt(process.env.SSE_MAX_CLIENTS_PER_REQUEST || '10', 10),
43
+ clientTimeoutMs: parseInt(process.env.SSE_CLIENT_TIMEOUT_MS || '1800000', 10),
44
+ cleanupIntervalMs: parseInt(process.env.SSE_CLEANUP_INTERVAL_MS || '300000', 10),
45
+ },
46
+ services: {
47
+ pluginHost: process.env.PLUGIN_SERVICE_HOST || 'plugin',
48
+ pluginPort: parseInt(process.env.PLUGIN_SERVICE_PORT || '3000', 10),
49
+ pipelineHost: process.env.PIPELINE_SERVICE_HOST || 'pipeline',
50
+ pipelinePort: parseInt(process.env.PIPELINE_SERVICE_PORT || '3000', 10),
51
+ messageHost: process.env.MESSAGE_SERVICE_HOST || 'message',
52
+ messagePort: parseInt(process.env.MESSAGE_SERVICE_PORT || '3000', 10),
53
+ complianceHost: process.env.COMPLIANCE_SERVICE_HOST || 'compliance',
54
+ compliancePort: parseInt(process.env.COMPLIANCE_SERVICE_PORT || '3000', 10),
55
+ billingHost: process.env.BILLING_SERVICE_HOST || 'billing',
56
+ billingPort: parseInt(process.env.BILLING_SERVICE_PORT || '3000', 10),
57
+ billingTimeout: parseInt(process.env.BILLING_SERVICE_TIMEOUT || '5000', 10),
58
+ },
59
+ };
60
+ }
61
+ /**
62
+ * Load authentication configuration from environment variables.
63
+ *
64
+ * Environment variables:
65
+ * - `JWT_SECRET` — **Required.** Secret key for signing JWTs
66
+ * - `REFRESH_TOKEN_SECRET` — **Required.** Secret key for signing refresh tokens
67
+ * - `JWT_EXPIRES_IN` — JWT lifetime in seconds (default: `7200` = 2 hours)
68
+ * - `JWT_ALGORITHM` — JWT signing algorithm (default: `'HS256'`)
69
+ * - `JWT_SALT_ROUNDS` — bcrypt salt rounds for password hashing (default: `12`)
70
+ * - `REFRESH_TOKEN_EXPIRES_IN` — Refresh token lifetime in seconds (default: `2592000` = 30 days)
71
+ *
72
+ * @returns Authentication configuration with safe defaults (empty strings when env vars are unset).
73
+ * Call {@link validateAuthConfig} at server startup to enforce required secrets.
74
+ */
75
+ function loadAuthConfig() {
76
+ return {
77
+ jwt: {
78
+ secret: process.env.JWT_SECRET ?? '',
79
+ expiresIn: parseInt(process.env.JWT_EXPIRES_IN || '7200', 10),
80
+ algorithm: (process.env.JWT_ALGORITHM || 'HS256'),
81
+ saltRounds: parseInt(process.env.JWT_SALT_ROUNDS || '12', 10),
82
+ },
83
+ refreshToken: {
84
+ secret: process.env.REFRESH_TOKEN_SECRET || '',
85
+ expiresIn: parseInt(process.env.REFRESH_TOKEN_EXPIRES_IN || '2592000', 10),
86
+ },
87
+ };
88
+ }
89
+ /**
90
+ * Load rate limiting configuration from environment variables.
91
+ *
92
+ * Environment variables:
93
+ * - `LIMITER_MAX` — Max requests per window (default: `100`)
94
+ * - `LIMITER_WINDOWMS` — Rate limit window in ms (default: `900000` = 15 minutes)
95
+ *
96
+ * @returns Rate limit configuration
97
+ */
98
+ function loadRateLimitConfig() {
99
+ return {
100
+ max: parseInt(process.env.LIMITER_MAX || '100', 10),
101
+ windowMs: parseInt(process.env.LIMITER_WINDOWMS || '900000', 10),
102
+ legacyHeaders: false,
103
+ standardHeaders: true,
104
+ };
105
+ }
106
+ /**
107
+ * Validate server configuration and log warnings for insecure settings.
108
+ *
109
+ * @param config - Server configuration to validate
110
+ */
111
+ function validateServerConfig(config) {
112
+ const warnings = [];
113
+ // Check CORS configuration
114
+ const origin = config.cors.origin;
115
+ const isWildcard = origin === '*' || (Array.isArray(origin) && origin.includes('*'));
116
+ if (isWildcard) {
117
+ warnings.push('CORS origin set to wildcard (*) - consider restricting to specific domains');
118
+ }
119
+ if (isWildcard && config.cors.credentials) {
120
+ // Browsers reject this combination, but it indicates a misconfiguration
121
+ throw new Error('SECURITY ERROR: CORS_ORIGIN=* with CORS_CREDENTIALS=true is an invalid and insecure configuration. ' +
122
+ 'Set CORS_ORIGIN to specific domains or disable CORS_CREDENTIALS.');
123
+ }
124
+ // Check platform URL uses HTTPS
125
+ if (config.platformUrl.startsWith('http://') &&
126
+ !config.platformUrl.includes('localhost')) {
127
+ warnings.push('Platform URL uses HTTP instead of HTTPS - insecure for production');
128
+ }
129
+ // Display warnings
130
+ if (warnings.length > 0) {
131
+ log.warn('Server configuration warnings:');
132
+ warnings.forEach(warning => log.warn(` - ${warning}`));
133
+ }
134
+ }
135
+ const INSECURE_PATTERNS = ['secret', 'password', 'changeme', 'default', '123456', 'admin'];
136
+ function isInsecureSecret(secret) {
137
+ const lower = secret.toLowerCase();
138
+ return INSECURE_PATTERNS.some(s => lower === s || (lower.length < 64 && lower.includes(s)));
139
+ }
140
+ /**
141
+ * Validate authentication configuration (JWT secrets, algorithms, expiration).
142
+ * Call this at server startup, not during CDK synthesis.
143
+ *
144
+ * @param config - Auth configuration to validate
145
+ * @throws {Error} If secrets are insecure, too short (<32 chars), or use disallowed algorithms
146
+ */
147
+ function validateAuthConfig(config) {
148
+ const errors = [];
149
+ const warnings = [];
150
+ // Validate both secrets with the same checks
151
+ for (const [label, secret] of [['JWT', config.jwt.secret], ['Refresh token', config.refreshToken.secret]]) {
152
+ if (secret.length < 32) {
153
+ errors.push(`${label} secret should be at least 32 characters long`);
154
+ }
155
+ if (isInsecureSecret(secret)) {
156
+ errors.push(`${label} secret appears to be insecure or default value`);
157
+ }
158
+ }
159
+ // Check JWT expiration times
160
+ if (config.jwt.expiresIn > 86400) {
161
+ errors.push('JWT expiration must not exceed 24 hours (86400 seconds)');
162
+ }
163
+ else if (config.jwt.expiresIn > 7200) {
164
+ warnings.push('JWT expiration time is greater than 2 hours - shorter expiration recommended');
165
+ }
166
+ // Check algorithm
167
+ if (!app_config_1.CoreConstants.ALLOWED_JWT_ALGORITHMS.includes(config.jwt.algorithm)) {
168
+ errors.push(`JWT algorithm ${config.jwt.algorithm} is not in the allowed list`);
169
+ }
170
+ // Display warnings
171
+ if (warnings.length > 0) {
172
+ log.warn('Auth configuration warnings:');
173
+ warnings.forEach(warning => log.warn(` - ${warning}`));
174
+ }
175
+ // Throw errors
176
+ if (errors.length > 0) {
177
+ throw new Error(`Auth configuration validation failed:\n${errors.map(e => ` - ${e}`).join('\n')}`);
178
+ }
179
+ }
180
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLWNvbmZpZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb25maWcvc2VydmVyLWNvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsK0NBQStDO0FBQy9DLHNDQUFzQzs7QUFxQnRDLDRDQXNDQztBQWdCRCx3Q0FhQztBQVdELGtEQU9DO0FBT0Qsb0RBNEJDO0FBZ0JELGdEQXNDQztBQWpNRCx5REFBMEQ7QUFFMUQsNkNBQTZDO0FBRzdDLE1BQU0sR0FBRyxHQUFHLElBQUEsdUJBQVksRUFBQyxjQUFjLENBQUMsQ0FBQztBQUV6Qzs7Ozs7Ozs7Ozs7R0FXRztBQUNILFNBQWdCLGdCQUFnQjtJQUM5QixPQUFPO1FBQ0wsSUFBSSxFQUFFLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxNQUFNLEVBQUUsRUFBRSxDQUFDO1FBQzlDLElBQUksRUFBRTtZQUNKLFdBQVcsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLGdCQUFnQixLQUFLLE9BQU87WUFDckQsTUFBTSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVztnQkFDN0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQ3ZELENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLElBQUksMEJBQWEsQ0FBQyxvQkFBb0IsQ0FBQztTQUMxRTtRQUNELFVBQVUsRUFBRSxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxXQUFXLElBQUksR0FBRyxFQUFFLEVBQUUsQ0FBQztRQUN4RCxXQUFXLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsSUFBSSwwQkFBYSxDQUFDLG9CQUFvQjtRQUVoRixVQUFVLEVBQUU7WUFDVixP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QUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUNuRixDQUFDO0lBQ0osQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHR5cGUgeyBBbGdvcml0aG0gfSBmcm9tICdqc29ud2VidG9rZW4nO1xuaW1wb3J0IHsgQ29yZUNvbnN0YW50cyB9IGZyb20gJy4vYXBwLWNvbmZpZyc7XG5pbXBvcnQgdHlwZSB7IFNlcnZlckNvbmZpZywgQXV0aENvbmZpZywgUmF0ZUxpbWl0Q29uZmlnIH0gZnJvbSAnLi9jb25maWctdHlwZXMnO1xuXG5jb25zdCBsb2cgPSBjcmVhdGVMb2dnZXIoJ1NlcnZlckNvbmZpZycpO1xuXG4vKipcbiAqIExvYWQgc2VydmVyIGNvbmZpZ3VyYXRpb24gZnJvbSBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXG4gKlxuICogRW52aXJvbm1lbnQgdmFyaWFibGVzOlxuICogLSBgUE9SVGAg4oCUIEhUVFAgbGlzdGVuIHBvcnQgKGRlZmF1bHQ6IGAzMDAwYClcbiAqIC0gYENPUlNfT1JJR0lOYCDigJQgQ29tbWEtc2VwYXJhdGVkIGFsbG93ZWQgb3JpZ2lucyAoZGVmYXVsdDogYFBMQVRGT1JNX0JBU0VfVVJMYClcbiAqIC0gYENPUlNfQ1JFREVOVElBTFNgIOKAlCBBbGxvdyBjcmVkZW50aWFsczsgc2V0IHRvIGAnZmFsc2UnYCB0byBkaXNhYmxlIChkZWZhdWx0OiBgdHJ1ZWApXG4gKiAtIGBUUlVTVF9QUk9YWWAg4oCUIEV4cHJlc3MgdHJ1c3QgcHJveHkgaG9wcyAoZGVmYXVsdDogYDFgKVxuICogLSBgUExBVEZPUk1fQkFTRV9VUkxgIOKAlCBGcm9udGVuZCBVUkwgdXNlZCBhcyBDT1JTIGZhbGxiYWNrIChkZWZhdWx0OiBgJ2h0dHBzOi8vbG9jYWxob3N0Ojg0NDMnYClcbiAqXG4gKiBAcmV0dXJucyBTZXJ2ZXIgY29uZmlndXJhdGlvbiB3aXRoIHBvcnQsIENPUlMsIHRydXN0IHByb3h5LCBhbmQgcGxhdGZvcm0gVVJMXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsb2FkU2VydmVyQ29uZmlnKCk6IFNlcnZlckNvbmZpZyB7XG4gIHJldHVybiB7XG4gICAgcG9ydDogcGFyc2VJbnQocHJvY2Vzcy5lbnYuUE9SVCB8fCAnMzAwMCcsIDEwKSxcbiAgICBjb3JzOiB7XG4gICAgICBjcmVkZW50aWFsczogcHJvY2Vzcy5lbnYuQ09SU19DUkVERU5USUFMUyAhPT0gJ2ZhbHNlJyxcbiAgICAgIG9yaWdpbjogcHJvY2Vzcy5lbnYuQ09SU19PUklHSU5cbiAgICAgICAgPyBwcm9jZXNzLmVudi5DT1JTX09SSUdJTi5zcGxpdCgnLCcpLm1hcChvID0+IG8udHJpbSgpKVxuICAgICAgICA6IFtwcm9jZXNzLmVudi5QTEFURk9STV9CQVNFX1VSTCB8fCBDb3JlQ29uc3RhbnRzLkRFRkFVTFRfUExBVEZPUk1fVVJMXSxcbiAgICB9LFxuICAgIHRydXN0UHJveHk6IHBhcnNlSW50KHByb2Nlc3MuZW52LlRSVVNUX1BST1hZIHx8ICcxJywgMTApLFxuICAgIHBsYXRmb3JtVXJsOiBwcm9jZXNzLmVudi5QTEFURk9STV9CQVNFX1VSTCB8fCBDb3JlQ29uc3RhbnRzLkRFRkFVTFRfUExBVEZPUk1fVVJMLFxuXG4gICAgaHR0cENsaWVudDoge1xuICAgICAgdGltZW91dDogcGFyc2VJbnQocHJvY2Vzcy5lbnYuSFRUUF9DTElFTlRfVElNRU9VVCB8fCAnNTAwMCcsIDEwKSxcbiAgICAgIG1heFJldHJpZXM6IHBhcnNlSW50KHByb2Nlc3MuZW52LkhUVFBfQ0xJRU5UX01BWF9SRVRSSUVTIHx8ICcyJywgMTApLFxuICAgICAgcmV0cnlEZWxheU1zOiBwYXJzZUludChwcm9jZXNzLmVudi5IVFRQX0NMSUVOVF9SRVRSWV9ERUxBWV9NUyB8fCAnMjAwJywgMTApLFxuICAgIH0sXG5cbiAgICBzc2U6IHtcbiAgICAgIG1heENsaWVudHNQZXJSZXF1ZXN0OiBwYXJzZUludChwcm9jZXNzLmVudi5TU0VfTUFYX0NMSUVOVFNfUEVSX1JFUVVFU1QgfHwgJzEwJywgMTApLFxuICAgICAgY2xpZW50VGltZW91dE1zOiBwYXJzZUludChwcm9jZXNzLmVudi5TU0VfQ0xJRU5UX1RJTUVPVVRfTVMgfHwgJzE4MDAwMDAnLCAxMCksXG4gICAgICBjbGVhbnVwSW50ZXJ2YWxNczogcGFyc2VJbnQocHJvY2Vzcy5lbnYuU1NFX0NMRUFOVVBfSU5URVJWQUxfTVMgfHwgJzMwMDAwMCcsIDEwKSxcbiAgICB9LFxuXG4gICAgc2VydmljZXM6IHtcbiAgICAgIHBsdWdpbkhvc3Q6IHByb2Nlc3MuZW52LlBMVUdJTl9TRVJWSUNFX0hPU1QgfHwgJ3BsdWdpbicsXG4gICAgICBwbHVnaW5Qb3J0OiBwYXJzZUludChwcm9jZXNzLmVudi5QTFVHSU5fU0VSVklDRV9QT1JUIHx8ICczMDAwJywgMTApLFxuICAgICAgcGlwZWxpbmVIb3N0OiBwcm9jZXNzLmVudi5QSVBFTElORV9TRVJWSUNFX0hPU1QgfHwgJ3BpcGVsaW5lJyxcbiAgICAgIHBpcGVsaW5lUG9ydDogcGFyc2VJbnQocHJvY2Vzcy5lbnYuUElQRUxJTkVfU0VSVklDRV9QT1JUIHx8ICczMDAwJywgMTApLFxuICAgICAgbWVzc2FnZUhvc3Q6IHByb2Nlc3MuZW52Lk1FU1NBR0VfU0VSVklDRV9IT1NUIHx8ICdtZXNzYWdlJyxcbiAgICAgIG1lc3NhZ2VQb3J0OiBwYXJzZUludChwcm9jZXNzLmVudi5NRVNTQUdFX1NFUlZJQ0VfUE9SVCB8fCAnMzAwMCcsIDEwKSxcbiAgICAgIGNvbXBsaWFuY2VIb3N0OiBwcm9jZXNzLmVudi5DT01QTElBTkNFX1NFUlZJQ0VfSE9TVCB8fCAnY29tcGxpYW5jZScsXG4gICAgICBjb21wbGlhbmNlUG9ydDogcGFyc2VJbnQocHJvY2Vzcy5lbnYuQ09NUExJQU5DRV9TRVJWSUNFX1BPUlQgfHwgJzMwMDAnLCAxMCksXG4gICAgICBiaWxsaW5nSG9zdDogcHJvY2Vzcy5lbnYuQklMTElOR19TRVJWSUNFX0hPU1QgfHwgJ2JpbGxpbmcnLFxuICAgICAgYmlsbGluZ1BvcnQ6IHBhcnNlSW50KHByb2Nlc3MuZW52LkJJTExJTkdfU0VSVklDRV9QT1JUIHx8ICczMDAwJywgMTApLFxuICAgICAgYmlsbGluZ1RpbWVvdXQ6IHBhcnNlSW50KHByb2Nlc3MuZW52LkJJTExJTkdfU0VSVklDRV9USU1FT1VUIHx8ICc1MDAwJywgMTApLFxuICAgIH0sXG4gIH07XG59XG5cbi8qKlxuICogTG9hZCBhdXRoZW50aWNhdGlvbiBjb25maWd1cmF0aW9uIGZyb20gZW52aXJvbm1lbnQgdmFyaWFibGVzLlxuICpcbiAqIEVudmlyb25tZW50IHZhcmlhYmxlczpcbiAqIC0gYEpXVF9TRUNSRVRgIOKAlCAqKlJlcXVpcmVkLioqIFNlY3JldCBrZXkgZm9yIHNpZ25pbmcgSldUc1xuICogLSBgUkVGUkVTSF9UT0tFTl9TRUNSRVRgIOKAlCAqKlJlcXVpcmVkLioqIFNlY3JldCBrZXkgZm9yIHNpZ25pbmcgcmVmcmVzaCB0b2tlbnNcbiAqIC0gYEpXVF9FWFBJUkVTX0lOYCDigJQgSldUIGxpZmV0aW1lIGluIHNlY29uZHMgKGRlZmF1bHQ6IGA3MjAwYCA9IDIgaG91cnMpXG4gKiAtIGBKV1RfQUxHT1JJVEhNYCDigJQgSldUIHNpZ25pbmcgYWxnb3JpdGhtIChkZWZhdWx0OiBgJ0hTMjU2J2ApXG4gKiAtIGBKV1RfU0FMVF9ST1VORFNgIOKAlCBiY3J5cHQgc2FsdCByb3VuZHMgZm9yIHBhc3N3b3JkIGhhc2hpbmcgKGRlZmF1bHQ6IGAxMmApXG4gKiAtIGBSRUZSRVNIX1RPS0VOX0VYUElSRVNfSU5gIOKAlCBSZWZyZXNoIHRva2VuIGxpZmV0aW1lIGluIHNlY29uZHMgKGRlZmF1bHQ6IGAyNTkyMDAwYCA9IDMwIGRheXMpXG4gKlxuICogQHJldHVybnMgQXV0aGVudGljYXRpb24gY29uZmlndXJhdGlvbiB3aXRoIHNhZmUgZGVmYXVsdHMgKGVtcHR5IHN0cmluZ3Mgd2hlbiBlbnYgdmFycyBhcmUgdW5zZXQpLlxuICogQ2FsbCB7QGxpbmsgdmFsaWRhdGVBdXRoQ29uZmlnfSBhdCBzZXJ2ZXIgc3RhcnR1cCB0byBlbmZvcmNlIHJlcXVpcmVkIHNlY3JldHMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsb2FkQXV0aENvbmZpZygpOiBBdXRoQ29uZmlnIHtcbiAgcmV0dXJuIHtcbiAgICBqd3Q6IHtcbiAgICAgIHNlY3JldDogcHJvY2Vzcy5lbnYuSldUX1NFQ1JFVCA/PyAnJyxcbiAgICAgIGV4cGlyZXNJbjogcGFyc2VJbnQocHJvY2Vzcy5lbnYuSldUX0VYUElSRVNfSU4gfHwgJzcyMDAnLCAxMCksXG4gICAgICBhbGdvcml0aG06IChwcm9jZXNzLmVudi5KV1RfQUxHT1JJVEhNIHx8ICdIUzI1NicpIGFzIEFsZ29yaXRobSxcbiAgICAgIHNhbHRSb3VuZHM6IHBhcnNlSW50KHByb2Nlc3MuZW52LkpXVF9TQUxUX1JPVU5EUyB8fCAnMTInLCAxMCksXG4gICAgfSxcbiAgICByZWZyZXNoVG9rZW46IHtcbiAgICAgIHNlY3JldDogcHJvY2Vzcy5lbnYuUkVGUkVTSF9UT0tFTl9TRUNSRVQgfHwgJycsXG4gICAgICBleHBpcmVzSW46IHBhcnNlSW50KHByb2Nlc3MuZW52LlJFRlJFU0hfVE9LRU5fRVhQSVJFU19JTiB8fCAnMjU5MjAwMCcsIDEwKSxcbiAgICB9LFxuICB9O1xufVxuXG4vKipcbiAqIExvYWQgcmF0ZSBsaW1pdGluZyBjb25maWd1cmF0aW9uIGZyb20gZW52aXJvbm1lbnQgdmFyaWFibGVzLlxuICpcbiAqIEVudmlyb25tZW50IHZhcmlhYmxlczpcbiAqIC0gYExJTUlURVJfTUFYYCDigJQgTWF4IHJlcXVlc3RzIHBlciB3aW5kb3cgKGRlZmF1bHQ6IGAxMDBgKVxuICogLSBgTElNSVRFUl9XSU5ET1dNU2Ag4oCUIFJhdGUgbGltaXQgd2luZG93IGluIG1zIChkZWZhdWx0OiBgOTAwMDAwYCA9IDE1IG1pbnV0ZXMpXG4gKlxuICogQHJldHVybnMgUmF0ZSBsaW1pdCBjb25maWd1cmF0aW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsb2FkUmF0ZUxpbWl0Q29uZmlnKCk6IFJhdGVMaW1pdENvbmZpZyB7XG4gIHJldHVybiB7XG4gICAgbWF4OiBwYXJzZUludChwcm9jZXNzLmVudi5MSU1JVEVSX01BWCB8fCAnMTAwJywgMTApLFxuICAgIHdpbmRvd01zOiBwYXJzZUludChwcm9jZXNzLmVudi5MSU1JVEVSX1dJTkRPV01TIHx8ICc5MDAwMDAnLCAxMCksXG4gICAgbGVnYWN5SGVhZGVyczogZmFsc2UsXG4gICAgc3RhbmRhcmRIZWFkZXJzOiB0cnVlLFxuICB9O1xufVxuXG4vKipcbiAqIFZhbGlkYXRlIHNlcnZlciBjb25maWd1cmF0aW9uIGFuZCBsb2cgd2FybmluZ3MgZm9yIGluc2VjdXJlIHNldHRpbmdzLlxuICpcbiAqIEBwYXJhbSBjb25maWcgLSBTZXJ2ZXIgY29uZmlndXJhdGlvbiB0byB2YWxpZGF0ZVxuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVTZXJ2ZXJDb25maWcoY29uZmlnOiBTZXJ2ZXJDb25maWcpOiB2b2lkIHtcbiAgY29uc3Qgd2FybmluZ3M6IHN0cmluZ1tdID0gW107XG5cbiAgLy8gQ2hlY2sgQ09SUyBjb25maWd1cmF0aW9uXG4gIGNvbnN0IG9yaWdpbiA9IGNvbmZpZy5jb3JzLm9yaWdpbjtcbiAgY29uc3QgaXNXaWxkY2FyZCA9IG9yaWdpbiA9PT0gJyonIHx8IChBcnJheS5pc0FycmF5KG9yaWdpbikgJiYgb3JpZ2luLmluY2x1ZGVzKCcqJykpO1xuICBpZiAoaXNXaWxkY2FyZCkge1xuICAgIHdhcm5pbmdzLnB1c2goJ0NPUlMgb3JpZ2luIHNldCB0byB3aWxkY2FyZCAoKikgLSBjb25zaWRlciByZXN0cmljdGluZyB0byBzcGVjaWZpYyBkb21haW5zJyk7XG4gIH1cbiAgaWYgKGlzV2lsZGNhcmQgJiYgY29uZmlnLmNvcnMuY3JlZGVudGlhbHMpIHtcbiAgICAvLyBCcm93c2VycyByZWplY3QgdGhpcyBjb21iaW5hdGlvbiwgYnV0IGl0IGluZGljYXRlcyBhIG1pc2NvbmZpZ3VyYXRpb25cbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAnU0VDVVJJVFkgRVJST1I6IENPUlNfT1JJR0lOPSogd2l0aCBDT1JTX0NSRURFTlRJQUxTPXRydWUgaXMgYW4gaW52YWxpZCBhbmQgaW5zZWN1cmUgY29uZmlndXJhdGlvbi4gJyArXG4gICAgICAnU2V0IENPUlNfT1JJR0lOIHRvIHNwZWNpZmljIGRvbWFpbnMgb3IgZGlzYWJsZSBDT1JTX0NSRURFTlRJQUxTLicsXG4gICAgKTtcbiAgfVxuXG4gIC8vIENoZWNrIHBsYXRmb3JtIFVSTCB1c2VzIEhUVFBTXG4gIGlmIChjb25maWcucGxhdGZvcm1Vcmwuc3RhcnRzV2l0aCgnaHR0cDovLycpICYmXG4gICAgIWNvbmZpZy5wbGF0Zm9ybVVybC5pbmNsdWRlcygnbG9jYWxob3N0JykpIHtcbiAgICB3YXJuaW5ncy5wdXNoKCdQbGF0Zm9ybSBVUkwgdXNlcyBIVFRQIGluc3RlYWQgb2YgSFRUUFMgLSBpbnNlY3VyZSBmb3IgcHJvZHVjdGlvbicpO1xuICB9XG5cbiAgLy8gRGlzcGxheSB3YXJuaW5nc1xuICBpZiAod2FybmluZ3MubGVuZ3RoID4gMCkge1xuICAgIGxvZy53YXJuKCdTZXJ2ZXIgY29uZmlndXJhdGlvbiB3YXJuaW5nczonKTtcbiAgICB3YXJuaW5ncy5mb3JFYWNoKHdhcm5pbmcgPT4gbG9nLndhcm4oYCAgLSAke3dhcm5pbmd9YCkpO1xuICB9XG59XG5cbmNvbnN0IElOU0VDVVJFX1BBVFRFUk5TID0gWydzZWNyZXQnLCAncGFzc3dvcmQnLCAnY2hhbmdlbWUnLCAnZGVmYXVsdCcsICcxMjM0NTYnLCAnYWRtaW4nXTtcblxuZnVuY3Rpb24gaXNJbnNlY3VyZVNlY3JldChzZWNyZXQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBjb25zdCBsb3dlciA9IHNlY3JldC50b0xvd2VyQ2FzZSgpO1xuICByZXR1cm4gSU5TRUNVUkVfUEFUVEVSTlMuc29tZShzID0+IGxvd2VyID09PSBzIHx8IChsb3dlci5sZW5ndGggPCA2NCAmJiBsb3dlci5pbmNsdWRlcyhzKSkpO1xufVxuXG4vKipcbiAqIFZhbGlkYXRlIGF1dGhlbnRpY2F0aW9uIGNvbmZpZ3VyYXRpb24gKEpXVCBzZWNyZXRzLCBhbGdvcml0aG1zLCBleHBpcmF0aW9uKS5cbiAqIENhbGwgdGhpcyBhdCBzZXJ2ZXIgc3RhcnR1cCwgbm90IGR1cmluZyBDREsgc3ludGhlc2lzLlxuICpcbiAqIEBwYXJhbSBjb25maWcgLSBBdXRoIGNvbmZpZ3VyYXRpb24gdG8gdmFsaWRhdGVcbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiBzZWNyZXRzIGFyZSBpbnNlY3VyZSwgdG9vIHNob3J0ICg8MzIgY2hhcnMpLCBvciB1c2UgZGlzYWxsb3dlZCBhbGdvcml0aG1zXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZUF1dGhDb25maWcoY29uZmlnOiBBdXRoQ29uZmlnKTogdm9pZCB7XG4gIGNvbnN0IGVycm9yczogc3RyaW5nW10gPSBbXTtcbiAgY29uc3Qgd2FybmluZ3M6IHN0cmluZ1tdID0gW107XG5cbiAgLy8gVmFsaWRhdGUgYm90aCBzZWNyZXRzIHdpdGggdGhlIHNhbWUgY2hlY2tzXG4gIGZvciAoY29uc3QgW2xhYmVsLCBzZWNyZXRdIG9mIFtbJ0pXVCcsIGNvbmZpZy5qd3Quc2VjcmV0XSwgWydSZWZyZXNoIHRva2VuJywgY29uZmlnLnJlZnJlc2hUb2tlbi5zZWNyZXRdXSBhcyBjb25zdCkge1xuICAgIGlmIChzZWNyZXQubGVuZ3RoIDwgMzIpIHtcbiAgICAgIGVycm9ycy5wdXNoKGAke2xhYmVsfSBzZWNyZXQgc2hvdWxkIGJlIGF0IGxlYXN0IDMyIGNoYXJhY3RlcnMgbG9uZ2ApO1xuICAgIH1cbiAgICBpZiAoaXNJbnNlY3VyZVNlY3JldChzZWNyZXQpKSB7XG4gICAgICBlcnJvcnMucHVzaChgJHtsYWJlbH0gc2VjcmV0IGFwcGVhcnMgdG8gYmUgaW5zZWN1cmUgb3IgZGVmYXVsdCB2YWx1ZWApO1xuICAgIH1cbiAgfVxuXG4gIC8vIENoZWNrIEpXVCBleHBpcmF0aW9uIHRpbWVzXG4gIGlmIChjb25maWcuand0LmV4cGlyZXNJbiA+IDg2NDAwKSB7XG4gICAgZXJyb3JzLnB1c2goJ0pXVCBleHBpcmF0aW9uIG11c3Qgbm90IGV4Y2VlZCAyNCBob3VycyAoODY0MDAgc2Vjb25kcyknKTtcbiAgfSBlbHNlIGlmIChjb25maWcuand0LmV4cGlyZXNJbiA+IDcyMDApIHtcbiAgICB3YXJuaW5ncy5wdXNoKCdKV1QgZXhwaXJhdGlvbiB0aW1lIGlzIGdyZWF0ZXIgdGhhbiAyIGhvdXJzIC0gc2hvcnRlciBleHBpcmF0aW9uIHJlY29tbWVuZGVkJyk7XG4gIH1cblxuICAvLyBDaGVjayBhbGdvcml0aG1cbiAgaWYgKCFDb3JlQ29uc3RhbnRzLkFMTE9XRURfSldUX0FMR09SSVRITVMuaW5jbHVkZXMoY29uZmlnLmp3dC5hbGdvcml0aG0pKSB7XG4gICAgZXJyb3JzLnB1c2goYEpXVCBhbGdvcml0aG0gJHtjb25maWcuand0LmFsZ29yaXRobX0gaXMgbm90IGluIHRoZSBhbGxvd2VkIGxpc3RgKTtcbiAgfVxuXG4gIC8vIERpc3BsYXkgd2FybmluZ3NcbiAgaWYgKHdhcm5pbmdzLmxlbmd0aCA+IDApIHtcbiAgICBsb2cud2FybignQXV0aCBjb25maWd1cmF0aW9uIHdhcm5pbmdzOicpO1xuICAgIHdhcm5pbmdzLmZvckVhY2god2FybmluZyA9PiBsb2cud2FybihgICAtICR7d2FybmluZ31gKSk7XG4gIH1cblxuICAvLyBUaHJvdyBlcnJvcnNcbiAgaWYgKGVycm9ycy5sZW5ndGggPiAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYEF1dGggY29uZmlndXJhdGlvbiB2YWxpZGF0aW9uIGZhaWxlZDpcXG4ke2Vycm9ycy5tYXAoZSA9PiBgICAtICR7ZX1gKS5qb2luKCdcXG4nKX1gLFxuICAgICk7XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,62 @@
1
+ import { CodeBuildStep, FileSet, ShellStep } from 'aws-cdk-lib/pipelines';
2
+ export interface ArtifactKey {
3
+ readonly stageName: string;
4
+ readonly stageAlias: string;
5
+ readonly pluginName: string;
6
+ readonly pluginAlias: string;
7
+ readonly outputDirectory: string;
8
+ }
9
+ /**
10
+ * Manages build step artifacts with hierarchical key-based lookup.
11
+ * Keys follow the pattern: stageName:stageAlias:pluginName:pluginAlias:outputDirectory
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * // Synth step: "no-stage:no-stage-alias:cdk-synth:cdk-synth-alias:cdk.out"
16
+ * // Build step: "build:build-alias:nodejs-build:nodejs-build-alias:dist"
17
+ * ```
18
+ */
19
+ export declare class ArtifactManager {
20
+ private readonly artifacts;
21
+ /**
22
+ * Generate a key string from artifact parameters
23
+ */
24
+ private generateKey;
25
+ /**
26
+ * Register a build step artifact
27
+ * @param key - The hierarchical key identifying this artifact (includes output directory)
28
+ * @param step - The CodeBuildStep or ShellStep to store
29
+ */
30
+ add(key: ArtifactKey, step: CodeBuildStep | ShellStep): void;
31
+ /**
32
+ * Get a build step by its artifact key
33
+ * @param key - The hierarchical key identifying the artifact
34
+ * @returns The stored step, or undefined if not found
35
+ */
36
+ get(key: ArtifactKey): CodeBuildStep | ShellStep | undefined;
37
+ /**
38
+ * Get the primary output FileSet from a registered step.
39
+ * @param key - The artifact key identifying the step
40
+ * @returns The primary output FileSet
41
+ * @throws Error if the step is not found or has no primary output
42
+ */
43
+ getOutput(key: ArtifactKey): FileSet;
44
+ /**
45
+ * Register an additional output directory on a stored step and return its FileSet.
46
+ * Calls CDK's addOutputDirectory() to create a named output beyond the primary.
47
+ * @param key - The artifact key identifying the step
48
+ * @param directory - The additional output directory path to register
49
+ * @returns The FileSet for the additional output directory
50
+ * @throws Error if the step is not found
51
+ */
52
+ addOutput(key: ArtifactKey, directory: string): FileSet;
53
+ /**
54
+ * Get a step by key or throw with a helpful error listing available artifacts.
55
+ */
56
+ private require;
57
+ /**
58
+ * List all artifact keys
59
+ * @returns Array of all stored artifact key strings
60
+ */
61
+ list(): string[];
62
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.ArtifactManager = void 0;
6
+ /**
7
+ * Manages build step artifacts with hierarchical key-based lookup.
8
+ * Keys follow the pattern: stageName:stageAlias:pluginName:pluginAlias:outputDirectory
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * // Synth step: "no-stage:no-stage-alias:cdk-synth:cdk-synth-alias:cdk.out"
13
+ * // Build step: "build:build-alias:nodejs-build:nodejs-build-alias:dist"
14
+ * ```
15
+ */
16
+ class ArtifactManager {
17
+ artifacts = new Map();
18
+ /**
19
+ * Generate a key string from artifact parameters
20
+ */
21
+ generateKey(key) {
22
+ return `${key.stageName}:${key.stageAlias}:${key.pluginName}:${key.pluginAlias}:${key.outputDirectory}`;
23
+ }
24
+ /**
25
+ * Register a build step artifact
26
+ * @param key - The hierarchical key identifying this artifact (includes output directory)
27
+ * @param step - The CodeBuildStep or ShellStep to store
28
+ */
29
+ add(key, step) {
30
+ this.artifacts.set(this.generateKey(key), step);
31
+ }
32
+ /**
33
+ * Get a build step by its artifact key
34
+ * @param key - The hierarchical key identifying the artifact
35
+ * @returns The stored step, or undefined if not found
36
+ */
37
+ get(key) {
38
+ return this.artifacts.get(this.generateKey(key));
39
+ }
40
+ /**
41
+ * Get the primary output FileSet from a registered step.
42
+ * @param key - The artifact key identifying the step
43
+ * @returns The primary output FileSet
44
+ * @throws Error if the step is not found or has no primary output
45
+ */
46
+ getOutput(key) {
47
+ const step = this.require(key);
48
+ const output = step.primaryOutput;
49
+ if (!output) {
50
+ throw new Error(`Step '${key.pluginName}' has no primary output`);
51
+ }
52
+ return output;
53
+ }
54
+ /**
55
+ * Register an additional output directory on a stored step and return its FileSet.
56
+ * Calls CDK's addOutputDirectory() to create a named output beyond the primary.
57
+ * @param key - The artifact key identifying the step
58
+ * @param directory - The additional output directory path to register
59
+ * @returns The FileSet for the additional output directory
60
+ * @throws Error if the step is not found
61
+ */
62
+ addOutput(key, directory) {
63
+ return this.require(key).addOutputDirectory(directory);
64
+ }
65
+ /**
66
+ * Get a step by key or throw with a helpful error listing available artifacts.
67
+ */
68
+ require(key) {
69
+ const step = this.get(key);
70
+ if (!step) {
71
+ const registered = this.list();
72
+ const available = registered.length > 0 ? ` Available: [${registered.join(', ')}]` : ' No artifacts registered.';
73
+ throw new Error(`No artifact registered for "${this.generateKey(key)}".${available}`);
74
+ }
75
+ return step;
76
+ }
77
+ /**
78
+ * List all artifact keys
79
+ * @returns Array of all stored artifact key strings
80
+ */
81
+ list() {
82
+ return Array.from(this.artifacts.keys());
83
+ }
84
+ }
85
+ exports.ArtifactManager = ArtifactManager;
86
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJ0aWZhY3QtbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb3JlL2FydGlmYWN0LW1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7OztBQVl0Qzs7Ozs7Ozs7O0dBU0c7QUFDSCxNQUFhLGVBQWU7SUFDVCxTQUFTLEdBQTJDLElBQUksR0FBRyxFQUFFLENBQUM7SUFFL0U7O09BRUc7SUFDSyxXQUFXLENBQUMsR0FBZ0I7UUFDbEMsT0FBTyxHQUFHLEdBQUcsQ0FBQyxTQUFTLElBQUksR0FBRyxDQUFDLFVBQVUsSUFBSSxHQUFHLENBQUMsVUFBVSxJQUFJLEdBQUcsQ0FBQyxXQUFXLElBQUksR0FBRyxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQzFHLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsR0FBRyxDQUFDLEdBQWdCLEVBQUUsSUFBK0I7UUFDbkQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUNsRCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEdBQUcsQ0FBQyxHQUFnQjtRQUNsQixPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNuRCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxTQUFTLENBQUMsR0FBZ0I7UUFDeEIsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUMvQixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDO1FBQ2xDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNaLE1BQU0sSUFBSSxLQUFLLENBQUMsU0FBUyxHQUFHLENBQUMsVUFBVSx5QkFBeUIsQ0FBQyxDQUFDO1FBQ3BFLENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILFNBQVMsQ0FBQyxHQUFnQixFQUFFLFNBQWlCO1FBQzNDLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxPQUFPLENBQUMsR0FBZ0I7UUFDOUIsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUMzQixJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDVixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDL0IsTUFBTSxTQUFTLEdBQUcsVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLDJCQUEyQixDQUFDO1lBQ2pILE1BQU0sSUFBSSxLQUFLLENBQUMsK0JBQStCLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssU0FBUyxFQUFFLENBQUMsQ0FBQztRQUN4RixDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsSUFBSTtRQUNGLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDM0MsQ0FBQztDQUNGO0FBM0VELDBDQTJFQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBDb2RlQnVpbGRTdGVwLCBGaWxlU2V0LCBTaGVsbFN0ZXAgfSBmcm9tICdhd3MtY2RrLWxpYi9waXBlbGluZXMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEFydGlmYWN0S2V5IHtcbiAgcmVhZG9ubHkgc3RhZ2VOYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHN0YWdlQWxpYXM6IHN0cmluZztcbiAgcmVhZG9ubHkgcGx1Z2luTmFtZTogc3RyaW5nO1xuICByZWFkb25seSBwbHVnaW5BbGlhczogc3RyaW5nO1xuICByZWFkb25seSBvdXRwdXREaXJlY3Rvcnk6IHN0cmluZztcbn1cblxuLyoqXG4gKiBNYW5hZ2VzIGJ1aWxkIHN0ZXAgYXJ0aWZhY3RzIHdpdGggaGllcmFyY2hpY2FsIGtleS1iYXNlZCBsb29rdXAuXG4gKiBLZXlzIGZvbGxvdyB0aGUgcGF0dGVybjogc3RhZ2VOYW1lOnN0YWdlQWxpYXM6cGx1Z2luTmFtZTpwbHVnaW5BbGlhczpvdXRwdXREaXJlY3RvcnlcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gU3ludGggc3RlcDogXCJuby1zdGFnZTpuby1zdGFnZS1hbGlhczpjZGstc3ludGg6Y2RrLXN5bnRoLWFsaWFzOmNkay5vdXRcIlxuICogLy8gQnVpbGQgc3RlcDogXCJidWlsZDpidWlsZC1hbGlhczpub2RlanMtYnVpbGQ6bm9kZWpzLWJ1aWxkLWFsaWFzOmRpc3RcIlxuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBBcnRpZmFjdE1hbmFnZXIge1xuICBwcml2YXRlIHJlYWRvbmx5IGFydGlmYWN0czogTWFwPHN0cmluZywgQ29kZUJ1aWxkU3RlcCB8IFNoZWxsU3RlcD4gPSBuZXcgTWFwKCk7XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIGEga2V5IHN0cmluZyBmcm9tIGFydGlmYWN0IHBhcmFtZXRlcnNcbiAgICovXG4gIHByaXZhdGUgZ2VuZXJhdGVLZXkoa2V5OiBBcnRpZmFjdEtleSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGAke2tleS5zdGFnZU5hbWV9OiR7a2V5LnN0YWdlQWxpYXN9OiR7a2V5LnBsdWdpbk5hbWV9OiR7a2V5LnBsdWdpbkFsaWFzfToke2tleS5vdXRwdXREaXJlY3Rvcnl9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciBhIGJ1aWxkIHN0ZXAgYXJ0aWZhY3RcbiAgICogQHBhcmFtIGtleSAtIFRoZSBoaWVyYXJjaGljYWwga2V5IGlkZW50aWZ5aW5nIHRoaXMgYXJ0aWZhY3QgKGluY2x1ZGVzIG91dHB1dCBkaXJlY3RvcnkpXG4gICAqIEBwYXJhbSBzdGVwIC0gVGhlIENvZGVCdWlsZFN0ZXAgb3IgU2hlbGxTdGVwIHRvIHN0b3JlXG4gICAqL1xuICBhZGQoa2V5OiBBcnRpZmFjdEtleSwgc3RlcDogQ29kZUJ1aWxkU3RlcCB8IFNoZWxsU3RlcCk6IHZvaWQge1xuICAgIHRoaXMuYXJ0aWZhY3RzLnNldCh0aGlzLmdlbmVyYXRlS2V5KGtleSksIHN0ZXApO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhIGJ1aWxkIHN0ZXAgYnkgaXRzIGFydGlmYWN0IGtleVxuICAgKiBAcGFyYW0ga2V5IC0gVGhlIGhpZXJhcmNoaWNhbCBrZXkgaWRlbnRpZnlpbmcgdGhlIGFydGlmYWN0XG4gICAqIEByZXR1cm5zIFRoZSBzdG9yZWQgc3RlcCwgb3IgdW5kZWZpbmVkIGlmIG5vdCBmb3VuZFxuICAgKi9cbiAgZ2V0KGtleTogQXJ0aWZhY3RLZXkpOiBDb2RlQnVpbGRTdGVwIHwgU2hlbGxTdGVwIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5hcnRpZmFjdHMuZ2V0KHRoaXMuZ2VuZXJhdGVLZXkoa2V5KSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBwcmltYXJ5IG91dHB1dCBGaWxlU2V0IGZyb20gYSByZWdpc3RlcmVkIHN0ZXAuXG4gICAqIEBwYXJhbSBrZXkgLSBUaGUgYXJ0aWZhY3Qga2V5IGlkZW50aWZ5aW5nIHRoZSBzdGVwXG4gICAqIEByZXR1cm5zIFRoZSBwcmltYXJ5IG91dHB1dCBGaWxlU2V0XG4gICAqIEB0aHJvd3MgRXJyb3IgaWYgdGhlIHN0ZXAgaXMgbm90IGZvdW5kIG9yIGhhcyBubyBwcmltYXJ5IG91dHB1dFxuICAgKi9cbiAgZ2V0T3V0cHV0KGtleTogQXJ0aWZhY3RLZXkpOiBGaWxlU2V0IHtcbiAgICBjb25zdCBzdGVwID0gdGhpcy5yZXF1aXJlKGtleSk7XG4gICAgY29uc3Qgb3V0cHV0ID0gc3RlcC5wcmltYXJ5T3V0cHV0O1xuICAgIGlmICghb3V0cHV0KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFN0ZXAgJyR7a2V5LnBsdWdpbk5hbWV9JyBoYXMgbm8gcHJpbWFyeSBvdXRwdXRgKTtcbiAgICB9XG4gICAgcmV0dXJuIG91dHB1dDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciBhbiBhZGRpdGlvbmFsIG91dHB1dCBkaXJlY3Rvcnkgb24gYSBzdG9yZWQgc3RlcCBhbmQgcmV0dXJuIGl0cyBGaWxlU2V0LlxuICAgKiBDYWxscyBDREsncyBhZGRPdXRwdXREaXJlY3RvcnkoKSB0byBjcmVhdGUgYSBuYW1lZCBvdXRwdXQgYmV5b25kIHRoZSBwcmltYXJ5LlxuICAgKiBAcGFyYW0ga2V5IC0gVGhlIGFydGlmYWN0IGtleSBpZGVudGlmeWluZyB0aGUgc3RlcFxuICAgKiBAcGFyYW0gZGlyZWN0b3J5IC0gVGhlIGFkZGl0aW9uYWwgb3V0cHV0IGRpcmVjdG9yeSBwYXRoIHRvIHJlZ2lzdGVyXG4gICAqIEByZXR1cm5zIFRoZSBGaWxlU2V0IGZvciB0aGUgYWRkaXRpb25hbCBvdXRwdXQgZGlyZWN0b3J5XG4gICAqIEB0aHJvd3MgRXJyb3IgaWYgdGhlIHN0ZXAgaXMgbm90IGZvdW5kXG4gICAqL1xuICBhZGRPdXRwdXQoa2V5OiBBcnRpZmFjdEtleSwgZGlyZWN0b3J5OiBzdHJpbmcpOiBGaWxlU2V0IHtcbiAgICByZXR1cm4gdGhpcy5yZXF1aXJlKGtleSkuYWRkT3V0cHV0RGlyZWN0b3J5KGRpcmVjdG9yeSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGEgc3RlcCBieSBrZXkgb3IgdGhyb3cgd2l0aCBhIGhlbHBmdWwgZXJyb3IgbGlzdGluZyBhdmFpbGFibGUgYXJ0aWZhY3RzLlxuICAgKi9cbiAgcHJpdmF0ZSByZXF1aXJlKGtleTogQXJ0aWZhY3RLZXkpOiBDb2RlQnVpbGRTdGVwIHwgU2hlbGxTdGVwIHtcbiAgICBjb25zdCBzdGVwID0gdGhpcy5nZXQoa2V5KTtcbiAgICBpZiAoIXN0ZXApIHtcbiAgICAgIGNvbnN0IHJlZ2lzdGVyZWQgPSB0aGlzLmxpc3QoKTtcbiAgICAgIGNvbnN0IGF2YWlsYWJsZSA9IHJlZ2lzdGVyZWQubGVuZ3RoID4gMCA/IGAgQXZhaWxhYmxlOiBbJHtyZWdpc3RlcmVkLmpvaW4oJywgJyl9XWAgOiAnIE5vIGFydGlmYWN0cyByZWdpc3RlcmVkLic7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGFydGlmYWN0IHJlZ2lzdGVyZWQgZm9yIFwiJHt0aGlzLmdlbmVyYXRlS2V5KGtleSl9XCIuJHthdmFpbGFibGV9YCk7XG4gICAgfVxuICAgIHJldHVybiBzdGVwO1xuICB9XG5cbiAgLyoqXG4gICAqIExpc3QgYWxsIGFydGlmYWN0IGtleXNcbiAgICogQHJldHVybnMgQXJyYXkgb2YgYWxsIHN0b3JlZCBhcnRpZmFjdCBrZXkgc3RyaW5nc1xuICAgKi9cbiAgbGlzdCgpOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5hcnRpZmFjdHMua2V5cygpKTtcbiAgfVxufVxuIl19
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Generates unique CDK construct IDs by appending auto-incrementing counters to labels.
3
+ * Labels that already end with a numeric counter (e.g., 'cdk:pipeline:1') are returned as-is.
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * const id = new UniqueId();
8
+ *
9
+ * id.generate('plugin:lookup'); // "plugin:lookup:1"
10
+ * id.generate('cdk:synth'); // "cdk:synth:1"
11
+ * id.generate('plugin:lookup'); // "plugin:lookup:2"
12
+ * id.generate('cdk:pipeline:1'); // "cdk:pipeline:1" (already has counter)
13
+ * ```
14
+ */
15
+ export declare class UniqueId {
16
+ private readonly _counters;
17
+ /**
18
+ * Returns a unique construct ID for the given label.
19
+ * If the label already ends with a numeric counter, it is returned as-is.
20
+ * Otherwise, an auto-incrementing counter is appended.
21
+ *
22
+ * @param label - Colon-separated namespace (e.g., 'plugin:lookup')
23
+ * @returns The label with counter appended, or unchanged if it already has one
24
+ */
25
+ generate(label: string): string;
26
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.UniqueId = void 0;
6
+ /**
7
+ * Generates unique CDK construct IDs by appending auto-incrementing counters to labels.
8
+ * Labels that already end with a numeric counter (e.g., 'cdk:pipeline:1') are returned as-is.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const id = new UniqueId();
13
+ *
14
+ * id.generate('plugin:lookup'); // "plugin:lookup:1"
15
+ * id.generate('cdk:synth'); // "cdk:synth:1"
16
+ * id.generate('plugin:lookup'); // "plugin:lookup:2"
17
+ * id.generate('cdk:pipeline:1'); // "cdk:pipeline:1" (already has counter)
18
+ * ```
19
+ */
20
+ class UniqueId {
21
+ _counters = new Map();
22
+ /**
23
+ * Returns a unique construct ID for the given label.
24
+ * If the label already ends with a numeric counter, it is returned as-is.
25
+ * Otherwise, an auto-incrementing counter is appended.
26
+ *
27
+ * @param label - Colon-separated namespace (e.g., 'plugin:lookup')
28
+ * @returns The label with counter appended, or unchanged if it already has one
29
+ */
30
+ generate(label) {
31
+ if (!label || typeof label !== 'string') {
32
+ throw new Error('Label must be a non-empty string');
33
+ }
34
+ // If label already ends with a numeric counter, return as-is
35
+ if (/:\d+$/.test(label)) {
36
+ return label;
37
+ }
38
+ const count = (this._counters.get(label) ?? 0) + 1;
39
+ this._counters.set(label, count);
40
+ return `${label}:${count}`;
41
+ }
42
+ }
43
+ exports.UniqueId = UniqueId;
44
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaWQtZ2VuZXJhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvcmUvaWQtZ2VuZXJhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDOzs7QUFFdEM7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILE1BQWEsUUFBUTtJQUNGLFNBQVMsR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztJQUV2RDs7Ozs7OztPQU9HO0lBQ0gsUUFBUSxDQUFDLEtBQWE7UUFDcEIsSUFBSSxDQUFDLEtBQUssSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUN4QyxNQUFNLElBQUksS0FBSyxDQUFDLGtDQUFrQyxDQUFDLENBQUM7UUFDdEQsQ0FBQztRQUVELDZEQUE2RDtRQUM3RCxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN4QixPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFFRCxNQUFNLEtBQUssR0FBRyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNuRCxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFFakMsT0FBTyxHQUFHLEtBQUssSUFBSSxLQUFLLEVBQUUsQ0FBQztJQUM3QixDQUFDO0NBQ0Y7QUExQkQsNEJBMEJDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogR2VuZXJhdGVzIHVuaXF1ZSBDREsgY29uc3RydWN0IElEcyBieSBhcHBlbmRpbmcgYXV0by1pbmNyZW1lbnRpbmcgY291bnRlcnMgdG8gbGFiZWxzLlxuICogTGFiZWxzIHRoYXQgYWxyZWFkeSBlbmQgd2l0aCBhIG51bWVyaWMgY291bnRlciAoZS5nLiwgJ2NkazpwaXBlbGluZToxJykgYXJlIHJldHVybmVkIGFzLWlzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBpZCA9IG5ldyBVbmlxdWVJZCgpO1xuICpcbiAqIGlkLmdlbmVyYXRlKCdwbHVnaW46bG9va3VwJyk7ICAgLy8gXCJwbHVnaW46bG9va3VwOjFcIlxuICogaWQuZ2VuZXJhdGUoJ2NkazpzeW50aCcpOyAgICAgICAvLyBcImNkazpzeW50aDoxXCJcbiAqIGlkLmdlbmVyYXRlKCdwbHVnaW46bG9va3VwJyk7ICAgLy8gXCJwbHVnaW46bG9va3VwOjJcIlxuICogaWQuZ2VuZXJhdGUoJ2NkazpwaXBlbGluZToxJyk7IC8vIFwiY2RrOnBpcGVsaW5lOjFcIiAoYWxyZWFkeSBoYXMgY291bnRlcilcbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgVW5pcXVlSWQge1xuICBwcml2YXRlIHJlYWRvbmx5IF9jb3VudGVycyA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSB1bmlxdWUgY29uc3RydWN0IElEIGZvciB0aGUgZ2l2ZW4gbGFiZWwuXG4gICAqIElmIHRoZSBsYWJlbCBhbHJlYWR5IGVuZHMgd2l0aCBhIG51bWVyaWMgY291bnRlciwgaXQgaXMgcmV0dXJuZWQgYXMtaXMuXG4gICAqIE90aGVyd2lzZSwgYW4gYXV0by1pbmNyZW1lbnRpbmcgY291bnRlciBpcyBhcHBlbmRlZC5cbiAgICpcbiAgICogQHBhcmFtIGxhYmVsIC0gQ29sb24tc2VwYXJhdGVkIG5hbWVzcGFjZSAoZS5nLiwgJ3BsdWdpbjpsb29rdXAnKVxuICAgKiBAcmV0dXJucyBUaGUgbGFiZWwgd2l0aCBjb3VudGVyIGFwcGVuZGVkLCBvciB1bmNoYW5nZWQgaWYgaXQgYWxyZWFkeSBoYXMgb25lXG4gICAqL1xuICBnZW5lcmF0ZShsYWJlbDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBpZiAoIWxhYmVsIHx8IHR5cGVvZiBsYWJlbCAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTGFiZWwgbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmcnKTtcbiAgICB9XG5cbiAgICAvLyBJZiBsYWJlbCBhbHJlYWR5IGVuZHMgd2l0aCBhIG51bWVyaWMgY291bnRlciwgcmV0dXJuIGFzLWlzXG4gICAgaWYgKC86XFxkKyQvLnRlc3QobGFiZWwpKSB7XG4gICAgICByZXR1cm4gbGFiZWw7XG4gICAgfVxuXG4gICAgY29uc3QgY291bnQgPSAodGhpcy5fY291bnRlcnMuZ2V0KGxhYmVsKSA/PyAwKSArIDE7XG4gICAgdGhpcy5fY291bnRlcnMuc2V0KGxhYmVsLCBjb3VudCk7XG5cbiAgICByZXR1cm4gYCR7bGFiZWx9OiR7Y291bnR9YDtcbiAgfVxufVxuIl19
@@ -0,0 +1,13 @@
1
+ import type { BuildEnvironment } from 'aws-cdk-lib/aws-codebuild';
2
+ import type { CodeBuildStepProps, CodePipelineProps, ShellStepProps } from 'aws-cdk-lib/pipelines';
3
+ import type { MetaDataType } from './pipeline-types';
4
+ /** Extract CDK construct config from metadata for a given namespace. */
5
+ export declare function buildConfigFromMetadata(metadata: MetaDataType, namespace: string): Record<string, unknown>;
6
+ /** Extract CodePipeline config from metadata. */
7
+ export declare function metadataForCodePipeline(metadata: MetaDataType): Partial<CodePipelineProps>;
8
+ /** Extract CodeBuildStep config from metadata. */
9
+ export declare function metadataForCodeBuildStep(metadata: MetaDataType): Partial<CodeBuildStepProps>;
10
+ /** Extract ShellStep config from metadata. */
11
+ export declare function metadataForShellStep(metadata: MetaDataType): Partial<ShellStepProps>;
12
+ /** Extract BuildEnvironment config from metadata. */
13
+ export declare function metadataForBuildEnvironment(metadata: MetaDataType): Partial<BuildEnvironment>;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.buildConfigFromMetadata = buildConfigFromMetadata;
6
+ exports.metadataForCodePipeline = metadataForCodePipeline;
7
+ exports.metadataForCodeBuildStep = metadataForCodeBuildStep;
8
+ exports.metadataForShellStep = metadataForShellStep;
9
+ exports.metadataForBuildEnvironment = metadataForBuildEnvironment;
10
+ const pipeline_types_1 = require("./pipeline-types");
11
+ /**
12
+ * Type-safe namespace constants for metadata configuration.
13
+ */
14
+ const NAMESPACE = {
15
+ SHELL_STEP: 'pipelines:shellstep',
16
+ CODE_BUILD_STEP: 'pipelines:codebuildstep',
17
+ BUILD_ENVIRONMENT: 'codebuild:buildenvironment',
18
+ CODE_PIPELINE: 'pipelines:codepipeline',
19
+ };
20
+ const NAMESPACE_KEY_MAP = {
21
+ [NAMESPACE.SHELL_STEP]: {
22
+ booleanKeys: [],
23
+ passthroughKeys: ['additionalInputs', 'commands', 'env', 'envFromCfnOutputs', 'input', 'installCommands', 'primaryOutputDirectory'],
24
+ },
25
+ [NAMESPACE.CODE_BUILD_STEP]: {
26
+ booleanKeys: [],
27
+ passthroughKeys: ['actionRole', 'additionalInputs', 'buildEnvironment', 'cache', 'commands', 'env', 'envFromCfnOutputs', 'fileSystemLocations', 'input', 'installCommands', 'logging', 'partialBuildSpec', 'primaryOutputDirectory', 'projectName', 'role', 'rolePolicyStatements', 'timeout'],
28
+ },
29
+ [NAMESPACE.BUILD_ENVIRONMENT]: {
30
+ booleanKeys: ['privileged'],
31
+ passthroughKeys: ['buildImage', 'certificate', 'computeType', 'dockerServer', 'environmentVariables', 'fleet'],
32
+ },
33
+ [NAMESPACE.CODE_PIPELINE]: {
34
+ booleanKeys: ['crossAccountKeys', 'dockerEnabledForSelfMutation', 'dockerEnabledForSynth', 'enableKeyRotation', 'publishAssetsInParallel', 'reuseCrossRegionSupportStacks', 'selfMutation', 'useChangeSets', 'usePipelineRoleForActions'],
35
+ passthroughKeys: ['artifactBucket', 'assetPublishingCodeBuildDefaults', 'cdkAssetsCliVersion', 'cliVersion', 'codeBuildDefaults', 'codePipeline', 'crossRegionReplicationBuckets', 'dockerCredentials', 'pipelineName', 'pipelineType', 'role', 'selfMutationCodeBuildDefaults', 'synth', 'synthCodeBuildDefaults'],
36
+ },
37
+ };
38
+ const EMPTY_KEY_CONFIG = { booleanKeys: [], passthroughKeys: [] };
39
+ function getCustomKey(prefix, key) {
40
+ return `${pipeline_types_1.CDK_METADATA_PREFIX}${prefix}:${key}`.toLowerCase();
41
+ }
42
+ function isTrue(value) {
43
+ if (typeof value === 'boolean')
44
+ return value;
45
+ if (typeof value === 'string')
46
+ return value.toLowerCase() === 'true';
47
+ return false;
48
+ }
49
+ /** Extract CDK construct config from metadata for a given namespace. */
50
+ function buildConfigFromMetadata(metadata, namespace) {
51
+ const { booleanKeys, passthroughKeys } = NAMESPACE_KEY_MAP[namespace] ?? EMPTY_KEY_CONFIG;
52
+ const result = {};
53
+ for (const key of booleanKeys) {
54
+ const raw = metadata[getCustomKey(namespace, key)];
55
+ if (raw !== undefined)
56
+ result[key] = isTrue(raw);
57
+ }
58
+ for (const key of passthroughKeys) {
59
+ const raw = metadata[getCustomKey(namespace, key)];
60
+ if (raw !== undefined)
61
+ result[key] = raw;
62
+ }
63
+ return result;
64
+ }
65
+ /** Extract CodePipeline config from metadata. */
66
+ function metadataForCodePipeline(metadata) {
67
+ return buildConfigFromMetadata(metadata, NAMESPACE.CODE_PIPELINE);
68
+ }
69
+ /** Extract CodeBuildStep config from metadata. */
70
+ function metadataForCodeBuildStep(metadata) {
71
+ return buildConfigFromMetadata(metadata, NAMESPACE.CODE_BUILD_STEP);
72
+ }
73
+ /** Extract ShellStep config from metadata. */
74
+ function metadataForShellStep(metadata) {
75
+ return buildConfigFromMetadata(metadata, NAMESPACE.SHELL_STEP);
76
+ }
77
+ /** Extract BuildEnvironment config from metadata. */
78
+ function metadataForBuildEnvironment(metadata) {
79
+ return buildConfigFromMetadata(metadata, NAMESPACE.BUILD_ENVIRONMENT);
80
+ }
81
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWV0YWRhdGEtYnVpbGRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb3JlL21ldGFkYXRhLWJ1aWxkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7O0FBdUR0QywwREFvQkM7QUFHRCwwREFFQztBQUdELDREQUVDO0FBR0Qsb0RBRUM7QUFHRCxrRUFFQztBQTNGRCxxREFBdUQ7QUFHdkQ7O0dBRUc7QUFDSCxNQUFNLFNBQVMsR0FBRztJQUNoQixVQUFVLEVBQUUscUJBQXFCO0lBQ2pDLGVBQWUsRUFBRSx5QkFBeUI7SUFDMUMsaUJBQWlCLEVBQUUsNEJBQTRCO0lBQy9DLGFBQWEsRUFBRSx3QkFBd0I7Q0FDL0IsQ0FBQztBQVFYLE1BQU0saUJBQWlCLEdBQTBDO0lBQy9ELENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxFQUFFO1FBQ3RCLFdBQVcsRUFBRSxFQUFFO1FBQ2YsZUFBZSxFQUFFLENBQUMsa0JBQWtCLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsd0JBQXdCLENBQUM7S0FDcEk7SUFDRCxDQUFDLFNBQVMsQ0FBQyxlQUFlLENBQUMsRUFBRTtRQUMzQixXQUFXLEVBQUUsRUFBRTtRQUNmLGVBQWUsRUFBRSxDQUFDLFlBQVksRUFBRSxrQkFBa0IsRUFBRSxrQkFBa0IsRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxxQkFBcUIsRUFBRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsU0FBUyxFQUFFLGtCQUFrQixFQUFFLHdCQUF3QixFQUFFLGFBQWEsRUFBRSxNQUFNLEVBQUUsc0JBQXNCLEVBQUUsU0FBUyxDQUFDO0tBQy9SO0lBQ0QsQ0FBQyxTQUFTLENBQUMsaUJBQWlCLENBQUMsRUFBRTtRQUM3QixXQUFXLEVBQUUsQ0FBQyxZQUFZLENBQUM7UUFDM0IsZUFBZSxFQUFF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LFNBQVMsQ0FBQyxpQkFBaUIsQ0FBOEIsQ0FBQztBQUNyRyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB0eXBlIHsgQnVpbGRFbnZpcm9ubWVudCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1jb2RlYnVpbGQnO1xuaW1wb3J0IHR5cGUgeyBDb2RlQnVpbGRTdGVwUHJvcHMsIENvZGVQaXBlbGluZVByb3BzLCBTaGVsbFN0ZXBQcm9wcyB9IGZyb20gJ2F3cy1jZGstbGliL3BpcGVsaW5lcyc7XG5pbXBvcnQgeyBDREtfTUVUQURBVEFfUFJFRklYIH0gZnJvbSAnLi9waXBlbGluZS10eXBlcyc7XG5pbXBvcnQgdHlwZSB7IE1ldGFEYXRhVHlwZSB9IGZyb20gJy4vcGlwZWxpbmUtdHlwZXMnO1xuXG4vKipcbiAqIFR5cGUtc2FmZSBuYW1lc3BhY2UgY29uc3RhbnRzIGZvciBtZXRhZGF0YSBjb25maWd1cmF0aW9uLlxuICovXG5jb25zdCBOQU1FU1BBQ0UgPSB7XG4gIFNIRUxMX1NURVA6ICdwaXBlbGluZXM6c2hlbGxzdGVwJyxcbiAgQ09ERV9CVUlMRF9TVEVQOiAncGlwZWxpbmVzOmNvZGVidWlsZHN0ZXAnLFxuICBCVUlMRF9FTlZJUk9OTUVOVDogJ2NvZGVidWlsZDpidWlsZGVudmlyb25tZW50JyxcbiAgQ09ERV9QSVBFTElORTogJ3BpcGVsaW5lczpjb2RlcGlwZWxpbmUnLFxufSBhcyBjb25zdDtcbnR5cGUgTmFtZXNwYWNlID0gKHR5cGVvZiBOQU1FU1BBQ0UpW2tleW9mIHR5cGVvZiBOQU1FU1BBQ0VdO1xuXG5pbnRlcmZhY2UgTmFtZXNwYWNlS2V5Q29uZmlnIHtcbiAgYm9vbGVhbktleXM6IHJlYWRvbmx5IHN0cmluZ1tdO1xuICBwYXNzdGhyb3VnaEtleXM6IHJlYWRvbmx5IHN0cmluZ1tdO1xufVxuXG5jb25zdCBOQU1FU1BBQ0VfS0VZX01BUDogUmVjb3JkPE5hbWVzcGFjZSwgTmFtZXNwYWNlS2V5Q29uZmlnPiA9IHtcbiAgW05BTUVTUEFDRS5TSEVMTF9TVEVQXToge1xuICAgIGJvb2xlYW5LZXlzOiBbXSxcbiAgICBwYXNzdGhyb3VnaEtleXM6IFsnYWRkaXRpb25hbElucHV0cycsICdjb21tYW5kcycsICdlbnYnLCAnZW52RnJvbUNmbk91dHB1dHMnLCAnaW5wdXQnLCAnaW5zdGFsbENvbW1hbmRzJywgJ3ByaW1hcnlPdXRwdXREaXJlY3RvcnknXSxcbiAgfSxcbiAgW05BTUVTUEFDRS5DT0RFX0JVSUxEX1NURVBdOiB7XG4gICAgYm9vbGVhbktleXM6IFtdLFxuICAgIHBhc3N0aHJvdWdoS2V5czogWydhY3Rpb25Sb2xlJywgJ2FkZGl0aW9uYWxJbnB1dHMnLCAnYnVpbGRFbnZpcm9ubWVudCcsICdjYWNoZScsICdjb21tYW5kcycsICdlbnYnLCAnZW52RnJvbUNmbk91dHB1dHMnLCAnZmlsZVN5c3RlbUxvY2F0aW9ucycsICdpbnB1dCcsICdpbnN0YWxsQ29tbWFuZHMnLCAnbG9nZ2luZycsICdwYXJ0aWFsQnVpbGRTcGVjJywgJ3ByaW1hcnlPdXRwdXREaXJlY3RvcnknLCAncHJvamVjdE5hbWUnLCAncm9sZScsICdyb2xlUG9saWN5U3RhdGVtZW50cycsICd0aW1lb3V0J10sXG4gIH0sXG4gIFtOQU1FU1BBQ0UuQlVJTERfRU5WSVJPTk1FTlRdOiB7XG4gICAgYm9vbGVhbktleXM6IFsncHJpdmlsZWdlZCddLFxuICAgIHBhc3N0aHJvdWdoS2V5czogWydidWlsZEltYWdlJywgJ2NlcnRpZmljYXRlJywgJ2NvbXB1dGVUeXBlJywgJ2RvY2tlclNlcnZlcicsICdlbnZpcm9ubWVudFZhcmlhYmxlcycsICdmbGVldCddLFxuICB9LFxuICBbTkFNRVNQQUNFLkNPREVfUElQRUxJTkVdOiB7XG4gICAgYm9vbGVhbktleXM6IFsnY3Jvc3NBY2NvdW50S2V5cycsICdkb2NrZXJFbmFibGVkRm9yU2VsZk11dGF0aW9uJywgJ2RvY2tlckVuYWJsZWRGb3JTeW50aCcsICdlbmFibGVLZXlSb3RhdGlvbicsICdwdWJsaXNoQXNzZXRzSW5QYXJhbGxlbCcsICdyZXVzZUNyb3NzUmVnaW9uU3VwcG9ydFN0YWNrcycsICdzZWxmTXV0YXRpb24nLCAndXNlQ2hhbmdlU2V0cycsICd1c2VQaXBlbGluZVJvbGVGb3JBY3Rpb25zJ10sXG4gICAgcGFzc3Rocm91Z2hLZXlzOiBbJ2FydGlmYWN0QnVja2V0JywgJ2Fzc2V0UHVibGlzaGluZ0NvZGVCdWlsZERlZmF1bHRzJywgJ2Nka0Fzc2V0c0NsaVZlcnNpb24nLCAnY2xpVmVyc2lvbicsICdjb2RlQnVpbGREZWZhdWx0cycsICdjb2RlUGlwZWxpbmUnLCAnY3Jvc3NSZWdpb25SZXBsaWNhdGlvbkJ1Y2tldHMnLCAnZG9ja2VyQ3JlZGVudGlhbHMnLCAncGlwZWxpbmVOYW1lJywgJ3BpcGVsaW5lVHlwZScsICdyb2xlJywgJ3NlbGZNdXRhdGlvbkNvZGVCdWlsZERlZmF1bHRzJywgJ3N5bnRoJywgJ3N5bnRoQ29kZUJ1aWxkRGVmYXVsdHMnXSxcbiAgfSxcbn07XG5cbmNvbnN0IEVNUFRZX0tFWV9DT05GSUc6IE5hbWVzcGFjZUtleUNvbmZpZyA9IHsgYm9vbGVhbktleXM6IFtdLCBwYXNzdGhyb3VnaEtleXM6IFtdIH07XG5cbmZ1bmN0aW9uIGdldEN1c3RvbUtleShwcmVmaXg6IHN0cmluZywga2V5OiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gYCR7Q0RLX01FVEFEQVRBX1BSRUZJWH0ke3ByZWZpeH06JHtrZXl9YC50b0xvd2VyQ2FzZSgpO1xufVxuXG5mdW5jdGlvbiBpc1RydWUodmFsdWU6IHVua25vd24pOiBib29sZWFuIHtcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nKSByZXR1cm4gdmFsdWU7XG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSByZXR1cm4gdmFsdWUudG9Mb3dlckNhc2UoKSA9PT0gJ3RydWUnO1xuICByZXR1cm4gZmFsc2U7XG59XG5cbi8qKiBFeHRyYWN0IENESyBjb25zdHJ1Y3QgY29uZmlnIGZyb20gbWV0YWRhdGEgZm9yIGEgZ2l2ZW4gbmFtZXNwYWNlLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkQ29uZmlnRnJvbU1ldGFkYXRhKFxuICBtZXRhZGF0YTogTWV0YURhdGFUeXBlLFxuICBuYW1lc3BhY2U6IHN0cmluZyxcbik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgY29uc3QgeyBib29sZWFuS2V5cywgcGFzc3Rocm91Z2hLZXlzIH0gPVxuICAgIE5BTUVTUEFDRV9LRVlfTUFQW25hbWVzcGFjZSBhcyBOYW1lc3BhY2VdID8/IEVNUFRZX0tFWV9DT05GSUc7XG5cbiAgY29uc3QgcmVzdWx0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuXG4gIGZvciAoY29uc3Qga2V5IG9mIGJvb2xlYW5LZXlzKSB7XG4gICAgY29uc3QgcmF3ID0gbWV0YWRhdGFbZ2V0Q3VzdG9tS2V5KG5hbWVzcGFjZSwga2V5KV07XG4gICAgaWYgKHJhdyAhPT0gdW5kZWZpbmVkKSByZXN1bHRba2V5XSA9IGlzVHJ1ZShyYXcpO1xuICB9XG5cbiAgZm9yIChjb25zdCBrZXkgb2YgcGFzc3Rocm91Z2hLZXlzKSB7XG4gICAgY29uc3QgcmF3ID0gbWV0YWRhdGFbZ2V0Q3VzdG9tS2V5KG5hbWVzcGFjZSwga2V5KV07XG4gICAgaWYgKHJhdyAhPT0gdW5kZWZpbmVkKSByZXN1bHRba2V5XSA9IHJhdztcbiAgfVxuXG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKiBFeHRyYWN0IENvZGVQaXBlbGluZSBjb25maWcgZnJvbSBtZXRhZGF0YS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZXRhZGF0YUZvckNvZGVQaXBlbGluZShtZXRhZGF0YTogTWV0YURhdGFUeXBlKTogUGFydGlhbDxDb2RlUGlwZWxpbmVQcm9wcz4ge1xuICByZXR1cm4gYnVpbGRDb25maWdGcm9tTWV0YWRhdGEobWV0YWRhdGEsIE5BTUVTUEFDRS5DT0RFX1BJUEVMSU5FKSBhcyBQYXJ0aWFsPENvZGVQaXBlbGluZVByb3BzPjtcbn1cblxuLyoqIEV4dHJhY3QgQ29kZUJ1aWxkU3RlcCBjb25maWcgZnJvbSBtZXRhZGF0YS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZXRhZGF0YUZvckNvZGVCdWlsZFN0ZXAobWV0YWRhdGE6IE1ldGFEYXRhVHlwZSk6IFBhcnRpYWw8Q29kZUJ1aWxkU3RlcFByb3BzPiB7XG4gIHJldHVybiBidWlsZENvbmZpZ0Zyb21NZXRhZGF0YShtZXRhZGF0YSwgTkFNRVNQQUNFLkNPREVfQlVJTERfU1RFUCkgYXMgUGFydGlhbDxDb2RlQnVpbGRTdGVwUHJvcHM+O1xufVxuXG4vKiogRXh0cmFjdCBTaGVsbFN0ZXAgY29uZmlnIGZyb20gbWV0YWRhdGEuICovXG5leHBvcnQgZnVuY3Rpb24gbWV0YWRhdGFGb3JTaGVsbFN0ZXAobWV0YWRhdGE6IE1ldGFEYXRhVHlwZSk6IFBhcnRpYWw8U2hlbGxTdGVwUHJvcHM+IHtcbiAgcmV0dXJuIGJ1aWxkQ29uZmlnRnJvbU1ldGFkYXRhKG1ldGFkYXRhLCBOQU1FU1BBQ0UuU0hFTExfU1RFUCkgYXMgUGFydGlhbDxTaGVsbFN0ZXBQcm9wcz47XG59XG5cbi8qKiBFeHRyYWN0IEJ1aWxkRW52aXJvbm1lbnQgY29uZmlnIGZyb20gbWV0YWRhdGEuICovXG5leHBvcnQgZnVuY3Rpb24gbWV0YWRhdGFGb3JCdWlsZEVudmlyb25tZW50KG1ldGFkYXRhOiBNZXRhRGF0YVR5cGUpOiBQYXJ0aWFsPEJ1aWxkRW52aXJvbm1lbnQ+IHtcbiAgcmV0dXJuIGJ1aWxkQ29uZmlnRnJvbU1ldGFkYXRhKG1ldGFkYXRhLCBOQU1FU1BBQ0UuQlVJTERfRU5WSVJPTk1FTlQpIGFzIFBhcnRpYWw8QnVpbGRFbnZpcm9ubWVudD47XG59XG4iXX0=