@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,346 @@
1
+ import type { QuotaTier, QuotaTierLimits } from '@pipeline-builder/api-core';
2
+ import type { Algorithm } from 'jsonwebtoken';
3
+ /**
4
+ * Type-safe configuration interface
5
+ */
6
+ export interface AppConfig {
7
+ readonly server: ServerConfig;
8
+ readonly auth: AuthConfig;
9
+ readonly database: DatabaseConfig;
10
+ readonly registry: RegistryConfig;
11
+ readonly redis: RedisConfig;
12
+ readonly pluginBuild: PluginBuildConfig;
13
+ readonly dockerConfig: BuildConfig;
14
+ readonly observability: ObservabilityConfig;
15
+ readonly compliance: ComplianceConfig;
16
+ readonly aws: AWSConfig;
17
+ readonly rateLimit: RateLimitConfig;
18
+ readonly billing: BillingConfig;
19
+ }
20
+ /** Express server configuration. */
21
+ export interface ServerConfig {
22
+ /** HTTP listen port (env: `PORT`). */
23
+ readonly port: number;
24
+ readonly cors: {
25
+ /** Whether to include credentials in CORS responses (env: `CORS_CREDENTIALS`). */
26
+ readonly credentials: boolean;
27
+ /** Allowed origin(s) — single string, array, or `'*'` (env: `CORS_ORIGIN`). */
28
+ readonly origin: string | string[];
29
+ };
30
+ /** Number of reverse proxy hops to trust (env: `TRUST_PROXY`). */
31
+ readonly trustProxy: number;
32
+ /** Frontend base URL, used as CORS fallback (env: `PLATFORM_BASE_URL`). */
33
+ readonly platformUrl: string;
34
+ readonly httpClient: {
35
+ /** Default HTTP request timeout in ms (env: `HTTP_CLIENT_TIMEOUT`). */
36
+ readonly timeout: number;
37
+ /** Maximum retry attempts for failed requests (env: `HTTP_CLIENT_MAX_RETRIES`). */
38
+ readonly maxRetries: number;
39
+ /** Base delay between retries in ms (env: `HTTP_CLIENT_RETRY_DELAY_MS`). */
40
+ readonly retryDelayMs: number;
41
+ };
42
+ readonly sse: {
43
+ /** Max SSE clients per request (env: `SSE_MAX_CLIENTS_PER_REQUEST`). */
44
+ readonly maxClientsPerRequest: number;
45
+ /** SSE client timeout in ms (env: `SSE_CLIENT_TIMEOUT_MS`). */
46
+ readonly clientTimeoutMs: number;
47
+ /** SSE cleanup interval in ms (env: `SSE_CLEANUP_INTERVAL_MS`). */
48
+ readonly cleanupIntervalMs: number;
49
+ };
50
+ readonly services: {
51
+ readonly pluginHost: string;
52
+ readonly pluginPort: number;
53
+ readonly pipelineHost: string;
54
+ readonly pipelinePort: number;
55
+ readonly messageHost: string;
56
+ readonly messagePort: number;
57
+ readonly platformHost: string;
58
+ readonly platformPort: number;
59
+ readonly complianceHost: string;
60
+ readonly compliancePort: number;
61
+ readonly billingHost: string;
62
+ readonly billingPort: number;
63
+ readonly billingTimeout: number;
64
+ };
65
+ }
66
+ /** JWT and refresh token authentication configuration. */
67
+ export interface AuthConfig {
68
+ readonly jwt: {
69
+ /** Signing secret for access tokens (env: `JWT_SECRET`). */
70
+ readonly secret: string;
71
+ /** Token lifetime in seconds (env: `JWT_EXPIRES_IN`). */
72
+ readonly expiresIn: number;
73
+ /** Signing algorithm, e.g. `'HS256'` (env: `JWT_ALGORITHM`). */
74
+ readonly algorithm: Algorithm;
75
+ /** bcrypt salt rounds for password hashing (env: `BCRYPT_SALT_ROUNDS`). */
76
+ readonly saltRounds: number;
77
+ };
78
+ readonly refreshToken: {
79
+ /** Signing secret for refresh tokens (env: `REFRESH_TOKEN_SECRET`). */
80
+ readonly secret: string;
81
+ /** Token lifetime in seconds (env: `REFRESH_TOKEN_EXPIRES_IN`). */
82
+ readonly expiresIn: number;
83
+ };
84
+ }
85
+ /** PostgreSQL and Drizzle ORM database configuration. */
86
+ export interface DatabaseConfig {
87
+ readonly postgres: {
88
+ /** PostgreSQL host (env: `DB_HOST`). */
89
+ readonly host: string;
90
+ /** PostgreSQL port (env: `DB_PORT`). */
91
+ readonly port: number;
92
+ /** Database name (env: `DATABASE`). */
93
+ readonly database: string;
94
+ /** Database user (env: `DB_USER`). */
95
+ readonly user: string;
96
+ /** Database password (env: `DB_PASSWORD`). */
97
+ readonly password: string;
98
+ };
99
+ readonly drizzle: {
100
+ /** Maximum connection pool size (env: `DRIZZLE_MAX_POOL_SIZE`). */
101
+ readonly maxPoolSize: number;
102
+ /** Idle connection timeout in ms (env: `DRIZZLE_IDLE_TIMEOUT_MILLIS`). */
103
+ readonly idleTimeoutMillis: number;
104
+ /** New connection timeout in ms (env: `DRIZZLE_CONNECTION_TIMEOUT_MILLIS`). */
105
+ readonly connectionTimeoutMillis: number;
106
+ };
107
+ }
108
+ export interface RegistryConfig {
109
+ readonly host: string;
110
+ readonly port: number;
111
+ /**
112
+ * Host/port an OUT-OF-CLUSTER client (notably AWS CodeBuild) uses to pull
113
+ * plugin images, when it differs from the in-cluster `host`/`port`. The
114
+ * in-cluster `registry:5000` ClusterIP isn't resolvable from the VPC, so the
115
+ * synthesized CodeBuild image URI must point at the public gateway instead.
116
+ * Env: `IMAGE_REGISTRY_PULL_HOST` / `IMAGE_REGISTRY_PULL_PORT`. Optional;
117
+ * consumers fall back to `host`/`port` when unset (single-host /
118
+ * in-cluster-only deploys). `loadRegistryConfig` always populates them.
119
+ */
120
+ readonly pullHost?: string;
121
+ readonly pullPort?: number;
122
+ /** Docker network for build/push (empty string = default). */
123
+ readonly network: string;
124
+ /**
125
+ * BuildKit talks to the registry over plain HTTP when true; HTTPS with the
126
+ * system CA bundle otherwise. Env: `IMAGE_REGISTRY_HTTP` (defaults true —
127
+ * the in-cluster registry has no TLS).
128
+ */
129
+ readonly http: boolean;
130
+ }
131
+ export interface RedisConfig {
132
+ readonly host: string;
133
+ readonly port: number;
134
+ }
135
+ export interface PluginBuildConfig {
136
+ readonly concurrency: number;
137
+ readonly maxAttempts: number;
138
+ readonly backoffDelayMs: number;
139
+ readonly workerTimeoutMs: number;
140
+ readonly tempDirMaxAgeMs: number;
141
+ readonly dlqMaxAttempts: number;
142
+ readonly dlqBackoffBaseMs: number;
143
+ readonly dlqMaxSize: number;
144
+ }
145
+ export interface BuildConfig {
146
+ /** Root directory for build temp files. */
147
+ readonly tempRoot: string;
148
+ /** Build timeout in milliseconds. */
149
+ readonly timeoutMs: number;
150
+ /** Push timeout in milliseconds. */
151
+ readonly pushTimeoutMs: number;
152
+ /**
153
+ * Path to the buildkitd socket the plugin's `buildctl` connects to. In k8s
154
+ * and compose this is a shared emptyDir/tmpfs volume mounted from the
155
+ * buildkitd sidecar.
156
+ */
157
+ readonly buildkitAddr: string;
158
+ }
159
+ export interface ObservabilityConfig {
160
+ readonly logLevel: string;
161
+ readonly logFormat: string;
162
+ readonly serviceName: string;
163
+ readonly tracing: {
164
+ readonly enabled: boolean;
165
+ readonly endpoint: string;
166
+ };
167
+ }
168
+ export interface ComplianceConfig {
169
+ readonly scanSchedulerIntervalMs: number;
170
+ /** When false, the scheduler skips scans/schedules for the system org. Default: false. */
171
+ readonly systemOrgScansEnabled: boolean;
172
+ /** Cross-pod leader-lock TTL for the scan scheduler (ms). Default: 300000. */
173
+ readonly scanLockTtlMs: number;
174
+ /** How often the digest scheduler checks for due digests (ms). Default: 3600000. */
175
+ readonly digestSchedulerIntervalMs: number;
176
+ /** Cross-pod leader-lock TTL for the digest scheduler (ms). Default: 300000. */
177
+ readonly digestLockTtlMs: number;
178
+ }
179
+ /**
180
+ * AWS infrastructure configuration.
181
+ *
182
+ * Deliberately expressed in PLAIN DATA (numbers, strings, string unions) rather
183
+ * than CDK value objects (`Duration`, `Runtime`, `RetentionDays`, ...). Config is
184
+ * loaded by every service, but only the CDK entry point (`@pipeline-builder/
185
+ * pipeline-core/cdk`) builds stacks typing this block with CDK classes put
186
+ * `aws-cdk-lib` on the import graph of `Config`, and therefore of every API
187
+ * service that reads so much as a port number. Conversion to CDK objects happens
188
+ * at the construct boundary in `config/aws-config-cdk.ts`.
189
+ */
190
+ export interface AWSConfig {
191
+ readonly lambda: {
192
+ /** Lambda runtime identifier, e.g. `'nodejs24.x'` (env: `LAMBDA_RUNTIME`). */
193
+ readonly runtime: string;
194
+ /** Function timeout in seconds (env: `LAMBDA_TIMEOUT`). */
195
+ readonly timeoutSeconds: number;
196
+ readonly memorySize: number;
197
+ readonly architecture: 'arm64' | 'x86_64';
198
+ readonly reservedConcurrentExecutions?: number;
199
+ };
200
+ readonly logging: {
201
+ readonly groupName: string;
202
+ /** CloudWatch retention in days; `0` means never expire (env: `LOG_RETENTION`). */
203
+ readonly retentionDays: number;
204
+ readonly removalPolicy: 'retain' | 'destroy';
205
+ };
206
+ readonly codeBuild: {
207
+ /** CodeBuild compute type name, e.g. `'SMALL'` (env: `CODEBUILD_COMPUTE_TYPE`). */
208
+ readonly computeType: string;
209
+ /**
210
+ * Image used for CodeBuild steps that don't have a plugin-baked image
211
+ * (cold-start synth bootstrap, ShellSteps with no registry, and
212
+ * `metadata_only` plugins). env: `CODEBUILD_DEFAULT_IMAGE`. Default
213
+ * `pipeline-bootstrap:1.0` — the local tag built by
214
+ * `deploy/codebuild/bootstrap/Dockerfile`, with `pipeline-manager`
215
+ * baked in.
216
+ *
217
+ * Contract: the image MUST have `pipeline-manager` on PATH. The
218
+ * bootstrap synth path no longer self-heals via `npm install -g`;
219
+ * pointing this at an image without the tool gets exit 127 on the
220
+ * first cold-start build.
221
+ *
222
+ * Resolution:
223
+ * - Bare tag (no `/`) → auto-prefixed to
224
+ * `<registry-host>:<port>/library/<tag>` using the registry config,
225
+ * with the per-org platform Secret as Basic auth (same flow as
226
+ * plugin images).
227
+ * - Fully-qualified registry URI (contains `/`) → used as-is, no
228
+ * auth wired (operator owns making it pullable).
229
+ * - When the registry isn't configured or per-org auth isn't
230
+ * available at the call site, falls back to
231
+ * `aws/codebuild/standard:8.0` with a warning — cold-start synth
232
+ * will then fail on `pipeline-manager: not found`, surfacing the
233
+ * misconfiguration loudly instead of silently swapping images.
234
+ */
235
+ readonly defaultImage: string;
236
+ };
237
+ }
238
+ /** Express rate limiting configuration. */
239
+ export interface RateLimitConfig {
240
+ /** Maximum requests per window (env: `LIMITER_MAX`). */
241
+ readonly max: number;
242
+ /** Rate limit window in milliseconds (env: `LIMITER_WINDOWMS`). */
243
+ readonly windowMs: number;
244
+ /** Include legacy `X-RateLimit-*` headers. */
245
+ readonly legacyHeaders: boolean;
246
+ /** Include standard `RateLimit-*` headers (RFC 6585). */
247
+ readonly standardHeaders: boolean;
248
+ }
249
+ /** Price configuration for a single billing plan (in cents). */
250
+ export interface BillingPlanPrices {
251
+ readonly monthly: number;
252
+ readonly annual: number;
253
+ }
254
+ /** Full billing plan definition used for seeding and runtime configuration. */
255
+ export interface BillingPlanConfig {
256
+ readonly id: string;
257
+ readonly name: string;
258
+ readonly description: string;
259
+ readonly tier: QuotaTier;
260
+ readonly prices: BillingPlanPrices;
261
+ readonly features: readonly string[];
262
+ readonly isActive: boolean;
263
+ readonly isDefault: boolean;
264
+ readonly sortOrder: number;
265
+ }
266
+ /**
267
+ * A purchasable add-on bundle: a quantity-stackable pack that ADDS to the
268
+ * account's base (tier) limits and adds a recurring line item. See
269
+ * docs/billing-bundles.md.
270
+ */
271
+ export interface BundleConfig {
272
+ readonly id: string;
273
+ readonly name: string;
274
+ readonly description: string;
275
+ /** Per-unit deltas on `QuotaTierLimits` fields, e.g. `{ seats: 5 }`. Keys are
276
+ * constrained to real quota fields so a typo is a compile error (was
277
+ * `Record<string, number>`, where a misspelled key was silently unenforceable). */
278
+ readonly grants: Readonly<Partial<Record<keyof QuotaTierLimits, number>>>;
279
+ /** Feature flags granted by a feature bundle (e.g. `audit_log`). */
280
+ readonly features?: readonly string[];
281
+ /** Per-unit price (cents). Stripe multiplies by quantity. */
282
+ readonly prices: BillingPlanPrices;
283
+ /** True for stackable resource packs; false for a boolean feature bundle. */
284
+ readonly stackable: boolean;
285
+ /**
286
+ * Maximum purchasable quantity for a stackable pack. Enforced by the addon
287
+ * purchase/preview route (`quantity ≤ maxQuantity`, reject over-cap). Used to
288
+ * keep retention packs under the 730-day retention ceiling (e.g. the Standard
289
+ * Retention Pack caps at 7 so 30 + 7×90 = 660 ≤ 730). Absent ⇒ unbounded.
290
+ */
291
+ readonly maxQuantity?: number;
292
+ /**
293
+ * Optional per-unit volume discount tiers for a stackable pack: at ≥ `minQuantity`
294
+ * purchased units, `discountPercent` comes off the line subtotal (unit × quantity).
295
+ * The highest matching tier wins. Realized as a recurring usage credit (like a
296
+ * combo), so the provider still charges unit×qty and the credit offsets the
297
+ * balance. Env-overridable via `BILLING_BUNDLE_<ID>_VOLUME_TIERS` (JSON). Used by
298
+ * the per-seat `seat` bundle. Absent ⇒ no volume discount.
299
+ */
300
+ readonly volumeTiers?: readonly {
301
+ readonly minQuantity: number;
302
+ readonly discountPercent: number;
303
+ }[];
304
+ /** Base tiers this bundle is offered to. */
305
+ readonly availableForTiers: readonly QuotaTier[];
306
+ /**
307
+ * Prerequisite bundle ids that must be held (or purchased in the same action)
308
+ * before this bundle can be added. Enforced by the addon purchase/preview route
309
+ * (reject with 400 when unmet); a combo that includes the prerequisite satisfies
310
+ * it. Used by `compliance_advanced` (`requires: ['compliance_standard']`).
311
+ * Absent ⇒ no prerequisite.
312
+ */
313
+ readonly requires?: readonly string[];
314
+ readonly isActive: boolean;
315
+ readonly sortOrder: number;
316
+ }
317
+ /**
318
+ * A combo discount: when an account holds EVERY bundle in `bundleIds`, the pair
319
+ * is billed at `prices` (the combined price) instead of the sum of the members'
320
+ * individual prices. Realized as a recurring usage credit for the difference —
321
+ * never a provider coupon — consistent with the usage-credit discount model. See
322
+ * docs/billing-bundles.md §Combo pricing.
323
+ */
324
+ export interface ComboDiscountConfig {
325
+ readonly id: string;
326
+ readonly name: string;
327
+ /** The member bundle ids that must ALL be present for the combo to apply. */
328
+ readonly bundleIds: readonly string[];
329
+ /** Per-member minimum quantity (bundleId → count; absent ⇒ 1). Lets a stackable
330
+ * capacity pack anchor a combo — e.g. `{ seat: 5 }` = "≥ 5 seats". The credit
331
+ * basis uses this minimum, so extra units never inflate the discount. */
332
+ readonly minQuantities?: Readonly<Record<string, number>>;
333
+ /** The combined price for the minimum set (cents). The credit is
334
+ * `Σ member unit price × minQty − prices`, clamped ≥ 0. */
335
+ readonly prices: BillingPlanPrices;
336
+ /** Deterministic tie-break among equal-total optimal packings when combos overlap
337
+ * (lower wins). */
338
+ readonly sortOrder: number;
339
+ readonly isActive: boolean;
340
+ }
341
+ /** Billing plans + add-on bundle configuration. */
342
+ export interface BillingConfig {
343
+ readonly plans: readonly BillingPlanConfig[];
344
+ readonly bundles: readonly BundleConfig[];
345
+ readonly comboDiscounts: readonly ComboDiscountConfig[];
346
+ }
@@ -0,0 +1,4 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ export {};
4
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLXR5cGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbmZpZy9jb25maWctdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgdHlwZSB7IFF1b3RhVGllciwgUXVvdGFUaWVyTGltaXRzIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHR5cGUgeyBBbGdvcml0aG0gfSBmcm9tICdqc29ud2VidG9rZW4nO1xuXG4vKipcbiAqIFR5cGUtc2FmZSBjb25maWd1cmF0aW9uIGludGVyZmFjZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIEFwcENvbmZpZyB7XG4gIHJlYWRvbmx5IHNlcnZlcjogU2VydmVyQ29uZmlnO1xuICByZWFkb25seSBhdXRoOiBBdXRoQ29uZmlnO1xuICByZWFkb25seSBkYXRhYmFzZTogRGF0YWJhc2VDb25maWc7XG4gIHJlYWRvbmx5IHJlZ2lzdHJ5OiBSZWdpc3RyeUNvbmZpZztcbiAgcmVhZG9ubHkgcmVkaXM6IFJlZGlzQ29uZmlnO1xuICByZWFkb25seSBwbHVnaW5CdWlsZDogUGx1Z2luQnVpbGRDb25maWc7XG4gIHJlYWRvbmx5IGRvY2tlckNvbmZpZzogQnVpbGRDb25maWc7XG4gIHJlYWRvbmx5IG9ic2VydmFiaWxpdHk6IE9ic2VydmFiaWxpdHlDb25maWc7XG4gIHJlYWRvbmx5IGNvbXBsaWFuY2U6IENvbXBsaWFuY2VDb25maWc7XG4gIHJlYWRvbmx5IGF3czogQVdTQ29uZmlnO1xuICByZWFkb25seSByYXRlTGltaXQ6IFJhdGVMaW1pdENvbmZpZztcbiAgcmVhZG9ubHkgYmlsbGluZzogQmlsbGluZ0NvbmZpZztcbn1cblxuLyoqIEV4cHJlc3Mgc2VydmVyIGNvbmZpZ3VyYXRpb24uICovXG5leHBvcnQgaW50ZXJmYWNlIFNlcnZlckNvbmZpZyB7XG4gIC8qKiBIVFRQIGxpc3RlbiBwb3J0IChlbnY6IGBQT1JUYCkuICovXG4gIHJlYWRvbmx5IHBvcnQ6IG51bWJlcjtcbiAgcmVhZG9ubHkgY29yczoge1xuICAgIC8qKiBXaGV0aGVyIHRvIGluY2x1ZGUgY3JlZGVudGlhbHMgaW4gQ09SUyByZXNwb25zZXMgKGVudjogYENPUlNfQ1JFREVOVElBTFNgKS4gKi9cbiAgICByZWFkb25seSBjcmVkZW50aWFsczogYm9vbGVhbjtcbiAgICAvKiogQWxsb3dlZCBvcmlnaW4ocykg4oCUIHNpbmdsZSBzdHJpbmcsIGFycmF5LCBvciBgJyonYCAoZW52OiBgQ09SU19PUklHSU5gKS4gKi9cbiAgICByZWFkb25seSBvcmlnaW46IHN0cmluZyB8IHN0cmluZ1tdO1xuICB9O1xuICAvKiogTnVtYmVyIG9mIHJldmVyc2UgcHJveHkgaG9wcyB0byB0cnVzdCAoZW52OiBgVFJVU1RfUFJPWFlgKS4gKi9cbiAgcmVhZG9ubHkgdHJ1c3RQcm94eTogbnVtYmVyO1xuICAvKiogRnJvbnRlbmQgYmFzZSBVUkwsIHVzZWQgYXMgQ09SUyBmYWxsYmFjayAoZW52OiBgUExBVEZPUk1fQkFTRV9VUkxgKS4gKi9cbiAgcmVhZG9ubHkgcGxhdGZvcm1Vcmw6IHN0cmluZztcbiAgcmVhZG9ubHkgaHR0cENsaWVudDoge1xuICAgIC8qKiBEZWZhdWx0IEhUVFAgcmVxdWVzdCB0aW1lb3V0IGluIG1zIChlbnY6IGBIVFRQX0NMSUVOVF9USU1FT1VUYCkuICovXG4gICAgcmVhZG9ubHkgdGltZW91dDogbnVtYmVyO1xuICAgIC8qKiBNYXhpbXVtIHJldHJ5IGF0dGVtcHRzIGZvciBmYWlsZWQgcmVxdWVzdHMgKGVudjogYEhUVFBfQ0xJRU5UX01BWF9SRVRSSUVTYCkuICovXG4gICAgcmVhZG9ubHkgbWF4UmV0cmllczogbnVtYmVyO1xuICAgIC8qKiBCYXNlIGRlbGF5IGJldHdlZW4gcmV0cmllcyBpbiBtcyAoZW52OiBgSFRUUF9DTElFTlRfUkVUUllfREVMQVlfTVNgKS4gKi9cbiAgICByZWFkb25seSByZXRyeURlbGF5TXM6IG51bWJlcjtcbiAgfTtcbiAgcmVhZG9ubHkgc3NlOiB7XG4gICAgLyoqIE1heCBTU0UgY2xpZW50cyBwZXIgcmVxdWVzdCAoZW52OiBgU1NFX01BWF9DTElFTlRTX1BFUl9SRVFVRVNUYCkuICovXG4gICAgcmVhZG9ubHkgbWF4Q2xpZW50c1BlclJlcXVlc3Q6IG51bWJlcjtcbiAgICAvKiogU1NFIGNsaWVudCB0aW1lb3V0IGluIG1zIChlbnY6IGBTU0VfQ0xJRU5UX1RJTUVPVVRfTVNgKS4gKi9cbiAgICByZWFkb25seSBjbGllbnRUaW1lb3V0TXM6IG51bWJlcjtcbiAgICAvKiogU1NFIGNsZWFudXAgaW50ZXJ2YWwgaW4gbXMgKGVudjogYFNTRV9DTEVBTlVQX0lOVEVSVkFMX01TYCkuICovXG4gICAgcmVhZG9ubHkgY2xlYW51cEludGVydmFsTXM6IG51bWJlcjtcbiAgfTtcbiAgcmVhZG9ubHkgc2VydmljZXM6IHtcbiAgICByZWFkb25seSBwbHVnaW5Ib3N0OiBzdHJpbmc7XG4gICAgcmVhZG9ubHkgcGx1Z2luUG9ydDogbnVtYmVyO1xuICAgIHJlYWRvbmx5IHBpcGVsaW5lSG9zdDogc3RyaW5nO1xuICAgIHJlYWRvbmx5IHBpcGVsaW5lUG9ydDogbnVtYmVyO1xuICAgIHJlYWRvbmx5IG1lc3NhZ2VIb3N0OiBzdHJpbmc7XG4gICAgcmVhZG9ubHkgbWVzc2FnZVBvcnQ6IG51bWJlcjtcbiAgICByZWFkb25seSBwbGF0Zm9ybUhvc3Q6IHN0cmluZztcbiAgICByZWFkb25seSBwbGF0Zm9ybVBvcnQ6IG51bWJlcjtcbiAgICByZWFkb25seSBjb21wbGlhbmNlSG9zdDogc3RyaW5nO1xuICAgIHJlYWRvbmx5IGNvbXBsaWFuY2VQb3J0OiBudW1iZXI7XG4gICAgcmVhZG9ubHkgYmlsbGluZ0hvc3Q6IHN0cmluZztcbiAgICByZWFkb25seSBiaWxsaW5nUG9ydDogbnVtYmVyO1xuICAgIHJlYWRvbmx5IGJpbGxpbmdUaW1lb3V0OiBudW1iZXI7XG4gIH07XG59XG5cbi8qKiBKV1QgYW5kIHJlZnJlc2ggdG9rZW4gYXV0aGVudGljYXRpb24gY29uZmlndXJhdGlvbi4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXV0aENvbmZpZyB7XG4gIHJlYWRvbmx5IGp3dDoge1xuICAgIC8qKiBTaWduaW5nIHNlY3JldCBmb3IgYWNjZXNzIHRva2VucyAoZW52OiBgSldUX1NFQ1JFVGApLiAqL1xuICAgIHJlYWRvbmx5IHNlY3JldDogc3RyaW5nO1xuICAgIC8qKiBUb2tlbiBsaWZldGltZSBpbiBzZWNvbmRzIChlbnY6IGBKV1RfRVhQSVJFU19JTmApLiAqL1xuICAgIHJlYWRvbmx5IGV4cGlyZXNJbjogbnVtYmVyO1xuICAgIC8qKiBTaWduaW5nIGFsZ29yaXRobSwgZS5nLiBgJ0hTMjU2J2AgKGVudjogYEpXVF9BTEdPUklUSE1gKS4gKi9cbiAgICByZWFkb25seSBhbGdvcml0aG06IEFsZ29yaXRobTtcbiAgICAvKiogYmNyeXB0IHNhbHQgcm91bmRzIGZvciBwYXNzd29yZCBoYXNoaW5nIChlbnY6IGBCQ1JZUFRfU0FMVF9ST1VORFNgKS4gKi9cbiAgICByZWFkb25seSBzYWx0Um91bmRzOiBudW1iZXI7XG4gIH07XG4gIHJlYWRvbmx5IHJlZnJlc2hUb2tlbjoge1xuICAgIC8qKiBTaWduaW5nIHNlY3JldCBmb3IgcmVmcmVzaCB0b2tlbnMgKGVudjogYFJFRlJFU0hfVE9LRU5fU0VDUkVUYCkuICovXG4gICAgcmVhZG9ubHkgc2VjcmV0OiBzdHJpbmc7XG4gICAgLyoqIFRva2VuIGxpZmV0aW1lIGluIHNlY29uZHMgKGVudjogYFJFRlJFU0hfVE9LRU5fRVhQSVJFU19JTmApLiAqL1xuICAgIHJlYWRvbmx5IGV4cGlyZXNJbjogbnVtYmVyO1xuICB9O1xufVxuXG4vKiogUG9zdGdyZVNRTCBhbmQgRHJpenpsZSBPUk0gZGF0YWJhc2UgY29uZmlndXJhdGlvbi4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRGF0YWJhc2VDb25maWcge1xuICByZWFkb25seSBwb3N0Z3Jlczoge1xuICAgIC8qKiBQb3N0Z3JlU1FMIGhvc3QgKGVudjogYERCX0hPU1RgKS4gKi9cbiAgICByZWFkb25seSBob3N0OiBzdHJpbmc7XG4gICAgLyoqIFBvc3RncmVTUUwgcG9ydCAoZW52OiBgREJfUE9SVGApLiAqL1xuICAgIHJlYWRvbmx5IHBvcnQ6IG51bWJlcjtcbiAgICAvKiogRGF0YWJhc2UgbmFtZSAoZW52OiBgREFUQUJBU0VgKS4gKi9cbiAgICByZWFkb25seSBkYXRhYmFzZTogc3RyaW5nO1xuICAgIC8qKiBEYXRhYmFzZSB1c2VyIChlbnY6IGBEQl9VU0VSYCkuICovXG4gICAgcmVhZG9ubHkgdXNlcjogc3RyaW5nO1xuICAgIC8qKiBEYXRhYmFzZSBwYXNzd29yZCAoZW52OiBgREJfUEFTU1dPUkRgKS4gKi9cbiAgICByZWFkb25seSBwYXNzd29yZDogc3RyaW5nO1xuICB9O1xuICByZWFkb25seSBkcml6emxlOiB7XG4gICAgLyoqIE1heGltdW0gY29ubmVjdGlvbiBwb29sIHNpemUgKGVudjogYERSSVpaTEVfTUFYX1BPT0xfU0laRWApLiAqL1xuICAgIHJlYWRvbmx5IG1heFBvb2xTaXplOiBudW1iZXI7XG4gICAgLyoqIElkbGUgY29ubmVjdGlvbiB0aW1lb3V0IGluIG1zIChlbnY6IGBEUklaWkxFX0lETEVfVElNRU9VVF9NSUxMSVNgKS4gKi9cbiAgICByZWFkb25seSBpZGxlVGltZW91dE1pbGxpczogbnVtYmVyO1xuICAgIC8qKiBOZXcgY29ubmVjdGlvbiB0aW1lb3V0IGluIG1zIChlbnY6IGBEUklaWkxFX0NPTk5FQ1RJT05fVElNRU9VVF9NSUxMSVNgKS4gKi9cbiAgICByZWFkb25seSBjb25uZWN0aW9uVGltZW91dE1pbGxpczogbnVtYmVyO1xuICB9O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlZ2lzdHJ5Q29uZmlnIHtcbiAgcmVhZG9ubHkgaG9zdDogc3RyaW5nO1xuICByZWFkb25seSBwb3J0OiBudW1iZXI7XG4gIC8qKlxuICAgKiBIb3N0L3BvcnQgYW4gT1VULU9GLUNMVVNURVIgY2xpZW50IChub3RhYmx5IEFXUyBDb2RlQnVpbGQpIHVzZXMgdG8gcHVsbFxuICAgKiBwbHVnaW4gaW1hZ2VzLCB3aGVuIGl0IGRpZmZlcnMgZnJvbSB0aGUgaW4tY2x1c3RlciBgaG9zdGAvYHBvcnRgLiBUaGVcbiAgICogaW4tY2x1c3RlciBgcmVnaXN0cnk6NTAwMGAgQ2x1c3RlcklQIGlzbid0IHJlc29sdmFibGUgZnJvbSB0aGUgVlBDLCBzbyB0aGVcbiAgICogc3ludGhlc2l6ZWQgQ29kZUJ1aWxkIGltYWdlIFVSSSBtdXN0IHBvaW50IGF0IHRoZSBwdWJsaWMgZ2F0ZXdheSBpbnN0ZWFkLlxuICAgKiBFbnY6IGBJTUFHRV9SRUdJU1RSWV9QVUxMX0hPU1RgIC8gYElNQUdFX1JFR0lTVFJZX1BVTExfUE9SVGAuIE9wdGlvbmFsO1xuICAgKiBjb25zdW1lcnMgZmFsbCBiYWNrIHRvIGBob3N0YC9gcG9ydGAgd2hlbiB1bnNldCAoc2luZ2xlLWhvc3QgL1xuICAgKiBpbi1jbHVzdGVyLW9ubHkgZGVwbG95cykuIGBsb2FkUmVnaXN0cnlDb25maWdgIGFsd2F5cyBwb3B1bGF0ZXMgdGhlbS5cbiAgICovXG4gIHJlYWRvbmx5IHB1bGxIb3N0Pzogc3RyaW5nO1xuICByZWFkb25seSBwdWxsUG9ydD86IG51bWJlcjtcbiAgLyoqIERvY2tlciBuZXR3b3JrIGZvciBidWlsZC9wdXNoIChlbXB0eSBzdHJpbmcgPSBkZWZhdWx0KS4gKi9cbiAgcmVhZG9ubHkgbmV0d29yazogc3RyaW5nO1xuICAvKipcbiAgICogQnVpbGRLaXQgdGFsa3MgdG8gdGhlIHJlZ2lzdHJ5IG92ZXIgcGxhaW4gSFRUUCB3aGVuIHRydWU7IEhUVFBTIHdpdGggdGhlXG4gICAqIHN5c3RlbSBDQSBidW5kbGUgb3RoZXJ3aXNlLiBFbnY6IGBJTUFHRV9SRUdJU1RSWV9IVFRQYCAoZGVmYXVsdHMgdHJ1ZSDigJRcbiAgICogdGhlIGluLWNsdXN0ZXIgcmVnaXN0cnkgaGFzIG5vIFRMUykuXG4gICAqL1xuICByZWFkb25seSBodHRwOiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlZGlzQ29uZmlnIHtcbiAgcmVhZG9ubHkgaG9zdDogc3RyaW5nO1xuICByZWFkb25seSBwb3J0OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGx1Z2luQnVpbGRDb25maWcge1xuICByZWFkb25seSBjb25jdXJyZW5jeTogbnVtYmVyO1xuICByZWFkb25seSBtYXhBdHRlbXB0czogbnVtYmVyO1xuICByZWFkb25seSBiYWNrb2ZmRGVsYXlNczogbnVtYmVyO1xuICByZWFkb25seSB3b3JrZXJUaW1lb3V0TXM6IG51bWJlcjtcbiAgcmVhZG9ubHkgdGVtcERpck1heEFnZU1zOiBudW1iZXI7XG4gIHJlYWRvbmx5IGRscU1heEF0dGVtcHRzOiBudW1iZXI7XG4gIHJlYWRvbmx5IGRscUJhY2tvZmZCYXNlTXM6IG51bWJlcjtcbiAgcmVhZG9ubHkgZGxxTWF4U2l6ZTogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEJ1aWxkQ29uZmlnIHtcbiAgLyoqIFJvb3QgZGlyZWN0b3J5IGZvciBidWlsZCB0ZW1wIGZpbGVzLiAqL1xuICByZWFkb25seSB0ZW1wUm9vdDogc3RyaW5nO1xuICAvKiogQnVpbGQgdGltZW91dCBpbiBtaWxsaXNlY29uZHMuICovXG4gIHJlYWRvbmx5IHRpbWVvdXRNczogbnVtYmVyO1xuICAvKiogUHVzaCB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcy4gKi9cbiAgcmVhZG9ubHkgcHVzaFRpbWVvdXRNczogbnVtYmVyO1xuICAvKipcbiAgICogUGF0aCB0byB0aGUgYnVpbGRraXRkIHNvY2tldCB0aGUgcGx1Z2luJ3MgYGJ1aWxkY3RsYCBjb25uZWN0cyB0by4gSW4gazhzXG4gICAqIGFuZCBjb21wb3NlIHRoaXMgaXMgYSBzaGFyZWQgZW1wdHlEaXIvdG1wZnMgdm9sdW1lIG1vdW50ZWQgZnJvbSB0aGVcbiAgICogYnVpbGRraXRkIHNpZGVjYXIuXG4gICAqL1xuICByZWFkb25seSBidWlsZGtpdEFkZHI6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBPYnNlcnZhYmlsaXR5Q29uZmlnIHtcbiAgcmVhZG9ubHkgbG9nTGV2ZWw6IHN0cmluZztcbiAgcmVhZG9ubHkgbG9nRm9ybWF0OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHNlcnZpY2VOYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHRyYWNpbmc6IHtcbiAgICByZWFkb25seSBlbmFibGVkOiBib29sZWFuO1xuICAgIHJlYWRvbmx5IGVuZHBvaW50OiBzdHJpbmc7XG4gIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcGxpYW5jZUNvbmZpZyB7XG4gIHJlYWRvbmx5IHNjYW5TY2hlZHVsZXJJbnRlcnZhbE1zOiBudW1iZXI7XG4gIC8qKiBXaGVuIGZhbHNlLCB0aGUgc2NoZWR1bGVyIHNraXBzIHNjYW5zL3NjaGVkdWxlcyBmb3IgdGhlIHN5c3RlbSBvcmcuIERlZmF1bHQ6IGZhbHNlLiAqL1xuICByZWFkb25seSBzeXN0ZW1PcmdTY2Fuc0VuYWJsZWQ6IGJvb2xlYW47XG4gIC8qKiBDcm9zcy1wb2QgbGVhZGVyLWxvY2sgVFRMIGZvciB0aGUgc2NhbiBzY2hlZHVsZXIgKG1zKS4gRGVmYXVsdDogMzAwMDAwLiAqL1xuICByZWFkb25seSBzY2FuTG9ja1R0bE1zOiBudW1iZXI7XG4gIC8qKiBIb3cgb2Z0ZW4gdGhlIGRpZ2VzdCBzY2hlZHVsZXIgY2hlY2tzIGZvciBkdWUgZGlnZXN0cyAobXMpLiBEZWZhdWx0OiAzNjAwMDAwLiAqL1xuICByZWFkb25seSBkaWdlc3RTY2hlZHVsZXJJbnRlcnZhbE1zOiBudW1iZXI7XG4gIC8qKiBDcm9zcy1wb2QgbGVhZGVyLWxvY2sgVFRMIGZvciB0aGUgZGlnZXN0IHNjaGVkdWxlciAobXMpLiBEZWZhdWx0OiAzMDAwMDAuICovXG4gIHJlYWRvbmx5IGRpZ2VzdExvY2tUdGxNczogbnVtYmVyO1xufVxuXG4vKipcbiAqIEFXUyBpbmZyYXN0cnVjdHVyZSBjb25maWd1cmF0aW9uLlxuICpcbiAqIERlbGliZXJhdGVseSBleHByZXNzZWQgaW4gUExBSU4gREFUQSAobnVtYmVycywgc3RyaW5ncywgc3RyaW5nIHVuaW9ucykgcmF0aGVyXG4gKiB0aGFuIENESyB2YWx1ZSBvYmplY3RzIChgRHVyYXRpb25gLCBgUnVudGltZWAsIGBSZXRlbnRpb25EYXlzYCwgLi4uKS4gQ29uZmlnIGlzXG4gKiBsb2FkZWQgYnkgZXZlcnkgc2VydmljZSwgYnV0IG9ubHkgdGhlIENESyBlbnRyeSBwb2ludCAoYEBwaXBlbGluZS1idWlsZGVyL1xuICogcGlwZWxpbmUtY29yZS9jZGtgKSBidWlsZHMgc3RhY2tzICB0eXBpbmcgdGhpcyBibG9jayB3aXRoIENESyBjbGFzc2VzIHB1dFxuICogYGF3cy1jZGstbGliYCBvbiB0aGUgaW1wb3J0IGdyYXBoIG9mIGBDb25maWdgLCBhbmQgdGhlcmVmb3JlIG9mIGV2ZXJ5IEFQSVxuICogc2VydmljZSB0aGF0IHJlYWRzIHNvIG11Y2ggYXMgYSBwb3J0IG51bWJlci4gQ29udmVyc2lvbiB0byBDREsgb2JqZWN0cyBoYXBwZW5zXG4gKiBhdCB0aGUgY29uc3RydWN0IGJvdW5kYXJ5IGluIGBjb25maWcvYXdzLWNvbmZpZy1jZGsudHNgLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEFXU0NvbmZpZyB7XG4gIHJlYWRvbmx5IGxhbWJkYToge1xuICAgIC8qKiBMYW1iZGEgcnVudGltZSBpZGVudGlmaWVyLCBlLmcuIGAnbm9kZWpzMjQueCdgIChlbnY6IGBMQU1CREFfUlVOVElNRWApLiAqL1xuICAgIHJlYWRvbmx5IHJ1bnRpbWU6IHN0cmluZztcbiAgICAvKiogRnVuY3Rpb24gdGltZW91dCBpbiBzZWNvbmRzIChlbnY6IGBMQU1CREFfVElNRU9VVGApLiAqL1xuICAgIHJlYWRvbmx5IHRpbWVvdXRTZWNvbmRzOiBudW1iZXI7XG4gICAgcmVhZG9ubHkgbWVtb3J5U2l6ZTogbnVtYmVyO1xuICAgIHJlYWRvbmx5IGFyY2hpdGVjdHVyZTogJ2FybTY0JyB8ICd4ODZfNjQnO1xuICAgIHJlYWRvbmx5IHJlc2VydmVkQ29uY3VycmVudEV4ZWN1dGlvbnM/OiBudW1iZXI7XG4gIH07XG4gIHJlYWRvbmx5IGxvZ2dpbmc6IHtcbiAgICByZWFkb25seSBncm91cE5hbWU6IHN0cmluZztcbiAgICAvKiogQ2xvdWRXYXRjaCByZXRlbnRpb24gaW4gZGF5czsgYDBgIG1lYW5zIG5ldmVyIGV4cGlyZSAoZW52OiBgTE9HX1JFVEVOVElPTmApLiAqL1xuICAgIHJlYWRvbmx5IHJldGVudGlvbkRheXM6IG51bWJlcjtcbiAgICByZWFkb25seSByZW1vdmFsUG9saWN5OiAncmV0YWluJyB8ICdkZXN0cm95JztcbiAgfTtcbiAgcmVhZG9ubHkgY29kZUJ1aWxkOiB7XG4gICAgLyoqIENvZGVCdWlsZCBjb21wdXRlIHR5cGUgbmFtZSwgZS5nLiBgJ1NNQUxMJ2AgKGVudjogYENPREVCVUlMRF9DT01QVVRFX1RZUEVgKS4gKi9cbiAgICByZWFkb25seSBjb21wdXRlVHlwZTogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIEltYWdlIHVzZWQgZm9yIENvZGVCdWlsZCBzdGVwcyB0aGF0IGRvbid0IGhhdmUgYSBwbHVnaW4tYmFrZWQgaW1hZ2VcbiAgICAgKiAoY29sZC1zdGFydCBzeW50aCBib290c3RyYXAsIFNoZWxsU3RlcHMgd2l0aCBubyByZWdpc3RyeSwgYW5kXG4gICAgICogYG1ldGFkYXRhX29ubHlgIHBsdWdpbnMpLiBlbnY6IGBDT0RFQlVJTERfREVGQVVMVF9JTUFHRWAuIERlZmF1bHRcbiAgICAgKiBgcGlwZWxpbmUtYm9vdHN0cmFwOjEuMGAg4oCUIHRoZSBsb2NhbCB0YWcgYnVpbHQgYnlcbiAgICAgKiBgZGVwbG95L2NvZGVidWlsZC9ib290c3RyYXAvRG9ja2VyZmlsZWAsIHdpdGggYHBpcGVsaW5lLW1hbmFnZXJgXG4gICAgICogYmFrZWQgaW4uXG4gICAgICpcbiAgICAgKiBDb250cmFjdDogdGhlIGltYWdlIE1VU1QgaGF2ZSBgcGlwZWxpbmUtbWFuYWdlcmAgb24gUEFUSC4gVGhlXG4gICAgICogYm9vdHN0cmFwIHN5bnRoIHBhdGggbm8gbG9uZ2VyIHNlbGYtaGVhbHMgdmlhIGBucG0gaW5zdGFsbCAtZ2A7XG4gICAgICogcG9pbnRpbmcgdGhpcyBhdCBhbiBpbWFnZSB3aXRob3V0IHRoZSB0b29sIGdldHMgZXhpdCAxMjcgb24gdGhlXG4gICAgICogZmlyc3QgY29sZC1zdGFydCBidWlsZC5cbiAgICAgKlxuICAgICAqIFJlc29sdXRpb246XG4gICAgICogLSBCYXJlIHRhZyAobm8gYC9gKSDihpIgYXV0by1wcmVmaXhlZCB0b1xuICAgICAqICAgYDxyZWdpc3RyeS1ob3N0Pjo8cG9ydD4vbGlicmFyeS88dGFnPmAgdXNpbmcgdGhlIHJlZ2lzdHJ5IGNvbmZpZyxcbiAgICAgKiAgIHdpdGggdGhlIHBlci1vcmcgcGxhdGZvcm0gU2VjcmV0IGFzIEJhc2ljIGF1dGggKHNhbWUgZmxvdyBhc1xuICAgICAqICAgcGx1Z2luIGltYWdlcykuXG4gICAgICogLSBGdWxseS1xdWFsaWZpZWQgcmVnaXN0cnkgVVJJIChjb250YWlucyBgL2ApIOKGkiB1c2VkIGFzLWlzLCBub1xuICAgICAqICAgYXV0aCB3aXJlZCAob3BlcmF0b3Igb3ducyBtYWtpbmcgaXQgcHVsbGFibGUpLlxuICAgICAqIC0gV2hlbiB0aGUgcmVnaXN0cnkgaXNuJ3QgY29uZmlndXJlZCBvciBwZXItb3JnIGF1dGggaXNuJ3RcbiAgICAgKiAgIGF2YWlsYWJsZSBhdCB0aGUgY2FsbCBzaXRlLCBmYWxscyBiYWNrIHRvXG4gICAgICogICBgYXdzL2NvZGVidWlsZC9zdGFuZGFyZDo4LjBgIHdpdGggYSB3YXJuaW5nIOKAlCBjb2xkLXN0YXJ0IHN5bnRoXG4gICAgICogICB3aWxsIHRoZW4gZmFpbCBvbiBgcGlwZWxpbmUtbWFuYWdlcjogbm90IGZvdW5kYCwgc3VyZmFjaW5nIHRoZVxuICAgICAqICAgbWlzY29uZmlndXJhdGlvbiBsb3VkbHkgaW5zdGVhZCBvZiBzaWxlbnRseSBzd2FwcGluZyBpbWFnZXMuXG4gICAgICovXG4gICAgcmVhZG9ubHkgZGVmYXVsdEltYWdlOiBzdHJpbmc7XG4gIH07XG59XG5cbi8qKiBFeHByZXNzIHJhdGUgbGltaXRpbmcgY29uZmlndXJhdGlvbi4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmF0ZUxpbWl0Q29uZmlnIHtcbiAgLyoqIE1heGltdW0gcmVxdWVzdHMgcGVyIHdpbmRvdyAoZW52OiBgTElNSVRFUl9NQVhgKS4gKi9cbiAgcmVhZG9ubHkgbWF4OiBudW1iZXI7XG4gIC8qKiBSYXRlIGxpbWl0IHdpbmRvdyBpbiBtaWxsaXNlY29uZHMgKGVudjogYExJTUlURVJfV0lORE9XTVNgKS4gKi9cbiAgcmVhZG9ubHkgd2luZG93TXM6IG51bWJlcjtcbiAgLyoqIEluY2x1ZGUgbGVnYWN5IGBYLVJhdGVMaW1pdC0qYCBoZWFkZXJzLiAqL1xuICByZWFkb25seSBsZWdhY3lIZWFkZXJzOiBib29sZWFuO1xuICAvKiogSW5jbHVkZSBzdGFuZGFyZCBgUmF0ZUxpbWl0LSpgIGhlYWRlcnMgKFJGQyA2NTg1KS4gKi9cbiAgcmVhZG9ubHkgc3RhbmRhcmRIZWFkZXJzOiBib29sZWFuO1xufVxuXG4vKiogUHJpY2UgY29uZmlndXJhdGlvbiBmb3IgYSBzaW5nbGUgYmlsbGluZyBwbGFuIChpbiBjZW50cykuICovXG5leHBvcnQgaW50ZXJmYWNlIEJpbGxpbmdQbGFuUHJpY2VzIHtcbiAgcmVhZG9ubHkgbW9udGhseTogbnVtYmVyO1xuICByZWFkb25seSBhbm51YWw6IG51bWJlcjtcbn1cblxuLyoqIEZ1bGwgYmlsbGluZyBwbGFuIGRlZmluaXRpb24gdXNlZCBmb3Igc2VlZGluZyBhbmQgcnVudGltZSBjb25maWd1cmF0aW9uLiAqL1xuZXhwb3J0IGludGVyZmFjZSBCaWxsaW5nUGxhbkNvbmZpZyB7XG4gIHJlYWRvbmx5IGlkOiBzdHJpbmc7XG4gIHJlYWRvbmx5IG5hbWU6IHN0cmluZztcbiAgcmVhZG9ubHkgZGVzY3JpcHRpb246IHN0cmluZztcbiAgcmVhZG9ubHkgdGllcjogUXVvdGFUaWVyO1xuICByZWFkb25seSBwcmljZXM6IEJpbGxpbmdQbGFuUHJpY2VzO1xuICByZWFkb25seSBmZWF0dXJlczogcmVhZG9ubHkgc3RyaW5nW107XG4gIHJlYWRvbmx5IGlzQWN0aXZlOiBib29sZWFuO1xuICByZWFkb25seSBpc0RlZmF1bHQ6IGJvb2xlYW47XG4gIHJlYWRvbmx5IHNvcnRPcmRlcjogbnVtYmVyO1xufVxuXG4vKipcbiAqIEEgcHVyY2hhc2FibGUgYWRkLW9uIGJ1bmRsZTogYSBxdWFudGl0eS1zdGFja2FibGUgcGFjayB0aGF0IEFERFMgdG8gdGhlXG4gKiBhY2NvdW50J3MgYmFzZSAodGllcikgbGltaXRzIGFuZCBhZGRzIGEgcmVjdXJyaW5nIGxpbmUgaXRlbS4gU2VlXG4gKiBkb2NzL2JpbGxpbmctYnVuZGxlcy5tZC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCdW5kbGVDb25maWcge1xuICByZWFkb25seSBpZDogc3RyaW5nO1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGRlc2NyaXB0aW9uOiBzdHJpbmc7XG4gIC8qKiBQZXItdW5pdCBkZWx0YXMgb24gYFF1b3RhVGllckxpbWl0c2AgZmllbGRzLCBlLmcuIGB7IHNlYXRzOiA1IH1gLiBLZXlzIGFyZVxuICAgKiAgY29uc3RyYWluZWQgdG8gcmVhbCBxdW90YSBmaWVsZHMgc28gYSB0eXBvIGlzIGEgY29tcGlsZSBlcnJvciAod2FzXG4gICAqICBgUmVjb3JkPHN0cmluZywgbnVtYmVyPmAsIHdoZXJlIGEgbWlzc3BlbGxlZCBrZXkgd2FzIHNpbGVudGx5IHVuZW5mb3JjZWFibGUpLiAqL1xuICByZWFkb25seSBncmFudHM6IFJlYWRvbmx5PFBhcnRpYWw8UmVjb3JkPGtleW9mIFF1b3RhVGllckxpbWl0cywgbnVtYmVyPj4+O1xuICAvKiogRmVhdHVyZSBmbGFncyBncmFudGVkIGJ5IGEgZmVhdHVyZSBidW5kbGUgKGUuZy4gYGF1ZGl0X2xvZ2ApLiAqL1xuICByZWFkb25seSBmZWF0dXJlcz86IHJlYWRvbmx5IHN0cmluZ1tdO1xuICAvKiogUGVyLXVuaXQgcHJpY2UgKGNlbnRzKS4gU3RyaXBlIG11bHRpcGxpZXMgYnkgcXVhbnRpdHkuICovXG4gIHJlYWRvbmx5IHByaWNlczogQmlsbGluZ1BsYW5QcmljZXM7XG4gIC8qKiBUcnVlIGZvciBzdGFja2FibGUgcmVzb3VyY2UgcGFja3M7IGZhbHNlIGZvciBhIGJvb2xlYW4gZmVhdHVyZSBidW5kbGUuICovXG4gIHJlYWRvbmx5IHN0YWNrYWJsZTogYm9vbGVhbjtcbiAgLyoqXG4gICAqIE1heGltdW0gcHVyY2hhc2FibGUgcXVhbnRpdHkgZm9yIGEgc3RhY2thYmxlIHBhY2suIEVuZm9yY2VkIGJ5IHRoZSBhZGRvblxuICAgKiBwdXJjaGFzZS9wcmV2aWV3IHJvdXRlIChgcXVhbnRpdHkg4omkIG1heFF1YW50aXR5YCwgcmVqZWN0IG92ZXItY2FwKS4gVXNlZCB0b1xuICAgKiBrZWVwIHJldGVudGlvbiBwYWNrcyB1bmRlciB0aGUgNzMwLWRheSByZXRlbnRpb24gY2VpbGluZyAoZS5nLiB0aGUgU3RhbmRhcmRcbiAgICogUmV0ZW50aW9uIFBhY2sgY2FwcyBhdCA3IHNvIDMwICsgN8OXOTAgPSA2NjAg4omkIDczMCkuIEFic2VudCDih5IgdW5ib3VuZGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgbWF4UXVhbnRpdHk/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBPcHRpb25hbCBwZXItdW5pdCB2b2x1bWUgZGlzY291bnQgdGllcnMgZm9yIGEgc3RhY2thYmxlIHBhY2s6IGF0IOKJpSBgbWluUXVhbnRpdHlgXG4gICAqIHB1cmNoYXNlZCB1bml0cywgYGRpc2NvdW50UGVyY2VudGAgY29tZXMgb2ZmIHRoZSBsaW5lIHN1YnRvdGFsICh1bml0IMOXIHF1YW50aXR5KS5cbiAgICogVGhlIGhpZ2hlc3QgbWF0Y2hpbmcgdGllciB3aW5zLiBSZWFsaXplZCBhcyBhIHJlY3VycmluZyB1c2FnZSBjcmVkaXQgKGxpa2UgYVxuICAgKiBjb21ibyksIHNvIHRoZSBwcm92aWRlciBzdGlsbCBjaGFyZ2VzIHVuaXTDl3F0eSBhbmQgdGhlIGNyZWRpdCBvZmZzZXRzIHRoZVxuICAgKiBiYWxhbmNlLiBFbnYtb3ZlcnJpZGFibGUgdmlhIGBCSUxMSU5HX0JVTkRMRV88SUQ+X1ZPTFVNRV9USUVSU2AgKEpTT04pLiBVc2VkIGJ5XG4gICAqIHRoZSBwZXItc2VhdCBgc2VhdGAgYnVuZGxlLiBBYnNlbnQg4oeSIG5vIHZvbHVtZSBkaXNjb3VudC5cbiAgICovXG4gIHJlYWRvbmx5IHZvbHVtZVRpZXJzPzogcmVhZG9ubHkgeyByZWFkb25seSBtaW5RdWFudGl0eTogbnVtYmVyOyByZWFkb25seSBkaXNjb3VudFBlcmNlbnQ6IG51bWJlciB9W107XG4gIC8qKiBCYXNlIHRpZXJzIHRoaXMgYnVuZGxlIGlzIG9mZmVyZWQgdG8uICovXG4gIHJlYWRvbmx5IGF2YWlsYWJsZUZvclRpZXJzOiByZWFkb25seSBRdW90YVRpZXJbXTtcbiAgLyoqXG4gICAqIFByZXJlcXVpc2l0ZSBidW5kbGUgaWRzIHRoYXQgbXVzdCBiZSBoZWxkIChvciBwdXJjaGFzZWQgaW4gdGhlIHNhbWUgYWN0aW9uKVxuICAgKiBiZWZvcmUgdGhpcyBidW5kbGUgY2FuIGJlIGFkZGVkLiBFbmZvcmNlZCBieSB0aGUgYWRkb24gcHVyY2hhc2UvcHJldmlldyByb3V0ZVxuICAgKiAocmVqZWN0IHdpdGggNDAwIHdoZW4gdW5tZXQpOyBhIGNvbWJvIHRoYXQgaW5jbHVkZXMgdGhlIHByZXJlcXVpc2l0ZSBzYXRpc2ZpZXNcbiAgICogaXQuIFVzZWQgYnkgYGNvbXBsaWFuY2VfYWR2YW5jZWRgIChgcmVxdWlyZXM6IFsnY29tcGxpYW5jZV9zdGFuZGFyZCddYCkuXG4gICAqIEFic2VudCDih5Igbm8gcHJlcmVxdWlzaXRlLlxuICAgKi9cbiAgcmVhZG9ubHkgcmVxdWlyZXM/OiByZWFkb25seSBzdHJpbmdbXTtcbiAgcmVhZG9ubHkgaXNBY3RpdmU6IGJvb2xlYW47XG4gIHJlYWRvbmx5IHNvcnRPcmRlcjogbnVtYmVyO1xufVxuXG4vKipcbiAqIEEgY29tYm8gZGlzY291bnQ6IHdoZW4gYW4gYWNjb3VudCBob2xkcyBFVkVSWSBidW5kbGUgaW4gYGJ1bmRsZUlkc2AsIHRoZSBwYWlyXG4gKiBpcyBiaWxsZWQgYXQgYHByaWNlc2AgKHRoZSBjb21iaW5lZCBwcmljZSkgaW5zdGVhZCBvZiB0aGUgc3VtIG9mIHRoZSBtZW1iZXJzJ1xuICogaW5kaXZpZHVhbCBwcmljZXMuIFJlYWxpemVkIGFzIGEgcmVjdXJyaW5nIHVzYWdlIGNyZWRpdCBmb3IgdGhlIGRpZmZlcmVuY2Ug4oCUXG4gKiBuZXZlciBhIHByb3ZpZGVyIGNvdXBvbiDigJQgY29uc2lzdGVudCB3aXRoIHRoZSB1c2FnZS1jcmVkaXQgZGlzY291bnQgbW9kZWwuIFNlZVxuICogZG9jcy9iaWxsaW5nLWJ1bmRsZXMubWQgwqdDb21ibyBwcmljaW5nLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbWJvRGlzY291bnRDb25maWcge1xuICByZWFkb25seSBpZDogc3RyaW5nO1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG4gIC8qKiBUaGUgbWVtYmVyIGJ1bmRsZSBpZHMgdGhhdCBtdXN0IEFMTCBiZSBwcmVzZW50IGZvciB0aGUgY29tYm8gdG8gYXBwbHkuICovXG4gIHJlYWRvbmx5IGJ1bmRsZUlkczogcmVhZG9ubHkgc3RyaW5nW107XG4gIC8qKiBQZXItbWVtYmVyIG1pbmltdW0gcXVhbnRpdHkgKGJ1bmRsZUlkIOKGkiBjb3VudDsgYWJzZW50IOKHkiAxKS4gTGV0cyBhIHN0YWNrYWJsZVxuICAgKiAgY2FwYWNpdHkgcGFjayBhbmNob3IgYSBjb21ibyDigJQgZS5nLiBgeyBzZWF0OiA1IH1gID0gXCLiiaUgNSBzZWF0c1wiLiBUaGUgY3JlZGl0XG4gICAqICBiYXNpcyB1c2VzIHRoaXMgbWluaW11bSwgc28gZXh0cmEgdW5pdHMgbmV2ZXIgaW5mbGF0ZSB0aGUgZGlzY291bnQuICovXG4gIHJlYWRvbmx5IG1pblF1YW50aXRpZXM/OiBSZWFkb25seTxSZWNvcmQ8c3RyaW5nLCBudW1iZXI+PjtcbiAgLyoqIFRoZSBjb21iaW5lZCBwcmljZSBmb3IgdGhlIG1pbmltdW0gc2V0IChjZW50cykuIFRoZSBjcmVkaXQgaXNcbiAgICogIGDOoyBtZW1iZXIgdW5pdCBwcmljZSDDlyBtaW5RdHkg4oiSIHByaWNlc2AsIGNsYW1wZWQg4omlIDAuICovXG4gIHJlYWRvbmx5IHByaWNlczogQmlsbGluZ1BsYW5QcmljZXM7XG4gIC8qKiBEZXRlcm1pbmlzdGljIHRpZS1icmVhayBhbW9uZyBlcXVhbC10b3RhbCBvcHRpbWFsIHBhY2tpbmdzIHdoZW4gY29tYm9zIG92ZXJsYXBcbiAgICogIChsb3dlciB3aW5zKS4gKi9cbiAgcmVhZG9ubHkgc29ydE9yZGVyOiBudW1iZXI7XG4gIHJlYWRvbmx5IGlzQWN0aXZlOiBib29sZWFuO1xufVxuXG4vKiogQmlsbGluZyBwbGFucyArIGFkZC1vbiBidW5kbGUgY29uZmlndXJhdGlvbi4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQmlsbGluZ0NvbmZpZyB7XG4gIHJlYWRvbmx5IHBsYW5zOiByZWFkb25seSBCaWxsaW5nUGxhbkNvbmZpZ1tdO1xuICByZWFkb25seSBidW5kbGVzOiByZWFkb25seSBCdW5kbGVDb25maWdbXTtcbiAgcmVhZG9ubHkgY29tYm9EaXNjb3VudHM6IHJlYWRvbmx5IENvbWJvRGlzY291bnRDb25maWdbXTtcbn1cbiJdfQ==
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Effective-entitlement math for the account/entitlement model.
3
+ *
4
+ * The canonical "effective limits = tier base + Σ(bundle grants)" computation
5
+ * lives here — next to the plan/bundle config it operates on — so ANY
6
+ * account-scoped consumer (billing, and future quota/platform readers) shares
7
+ * one implementation instead of re-deriving the coalesce. Pure: the tier limits
8
+ * come from api-core (`getTierLimits`) and the bundle catalog is passed in.
9
+ */
10
+ import { type QuotaTier, type QuotaTierLimits } from '@pipeline-builder/api-core';
11
+ import type { BundleConfig } from './config-types.js';
12
+ /**
13
+ * Compute an account's EFFECTIVE entitlements = tier base limits + Σ(bundle
14
+ * grants × quantity), plus the union of bundle-granted feature flags. A field
15
+ * already `-1` (unlimited) stays `-1`. Pure; the catalog is passed in.
16
+ */
17
+ export declare function effectiveEntitlements(tier: QuotaTier, addons: ReadonlyArray<{
18
+ bundleId: string;
19
+ quantity: number;
20
+ }>, bundles: readonly BundleConfig[]): {
21
+ limits: Record<keyof QuotaTierLimits, number>;
22
+ features: string[];
23
+ };
@@ -0,0 +1,46 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Effective-entitlement math for the account/entitlement model.
5
+ *
6
+ * The canonical "effective limits = tier base + Σ(bundle grants)" computation
7
+ * lives here — next to the plan/bundle config it operates on — so ANY
8
+ * account-scoped consumer (billing, and future quota/platform readers) shares
9
+ * one implementation instead of re-deriving the coalesce. Pure: the tier limits
10
+ * come from api-core (`getTierLimits`) and the bundle catalog is passed in.
11
+ */
12
+ import { getTierLimits } from '@pipeline-builder/api-core';
13
+ /**
14
+ * Compute an account's EFFECTIVE entitlements = tier base limits + Σ(bundle
15
+ * grants × quantity), plus the union of bundle-granted feature flags. A field
16
+ * already `-1` (unlimited) stays `-1`. Pure; the catalog is passed in.
17
+ */
18
+ export function effectiveEntitlements(tier, addons, bundles) {
19
+ const limits = { ...getTierLimits(tier) };
20
+ const features = new Set();
21
+ const byId = new Map(bundles.map((b) => [b.id, b]));
22
+ for (const { bundleId, quantity } of addons) {
23
+ const bundle = byId.get(bundleId);
24
+ if (!bundle || quantity <= 0)
25
+ continue;
26
+ // Enforce the non-stackable invariant AND the maxQuantity ceiling in the
27
+ // CANONICAL math, not just at the purchase route: a `stackable:false` bundle
28
+ // counts once, and a stackable pack is clamped to its `maxQuantity` — so a
29
+ // non-route caller (drift reconciler, subscription-lifecycle) can't over-grant
30
+ // a quota from a stored/drifted quantity (e.g. a retention pack past its cap).
31
+ const effectiveQty = bundle.stackable ? Math.min(quantity, bundle.maxQuantity ?? quantity) : 1;
32
+ for (const [rawField, delta] of Object.entries(bundle.grants)) {
33
+ // `grants` is a Partial map, so a value can be undefined — skip those.
34
+ if (delta === undefined)
35
+ continue;
36
+ const field = rawField; // grants keys ARE quota fields
37
+ if (limits[field] === -1)
38
+ continue; // already unlimited
39
+ limits[field] = (limits[field] ?? 0) + delta * effectiveQty;
40
+ }
41
+ for (const f of bundle.features ?? [])
42
+ features.add(f);
43
+ }
44
+ return { limits, features: [...features] };
45
+ }
46
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXRsZW1lbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbmZpZy9lbnRpdGxlbWVudHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0Qzs7Ozs7Ozs7R0FRRztBQUVILE9BQU8sRUFBRSxhQUFhLEVBQXdDLE1BQU0sNEJBQTRCLENBQUM7QUFHakc7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxxQkFBcUIsQ0FDbkMsSUFBZSxFQUNmLE1BQTZELEVBQzdELE9BQWdDO0lBRWhDLE1BQU0sTUFBTSxHQUFHLEVBQUUsR0FBRyxhQUFhLENBQUMsSUFBSSxDQUFDLEVBQTJDLENBQUM7SUFDbkYsTUFBTSxRQUFRLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztJQUNuQyxNQUFNLElBQUksR0FBRyxJQUFJLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BELEtBQUssTUFBTSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUM1QyxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ2xDLElBQUksQ0FBQyxNQUFNLElBQUksUUFBUSxJQUFJLENBQUM7WUFBRSxTQUFTO1FBQ3ZDLHlFQUF5RTtRQUN6RSw2RUFBNkU7UUFDN0UsMkVBQTJFO1FBQzNFLCtFQUErRTtRQUMvRSwrRUFBK0U7UUFDL0UsTUFBTSxZQUFZLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLFdBQVcsSUFBSSxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQy9GLEtBQUssTUFBTSxDQUFDLFFBQVEsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQzlELHVFQUF1RTtZQUN2RSxJQUFJLEtBQUssS0FBSyxTQUFTO2dCQUFFLFNBQVM7WUFDbEMsTUFBTSxLQUFLLEdBQUcsUUFBaUMsQ0FBQyxDQUFDLCtCQUErQjtZQUNoRixJQUFJLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQUUsU0FBUyxDQUFDLG9CQUFvQjtZQUN4RCxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsS0FBSyxHQUFHLFlBQVksQ0FBQztRQUM5RCxDQUFDO1FBQ0QsS0FBSyxNQUFNLENBQUMsSUFBSSxNQUFNLENBQUMsUUFBUSxJQUFJLEVBQUU7WUFBRSxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFDRCxPQUFPLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxDQUFDLEdBQUcsUUFBUSxDQUFDLEVBQUUsQ0FBQztBQUM3QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogRWZmZWN0aXZlLWVudGl0bGVtZW50IG1hdGggZm9yIHRoZSBhY2NvdW50L2VudGl0bGVtZW50IG1vZGVsLlxuICpcbiAqIFRoZSBjYW5vbmljYWwgXCJlZmZlY3RpdmUgbGltaXRzID0gdGllciBiYXNlICsgzqMoYnVuZGxlIGdyYW50cylcIiBjb21wdXRhdGlvblxuICogbGl2ZXMgaGVyZSDigJQgbmV4dCB0byB0aGUgcGxhbi9idW5kbGUgY29uZmlnIGl0IG9wZXJhdGVzIG9uIOKAlCBzbyBBTllcbiAqIGFjY291bnQtc2NvcGVkIGNvbnN1bWVyIChiaWxsaW5nLCBhbmQgZnV0dXJlIHF1b3RhL3BsYXRmb3JtIHJlYWRlcnMpIHNoYXJlc1xuICogb25lIGltcGxlbWVudGF0aW9uIGluc3RlYWQgb2YgcmUtZGVyaXZpbmcgdGhlIGNvYWxlc2NlLiBQdXJlOiB0aGUgdGllciBsaW1pdHNcbiAqIGNvbWUgZnJvbSBhcGktY29yZSAoYGdldFRpZXJMaW1pdHNgKSBhbmQgdGhlIGJ1bmRsZSBjYXRhbG9nIGlzIHBhc3NlZCBpbi5cbiAqL1xuXG5pbXBvcnQgeyBnZXRUaWVyTGltaXRzLCB0eXBlIFF1b3RhVGllciwgdHlwZSBRdW90YVRpZXJMaW1pdHMgfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZSc7XG5pbXBvcnQgdHlwZSB7IEJ1bmRsZUNvbmZpZyB9IGZyb20gJy4vY29uZmlnLXR5cGVzLmpzJztcblxuLyoqXG4gKiBDb21wdXRlIGFuIGFjY291bnQncyBFRkZFQ1RJVkUgZW50aXRsZW1lbnRzID0gdGllciBiYXNlIGxpbWl0cyArIM6jKGJ1bmRsZVxuICogZ3JhbnRzIMOXIHF1YW50aXR5KSwgcGx1cyB0aGUgdW5pb24gb2YgYnVuZGxlLWdyYW50ZWQgZmVhdHVyZSBmbGFncy4gQSBmaWVsZFxuICogYWxyZWFkeSBgLTFgICh1bmxpbWl0ZWQpIHN0YXlzIGAtMWAuIFB1cmU7IHRoZSBjYXRhbG9nIGlzIHBhc3NlZCBpbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVmZmVjdGl2ZUVudGl0bGVtZW50cyhcbiAgdGllcjogUXVvdGFUaWVyLFxuICBhZGRvbnM6IFJlYWRvbmx5QXJyYXk8eyBidW5kbGVJZDogc3RyaW5nOyBxdWFudGl0eTogbnVtYmVyIH0+LFxuICBidW5kbGVzOiByZWFkb25seSBCdW5kbGVDb25maWdbXSxcbik6IHsgbGltaXRzOiBSZWNvcmQ8a2V5b2YgUXVvdGFUaWVyTGltaXRzLCBudW1iZXI+OyBmZWF0dXJlczogc3RyaW5nW10gfSB7XG4gIGNvbnN0IGxpbWl0cyA9IHsgLi4uZ2V0VGllckxpbWl0cyh0aWVyKSB9IGFzIFJlY29yZDxrZXlvZiBRdW90YVRpZXJMaW1pdHMsIG51bWJlcj47XG4gIGNvbnN0IGZlYXR1cmVzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIGNvbnN0IGJ5SWQgPSBuZXcgTWFwKGJ1bmRsZXMubWFwKChiKSA9PiBbYi5pZCwgYl0pKTtcbiAgZm9yIChjb25zdCB7IGJ1bmRsZUlkLCBxdWFudGl0eSB9IG9mIGFkZG9ucykge1xuICAgIGNvbnN0IGJ1bmRsZSA9IGJ5SWQuZ2V0KGJ1bmRsZUlkKTtcbiAgICBpZiAoIWJ1bmRsZSB8fCBxdWFudGl0eSA8PSAwKSBjb250aW51ZTtcbiAgICAvLyBFbmZvcmNlIHRoZSBub24tc3RhY2thYmxlIGludmFyaWFudCBBTkQgdGhlIG1heFF1YW50aXR5IGNlaWxpbmcgaW4gdGhlXG4gICAgLy8gQ0FOT05JQ0FMIG1hdGgsIG5vdCBqdXN0IGF0IHRoZSBwdXJjaGFzZSByb3V0ZTogYSBgc3RhY2thYmxlOmZhbHNlYCBidW5kbGVcbiAgICAvLyBjb3VudHMgb25jZSwgYW5kIGEgc3RhY2thYmxlIHBhY2sgaXMgY2xhbXBlZCB0byBpdHMgYG1heFF1YW50aXR5YCDigJQgc28gYVxuICAgIC8vIG5vbi1yb3V0ZSBjYWxsZXIgKGRyaWZ0IHJlY29uY2lsZXIsIHN1YnNjcmlwdGlvbi1saWZlY3ljbGUpIGNhbid0IG92ZXItZ3JhbnRcbiAgICAvLyBhIHF1b3RhIGZyb20gYSBzdG9yZWQvZHJpZnRlZCBxdWFudGl0eSAoZS5nLiBhIHJldGVudGlvbiBwYWNrIHBhc3QgaXRzIGNhcCkuXG4gICAgY29uc3QgZWZmZWN0aXZlUXR5ID0gYnVuZGxlLnN0YWNrYWJsZSA/IE1hdGgubWluKHF1YW50aXR5LCBidW5kbGUubWF4UXVhbnRpdHkgPz8gcXVhbnRpdHkpIDogMTtcbiAgICBmb3IgKGNvbnN0IFtyYXdGaWVsZCwgZGVsdGFdIG9mIE9iamVjdC5lbnRyaWVzKGJ1bmRsZS5ncmFudHMpKSB7XG4gICAgICAvLyBgZ3JhbnRzYCBpcyBhIFBhcnRpYWwgbWFwLCBzbyBhIHZhbHVlIGNhbiBiZSB1bmRlZmluZWQg4oCUIHNraXAgdGhvc2UuXG4gICAgICBpZiAoZGVsdGEgPT09IHVuZGVmaW5lZCkgY29udGludWU7XG4gICAgICBjb25zdCBmaWVsZCA9IHJhd0ZpZWxkIGFzIGtleW9mIFF1b3RhVGllckxpbWl0czsgLy8gZ3JhbnRzIGtleXMgQVJFIHF1b3RhIGZpZWxkc1xuICAgICAgaWYgKGxpbWl0c1tmaWVsZF0gPT09IC0xKSBjb250aW51ZTsgLy8gYWxyZWFkeSB1bmxpbWl0ZWRcbiAgICAgIGxpbWl0c1tmaWVsZF0gPSAobGltaXRzW2ZpZWxkXSA/PyAwKSArIGRlbHRhICogZWZmZWN0aXZlUXR5O1xuICAgIH1cbiAgICBmb3IgKGNvbnN0IGYgb2YgYnVuZGxlLmZlYXR1cmVzID8/IFtdKSBmZWF0dXJlcy5hZGQoZik7XG4gIH1cbiAgcmV0dXJuIHsgbGltaXRzLCBmZWF0dXJlczogWy4uLmZlYXR1cmVzXSB9O1xufVxuIl19
@@ -0,0 +1,10 @@
1
+ /** Default platform URL fallback when PLATFORM_BASE_URL is not set. */
2
+ export declare const DEFAULT_PLATFORM_URL = "https://localhost:8443";
3
+ /** Custom-resource handler timeout (must be < the Lambda's 30s to allow response handling). */
4
+ export declare const HANDLER_TIMEOUT_MS: number;
5
+ /** Platform base URL the handler calls; overridable per-request via ResourceProperties.baseURL. */
6
+ export declare const HANDLER_DEFAULT_BASE_URL: string;
7
+ /** Max retries on transient plugin-lookup failures. */
8
+ export declare const HANDLER_MAX_RETRIES: number;
9
+ /** Base backoff between handler retries (exponential). */
10
+ export declare const HANDLER_RETRY_DELAY_MS: number;
@@ -0,0 +1,39 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Leaf constants for the PluginLookup Lambda handler.
5
+ *
6
+ * Deliberately dependency-free (only `process.env` reads, no imports) so the
7
+ * handler's esbuild bundle stays small — it does not drag in the whole config
8
+ * machinery via `app-config.ts`. The handler imports THIS module, not
9
+ * `CoreConstants`.
10
+ *
11
+ * This originally guarded a much sharper edge: `app-config.ts` →
12
+ * `infrastructure-config.ts` → `aws-cdk-lib`, which OOM-killed esbuild
13
+ * (hundreds of MB, SIGKILL during cold-start synth). That chain is gone —
14
+ * `infrastructure-config.ts` is now CDK-free and the constructs live behind the
15
+ * `/cdk` entry point — but the dependency-free contract is still worth keeping.
16
+ *
17
+ * `CoreConstants` (app-config.ts) re-exports these so synth-side consumers
18
+ * (api-server, server-config) keep using `CoreConstants.HANDLER_*` unchanged —
19
+ * single source of truth lives here.
20
+ */
21
+ /** Parse an integer env var, falling back on unset OR malformed (NaN). A raw
22
+ * `parseInt` returning NaN silently disables the handler's retry loop / axios
23
+ * timeout — breaking every plugin lookup — so guard it. Kept inline to preserve
24
+ * this module's dependency-free contract (no imports → small Lambda bundle). */
25
+ function envInt(value, fallback) {
26
+ const n = parseInt(value ?? '', 10);
27
+ return Number.isNaN(n) ? fallback : n;
28
+ }
29
+ /** Default platform URL fallback when PLATFORM_BASE_URL is not set. */
30
+ export const DEFAULT_PLATFORM_URL = 'https://localhost:8443';
31
+ /** Custom-resource handler timeout (must be < the Lambda's 30s to allow response handling). */
32
+ export const HANDLER_TIMEOUT_MS = envInt(process.env.HANDLER_TIMEOUT_MS, 25000); // 25s
33
+ /** Platform base URL the handler calls; overridable per-request via ResourceProperties.baseURL. */
34
+ export const HANDLER_DEFAULT_BASE_URL = process.env.PLATFORM_BASE_URL || DEFAULT_PLATFORM_URL;
35
+ /** Max retries on transient plugin-lookup failures. */
36
+ export const HANDLER_MAX_RETRIES = envInt(process.env.HANDLER_MAX_RETRIES, 2);
37
+ /** Base backoff between handler retries (exponential). */
38
+ export const HANDLER_RETRY_DELAY_MS = envInt(process.env.HANDLER_RETRY_DELAY_MS, 1000); // 1s
39
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFuZGxlci1jb25zdGFudHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29uZmlnL2hhbmRsZXItY29uc3RhbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBaUJHO0FBRUg7OztpRkFHaUY7QUFDakYsU0FBUyxNQUFNLENBQUMsS0FBeUIsRUFBRSxRQUFnQjtJQUN6RCxNQUFNLENBQUMsR0FBRyxRQUFRLENBQUMsS0FBSyxJQUFJLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNwQyxPQUFPLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ3hDLENBQUM7QUFFRCx1RUFBdUU7QUFDdkUsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsd0JBQXdCLENBQUM7QUFFN0QsK0ZBQStGO0FBQy9GLE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTTtBQUV2RixtR0FBbUc7QUFDbkcsTUFBTSxDQUFDLE1BQU0sd0JBQXdCLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsSUFBSSxvQkFBb0IsQ0FBQztBQUU5Rix1REFBdUQ7QUFDdkQsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQW1CLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFFOUUsMERBQTBEO0FBQzFELE1BQU0sQ0FBQyxNQUFNLHNCQUFzQixHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLHNCQUFzQixFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIExlYWYgY29uc3RhbnRzIGZvciB0aGUgUGx1Z2luTG9va3VwIExhbWJkYSBoYW5kbGVyLlxuICpcbiAqIERlbGliZXJhdGVseSBkZXBlbmRlbmN5LWZyZWUgKG9ubHkgYHByb2Nlc3MuZW52YCByZWFkcywgbm8gaW1wb3J0cykgc28gdGhlXG4gKiBoYW5kbGVyJ3MgZXNidWlsZCBidW5kbGUgc3RheXMgc21hbGwg4oCUIGl0IGRvZXMgbm90IGRyYWcgaW4gdGhlIHdob2xlIGNvbmZpZ1xuICogbWFjaGluZXJ5IHZpYSBgYXBwLWNvbmZpZy50c2AuIFRoZSBoYW5kbGVyIGltcG9ydHMgVEhJUyBtb2R1bGUsIG5vdFxuICogYENvcmVDb25zdGFudHNgLlxuICpcbiAqIFRoaXMgb3JpZ2luYWxseSBndWFyZGVkIGEgbXVjaCBzaGFycGVyIGVkZ2U6IGBhcHAtY29uZmlnLnRzYCDihpJcbiAqIGBpbmZyYXN0cnVjdHVyZS1jb25maWcudHNgIOKGkiBgYXdzLWNkay1saWJgLCB3aGljaCBPT00ta2lsbGVkIGVzYnVpbGRcbiAqIChodW5kcmVkcyBvZiBNQiwgU0lHS0lMTCBkdXJpbmcgY29sZC1zdGFydCBzeW50aCkuIFRoYXQgY2hhaW4gaXMgZ29uZSDigJRcbiAqIGBpbmZyYXN0cnVjdHVyZS1jb25maWcudHNgIGlzIG5vdyBDREstZnJlZSBhbmQgdGhlIGNvbnN0cnVjdHMgbGl2ZSBiZWhpbmQgdGhlXG4gKiBgL2Nka2AgZW50cnkgcG9pbnQg4oCUIGJ1dCB0aGUgZGVwZW5kZW5jeS1mcmVlIGNvbnRyYWN0IGlzIHN0aWxsIHdvcnRoIGtlZXBpbmcuXG4gKlxuICogYENvcmVDb25zdGFudHNgIChhcHAtY29uZmlnLnRzKSByZS1leHBvcnRzIHRoZXNlIHNvIHN5bnRoLXNpZGUgY29uc3VtZXJzXG4gKiAoYXBpLXNlcnZlciwgc2VydmVyLWNvbmZpZykga2VlcCB1c2luZyBgQ29yZUNvbnN0YW50cy5IQU5ETEVSXypgIHVuY2hhbmdlZCDigJRcbiAqIHNpbmdsZSBzb3VyY2Ugb2YgdHJ1dGggbGl2ZXMgaGVyZS5cbiAqL1xuXG4vKiogUGFyc2UgYW4gaW50ZWdlciBlbnYgdmFyLCBmYWxsaW5nIGJhY2sgb24gdW5zZXQgT1IgbWFsZm9ybWVkIChOYU4pLiBBIHJhd1xuICogIGBwYXJzZUludGAgcmV0dXJuaW5nIE5hTiBzaWxlbnRseSBkaXNhYmxlcyB0aGUgaGFuZGxlcidzIHJldHJ5IGxvb3AgLyBheGlvc1xuICogIHRpbWVvdXQg4oCUIGJyZWFraW5nIGV2ZXJ5IHBsdWdpbiBsb29rdXAg4oCUIHNvIGd1YXJkIGl0LiBLZXB0IGlubGluZSB0byBwcmVzZXJ2ZVxuICogIHRoaXMgbW9kdWxlJ3MgZGVwZW5kZW5jeS1mcmVlIGNvbnRyYWN0IChubyBpbXBvcnRzIOKGkiBzbWFsbCBMYW1iZGEgYnVuZGxlKS4gKi9cbmZ1bmN0aW9uIGVudkludCh2YWx1ZTogc3RyaW5nIHwgdW5kZWZpbmVkLCBmYWxsYmFjazogbnVtYmVyKTogbnVtYmVyIHtcbiAgY29uc3QgbiA9IHBhcnNlSW50KHZhbHVlID8/ICcnLCAxMCk7XG4gIHJldHVybiBOdW1iZXIuaXNOYU4obikgPyBmYWxsYmFjayA6IG47XG59XG5cbi8qKiBEZWZhdWx0IHBsYXRmb3JtIFVSTCBmYWxsYmFjayB3aGVuIFBMQVRGT1JNX0JBU0VfVVJMIGlzIG5vdCBzZXQuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9QTEFURk9STV9VUkwgPSAnaHR0cHM6Ly9sb2NhbGhvc3Q6ODQ0Myc7XG5cbi8qKiBDdXN0b20tcmVzb3VyY2UgaGFuZGxlciB0aW1lb3V0IChtdXN0IGJlIDwgdGhlIExhbWJkYSdzIDMwcyB0byBhbGxvdyByZXNwb25zZSBoYW5kbGluZykuICovXG5leHBvcnQgY29uc3QgSEFORExFUl9USU1FT1VUX01TID0gZW52SW50KHByb2Nlc3MuZW52LkhBTkRMRVJfVElNRU9VVF9NUywgMjUwMDApOyAvLyAyNXNcblxuLyoqIFBsYXRmb3JtIGJhc2UgVVJMIHRoZSBoYW5kbGVyIGNhbGxzOyBvdmVycmlkYWJsZSBwZXItcmVxdWVzdCB2aWEgUmVzb3VyY2VQcm9wZXJ0aWVzLmJhc2VVUkwuICovXG5leHBvcnQgY29uc3QgSEFORExFUl9ERUZBVUxUX0JBU0VfVVJMID0gcHJvY2Vzcy5lbnYuUExBVEZPUk1fQkFTRV9VUkwgfHwgREVGQVVMVF9QTEFURk9STV9VUkw7XG5cbi8qKiBNYXggcmV0cmllcyBvbiB0cmFuc2llbnQgcGx1Z2luLWxvb2t1cCBmYWlsdXJlcy4gKi9cbmV4cG9ydCBjb25zdCBIQU5ETEVSX01BWF9SRVRSSUVTID0gZW52SW50KHByb2Nlc3MuZW52LkhBTkRMRVJfTUFYX1JFVFJJRVMsIDIpO1xuXG4vKiogQmFzZSBiYWNrb2ZmIGJldHdlZW4gaGFuZGxlciByZXRyaWVzIChleHBvbmVudGlhbCkuICovXG5leHBvcnQgY29uc3QgSEFORExFUl9SRVRSWV9ERUxBWV9NUyA9IGVudkludChwcm9jZXNzLmVudi5IQU5ETEVSX1JFVFJZX0RFTEFZX01TLCAxMDAwKTsgLy8gMXNcbiJdfQ==
@@ -0,0 +1,66 @@
1
+ import type { AWSConfig, BuildConfig, ComplianceConfig, DatabaseConfig, ObservabilityConfig, PluginBuildConfig, RedisConfig, RegistryConfig } from './config-types.js';
2
+ /**
3
+ * Load Docker registry configuration from environment variables.
4
+ *
5
+ * Environment variables:
6
+ * - `IMAGE_REGISTRY_HOST` — Registry hostname (default: `'registry'`)
7
+ * - `IMAGE_REGISTRY_PORT` — Registry port (default: `5000`)
8
+ * - `IMAGE_REGISTRY_PULL_HOST` — Host an out-of-cluster client (CodeBuild)
9
+ * uses to pull plugin images. When unset, derived from `PLATFORM_BASE_URL`'s
10
+ * host (the public endpoint CodeBuild can resolve), then `IMAGE_REGISTRY_HOST`.
11
+ * - `IMAGE_REGISTRY_PULL_PORT` — Port for the above. When unset, derived from
12
+ * `PLATFORM_BASE_URL`'s port, then `IMAGE_REGISTRY_PORT`.
13
+ * - `DOCKER_NETWORK` — Docker network for build/push (default: `''`)
14
+ * - `IMAGE_REGISTRY_HTTP` — Use plain HTTP instead of HTTPS (default: `true`,
15
+ * the in-cluster registry has no TLS).
16
+ *
17
+ * @returns Registry configuration
18
+ */
19
+ export declare function loadRegistryConfig(): RegistryConfig;
20
+ /** Extract host + port from PLATFORM_BASE_URL (e.g. `https://pipeline-builder.com`
21
+ * → `{ host: 'pipeline-builder.com', port: 443 }`). Returns null when the value
22
+ * is unset or not a valid URL. Exported so the CLI (pipeline-manager) derives
23
+ * the registry pull target with the SAME parsing, instead of duplicating it. */
24
+ export declare function parsePlatformBaseUrl(raw?: string): {
25
+ host: string;
26
+ port: number;
27
+ } | null;
28
+ export declare function loadRedisConfig(): RedisConfig;
29
+ /**
30
+ * Load plugin build queue configuration.
31
+ *
32
+ * Environment variables:
33
+ * - `PLUGIN_BUILD_CONCURRENCY` — Max concurrent plugin builds (default: `1`)
34
+ */
35
+ export declare function loadPluginBuildConfig(): PluginBuildConfig;
36
+ export declare function loadDatabaseConfig(): DatabaseConfig;
37
+ export declare function loadObservabilityConfig(): ObservabilityConfig;
38
+ export declare function loadComplianceConfig(): ComplianceConfig;
39
+ /**
40
+ * Load plugin build configuration. Builds run against a rootless `moby/buildkit`
41
+ * sidecar — see `BUILDKIT_HOST`.
42
+ *
43
+ * Environment variables:
44
+ * - `DOCKER_BUILD_TEMP_ROOT` — Temp directory for build contexts (default: `<cwd>/tmp`)
45
+ * - `DOCKER_BUILD_TIMEOUT_MS` — Build timeout in milliseconds (default: `900000` / 15 min)
46
+ * - `DOCKER_PUSH_TIMEOUT_MS` — Push timeout in milliseconds (default: `300000` / 5 min)
47
+ * - `BUILDKIT_HOST` — buildctl `--addr` value for the buildkitd sidecar
48
+ * (default: `unix:///run/buildkit/buildkitd.sock`)
49
+ */
50
+ export declare function loadDockerConfig(): BuildConfig;
51
+ /**
52
+ * Load AWS infrastructure configuration from environment variables.
53
+ *
54
+ * Environment variables:
55
+ * - `LAMBDA_RUNTIME` — Lambda runtime (default: `'nodejs24.x'`; unknown values fall back to it)
56
+ * - `LAMBDA_TIMEOUT` — Lambda timeout in seconds (default: `900`)
57
+ * - `LAMBDA_MEMORY_SIZE` — Lambda memory in MB (default: `512`)
58
+ * - `LAMBDA_ARCHITECTURE` — `'x86_64'` or ARM (default: ARM_64)
59
+ * - `LOG_GROUP_NAME` — CloudWatch log group (default: `'/pipeline-builder/logs'`)
60
+ * - `LOG_RETENTION` — Log retention in days (default: `7`)
61
+ * - `LOG_REMOVAL_POLICY` — `'RETAIN'` or destroy (default: DESTROY)
62
+ * - `CODEBUILD_COMPUTE_TYPE` — CodeBuild compute type (default: `'SMALL'`)
63
+ *
64
+ * @returns AWS infrastructure configuration
65
+ */
66
+ export declare function loadAWSConfig(): AWSConfig;