@pipeline-builder/pipeline-manager 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +145 -0
- package/cdk.json +91 -0
- package/config.yml +94 -0
- package/dist/agent/ai.d.ts +48 -0
- package/dist/agent/ai.d.ts.map +1 -0
- package/dist/agent/ai.js +149 -0
- package/dist/agent/bootstrap.d.ts +39 -0
- package/dist/agent/bootstrap.d.ts.map +1 -0
- package/dist/agent/bootstrap.js +66 -0
- package/dist/agent/env-file.d.ts +17 -0
- package/dist/agent/env-file.d.ts.map +1 -0
- package/dist/agent/env-file.js +47 -0
- package/dist/agent/executor.d.ts +30 -0
- package/dist/agent/executor.d.ts.map +1 -0
- package/dist/agent/executor.js +60 -0
- package/dist/agent/health.d.ts +43 -0
- package/dist/agent/health.d.ts.map +1 -0
- package/dist/agent/health.js +109 -0
- package/dist/agent/ports.d.ts +26 -0
- package/dist/agent/ports.d.ts.map +1 -0
- package/dist/agent/ports.js +132 -0
- package/dist/agent/post-steps.d.ts +61 -0
- package/dist/agent/post-steps.d.ts.map +1 -0
- package/dist/agent/post-steps.js +131 -0
- package/dist/agent/prereqs.d.ts +26 -0
- package/dist/agent/prereqs.d.ts.map +1 -0
- package/dist/agent/prereqs.js +134 -0
- package/dist/agent/targets.d.ts +128 -0
- package/dist/agent/targets.d.ts.map +1 -0
- package/dist/agent/targets.js +265 -0
- package/dist/agent/tools.d.ts +13 -0
- package/dist/agent/tools.d.ts.map +1 -0
- package/dist/agent/tools.js +75 -0
- package/dist/agent/troubleshoot.d.ts +30 -0
- package/dist/agent/troubleshoot.d.ts.map +1 -0
- package/dist/agent/troubleshoot.js +87 -0
- package/dist/boilerplate.d.ts +3 -0
- package/dist/boilerplate.d.ts.map +1 -0
- package/dist/boilerplate.js +54 -0
- package/dist/cdk.json +91 -0
- package/dist/cli.d.ts +62 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +463 -0
- package/dist/commands/audit-stacks.d.ts +24 -0
- package/dist/commands/audit-stacks.d.ts.map +1 -0
- package/dist/commands/audit-stacks.js +182 -0
- package/dist/commands/audit-tokens.d.ts +21 -0
- package/dist/commands/audit-tokens.d.ts.map +1 -0
- package/dist/commands/audit-tokens.js +153 -0
- package/dist/commands/bootstrap.d.ts +11 -0
- package/dist/commands/bootstrap.d.ts.map +1 -0
- package/dist/commands/bootstrap.js +159 -0
- package/dist/commands/create-pat.d.ts +27 -0
- package/dist/commands/create-pat.d.ts.map +1 -0
- package/dist/commands/create-pat.js +194 -0
- package/dist/commands/create-pipeline.d.ts +12 -0
- package/dist/commands/create-pipeline.d.ts.map +1 -0
- package/dist/commands/create-pipeline.js +315 -0
- package/dist/commands/deploy.d.ts +15 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +157 -0
- package/dist/commands/entity-get.d.ts +51 -0
- package/dist/commands/entity-get.d.ts.map +1 -0
- package/dist/commands/entity-get.js +69 -0
- package/dist/commands/entity-list.d.ts +39 -0
- package/dist/commands/entity-list.d.ts.map +1 -0
- package/dist/commands/entity-list.js +88 -0
- package/dist/commands/get-pipeline.d.ts +13 -0
- package/dist/commands/get-pipeline.d.ts.map +1 -0
- package/dist/commands/get-pipeline.js +49 -0
- package/dist/commands/get-plugin.d.ts +13 -0
- package/dist/commands/get-plugin.d.ts.map +1 -0
- package/dist/commands/get-plugin.js +51 -0
- package/dist/commands/instantiate-template.d.ts +20 -0
- package/dist/commands/instantiate-template.d.ts.map +1 -0
- package/dist/commands/instantiate-template.js +274 -0
- package/dist/commands/list-pipelines.d.ts +20 -0
- package/dist/commands/list-pipelines.d.ts.map +1 -0
- package/dist/commands/list-pipelines.js +99 -0
- package/dist/commands/list-plugins.d.ts +20 -0
- package/dist/commands/list-plugins.d.ts.map +1 -0
- package/dist/commands/list-plugins.js +92 -0
- package/dist/commands/login.d.ts +21 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +174 -0
- package/dist/commands/new-plugin.d.ts +12 -0
- package/dist/commands/new-plugin.d.ts.map +1 -0
- package/dist/commands/new-plugin.js +129 -0
- package/dist/commands/org-export.d.ts +25 -0
- package/dist/commands/org-export.d.ts.map +1 -0
- package/dist/commands/org-export.js +100 -0
- package/dist/commands/provision.d.ts +122 -0
- package/dist/commands/provision.d.ts.map +1 -0
- package/dist/commands/provision.js +867 -0
- package/dist/commands/redrive-events.d.ts +24 -0
- package/dist/commands/redrive-events.d.ts.map +1 -0
- package/dist/commands/redrive-events.js +127 -0
- package/dist/commands/register.d.ts +38 -0
- package/dist/commands/register.d.ts.map +1 -0
- package/dist/commands/register.js +160 -0
- package/dist/commands/setup-events.d.ts +15 -0
- package/dist/commands/setup-events.d.ts.map +1 -0
- package/dist/commands/setup-events.js +168 -0
- package/dist/commands/status.d.ts +11 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +81 -0
- package/dist/commands/store-token.d.ts +26 -0
- package/dist/commands/store-token.d.ts.map +1 -0
- package/dist/commands/store-token.js +305 -0
- package/dist/commands/synth.d.ts +21 -0
- package/dist/commands/synth.d.ts.map +1 -0
- package/dist/commands/synth.js +158 -0
- package/dist/commands/upload-plugin.d.ts +21 -0
- package/dist/commands/upload-plugin.d.ts.map +1 -0
- package/dist/commands/upload-plugin.js +275 -0
- package/dist/commands/validate-plugin.d.ts +12 -0
- package/dist/commands/validate-plugin.d.ts.map +1 -0
- package/dist/commands/validate-plugin.js +175 -0
- package/dist/commands/validate-templates.d.ts +11 -0
- package/dist/commands/validate-templates.d.ts.map +1 -0
- package/dist/commands/validate-templates.js +116 -0
- package/dist/commands/version.d.ts +12 -0
- package/dist/commands/version.d.ts.map +1 -0
- package/dist/commands/version.js +216 -0
- package/dist/config/cli.constants.d.ts +116 -0
- package/dist/config/cli.constants.d.ts.map +1 -0
- package/dist/config/cli.constants.js +194 -0
- package/dist/config.yml +94 -0
- package/dist/lambda/token-renew-handler.d.ts +2 -0
- package/dist/lambda/token-renew-handler.d.ts.map +1 -0
- package/dist/lambda/token-renew-handler.js +125 -0
- package/dist/templates/events-stack.json +174 -0
- package/dist/templates/token-renew-stack.json +122 -0
- package/dist/types/config.d.ts +53 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +4 -0
- package/dist/types/error.d.ts +61 -0
- package/dist/types/error.d.ts.map +1 -0
- package/dist/types/error.js +35 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +11 -0
- package/dist/types/pipeline-template.d.ts +48 -0
- package/dist/types/pipeline-template.d.ts.map +1 -0
- package/dist/types/pipeline-template.js +4 -0
- package/dist/types/pipeline.d.ts +121 -0
- package/dist/types/pipeline.d.ts.map +1 -0
- package/dist/types/pipeline.js +4 -0
- package/dist/types/plugin.d.ts +135 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +4 -0
- package/dist/utils/api-client.d.ts +26 -0
- package/dist/utils/api-client.d.ts.map +1 -0
- package/dist/utils/api-client.js +151 -0
- package/dist/utils/audit-log.d.ts +8 -0
- package/dist/utils/audit-log.d.ts.map +1 -0
- package/dist/utils/audit-log.js +57 -0
- package/dist/utils/auth-guard.d.ts +20 -0
- package/dist/utils/auth-guard.d.ts.map +1 -0
- package/dist/utils/auth-guard.js +22 -0
- package/dist/utils/auth-utils.d.ts +68 -0
- package/dist/utils/auth-utils.d.ts.map +1 -0
- package/dist/utils/auth-utils.js +77 -0
- package/dist/utils/aws-env.d.ts +21 -0
- package/dist/utils/aws-env.d.ts.map +1 -0
- package/dist/utils/aws-env.js +34 -0
- package/dist/utils/aws-secrets.d.ts +48 -0
- package/dist/utils/aws-secrets.d.ts.map +1 -0
- package/dist/utils/aws-secrets.js +115 -0
- package/dist/utils/banner.d.ts +19 -0
- package/dist/utils/banner.d.ts.map +1 -0
- package/dist/utils/banner.js +52 -0
- package/dist/utils/cdk-utils.d.ts +74 -0
- package/dist/utils/cdk-utils.d.ts.map +1 -0
- package/dist/utils/cdk-utils.js +152 -0
- package/dist/utils/command-utils.d.ts +75 -0
- package/dist/utils/command-utils.d.ts.map +1 -0
- package/dist/utils/command-utils.js +155 -0
- package/dist/utils/config-loader.d.ts +33 -0
- package/dist/utils/config-loader.d.ts.map +1 -0
- package/dist/utils/config-loader.js +154 -0
- package/dist/utils/cron.d.ts +28 -0
- package/dist/utils/cron.d.ts.map +1 -0
- package/dist/utils/cron.js +119 -0
- package/dist/utils/deploy-runner.d.ts +38 -0
- package/dist/utils/deploy-runner.d.ts.map +1 -0
- package/dist/utils/deploy-runner.js +112 -0
- package/dist/utils/error-handler.d.ts +29 -0
- package/dist/utils/error-handler.d.ts.map +1 -0
- package/dist/utils/error-handler.js +302 -0
- package/dist/utils/list-command-utils.d.ts +23 -0
- package/dist/utils/list-command-utils.d.ts.map +1 -0
- package/dist/utils/list-command-utils.js +57 -0
- package/dist/utils/output-utils.d.ts +40 -0
- package/dist/utils/output-utils.d.ts.map +1 -0
- package/dist/utils/output-utils.js +250 -0
- package/dist/utils/pipeline-config.d.ts +33 -0
- package/dist/utils/pipeline-config.d.ts.map +1 -0
- package/dist/utils/pipeline-config.js +55 -0
- package/dist/utils/platform-secret.d.ts +27 -0
- package/dist/utils/platform-secret.d.ts.map +1 -0
- package/dist/utils/platform-secret.js +92 -0
- package/dist/utils/plugin-resolver.d.ts +17 -0
- package/dist/utils/plugin-resolver.d.ts.map +1 -0
- package/dist/utils/plugin-resolver.js +101 -0
- package/dist/utils/preflight.d.ts +26 -0
- package/dist/utils/preflight.d.ts.map +1 -0
- package/dist/utils/preflight.js +59 -0
- package/dist/utils/rate-limiter.d.ts +15 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +164 -0
- package/dist/utils/registry.d.ts +86 -0
- package/dist/utils/registry.d.ts.map +1 -0
- package/dist/utils/registry.js +140 -0
- package/dist/utils/response-utils.d.ts +21 -0
- package/dist/utils/response-utils.d.ts.map +1 -0
- package/dist/utils/response-utils.js +70 -0
- package/dist/utils/tls.d.ts +52 -0
- package/dist/utils/tls.d.ts.map +1 -0
- package/dist/utils/tls.js +88 -0
- package/package.json +181 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { promises as fs } from 'fs';
|
|
4
|
+
import { homedir } from 'os';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
import { parsePlatformBaseUrl } from '@pipeline-builder/pipeline-core';
|
|
7
|
+
import { resolveAwsRegion } from './aws-env.js';
|
|
8
|
+
import { printInfo } from './output-utils.js';
|
|
9
|
+
import { defaultPipelineName } from '../config/cli.constants.js';
|
|
10
|
+
/**
|
|
11
|
+
* Helpers for registering a deployed pipeline ARN with the platform.
|
|
12
|
+
*
|
|
13
|
+
* The registry table maps deployed CodePipeline ARNs back to pipeline records
|
|
14
|
+
* and orgs. It's how the dashboard's "Deployed pipelines" panel and the event
|
|
15
|
+
* reporting Lambda resolve incoming events to a pipeline definition.
|
|
16
|
+
*
|
|
17
|
+
* Two failure modes are handled here:
|
|
18
|
+
*
|
|
19
|
+
* 1. Platform unreachable at deploy time. The CDK stack lands in AWS but the
|
|
20
|
+
* registry POST fails. Without retry the deploy command would have to
|
|
21
|
+
* re-run cdk-deploy (slow, sometimes blocked by stack state) just to
|
|
22
|
+
* record the ARN. Instead, we write a pending intent to a local file;
|
|
23
|
+
* `pipeline-manager pipeline register` drains them.
|
|
24
|
+
*
|
|
25
|
+
* 2. User explicitly invokes `pipeline-manager pipeline register --id <pipelineId>`
|
|
26
|
+
* after a successful deploy that didn't register. Same path: rebuilds
|
|
27
|
+
* the ARN from STS, POSTs to the platform.
|
|
28
|
+
*
|
|
29
|
+
* Pending intents store ONLY the registration payload — never tokens or URLs.
|
|
30
|
+
* Auth is supplied by whichever command drains the intent (deploy or register),
|
|
31
|
+
* so a stale intent file is never an authentication risk.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Platform-sourced registry pull target for the CDK synth, derived from the
|
|
35
|
+
* platform base URL the CLI deploys against (the same host that serves the
|
|
36
|
+
* registry `/v2/` data path via nginx). Reuses pipeline-core's
|
|
37
|
+
* `parsePlatformBaseUrl` so host/port parsing stays identical on both sides.
|
|
38
|
+
* Returns `undefined` for an unparseable/absent URL. (Only the pull host/port
|
|
39
|
+
* are returned — `registry.http` describes the in-cluster push hop, which the
|
|
40
|
+
* synth never reads, so deriving it from the public URL would be misleading.)
|
|
41
|
+
*/
|
|
42
|
+
export function registryOverrideFromBaseUrl(baseUrl) {
|
|
43
|
+
const parsed = parsePlatformBaseUrl(baseUrl);
|
|
44
|
+
return parsed ? { pullHost: parsed.host, pullPort: parsed.port } : undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Bake the platform-derived registry pull target into the synth props
|
|
48
|
+
* (`BuilderProps.registry`) so the CodeBuild image URIs use a host AWS CodeBuild
|
|
49
|
+
* can resolve — not the in-cluster `registry:5000` default. Shared by the
|
|
50
|
+
* `deploy` and `synth` commands.
|
|
51
|
+
*
|
|
52
|
+
* An explicit `IMAGE_REGISTRY_PULL_HOST` in the synth env takes precedence, so
|
|
53
|
+
* this is a no-op when it is set (the synth's `loadRegistryConfig` already
|
|
54
|
+
* honors it). Also a no-op for an unparseable/absent base URL.
|
|
55
|
+
*/
|
|
56
|
+
export function bakePlatformRegistry(props, baseUrl) {
|
|
57
|
+
if (process.env.IMAGE_REGISTRY_PULL_HOST)
|
|
58
|
+
return; // explicit env wins
|
|
59
|
+
const override = registryOverrideFromBaseUrl(baseUrl);
|
|
60
|
+
if (!override)
|
|
61
|
+
return;
|
|
62
|
+
props.registry = override;
|
|
63
|
+
printInfo('Registry pull target', { host: override.pullHost, port: override.pullPort });
|
|
64
|
+
}
|
|
65
|
+
/** Where pending registration intents are persisted between CLI invocations. */
|
|
66
|
+
const PENDING_INTENTS_DIR = join(homedir(), '.pipeline-manager', 'pending-registrations');
|
|
67
|
+
/**
|
|
68
|
+
* Build a RegistryPayload from the platform's pipeline metadata. No AWS calls
|
|
69
|
+
* and no ARN/account: the events Lambda attributes events via the pipeline's
|
|
70
|
+
* `pb.pipeline-id` tag (= pipelineId), so the registry only needs the stable
|
|
71
|
+
* pipelineId + display metadata.
|
|
72
|
+
*/
|
|
73
|
+
export async function buildRegistryPayload(pipeline, regionOverride) {
|
|
74
|
+
const region = resolveAwsRegion(regionOverride);
|
|
75
|
+
const pipelineName = pipeline.pipelineName
|
|
76
|
+
|| defaultPipelineName(pipeline.organization, pipeline.project);
|
|
77
|
+
const stackName = `${pipeline.project}-${pipeline.organization}`.toLowerCase();
|
|
78
|
+
return {
|
|
79
|
+
pipelineId: pipeline.id,
|
|
80
|
+
orgId: pipeline.orgId,
|
|
81
|
+
pipelineName,
|
|
82
|
+
region,
|
|
83
|
+
project: pipeline.project,
|
|
84
|
+
organization: pipeline.organization,
|
|
85
|
+
stackName,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Persist a registration intent for later retry.
|
|
90
|
+
*
|
|
91
|
+
* Intent files are keyed by pipelineId so re-running deploy on the same
|
|
92
|
+
* pipeline overwrites rather than accumulates. We deliberately store the
|
|
93
|
+
* payload plain (not the full pipeline doc, not auth) so a stale file is
|
|
94
|
+
* safe to leave around indefinitely.
|
|
95
|
+
*/
|
|
96
|
+
export async function writePendingIntent(payload) {
|
|
97
|
+
await fs.mkdir(PENDING_INTENTS_DIR, { recursive: true });
|
|
98
|
+
const path = join(PENDING_INTENTS_DIR, `${payload.pipelineId}.json`);
|
|
99
|
+
await fs.writeFile(path, JSON.stringify(payload, null, 2), 'utf8');
|
|
100
|
+
return path;
|
|
101
|
+
}
|
|
102
|
+
/** Remove a pending intent after a successful drain. */
|
|
103
|
+
export async function clearPendingIntent(pipelineId) {
|
|
104
|
+
const path = join(PENDING_INTENTS_DIR, `${pipelineId}.json`);
|
|
105
|
+
try {
|
|
106
|
+
await fs.unlink(path);
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
// ENOENT is fine — already cleared. Anything else is a real problem.
|
|
110
|
+
if (err.code !== 'ENOENT')
|
|
111
|
+
throw err;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/** Read all pending intents currently on disk. Empty array if dir doesn't exist. */
|
|
115
|
+
export async function readPendingIntents() {
|
|
116
|
+
let entries;
|
|
117
|
+
try {
|
|
118
|
+
entries = await fs.readdir(PENDING_INTENTS_DIR);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
if (err.code === 'ENOENT')
|
|
122
|
+
return [];
|
|
123
|
+
throw err;
|
|
124
|
+
}
|
|
125
|
+
const intents = [];
|
|
126
|
+
for (const file of entries) {
|
|
127
|
+
if (!file.endsWith('.json'))
|
|
128
|
+
continue;
|
|
129
|
+
try {
|
|
130
|
+
const text = await fs.readFile(join(PENDING_INTENTS_DIR, file), 'utf8');
|
|
131
|
+
intents.push(JSON.parse(text));
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// Skip unreadable / malformed files — they'll need manual cleanup but
|
|
135
|
+
// shouldn't block valid intents from draining.
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return intents;
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaXN0cnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvcmVnaXN0cnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUsUUFBUSxJQUFJLEVBQUUsRUFBRSxNQUFNLElBQUksQ0FBQztBQUNwQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQzdCLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDNUIsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDdkUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ2hELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUM5QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUVqRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRztBQUVIOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxVQUFVLDJCQUEyQixDQUN6QyxPQUEyQjtJQUUzQixNQUFNLE1BQU0sR0FBRyxvQkFBb0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUM3QyxPQUFPLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLElBQUksRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDL0UsQ0FBQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNILE1BQU0sVUFBVSxvQkFBb0IsQ0FBQyxLQUE4QixFQUFFLE9BQTJCO0lBQzlGLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0I7UUFBRSxPQUFPLENBQUMsb0JBQW9CO0lBQ3RFLE1BQU0sUUFBUSxHQUFHLDJCQUEyQixDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3RELElBQUksQ0FBQyxRQUFRO1FBQUUsT0FBTztJQUN0QixLQUFLLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQztJQUMxQixTQUFTLENBQUMsc0JBQXNCLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxDQUFDLFFBQVEsRUFBRSxJQUFJLEVBQUUsUUFBUSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7QUFDMUYsQ0FBQztBQXNCRCxnRkFBZ0Y7QUFDaEYsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLEVBQUUsbUJBQW1CLEVBQUUsdUJBQXVCLENBQUMsQ0FBQztBQUUxRjs7Ozs7R0FLRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsb0JBQW9CLENBQ3hDLFFBQTZCLEVBQzdCLGNBQXVCO0lBRXZCLE1BQU0sTUFBTSxHQUFHLGdCQUFnQixDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBRWhELE1BQU0sWUFBWSxHQUFHLFFBQVEsQ0FBQyxZQUFZO1dBQ3JDLG1CQUFtQixDQUFDLFFBQVEsQ0FBQyxZQUFZLEVBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ2xFLE1BQU0sU0FBUyxHQUFHLEdBQUcsUUFBUSxDQUFDLE9BQU8sSUFBSSxRQUFRLENBQUMsWUFBWSxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUM7SUFFL0UsT0FBTztRQUNMLFVBQVUsRUFBRSxRQUFRLENBQUMsRUFBRTtRQUN2QixLQUFLLEVBQUUsUUFBUSxDQUFDLEtBQUs7UUFDckIsWUFBWTtRQUNaLE1BQU07UUFDTixPQUFPLEVBQUUsUUFBUSxDQUFDLE9BQU87UUFDekIsWUFBWSxFQUFFLFFBQVEsQ0FBQyxZQUFZO1FBQ25DLFNBQVM7S0FDVixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLGtCQUFrQixDQUFDLE9BQXdCO0lBQy9ELE1BQU0sRUFBRSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3pELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxHQUFHLE9BQU8sQ0FBQyxVQUFVLE9BQU8sQ0FBQyxDQUFDO0lBQ3JFLE1BQU0sRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ25FLE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVELHdEQUF3RDtBQUN4RCxNQUFNLENBQUMsS0FBSyxVQUFVLGtCQUFrQixDQUFDLFVBQWtCO0lBQ3pELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxHQUFHLFVBQVUsT0FBTyxDQUFDLENBQUM7SUFDN0QsSUFBSSxDQUFDO1FBQ0gsTUFBTSxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3hCLENBQUM7SUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQ2IscUVBQXFFO1FBQ3JFLElBQUssR0FBNkIsQ0FBQyxJQUFJLEtBQUssUUFBUTtZQUFFLE1BQU0sR0FBRyxDQUFDO0lBQ2xFLENBQUM7QUFDSCxDQUFDO0FBRUQsb0ZBQW9GO0FBQ3BGLE1BQU0sQ0FBQyxLQUFLLFVBQVUsa0JBQWtCO0lBQ3RDLElBQUksT0FBaUIsQ0FBQztJQUN0QixJQUFJLENBQUM7UUFDSCxPQUFPLEdBQUcsTUFBTSxFQUFFLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixJQUFLLEdBQTZCLENBQUMsSUFBSSxLQUFLLFFBQVE7WUFBRSxPQUFPLEVBQUUsQ0FBQztRQUNoRSxNQUFNLEdBQUcsQ0FBQztJQUNaLENBQUM7SUFFRCxNQUFNLE9BQU8sR0FBc0IsRUFBRSxDQUFDO0lBQ3RDLEtBQUssTUFBTSxJQUFJLElBQUksT0FBTyxFQUFFLENBQUM7UUFDM0IsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO1lBQUUsU0FBUztRQUN0QyxJQUFJLENBQUM7WUFDSCxNQUFNLElBQUksR0FBRyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLG1CQUFtQixFQUFFLElBQUksQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQ3hFLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQW9CLENBQUMsQ0FBQztRQUNwRCxDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1Asc0VBQXNFO1lBQ3RFLCtDQUErQztRQUNqRCxDQUFDO0lBQ0gsQ0FBQztJQUNELE9BQU8sT0FBTyxDQUFDO0FBQ2pCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgcHJvbWlzZXMgYXMgZnMgfSBmcm9tICdmcyc7XG5pbXBvcnQgeyBob21lZGlyIH0gZnJvbSAnb3MnO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgcGFyc2VQbGF0Zm9ybUJhc2VVcmwgfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9waXBlbGluZS1jb3JlJztcbmltcG9ydCB7IHJlc29sdmVBd3NSZWdpb24gfSBmcm9tICcuL2F3cy1lbnYuanMnO1xuaW1wb3J0IHsgcHJpbnRJbmZvIH0gZnJvbSAnLi9vdXRwdXQtdXRpbHMuanMnO1xuaW1wb3J0IHsgZGVmYXVsdFBpcGVsaW5lTmFtZSB9IGZyb20gJy4uL2NvbmZpZy9jbGkuY29uc3RhbnRzLmpzJztcblxuLyoqXG4gKiBIZWxwZXJzIGZvciByZWdpc3RlcmluZyBhIGRlcGxveWVkIHBpcGVsaW5lIEFSTiB3aXRoIHRoZSBwbGF0Zm9ybS5cbiAqXG4gKiBUaGUgcmVnaXN0cnkgdGFibGUgbWFwcyBkZXBsb3llZCBDb2RlUGlwZWxpbmUgQVJOcyBiYWNrIHRvIHBpcGVsaW5lIHJlY29yZHNcbiAqIGFuZCBvcmdzLiBJdCdzIGhvdyB0aGUgZGFzaGJvYXJkJ3MgXCJEZXBsb3llZCBwaXBlbGluZXNcIiBwYW5lbCBhbmQgdGhlIGV2ZW50XG4gKiByZXBvcnRpbmcgTGFtYmRhIHJlc29sdmUgaW5jb21pbmcgZXZlbnRzIHRvIGEgcGlwZWxpbmUgZGVmaW5pdGlvbi5cbiAqXG4gKiBUd28gZmFpbHVyZSBtb2RlcyBhcmUgaGFuZGxlZCBoZXJlOlxuICpcbiAqICAgMS4gUGxhdGZvcm0gdW5yZWFjaGFibGUgYXQgZGVwbG95IHRpbWUuIFRoZSBDREsgc3RhY2sgbGFuZHMgaW4gQVdTIGJ1dCB0aGVcbiAqICAgICAgcmVnaXN0cnkgUE9TVCBmYWlscy4gV2l0aG91dCByZXRyeSB0aGUgZGVwbG95IGNvbW1hbmQgd291bGQgaGF2ZSB0b1xuICogICAgICByZS1ydW4gY2RrLWRlcGxveSAoc2xvdywgc29tZXRpbWVzIGJsb2NrZWQgYnkgc3RhY2sgc3RhdGUpIGp1c3QgdG9cbiAqICAgICAgcmVjb3JkIHRoZSBBUk4uIEluc3RlYWQsIHdlIHdyaXRlIGEgcGVuZGluZyBpbnRlbnQgdG8gYSBsb2NhbCBmaWxlO1xuICogICAgICBgcGlwZWxpbmUtbWFuYWdlciBwaXBlbGluZSByZWdpc3RlcmAgZHJhaW5zIHRoZW0uXG4gKlxuICogICAyLiBVc2VyIGV4cGxpY2l0bHkgaW52b2tlcyBgcGlwZWxpbmUtbWFuYWdlciBwaXBlbGluZSByZWdpc3RlciAtLWlkIDxwaXBlbGluZUlkPmBcbiAqICAgICAgYWZ0ZXIgYSBzdWNjZXNzZnVsIGRlcGxveSB0aGF0IGRpZG4ndCByZWdpc3Rlci4gU2FtZSBwYXRoOiByZWJ1aWxkc1xuICogICAgICB0aGUgQVJOIGZyb20gU1RTLCBQT1NUcyB0byB0aGUgcGxhdGZvcm0uXG4gKlxuICogUGVuZGluZyBpbnRlbnRzIHN0b3JlIE9OTFkgdGhlIHJlZ2lzdHJhdGlvbiBwYXlsb2FkIOKAlCBuZXZlciB0b2tlbnMgb3IgVVJMcy5cbiAqIEF1dGggaXMgc3VwcGxpZWQgYnkgd2hpY2hldmVyIGNvbW1hbmQgZHJhaW5zIHRoZSBpbnRlbnQgKGRlcGxveSBvciByZWdpc3RlciksXG4gKiBzbyBhIHN0YWxlIGludGVudCBmaWxlIGlzIG5ldmVyIGFuIGF1dGhlbnRpY2F0aW9uIHJpc2suXG4gKi9cblxuLyoqXG4gKiBQbGF0Zm9ybS1zb3VyY2VkIHJlZ2lzdHJ5IHB1bGwgdGFyZ2V0IGZvciB0aGUgQ0RLIHN5bnRoLCBkZXJpdmVkIGZyb20gdGhlXG4gKiBwbGF0Zm9ybSBiYXNlIFVSTCB0aGUgQ0xJIGRlcGxveXMgYWdhaW5zdCAodGhlIHNhbWUgaG9zdCB0aGF0IHNlcnZlcyB0aGVcbiAqIHJlZ2lzdHJ5IGAvdjIvYCBkYXRhIHBhdGggdmlhIG5naW54KS4gUmV1c2VzIHBpcGVsaW5lLWNvcmUnc1xuICogYHBhcnNlUGxhdGZvcm1CYXNlVXJsYCBzbyBob3N0L3BvcnQgcGFyc2luZyBzdGF5cyBpZGVudGljYWwgb24gYm90aCBzaWRlcy5cbiAqIFJldHVybnMgYHVuZGVmaW5lZGAgZm9yIGFuIHVucGFyc2VhYmxlL2Fic2VudCBVUkwuIChPbmx5IHRoZSBwdWxsIGhvc3QvcG9ydFxuICogYXJlIHJldHVybmVkIOKAlCBgcmVnaXN0cnkuaHR0cGAgZGVzY3JpYmVzIHRoZSBpbi1jbHVzdGVyIHB1c2ggaG9wLCB3aGljaCB0aGVcbiAqIHN5bnRoIG5ldmVyIHJlYWRzLCBzbyBkZXJpdmluZyBpdCBmcm9tIHRoZSBwdWJsaWMgVVJMIHdvdWxkIGJlIG1pc2xlYWRpbmcuKVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVnaXN0cnlPdmVycmlkZUZyb21CYXNlVXJsKFxuICBiYXNlVXJsOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4pOiB7IHB1bGxIb3N0OiBzdHJpbmc7IHB1bGxQb3J0OiBudW1iZXIgfSB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHBhcnNlZCA9IHBhcnNlUGxhdGZvcm1CYXNlVXJsKGJhc2VVcmwpO1xuICByZXR1cm4gcGFyc2VkID8geyBwdWxsSG9zdDogcGFyc2VkLmhvc3QsIHB1bGxQb3J0OiBwYXJzZWQucG9ydCB9IDogdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIEJha2UgdGhlIHBsYXRmb3JtLWRlcml2ZWQgcmVnaXN0cnkgcHVsbCB0YXJnZXQgaW50byB0aGUgc3ludGggcHJvcHNcbiAqIChgQnVpbGRlclByb3BzLnJlZ2lzdHJ5YCkgc28gdGhlIENvZGVCdWlsZCBpbWFnZSBVUklzIHVzZSBhIGhvc3QgQVdTIENvZGVCdWlsZFxuICogY2FuIHJlc29sdmUg4oCUIG5vdCB0aGUgaW4tY2x1c3RlciBgcmVnaXN0cnk6NTAwMGAgZGVmYXVsdC4gU2hhcmVkIGJ5IHRoZVxuICogYGRlcGxveWAgYW5kIGBzeW50aGAgY29tbWFuZHMuXG4gKlxuICogQW4gZXhwbGljaXQgYElNQUdFX1JFR0lTVFJZX1BVTExfSE9TVGAgaW4gdGhlIHN5bnRoIGVudiB0YWtlcyBwcmVjZWRlbmNlLCBzb1xuICogdGhpcyBpcyBhIG5vLW9wIHdoZW4gaXQgaXMgc2V0ICh0aGUgc3ludGgncyBgbG9hZFJlZ2lzdHJ5Q29uZmlnYCBhbHJlYWR5XG4gKiBob25vcnMgaXQpLiBBbHNvIGEgbm8tb3AgZm9yIGFuIHVucGFyc2VhYmxlL2Fic2VudCBiYXNlIFVSTC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJha2VQbGF0Zm9ybVJlZ2lzdHJ5KHByb3BzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiwgYmFzZVVybDogc3RyaW5nIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gIGlmIChwcm9jZXNzLmVudi5JTUFHRV9SRUdJU1RSWV9QVUxMX0hPU1QpIHJldHVybjsgLy8gZXhwbGljaXQgZW52IHdpbnNcbiAgY29uc3Qgb3ZlcnJpZGUgPSByZWdpc3RyeU92ZXJyaWRlRnJvbUJhc2VVcmwoYmFzZVVybCk7XG4gIGlmICghb3ZlcnJpZGUpIHJldHVybjtcbiAgcHJvcHMucmVnaXN0cnkgPSBvdmVycmlkZTtcbiAgcHJpbnRJbmZvKCdSZWdpc3RyeSBwdWxsIHRhcmdldCcsIHsgaG9zdDogb3ZlcnJpZGUucHVsbEhvc3QsIHBvcnQ6IG92ZXJyaWRlLnB1bGxQb3J0IH0pO1xufVxuXG4vKiogU2hhcGUgb2YgdGhlIGJvZHkgUE9TVGVkIHRvIC9hcGkvcGlwZWxpbmVzL3JlZ2lzdHJ5LiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZWdpc3RyeVBheWxvYWQge1xuICBwaXBlbGluZUlkOiBzdHJpbmc7XG4gIG9yZ0lkOiBzdHJpbmc7XG4gIHBpcGVsaW5lTmFtZTogc3RyaW5nO1xuICByZWdpb246IHN0cmluZztcbiAgcHJvamVjdDogc3RyaW5nO1xuICBvcmdhbml6YXRpb246IHN0cmluZztcbiAgc3RhY2tOYW1lOiBzdHJpbmc7XG59XG5cbi8qKiBQaXBlbGluZSBmaWVsZHMgbmVlZGVkIHRvIGNvbnN0cnVjdCBhIFJlZ2lzdHJ5UGF5bG9hZC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGlwZWxpbmVGb3JSZWdpc3RyeSB7XG4gIGlkOiBzdHJpbmc7XG4gIG9yZ0lkOiBzdHJpbmc7XG4gIHBpcGVsaW5lTmFtZT86IHN0cmluZztcbiAgcHJvamVjdDogc3RyaW5nO1xuICBvcmdhbml6YXRpb246IHN0cmluZztcbn1cblxuLyoqIFdoZXJlIHBlbmRpbmcgcmVnaXN0cmF0aW9uIGludGVudHMgYXJlIHBlcnNpc3RlZCBiZXR3ZWVuIENMSSBpbnZvY2F0aW9ucy4gKi9cbmNvbnN0IFBFTkRJTkdfSU5URU5UU19ESVIgPSBqb2luKGhvbWVkaXIoKSwgJy5waXBlbGluZS1tYW5hZ2VyJywgJ3BlbmRpbmctcmVnaXN0cmF0aW9ucycpO1xuXG4vKipcbiAqIEJ1aWxkIGEgUmVnaXN0cnlQYXlsb2FkIGZyb20gdGhlIHBsYXRmb3JtJ3MgcGlwZWxpbmUgbWV0YWRhdGEuIE5vIEFXUyBjYWxsc1xuICogYW5kIG5vIEFSTi9hY2NvdW50OiB0aGUgZXZlbnRzIExhbWJkYSBhdHRyaWJ1dGVzIGV2ZW50cyB2aWEgdGhlIHBpcGVsaW5lJ3NcbiAqIGBwYi5waXBlbGluZS1pZGAgdGFnICg9IHBpcGVsaW5lSWQpLCBzbyB0aGUgcmVnaXN0cnkgb25seSBuZWVkcyB0aGUgc3RhYmxlXG4gKiBwaXBlbGluZUlkICsgZGlzcGxheSBtZXRhZGF0YS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGJ1aWxkUmVnaXN0cnlQYXlsb2FkKFxuICBwaXBlbGluZTogUGlwZWxpbmVGb3JSZWdpc3RyeSxcbiAgcmVnaW9uT3ZlcnJpZGU/OiBzdHJpbmcsXG4pOiBQcm9taXNlPFJlZ2lzdHJ5UGF5bG9hZD4ge1xuICBjb25zdCByZWdpb24gPSByZXNvbHZlQXdzUmVnaW9uKHJlZ2lvbk92ZXJyaWRlKTtcblxuICBjb25zdCBwaXBlbGluZU5hbWUgPSBwaXBlbGluZS5waXBlbGluZU5hbWVcbiAgICB8fCBkZWZhdWx0UGlwZWxpbmVOYW1lKHBpcGVsaW5lLm9yZ2FuaXphdGlvbiwgcGlwZWxpbmUucHJvamVjdCk7XG4gIGNvbnN0IHN0YWNrTmFtZSA9IGAke3BpcGVsaW5lLnByb2plY3R9LSR7cGlwZWxpbmUub3JnYW5pemF0aW9ufWAudG9Mb3dlckNhc2UoKTtcblxuICByZXR1cm4ge1xuICAgIHBpcGVsaW5lSWQ6IHBpcGVsaW5lLmlkLFxuICAgIG9yZ0lkOiBwaXBlbGluZS5vcmdJZCxcbiAgICBwaXBlbGluZU5hbWUsXG4gICAgcmVnaW9uLFxuICAgIHByb2plY3Q6IHBpcGVsaW5lLnByb2plY3QsXG4gICAgb3JnYW5pemF0aW9uOiBwaXBlbGluZS5vcmdhbml6YXRpb24sXG4gICAgc3RhY2tOYW1lLFxuICB9O1xufVxuXG4vKipcbiAqIFBlcnNpc3QgYSByZWdpc3RyYXRpb24gaW50ZW50IGZvciBsYXRlciByZXRyeS5cbiAqXG4gKiBJbnRlbnQgZmlsZXMgYXJlIGtleWVkIGJ5IHBpcGVsaW5lSWQgc28gcmUtcnVubmluZyBkZXBsb3kgb24gdGhlIHNhbWVcbiAqIHBpcGVsaW5lIG92ZXJ3cml0ZXMgcmF0aGVyIHRoYW4gYWNjdW11bGF0ZXMuIFdlIGRlbGliZXJhdGVseSBzdG9yZSB0aGVcbiAqIHBheWxvYWQgcGxhaW4gKG5vdCB0aGUgZnVsbCBwaXBlbGluZSBkb2MsIG5vdCBhdXRoKSBzbyBhIHN0YWxlIGZpbGUgaXNcbiAqIHNhZmUgdG8gbGVhdmUgYXJvdW5kIGluZGVmaW5pdGVseS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHdyaXRlUGVuZGluZ0ludGVudChwYXlsb2FkOiBSZWdpc3RyeVBheWxvYWQpOiBQcm9taXNlPHN0cmluZz4ge1xuICBhd2FpdCBmcy5ta2RpcihQRU5ESU5HX0lOVEVOVFNfRElSLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgY29uc3QgcGF0aCA9IGpvaW4oUEVORElOR19JTlRFTlRTX0RJUiwgYCR7cGF5bG9hZC5waXBlbGluZUlkfS5qc29uYCk7XG4gIGF3YWl0IGZzLndyaXRlRmlsZShwYXRoLCBKU09OLnN0cmluZ2lmeShwYXlsb2FkLCBudWxsLCAyKSwgJ3V0ZjgnKTtcbiAgcmV0dXJuIHBhdGg7XG59XG5cbi8qKiBSZW1vdmUgYSBwZW5kaW5nIGludGVudCBhZnRlciBhIHN1Y2Nlc3NmdWwgZHJhaW4uICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQZW5kaW5nSW50ZW50KHBpcGVsaW5lSWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBwYXRoID0gam9pbihQRU5ESU5HX0lOVEVOVFNfRElSLCBgJHtwaXBlbGluZUlkfS5qc29uYCk7XG4gIHRyeSB7XG4gICAgYXdhaXQgZnMudW5saW5rKHBhdGgpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICAvLyBFTk9FTlQgaXMgZmluZSDigJQgYWxyZWFkeSBjbGVhcmVkLiBBbnl0aGluZyBlbHNlIGlzIGEgcmVhbCBwcm9ibGVtLlxuICAgIGlmICgoZXJyIGFzIE5vZGVKUy5FcnJub0V4Y2VwdGlvbikuY29kZSAhPT0gJ0VOT0VOVCcpIHRocm93IGVycjtcbiAgfVxufVxuXG4vKiogUmVhZCBhbGwgcGVuZGluZyBpbnRlbnRzIGN1cnJlbnRseSBvbiBkaXNrLiBFbXB0eSBhcnJheSBpZiBkaXIgZG9lc24ndCBleGlzdC4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWFkUGVuZGluZ0ludGVudHMoKTogUHJvbWlzZTxSZWdpc3RyeVBheWxvYWRbXT4ge1xuICBsZXQgZW50cmllczogc3RyaW5nW107XG4gIHRyeSB7XG4gICAgZW50cmllcyA9IGF3YWl0IGZzLnJlYWRkaXIoUEVORElOR19JTlRFTlRTX0RJUik7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGlmICgoZXJyIGFzIE5vZGVKUy5FcnJub0V4Y2VwdGlvbikuY29kZSA9PT0gJ0VOT0VOVCcpIHJldHVybiBbXTtcbiAgICB0aHJvdyBlcnI7XG4gIH1cblxuICBjb25zdCBpbnRlbnRzOiBSZWdpc3RyeVBheWxvYWRbXSA9IFtdO1xuICBmb3IgKGNvbnN0IGZpbGUgb2YgZW50cmllcykge1xuICAgIGlmICghZmlsZS5lbmRzV2l0aCgnLmpzb24nKSkgY29udGludWU7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHRleHQgPSBhd2FpdCBmcy5yZWFkRmlsZShqb2luKFBFTkRJTkdfSU5URU5UU19ESVIsIGZpbGUpLCAndXRmOCcpO1xuICAgICAgaW50ZW50cy5wdXNoKEpTT04ucGFyc2UodGV4dCkgYXMgUmVnaXN0cnlQYXlsb2FkKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIFNraXAgdW5yZWFkYWJsZSAvIG1hbGZvcm1lZCBmaWxlcyDigJQgdGhleSdsbCBuZWVkIG1hbnVhbCBjbGVhbnVwIGJ1dFxuICAgICAgLy8gc2hvdWxkbid0IGJsb2NrIHZhbGlkIGludGVudHMgZnJvbSBkcmFpbmluZy5cbiAgICB9XG4gIH1cbiAgcmV0dXJuIGludGVudHM7XG59XG4iXX0=
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unwrap a sendSuccess API envelope: { success, statusCode, data: { ... } }
|
|
3
|
+
* Returns the inner `data` object, or the original response if not wrapped.
|
|
4
|
+
*/
|
|
5
|
+
export declare function unwrapEnvelope(response: unknown): Record<string, unknown>;
|
|
6
|
+
/**
|
|
7
|
+
* Extract a single entity from an API response, handling envelope formats.
|
|
8
|
+
* Tries: payload[entityKey], payload directly (if identifierKey exists), or undefined.
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractSingleResponse<T>(response: unknown, entityKey: string, identifierKey: string): T | undefined;
|
|
11
|
+
export interface ListResponseResult<T> {
|
|
12
|
+
items: T[];
|
|
13
|
+
total?: number;
|
|
14
|
+
hasMore: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Extract items from an API list response, handling multiple response formats.
|
|
18
|
+
* Supports: `{ <key>: T[] }`, `{ items: T[] }`, `T[]`, or invalid formats.
|
|
19
|
+
*/
|
|
20
|
+
export declare function extractListResponse<T>(response: unknown, itemsKey: string): ListResponseResult<T>;
|
|
21
|
+
//# sourceMappingURL=response-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-utils.d.ts","sourceRoot":"","sources":["../../src/utils/response-utils.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAQnH;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACnC,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAoCjG"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// API response-envelope parsing. Split out of output-utils (which is about
|
|
4
|
+
// rendering) — this is purely about reading the `{ success, data }` shapes the
|
|
5
|
+
// platform returns and pulling out single entities / lists.
|
|
6
|
+
import { printError, printWarning } from './output-utils.js';
|
|
7
|
+
/**
|
|
8
|
+
* Unwrap a sendSuccess API envelope: { success, statusCode, data: { ... } }
|
|
9
|
+
* Returns the inner `data` object, or the original response if not wrapped.
|
|
10
|
+
*/
|
|
11
|
+
export function unwrapEnvelope(response) {
|
|
12
|
+
if (response && typeof response === 'object') {
|
|
13
|
+
const obj = response;
|
|
14
|
+
if ('success' in obj && 'data' in obj && obj.data && typeof obj.data === 'object') {
|
|
15
|
+
return obj.data;
|
|
16
|
+
}
|
|
17
|
+
return obj;
|
|
18
|
+
}
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Extract a single entity from an API response, handling envelope formats.
|
|
23
|
+
* Tries: payload[entityKey], payload directly (if identifierKey exists), or undefined.
|
|
24
|
+
*/
|
|
25
|
+
export function extractSingleResponse(response, entityKey, identifierKey) {
|
|
26
|
+
const payload = unwrapEnvelope(response);
|
|
27
|
+
// Direct entity: payload has the identifier (e.g. payload.id, payload.props, payload.name)
|
|
28
|
+
if (identifierKey in payload)
|
|
29
|
+
return payload;
|
|
30
|
+
// Nested under entity key: payload.pipeline, payload.plugin
|
|
31
|
+
const nested = payload[entityKey];
|
|
32
|
+
if (nested && typeof nested === 'object' && identifierKey in nested)
|
|
33
|
+
return nested;
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Extract items from an API list response, handling multiple response formats.
|
|
38
|
+
* Supports: `{ <key>: T[] }`, `{ items: T[] }`, `T[]`, or invalid formats.
|
|
39
|
+
*/
|
|
40
|
+
export function extractListResponse(response, itemsKey) {
|
|
41
|
+
if (Array.isArray(response)) {
|
|
42
|
+
return { items: response, total: undefined, hasMore: false };
|
|
43
|
+
}
|
|
44
|
+
if (response && typeof response === 'object') {
|
|
45
|
+
const obj = unwrapEnvelope(response);
|
|
46
|
+
// A `{ success, data: [...] }` envelope unwraps to the bare array — return it directly
|
|
47
|
+
// (the `itemsKey in obj` / `'items' in obj` checks below are false for an array, so
|
|
48
|
+
// without this such list envelopes would silently yield zero items).
|
|
49
|
+
if (Array.isArray(obj)) {
|
|
50
|
+
return { items: obj, total: undefined, hasMore: false };
|
|
51
|
+
}
|
|
52
|
+
// Extract pagination metadata if present
|
|
53
|
+
const pagination = obj.pagination;
|
|
54
|
+
const total = (pagination?.total ?? obj.total);
|
|
55
|
+
const hasMore = (pagination?.hasMore ?? obj.hasMore) || false;
|
|
56
|
+
// Try primary key (e.g. 'pipelines', 'plugins')
|
|
57
|
+
if (itemsKey in obj && Array.isArray(obj[itemsKey])) {
|
|
58
|
+
return { items: obj[itemsKey], total, hasMore };
|
|
59
|
+
}
|
|
60
|
+
// Try generic 'items' key
|
|
61
|
+
if ('items' in obj && Array.isArray(obj.items)) {
|
|
62
|
+
return { items: obj.items, total, hasMore };
|
|
63
|
+
}
|
|
64
|
+
printWarning('Unexpected response format, attempting to handle');
|
|
65
|
+
return { items: [], total: undefined, hasMore: false };
|
|
66
|
+
}
|
|
67
|
+
printError('Invalid response format from API');
|
|
68
|
+
throw new Error('Unexpected API response format');
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzcG9uc2UtdXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvcmVzcG9uc2UtdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QywyRUFBMkU7QUFDM0UsK0VBQStFO0FBQy9FLDREQUE0RDtBQUU1RCxPQUFPLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRTdEOzs7R0FHRztBQUNILE1BQU0sVUFBVSxjQUFjLENBQUMsUUFBaUI7SUFDOUMsSUFBSSxRQUFRLElBQUksT0FBTyxRQUFRLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDN0MsTUFBTSxHQUFHLEdBQUcsUUFBbUMsQ0FBQztRQUNoRCxJQUFJLFNBQVMsSUFBSSxHQUFHLElBQUksTUFBTSxJQUFJLEdBQUcsSUFBSSxHQUFHLENBQUMsSUFBSSxJQUFJLE9BQU8sR0FBRyxDQUFDLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUNsRixPQUFPLEdBQUcsQ0FBQyxJQUErQixDQUFDO1FBQzdDLENBQUM7UUFDRCxPQUFPLEdBQUcsQ0FBQztJQUNiLENBQUM7SUFDRCxPQUFPLEVBQUUsQ0FBQztBQUNaLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUscUJBQXFCLENBQUksUUFBaUIsRUFBRSxTQUFpQixFQUFFLGFBQXFCO0lBQ2xHLE1BQU0sT0FBTyxHQUFHLGNBQWMsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN6QywyRkFBMkY7SUFDM0YsSUFBSSxhQUFhLElBQUksT0FBTztRQUFFLE9BQU8sT0FBdUIsQ0FBQztJQUM3RCw0REFBNEQ7SUFDNUQsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBd0MsQ0FBQztJQUN6RSxJQUFJLE1BQU0sSUFBSSxPQUFPLE1BQU0sS0FBSyxRQUFRLElBQUksYUFBYSxJQUFJLE1BQU07UUFBRSxPQUFPLE1BQXNCLENBQUM7SUFDbkcsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQVFEOzs7R0FHRztBQUNILE1BQU0sVUFBVSxtQkFBbUIsQ0FBSSxRQUFpQixFQUFFLFFBQWdCO0lBQ3hFLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1FBQzVCLE9BQU8sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxDQUFDO0lBQy9ELENBQUM7SUFFRCxJQUFJLFFBQVEsSUFBSSxPQUFPLFFBQVEsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUM3QyxNQUFNLEdBQUcsR0FBRyxjQUFjLENBQUMsUUFBUSxDQUFDLENBQUM7UUFFckMsdUZBQXVGO1FBQ3ZGLG9GQUFvRjtRQUNwRixxRUFBcUU7UUFDckUsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDdkIsT0FBTyxFQUFFLEtBQUssRUFBRSxHQUFVLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUM7UUFDakUsQ0FBQztRQUVELHlDQUF5QztRQUN6QyxNQUFNLFVBQVUsR0FBRyxHQUFHLENBQUMsVUFBaUQsQ0FBQztRQUN6RSxNQUFNLEtBQUssR0FBRyxDQUFDLFVBQVUsRUFBRSxLQUFLLElBQUksR0FBRyxDQUFDLEtBQUssQ0FBdUIsQ0FBQztRQUNyRSxNQUFNLE9BQU8sR0FBSSxDQUFDLFVBQVUsRUFBRSxPQUFPLElBQUksR0FBRyxDQUFDLE9BQU8sQ0FBYSxJQUFJLEtBQUssQ0FBQztRQUUzRSxnREFBZ0Q7UUFDaEQsSUFBSSxRQUFRLElBQUksR0FBRyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNwRCxPQUFPLEVBQUUsS0FBSyxFQUFFLEdBQUcsQ0FBQyxRQUFRLENBQVEsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUM7UUFDekQsQ0FBQztRQUVELDBCQUEwQjtRQUMxQixJQUFJLE9BQU8sSUFBSSxHQUFHLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUMvQyxPQUFPLEVBQUUsS0FBSyxFQUFFLEdBQUcsQ0FBQyxLQUFZLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxDQUFDO1FBQ3JELENBQUM7UUFFRCxZQUFZLENBQUMsa0RBQWtELENBQUMsQ0FBQztRQUNqRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsQ0FBQztJQUN6RCxDQUFDO0lBRUQsVUFBVSxDQUFDLGtDQUFrQyxDQUFDLENBQUM7SUFDL0MsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO0FBQ3BELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLy8gQVBJIHJlc3BvbnNlLWVudmVsb3BlIHBhcnNpbmcuIFNwbGl0IG91dCBvZiBvdXRwdXQtdXRpbHMgKHdoaWNoIGlzIGFib3V0XG4vLyByZW5kZXJpbmcpIOKAlCB0aGlzIGlzIHB1cmVseSBhYm91dCByZWFkaW5nIHRoZSBgeyBzdWNjZXNzLCBkYXRhIH1gIHNoYXBlcyB0aGVcbi8vIHBsYXRmb3JtIHJldHVybnMgYW5kIHB1bGxpbmcgb3V0IHNpbmdsZSBlbnRpdGllcyAvIGxpc3RzLlxuXG5pbXBvcnQgeyBwcmludEVycm9yLCBwcmludFdhcm5pbmcgfSBmcm9tICcuL291dHB1dC11dGlscy5qcyc7XG5cbi8qKlxuICogVW53cmFwIGEgc2VuZFN1Y2Nlc3MgQVBJIGVudmVsb3BlOiB7IHN1Y2Nlc3MsIHN0YXR1c0NvZGUsIGRhdGE6IHsgLi4uIH0gfVxuICogUmV0dXJucyB0aGUgaW5uZXIgYGRhdGFgIG9iamVjdCwgb3IgdGhlIG9yaWdpbmFsIHJlc3BvbnNlIGlmIG5vdCB3cmFwcGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdW53cmFwRW52ZWxvcGUocmVzcG9uc2U6IHVua25vd24pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIGlmIChyZXNwb25zZSAmJiB0eXBlb2YgcmVzcG9uc2UgPT09ICdvYmplY3QnKSB7XG4gICAgY29uc3Qgb2JqID0gcmVzcG9uc2UgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgaWYgKCdzdWNjZXNzJyBpbiBvYmogJiYgJ2RhdGEnIGluIG9iaiAmJiBvYmouZGF0YSAmJiB0eXBlb2Ygb2JqLmRhdGEgPT09ICdvYmplY3QnKSB7XG4gICAgICByZXR1cm4gb2JqLmRhdGEgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgfVxuICAgIHJldHVybiBvYmo7XG4gIH1cbiAgcmV0dXJuIHt9O1xufVxuXG4vKipcbiAqIEV4dHJhY3QgYSBzaW5nbGUgZW50aXR5IGZyb20gYW4gQVBJIHJlc3BvbnNlLCBoYW5kbGluZyBlbnZlbG9wZSBmb3JtYXRzLlxuICogVHJpZXM6IHBheWxvYWRbZW50aXR5S2V5XSwgcGF5bG9hZCBkaXJlY3RseSAoaWYgaWRlbnRpZmllcktleSBleGlzdHMpLCBvciB1bmRlZmluZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0U2luZ2xlUmVzcG9uc2U8VD4ocmVzcG9uc2U6IHVua25vd24sIGVudGl0eUtleTogc3RyaW5nLCBpZGVudGlmaWVyS2V5OiBzdHJpbmcpOiBUIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgcGF5bG9hZCA9IHVud3JhcEVudmVsb3BlKHJlc3BvbnNlKTtcbiAgLy8gRGlyZWN0IGVudGl0eTogcGF5bG9hZCBoYXMgdGhlIGlkZW50aWZpZXIgKGUuZy4gcGF5bG9hZC5pZCwgcGF5bG9hZC5wcm9wcywgcGF5bG9hZC5uYW1lKVxuICBpZiAoaWRlbnRpZmllcktleSBpbiBwYXlsb2FkKSByZXR1cm4gcGF5bG9hZCBhcyB1bmtub3duIGFzIFQ7XG4gIC8vIE5lc3RlZCB1bmRlciBlbnRpdHkga2V5OiBwYXlsb2FkLnBpcGVsaW5lLCBwYXlsb2FkLnBsdWdpblxuICBjb25zdCBuZXN0ZWQgPSBwYXlsb2FkW2VudGl0eUtleV0gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWQ7XG4gIGlmIChuZXN0ZWQgJiYgdHlwZW9mIG5lc3RlZCA9PT0gJ29iamVjdCcgJiYgaWRlbnRpZmllcktleSBpbiBuZXN0ZWQpIHJldHVybiBuZXN0ZWQgYXMgdW5rbm93biBhcyBUO1xuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIExpc3RSZXNwb25zZVJlc3VsdDxUPiB7XG4gIGl0ZW1zOiBUW107XG4gIHRvdGFsPzogbnVtYmVyO1xuICBoYXNNb3JlOiBib29sZWFuO1xufVxuXG4vKipcbiAqIEV4dHJhY3QgaXRlbXMgZnJvbSBhbiBBUEkgbGlzdCByZXNwb25zZSwgaGFuZGxpbmcgbXVsdGlwbGUgcmVzcG9uc2UgZm9ybWF0cy5cbiAqIFN1cHBvcnRzOiBgeyA8a2V5PjogVFtdIH1gLCBgeyBpdGVtczogVFtdIH1gLCBgVFtdYCwgb3IgaW52YWxpZCBmb3JtYXRzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdExpc3RSZXNwb25zZTxUPihyZXNwb25zZTogdW5rbm93biwgaXRlbXNLZXk6IHN0cmluZyk6IExpc3RSZXNwb25zZVJlc3VsdDxUPiB7XG4gIGlmIChBcnJheS5pc0FycmF5KHJlc3BvbnNlKSkge1xuICAgIHJldHVybiB7IGl0ZW1zOiByZXNwb25zZSwgdG90YWw6IHVuZGVmaW5lZCwgaGFzTW9yZTogZmFsc2UgfTtcbiAgfVxuXG4gIGlmIChyZXNwb25zZSAmJiB0eXBlb2YgcmVzcG9uc2UgPT09ICdvYmplY3QnKSB7XG4gICAgY29uc3Qgb2JqID0gdW53cmFwRW52ZWxvcGUocmVzcG9uc2UpO1xuXG4gICAgLy8gQSBgeyBzdWNjZXNzLCBkYXRhOiBbLi4uXSB9YCBlbnZlbG9wZSB1bndyYXBzIHRvIHRoZSBiYXJlIGFycmF5IOKAlCByZXR1cm4gaXQgZGlyZWN0bHlcbiAgICAvLyAodGhlIGBpdGVtc0tleSBpbiBvYmpgIC8gYCdpdGVtcycgaW4gb2JqYCBjaGVja3MgYmVsb3cgYXJlIGZhbHNlIGZvciBhbiBhcnJheSwgc29cbiAgICAvLyB3aXRob3V0IHRoaXMgc3VjaCBsaXN0IGVudmVsb3BlcyB3b3VsZCBzaWxlbnRseSB5aWVsZCB6ZXJvIGl0ZW1zKS5cbiAgICBpZiAoQXJyYXkuaXNBcnJheShvYmopKSB7XG4gICAgICByZXR1cm4geyBpdGVtczogb2JqIGFzIFRbXSwgdG90YWw6IHVuZGVmaW5lZCwgaGFzTW9yZTogZmFsc2UgfTtcbiAgICB9XG5cbiAgICAvLyBFeHRyYWN0IHBhZ2luYXRpb24gbWV0YWRhdGEgaWYgcHJlc2VudFxuICAgIGNvbnN0IHBhZ2luYXRpb24gPSBvYmoucGFnaW5hdGlvbiBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZDtcbiAgICBjb25zdCB0b3RhbCA9IChwYWdpbmF0aW9uPy50b3RhbCA/PyBvYmoudG90YWwpIGFzIG51bWJlciB8IHVuZGVmaW5lZDtcbiAgICBjb25zdCBoYXNNb3JlID0gKChwYWdpbmF0aW9uPy5oYXNNb3JlID8/IG9iai5oYXNNb3JlKSBhcyBib29sZWFuKSB8fCBmYWxzZTtcblxuICAgIC8vIFRyeSBwcmltYXJ5IGtleSAoZS5nLiAncGlwZWxpbmVzJywgJ3BsdWdpbnMnKVxuICAgIGlmIChpdGVtc0tleSBpbiBvYmogJiYgQXJyYXkuaXNBcnJheShvYmpbaXRlbXNLZXldKSkge1xuICAgICAgcmV0dXJuIHsgaXRlbXM6IG9ialtpdGVtc0tleV0gYXMgVFtdLCB0b3RhbCwgaGFzTW9yZSB9O1xuICAgIH1cblxuICAgIC8vIFRyeSBnZW5lcmljICdpdGVtcycga2V5XG4gICAgaWYgKCdpdGVtcycgaW4gb2JqICYmIEFycmF5LmlzQXJyYXkob2JqLml0ZW1zKSkge1xuICAgICAgcmV0dXJuIHsgaXRlbXM6IG9iai5pdGVtcyBhcyBUW10sIHRvdGFsLCBoYXNNb3JlIH07XG4gICAgfVxuXG4gICAgcHJpbnRXYXJuaW5nKCdVbmV4cGVjdGVkIHJlc3BvbnNlIGZvcm1hdCwgYXR0ZW1wdGluZyB0byBoYW5kbGUnKTtcbiAgICByZXR1cm4geyBpdGVtczogW10sIHRvdGFsOiB1bmRlZmluZWQsIGhhc01vcmU6IGZhbHNlIH07XG4gIH1cblxuICBwcmludEVycm9yKCdJbnZhbGlkIHJlc3BvbnNlIGZvcm1hdCBmcm9tIEFQSScpO1xuICB0aHJvdyBuZXcgRXJyb3IoJ1VuZXhwZWN0ZWQgQVBJIHJlc3BvbnNlIGZvcm1hdCcpO1xufVxuIl19
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import https from 'https';
|
|
2
|
+
/**
|
|
3
|
+
* Hosts that legitimately front a self-signed certificate — local dev stacks and
|
|
4
|
+
* kubectl port-forwards. Everything else (a real deploy domain) is expected to
|
|
5
|
+
* present a valid (ACM) certificate and MUST be verified, so a post-deploy probe
|
|
6
|
+
* can't be silently MITM'd.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isLocalHttpsHost(url: string): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Return an https.Agent that skips certificate verification ONLY for local /
|
|
11
|
+
* self-signed hosts; returns `undefined` (Node's default verification) for real
|
|
12
|
+
* domains. Pass the result straight to axios' `httpsAgent` — `undefined` keeps the
|
|
13
|
+
* default secure behavior.
|
|
14
|
+
*/
|
|
15
|
+
export declare function httpsAgentForUrl(url: string): https.Agent | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Single source of truth for "is this a production run?" — the whole CLI keys its
|
|
18
|
+
* TLS-disable refusal off `NODE_ENV=production`. Centralized here (rather than a
|
|
19
|
+
* bare `process.env.NODE_ENV === 'production'` copied into config-loader, login,
|
|
20
|
+
* platform-secret and the renew handler) so the policy can't drift between the
|
|
21
|
+
* paths that transmit passwords/JWTs and the paths that merely read config.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isProductionEnv(): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Guard for the credential-transmitting SSL-disable paths (login, inline-login,
|
|
26
|
+
* token renewal, and every authenticated command via `getConfigWithOptions`).
|
|
27
|
+
*
|
|
28
|
+
* When a caller asks to disable certificate verification AND the run is
|
|
29
|
+
* production, this THROWS a clear error rather than silently proceeding — a MITM
|
|
30
|
+
* on a "prod with --no-verify-ssl" run would otherwise harvest the very
|
|
31
|
+
* passwords/JWTs these paths send. In non-production it is a no-op, so
|
|
32
|
+
* `--no-verify-ssl` / `PLATFORM_VERIFY_SSL=false` still work against self-signed
|
|
33
|
+
* dev platforms.
|
|
34
|
+
*
|
|
35
|
+
* @param context - short description of the path being guarded, for the message.
|
|
36
|
+
* @throws Error in production; returns `void` otherwise.
|
|
37
|
+
*/
|
|
38
|
+
export declare function assertSslDisableAllowed(context?: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* Apply the `--no-verify-ssl` relaxation as a process-wide env flag
|
|
41
|
+
* (`NODE_TLS_REJECT_UNAUTHORIZED=0`) so spawned CDK subprocesses (Lambda,
|
|
42
|
+
* CodeBuild synth) inherit it — but REFUSE in production, mirroring the guard in
|
|
43
|
+
* config-loader. That flag disables certificate validation for ALL outbound TLS
|
|
44
|
+
* (including the AWS SDK), so it must never be silently enabled for a prod
|
|
45
|
+
* deploy/synth.
|
|
46
|
+
*
|
|
47
|
+
* @param verifySsl - the command's `--verify-ssl` value (`false` = user asked to disable).
|
|
48
|
+
* @param warn - warning sink (e.g. `printWarning`).
|
|
49
|
+
* @returns true if verification was disabled; false if left enabled.
|
|
50
|
+
*/
|
|
51
|
+
export declare function relaxTlsForCli(verifySsl: boolean | undefined, warn: (message: string) => void): boolean;
|
|
52
|
+
//# sourceMappingURL=tls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tls.d.ts","sourceRoot":"","sources":["../../src/utils/tls.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAgBrD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,KAAK,GAAG,SAAS,CAErE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAQ9D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,OAAO,GAAG,SAAS,EAC9B,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAC9B,OAAO,CAQT"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import https from 'https';
|
|
4
|
+
/**
|
|
5
|
+
* Hosts that legitimately front a self-signed certificate — local dev stacks and
|
|
6
|
+
* kubectl port-forwards. Everything else (a real deploy domain) is expected to
|
|
7
|
+
* present a valid (ACM) certificate and MUST be verified, so a post-deploy probe
|
|
8
|
+
* can't be silently MITM'd.
|
|
9
|
+
*/
|
|
10
|
+
export function isLocalHttpsHost(url) {
|
|
11
|
+
let hostname;
|
|
12
|
+
try {
|
|
13
|
+
hostname = new URL(url).hostname;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return (hostname === 'localhost' ||
|
|
19
|
+
hostname === '127.0.0.1' ||
|
|
20
|
+
hostname === '::1' ||
|
|
21
|
+
hostname.endsWith('.local') ||
|
|
22
|
+
/^10\./.test(hostname) ||
|
|
23
|
+
/^192\.168\./.test(hostname) ||
|
|
24
|
+
/^172\.(1[6-9]|2\d|3[01])\./.test(hostname));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Return an https.Agent that skips certificate verification ONLY for local /
|
|
28
|
+
* self-signed hosts; returns `undefined` (Node's default verification) for real
|
|
29
|
+
* domains. Pass the result straight to axios' `httpsAgent` — `undefined` keeps the
|
|
30
|
+
* default secure behavior.
|
|
31
|
+
*/
|
|
32
|
+
export function httpsAgentForUrl(url) {
|
|
33
|
+
return isLocalHttpsHost(url) ? new https.Agent({ rejectUnauthorized: false }) : undefined;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Single source of truth for "is this a production run?" — the whole CLI keys its
|
|
37
|
+
* TLS-disable refusal off `NODE_ENV=production`. Centralized here (rather than a
|
|
38
|
+
* bare `process.env.NODE_ENV === 'production'` copied into config-loader, login,
|
|
39
|
+
* platform-secret and the renew handler) so the policy can't drift between the
|
|
40
|
+
* paths that transmit passwords/JWTs and the paths that merely read config.
|
|
41
|
+
*/
|
|
42
|
+
export function isProductionEnv() {
|
|
43
|
+
return process.env.NODE_ENV === 'production';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Guard for the credential-transmitting SSL-disable paths (login, inline-login,
|
|
47
|
+
* token renewal, and every authenticated command via `getConfigWithOptions`).
|
|
48
|
+
*
|
|
49
|
+
* When a caller asks to disable certificate verification AND the run is
|
|
50
|
+
* production, this THROWS a clear error rather than silently proceeding — a MITM
|
|
51
|
+
* on a "prod with --no-verify-ssl" run would otherwise harvest the very
|
|
52
|
+
* passwords/JWTs these paths send. In non-production it is a no-op, so
|
|
53
|
+
* `--no-verify-ssl` / `PLATFORM_VERIFY_SSL=false` still work against self-signed
|
|
54
|
+
* dev platforms.
|
|
55
|
+
*
|
|
56
|
+
* @param context - short description of the path being guarded, for the message.
|
|
57
|
+
* @throws Error in production; returns `void` otherwise.
|
|
58
|
+
*/
|
|
59
|
+
export function assertSslDisableAllowed(context) {
|
|
60
|
+
if (isProductionEnv()) {
|
|
61
|
+
throw new Error(`Refusing to disable TLS certificate verification in production (NODE_ENV=production)${context ? ` — ${context}` : ''}. `
|
|
62
|
+
+ 'Credentials and tokens must never be transmitted over an unverified TLS connection. '
|
|
63
|
+
+ 'Use a platform with a valid certificate, or unset NODE_ENV for local/self-signed development.');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Apply the `--no-verify-ssl` relaxation as a process-wide env flag
|
|
68
|
+
* (`NODE_TLS_REJECT_UNAUTHORIZED=0`) so spawned CDK subprocesses (Lambda,
|
|
69
|
+
* CodeBuild synth) inherit it — but REFUSE in production, mirroring the guard in
|
|
70
|
+
* config-loader. That flag disables certificate validation for ALL outbound TLS
|
|
71
|
+
* (including the AWS SDK), so it must never be silently enabled for a prod
|
|
72
|
+
* deploy/synth.
|
|
73
|
+
*
|
|
74
|
+
* @param verifySsl - the command's `--verify-ssl` value (`false` = user asked to disable).
|
|
75
|
+
* @param warn - warning sink (e.g. `printWarning`).
|
|
76
|
+
* @returns true if verification was disabled; false if left enabled.
|
|
77
|
+
*/
|
|
78
|
+
export function relaxTlsForCli(verifySsl, warn) {
|
|
79
|
+
if (verifySsl !== false)
|
|
80
|
+
return false;
|
|
81
|
+
if (isProductionEnv()) {
|
|
82
|
+
warn('Refusing to disable TLS verification in production (NODE_ENV=production) — certificate validation remains enabled.');
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL3Rscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUUxQjs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxnQkFBZ0IsQ0FBQyxHQUFXO0lBQzFDLElBQUksUUFBZ0IsQ0FBQztJQUNyQixJQUFJLENBQUM7UUFDSCxRQUFRLEdBQUcsSUFBSSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDO0lBQ25DLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFDRCxPQUFPLENBQ0wsUUFBUSxLQUFLLFdBQVc7UUFDeEIsUUFBUSxLQUFLLFdBQVc7UUFDeEIsUUFBUSxLQUFLLEtBQUs7UUFDbEIsUUFBUSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUM7UUFDM0IsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUM7UUFDdEIsYUFBYSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUM7UUFDNUIsNEJBQTRCLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUM1QyxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLGdCQUFnQixDQUFDLEdBQVc7SUFDMUMsT0FBTyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLENBQUMsS0FBSyxDQUFDLEVBQUUsa0JBQWtCLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0FBQzVGLENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsZUFBZTtJQUM3QixPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxLQUFLLFlBQVksQ0FBQztBQUMvQyxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILE1BQU0sVUFBVSx1QkFBdUIsQ0FBQyxPQUFnQjtJQUN0RCxJQUFJLGVBQWUsRUFBRSxFQUFFLENBQUM7UUFDdEIsTUFBTSxJQUFJLEtBQUssQ0FDYix1RkFBdUYsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUk7Y0FDdkgsc0ZBQXNGO2NBQ3RGLCtGQUErRixDQUNsRyxDQUFDO0lBQ0osQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7Ozs7Ozs7R0FXRztBQUNILE1BQU0sVUFBVSxjQUFjLENBQzVCLFNBQThCLEVBQzlCLElBQStCO0lBRS9CLElBQUksU0FBUyxLQUFLLEtBQUs7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUN0QyxJQUFJLGVBQWUsRUFBRSxFQUFFLENBQUM7UUFDdEIsSUFBSSxDQUFDLG9IQUFvSCxDQUFDLENBQUM7UUFDM0gsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyw0QkFBNEIsR0FBRyxHQUFHLENBQUM7SUFDL0MsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XG5cbi8qKlxuICogSG9zdHMgdGhhdCBsZWdpdGltYXRlbHkgZnJvbnQgYSBzZWxmLXNpZ25lZCBjZXJ0aWZpY2F0ZSDigJQgbG9jYWwgZGV2IHN0YWNrcyBhbmRcbiAqIGt1YmVjdGwgcG9ydC1mb3J3YXJkcy4gRXZlcnl0aGluZyBlbHNlIChhIHJlYWwgZGVwbG95IGRvbWFpbikgaXMgZXhwZWN0ZWQgdG9cbiAqIHByZXNlbnQgYSB2YWxpZCAoQUNNKSBjZXJ0aWZpY2F0ZSBhbmQgTVVTVCBiZSB2ZXJpZmllZCwgc28gYSBwb3N0LWRlcGxveSBwcm9iZVxuICogY2FuJ3QgYmUgc2lsZW50bHkgTUlUTSdkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNMb2NhbEh0dHBzSG9zdCh1cmw6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBsZXQgaG9zdG5hbWU6IHN0cmluZztcbiAgdHJ5IHtcbiAgICBob3N0bmFtZSA9IG5ldyBVUkwodXJsKS5ob3N0bmFtZTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiAoXG4gICAgaG9zdG5hbWUgPT09ICdsb2NhbGhvc3QnIHx8XG4gICAgaG9zdG5hbWUgPT09ICcxMjcuMC4wLjEnIHx8XG4gICAgaG9zdG5hbWUgPT09ICc6OjEnIHx8XG4gICAgaG9zdG5hbWUuZW5kc1dpdGgoJy5sb2NhbCcpIHx8XG4gICAgL14xMFxcLi8udGVzdChob3N0bmFtZSkgfHxcbiAgICAvXjE5MlxcLjE2OFxcLi8udGVzdChob3N0bmFtZSkgfHxcbiAgICAvXjE3MlxcLigxWzYtOV18MlxcZHwzWzAxXSlcXC4vLnRlc3QoaG9zdG5hbWUpXG4gICk7XG59XG5cbi8qKlxuICogUmV0dXJuIGFuIGh0dHBzLkFnZW50IHRoYXQgc2tpcHMgY2VydGlmaWNhdGUgdmVyaWZpY2F0aW9uIE9OTFkgZm9yIGxvY2FsIC9cbiAqIHNlbGYtc2lnbmVkIGhvc3RzOyByZXR1cm5zIGB1bmRlZmluZWRgIChOb2RlJ3MgZGVmYXVsdCB2ZXJpZmljYXRpb24pIGZvciByZWFsXG4gKiBkb21haW5zLiBQYXNzIHRoZSByZXN1bHQgc3RyYWlnaHQgdG8gYXhpb3MnIGBodHRwc0FnZW50YCDigJQgYHVuZGVmaW5lZGAga2VlcHMgdGhlXG4gKiBkZWZhdWx0IHNlY3VyZSBiZWhhdmlvci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGh0dHBzQWdlbnRGb3JVcmwodXJsOiBzdHJpbmcpOiBodHRwcy5BZ2VudCB8IHVuZGVmaW5lZCB7XG4gIHJldHVybiBpc0xvY2FsSHR0cHNIb3N0KHVybCkgPyBuZXcgaHR0cHMuQWdlbnQoeyByZWplY3RVbmF1dGhvcml6ZWQ6IGZhbHNlIH0pIDogdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFNpbmdsZSBzb3VyY2Ugb2YgdHJ1dGggZm9yIFwiaXMgdGhpcyBhIHByb2R1Y3Rpb24gcnVuP1wiIOKAlCB0aGUgd2hvbGUgQ0xJIGtleXMgaXRzXG4gKiBUTFMtZGlzYWJsZSByZWZ1c2FsIG9mZiBgTk9ERV9FTlY9cHJvZHVjdGlvbmAuIENlbnRyYWxpemVkIGhlcmUgKHJhdGhlciB0aGFuIGFcbiAqIGJhcmUgYHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSAncHJvZHVjdGlvbidgIGNvcGllZCBpbnRvIGNvbmZpZy1sb2FkZXIsIGxvZ2luLFxuICogcGxhdGZvcm0tc2VjcmV0IGFuZCB0aGUgcmVuZXcgaGFuZGxlcikgc28gdGhlIHBvbGljeSBjYW4ndCBkcmlmdCBiZXR3ZWVuIHRoZVxuICogcGF0aHMgdGhhdCB0cmFuc21pdCBwYXNzd29yZHMvSldUcyBhbmQgdGhlIHBhdGhzIHRoYXQgbWVyZWx5IHJlYWQgY29uZmlnLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNQcm9kdWN0aW9uRW52KCk6IGJvb2xlYW4ge1xuICByZXR1cm4gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09ICdwcm9kdWN0aW9uJztcbn1cblxuLyoqXG4gKiBHdWFyZCBmb3IgdGhlIGNyZWRlbnRpYWwtdHJhbnNtaXR0aW5nIFNTTC1kaXNhYmxlIHBhdGhzIChsb2dpbiwgaW5saW5lLWxvZ2luLFxuICogdG9rZW4gcmVuZXdhbCwgYW5kIGV2ZXJ5IGF1dGhlbnRpY2F0ZWQgY29tbWFuZCB2aWEgYGdldENvbmZpZ1dpdGhPcHRpb25zYCkuXG4gKlxuICogV2hlbiBhIGNhbGxlciBhc2tzIHRvIGRpc2FibGUgY2VydGlmaWNhdGUgdmVyaWZpY2F0aW9uIEFORCB0aGUgcnVuIGlzXG4gKiBwcm9kdWN0aW9uLCB0aGlzIFRIUk9XUyBhIGNsZWFyIGVycm9yIHJhdGhlciB0aGFuIHNpbGVudGx5IHByb2NlZWRpbmcg4oCUIGEgTUlUTVxuICogb24gYSBcInByb2Qgd2l0aCAtLW5vLXZlcmlmeS1zc2xcIiBydW4gd291bGQgb3RoZXJ3aXNlIGhhcnZlc3QgdGhlIHZlcnlcbiAqIHBhc3N3b3Jkcy9KV1RzIHRoZXNlIHBhdGhzIHNlbmQuIEluIG5vbi1wcm9kdWN0aW9uIGl0IGlzIGEgbm8tb3AsIHNvXG4gKiBgLS1uby12ZXJpZnktc3NsYCAvIGBQTEFURk9STV9WRVJJRllfU1NMPWZhbHNlYCBzdGlsbCB3b3JrIGFnYWluc3Qgc2VsZi1zaWduZWRcbiAqIGRldiBwbGF0Zm9ybXMuXG4gKlxuICogQHBhcmFtIGNvbnRleHQgLSBzaG9ydCBkZXNjcmlwdGlvbiBvZiB0aGUgcGF0aCBiZWluZyBndWFyZGVkLCBmb3IgdGhlIG1lc3NhZ2UuXG4gKiBAdGhyb3dzIEVycm9yIGluIHByb2R1Y3Rpb247IHJldHVybnMgYHZvaWRgIG90aGVyd2lzZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFzc2VydFNzbERpc2FibGVBbGxvd2VkKGNvbnRleHQ/OiBzdHJpbmcpOiB2b2lkIHtcbiAgaWYgKGlzUHJvZHVjdGlvbkVudigpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYFJlZnVzaW5nIHRvIGRpc2FibGUgVExTIGNlcnRpZmljYXRlIHZlcmlmaWNhdGlvbiBpbiBwcm9kdWN0aW9uIChOT0RFX0VOVj1wcm9kdWN0aW9uKSR7Y29udGV4dCA/IGAg4oCUICR7Y29udGV4dH1gIDogJyd9LiBgXG4gICAgICArICdDcmVkZW50aWFscyBhbmQgdG9rZW5zIG11c3QgbmV2ZXIgYmUgdHJhbnNtaXR0ZWQgb3ZlciBhbiB1bnZlcmlmaWVkIFRMUyBjb25uZWN0aW9uLiAnXG4gICAgICArICdVc2UgYSBwbGF0Zm9ybSB3aXRoIGEgdmFsaWQgY2VydGlmaWNhdGUsIG9yIHVuc2V0IE5PREVfRU5WIGZvciBsb2NhbC9zZWxmLXNpZ25lZCBkZXZlbG9wbWVudC4nLFxuICAgICk7XG4gIH1cbn1cblxuLyoqXG4gKiBBcHBseSB0aGUgYC0tbm8tdmVyaWZ5LXNzbGAgcmVsYXhhdGlvbiBhcyBhIHByb2Nlc3Mtd2lkZSBlbnYgZmxhZ1xuICogKGBOT0RFX1RMU19SRUpFQ1RfVU5BVVRIT1JJWkVEPTBgKSBzbyBzcGF3bmVkIENESyBzdWJwcm9jZXNzZXMgKExhbWJkYSxcbiAqIENvZGVCdWlsZCBzeW50aCkgaW5oZXJpdCBpdCDigJQgYnV0IFJFRlVTRSBpbiBwcm9kdWN0aW9uLCBtaXJyb3JpbmcgdGhlIGd1YXJkIGluXG4gKiBjb25maWctbG9hZGVyLiBUaGF0IGZsYWcgZGlzYWJsZXMgY2VydGlmaWNhdGUgdmFsaWRhdGlvbiBmb3IgQUxMIG91dGJvdW5kIFRMU1xuICogKGluY2x1ZGluZyB0aGUgQVdTIFNESyksIHNvIGl0IG11c3QgbmV2ZXIgYmUgc2lsZW50bHkgZW5hYmxlZCBmb3IgYSBwcm9kXG4gKiBkZXBsb3kvc3ludGguXG4gKlxuICogQHBhcmFtIHZlcmlmeVNzbCAtIHRoZSBjb21tYW5kJ3MgYC0tdmVyaWZ5LXNzbGAgdmFsdWUgKGBmYWxzZWAgPSB1c2VyIGFza2VkIHRvIGRpc2FibGUpLlxuICogQHBhcmFtIHdhcm4gLSB3YXJuaW5nIHNpbmsgKGUuZy4gYHByaW50V2FybmluZ2ApLlxuICogQHJldHVybnMgdHJ1ZSBpZiB2ZXJpZmljYXRpb24gd2FzIGRpc2FibGVkOyBmYWxzZSBpZiBsZWZ0IGVuYWJsZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWxheFRsc0ZvckNsaShcbiAgdmVyaWZ5U3NsOiBib29sZWFuIHwgdW5kZWZpbmVkLFxuICB3YXJuOiAobWVzc2FnZTogc3RyaW5nKSA9PiB2b2lkLFxuKTogYm9vbGVhbiB7XG4gIGlmICh2ZXJpZnlTc2wgIT09IGZhbHNlKSByZXR1cm4gZmFsc2U7XG4gIGlmIChpc1Byb2R1Y3Rpb25FbnYoKSkge1xuICAgIHdhcm4oJ1JlZnVzaW5nIHRvIGRpc2FibGUgVExTIHZlcmlmaWNhdGlvbiBpbiBwcm9kdWN0aW9uIChOT0RFX0VOVj1wcm9kdWN0aW9uKSDigJQgY2VydGlmaWNhdGUgdmFsaWRhdGlvbiByZW1haW5zIGVuYWJsZWQuJyk7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHByb2Nlc3MuZW52Lk5PREVfVExTX1JFSkVDVF9VTkFVVEhPUklaRUQgPSAnMCc7XG4gIHJldHVybiB0cnVlO1xufVxuIl19
|
package/package.json
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pipeline-builder/pipeline-manager",
|
|
3
|
+
"description": "CLI for Pipeline Builder self-service AWS CodePipeline platform with 125 reusable containerized plugins, per-org compliance enforcement, and per-organization (and team) isolation.",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/mwashburn160/pipeline-builder.git"
|
|
7
|
+
},
|
|
8
|
+
"bin": {
|
|
9
|
+
"pipeline-manager": "./dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@jest/globals": "30.4.1",
|
|
13
|
+
"@stylistic/eslint-plugin": "^2",
|
|
14
|
+
"@types/figlet": "1.7.0",
|
|
15
|
+
"@types/node": "^24",
|
|
16
|
+
"@types/progress": "2.0.7",
|
|
17
|
+
"@typescript-eslint/eslint-plugin": "^8",
|
|
18
|
+
"@typescript-eslint/parser": "^8",
|
|
19
|
+
"@typescript/native": "npm:typescript@^7.0.2",
|
|
20
|
+
"copyfiles": "2.4.1",
|
|
21
|
+
"eslint": "^9",
|
|
22
|
+
"eslint-import-resolver-typescript": "^4.4.4",
|
|
23
|
+
"eslint-plugin-import": "^2.32.0",
|
|
24
|
+
"jest": "30.4.2",
|
|
25
|
+
"jest-junit": "^17",
|
|
26
|
+
"ts-jest": "29.4.12",
|
|
27
|
+
"typescript": "npm:@typescript/typescript6@^6.0.2"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@aws-sdk/client-cloudformation": "3.1101.0",
|
|
31
|
+
"@aws-sdk/client-lambda": "3.1101.0",
|
|
32
|
+
"@aws-sdk/client-secrets-manager": "3.1101.0",
|
|
33
|
+
"@aws-sdk/client-sqs": "3.1101.0",
|
|
34
|
+
"@aws-sdk/client-sts": "3.1101.0",
|
|
35
|
+
"aws-cdk-lib": "2.263.0",
|
|
36
|
+
"axios": "1.19.0",
|
|
37
|
+
"commander": "15.0.0",
|
|
38
|
+
"constructs": "10.7.0",
|
|
39
|
+
"figlet": "1.11.4",
|
|
40
|
+
"form-data": "4.0.6",
|
|
41
|
+
"ora": "9.4.1",
|
|
42
|
+
"picocolors": "1.1.1",
|
|
43
|
+
"progress": "2.0.3",
|
|
44
|
+
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
45
|
+
"yaml": "2.9.0",
|
|
46
|
+
"zod": "4.4.3",
|
|
47
|
+
"@pipeline-builder/ai-core": "0.0.1",
|
|
48
|
+
"@pipeline-builder/api-core": "0.0.1",
|
|
49
|
+
"@pipeline-builder/pipeline-core": "0.0.1"
|
|
50
|
+
},
|
|
51
|
+
"keywords": [
|
|
52
|
+
"ci-cd",
|
|
53
|
+
"cicd",
|
|
54
|
+
"continuous-delivery",
|
|
55
|
+
"devops",
|
|
56
|
+
"self-service",
|
|
57
|
+
"platform-engineering",
|
|
58
|
+
"internal-developer-platform",
|
|
59
|
+
"developer-platform",
|
|
60
|
+
"aws",
|
|
61
|
+
"aws-cdk",
|
|
62
|
+
"cdk",
|
|
63
|
+
"codepipeline",
|
|
64
|
+
"codebuild",
|
|
65
|
+
"cloudformation",
|
|
66
|
+
"pipeline",
|
|
67
|
+
"pipeline-as-code",
|
|
68
|
+
"infrastructure-as-code",
|
|
69
|
+
"iac",
|
|
70
|
+
"compliance",
|
|
71
|
+
"policy-as-code",
|
|
72
|
+
"governance",
|
|
73
|
+
"golden-paths",
|
|
74
|
+
"multi-tenant",
|
|
75
|
+
"rbac",
|
|
76
|
+
"ai",
|
|
77
|
+
"ai-pipeline-generation",
|
|
78
|
+
"llm",
|
|
79
|
+
"bedrock",
|
|
80
|
+
"plugins",
|
|
81
|
+
"plugin-marketplace",
|
|
82
|
+
"containerized",
|
|
83
|
+
"docker",
|
|
84
|
+
"kubernetes",
|
|
85
|
+
"typescript",
|
|
86
|
+
"cli"
|
|
87
|
+
],
|
|
88
|
+
"engines": {
|
|
89
|
+
"node": ">= 24.14.0"
|
|
90
|
+
},
|
|
91
|
+
"devEngines": {
|
|
92
|
+
"packageManager": {
|
|
93
|
+
"name": "pnpm",
|
|
94
|
+
"version": ">=10",
|
|
95
|
+
"onFail": "ignore"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"license": "Apache-2.0",
|
|
99
|
+
"homepage": "https://mwashburn160.github.io/pipeline-builder/",
|
|
100
|
+
"publishConfig": {
|
|
101
|
+
"access": "public",
|
|
102
|
+
"registry": "https://registry.npmjs.org/"
|
|
103
|
+
},
|
|
104
|
+
"version": "0.0.1",
|
|
105
|
+
"bugs": {
|
|
106
|
+
"url": "https://github.com/mwashburn160/pipeline-builder/issues"
|
|
107
|
+
},
|
|
108
|
+
"jest": {
|
|
109
|
+
"coverageProvider": "v8",
|
|
110
|
+
"testMatch": [
|
|
111
|
+
"<rootDir>/@(src|test)/**/*(*.)@(spec|test).[jt]s?(x)",
|
|
112
|
+
"<rootDir>/@(src|test)/**/__tests__/**/*.[jt]s?(x)"
|
|
113
|
+
],
|
|
114
|
+
"clearMocks": true,
|
|
115
|
+
"collectCoverage": true,
|
|
116
|
+
"coverageReporters": [
|
|
117
|
+
"json",
|
|
118
|
+
"lcov",
|
|
119
|
+
"clover",
|
|
120
|
+
"cobertura",
|
|
121
|
+
"text"
|
|
122
|
+
],
|
|
123
|
+
"coverageDirectory": "coverage",
|
|
124
|
+
"coveragePathIgnorePatterns": [
|
|
125
|
+
"/node_modules/"
|
|
126
|
+
],
|
|
127
|
+
"testPathIgnorePatterns": [
|
|
128
|
+
"/node_modules/"
|
|
129
|
+
],
|
|
130
|
+
"watchPathIgnorePatterns": [
|
|
131
|
+
"/node_modules/"
|
|
132
|
+
],
|
|
133
|
+
"reporters": [
|
|
134
|
+
"default",
|
|
135
|
+
[
|
|
136
|
+
"jest-junit",
|
|
137
|
+
{
|
|
138
|
+
"outputDirectory": "test-reports"
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
],
|
|
142
|
+
"transform": {
|
|
143
|
+
"^.+\\.[t]sx?$": [
|
|
144
|
+
"ts-jest",
|
|
145
|
+
{
|
|
146
|
+
"useESM": true,
|
|
147
|
+
"tsconfig": "tsconfig.dev.json",
|
|
148
|
+
"diagnostics": {
|
|
149
|
+
"ignoreCodes": [
|
|
150
|
+
151002
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
},
|
|
156
|
+
"extensionsToTreatAsEsm": [
|
|
157
|
+
".ts",
|
|
158
|
+
".tsx"
|
|
159
|
+
],
|
|
160
|
+
"moduleNameMapper": {
|
|
161
|
+
"^uuid$": "<rootDir>/../../jest-uuid-stub.js",
|
|
162
|
+
"^(\\.{1,2}/.*)\\.js$": "$1"
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
"type": "module",
|
|
166
|
+
"//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"pnpm dlx projen\".",
|
|
167
|
+
"scripts": {
|
|
168
|
+
"audit": "pnpm dlx projen audit",
|
|
169
|
+
"build": "pnpm dlx projen build",
|
|
170
|
+
"compile": "pnpm dlx projen compile",
|
|
171
|
+
"default": "pnpm dlx projen default",
|
|
172
|
+
"eslint": "pnpm dlx projen eslint",
|
|
173
|
+
"package": "pnpm dlx projen package",
|
|
174
|
+
"post-compile": "pnpm dlx projen post-compile",
|
|
175
|
+
"pre-compile": "pnpm dlx projen pre-compile",
|
|
176
|
+
"test": "pnpm dlx projen test",
|
|
177
|
+
"test:watch": "pnpm dlx projen test:watch",
|
|
178
|
+
"watch": "pnpm dlx projen watch",
|
|
179
|
+
"projen": "pnpm dlx projen"
|
|
180
|
+
}
|
|
181
|
+
}
|