@kungfu-tech/buildchain 2.14.14-alpha.0 → 2.14.14-alpha.2
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/actions/promote-buildchain-ref/README.md +6 -4
- package/dist/site/buildchain-contract.json +75 -21
- package/dist/site/buildchain-site.json +26 -25
- package/dist/site/controller-registry.json +47 -1
- package/dist/site/kfd-claims.json +10 -5
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +5 -5
- package/dist/site/node-api-registry.json +5 -5
- package/dist/site/page-registry.json +12 -12
- package/dist/site/public-surface-audit.json +9 -4
- package/dist/site/publication-authority-registry.json +3 -2
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-model.json +4 -2
- package/dist/site/site-manifest.json +9 -9
- package/dist/site/workflow-registry.json +7 -2
- package/docs/binary-distribution.md +22 -8
- package/docs/release-candidate.md +4 -2
- package/docs/release-governance.md +5 -3
- package/docs/site-bundle-contract.md +4 -0
- package/docs/web-surface-deployments.md +6 -1
- package/package.json +1 -1
- package/packages/core/buildchain-contract.js +2 -1
- package/packages/core/controller-evidence.js +8 -0
- package/packages/core/issue-reporting.js +9 -4
- package/packages/core/publication-authority.js +75 -0
- package/scripts/assemble-binary-release-admission.mjs +201 -0
- package/scripts/check-inventory.mjs +1 -1
- package/scripts/ensure-github-release.mjs +20 -6
- package/scripts/generate-channel-promotion-workflow.mjs +3 -3
- package/scripts/generate-site-bundle.mjs +8 -4
- package/scripts/runtime-ref-core.mjs +12 -0
- package/scripts/site-bundle-homepage.mjs +39 -0
- package/scripts/web-surface-cloudfront-rewrite.mjs +100 -53
|
@@ -861,7 +861,7 @@ for (const forbiddenSnippet of [
|
|
|
861
861
|
}
|
|
862
862
|
for (const requiredSnippet of [
|
|
863
863
|
"id-token: write",
|
|
864
|
-
"actions:
|
|
864
|
+
"actions: write",
|
|
865
865
|
"uses: ./.github/workflows/.release-candidate-promote.yml",
|
|
866
866
|
"github.event.workflow_run.event == 'push'",
|
|
867
867
|
"!startsWith(github.event.workflow_run.display_title, 'chore(release): prepare v')",
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { pathToFileURL } from "node:url";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
function classifyPublicationChannel(channel = "") {
|
|
5
|
+
const normalized = String(channel || "").trim().toLowerCase();
|
|
6
|
+
if (!normalized) return undefined;
|
|
7
|
+
if (normalized === "alpha") return true;
|
|
8
|
+
if (["release", "stable", "major"].includes(normalized)) return false;
|
|
9
|
+
throw new Error(`Unsupported GitHub Release publication channel: ${channel}`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function classifyReleaseTag(tag, { channel = "" } = {}) {
|
|
5
13
|
const normalized = String(tag || "").trim();
|
|
6
14
|
const match = normalized.match(/^v\d+\.\d+\.\d+(?:-[0-9A-Za-z][0-9A-Za-z.-]*)?$/);
|
|
7
15
|
if (!match) {
|
|
8
16
|
throw new Error(`Unsupported semver release tag: ${tag}`);
|
|
9
17
|
}
|
|
10
|
-
const
|
|
18
|
+
const channelPrerelease = classifyPublicationChannel(channel);
|
|
19
|
+
const prerelease = channelPrerelease ?? normalized.includes("-");
|
|
11
20
|
return {
|
|
12
21
|
tag: normalized,
|
|
13
22
|
prerelease,
|
|
@@ -23,6 +32,7 @@ function parseArgs(argv) {
|
|
|
23
32
|
title: "",
|
|
24
33
|
notes: "",
|
|
25
34
|
target: "",
|
|
35
|
+
channel: "",
|
|
26
36
|
};
|
|
27
37
|
for (let index = 0; index < argv.length; index += 1) {
|
|
28
38
|
const arg = argv[index];
|
|
@@ -38,6 +48,7 @@ function parseArgs(argv) {
|
|
|
38
48
|
else if (arg === "--title") args.title = readValue();
|
|
39
49
|
else if (arg === "--notes") args.notes = readValue();
|
|
40
50
|
else if (arg === "--target") args.target = readValue();
|
|
51
|
+
else if (arg === "--channel") args.channel = readValue();
|
|
41
52
|
else if (arg === "--api-url") args.apiUrl = readValue();
|
|
42
53
|
else if (arg === "--help" || arg === "-h") {
|
|
43
54
|
args.help = true;
|
|
@@ -50,11 +61,12 @@ function parseArgs(argv) {
|
|
|
50
61
|
|
|
51
62
|
function usage() {
|
|
52
63
|
return [
|
|
53
|
-
"usage: node scripts/ensure-github-release.mjs --repository <owner/repo> --tag <tag>",
|
|
64
|
+
"usage: node scripts/ensure-github-release.mjs --repository <owner/repo> --tag <tag> [--channel alpha|release]",
|
|
54
65
|
"",
|
|
55
66
|
"Ensures Buildchain GitHub Release metadata is deterministic:",
|
|
56
|
-
"-
|
|
57
|
-
"-
|
|
67
|
+
"- explicit alpha => prerelease=true, make_latest=false",
|
|
68
|
+
"- explicit release/stable/major => prerelease=false, make_latest=true",
|
|
69
|
+
"- without --channel, semver prerelease syntax remains the fallback",
|
|
58
70
|
].join("\n");
|
|
59
71
|
}
|
|
60
72
|
|
|
@@ -106,9 +118,10 @@ export async function ensureGitHubRelease({
|
|
|
106
118
|
title = "",
|
|
107
119
|
notes = "",
|
|
108
120
|
target = "",
|
|
121
|
+
channel = "",
|
|
109
122
|
} = {}) {
|
|
110
123
|
const { owner, repo } = splitRepository(repository);
|
|
111
|
-
const metadata = classifyReleaseTag(tag);
|
|
124
|
+
const metadata = classifyReleaseTag(tag, { channel });
|
|
112
125
|
const encodedTag = encodeURIComponent(metadata.tag);
|
|
113
126
|
const releasePath = `/repos/${owner}/${repo}/releases/tags/${encodedTag}`;
|
|
114
127
|
const refPath = `/repos/${owner}/${repo}/git/ref/tags/${encodedTag}`;
|
|
@@ -163,6 +176,7 @@ async function main() {
|
|
|
163
176
|
title: args.title,
|
|
164
177
|
notes: args.notes,
|
|
165
178
|
target: args.target,
|
|
179
|
+
channel: args.channel,
|
|
166
180
|
});
|
|
167
181
|
console.log(`github-release-${result.action}=${result.metadata.tag}`);
|
|
168
182
|
console.log(`github-release-prerelease=${result.metadata.prerelease}`);
|
|
@@ -204,7 +204,7 @@ ${secrets.trimEnd()}
|
|
|
204
204
|
${publicOutputs(outputs)}
|
|
205
205
|
|
|
206
206
|
permissions:
|
|
207
|
-
actions:
|
|
207
|
+
actions: write
|
|
208
208
|
checks: write
|
|
209
209
|
contents: write
|
|
210
210
|
id-token: write
|
|
@@ -404,7 +404,7 @@ jobs:
|
|
|
404
404
|
if: \${{ needs.resolve-promotion.outputs.channel == 'alpha' }}
|
|
405
405
|
uses: kungfu-systems/buildchain/${alphaRoute.workflowPath}@${alphaRoute.callRef}
|
|
406
406
|
permissions:
|
|
407
|
-
actions:
|
|
407
|
+
actions: write
|
|
408
408
|
checks: write
|
|
409
409
|
contents: write
|
|
410
410
|
id-token: write
|
|
@@ -419,7 +419,7 @@ ${alphaForwarded}
|
|
|
419
419
|
if: \${{ needs.resolve-promotion.outputs.channel == 'stable' }}
|
|
420
420
|
uses: kungfu-systems/buildchain/${stableRoute.workflowPath}@${stableRoute.callRef}
|
|
421
421
|
permissions:
|
|
422
|
-
actions:
|
|
422
|
+
actions: write
|
|
423
423
|
checks: write
|
|
424
424
|
contents: write
|
|
425
425
|
id-token: write
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
enumerateWorkflowInputs,
|
|
29
29
|
} from "../packages/core/public-surface-audit.js";
|
|
30
30
|
import { createSurfaceTimestampPolicy } from "../packages/core/surface-manifest.js";
|
|
31
|
+
import { projectHomepageIntro } from "./site-bundle-homepage.mjs";
|
|
31
32
|
|
|
32
33
|
const SITE_BUNDLE_CONTRACT = "kungfu-buildchain-site-bundle";
|
|
33
34
|
const PUBLICATION_RELEASE_REGISTRY_CONTRACT = "kungfu-buildchain-publication-release-registry";
|
|
@@ -702,6 +703,7 @@ function buildSiteBundle() {
|
|
|
702
703
|
const packageJson = readJson("package.json");
|
|
703
704
|
const inventory = readJson("tests/buildchain-inventory.json");
|
|
704
705
|
const readme = parseReadme(readText(README_PATH));
|
|
706
|
+
const homepageIntro = projectHomepageIntro(readme.intro);
|
|
705
707
|
const docs = BUILDCHAIN_AGENT_MANUALS.map((manual) => docEntry(manual.id, manual.title, manual.path, manual.plane));
|
|
706
708
|
const pages = buildSitePages();
|
|
707
709
|
const preservedTimestampPolicy = readExistingSiteTimestampPolicy(packageJson.version);
|
|
@@ -945,8 +947,10 @@ function buildSiteBundle() {
|
|
|
945
947
|
},
|
|
946
948
|
githubRelease: {
|
|
947
949
|
exactTagRelease: true,
|
|
948
|
-
|
|
949
|
-
|
|
950
|
+
authoritativeIntent: "Buildchain publication channel controls prerelease/latest metadata when available",
|
|
951
|
+
alphaChannel: "alpha publication sets prerelease=true and make_latest=false",
|
|
952
|
+
stableChannels: "release, stable, and major publication set prerelease=false and make_latest=true",
|
|
953
|
+
tagFallback: "ordinary callers without publication intent use semver prerelease syntax",
|
|
950
954
|
evidenceAssets: [
|
|
951
955
|
"publish evidence JSON",
|
|
952
956
|
"buildchain.release.json",
|
|
@@ -1218,8 +1222,8 @@ function buildSiteBundle() {
|
|
|
1218
1222
|
},
|
|
1219
1223
|
homepage: {
|
|
1220
1224
|
title: readme.title,
|
|
1221
|
-
lead:
|
|
1222
|
-
mechanismSummary:
|
|
1225
|
+
lead: homepageIntro.lead,
|
|
1226
|
+
mechanismSummary: homepageIntro.mechanismSummary,
|
|
1223
1227
|
sections: homepageSections,
|
|
1224
1228
|
displayPlan: {
|
|
1225
1229
|
firstScreen: {
|
|
@@ -111,6 +111,8 @@ export function validateRuntimeOverrideTrust({
|
|
|
111
111
|
requestedRef = "",
|
|
112
112
|
eventName = "",
|
|
113
113
|
actorPermission = "",
|
|
114
|
+
sameRepositoryPullRequest = false,
|
|
115
|
+
pullRequestHeadSha = "",
|
|
114
116
|
} = {}) {
|
|
115
117
|
if (!String(requestedRef || "").trim()) {
|
|
116
118
|
return { ok: true, decision: "stable-default" };
|
|
@@ -118,6 +120,16 @@ export function validateRuntimeOverrideTrust({
|
|
|
118
120
|
if (isOfficialBuildchainChannelRef(requestedRef)) {
|
|
119
121
|
return { ok: true, decision: "official-channel" };
|
|
120
122
|
}
|
|
123
|
+
const normalizedRequested = String(requestedRef || "").trim().toLowerCase();
|
|
124
|
+
const normalizedHeadSha = String(pullRequestHeadSha || "").trim().toLowerCase();
|
|
125
|
+
if (
|
|
126
|
+
eventName === "pull_request" &&
|
|
127
|
+
sameRepositoryPullRequest === true &&
|
|
128
|
+
EXACT_SHA_RE.test(normalizedRequested) &&
|
|
129
|
+
normalizedRequested === normalizedHeadSha
|
|
130
|
+
) {
|
|
131
|
+
return { ok: true, decision: "same-repository-pr-head" };
|
|
132
|
+
}
|
|
121
133
|
if (eventName !== "workflow_dispatch") {
|
|
122
134
|
return {
|
|
123
135
|
ok: false,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const BADGE_BLOCK_START = "<!-- buildchain:badges:start -->";
|
|
2
|
+
const BADGE_BLOCK_END = "<!-- buildchain:badges:end -->";
|
|
3
|
+
|
|
4
|
+
function normalizeMarkdown(value) {
|
|
5
|
+
return String(value || "").replace(/\r\n/g, "\n").trim();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function paragraphBlocks(markdown) {
|
|
9
|
+
return normalizeMarkdown(markdown)
|
|
10
|
+
.split(/\n{2,}/)
|
|
11
|
+
.map((block) => block.replace(/\n/g, " ").trim())
|
|
12
|
+
.filter(Boolean);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function projectHomepageIntro(markdown) {
|
|
16
|
+
const intro = normalizeMarkdown(markdown);
|
|
17
|
+
const start = intro.indexOf(BADGE_BLOCK_START);
|
|
18
|
+
const end = intro.indexOf(BADGE_BLOCK_END);
|
|
19
|
+
if ((start >= 0) !== (end >= 0) || (start >= 0 && end < start)) {
|
|
20
|
+
throw new Error("README.md managed badge block is incomplete");
|
|
21
|
+
}
|
|
22
|
+
if (start >= 0) {
|
|
23
|
+
const endOffset = end + BADGE_BLOCK_END.length;
|
|
24
|
+
const lead = intro.slice(start, endOffset).trim();
|
|
25
|
+
const remaining = [intro.slice(0, start), intro.slice(endOffset)]
|
|
26
|
+
.map((part) => part.trim())
|
|
27
|
+
.filter(Boolean)
|
|
28
|
+
.join("\n\n");
|
|
29
|
+
return {
|
|
30
|
+
lead,
|
|
31
|
+
mechanismSummary: paragraphBlocks(remaining),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const blocks = paragraphBlocks(intro);
|
|
35
|
+
return {
|
|
36
|
+
lead: blocks[0] || "",
|
|
37
|
+
mechanismSummary: blocks.slice(1),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -15,6 +15,9 @@ const FUNCTION_CODE = `function handler(event) {
|
|
|
15
15
|
}
|
|
16
16
|
`;
|
|
17
17
|
|
|
18
|
+
const DISTRIBUTION_UPDATE_MAX_ATTEMPTS = 3;
|
|
19
|
+
const DISTRIBUTION_UPDATE_RETRY_DELAY_MS = 250;
|
|
20
|
+
|
|
18
21
|
function readArg(name, fallback = "") {
|
|
19
22
|
const flag = `--${name}`;
|
|
20
23
|
const index = process.argv.indexOf(flag);
|
|
@@ -31,7 +34,7 @@ function runAws(args, { allowFailure = false } = {}) {
|
|
|
31
34
|
});
|
|
32
35
|
if (result.error) {
|
|
33
36
|
if (allowFailure) {
|
|
34
|
-
return { ok: false, stdout: "", stderr: String(result.error.message || result.error) };
|
|
37
|
+
return { ok: false, status: null, stdout: "", stderr: String(result.error.message || result.error) };
|
|
35
38
|
}
|
|
36
39
|
throw result.error;
|
|
37
40
|
}
|
|
@@ -39,11 +42,11 @@ function runAws(args, { allowFailure = false } = {}) {
|
|
|
39
42
|
const stderr = String(result.stderr || "");
|
|
40
43
|
if (result.status !== 0) {
|
|
41
44
|
if (allowFailure) {
|
|
42
|
-
return { ok: false, stdout, stderr };
|
|
45
|
+
return { ok: false, status: result.status, stdout, stderr };
|
|
43
46
|
}
|
|
44
47
|
throw new Error(`aws ${args.join(" ")} failed with exit code ${result.status}${stderr.trim() ? `: ${stderr.trim()}` : ""}`);
|
|
45
48
|
}
|
|
46
|
-
return { ok: true, stdout, stderr };
|
|
49
|
+
return { ok: true, status: result.status, stdout, stderr };
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
function runAwsJson(args, options = {}) {
|
|
@@ -58,6 +61,22 @@ function functionConfig(comment) {
|
|
|
58
61
|
return `Comment=${comment.replace(/,/g, " ")},Runtime=cloudfront-js-2.0`;
|
|
59
62
|
}
|
|
60
63
|
|
|
64
|
+
function awsFailureMessage(args, result) {
|
|
65
|
+
const status = result.status === null || result.status === undefined
|
|
66
|
+
? ""
|
|
67
|
+
: ` with exit code ${result.status}`;
|
|
68
|
+
const stderr = String(result.stderr || "").trim();
|
|
69
|
+
return `aws ${args.join(" ")} failed${status}${stderr ? `: ${stderr}` : ""}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function isStaleDistributionEtag(result) {
|
|
73
|
+
return result.ok === false && /\bPreconditionFailed\b/.test(String(result.stderr || ""));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function sleepSync(milliseconds) {
|
|
77
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);
|
|
78
|
+
}
|
|
79
|
+
|
|
61
80
|
function writeFunctionCode(tmpDir) {
|
|
62
81
|
const file = path.join(tmpDir, "directory-index-rewrite.js");
|
|
63
82
|
fs.writeFileSync(file, FUNCTION_CODE);
|
|
@@ -130,57 +149,85 @@ function publishFunction({ name, etag }) {
|
|
|
130
149
|
}
|
|
131
150
|
|
|
132
151
|
function attachFunction({ distributionId, functionArn }) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
152
|
+
let previousViewerRequestFunction;
|
|
153
|
+
for (let attempt = 1; attempt <= DISTRIBUTION_UPDATE_MAX_ATTEMPTS; attempt += 1) {
|
|
154
|
+
const current = runAwsJson(["cloudfront", "get-distribution-config", "--id", distributionId]);
|
|
155
|
+
const etag = current.data?.ETag || "";
|
|
156
|
+
const config = current.data?.DistributionConfig;
|
|
157
|
+
if (!etag || !config) {
|
|
158
|
+
throw new Error(`cloudfront get-distribution-config did not return ETag and DistributionConfig for ${distributionId}`);
|
|
159
|
+
}
|
|
160
|
+
const defaultBehavior = config.DefaultCacheBehavior || {};
|
|
161
|
+
const existing = defaultBehavior.FunctionAssociations || { Quantity: 0, Items: [] };
|
|
162
|
+
const items = Array.isArray(existing.Items) ? [...existing.Items] : [];
|
|
163
|
+
const currentViewer = items.find((item) => item.EventType === "viewer-request");
|
|
164
|
+
if (previousViewerRequestFunction === undefined) {
|
|
165
|
+
previousViewerRequestFunction = currentViewer?.FunctionARN || "";
|
|
166
|
+
}
|
|
167
|
+
if (currentViewer && currentViewer.FunctionARN && currentViewer.FunctionARN !== functionArn) {
|
|
168
|
+
throw new Error(
|
|
169
|
+
`CloudFront distribution ${distributionId} already has a different viewer-request function ${currentViewer.FunctionARN}; ` +
|
|
170
|
+
"remove or migrate it before Buildchain can manage directory-index rewrites",
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
if (currentViewer?.FunctionARN === functionArn) {
|
|
174
|
+
return {
|
|
175
|
+
previousViewerRequestFunction,
|
|
176
|
+
nextViewerRequestFunction: functionArn,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const nextItems = [
|
|
181
|
+
...items.filter((item) => item.EventType !== "viewer-request"),
|
|
182
|
+
{
|
|
183
|
+
EventType: "viewer-request",
|
|
184
|
+
FunctionARN: functionArn,
|
|
185
|
+
},
|
|
186
|
+
];
|
|
187
|
+
config.DefaultCacheBehavior = {
|
|
188
|
+
...defaultBehavior,
|
|
189
|
+
FunctionAssociations: {
|
|
190
|
+
Quantity: nextItems.length,
|
|
191
|
+
Items: nextItems,
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "buildchain-cloudfront-distribution-"));
|
|
195
|
+
let args;
|
|
196
|
+
let updated;
|
|
197
|
+
try {
|
|
198
|
+
const configFile = path.join(tmpDir, "distribution-config.json");
|
|
199
|
+
fs.writeFileSync(configFile, `${JSON.stringify(config, null, 2)}\n`);
|
|
200
|
+
args = [
|
|
201
|
+
"cloudfront",
|
|
202
|
+
"update-distribution",
|
|
203
|
+
"--id",
|
|
204
|
+
distributionId,
|
|
205
|
+
"--if-match",
|
|
206
|
+
etag,
|
|
207
|
+
"--distribution-config",
|
|
208
|
+
`file://${configFile}`,
|
|
209
|
+
];
|
|
210
|
+
updated = runAws(args, { allowFailure: true });
|
|
211
|
+
} finally {
|
|
212
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
213
|
+
}
|
|
214
|
+
if (updated.ok) {
|
|
215
|
+
return {
|
|
216
|
+
previousViewerRequestFunction,
|
|
217
|
+
nextViewerRequestFunction: functionArn,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
if (!isStaleDistributionEtag(updated)) {
|
|
221
|
+
throw new Error(awsFailureMessage(args, updated));
|
|
222
|
+
}
|
|
223
|
+
if (attempt === DISTRIBUTION_UPDATE_MAX_ATTEMPTS) {
|
|
224
|
+
throw new Error(
|
|
225
|
+
`CloudFront update-distribution still failed after ${attempt} attempts: ${awsFailureMessage(args, updated)}`,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
sleepSync(DISTRIBUTION_UPDATE_RETRY_DELAY_MS * attempt);
|
|
179
229
|
}
|
|
180
|
-
|
|
181
|
-
previousViewerRequestFunction: currentViewer?.FunctionARN || "",
|
|
182
|
-
nextViewerRequestFunction: functionArn,
|
|
183
|
-
};
|
|
230
|
+
throw new Error(`CloudFront update-distribution retry loop ended unexpectedly for ${distributionId}`);
|
|
184
231
|
}
|
|
185
232
|
|
|
186
233
|
export function ensureCloudFrontDirectoryIndexRewrite({
|