@kungfu-tech/buildchain 3.0.4-alpha.0 → 3.0.4-alpha.10
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/AGENTS.md +14 -5
- package/README.md +18 -0
- package/bin/buildchain.mjs +136 -73
- package/bin/internal/trust-release-cli.mjs +15 -537
- package/bin/internal/trust-release-command-handlers.mjs +14 -0
- package/bin/internal/trust-release-inspection-handlers.mjs +175 -0
- package/bin/internal/trust-release-release-handlers.mjs +317 -0
- package/bin/internal/trust-release-verification-handlers.mjs +306 -0
- package/dist/site/buildchain-contract.json +36 -25
- package/dist/site/buildchain-site.json +1474 -61
- package/dist/site/capability-registry.json +8 -5
- package/dist/site/cli-registry.json +1869 -0
- package/dist/site/controller-registry.json +16 -3
- package/dist/site/kfd-claims.json +84 -10
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +49 -6
- package/dist/site/node-api-registry.json +17802 -11
- package/dist/site/page-registry.json +1441 -59
- package/dist/site/public-surface-audit.json +2863 -358
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-model.json +7 -0
- package/dist/site/site-manifest.json +34 -10
- package/dist/site/workflow-registry.json +13 -5
- package/docs/MAP.md +21 -6
- package/docs/cli-reference.md +1936 -0
- package/docs/cli.md +15 -1
- package/docs/getting-started.md +167 -0
- package/docs/install.md +7 -8
- package/docs/node-api-reference.md +1952 -0
- package/docs/release-propagation.md +166 -8
- package/docs/site-bundle-contract.md +10 -4
- package/docs/versioning.md +5 -4
- package/package.json +8 -5
- package/packages/core/buildchain-agent-manuals.js +37 -0
- package/packages/core/buildchain-kfd-claims.js +4 -37
- package/packages/core/controller-evidence.js +8 -1
- package/packages/core/index.js +1 -13
- package/packages/core/paper-agent-entry.js +14 -11
- package/packages/core/paper-fleet.js +34 -7
- package/packages/core/paper-npm-bootstrap.js +492 -0
- package/packages/core/paper-repository.js +1 -0
- package/packages/core/paper.js +356 -674
- package/packages/core/public-surface-cli.js +12 -1
- package/packages/core/publication-package.js +7 -0
- package/packages/core/release-passport.js +67 -71
- package/packages/core/release-propagation-common.js +64 -0
- package/packages/core/release-propagation-execution-profile.js +59 -0
- package/packages/core/release-propagation-release.js +196 -0
- package/packages/core/release-propagation-stage-evidence.js +364 -0
- package/packages/core/release-propagation-work-capture.js +64 -0
- package/packages/core/release-propagation-work-constants.js +34 -0
- package/packages/core/release-propagation-work-control.js +203 -0
- package/packages/core/release-propagation-work-transitions.js +145 -0
- package/packages/core/release-propagation-work.js +517 -0
- package/packages/core/release-propagation.js +34 -158
- package/scripts/aggregate-build-summary.mjs +67 -4
- package/scripts/auditable-demo-renditions.mjs +131 -0
- package/scripts/auditable-demo.mjs +88 -91
- package/scripts/aws-windows-jit-controller-core.mjs +269 -0
- package/scripts/aws-windows-jit-controller.mjs +502 -0
- package/scripts/check-internal-architecture.mjs +178 -52
- package/scripts/check-inventory.mjs +2 -2
- package/scripts/check-maintainability.mjs +76 -17
- package/scripts/generate-public-reference.mjs +68 -0
- package/scripts/generate-site-bundle.mjs +35 -41
- package/scripts/maintainability-metrics.mjs +24 -4
- package/scripts/paper-work-fleet-cli.mjs +22 -3
- package/scripts/public-reference.mjs +557 -0
- package/scripts/release-propagation.mjs +126 -0
- package/scripts/resolve-artifact-transfer-mode.mjs +117 -0
- package/scripts/site-reference-registry.mjs +174 -0
- package/scripts/verify-golden-path.mjs +169 -0
- package/scripts/web-surface-core.mjs +46 -207
- package/scripts/web-surface-routing.mjs +286 -0
|
@@ -9,6 +9,29 @@ import { fileURLToPath } from "node:url";
|
|
|
9
9
|
import { loadBuildchainConfig, validateBuildchainConfig } from "../packages/core/buildchain-config.js";
|
|
10
10
|
import { createSurfaceTimestampPolicy } from "../packages/core/surface-manifest.js";
|
|
11
11
|
import { validateInstallerPublication, verifyInstallerPublicReadback } from "./installer-publication.mjs";
|
|
12
|
+
import {
|
|
13
|
+
classifyPreviewAlias,
|
|
14
|
+
resolveChannelUrl,
|
|
15
|
+
resolvePathOnlyUrl,
|
|
16
|
+
resolveSurfaceUrl,
|
|
17
|
+
manifestPrefixFor,
|
|
18
|
+
objectPrefixFor,
|
|
19
|
+
normalizeSurfacePath,
|
|
20
|
+
surfaceDeployConfig,
|
|
21
|
+
surfaceObjectPrefixFor,
|
|
22
|
+
normalizeS3Key,
|
|
23
|
+
joinS3Key,
|
|
24
|
+
joinUrlPath,
|
|
25
|
+
urlWithPath,
|
|
26
|
+
s3Uri,
|
|
27
|
+
cdnPath,
|
|
28
|
+
cdnWildcardPath,
|
|
29
|
+
viewerWildcardPath,
|
|
30
|
+
surfaceArtifactPrefix,
|
|
31
|
+
surfaceArtifactRootFor,
|
|
32
|
+
syncStaticArtifactArgs,
|
|
33
|
+
mutableCacheControlArgs,
|
|
34
|
+
} from "./web-surface-routing.mjs";
|
|
12
35
|
|
|
13
36
|
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
14
37
|
|
|
@@ -89,231 +112,47 @@ function retentionConfig(config, channel) {
|
|
|
89
112
|
};
|
|
90
113
|
}
|
|
91
114
|
|
|
92
|
-
function classifyPreviewAlias(alias) {
|
|
93
|
-
if (/^pr-\d+$/.test(alias)) {
|
|
94
|
-
return {
|
|
95
|
-
kind: "pr",
|
|
96
|
-
mutable: true,
|
|
97
|
-
retentionClass: "preview-pr-ephemeral",
|
|
98
|
-
retentionKey: "pr_days",
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
if (/^sha-[0-9a-f]{6,40}$/i.test(alias)) {
|
|
102
|
-
return {
|
|
103
|
-
kind: "sha",
|
|
104
|
-
mutable: false,
|
|
105
|
-
retentionClass: "preview-sha-immutable",
|
|
106
|
-
retentionKey: "sha_days",
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
return {
|
|
110
|
-
kind: "custom",
|
|
111
|
-
mutable: true,
|
|
112
|
-
retentionClass: "preview-custom-ephemeral",
|
|
113
|
-
retentionKey: "pr_days",
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
115
|
|
|
117
|
-
function resolveChannelUrl(channel, alias) {
|
|
118
|
-
if (channel.urlPattern) {
|
|
119
|
-
if (!alias) {
|
|
120
|
-
throw new Error(`channel ${channel.name} requires alias for url_pattern`);
|
|
121
|
-
}
|
|
122
|
-
return channel.urlPattern.replaceAll("{alias}", alias);
|
|
123
|
-
}
|
|
124
|
-
return channel.url;
|
|
125
|
-
}
|
|
126
116
|
|
|
127
|
-
function resolvePathOnlyUrl(channel, sourcePath, alias) {
|
|
128
|
-
const base = resolveChannelUrl(channel, alias);
|
|
129
|
-
const url = new URL(base);
|
|
130
|
-
const normalizedPath = normalizeSurfacePath(sourcePath);
|
|
131
|
-
if (normalizedPath === "/") {
|
|
132
|
-
return `${url.origin}/`;
|
|
133
|
-
}
|
|
134
|
-
return new URL(normalizedPath.replace(/^\//, ""), `${url.origin}/`).toString();
|
|
135
|
-
}
|
|
136
117
|
|
|
137
|
-
function resolveSurfaceUrl({ surface, channel, channelName, alias }) {
|
|
138
|
-
if (channelName === "preview" && surface.previewUrlPattern) {
|
|
139
|
-
if (!alias) {
|
|
140
|
-
throw new Error(`surface ${surface.name} requires alias for preview_url_pattern`);
|
|
141
|
-
}
|
|
142
|
-
return surface.previewUrlPattern.replaceAll("{alias}", alias);
|
|
143
|
-
}
|
|
144
|
-
if (channelName === "staging" && surface.stagingUrl) {
|
|
145
|
-
return surface.stagingUrl;
|
|
146
|
-
}
|
|
147
|
-
if (channelName === "production" && surface.productionUrl) {
|
|
148
|
-
return surface.productionUrl;
|
|
149
|
-
}
|
|
150
|
-
if (surface.pathOnly) {
|
|
151
|
-
return resolvePathOnlyUrl(channel, surface.path, alias);
|
|
152
|
-
}
|
|
153
|
-
const key = channelName === "preview"
|
|
154
|
-
? "preview_url_pattern"
|
|
155
|
-
: `${channelName}_url`;
|
|
156
|
-
throw new Error(`surfaces.${surface.name}.${key} is required for channel ${channelName}`);
|
|
157
|
-
}
|
|
158
118
|
|
|
159
|
-
function manifestPrefixFor(deployConfig) {
|
|
160
|
-
return deployConfig.manifest_prefix || ".buildchain/deployments";
|
|
161
|
-
}
|
|
162
119
|
|
|
163
|
-
function objectPrefixFor(deployConfig, alias) {
|
|
164
|
-
if (Object.hasOwn(deployConfig, "prefix")) {
|
|
165
|
-
return normalizeS3Key(deployConfig.prefix);
|
|
166
|
-
}
|
|
167
|
-
return alias || "preview";
|
|
168
|
-
}
|
|
169
120
|
|
|
170
|
-
function normalizeSurfacePath(value) {
|
|
171
|
-
const normalized = `/${String(value || "/").replace(/^\/+/, "")}`.replace(/\/{2,}/g, "/");
|
|
172
|
-
if (normalized === "/") {
|
|
173
|
-
return normalized;
|
|
174
|
-
}
|
|
175
|
-
return normalized.endsWith("/") ? normalized : `${normalized}/`;
|
|
176
|
-
}
|
|
177
121
|
|
|
178
|
-
function surfaceDeployConfig(deployConfig, surfaceName) {
|
|
179
|
-
const overrides = deployConfig.surfaces?.[surfaceName];
|
|
180
|
-
if (!overrides || typeof overrides !== "object" || Array.isArray(overrides)) {
|
|
181
|
-
return deployConfig;
|
|
182
|
-
}
|
|
183
|
-
return {
|
|
184
|
-
...deployConfig,
|
|
185
|
-
...overrides,
|
|
186
|
-
cacheControl: deployConfig.cacheControl || overrides.cacheControl
|
|
187
|
-
? { ...(deployConfig.cacheControl || {}), ...(overrides.cacheControl || {}) }
|
|
188
|
-
: undefined,
|
|
189
|
-
surfaces: deployConfig.surfaces,
|
|
190
|
-
secretRefs: [
|
|
191
|
-
...new Set([
|
|
192
|
-
...(deployConfig.secretRefs || []),
|
|
193
|
-
...(Array.isArray(overrides.secretRefs) ? overrides.secretRefs : []),
|
|
194
|
-
]),
|
|
195
|
-
],
|
|
196
|
-
artifactPath: overrides.artifactPath || deployConfig.artifactPath,
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
122
|
|
|
200
|
-
function surfaceObjectPrefixFor({ deployConfig, surface, alias }) {
|
|
201
|
-
const effective = surfaceDeployConfig(deployConfig, surface.name);
|
|
202
|
-
if (Object.hasOwn(effective, "prefix")) {
|
|
203
|
-
return normalizeS3Key(effective.prefix);
|
|
204
|
-
}
|
|
205
|
-
const root = objectPrefixFor(deployConfig, alias);
|
|
206
|
-
const surfacePath = normalizeS3Key(surface.path);
|
|
207
|
-
if (!surfacePath) {
|
|
208
|
-
return root;
|
|
209
|
-
}
|
|
210
|
-
return joinS3Key(root, surfacePath);
|
|
211
|
-
}
|
|
212
123
|
|
|
213
|
-
function normalizeS3Key(value) {
|
|
214
|
-
return String(value || "")
|
|
215
|
-
.replace(/^\/+/, "")
|
|
216
|
-
.replace(/\/{2,}/g, "/")
|
|
217
|
-
.replace(/\/+$/, "");
|
|
218
|
-
}
|
|
219
124
|
|
|
220
|
-
function joinS3Key(...parts) {
|
|
221
|
-
return normalizeS3Key(parts.filter(Boolean).join("/"));
|
|
222
|
-
}
|
|
223
125
|
|
|
224
|
-
function joinUrlPath(...parts) {
|
|
225
|
-
const raw = parts.join("/");
|
|
226
|
-
const normalized = normalizeS3Key(raw);
|
|
227
|
-
if (!normalized) {
|
|
228
|
-
return "/";
|
|
229
|
-
}
|
|
230
|
-
return raw.endsWith("/") ? `/${normalized}/` : `/${normalized}`;
|
|
231
|
-
}
|
|
232
126
|
|
|
233
|
-
function urlWithPath(baseUrl, requestPath) {
|
|
234
|
-
const url = new URL(baseUrl);
|
|
235
|
-
url.pathname = joinUrlPath(requestPath);
|
|
236
|
-
url.search = "";
|
|
237
|
-
url.hash = "";
|
|
238
|
-
return url.toString();
|
|
239
|
-
}
|
|
240
127
|
|
|
241
|
-
function s3Uri(bucket, key = "") {
|
|
242
|
-
if (!bucket) {
|
|
243
|
-
throw new Error("aws-s3-cloudfront adapter requires a bucket or target");
|
|
244
|
-
}
|
|
245
|
-
const normalizedKey = normalizeS3Key(key);
|
|
246
|
-
return normalizedKey ? `s3://${bucket}/${normalizedKey}` : `s3://${bucket}`;
|
|
247
|
-
}
|
|
248
128
|
|
|
249
|
-
function cdnPath(value) {
|
|
250
|
-
const normalized = normalizeS3Key(value);
|
|
251
|
-
return normalized ? `/${normalized}` : "/";
|
|
252
|
-
}
|
|
253
129
|
|
|
254
|
-
function cdnWildcardPath(value) {
|
|
255
|
-
const normalized = normalizeS3Key(value);
|
|
256
|
-
return normalized ? `/${normalized}/*` : "/*";
|
|
257
|
-
}
|
|
258
130
|
|
|
259
|
-
function viewerWildcardPath(binding) {
|
|
260
|
-
try {
|
|
261
|
-
return cdnWildcardPath(new URL(binding.url).pathname);
|
|
262
|
-
} catch {
|
|
263
|
-
return cdnWildcardPath(binding.objectPrefix);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
131
|
|
|
267
|
-
function surfaceArtifactPrefix(binding) {
|
|
268
|
-
return normalizeS3Key(binding.sourcePath);
|
|
269
|
-
}
|
|
270
132
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
function mutableCacheControlArgs({ artifactRoot, bucket, objectPrefix, cacheControl = "", excludePatterns = [] }) {
|
|
295
|
-
if (!cacheControl) return [];
|
|
296
|
-
const args = [
|
|
297
|
-
"s3",
|
|
298
|
-
"cp",
|
|
299
|
-
artifactRoot,
|
|
300
|
-
s3Uri(bucket, objectPrefix),
|
|
301
|
-
"--recursive",
|
|
302
|
-
"--exclude",
|
|
303
|
-
"*",
|
|
304
|
-
"--include",
|
|
305
|
-
"*.html",
|
|
306
|
-
"--include",
|
|
307
|
-
"*.json",
|
|
308
|
-
"--include",
|
|
309
|
-
"*.xml",
|
|
310
|
-
];
|
|
311
|
-
for (const pattern of excludePatterns) {
|
|
312
|
-
args.push("--exclude", pattern);
|
|
313
|
-
}
|
|
314
|
-
args.push("--cache-control", cacheControl);
|
|
315
|
-
return args;
|
|
316
|
-
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
317
156
|
|
|
318
157
|
const PUBLICATION_ARCHIVE_POLICY_CONTRACT = "kungfu-buildchain-publication-archive-policy";
|
|
319
158
|
const OBSERVED_EVIDENCE_OWNERSHIP_CONTRACT = "kungfu-buildchain-observed-evidence-ownership";
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
function classifyPreviewAlias(alias) {
|
|
6
|
+
if (/^pr-\d+$/.test(alias)) {
|
|
7
|
+
return {
|
|
8
|
+
kind: "pr",
|
|
9
|
+
mutable: true,
|
|
10
|
+
retentionClass: "preview-pr-ephemeral",
|
|
11
|
+
retentionKey: "pr_days",
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
if (/^sha-[0-9a-f]{6,40}$/i.test(alias)) {
|
|
15
|
+
return {
|
|
16
|
+
kind: "sha",
|
|
17
|
+
mutable: false,
|
|
18
|
+
retentionClass: "preview-sha-immutable",
|
|
19
|
+
retentionKey: "sha_days",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
kind: "custom",
|
|
24
|
+
mutable: true,
|
|
25
|
+
retentionClass: "preview-custom-ephemeral",
|
|
26
|
+
retentionKey: "pr_days",
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function resolveChannelUrl(channel, alias) {
|
|
31
|
+
if (channel.urlPattern) {
|
|
32
|
+
if (!alias) {
|
|
33
|
+
throw new Error(`channel ${channel.name} requires alias for url_pattern`);
|
|
34
|
+
}
|
|
35
|
+
return channel.urlPattern.replaceAll("{alias}", alias);
|
|
36
|
+
}
|
|
37
|
+
return channel.url;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function resolvePathOnlyUrl(channel, sourcePath, alias) {
|
|
41
|
+
const base = resolveChannelUrl(channel, alias);
|
|
42
|
+
const url = new URL(base);
|
|
43
|
+
const normalizedPath = normalizeSurfacePath(sourcePath);
|
|
44
|
+
if (normalizedPath === "/") {
|
|
45
|
+
return `${url.origin}/`;
|
|
46
|
+
}
|
|
47
|
+
return new URL(
|
|
48
|
+
normalizedPath.replace(/^\//, ""),
|
|
49
|
+
`${url.origin}/`,
|
|
50
|
+
).toString();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function resolveSurfaceUrl({ surface, channel, channelName, alias }) {
|
|
54
|
+
if (channelName === "preview" && surface.previewUrlPattern) {
|
|
55
|
+
if (!alias) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`surface ${surface.name} requires alias for preview_url_pattern`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
return surface.previewUrlPattern.replaceAll("{alias}", alias);
|
|
61
|
+
}
|
|
62
|
+
if (channelName === "staging" && surface.stagingUrl) {
|
|
63
|
+
return surface.stagingUrl;
|
|
64
|
+
}
|
|
65
|
+
if (channelName === "production" && surface.productionUrl) {
|
|
66
|
+
return surface.productionUrl;
|
|
67
|
+
}
|
|
68
|
+
if (surface.pathOnly) {
|
|
69
|
+
return resolvePathOnlyUrl(channel, surface.path, alias);
|
|
70
|
+
}
|
|
71
|
+
const key =
|
|
72
|
+
channelName === "preview" ? "preview_url_pattern" : `${channelName}_url`;
|
|
73
|
+
throw new Error(
|
|
74
|
+
`surfaces.${surface.name}.${key} is required for channel ${channelName}`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function manifestPrefixFor(deployConfig) {
|
|
79
|
+
return deployConfig.manifest_prefix || ".buildchain/deployments";
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function objectPrefixFor(deployConfig, alias) {
|
|
83
|
+
if (Object.hasOwn(deployConfig, "prefix")) {
|
|
84
|
+
return normalizeS3Key(deployConfig.prefix);
|
|
85
|
+
}
|
|
86
|
+
return alias || "preview";
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function normalizeSurfacePath(value) {
|
|
90
|
+
const normalized = `/${String(value || "/").replace(/^\/+/, "")}`.replace(
|
|
91
|
+
/\/{2,}/g,
|
|
92
|
+
"/",
|
|
93
|
+
);
|
|
94
|
+
if (normalized === "/") {
|
|
95
|
+
return normalized;
|
|
96
|
+
}
|
|
97
|
+
return normalized.endsWith("/") ? normalized : `${normalized}/`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function surfaceDeployConfig(deployConfig, surfaceName) {
|
|
101
|
+
const overrides = deployConfig.surfaces?.[surfaceName];
|
|
102
|
+
if (!overrides || typeof overrides !== "object" || Array.isArray(overrides)) {
|
|
103
|
+
return deployConfig;
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
...deployConfig,
|
|
107
|
+
...overrides,
|
|
108
|
+
cacheControl:
|
|
109
|
+
deployConfig.cacheControl || overrides.cacheControl
|
|
110
|
+
? {
|
|
111
|
+
...(deployConfig.cacheControl || {}),
|
|
112
|
+
...(overrides.cacheControl || {}),
|
|
113
|
+
}
|
|
114
|
+
: undefined,
|
|
115
|
+
surfaces: deployConfig.surfaces,
|
|
116
|
+
secretRefs: [
|
|
117
|
+
...new Set([
|
|
118
|
+
...(deployConfig.secretRefs || []),
|
|
119
|
+
...(Array.isArray(overrides.secretRefs) ? overrides.secretRefs : []),
|
|
120
|
+
]),
|
|
121
|
+
],
|
|
122
|
+
artifactPath: overrides.artifactPath || deployConfig.artifactPath,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function surfaceObjectPrefixFor({ deployConfig, surface, alias }) {
|
|
127
|
+
const effective = surfaceDeployConfig(deployConfig, surface.name);
|
|
128
|
+
if (Object.hasOwn(effective, "prefix")) {
|
|
129
|
+
return normalizeS3Key(effective.prefix);
|
|
130
|
+
}
|
|
131
|
+
const root = objectPrefixFor(deployConfig, alias);
|
|
132
|
+
const surfacePath = normalizeS3Key(surface.path);
|
|
133
|
+
if (!surfacePath) {
|
|
134
|
+
return root;
|
|
135
|
+
}
|
|
136
|
+
return joinS3Key(root, surfacePath);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function normalizeS3Key(value) {
|
|
140
|
+
return String(value || "")
|
|
141
|
+
.replace(/^\/+/, "")
|
|
142
|
+
.replace(/\/{2,}/g, "/")
|
|
143
|
+
.replace(/\/+$/, "");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function joinS3Key(...parts) {
|
|
147
|
+
return normalizeS3Key(parts.filter(Boolean).join("/"));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function joinUrlPath(...parts) {
|
|
151
|
+
const raw = parts.join("/");
|
|
152
|
+
const normalized = normalizeS3Key(raw);
|
|
153
|
+
if (!normalized) {
|
|
154
|
+
return "/";
|
|
155
|
+
}
|
|
156
|
+
return raw.endsWith("/") ? `/${normalized}/` : `/${normalized}`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function urlWithPath(baseUrl, requestPath) {
|
|
160
|
+
const url = new URL(baseUrl);
|
|
161
|
+
url.pathname = joinUrlPath(requestPath);
|
|
162
|
+
url.search = "";
|
|
163
|
+
url.hash = "";
|
|
164
|
+
return url.toString();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function s3Uri(bucket, key = "") {
|
|
168
|
+
if (!bucket) {
|
|
169
|
+
throw new Error("aws-s3-cloudfront adapter requires a bucket or target");
|
|
170
|
+
}
|
|
171
|
+
const normalizedKey = normalizeS3Key(key);
|
|
172
|
+
return normalizedKey ? `s3://${bucket}/${normalizedKey}` : `s3://${bucket}`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function cdnPath(value) {
|
|
176
|
+
const normalized = normalizeS3Key(value);
|
|
177
|
+
return normalized ? `/${normalized}` : "/";
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function cdnWildcardPath(value) {
|
|
181
|
+
const normalized = normalizeS3Key(value);
|
|
182
|
+
return normalized ? `/${normalized}/*` : "/*";
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function viewerWildcardPath(binding) {
|
|
186
|
+
try {
|
|
187
|
+
return cdnWildcardPath(new URL(binding.url).pathname);
|
|
188
|
+
} catch {
|
|
189
|
+
return cdnWildcardPath(binding.objectPrefix);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function surfaceArtifactPrefix(binding) {
|
|
194
|
+
return normalizeS3Key(binding.sourcePath);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function surfaceArtifactRootFor({ artifactRoot, binding }) {
|
|
198
|
+
const prefix = normalizeS3Key(
|
|
199
|
+
binding.artifactPathPrefix || surfaceArtifactPrefix(binding),
|
|
200
|
+
);
|
|
201
|
+
const root = prefix ? path.join(artifactRoot, prefix) : artifactRoot;
|
|
202
|
+
if (fs.existsSync(root)) {
|
|
203
|
+
return root;
|
|
204
|
+
}
|
|
205
|
+
return artifactRoot;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function syncStaticArtifactArgs({
|
|
209
|
+
artifactRoot,
|
|
210
|
+
bucket,
|
|
211
|
+
objectPrefix,
|
|
212
|
+
deleteExcludes = [],
|
|
213
|
+
cacheControl = "",
|
|
214
|
+
}) {
|
|
215
|
+
const args = [
|
|
216
|
+
"s3",
|
|
217
|
+
"sync",
|
|
218
|
+
artifactRoot,
|
|
219
|
+
s3Uri(bucket, objectPrefix),
|
|
220
|
+
"--delete",
|
|
221
|
+
];
|
|
222
|
+
if (!objectPrefix) {
|
|
223
|
+
args.push("--exclude", ".buildchain/*");
|
|
224
|
+
}
|
|
225
|
+
for (const pattern of deleteExcludes) {
|
|
226
|
+
args.push("--exclude", pattern);
|
|
227
|
+
}
|
|
228
|
+
if (cacheControl) {
|
|
229
|
+
args.push("--cache-control", cacheControl);
|
|
230
|
+
}
|
|
231
|
+
return args;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function mutableCacheControlArgs({
|
|
235
|
+
artifactRoot,
|
|
236
|
+
bucket,
|
|
237
|
+
objectPrefix,
|
|
238
|
+
cacheControl = "",
|
|
239
|
+
excludePatterns = [],
|
|
240
|
+
}) {
|
|
241
|
+
if (!cacheControl) return [];
|
|
242
|
+
const args = [
|
|
243
|
+
"s3",
|
|
244
|
+
"cp",
|
|
245
|
+
artifactRoot,
|
|
246
|
+
s3Uri(bucket, objectPrefix),
|
|
247
|
+
"--recursive",
|
|
248
|
+
"--exclude",
|
|
249
|
+
"*",
|
|
250
|
+
"--include",
|
|
251
|
+
"*.html",
|
|
252
|
+
"--include",
|
|
253
|
+
"*.json",
|
|
254
|
+
"--include",
|
|
255
|
+
"*.xml",
|
|
256
|
+
];
|
|
257
|
+
for (const pattern of excludePatterns) {
|
|
258
|
+
args.push("--exclude", pattern);
|
|
259
|
+
}
|
|
260
|
+
args.push("--cache-control", cacheControl);
|
|
261
|
+
return args;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export {
|
|
265
|
+
classifyPreviewAlias,
|
|
266
|
+
resolveChannelUrl,
|
|
267
|
+
resolvePathOnlyUrl,
|
|
268
|
+
resolveSurfaceUrl,
|
|
269
|
+
manifestPrefixFor,
|
|
270
|
+
objectPrefixFor,
|
|
271
|
+
normalizeSurfacePath,
|
|
272
|
+
surfaceDeployConfig,
|
|
273
|
+
surfaceObjectPrefixFor,
|
|
274
|
+
normalizeS3Key,
|
|
275
|
+
joinS3Key,
|
|
276
|
+
joinUrlPath,
|
|
277
|
+
urlWithPath,
|
|
278
|
+
s3Uri,
|
|
279
|
+
cdnPath,
|
|
280
|
+
cdnWildcardPath,
|
|
281
|
+
viewerWildcardPath,
|
|
282
|
+
surfaceArtifactPrefix,
|
|
283
|
+
surfaceArtifactRootFor,
|
|
284
|
+
syncStaticArtifactArgs,
|
|
285
|
+
mutableCacheControlArgs,
|
|
286
|
+
};
|