@pipeline-builder/pipeline-events 4.0.9 → 4.0.11

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/lib/parse.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ import type { SQSRecord } from 'aws-lambda';
2
+ export interface ParsedEvent {
3
+ /**
4
+ * Resolved platform orgId (from the pipeline's OrgId tag; null when untagged).
5
+ * INTERNAL — used only to key the per-org GitHub token and to attribute
6
+ * ingest-health. Stripped from the payload POSTed to /reports/events (which
7
+ * resolves org from the pipeline registry, not the body).
8
+ */
9
+ orgId: string | null;
10
+ pipelineId: string;
11
+ eventSource: string;
12
+ eventType: string;
13
+ status: string;
14
+ executionId?: string;
15
+ stageName?: string;
16
+ actionName?: string;
17
+ /** Human-readable failure reason, from an Action event's
18
+ * `execution-result.external-execution-summary`. The log URL + error-code
19
+ * stay in `detail` for drill-down. */
20
+ errorMessage?: string;
21
+ startedAt?: string;
22
+ completedAt?: string;
23
+ durationMs?: number;
24
+ /** Source commit id (DORA deploy attribution). Undefined when the event
25
+ * carries no source revision — stored NULL downstream. */
26
+ commitSha?: string;
27
+ /** Source branch/ref (DORA deploy attribution). Undefined when unavailable. */
28
+ commitRef?: string;
29
+ /** Oldest-unshipped commit timestamp (ISO 8601) for the range since the last
30
+ * deploy — resolved in-account. Undefined when unresolvable. */
31
+ commitTimestamp?: string;
32
+ /** Number of commits in the resolved range (≥1). Undefined when unresolvable. */
33
+ commitCount?: number;
34
+ /** Deploy environment — set only when the event's stage is listed in the
35
+ * pipeline's `pb.deploys` tag. Undefined otherwise (⇒ not a deploy). */
36
+ environment?: string;
37
+ detail: Record<string, unknown>;
38
+ }
39
+ /** Parse + resolve one record to a reportable event, or null to skip it. */
40
+ export declare function parseRecord(record: SQSRecord): Promise<ParsedEvent | null>;
package/lib/parse.js ADDED
@@ -0,0 +1,150 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { classifySource, resolveCommitInfo } from './scm.js';
4
+ import { MAX_ATTR, resolvePipeline } from './tags.js';
5
+ import { log } from './util.js';
6
+ /** Cap on the stored failure summary — CodeBuild/Deploy summaries can be long. */
7
+ const MAX_ERROR_MESSAGE = 4000;
8
+ /** First non-empty string among the candidates, capped to the ingest max. */
9
+ function firstAttr(...vals) {
10
+ for (const v of vals) {
11
+ if (typeof v === 'string' && v.length > 0)
12
+ return v.slice(0, MAX_ATTR);
13
+ }
14
+ return undefined;
15
+ }
16
+ /**
17
+ * Best-effort extraction of the source commit id + ref (and the revision URL, used
18
+ * only in-account to classify the source type for commit-range resolution) from a
19
+ * CodePipeline event detail. CodePipeline surfaces the source revision under a few
20
+ * shapes depending on the event type / source-action; we check the known ones and
21
+ * leave the fields undefined when none are present (NULL downstream). Never pulls an
22
+ * ARN/account id: only revision/branch/url string fields are read; the revisionUrl
23
+ * is consumed in-account (source classification) and never forwarded on its own.
24
+ */
25
+ function extractCommit(detail) {
26
+ // `source-revisions` (kebab, EventBridge) / `sourceRevisions` (camel) — first entry.
27
+ const revs = (detail['source-revisions'] ?? detail.sourceRevisions);
28
+ const firstRev = Array.isArray(revs) ? revs[0] : undefined;
29
+ // On source actions the revision id can also ride on `execution-result`.
30
+ const execResult = detail['execution-result'];
31
+ const commitSha = firstAttr(detail.commitId, detail.revisionId, firstRev?.revisionId, execResult?.revisionId);
32
+ const commitRef = firstAttr(detail.commitRef, detail.branch, detail.sourceBranch, firstRev?.branchName, firstRev?.branch);
33
+ const revisionUrl = typeof firstRev?.revisionUrl === 'string' ? firstRev.revisionUrl : undefined;
34
+ return { ...(commitSha && { commitSha }), ...(commitRef && { commitRef }), ...(revisionUrl && { revisionUrl }) };
35
+ }
36
+ function classifyEvent(detailType) {
37
+ if (detailType.includes('Pipeline Execution'))
38
+ return { eventType: 'PIPELINE', eventSource: 'codepipeline' };
39
+ if (detailType.includes('Stage Execution'))
40
+ return { eventType: 'STAGE', eventSource: 'codepipeline' };
41
+ if (detailType.includes('Action Execution'))
42
+ return { eventType: 'ACTION', eventSource: 'codepipeline' };
43
+ // CodeBuild "Build State" events identify a build *project*, not a pipeline, so
44
+ // parseRecord drops them on the `eventSource !== 'codepipeline'` check below —
45
+ // the 'BUILD' eventType is never persisted here (plugin BUILD events are
46
+ // recorded directly by the plugin service). The 'codebuild' source is what
47
+ // routes the drop; keep this branch only for that.
48
+ if (detailType.includes('Build State'))
49
+ return { eventType: 'BUILD', eventSource: 'codebuild' };
50
+ return { eventType: 'PIPELINE', eventSource: 'codepipeline' };
51
+ }
52
+ /** Parse + resolve one record to a reportable event, or null to skip it. */
53
+ export async function parseRecord(record) {
54
+ let event;
55
+ // A malformed body is a dead message (retrying won't help) — log + skip it so
56
+ // it can't fail the whole batch. Resolution errors below (e.g. AccessDenied)
57
+ // are NOT caught here: those are transient/infra and must propagate to retry.
58
+ try {
59
+ event = JSON.parse(record.body);
60
+ }
61
+ catch (err) {
62
+ log.warn('Skipping SQS record with unparseable body', { messageId: record.messageId, error: String(err) });
63
+ return null;
64
+ }
65
+ const { eventType, eventSource } = classifyEvent(event['detail-type']);
66
+ const detail = { ...event.detail };
67
+ // The raw account never needs to leave AWS now — drop it from the payload.
68
+ delete detail.account;
69
+ // CodeBuild "Build State" events identify a build *project*, not a pipeline,
70
+ // and a project can be shared across pipelines — there's no clean 1:1 mapping
71
+ // to a pipeline id, so skip them.
72
+ if (eventSource !== 'codepipeline') {
73
+ log.warn('Skipping non-CodePipeline event (no pipeline tag to resolve)', { detailType: event['detail-type'] });
74
+ return null;
75
+ }
76
+ const pipelineName = detail.pipeline;
77
+ if (!pipelineName) {
78
+ log.warn('CodePipeline event missing pipeline name — skipping');
79
+ return null;
80
+ }
81
+ // Resolve the pipeline's pb.pipeline-id (= platform pipelineId) + pb.deploys map.
82
+ // The ARN is only a transient handle for the tag lookup; it is never stored.
83
+ const arn = `arn:aws:codepipeline:${event.region}:${event.account}:${pipelineName}`;
84
+ const { pipelineId, orgId, deploys } = await resolvePipeline(arn, event.region);
85
+ if (!pipelineId)
86
+ return null; // untagged / unregistered → skip
87
+ const startedAt = detail['start-time'] || event.time;
88
+ const state = detail.state;
89
+ let durationMs;
90
+ let completedAt;
91
+ if (['SUCCEEDED', 'FAILED', 'CANCELED', 'STOPPED'].includes(state)) {
92
+ completedAt = event.time;
93
+ if (startedAt && completedAt) {
94
+ const ms = new Date(completedAt).getTime() - new Date(startedAt).getTime();
95
+ if (ms >= 0)
96
+ durationMs = ms;
97
+ }
98
+ }
99
+ // Promote the failure reason to a typed field. On Action events AWS puts the
100
+ // human-readable summary (and a log URL + error-code, which stay in `detail`)
101
+ // under `execution-result`.
102
+ const result = detail['execution-result'];
103
+ const summary = result?.['external-execution-summary'];
104
+ const errorMessage = typeof summary === 'string' && summary.length > 0
105
+ ? summary.slice(0, MAX_ERROR_MESSAGE)
106
+ : undefined;
107
+ // DORA deploy attribution — all optional: omitted (undefined) when the
108
+ // event/pipeline doesn't carry them.
109
+ const { commitSha, commitRef, revisionUrl } = extractCommit(detail);
110
+ const executionId = detail['execution-id'];
111
+ const stageName = detail.stage;
112
+ const actionName = detail.action;
113
+ // Environment (⇒ isDeploy) is set ONLY when this event's stage is listed in the
114
+ // pipeline's pb.deploys tag. PIPELINE events have no stage → never a deploy.
115
+ const environment = stageName ? deploys.get(stageName) : undefined;
116
+ // Resolve the commit range (oldest-unshipped timestamp + count) for any
117
+ // event carrying a commit. Best-effort/in-account; omitted on any failure.
118
+ // GATED on `DORA_ENABLED` (set by `setup-events --with-dora`): DORA lead time is an
119
+ // advanced_reporting add-on, so orgs without it skip the SCM/secret cost entirely —
120
+ // standard reporting (commitSha + all other fields) still forwards regardless.
121
+ let commitTimestamp;
122
+ let commitCount;
123
+ if (commitSha && process.env.DORA_ENABLED === 'true') {
124
+ const src = classifySource(revisionUrl);
125
+ const info = await resolveCommitInfo(pipelineId, orgId, event.region, { sha: commitSha, ...src });
126
+ commitTimestamp = info.commitTimestamp;
127
+ commitCount = info.commitCount;
128
+ }
129
+ return {
130
+ orgId,
131
+ pipelineId,
132
+ eventSource,
133
+ eventType,
134
+ status: state,
135
+ executionId,
136
+ stageName,
137
+ actionName,
138
+ errorMessage,
139
+ startedAt,
140
+ completedAt,
141
+ durationMs,
142
+ ...(commitSha && { commitSha }),
143
+ ...(commitRef && { commitRef }),
144
+ ...(commitTimestamp && { commitTimestamp }),
145
+ ...(commitCount && { commitCount }),
146
+ ...(environment && { environment }),
147
+ detail,
148
+ };
149
+ }
150
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFyc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcGFyc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUd0QyxPQUFPLEVBQUUsY0FBYyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQzdELE9BQU8sRUFBRSxRQUFRLEVBQUUsZUFBZSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3RELE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxXQUFXLENBQUM7QUEwQ2hDLGtGQUFrRjtBQUNsRixNQUFNLGlCQUFpQixHQUFHLElBQUksQ0FBQztBQUUvQiw2RUFBNkU7QUFDN0UsU0FBUyxTQUFTLENBQUMsR0FBRyxJQUFlO0lBQ25DLEtBQUssTUFBTSxDQUFDLElBQUksSUFBSSxFQUFFLENBQUM7UUFDckIsSUFBSSxPQUFPLENBQUMsS0FBSyxRQUFRLElBQUksQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDO1lBQUUsT0FBTyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxRQUFRLENBQUMsQ0FBQztJQUN6RSxDQUFDO0lBQ0QsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQUVEOzs7Ozs7OztHQVFHO0FBQ0gsU0FBUyxhQUFhLENBQUMsTUFBK0I7SUFDcEQscUZBQXFGO0lBQ3JGLE1BQU0sSUFBSSxHQUFHLENBQUMsTUFBTSxDQUFDLGtCQUFrQixDQUFDLElBQUksTUFBTSxDQUFDLGVBQWUsQ0FDcEIsQ0FBQztJQUMvQyxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztJQUMzRCx5RUFBeUU7SUFDekUsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLGtCQUFrQixDQUF3QyxDQUFDO0lBRXJGLE1BQU0sU0FBUyxHQUFHLFNBQVMsQ0FDekIs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QyxNQUFNLElBQUksR0FBRyxNQUFNLGlCQUFpQixDQUFDLFVBQVUsRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLE1BQU0sRUFBRSxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsR0FBRyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ2xHLGVBQWUsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDO1FBQ3ZDLFdBQVcsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDO0lBQ2pDLENBQUM7SUFFRCxPQUFPO1FBQ0wsS0FBSztRQUNMLFVBQVU7UUFDVixXQUFXO1FBQ1gsU0FBUztRQUNULE1BQU0sRUFBRSxLQUFLO1FBQ2IsV0FBVztRQUNYLFNBQVM7UUFDVCxVQUFVO1FBQ1YsWUFBWTtRQUNaLFNBQVM7UUFDVCxXQUFXO1FBQ1gsVUFBVTtRQUNWLEdBQUcsQ0FBQyxTQUFTLElBQUksRUFBRSxTQUFTLEVBQUUsQ0FBQztRQUMvQixHQUFHLENBQUMsU0FBUyxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUM7UUFDL0IsR0FBRyxDQUFDLGVBQWUsSUFBSSxFQUFFLGVBQWUsRUFBRSxDQUFDO1FBQzNDLEdBQUcsQ0FBQyxXQUFXLElBQUksRUFBRSxXQUFXLEVBQUUsQ0FBQztRQUNuQyxHQUFHLENBQUMsV0FBVyxJQUFJLEVBQUUsV0FBVyxFQUFFLENBQUM7UUFDbkMsTUFBTTtLQUNQLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB0eXBlIHsgU1FTUmVjb3JkIH0gZnJvbSAnYXdzLWxhbWJkYSc7XG5pbXBvcnQgeyBjbGFzc2lmeVNvdXJjZSwgcmVzb2x2ZUNvbW1pdEluZm8gfSBmcm9tICcuL3NjbS5qcyc7XG5pbXBvcnQgeyBNQVhfQVRUUiwgcmVzb2x2ZVBpcGVsaW5lIH0gZnJvbSAnLi90YWdzLmpzJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vdXRpbC5qcyc7XG5cbi8vIEV2ZW50IHBhcnNpbmc6IGFuIFNRUyByZWNvcmQg4oaSIHRoZSBub3JtYWxpemVkIHJlcG9ydGluZyBldmVudC5cblxuZXhwb3J0IGludGVyZmFjZSBQYXJzZWRFdmVudCB7XG4gIC8qKlxuICAgKiBSZXNvbHZlZCBwbGF0Zm9ybSBvcmdJZCAoZnJvbSB0aGUgcGlwZWxpbmUncyBPcmdJZCB0YWc7IG51bGwgd2hlbiB1bnRhZ2dlZCkuXG4gICAqIElOVEVSTkFMIOKAlCB1c2VkIG9ubHkgdG8ga2V5IHRoZSBwZXItb3JnIEdpdEh1YiB0b2tlbiBhbmQgdG8gYXR0cmlidXRlXG4gICAqIGluZ2VzdC1oZWFsdGguIFN0cmlwcGVkIGZyb20gdGhlIHBheWxvYWQgUE9TVGVkIHRvIC9yZXBvcnRzL2V2ZW50cyAod2hpY2hcbiAgICogcmVzb2x2ZXMgb3JnIGZyb20gdGhlIHBpcGVsaW5lIHJlZ2lzdHJ5LCBub3QgdGhlIGJvZHkpLlxuICAgKi9cbiAgb3JnSWQ6IHN0cmluZyB8IG51bGw7XG4gIHBpcGVsaW5lSWQ6IHN0cmluZztcbiAgZXZlbnRTb3VyY2U6IHN0cmluZztcbiAgZXZlbnRUeXBlOiBzdHJpbmc7XG4gIHN0YXR1czogc3RyaW5nO1xuICBleGVjdXRpb25JZD86IHN0cmluZztcbiAgc3RhZ2VOYW1lPzogc3RyaW5nO1xuICBhY3Rpb25OYW1lPzogc3RyaW5nO1xuICAvKiogSHVtYW4tcmVhZGFibGUgZmFpbHVyZSByZWFzb24sIGZyb20gYW4gQWN0aW9uIGV2ZW50J3NcbiAgICogIGBleGVjdXRpb24tcmVzdWx0LmV4dGVybmFsLWV4ZWN1dGlvbi1zdW1tYXJ5YC4gVGhlIGxvZyBVUkwgKyBlcnJvci1jb2RlXG4gICAqICBzdGF5IGluIGBkZXRhaWxgIGZvciBkcmlsbC1kb3duLiAqL1xuICBlcnJvck1lc3NhZ2U/OiBzdHJpbmc7XG4gIHN0YXJ0ZWRBdD86IHN0cmluZztcbiAgY29tcGxldGVkQXQ/OiBzdHJpbmc7XG4gIGR1cmF0aW9uTXM/OiBudW1iZXI7XG4gIC8qKiBTb3VyY2UgY29tbWl0IGlkIChET1JBIGRlcGxveSBhdHRyaWJ1dGlvbikuIFVuZGVmaW5lZCB3aGVuIHRoZSBldmVudFxuICAgKiAgY2FycmllcyBubyBzb3VyY2UgcmV2aXNpb24g4oCUIHN0b3JlZCBOVUxMIGRvd25zdHJlYW0uICovXG4gIGNvbW1pdFNoYT86IHN0cmluZztcbiAgLyoqIFNvdXJjZSBicmFuY2gvcmVmIChET1JBIGRlcGxveSBhdHRyaWJ1dGlvbikuIFVuZGVmaW5lZCB3aGVuIHVuYXZhaWxhYmxlLiAqL1xuICBjb21taXRSZWY/OiBzdHJpbmc7XG4gIC8qKiBPbGRlc3QtdW5zaGlwcGVkIGNvbW1pdCB0aW1lc3RhbXAgKElTTyA4NjAxKSBmb3IgdGhlIHJhbmdlIHNpbmNlIHRoZSBsYXN0XG4gICAqICBkZXBsb3kg4oCUIHJlc29sdmVkIGluLWFjY291bnQuIFVuZGVmaW5lZCB3aGVuIHVucmVzb2x2YWJsZS4gKi9cbiAgY29tbWl0VGltZXN0YW1wPzogc3RyaW5nO1xuICAvKiogTnVtYmVyIG9mIGNvbW1pdHMgaW4gdGhlIHJlc29sdmVkIHJhbmdlICjiiaUxKS4gVW5kZWZpbmVkIHdoZW4gdW5yZXNvbHZhYmxlLiAqL1xuICBjb21taXRDb3VudD86IG51bWJlcjtcbiAgLyoqIERlcGxveSBlbnZpcm9ubWVudCDigJQgc2V0IG9ubHkgd2hlbiB0aGUgZXZlbnQncyBzdGFnZSBpcyBsaXN0ZWQgaW4gdGhlXG4gICAqICBwaXBlbGluZSdzIGBwYi5kZXBsb3lzYCB0YWcuIFVuZGVmaW5lZCBvdGhlcndpc2UgKOKHkiBub3QgYSBkZXBsb3kpLiAqL1xuICBlbnZpcm9ubWVudD86IHN0cmluZztcbiAgZGV0YWlsOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn1cblxuLyoqIENhcCBvbiB0aGUgc3RvcmVkIGZhaWx1cmUgc3VtbWFyeSDigJQgQ29kZUJ1aWxkL0RlcGxveSBzdW1tYXJpZXMgY2FuIGJlIGxvbmcuICovXG5jb25zdCBNQVhfRVJST1JfTUVTU0FHRSA9IDQwMDA7XG5cbi8qKiBGaXJzdCBub24tZW1wdHkgc3RyaW5nIGFtb25nIHRoZSBjYW5kaWRhdGVzLCBjYXBwZWQgdG8gdGhlIGluZ2VzdCBtYXguICovXG5mdW5jdGlvbiBmaXJzdEF0dHIoLi4udmFsczogdW5rbm93bltdKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgZm9yIChjb25zdCB2IG9mIHZhbHMpIHtcbiAgICBpZiAodHlwZW9mIHYgPT09ICdzdHJpbmcnICYmIHYubGVuZ3RoID4gMCkgcmV0dXJuIHYuc2xpY2UoMCwgTUFYX0FUVFIpO1xuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogQmVzdC1lZmZvcnQgZXh0cmFjdGlvbiBvZiB0aGUgc291cmNlIGNvbW1pdCBpZCArIHJlZiAoYW5kIHRoZSByZXZpc2lvbiBVUkwsIHVzZWRcbiAqIG9ubHkgaW4tYWNjb3VudCB0byBjbGFzc2lmeSB0aGUgc291cmNlIHR5cGUgZm9yIGNvbW1pdC1yYW5nZSByZXNvbHV0aW9uKSBmcm9tIGFcbiAqIENvZGVQaXBlbGluZSBldmVudCBkZXRhaWwuIENvZGVQaXBlbGluZSBzdXJmYWNlcyB0aGUgc291cmNlIHJldmlzaW9uIHVuZGVyIGEgZmV3XG4gKiBzaGFwZXMgZGVwZW5kaW5nIG9uIHRoZSBldmVudCB0eXBlIC8gc291cmNlLWFjdGlvbjsgd2UgY2hlY2sgdGhlIGtub3duIG9uZXMgYW5kXG4gKiBsZWF2ZSB0aGUgZmllbGRzIHVuZGVmaW5lZCB3aGVuIG5vbmUgYXJlIHByZXNlbnQgKE5VTEwgZG93bnN0cmVhbSkuIE5ldmVyIHB1bGxzIGFuXG4gKiBBUk4vYWNjb3VudCBpZDogb25seSByZXZpc2lvbi9icmFuY2gvdXJsIHN0cmluZyBmaWVsZHMgYXJlIHJlYWQ7IHRoZSByZXZpc2lvblVybFxuICogaXMgY29uc3VtZWQgaW4tYWNjb3VudCAoc291cmNlIGNsYXNzaWZpY2F0aW9uKSBhbmQgbmV2ZXIgZm9yd2FyZGVkIG9uIGl0cyBvd24uXG4gKi9cbmZ1bmN0aW9uIGV4dHJhY3RDb21taXQoZGV0YWlsOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IHsgY29tbWl0U2hhPzogc3RyaW5nOyBjb21taXRSZWY/OiBzdHJpbmc7IHJldmlzaW9uVXJsPzogc3RyaW5nIH0ge1xuICAvLyBgc291cmNlLXJldmlzaW9uc2AgKGtlYmFiLCBFdmVudEJyaWRnZSkgLyBgc291cmNlUmV2aXNpb25zYCAoY2FtZWwpIOKAlCBmaXJzdCBlbnRyeS5cbiAgY29uc3QgcmV2cyA9IChkZXRhaWxbJ3NvdXJjZS1yZXZpc2lvbnMnXSA/PyBkZXRhaWwuc291cmNlUmV2aXNpb25zKSBhc1xuICAgIHwgQXJyYXk8UmVjb3JkPHN0cmluZywgdW5rbm93bj4+IHwgdW5kZWZpbmVkO1xuICBjb25zdCBmaXJzdFJldiA9IEFycmF5LmlzQXJyYXkocmV2cykgPyByZXZzWzBdIDogdW5kZWZpbmVkO1xuICAvLyBPbiBzb3VyY2UgYWN0aW9ucyB0aGUgcmV2aXNpb24gaWQgY2FuIGFsc28gcmlkZSBvbiBgZXhlY3V0aW9uLXJlc3VsdGAuXG4gIGNvbnN0IGV4ZWNSZXN1bHQgPSBkZXRhaWxbJ2V4ZWN1dGlvbi1yZXN1bHQnXSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZDtcblxuICBjb25zdCBjb21taXRTaGEgPSBmaXJzdEF0dHIoXG4gICAgZGV0YWlsLmNvbW1pdElkLFxuICAgIGRldGFpbC5yZXZpc2lvbklkLFxuICAgIGZpcnN0UmV2Py5yZXZpc2lvbklkLFxuICAgIGV4ZWNSZXN1bHQ/LnJldmlzaW9uSWQsXG4gICk7XG4gIGNvbnN0IGNvbW1pdFJlZiA9IGZpcnN0QXR0cihcbiAgICBkZXRhaWwuY29tbWl0UmVmLFxuICAgIGRldGFpbC5icmFuY2gsXG4gICAgZGV0YWlsLnNvdXJjZUJyYW5jaCxcbiAgICBmaXJzdFJldj8uYnJhbmNoTmFtZSxcbiAgICBmaXJzdFJldj8uYnJhbmNoLFxuICApO1xuICBjb25zdCByZXZpc2lvblVybCA9IHR5cGVvZiBmaXJzdFJldj8ucmV2aXNpb25VcmwgPT09ICdzdHJpbmcnID8gZmlyc3RSZXYucmV2aXNpb25VcmwgOiB1bmRlZmluZWQ7XG5cbiAgcmV0dXJuIHsgLi4uKGNvbW1pdFNoYSAmJiB7IGNvbW1pdFNoYSB9KSwgLi4uKGNvbW1pdFJlZiAmJiB7IGNvbW1pdFJlZiB9KSwgLi4uKHJldmlzaW9uVXJsICYmIHsgcmV2aXNpb25VcmwgfSkgfTtcbn1cblxuZnVuY3Rpb24gY2xhc3NpZnlFdmVudChkZXRhaWxUeXBlOiBzdHJpbmcpOiB7IGV2ZW50VHlwZTogc3RyaW5nOyBldmVudFNvdXJjZTogc3RyaW5nIH0ge1xuICBpZiAoZGV0YWlsVHlwZS5pbmNsdWRlcygnUGlwZWxpbmUgRXhlY3V0aW9uJykpIHJldHVybiB7IGV2ZW50VHlwZTogJ1BJUEVMSU5FJywgZXZlbnRTb3VyY2U6ICdjb2RlcGlwZWxpbmUnIH07XG4gIGlmIChkZXRhaWxUeXBlLmluY2x1ZGVzKCdTdGFnZSBFeGVjdXRpb24nKSkgcmV0dXJuIHsgZXZlbnRUeXBlOiAnU1RBR0UnLCBldmVudFNvdXJjZTogJ2NvZGVwaXBlbGluZScgfTtcbiAgaWYgKGRldGFpbFR5cGUuaW5jbHVkZXMoJ0FjdGlvbiBFeGVjdXRpb24nKSkgcmV0dXJuIHsgZXZlbnRUeXBlOiAnQUNUSU9OJywgZXZlbnRTb3VyY2U6ICdjb2RlcGlwZWxpbmUnIH07XG4gIC8vIENvZGVCdWlsZCBcIkJ1aWxkIFN0YXRlXCIgZXZlbnRzIGlkZW50aWZ5IGEgYnVpbGQgKnByb2plY3QqLCBub3QgYSBwaXBlbGluZSwgc29cbiAgLy8gcGFyc2VSZWNvcmQgZHJvcHMgdGhlbSBvbiB0aGUgYGV2ZW50U291cmNlICE9PSAnY29kZXBpcGVsaW5lJ2AgY2hlY2sgYmVsb3cg4oCUXG4gIC8vIHRoZSAnQlVJTEQnIGV2ZW50VHlwZSBpcyBuZXZlciBwZXJzaXN0ZWQgaGVyZSAocGx1Z2luIEJVSUxEIGV2ZW50cyBhcmVcbiAgLy8gcmVjb3JkZWQgZGlyZWN0bHkgYnkgdGhlIHBsdWdpbiBzZXJ2aWNlKS4gVGhlICdjb2RlYnVpbGQnIHNvdXJjZSBpcyB3aGF0XG4gIC8vIHJvdXRlcyB0aGUgZHJvcDsga2VlcCB0aGlzIGJyYW5jaCBvbmx5IGZvciB0aGF0LlxuICBpZiAoZGV0YWlsVHlwZS5pbmNsdWRlcygnQnVpbGQgU3RhdGUnKSkgcmV0dXJuIHsgZXZlbnRUeXBlOiAnQlVJTEQnLCBldmVudFNvdXJjZTogJ2NvZGVidWlsZCcgfTtcbiAgcmV0dXJuIHsgZXZlbnRUeXBlOiAnUElQRUxJTkUnLCBldmVudFNvdXJjZTogJ2NvZGVwaXBlbGluZScgfTtcbn1cblxuLyoqIFBhcnNlICsgcmVzb2x2ZSBvbmUgcmVjb3JkIHRvIGEgcmVwb3J0YWJsZSBldmVudCwgb3IgbnVsbCB0byBza2lwIGl0LiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBhcnNlUmVjb3JkKHJlY29yZDogU1FTUmVjb3JkKTogUHJvbWlzZTxQYXJzZWRFdmVudCB8IG51bGw+IHtcbiAgbGV0IGV2ZW50OiB7XG4gICAgJ2RldGFpbC10eXBlJzogc3RyaW5nO1xuICAgICdzb3VyY2UnOiBzdHJpbmc7XG4gICAgJ2RldGFpbCc6IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgICd0aW1lJzogc3RyaW5nO1xuICAgICdyZWdpb24nOiBzdHJpbmc7XG4gICAgJ2FjY291bnQnOiBzdHJpbmc7XG4gIH07XG4gIC8vIEEgbWFsZm9ybWVkIGJvZHkgaXMgYSBkZWFkIG1lc3NhZ2UgKHJldHJ5aW5nIHdvbid0IGhlbHApIOKAlCBsb2cgKyBza2lwIGl0IHNvXG4gIC8vIGl0IGNhbid0IGZhaWwgdGhlIHdob2xlIGJhdGNoLiBSZXNvbHV0aW9uIGVycm9ycyBiZWxvdyAoZS5nLiBBY2Nlc3NEZW5pZWQpXG4gIC8vIGFyZSBOT1QgY2F1Z2h0IGhlcmU6IHRob3NlIGFyZSB0cmFuc2llbnQvaW5mcmEgYW5kIG11c3QgcHJvcGFnYXRlIHRvIHJldHJ5LlxuICB0cnkge1xuICAgIGV2ZW50ID0gSlNPTi5wYXJzZShyZWNvcmQuYm9keSk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZy53YXJuKCdTa2lwcGluZyBTUVMgcmVjb3JkIHdpdGggdW5wYXJzZWFibGUgYm9keScsIHsgbWVzc2FnZUlkOiByZWNvcmQubWVzc2FnZUlkLCBlcnJvcjogU3RyaW5nKGVycikgfSk7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCB7IGV2ZW50VHlwZSwgZXZlbnRTb3VyY2UgfSA9IGNsYXNzaWZ5RXZlbnQoZXZlbnRbJ2RldGFpbC10eXBlJ10pO1xuICBjb25zdCBkZXRhaWwgPSB7IC4uLmV2ZW50LmRldGFpbCB9O1xuICAvLyBUaGUgcmF3IGFjY291bnQgbmV2ZXIgbmVlZHMgdG8gbGVhdmUgQVdTIG5vdyDigJQgZHJvcCBpdCBmcm9tIHRoZSBwYXlsb2FkLlxuICBkZWxldGUgZGV0YWlsLmFjY291bnQ7XG5cbiAgLy8gQ29kZUJ1aWxkIFwiQnVpbGQgU3RhdGVcIiBldmVudHMgaWRlbnRpZnkgYSBidWlsZCAqcHJvamVjdCosIG5vdCBhIHBpcGVsaW5lLFxuICAvLyBhbmQgYSBwcm9qZWN0IGNhbiBiZSBzaGFyZWQgYWNyb3NzIHBpcGVsaW5lcyDigJQgdGhlcmUncyBubyBjbGVhbiAxOjEgbWFwcGluZ1xuICAvLyB0byBhIHBpcGVsaW5lIGlkLCBzbyBza2lwIHRoZW0uXG4gIGlmIChldmVudFNvdXJjZSAhPT0gJ2NvZGVwaXBlbGluZScpIHtcbiAgICBsb2cud2FybignU2tpcHBpbmcgbm9uLUNvZGVQaXBlbGluZSBldmVudCAobm8gcGlwZWxpbmUgdGFnIHRvIHJlc29sdmUpJywgeyBkZXRhaWxUeXBlOiBldmVudFsnZGV0YWlsLXR5cGUnXSB9KTtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGNvbnN0IHBpcGVsaW5lTmFtZSA9IGRldGFpbC5waXBlbGluZSBhcyBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGlmICghcGlwZWxpbmVOYW1lKSB7XG4gICAgbG9nLndhcm4oJ0NvZGVQaXBlbGluZSBldmVudCBtaXNzaW5nIHBpcGVsaW5lIG5hbWUg4oCUIHNraXBwaW5nJyk7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvLyBSZXNvbHZlIHRoZSBwaXBlbGluZSdzIHBiLnBpcGVsaW5lLWlkICg9IHBsYXRmb3JtIHBpcGVsaW5lSWQpICsgcGIuZGVwbG95cyBtYXAuXG4gIC8vIFRoZSBBUk4gaXMgb25seSBhIHRyYW5zaWVudCBoYW5kbGUgZm9yIHRoZSB0YWcgbG9va3VwOyBpdCBpcyBuZXZlciBzdG9yZWQuXG4gIGNvbnN0IGFybiA9IGBhcm46YXdzOmNvZGVwaXBlbGluZToke2V2ZW50LnJlZ2lvbn06JHtldmVudC5hY2NvdW50fToke3BpcGVsaW5lTmFtZX1gO1xuICBjb25zdCB7IHBpcGVsaW5lSWQsIG9yZ0lkLCBkZXBsb3lzIH0gPSBhd2FpdCByZXNvbHZlUGlwZWxpbmUoYXJuLCBldmVudC5yZWdpb24pO1xuICBpZiAoIXBpcGVsaW5lSWQpIHJldHVybiBudWxsOyAvLyB1bnRhZ2dlZCAvIHVucmVnaXN0ZXJlZCDihpIgc2tpcFxuXG4gIGNvbnN0IHN0YXJ0ZWRBdCA9IChkZXRhaWxbJ3N0YXJ0LXRpbWUnXSBhcyBzdHJpbmcpIHx8IGV2ZW50LnRpbWU7XG4gIGNvbnN0IHN0YXRlID0gZGV0YWlsLnN0YXRlIGFzIHN0cmluZztcblxuICBsZXQgZHVyYXRpb25NczogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICBsZXQgY29tcGxldGVkQXQ6IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICBpZiAoWydTVUNDRUVERUQnLCAnRkFJTEVEJywgJ0NBTkNFTEVEJywgJ1NUT1BQRUQnXS5pbmNsdWRlcyhzdGF0ZSkpIHtcbiAgICBjb21wbGV0ZWRBdCA9IGV2ZW50LnRpbWU7XG4gICAgaWYgKHN0YXJ0ZWRBdCAmJiBjb21wbGV0ZWRBdCkge1xuICAgICAgY29uc3QgbXMgPSBuZXcgRGF0ZShjb21wbGV0ZWRBdCkuZ2V0VGltZSgpIC0gbmV3IERhdGUoc3RhcnRlZEF0KS5nZXRUaW1lKCk7XG4gICAgICBpZiAobXMgPj0gMCkgZHVyYXRpb25NcyA9IG1zO1xuICAgIH1cbiAgfVxuXG4gIC8vIFByb21vdGUgdGhlIGZhaWx1cmUgcmVhc29uIHRvIGEgdHlwZWQgZmllbGQuIE9uIEFjdGlvbiBldmVudHMgQVdTIHB1dHMgdGhlXG4gIC8vIGh1bWFuLXJlYWRhYmxlIHN1bW1hcnkgKGFuZCBhIGxvZyBVUkwgKyBlcnJvci1jb2RlLCB3aGljaCBzdGF5IGluIGBkZXRhaWxgKVxuICAvLyB1bmRlciBgZXhlY3V0aW9uLXJlc3VsdGAuXG4gIGNvbnN0IHJlc3VsdCA9IGRldGFpbFsnZXhlY3V0aW9uLXJlc3VsdCddIGFzIHsgJ2V4dGVybmFsLWV4ZWN1dGlvbi1zdW1tYXJ5Jz86IHVua25vd24gfSB8IHVuZGVmaW5lZDtcbiAgY29uc3Qgc3VtbWFyeSA9IHJlc3VsdD8uWydleHRlcm5hbC1leGVjdXRpb24tc3VtbWFyeSddO1xuICBjb25zdCBlcnJvck1lc3NhZ2UgPSB0eXBlb2Ygc3VtbWFyeSA9PT0gJ3N0cmluZycgJiYgc3VtbWFyeS5sZW5ndGggPiAwXG4gICAgPyBzdW1tYXJ5LnNsaWNlKDAsIE1BWF9FUlJPUl9NRVNTQUdFKVxuICAgIDogdW5kZWZpbmVkO1xuXG4gIC8vIERPUkEgZGVwbG95IGF0dHJpYnV0aW9uIOKAlCBhbGwgb3B0aW9uYWw6IG9taXR0ZWQgKHVuZGVmaW5lZCkgd2hlbiB0aGVcbiAgLy8gZXZlbnQvcGlwZWxpbmUgZG9lc24ndCBjYXJyeSB0aGVtLlxuICBjb25zdCB7IGNvbW1pdFNoYSwgY29tbWl0UmVmLCByZXZpc2lvblVybCB9ID0gZXh0cmFjdENvbW1pdChkZXRhaWwpO1xuXG4gIGNvbnN0IGV4ZWN1dGlvbklkID0gZGV0YWlsWydleGVjdXRpb24taWQnXSBhcyBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGNvbnN0IHN0YWdlTmFtZSA9IGRldGFpbC5zdGFnZSBhcyBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGNvbnN0IGFjdGlvbk5hbWUgPSBkZXRhaWwuYWN0aW9uIGFzIHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICAvLyBFbnZpcm9ubWVudCAo4oeSIGlzRGVwbG95KSBpcyBzZXQgT05MWSB3aGVuIHRoaXMgZXZlbnQncyBzdGFnZSBpcyBsaXN0ZWQgaW4gdGhlXG4gIC8vIHBpcGVsaW5lJ3MgcGIuZGVwbG95cyB0YWcuIFBJUEVMSU5FIGV2ZW50cyBoYXZlIG5vIHN0YWdlIOKGkiBuZXZlciBhIGRlcGxveS5cbiAgY29uc3QgZW52aXJvbm1lbnQgPSBzdGFnZU5hbWUgPyBkZXBsb3lzLmdldChzdGFnZU5hbWUpIDogdW5kZWZpbmVkO1xuXG4gIC8vIFJlc29sdmUgdGhlIGNvbW1pdCByYW5nZSAob2xkZXN0LXVuc2hpcHBlZCB0aW1lc3RhbXAgKyBjb3VudCkgZm9yIGFueVxuICAvLyBldmVudCBjYXJyeWluZyBhIGNvbW1pdC4gQmVzdC1lZmZvcnQvaW4tYWNjb3VudDsgb21pdHRlZCBvbiBhbnkgZmFpbHVyZS5cbiAgLy8gR0FURUQgb24gYERPUkFfRU5BQkxFRGAgKHNldCBieSBgc2V0dXAtZXZlbnRzIC0td2l0aC1kb3JhYCk6IERPUkEgbGVhZCB0aW1lIGlzIGFuXG4gIC8vIGFkdmFuY2VkX3JlcG9ydGluZyBhZGQtb24sIHNvIG9yZ3Mgd2l0aG91dCBpdCBza2lwIHRoZSBTQ00vc2VjcmV0IGNvc3QgZW50aXJlbHkg4oCUXG4gIC8vIHN0YW5kYXJkIHJlcG9ydGluZyAoY29tbWl0U2hhICsgYWxsIG90aGVyIGZpZWxkcykgc3RpbGwgZm9yd2FyZHMgcmVnYXJkbGVzcy5cbiAgbGV0IGNvbW1pdFRpbWVzdGFtcDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBsZXQgY29tbWl0Q291bnQ6IG51bWJlciB8IHVuZGVmaW5lZDtcbiAgaWYgKGNvbW1pdFNoYSAmJiBwcm9jZXNzLmVudi5ET1JBX0VOQUJMRUQgPT09ICd0cnVlJykge1xuICAgIGNvbnN0IHNyYyA9IGNsYXNzaWZ5U291cmNlKHJldmlzaW9uVXJsKTtcbiAgICBjb25zdCBpbmZvID0gYXdhaXQgcmVzb2x2ZUNvbW1pdEluZm8ocGlwZWxpbmVJZCwgb3JnSWQsIGV2ZW50LnJlZ2lvbiwgeyBzaGE6IGNvbW1pdFNoYSwgLi4uc3JjIH0pO1xuICAgIGNvbW1pdFRpbWVzdGFtcCA9IGluZm8uY29tbWl0VGltZXN0YW1wO1xuICAgIGNvbW1pdENvdW50ID0gaW5mby5jb21taXRDb3VudDtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgb3JnSWQsXG4gICAgcGlwZWxpbmVJZCxcbiAgICBldmVudFNvdXJjZSxcbiAgICBldmVudFR5cGUsXG4gICAgc3RhdHVzOiBzdGF0ZSxcbiAgICBleGVjdXRpb25JZCxcbiAgICBzdGFnZU5hbWUsXG4gICAgYWN0aW9uTmFtZSxcbiAgICBlcnJvck1lc3NhZ2UsXG4gICAgc3RhcnRlZEF0LFxuICAgIGNvbXBsZXRlZEF0LFxuICAgIGR1cmF0aW9uTXMsXG4gICAgLi4uKGNvbW1pdFNoYSAmJiB7IGNvbW1pdFNoYSB9KSxcbiAgICAuLi4oY29tbWl0UmVmICYmIHsgY29tbWl0UmVmIH0pLFxuICAgIC4uLihjb21taXRUaW1lc3RhbXAgJiYgeyBjb21taXRUaW1lc3RhbXAgfSksXG4gICAgLi4uKGNvbW1pdENvdW50ICYmIHsgY29tbWl0Q291bnQgfSksXG4gICAgLi4uKGVudmlyb25tZW50ICYmIHsgZW52aXJvbm1lbnQgfSksXG4gICAgZGV0YWlsLFxuICB9O1xufVxuIl19
package/lib/scm.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ type SourceProvider = 'github' | 'bitbucket' | 'codecommit' | 'unknown';
2
+ export interface SourceRef {
3
+ sha: string;
4
+ provider: SourceProvider;
5
+ owner?: string;
6
+ repo?: string;
7
+ repositoryName?: string;
8
+ }
9
+ export interface CommitInfo {
10
+ commitTimestamp?: string;
11
+ commitCount?: number;
12
+ }
13
+ /** Classify a source-revision URL into a provider + repo coordinates. */
14
+ export declare function classifySource(url: string | undefined): Omit<SourceRef, 'sha'>;
15
+ /**
16
+ * Resolve `commitTimestamp` + `commitCount` for a source/deploy event, in-account,
17
+ * best-effort. Computed once per (pipelineId, sha); advances the pipeline's range
18
+ * boundary only on success. Never throws — returns {} on any failure.
19
+ */
20
+ export declare function resolveCommitInfo(pipelineId: string, orgId: string | null, region: string, src: SourceRef): Promise<CommitInfo>;
21
+ export {};
package/lib/scm.js ADDED
@@ -0,0 +1,286 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { GetSecretValueCommand, SecretsManagerClient } from '@aws-sdk/client-secrets-manager';
4
+ import { BoundedMap, CACHE_MAX_ENTRIES, loadSdk, log } from './util.js';
5
+ // Per-(pipeline,sha) resolved result — computed once, reused across the many events
6
+ // (PIPELINE/STAGE/ACTION) that share a source revision and across redeliveries.
7
+ // Only RESOLVED results are cached — an empty `{}` (SCM cooldown, a timeout, a
8
+ // 404 from a repo whose token was just added) must not pin "no commit info" for
9
+ // that sha for the container's lifetime.
10
+ const commitResultCache = new BoundedMap(CACHE_MAX_ENTRIES);
11
+ // Last sha we successfully resolved per pipeline — the exclusive lower bound for the
12
+ // next range ("commits since the last deploy"). In-memory only: a cold start resets
13
+ // it, so the first post-cold event resolves as a single commit (expected, defensive).
14
+ const lastShaByPipeline = new BoundedMap(CACHE_MAX_ENTRIES);
15
+ // Per-sha CodeCommit metadata cache (date + first-parent) for range walks.
16
+ const commitMetaCache = new BoundedMap(CACHE_MAX_ENTRIES);
17
+ // SCM rate-limit cooldown: after a 403/429 we stop calling the SCM for a while.
18
+ let scmCooldownUntil = 0;
19
+ const SCM_COOLDOWN_MS = 2 * 60 * 1000;
20
+ // Cap the CodeCommit first-parent walk so a long range can't blow the Lambda timeout.
21
+ const MAX_COMMIT_WALK = 50;
22
+ // Per-request timeout for external SCM calls (defensive against slow/hung hosts).
23
+ const SCM_FETCH_TIMEOUT_MS = 3000;
24
+ // The forwarder is a fleet Lambda: one warm container resolves events for MANY
25
+ // orgs, so the GitHub token MUST be keyed by the event's resolved org (not a single
26
+ // container-global token). Each org's token lives at `<prefix>/<orgId>/github-token`,
27
+ // derived from PLATFORM_SECRET_NAME (`<prefix>/<containerOrg>/platform`). null caches
28
+ // a definitive miss (no secret / read failed) → unauthenticated best-effort.
29
+ const githubTokenByOrg = new BoundedMap(CACHE_MAX_ENTRIES);
30
+ /**
31
+ * Derive a specific org's github-token secret name from PLATFORM_SECRET_NAME
32
+ * (`<prefix>/<containerOrg>/platform`). With an `orgId` we swap the org segment
33
+ * (`<prefix>/<orgId>/github-token`); without one (pipeline carried no OrgId tag) we
34
+ * fall back to the container's own sibling secret. Returns undefined when
35
+ * PLATFORM_SECRET_NAME isn't the expected `.../platform` shape.
36
+ */
37
+ function githubTokenSecretName(orgId) {
38
+ const name = process.env.PLATFORM_SECRET_NAME;
39
+ if (!name || !name.endsWith('/platform'))
40
+ return undefined;
41
+ const base = name.slice(0, -'/platform'.length); // <prefix>/<containerOrg>
42
+ if (orgId) {
43
+ const slash = base.lastIndexOf('/');
44
+ const prefix = slash > 0 ? base.slice(0, slash) : base;
45
+ return `${prefix}/${orgId}/github-token`;
46
+ }
47
+ return `${base}/github-token`;
48
+ }
49
+ /** Read (and cache, per org) the org github token; null → unauthenticated best-effort. */
50
+ async function getGitHubToken(orgId) {
51
+ const key = orgId ?? '';
52
+ const cached = githubTokenByOrg.get(key);
53
+ if (cached !== undefined)
54
+ return cached;
55
+ const secretName = githubTokenSecretName(orgId);
56
+ if (!secretName) {
57
+ githubTokenByOrg.set(key, null);
58
+ return null;
59
+ }
60
+ let token;
61
+ try {
62
+ const client = new SecretsManagerClient({});
63
+ const res = await client.send(new GetSecretValueCommand({ SecretId: secretName }));
64
+ // The github-token secret is a RAW token string (not JSON — CDK resolves it via
65
+ // the default SecretString with no key).
66
+ token = res.SecretString && res.SecretString.length > 0 ? res.SecretString.trim() : null;
67
+ }
68
+ catch (err) {
69
+ log.warn('No github-token secret — GitHub commit resolution will be unauthenticated', { orgId, error: err?.name });
70
+ token = null;
71
+ }
72
+ githubTokenByOrg.set(key, token);
73
+ return token;
74
+ }
75
+ async function fetchWithTimeout(url, opts) {
76
+ const controller = new AbortController();
77
+ const timer = setTimeout(() => controller.abort(), SCM_FETCH_TIMEOUT_MS);
78
+ try {
79
+ return await fetch(url, { ...opts, signal: controller.signal });
80
+ }
81
+ finally {
82
+ clearTimeout(timer);
83
+ }
84
+ }
85
+ /** Normalize a commit date to ISO 8601. Accepts ISO strings and CodeCommit's
86
+ * "<epoch-seconds> +ZZZZ" form. Returns undefined when unparseable. */
87
+ function toIso(value) {
88
+ if (typeof value !== 'string' || value.length === 0)
89
+ return undefined;
90
+ const epoch = /^(\d{9,})\b/.exec(value.trim());
91
+ if (epoch) {
92
+ const d = new Date(Number(epoch[1]) * 1000);
93
+ return Number.isNaN(d.getTime()) ? undefined : d.toISOString();
94
+ }
95
+ const d = new Date(value);
96
+ return Number.isNaN(d.getTime()) ? undefined : d.toISOString();
97
+ }
98
+ /** Classify a source-revision URL into a provider + repo coordinates. */
99
+ export function classifySource(url) {
100
+ if (!url)
101
+ return { provider: 'unknown' };
102
+ try {
103
+ const u = new URL(url);
104
+ const host = u.hostname.toLowerCase();
105
+ if (host === 'github.com' || host.endsWith('.github.com')) {
106
+ const parts = u.pathname.split('/').filter(Boolean);
107
+ if (parts.length >= 2)
108
+ return { provider: 'github', owner: parts[0], repo: parts[1].replace(/\.git$/, '') };
109
+ }
110
+ if (host === 'bitbucket.org') {
111
+ const parts = u.pathname.split('/').filter(Boolean);
112
+ if (parts.length >= 2)
113
+ return { provider: 'bitbucket', owner: parts[0], repo: parts[1].replace(/\.git$/, '') };
114
+ }
115
+ if (u.pathname.toLowerCase().includes('codecommit') || u.hash.toLowerCase().includes('codecommit') || u.pathname.includes('/repositories/')) {
116
+ const m = /repositor(?:y|ies)\/([^/#?]+)/.exec(u.pathname + u.hash);
117
+ if (m)
118
+ return { provider: 'codecommit', repositoryName: decodeURIComponent(m[1]) };
119
+ }
120
+ }
121
+ catch {
122
+ // not a URL → unknown
123
+ }
124
+ return { provider: 'unknown' };
125
+ }
126
+ let codecommitClientsByRegion;
127
+ let codecommitMod;
128
+ async function codeCommitClient(region) {
129
+ if (!codecommitMod)
130
+ codecommitMod = await loadSdk('@aws-sdk/client-codecommit');
131
+ if (!codecommitClientsByRegion)
132
+ codecommitClientsByRegion = new Map();
133
+ let client = codecommitClientsByRegion.get(region);
134
+ if (!client) {
135
+ client = new codecommitMod.CodeCommitClient({ region });
136
+ codecommitClientsByRegion.set(region, client);
137
+ }
138
+ return client;
139
+ }
140
+ /** Fetch (cached) a single CodeCommit commit's date + first parents via GetCommit. */
141
+ async function codeCommitMeta(region, repositoryName, commitId) {
142
+ const cached = commitMetaCache.get(commitId);
143
+ if (cached)
144
+ return cached;
145
+ if (!codecommitMod)
146
+ codecommitMod = await loadSdk('@aws-sdk/client-codecommit');
147
+ const client = await codeCommitClient(region);
148
+ const out = await client.send(new codecommitMod.GetCommitCommand({ repositoryName, commitId }));
149
+ const commit = out.commit;
150
+ const meta = { date: toIso(commit?.committer?.date ?? commit?.author?.date), parents: commit?.parents };
151
+ commitMetaCache.set(commitId, meta);
152
+ return meta;
153
+ }
154
+ async function resolveCodeCommit(region, repositoryName, sha, sinceSha) {
155
+ let cur = sha;
156
+ let count = 0;
157
+ let oldest;
158
+ let truncated = false;
159
+ for (let i = 0;; i++) {
160
+ if (!cur)
161
+ break; // reached history root — the whole range is covered
162
+ if (sinceSha && cur === sinceSha)
163
+ break; // reached the exclusive lower bound
164
+ if (i >= MAX_COMMIT_WALK) {
165
+ truncated = true;
166
+ break;
167
+ } // hit the cap before the boundary
168
+ const meta = await codeCommitMeta(region, repositoryName, cur);
169
+ if (!meta?.date)
170
+ break;
171
+ count++;
172
+ oldest = meta.date;
173
+ if (!sinceSha)
174
+ break; // no range → single commit
175
+ cur = meta.parents?.[0];
176
+ }
177
+ // A truncated walk yields a commit NEWER than the true oldest-unshipped commit,
178
+ // which would UNDERSTATE lead time — omit the fields entirely rather than report a
179
+ // wrong (too-small) value. Reporting falls back to `unknown`.
180
+ if (truncated)
181
+ return {};
182
+ return oldest ? { commitTimestamp: oldest, commitCount: count } : {};
183
+ }
184
+ async function resolveGitHub(owner, repo, sha, sinceSha, orgId) {
185
+ const token = await getGitHubToken(orgId);
186
+ const headers = {
187
+ 'Accept': 'application/vnd.github+json',
188
+ 'User-Agent': 'pipeline-builder-forwarder',
189
+ 'X-GitHub-Api-Version': '2022-11-28',
190
+ };
191
+ if (token)
192
+ headers.Authorization = `Bearer ${token}`;
193
+ const rateLimited = (r) => r.status === 403 || r.status === 429;
194
+ if (sinceSha) {
195
+ const r = await fetchWithTimeout(`https://api.github.com/repos/${owner}/${repo}/compare/${sinceSha}...${sha}`, { headers });
196
+ if (rateLimited(r)) {
197
+ scmCooldownUntil = Date.now() + SCM_COOLDOWN_MS;
198
+ return {};
199
+ }
200
+ if (r.ok) {
201
+ const j = await r.json();
202
+ const commits = Array.isArray(j.commits) ? j.commits : [];
203
+ if (commits.length > 0) {
204
+ const oldest = toIso(commits[0]?.commit?.committer?.date ?? commits[0]?.commit?.author?.date);
205
+ if (oldest)
206
+ return { commitTimestamp: oldest, commitCount: commits.length };
207
+ }
208
+ }
209
+ // fall through to single-commit resolution
210
+ }
211
+ const r2 = await fetchWithTimeout(`https://api.github.com/repos/${owner}/${repo}/commits/${sha}`, { headers });
212
+ if (rateLimited(r2)) {
213
+ scmCooldownUntil = Date.now() + SCM_COOLDOWN_MS;
214
+ return {};
215
+ }
216
+ if (r2.ok) {
217
+ const j = await r2.json();
218
+ const d = toIso(j.commit?.committer?.date ?? j.commit?.author?.date);
219
+ if (d)
220
+ return { commitTimestamp: d, commitCount: 1 };
221
+ }
222
+ return {};
223
+ }
224
+ async function resolveBitbucket(owner, repo, sha) {
225
+ const r = await fetchWithTimeout(`https://api.bitbucket.org/2.0/repositories/${owner}/${repo}/commit/${sha}`, {
226
+ headers: { 'User-Agent': 'pipeline-builder-forwarder', 'Accept': 'application/json' },
227
+ });
228
+ if (r.status === 429) {
229
+ scmCooldownUntil = Date.now() + SCM_COOLDOWN_MS;
230
+ return {};
231
+ }
232
+ if (r.ok) {
233
+ const j = await r.json();
234
+ const d = toIso(j.date);
235
+ if (d)
236
+ return { commitTimestamp: d, commitCount: 1 };
237
+ }
238
+ return {};
239
+ }
240
+ /**
241
+ * Resolve `commitTimestamp` + `commitCount` for a source/deploy event, in-account,
242
+ * best-effort. Computed once per (pipelineId, sha); advances the pipeline's range
243
+ * boundary only on success. Never throws — returns {} on any failure.
244
+ */
245
+ export async function resolveCommitInfo(pipelineId, orgId, region, src) {
246
+ if (src.provider === 'unknown')
247
+ return {};
248
+ const rkey = `${pipelineId}|${src.sha}`;
249
+ const cached = commitResultCache.get(rkey);
250
+ if (cached)
251
+ return cached;
252
+ const prev = lastShaByPipeline.get(pipelineId);
253
+ const sinceSha = prev && prev !== src.sha ? prev : undefined;
254
+ let info = {};
255
+ try {
256
+ if (src.provider === 'codecommit' && src.repositoryName) {
257
+ info = await resolveCodeCommit(region, src.repositoryName, src.sha, sinceSha);
258
+ }
259
+ else if (src.provider === 'github' && src.owner && src.repo) {
260
+ if (Date.now() >= scmCooldownUntil)
261
+ info = await resolveGitHub(src.owner, src.repo, src.sha, sinceSha, orgId);
262
+ }
263
+ else if (src.provider === 'bitbucket' && src.owner && src.repo) {
264
+ if (Date.now() >= scmCooldownUntil)
265
+ info = await resolveBitbucket(src.owner, src.repo, src.sha);
266
+ }
267
+ }
268
+ catch (err) {
269
+ log.warn('Commit resolution failed (omitting commitTimestamp/commitCount)', { provider: src.provider, error: err?.name ?? String(err) });
270
+ info = {};
271
+ }
272
+ if (info.commitTimestamp) {
273
+ commitResultCache.set(rkey, info);
274
+ lastShaByPipeline.set(pipelineId, src.sha);
275
+ }
276
+ return info;
277
+ }
278
+ /** @internal Test-only: forget resolved commits, SCM cooldown and cached tokens. */
279
+ export function _resetScmForTests() {
280
+ commitResultCache.clear();
281
+ lastShaByPipeline.clear();
282
+ commitMetaCache.clear();
283
+ scmCooldownUntil = 0;
284
+ githubTokenByOrg.clear();
285
+ }
286
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NtLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3NjbS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzlGLE9BQU8sRUFBRSxVQUFVLEVBQUUsaUJBQWlCLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQThCeEUsb0ZBQW9GO0FBQ3BGLGdGQUFnRjtBQUNoRiwrRUFBK0U7QUFDL0UsZ0ZBQWdGO0FBQ2hGLHlDQUF5QztBQUN6QyxNQUFNLGlCQUFpQixHQUFHLElBQUksVUFBVSxDQUFxQixpQkFBaUIsQ0FBQyxDQUFDO0FBQ2hGLHFGQUFxRjtBQUNyRixvRkFBb0Y7QUFDcEYsc0ZBQXNGO0FBQ3RGLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxVQUFVLENBQWlCLGlCQUFpQixDQUFDLENBQUM7QUFDNUUsMkVBQTJFO0FBQzNFLE1BQU0sZUFBZSxHQUFHLElBQUksVUFBVSxDQUFnRCxpQkFBaUIsQ0FBQyxDQUFDO0FBQ3pHLGdGQUFnRjtBQUNoRixJQUFJLGdCQUFnQixHQUFHLENBQUMsQ0FBQztBQUN6QixNQUFNLGVBQWUsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUN0QyxzRkFBc0Y7QUFDdEYsTUFBTSxlQUFlLEdBQUcsRUFBRSxDQUFDO0FBQzNCLGtGQUFrRjtBQUNsRixNQUFNLG9CQUFvQixHQUFHLElBQUksQ0FBQztBQUVsQywrRUFBK0U7QUFDL0Usb0ZBQW9GO0FBQ3BGLHNGQUFzRjtBQUN0RixzRkFBc0Y7QUFDdEYsNkVBQTZFO0FBQzdFLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxVQUFVLENBQXdCLGlCQUFpQixDQUFDLENBQUM7QUFFbEY7Ozs7OztHQU1HO0FBQ0gsU0FBUyxxQkFBcUIsQ0FBQyxLQUFvQjtJQUNqRCxNQUFNLElB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LENBQUMsS0FBSyxFQUFFLENBQUM7QUFDM0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBHZXRTZWNyZXRWYWx1ZUNvbW1hbmQsIFNlY3JldHNNYW5hZ2VyQ2xpZW50IH0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LXNlY3JldHMtbWFuYWdlcic7XG5pbXBvcnQgeyBCb3VuZGVkTWFwLCBDQUNIRV9NQVhfRU5UUklFUywgbG9hZFNkaywgbG9nIH0gZnJvbSAnLi91dGlsLmpzJztcblxuLy8gSW4tYWNjb3VudCBjb21taXQtcmFuZ2UgcmVzb2x1dGlvbi5cbi8vIEZvciBhIHNvdXJjZS9kZXBsb3kgZXZlbnQgY2FycnlpbmcgYSBjb21taXRTaGEgd2UgcmVzb2x2ZSB0aGUgY29tbWl0IHRpbWVzdGFtcFxuLy8gKGFuZCBob3cgbWFueSBjb21taXRzIHNoaXBwZWQpIGZvciB0aGUgcmFuZ2Ugc2luY2UgdGhlIGxhc3QgcmVzb2x2ZWQgc2hhIG9mIHRoZVxuLy8gc2FtZSBwaXBlbGluZSDigJQgZW50aXJlbHkgSU4tQUNDT1VOVCwgcGVyIHNvdXJjZSB0eXBlOlxuLy8gICDigKIgQ29kZUNvbW1pdCAg4oaSIEFXUyBTREsgR2V0Q29tbWl0ICh3YWxrIGZpcnN0LXBhcmVudHMgYmFjayB0byB0aGUgYm91bmRhcnkpLlxuLy8gICDigKIgR2l0SHViL0NvZGVDb25uZWN0aW9ucy1HaXRIdWIg4oaSIEdpdEh1YiBSRVNUIGNvbXBhcmUvY29tbWl0cyBBUEkuIEF1dGhlbnRpY2F0ZWRcbi8vICAgICB3aXRoIHRoZSBvcmcncyBgcGlwZWxpbmUtYnVpbGRlci97b3JnSWR9L2dpdGh1Yi10b2tlbmAgc2VjcmV0IHdoZW4gcHJlc2VudFxuLy8gICAgIChkZXJpdmVkIGZyb20gUExBVEZPUk1fU0VDUkVUX05BTUUpLCBvdGhlcndpc2UgYmVzdC1lZmZvcnQgdW5hdXRoZW50aWNhdGVkLlxuLy8gICDigKIgQml0YnVja2V0ICAg4oaSIEJpdGJ1Y2tldCBSRVNUIGNvbW1pdCBBUEkgKHNpbmdsZS1jb21taXQ7IHJhbmdlIHdhbGsgb21pdHRlZCkuXG4vLyBUaGUgb2xkZXN0IHVuc2hpcHBlZCBjb21taXQncyB0aW1lc3RhbXAg4oaSIGBjb21taXRUaW1lc3RhbXBgOyB0aGUgbnVtYmVyIG9mIGNvbW1pdHNcbi8vIGluIHRoZSByYW5nZSDihpIgYGNvbW1pdENvdW50YC4gRXZlcnl0aGluZyBoZXJlIGlzIEJFU1QtRUZGT1JUOiBvbiBhbnkgZmFpbHVyZSB0aGVcbi8vIGZpZWxkcyBhcmUgc2ltcGx5IG9taXR0ZWQgKHJlcG9ydGluZyBmYWxscyBiYWNrIHRvIGB1bmtub3duYCkuIEl0IG11c3QgTkVWRVIgZmFpbFxuLy8gdGhlIGJhdGNoLlxuLy9cbi8vIElBTSByZXF1aXJlZCBieSB0aGlzIHBhdGggKGRvY3VtZW50IG9ubHkg4oCUIGdyYW50ZWQgb24gdGhlIGV2ZW50cyBzdGFjayk6XG4vLyAgIOKAoiBjb2RlY29tbWl0OkdldENvbW1pdCAgICAgICAgICAgIChDb2RlQ29tbWl0IHNvdXJjZXMpXG4vLyAgIOKAoiBzZWNyZXRzbWFuYWdlcjpHZXRTZWNyZXRWYWx1ZSBvbiBgcGlwZWxpbmUtYnVpbGRlci8qL2dpdGh1Yi10b2tlbmAgKHRva2VuIFNDTSBzb3VyY2VzKVxuXG50eXBlIFNvdXJjZVByb3ZpZGVyID0gJ2dpdGh1YicgfCAnYml0YnVja2V0JyB8ICdjb2RlY29tbWl0JyB8ICd1bmtub3duJztcbmV4cG9ydCBpbnRlcmZhY2UgU291cmNlUmVmIHtcbiAgc2hhOiBzdHJpbmc7XG4gIHByb3ZpZGVyOiBTb3VyY2VQcm92aWRlcjtcbiAgb3duZXI/OiBzdHJpbmc7XG4gIHJlcG8/OiBzdHJpbmc7XG4gIHJlcG9zaXRvcnlOYW1lPzogc3RyaW5nO1xufVxuZXhwb3J0IGludGVyZmFjZSBDb21taXRJbmZvIHsgY29tbWl0VGltZXN0YW1wPzogc3RyaW5nOyBjb21taXRDb3VudD86IG51bWJlciB9XG5cbi8vIFBlci0ocGlwZWxpbmUsc2hhKSByZXNvbHZlZCByZXN1bHQg4oCUIGNvbXB1dGVkIG9uY2UsIHJldXNlZCBhY3Jvc3MgdGhlIG1hbnkgZXZlbnRzXG4vLyAoUElQRUxJTkUvU1RBR0UvQUNUSU9OKSB0aGF0IHNoYXJlIGEgc291cmNlIHJldmlzaW9uIGFuZCBhY3Jvc3MgcmVkZWxpdmVyaWVzLlxuLy8gT25seSBSRVNPTFZFRCByZXN1bHRzIGFyZSBjYWNoZWQg4oCUIGFuIGVtcHR5IGB7fWAgKFNDTSBjb29sZG93biwgYSB0aW1lb3V0LCBhXG4vLyA0MDQgZnJvbSBhIHJlcG8gd2hvc2UgdG9rZW4gd2FzIGp1c3QgYWRkZWQpIG11c3Qgbm90IHBpbiBcIm5vIGNvbW1pdCBpbmZvXCIgZm9yXG4vLyB0aGF0IHNoYSBmb3IgdGhlIGNvbnRhaW5lcidzIGxpZmV0aW1lLlxuY29uc3QgY29tbWl0UmVzdWx0Q2FjaGUgPSBuZXcgQm91bmRlZE1hcDxzdHJpbmcsIENvbW1pdEluZm8+KENBQ0hFX01BWF9FTlRSSUVTKTtcbi8vIExhc3Qgc2hhIHdlIHN1Y2Nlc3NmdWxseSByZXNvbHZlZCBwZXIgcGlwZWxpbmUg4oCUIHRoZSBleGNsdXNpdmUgbG93ZXIgYm91bmQgZm9yIHRoZVxuLy8gbmV4dCByYW5nZSAoXCJjb21taXRzIHNpbmNlIHRoZSBsYXN0IGRlcGxveVwiKS4gSW4tbWVtb3J5IG9ubHk6IGEgY29sZCBzdGFydCByZXNldHNcbi8vIGl0LCBzbyB0aGUgZmlyc3QgcG9zdC1jb2xkIGV2ZW50IHJlc29sdmVzIGFzIGEgc2luZ2xlIGNvbW1pdCAoZXhwZWN0ZWQsIGRlZmVuc2l2ZSkuXG5jb25zdCBsYXN0U2hhQnlQaXBlbGluZSA9IG5ldyBCb3VuZGVkTWFwPHN0cmluZywgc3RyaW5nPihDQUNIRV9NQVhfRU5UUklFUyk7XG4vLyBQZXItc2hhIENvZGVDb21taXQgbWV0YWRhdGEgY2FjaGUgKGRhdGUgKyBmaXJzdC1wYXJlbnQpIGZvciByYW5nZSB3YWxrcy5cbmNvbnN0IGNvbW1pdE1ldGFDYWNoZSA9IG5ldyBCb3VuZGVkTWFwPHN0cmluZywgeyBkYXRlPzogc3RyaW5nOyBwYXJlbnRzPzogc3RyaW5nW10gfT4oQ0FDSEVfTUFYX0VOVFJJRVMpO1xuLy8gU0NNIHJhdGUtbGltaXQgY29vbGRvd246IGFmdGVyIGEgNDAzLzQyOSB3ZSBzdG9wIGNhbGxpbmcgdGhlIFNDTSBmb3IgYSB3aGlsZS5cbmxldCBzY21Db29sZG93blVudGlsID0gMDtcbmNvbnN0IFNDTV9DT09MRE9XTl9NUyA9IDIgKiA2MCAqIDEwMDA7XG4vLyBDYXAgdGhlIENvZGVDb21taXQgZmlyc3QtcGFyZW50IHdhbGsgc28gYSBsb25nIHJhbmdlIGNhbid0IGJsb3cgdGhlIExhbWJkYSB0aW1lb3V0LlxuY29uc3QgTUFYX0NPTU1JVF9XQUxLID0gNTA7XG4vLyBQZXItcmVxdWVzdCB0aW1lb3V0IGZvciBleHRlcm5hbCBTQ00gY2FsbHMgKGRlZmVuc2l2ZSBhZ2FpbnN0IHNsb3cvaHVuZyBob3N0cykuXG5jb25zdCBTQ01fRkVUQ0hfVElNRU9VVF9NUyA9IDMwMDA7XG5cbi8vIFRoZSBmb3J3YXJkZXIgaXMgYSBmbGVldCBMYW1iZGE6IG9uZSB3YXJtIGNvbnRhaW5lciByZXNvbHZlcyBldmVudHMgZm9yIE1BTllcbi8vIG9yZ3MsIHNvIHRoZSBHaXRIdWIgdG9rZW4gTVVTVCBiZSBrZXllZCBieSB0aGUgZXZlbnQncyByZXNvbHZlZCBvcmcgKG5vdCBhIHNpbmdsZVxuLy8gY29udGFpbmVyLWdsb2JhbCB0b2tlbikuIEVhY2ggb3JnJ3MgdG9rZW4gbGl2ZXMgYXQgYDxwcmVmaXg+LzxvcmdJZD4vZ2l0aHViLXRva2VuYCxcbi8vIGRlcml2ZWQgZnJvbSBQTEFURk9STV9TRUNSRVRfTkFNRSAoYDxwcmVmaXg+Lzxjb250YWluZXJPcmc+L3BsYXRmb3JtYCkuIG51bGwgY2FjaGVzXG4vLyBhIGRlZmluaXRpdmUgbWlzcyAobm8gc2VjcmV0IC8gcmVhZCBmYWlsZWQpIOKGkiB1bmF1dGhlbnRpY2F0ZWQgYmVzdC1lZmZvcnQuXG5jb25zdCBnaXRodWJUb2tlbkJ5T3JnID0gbmV3IEJvdW5kZWRNYXA8c3RyaW5nLCBzdHJpbmcgfCBudWxsPihDQUNIRV9NQVhfRU5UUklFUyk7XG5cbi8qKlxuICogRGVyaXZlIGEgc3BlY2lmaWMgb3JnJ3MgZ2l0aHViLXRva2VuIHNlY3JldCBuYW1lIGZyb20gUExBVEZPUk1fU0VDUkVUX05BTUVcbiAqIChgPHByZWZpeD4vPGNvbnRhaW5lck9yZz4vcGxhdGZvcm1gKS4gV2l0aCBhbiBgb3JnSWRgIHdlIHN3YXAgdGhlIG9yZyBzZWdtZW50XG4gKiAoYDxwcmVmaXg+LzxvcmdJZD4vZ2l0aHViLXRva2VuYCk7IHdpdGhvdXQgb25lIChwaXBlbGluZSBjYXJyaWVkIG5vIE9yZ0lkIHRhZykgd2VcbiAqIGZhbGwgYmFjayB0byB0aGUgY29udGFpbmVyJ3Mgb3duIHNpYmxpbmcgc2VjcmV0LiBSZXR1cm5zIHVuZGVmaW5lZCB3aGVuXG4gKiBQTEFURk9STV9TRUNSRVRfTkFNRSBpc24ndCB0aGUgZXhwZWN0ZWQgYC4uLi9wbGF0Zm9ybWAgc2hhcGUuXG4gKi9cbmZ1bmN0aW9uIGdpdGh1YlRva2VuU2VjcmV0TmFtZShvcmdJZDogc3RyaW5nIHwgbnVsbCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IG5hbWUgPSBwcm9jZXNzLmVudi5QTEFURk9STV9TRUNSRVRfTkFNRTtcbiAgaWYgKCFuYW1lIHx8ICFuYW1lLmVuZHNXaXRoKCcvcGxhdGZvcm0nKSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgYmFzZSA9IG5hbWUuc2xpY2UoMCwgLScvcGxhdGZvcm0nLmxlbmd0aCk7IC8vIDxwcmVmaXg+Lzxjb250YWluZXJPcmc+XG4gIGlmIChvcmdJZCkge1xuICAgIGNvbnN0IHNsYXNoID0gYmFzZS5sYXN0SW5kZXhPZignLycpO1xuICAgIGNvbnN0IHByZWZpeCA9IHNsYXNoID4gMCA/IGJhc2Uuc2xpY2UoMCwgc2xhc2gpIDogYmFzZTtcbiAgICByZXR1cm4gYCR7cHJlZml4fS8ke29yZ0lkfS9naXRodWItdG9rZW5gO1xuICB9XG4gIHJldHVybiBgJHtiYXNlfS9naXRodWItdG9rZW5gO1xufVxuXG4vKiogUmVhZCAoYW5kIGNhY2hlLCBwZXIgb3JnKSB0aGUgb3JnIGdpdGh1YiB0b2tlbjsgbnVsbCDihpIgdW5hdXRoZW50aWNhdGVkIGJlc3QtZWZmb3J0LiAqL1xuYXN5bmMgZnVuY3Rpb24gZ2V0R2l0SHViVG9rZW4ob3JnSWQ6IHN0cmluZyB8IG51bGwpOiBQcm9taXNlPHN0cmluZyB8IG51bGw+IHtcbiAgY29uc3Qga2V5ID0gb3JnSWQgPz8gJyc7XG4gIGNvbnN0IGNhY2hlZCA9IGdpdGh1YlRva2VuQnlPcmcuZ2V0KGtleSk7XG4gIGlmIChjYWNoZWQgIT09IHVuZGVmaW5lZCkgcmV0dXJuIGNhY2hlZDtcbiAgY29uc3Qgc2VjcmV0TmFtZSA9IGdpdGh1YlRva2VuU2VjcmV0TmFtZShvcmdJZCk7XG4gIGlmICghc2VjcmV0TmFtZSkgeyBnaXRodWJUb2tlbkJ5T3JnLnNldChrZXksIG51bGwpOyByZXR1cm4gbnVsbDsgfVxuICBsZXQgdG9rZW46IHN0cmluZyB8IG51bGw7XG4gIHRyeSB7XG4gICAgY29uc3QgY2xpZW50ID0gbmV3IFNlY3JldHNNYW5hZ2VyQ2xpZW50KHt9KTtcbiAgICBjb25zdCByZXMgPSBhd2FpdCBjbGllbnQuc2VuZChuZXcgR2V0U2VjcmV0VmFsdWVDb21tYW5kKHsgU2VjcmV0SWQ6IHNlY3JldE5hbWUgfSkpO1xuICAgIC8vIFRoZSBnaXRodWItdG9rZW4gc2VjcmV0IGlzIGEgUkFXIHRva2VuIHN0cmluZyAobm90IEpTT04g4oCUIENESyByZXNvbHZlcyBpdCB2aWFcbiAgICAvLyB0aGUgZGVmYXVsdCBTZWNyZXRTdHJpbmcgd2l0aCBubyBrZXkpLlxuICAgIHRva2VuID0gcmVzLlNlY3JldFN0cmluZyAmJiByZXMuU2VjcmV0U3RyaW5nLmxlbmd0aCA+IDAgPyByZXMuU2VjcmV0U3RyaW5nLnRyaW0oKSA6IG51bGw7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZy53YXJuKCdObyBnaXRodWItdG9rZW4gc2VjcmV0IOKAlCBHaXRIdWIgY29tbWl0IHJlc29sdXRpb24gd2lsbCBiZSB1bmF1dGhlbnRpY2F0ZWQnLCB7IG9yZ0lkLCBlcnJvcjogKGVyciBhcyB7IG5hbWU/OiBzdHJpbmcgfSk/Lm5hbWUgfSk7XG4gICAgdG9rZW4gPSBudWxsO1xuICB9XG4gIGdpdGh1YlRva2VuQnlPcmcuc2V0KGtleSwgdG9rZW4pO1xuICByZXR1cm4gdG9rZW47XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZldGNoV2l0aFRpbWVvdXQodXJsOiBzdHJpbmcsIG9wdHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogUHJvbWlzZTxSZXNwb25zZT4ge1xuICBjb25zdCBjb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICBjb25zdCB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4gY29udHJvbGxlci5hYm9ydCgpLCBTQ01fRkVUQ0hfVElNRU9VVF9NUyk7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGF3YWl0IGZldGNoKHVybCwgeyAuLi5vcHRzLCBzaWduYWw6IGNvbnRyb2xsZXIuc2lnbmFsIH0pO1xuICB9IGZpbmFsbHkge1xuICAgIGNsZWFyVGltZW91dCh0aW1lcik7XG4gIH1cbn1cblxuLyoqIE5vcm1hbGl6ZSBhIGNvbW1pdCBkYXRlIHRvIElTTyA4NjAxLiBBY2NlcHRzIElTTyBzdHJpbmdzIGFuZCBDb2RlQ29tbWl0J3NcbiAqICBcIjxlcG9jaC1zZWNvbmRzPiArWlpaWlwiIGZvcm0uIFJldHVybnMgdW5kZWZpbmVkIHdoZW4gdW5wYXJzZWFibGUuICovXG5mdW5jdGlvbiB0b0lzbyh2YWx1ZTogdW5rbm93bik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmICh0eXBlb2YgdmFsdWUgIT09ICdzdHJpbmcnIHx8IHZhbHVlLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgZXBvY2ggPSAvXihcXGR7OSx9KVxcYi8uZXhlYyh2YWx1ZS50cmltKCkpO1xuICBpZiAoZXBvY2gpIHtcbiAgICBjb25zdCBkID0gbmV3IERhdGUoTnVtYmVyKGVwb2NoWzFdKSAqIDEwMDApO1xuICAgIHJldHVybiBOdW1iZXIuaXNOYU4oZC5nZXRUaW1lKCkpID8gdW5kZWZpbmVkIDogZC50b0lTT1N0cmluZygpO1xuICB9XG4gIGNvbnN0IGQgPSBuZXcgRGF0ZSh2YWx1ZSk7XG4gIHJldHVybiBOdW1iZXIuaXNOYU4oZC5nZXRUaW1lKCkpID8gdW5kZWZpbmVkIDogZC50b0lTT1N0cmluZygpO1xufVxuXG4vKiogQ2xhc3NpZnkgYSBzb3VyY2UtcmV2aXNpb24gVVJMIGludG8gYSBwcm92aWRlciArIHJlcG8gY29vcmRpbmF0ZXMuICovXG5leHBvcnQgZnVuY3Rpb24gY2xhc3NpZnlTb3VyY2UodXJsOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBPbWl0PFNvdXJjZVJlZiwgJ3NoYSc+IHtcbiAgaWYgKCF1cmwpIHJldHVybiB7IHByb3ZpZGVyOiAndW5rbm93bicgfTtcbiAgdHJ5IHtcbiAgICBjb25zdCB1ID0gbmV3IFVSTCh1cmwpO1xuICAgIGNvbnN0IGhvc3QgPSB1Lmhvc3RuYW1lLnRvTG93ZXJDYXNlKCk7XG4gICAgaWYgKGhvc3QgPT09ICdnaXRodWIuY29tJyB8fCBob3N0LmVuZHNXaXRoKCcuZ2l0aHViLmNvbScpKSB7XG4gICAgICBjb25zdCBwYXJ0cyA9IHUucGF0aG5hbWUuc3BsaXQoJy8nKS5maWx0ZXIoQm9vbGVhbik7XG4gICAgICBpZiAocGFydHMubGVuZ3RoID49IDIpIHJldHVybiB7IHByb3ZpZGVyOiAnZ2l0aHViJywgb3duZXI6IHBhcnRzWzBdLCByZXBvOiBwYXJ0c1sxXS5yZXBsYWNlKC9cXC5naXQkLywgJycpIH07XG4gICAgfVxuICAgIGlmIChob3N0ID09PSAnYml0YnVja2V0Lm9yZycpIHtcbiAgICAgIGNvbnN0IHBhcnRzID0gdS5wYXRobmFtZS5zcGxpdCgnLycpLmZpbHRlcihCb29sZWFuKTtcbiAgICAgIGlmIChwYXJ0cy5sZW5ndGggPj0gMikgcmV0dXJuIHsgcHJvdmlkZXI6ICdiaXRidWNrZXQnLCBvd25lcjogcGFydHNbMF0sIHJlcG86IHBhcnRzWzFdLnJlcGxhY2UoL1xcLmdpdCQvLCAnJykgfTtcbiAgICB9XG4gICAgaWYgKHUucGF0aG5hbWUudG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnY29kZWNvbW1pdCcpIHx8IHUuaGFzaC50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKCdjb2RlY29tbWl0JykgfHwgdS5wYXRobmFtZS5pbmNsdWRlcygnL3JlcG9zaXRvcmllcy8nKSkge1xuICAgICAgY29uc3QgbSA9IC9yZXBvc2l0b3IoPzp5fGllcylcXC8oW14vIz9dKykvLmV4ZWModS5wYXRobmFtZSArIHUuaGFzaCk7XG4gICAgICBpZiAobSkgcmV0dXJuIHsgcHJvdmlkZXI6ICdjb2RlY29tbWl0JywgcmVwb3NpdG9yeU5hbWU6IGRlY29kZVVSSUNvbXBvbmVudChtWzFdKSB9O1xuICAgIH1cbiAgfSBjYXRjaCB7XG4gICAgLy8gbm90IGEgVVJMIOKGkiB1bmtub3duXG4gIH1cbiAgcmV0dXJuIHsgcHJvdmlkZXI6ICd1bmtub3duJyB9O1xufVxuXG5sZXQgY29kZWNvbW1pdENsaWVudHNCeVJlZ2lvbjogTWFwPHN0cmluZywgeyBzZW5kKGNvbW1hbmQ6IHVua25vd24pOiBQcm9taXNlPHVua25vd24+IH0+IHwgdW5kZWZpbmVkO1xuaW50ZXJmYWNlIENvZGVDb21taXRNb2R1bGUge1xuICBDb2RlQ29tbWl0Q2xpZW50OiBuZXcgKGNvbmZpZzogeyByZWdpb246IHN0cmluZyB9KSA9PiB7IHNlbmQoY29tbWFuZDogdW5rbm93bik6IFByb21pc2U8dW5rbm93bj4gfTtcbiAgR2V0Q29tbWl0Q29tbWFuZDogbmV3IChpbnB1dDogeyByZXBvc2l0b3J5TmFtZTogc3RyaW5nOyBjb21taXRJZDogc3RyaW5nIH0pID0+IHVua25vd247XG59XG5sZXQgY29kZWNvbW1pdE1vZDogQ29kZUNvbW1pdE1vZHVsZSB8IHVuZGVmaW5lZDtcbmFzeW5jIGZ1bmN0aW9uIGNvZGVDb21taXRDbGllbnQocmVnaW9uOiBzdHJpbmcpOiBQcm9taXNlPHsgc2VuZChjb21tYW5kOiB1bmtub3duKTogUHJvbWlzZTx1bmtub3duPiB9PiB7XG4gIGlmICghY29kZWNvbW1pdE1vZCkgY29kZWNvbW1pdE1vZCA9IGF3YWl0IGxvYWRTZGs8Q29kZUNvbW1pdE1vZHVsZT4oJ0Bhd3Mtc2RrL2NsaWVudC1jb2RlY29tbWl0Jyk7XG4gIGlmICghY29kZWNvbW1pdENsaWVudHNCeVJlZ2lvbikgY29kZWNvbW1pdENsaWVudHNCeVJlZ2lvbiA9IG5ldyBNYXAoKTtcbiAgbGV0IGNsaWVudCA9IGNvZGVjb21taXRDbGllbnRzQnlSZWdpb24uZ2V0KHJlZ2lvbik7XG4gIGlmICghY2xpZW50KSB7XG4gICAgY2xpZW50ID0gbmV3IGNvZGVjb21taXRNb2QuQ29kZUNvbW1pdENsaWVudCh7IHJlZ2lvbiB9KTtcbiAgICBjb2RlY29tbWl0Q2xpZW50c0J5UmVnaW9uLnNldChyZWdpb24sIGNsaWVudCk7XG4gIH1cbiAgcmV0dXJuIGNsaWVudDtcbn1cblxuLyoqIEZldGNoIChjYWNoZWQpIGEgc2luZ2xlIENvZGVDb21taXQgY29tbWl0J3MgZGF0ZSArIGZpcnN0IHBhcmVudHMgdmlhIEdldENvbW1pdC4gKi9cbmFzeW5jIGZ1bmN0aW9uIGNvZGVDb21taXRNZXRhKHJlZ2lvbjogc3RyaW5nLCByZXBvc2l0b3J5TmFtZTogc3RyaW5nLCBjb21taXRJZDogc3RyaW5nKTogUHJvbWlzZTx7IGRhdGU/OiBzdHJpbmc7IHBhcmVudHM/OiBzdHJpbmdbXSB9IHwgdW5kZWZpbmVkPiB7XG4gIGNvbnN0IGNhY2hlZCA9IGNvbW1pdE1ldGFDYWNoZS5nZXQoY29tbWl0SWQpO1xuICBpZiAoY2FjaGVkKSByZXR1cm4gY2FjaGVkO1xuICBpZiAoIWNvZGVjb21taXRNb2QpIGNvZGVjb21taXRNb2QgPSBhd2FpdCBsb2FkU2RrPENvZGVDb21taXRNb2R1bGU+KCdAYXdzLXNkay9jbGllbnQtY29kZWNvbW1pdCcpO1xuICBjb25zdCBjbGllbnQgPSBhd2FpdCBjb2RlQ29tbWl0Q2xpZW50KHJlZ2lvbik7XG4gIGNvbnN0IG91dCA9IGF3YWl0IGNsaWVudC5zZW5kKG5ldyBjb2RlY29tbWl0TW9kLkdldENvbW1pdENvbW1hbmQoeyByZXBvc2l0b3J5TmFtZSwgY29tbWl0SWQgfSkpIGFzIHtcbiAgICBjb21taXQ/OiB7IGNvbW1pdHRlcj86IHsgZGF0ZT86IHN0cmluZyB9OyBhdXRob3I/OiB7IGRhdGU/OiBzdHJpbmcgfTsgcGFyZW50cz86IHN0cmluZ1tdIH07XG4gIH07XG4gIGNvbnN0IGNvbW1pdCA9IG91dC5jb21taXQ7XG4gIGNvbnN0IG1ldGEgPSB7IGRhdGU6IHRvSXNvKGNvbW1pdD8uY29tbWl0dGVyPy5kYXRlID8/IGNvbW1pdD8uYXV0aG9yPy5kYXRlKSwgcGFyZW50czogY29tbWl0Py5wYXJlbnRzIH07XG4gIGNvbW1pdE1ldGFDYWNoZS5zZXQoY29tbWl0SWQsIG1ldGEpO1xuICByZXR1cm4gbWV0YTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZUNvZGVDb21taXQocmVnaW9uOiBzdHJpbmcsIHJlcG9zaXRvcnlOYW1lOiBzdHJpbmcsIHNoYTogc3RyaW5nLCBzaW5jZVNoYT86IHN0cmluZyk6IFByb21pc2U8Q29tbWl0SW5mbz4ge1xuICBsZXQgY3VyOiBzdHJpbmcgfCB1bmRlZmluZWQgPSBzaGE7XG4gIGxldCBjb3VudCA9IDA7XG4gIGxldCBvbGRlc3Q6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgbGV0IHRydW5jYXRlZCA9IGZhbHNlO1xuICBmb3IgKGxldCBpID0gMDsgOyBpKyspIHtcbiAgICBpZiAoIWN1cikgYnJlYWs7IC8vIHJlYWNoZWQgaGlzdG9yeSByb290IOKAlCB0aGUgd2hvbGUgcmFuZ2UgaXMgY292ZXJlZFxuICAgIGlmIChzaW5jZVNoYSAmJiBjdXIgPT09IHNpbmNlU2hhKSBicmVhazsgLy8gcmVhY2hlZCB0aGUgZXhjbHVzaXZlIGxvd2VyIGJvdW5kXG4gICAgaWYgKGkgPj0gTUFYX0NPTU1JVF9XQUxLKSB7IHRydW5jYXRlZCA9IHRydWU7IGJyZWFrOyB9IC8vIGhpdCB0aGUgY2FwIGJlZm9yZSB0aGUgYm91bmRhcnlcbiAgICBjb25zdCBtZXRhID0gYXdhaXQgY29kZUNvbW1pdE1ldGEocmVnaW9uLCByZXBvc2l0b3J5TmFtZSwgY3VyKTtcbiAgICBpZiAoIW1ldGE/LmRhdGUpIGJyZWFrO1xuICAgIGNvdW50Kys7XG4gICAgb2xkZXN0ID0gbWV0YS5kYXRlO1xuICAgIGlmICghc2luY2VTaGEpIGJyZWFrOyAvLyBubyByYW5nZSDihpIgc2luZ2xlIGNvbW1pdFxuICAgIGN1ciA9IG1ldGEucGFyZW50cz8uWzBdO1xuICB9XG4gIC8vIEEgdHJ1bmNhdGVkIHdhbGsgeWllbGRzIGEgY29tbWl0IE5FV0VSIHRoYW4gdGhlIHRydWUgb2xkZXN0LXVuc2hpcHBlZCBjb21taXQsXG4gIC8vIHdoaWNoIHdvdWxkIFVOREVSU1RBVEUgbGVhZCB0aW1lIOKAlCBvbWl0IHRoZSBmaWVsZHMgZW50aXJlbHkgcmF0aGVyIHRoYW4gcmVwb3J0IGFcbiAgLy8gd3JvbmcgKHRvby1zbWFsbCkgdmFsdWUuIFJlcG9ydGluZyBmYWxscyBiYWNrIHRvIGB1bmtub3duYC5cbiAgaWYgKHRydW5jYXRlZCkgcmV0dXJuIHt9O1xuICByZXR1cm4gb2xkZXN0ID8geyBjb21taXRUaW1lc3RhbXA6IG9sZGVzdCwgY29tbWl0Q291bnQ6IGNvdW50IH0gOiB7fTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZUdpdEh1Yihvd25lcjogc3RyaW5nLCByZXBvOiBzdHJpbmcsIHNoYTogc3RyaW5nLCBzaW5jZVNoYTogc3RyaW5nIHwgdW5kZWZpbmVkLCBvcmdJZDogc3RyaW5nIHwgbnVsbCk6IFByb21pc2U8Q29tbWl0SW5mbz4ge1xuICBjb25zdCB0b2tlbiA9IGF3YWl0IGdldEdpdEh1YlRva2VuKG9yZ0lkKTtcbiAgY29uc3QgaGVhZGVyczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICAnQWNjZXB0JzogJ2FwcGxpY2F0aW9uL3ZuZC5naXRodWIranNvbicsXG4gICAgJ1VzZXItQWdlbnQnOiAncGlwZWxpbmUtYnVpbGRlci1mb3J3YXJkZXInLFxuICAgICdYLUdpdEh1Yi1BcGktVmVyc2lvbic6ICcyMDIyLTExLTI4JyxcbiAgfTtcbiAgaWYgKHRva2VuKSBoZWFkZXJzLkF1dGhvcml6YXRpb24gPSBgQmVhcmVyICR7dG9rZW59YDtcbiAgY29uc3QgcmF0ZUxpbWl0ZWQgPSAocjogUmVzcG9uc2UpID0+IHIuc3RhdHVzID09PSA0MDMgfHwgci5zdGF0dXMgPT09IDQyOTtcblxuICBpZiAoc2luY2VTaGEpIHtcbiAgICBjb25zdCByID0gYXdhaXQgZmV0Y2hXaXRoVGltZW91dChgaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy8ke293bmVyfS8ke3JlcG99L2NvbXBhcmUvJHtzaW5jZVNoYX0uLi4ke3NoYX1gLCB7IGhlYWRlcnMgfSk7XG4gICAgaWYgKHJhdGVMaW1pdGVkKHIpKSB7IHNjbUNvb2xkb3duVW50aWwgPSBEYXRlLm5vdygpICsgU0NNX0NPT0xET1dOX01TOyByZXR1cm4ge307IH1cbiAgICBpZiAoci5vaykge1xuICAgICAgY29uc3QgaiA9IGF3YWl0IHIuanNvbigpIGFzIHsgY29tbWl0cz86IEFycmF5PHsgY29tbWl0PzogeyBjb21taXR0ZXI/OiB7IGRhdGU/OiBzdHJpbmcgfTsgYXV0aG9yPzogeyBkYXRlPzogc3RyaW5nIH0gfSB9PiB9O1xuICAgICAgY29uc3QgY29tbWl0cyA9IEFycmF5LmlzQXJyYXkoai5jb21taXRzKSA/IGouY29tbWl0cyA6IFtdO1xuICAgICAgaWYgKGNvbW1pdHMubGVuZ3RoID4gMCkge1xuICAgICAgICBjb25zdCBvbGRlc3QgPSB0b0lzbyhjb21taXRzWzBdPy5jb21taXQ/LmNvbW1pdHRlcj8uZGF0ZSA/PyBjb21taXRzWzBdPy5jb21taXQ/LmF1dGhvcj8uZGF0ZSk7XG4gICAgICAgIGlmIChvbGRlc3QpIHJldHVybiB7IGNvbW1pdFRpbWVzdGFtcDogb2xkZXN0LCBjb21taXRDb3VudDogY29tbWl0cy5sZW5ndGggfTtcbiAgICAgIH1cbiAgICB9XG4gICAgLy8gZmFsbCB0aHJvdWdoIHRvIHNpbmdsZS1jb21taXQgcmVzb2x1dGlvblxuICB9XG4gIGNvbnN0IHIyID0gYXdhaXQgZmV0Y2hXaXRoVGltZW91dChgaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy8ke293bmVyfS8ke3JlcG99L2NvbW1pdHMvJHtzaGF9YCwgeyBoZWFkZXJzIH0pO1xuICBpZiAocmF0ZUxpbWl0ZWQocjIpKSB7IHNjbUNvb2xkb3duVW50aWwgPSBEYXRlLm5vdygpICsgU0NNX0NPT0xET1dOX01TOyByZXR1cm4ge307IH1cbiAgaWYgKHIyLm9rKSB7XG4gICAgY29uc3QgaiA9IGF3YWl0IHIyLmpzb24oKSBhcyB7IGNvbW1pdD86IHsgY29tbWl0dGVyPzogeyBkYXRlPzogc3RyaW5nIH07IGF1dGhvcj86IHsgZGF0ZT86IHN0cmluZyB9IH0gfTtcbiAgICBjb25zdCBkID0gdG9Jc28oai5jb21taXQ/LmNvbW1pdHRlcj8uZGF0ZSA/PyBqLmNvbW1pdD8uYXV0aG9yPy5kYXRlKTtcbiAgICBpZiAoZCkgcmV0dXJuIHsgY29tbWl0VGltZXN0YW1wOiBkLCBjb21taXRDb3VudDogMSB9O1xuICB9XG4gIHJldHVybiB7fTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZUJpdGJ1Y2tldChvd25lcjogc3RyaW5nLCByZXBvOiBzdHJpbmcsIHNoYTogc3RyaW5nKTogUHJvbWlzZTxDb21taXRJbmZvPiB7XG4gIGNvbnN0IHIgPSBhd2FpdCBmZXRjaFdpdGhUaW1lb3V0KGBodHRwczovL2FwaS5iaXRidWNrZXQub3JnLzIuMC9yZXBvc2l0b3JpZXMvJHtvd25lcn0vJHtyZXBvfS9jb21taXQvJHtzaGF9YCwge1xuICAgIGhlYWRlcnM6IHsgJ1VzZXItQWdlbnQnOiAncGlwZWxpbmUtYnVpbGRlci1mb3J3YXJkZXInLCAnQWNjZXB0JzogJ2FwcGxpY2F0aW9uL2pzb24nIH0sXG4gIH0pO1xuICBpZiAoci5zdGF0dXMgPT09IDQyOSkgeyBzY21Db29sZG93blVudGlsID0gRGF0ZS5ub3coKSArIFNDTV9DT09MRE9XTl9NUzsgcmV0dXJuIHt9OyB9XG4gIGlmIChyLm9rKSB7XG4gICAgY29uc3QgaiA9IGF3YWl0IHIuanNvbigpIGFzIHsgZGF0ZT86IHN0cmluZyB9O1xuICAgIGNvbnN0IGQgPSB0b0lzbyhqLmRhdGUpO1xuICAgIGlmIChkKSByZXR1cm4geyBjb21taXRUaW1lc3RhbXA6IGQsIGNvbW1pdENvdW50OiAxIH07XG4gIH1cbiAgcmV0dXJuIHt9O1xufVxuXG4vKipcbiAqIFJlc29sdmUgYGNvbW1pdFRpbWVzdGFtcGAgKyBgY29tbWl0Q291bnRgIGZvciBhIHNvdXJjZS9kZXBsb3kgZXZlbnQsIGluLWFjY291bnQsXG4gKiBiZXN0LWVmZm9ydC4gQ29tcHV0ZWQgb25jZSBwZXIgKHBpcGVsaW5lSWQsIHNoYSk7IGFkdmFuY2VzIHRoZSBwaXBlbGluZSdzIHJhbmdlXG4gKiBib3VuZGFyeSBvbmx5IG9uIHN1Y2Nlc3MuIE5ldmVyIHRocm93cyDigJQgcmV0dXJucyB7fSBvbiBhbnkgZmFpbHVyZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlc29sdmVDb21taXRJbmZvKHBpcGVsaW5lSWQ6IHN0cmluZywgb3JnSWQ6IHN0cmluZyB8IG51bGwsIHJlZ2lvbjogc3RyaW5nLCBzcmM6IFNvdXJjZVJlZik6IFByb21pc2U8Q29tbWl0SW5mbz4ge1xuICBpZiAoc3JjLnByb3ZpZGVyID09PSAndW5rbm93bicpIHJldHVybiB7fTtcbiAgY29uc3QgcmtleSA9IGAke3BpcGVsaW5lSWR9fCR7c3JjLnNoYX1gO1xuICBjb25zdCBjYWNoZWQgPSBjb21taXRSZXN1bHRDYWNoZS5nZXQocmtleSk7XG4gIGlmIChjYWNoZWQpIHJldHVybiBjYWNoZWQ7XG5cbiAgY29uc3QgcHJldiA9IGxhc3RTaGFCeVBpcGVsaW5lLmdldChwaXBlbGluZUlkKTtcbiAgY29uc3Qgc2luY2VTaGEgPSBwcmV2ICYmIHByZXYgIT09IHNyYy5zaGEgPyBwcmV2IDogdW5kZWZpbmVkO1xuXG4gIGxldCBpbmZvOiBDb21taXRJbmZvID0ge307XG4gIHRyeSB7XG4gICAgaWYgKHNyYy5wcm92aWRlciA9PT0gJ2NvZGVjb21taXQnICYmIHNyYy5yZXBvc2l0b3J5TmFtZSkge1xuICAgICAgaW5mbyA9IGF3YWl0IHJlc29sdmVDb2RlQ29tbWl0KHJlZ2lvbiwgc3JjLnJlcG9zaXRvcnlOYW1lLCBzcmMuc2hhLCBzaW5jZVNoYSk7XG4gICAgfSBlbHNlIGlmIChzcmMucHJvdmlkZXIgPT09ICdnaXRodWInICYmIHNyYy5vd25lciAmJiBzcmMucmVwbykge1xuICAgICAgaWYgKERhdGUubm93KCkgPj0gc2NtQ29vbGRvd25VbnRpbCkgaW5mbyA9IGF3YWl0IHJlc29sdmVHaXRIdWIoc3JjLm93bmVyLCBzcmMucmVwbywgc3JjLnNoYSwgc2luY2VTaGEsIG9yZ0lkKTtcbiAgICB9IGVsc2UgaWYgKHNyYy5wcm92aWRlciA9PT0gJ2JpdGJ1Y2tldCcgJiYgc3JjLm93bmVyICYmIHNyYy5yZXBvKSB7XG4gICAgICBpZiAoRGF0ZS5ub3coKSA+PSBzY21Db29sZG93blVudGlsKSBpbmZvID0gYXdhaXQgcmVzb2x2ZUJpdGJ1Y2tldChzcmMub3duZXIsIHNyYy5yZXBvLCBzcmMuc2hhKTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZy53YXJuKCdDb21taXQgcmVzb2x1dGlvbiBmYWlsZWQgKG9taXR0aW5nIGNvbW1pdFRpbWVzdGFtcC9jb21taXRDb3VudCknLCB7IHByb3ZpZGVyOiBzcmMucHJvdmlkZXIsIGVycm9yOiAoZXJyIGFzIHsgbmFtZT86IHN0cmluZyB9KT8ubmFtZSA/PyBTdHJpbmcoZXJyKSB9KTtcbiAgICBpbmZvID0ge307XG4gIH1cblxuICBpZiAoaW5mby5jb21taXRUaW1lc3RhbXApIHtcbiAgICBjb21taXRSZXN1bHRDYWNoZS5zZXQocmtleSwgaW5mbyk7XG4gICAgbGFzdFNoYUJ5UGlwZWxpbmUuc2V0KHBpcGVsaW5lSWQsIHNyYy5zaGEpO1xuICB9XG4gIHJldHVybiBpbmZvO1xufVxuXG4vKiogQGludGVybmFsIFRlc3Qtb25seTogZm9yZ2V0IHJlc29sdmVkIGNvbW1pdHMsIFNDTSBjb29sZG93biBhbmQgY2FjaGVkIHRva2Vucy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBfcmVzZXRTY21Gb3JUZXN0cygpOiB2b2lkIHtcbiAgY29tbWl0UmVzdWx0Q2FjaGUuY2xlYXIoKTtcbiAgbGFzdFNoYUJ5UGlwZWxpbmUuY2xlYXIoKTtcbiAgY29tbWl0TWV0YUNhY2hlLmNsZWFyKCk7XG4gIHNjbUNvb2xkb3duVW50aWwgPSAwO1xuICBnaXRodWJUb2tlbkJ5T3JnLmNsZWFyKCk7XG59XG4iXX0=
package/lib/tags.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ /** Resolved pipeline metadata read from the CodePipeline resource tags. */
2
+ export interface ResolvedPipeline {
3
+ /** Platform pipelineId (pb.pipeline-id tag); null when untagged/unregistered. */
4
+ pipelineId: string | null;
5
+ /** Platform orgId (OrgId tag); null when the pipeline carries no org tag. */
6
+ orgId: string | null;
7
+ /** Map of deploy-stage name → environment (parsed from pb.deploys). Empty when none. */
8
+ deploys: Map<string, string>;
9
+ }
10
+ /** Cap on commit/ref/environment fields — the ingest contract allows max 255. */
11
+ export declare const MAX_ATTR = 255;
12
+ /**
13
+ * Resolve a CodePipeline's tags → the platform pipelineId (pb.pipeline-id) plus the
14
+ * deploy-stage→environment map (pb.deploys). `pipelineId` is null when the pipeline
15
+ * has no pb.pipeline-id tag (unregistered). Throws on AccessDenied so a missing IAM
16
+ * grant surfaces loudly instead of silently dropping every event.
17
+ */
18
+ export declare function resolvePipeline(arn: string, region: string): Promise<ResolvedPipeline>;