cdk-local 0.120.0 → 0.121.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,6 +16,7 @@ import { GetParameterCommand, GetParametersCommand, SSMClient } from "@aws-sdk/c
16
16
  import { execFile, spawn } from "node:child_process";
17
17
  import { connect, createServer } from "node:net";
18
18
  import { promisify } from "node:util";
19
+ import * as nodeCrypto from "node:crypto";
19
20
  import { X509Certificate, createHash, createHmac, createPublicKey, createVerify, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
20
21
  import { ECRClient, GetAuthorizationTokenCommand } from "@aws-sdk/client-ecr";
21
22
  import { readFile } from "fs/promises";
@@ -33,6 +34,8 @@ import { Sha256 } from "@aws-crypto/sha256-js";
33
34
  import { SignatureV4 } from "@smithy/signature-v4";
34
35
  import graphlib from "graphlib";
35
36
  import { GetSecretValueCommand, SecretsManagerClient } from "@aws-sdk/client-secrets-manager";
37
+ import * as nodeBuffer from "node:buffer";
38
+ import * as nodeQuerystring from "node:querystring";
36
39
  import * as vm from "node:vm";
37
40
  import "@aws-sdk/signature-v4a";
38
41
  import { CloudFrontClient, paginateListKeyValueStores } from "@aws-sdk/client-cloudfront";
@@ -18100,7 +18103,7 @@ function computeCodeImageTag(sourceDir, runtime, entryPoint, dockerfile) {
18100
18103
  async function downloadAndExtractS3Bundle(location, options = {}) {
18101
18104
  const ref = formatRef(location);
18102
18105
  getLogger().info(`Downloading fromS3 code bundle ${ref}...`);
18103
- const bytes = await (options.fetchObject ?? defaultFetchObject(options))(location);
18106
+ const bytes = await (options.fetchObject ?? defaultFetchObject$1(options))(location);
18104
18107
  let files;
18105
18108
  try {
18106
18109
  files = unzipSync(bytes);
@@ -18147,7 +18150,7 @@ function resolveSafeEntryPath(root, entry) {
18147
18150
  if (dest !== root && !dest.startsWith(rootWithSep)) throw new CdkLocalError(`Refusing to extract a fromS3 bundle entry that escapes the target dir: '${entry}'.`, "LOCAL_INVOKE_AGENTCORE_S3_BUNDLE_ZIP_SLIP");
18148
18151
  return dest;
18149
18152
  }
18150
- function defaultFetchObject(options) {
18153
+ function defaultFetchObject$1(options) {
18151
18154
  return async (location) => {
18152
18155
  const { S3Client, GetObjectCommand } = await import("@aws-sdk/client-s3");
18153
18156
  const client = new S3Client({
@@ -28187,6 +28190,44 @@ function createLocalFileKvsDataSource(args) {
28187
28190
  //#endregion
28188
28191
  //#region src/local/cloudfront-function-runtime.ts
28189
28192
  /**
28193
+ * The CloudFront Functions JS 2.0 runtime exposes a set of globals + `require`
28194
+ * modules that a bare `node:vm` context does NOT provide — code that uses any
28195
+ * of them works in production but fails locally with a `ReferenceError`
28196
+ * (issue #410). Reproduce them with their Node equivalents:
28197
+ *
28198
+ * - globals: `Buffer`, `atob` / `btoa`, `TextEncoder` / `TextDecoder`
28199
+ * (the 2.0 runtime's documented globals / built-in objects);
28200
+ * - `require('crypto')` (`createHash` / `createHmac`, md5 / sha1 / sha256),
28201
+ * `require('querystring')`, and `require('buffer')` — backed by the Node
28202
+ * modules (a superset of the 2.0 runtime's documented subset, which is the
28203
+ * right trade-off for a dev tool: a function using only the documented API
28204
+ * behaves identically; an undocumented Node-only API would work locally but
28205
+ * not deployed).
28206
+ *
28207
+ * `console` is added by the caller. A `require` of anything other than the
28208
+ * three modules above throws, and `fs` / `process` / timers / network / `eval`
28209
+ * are not provided as globals — matching the deployed runtime's restricted
28210
+ * features (a fidelity convenience, not a hard isolation guarantee; see the
28211
+ * module docstring).
28212
+ */
28213
+ function cloudFrontRuntimeRequire(name) {
28214
+ if (name === "crypto") return nodeCrypto;
28215
+ if (name === "querystring") return nodeQuerystring;
28216
+ if (name === "buffer") return nodeBuffer;
28217
+ throw new Error(`Cannot find module '${name}'. CloudFront Functions only provides the 'crypto', 'querystring', and 'buffer' built-in modules.`);
28218
+ }
28219
+ /** The CloudFront-Functions-2.0 globals + `require` to merge into a sandbox. */
28220
+ function cloudFrontRuntimeGlobals() {
28221
+ return {
28222
+ Buffer,
28223
+ atob,
28224
+ btoa,
28225
+ TextEncoder,
28226
+ TextDecoder,
28227
+ require: cloudFrontRuntimeRequire
28228
+ };
28229
+ }
28230
+ /**
28190
28231
  * Hard cap on a single CloudFront Function's synchronous run. The deployed
28191
28232
  * runtime caps CPU at ~1ms; locally we are generous but still bound it so a
28192
28233
  * runaway `while (true) {}` in a function fails that one request with a clear
@@ -28237,7 +28278,10 @@ function compileCloudFrontFunction(logicalId, code, runtime) {
28237
28278
  }
28238
28279
  let hasHandler;
28239
28280
  try {
28240
- const probeGlobals = { console };
28281
+ const probeGlobals = {
28282
+ console,
28283
+ ...cloudFrontRuntimeGlobals()
28284
+ };
28241
28285
  if (bindingName) probeGlobals[bindingName] = createUnboundCloudFrontModule(logicalId);
28242
28286
  const probeContext = vm.createContext(probeGlobals);
28243
28287
  hasHandler = new vm.Script(`${source}\n;typeof handler === 'function'`).runInContext(probeContext, { timeout: FUNCTION_TIMEOUT_MS });
@@ -28262,6 +28306,7 @@ function compileCloudFrontFunction(logicalId, code, runtime) {
28262
28306
  async function invokeCloudFrontFunction(fn, event) {
28263
28307
  const sandbox = {
28264
28308
  console,
28309
+ ...cloudFrontRuntimeGlobals(),
28265
28310
  [EVENT_GLOBAL]: event
28266
28311
  };
28267
28312
  if (fn.cloudfrontBindingName) sandbox[fn.cloudfrontBindingName] = fn.cloudfrontModule ?? createUnboundCloudFrontModule(fn.logicalId);
@@ -29182,15 +29227,11 @@ function serveFromStaticOrigin(input) {
29182
29227
  headers: { "content-type": contentTypeForKey(key) },
29183
29228
  body: direct
29184
29229
  };
29185
- const errorResponses = input.customErrorResponses ?? [];
29186
- for (const code of [403, 404]) {
29187
- const match = errorResponses.find((e) => e.errorCode === code);
29188
- if (!match || !match.responsePagePath) continue;
29189
- const errorKey = stripLeadingSlash(match.responsePagePath);
29190
- const body = readKey(input.localDirs, errorKey);
29230
+ for (const candidate of resolveErrorResponseCandidates(input.customErrorResponses)) {
29231
+ const body = readKey(input.localDirs, candidate.errorKey);
29191
29232
  if (body) return {
29192
- statusCode: match.responseCode ?? code,
29193
- headers: { "content-type": contentTypeForKey(errorKey) },
29233
+ statusCode: candidate.responseCode,
29234
+ headers: { "content-type": contentTypeForKey(candidate.errorKey) },
29194
29235
  body
29195
29236
  };
29196
29237
  }
@@ -29201,6 +29242,27 @@ function serveFromStaticOrigin(input) {
29201
29242
  };
29202
29243
  }
29203
29244
  /**
29245
+ * Resolve the ordered list of custom-error-page candidates to try when an
29246
+ * origin object is missing/forbidden, shared by the local-dir static origin and
29247
+ * the deployed-S3 read-through origin so the 403-then-404 priority + the
29248
+ * `ResponseCode` mapping live in ONE place. We try 403 first then 404 because a
29249
+ * missing key on an OAC-fronted private bucket returns 403 AccessDenied (the
29250
+ * common static-site setup), but an app that mapped 404 instead is also honored.
29251
+ */
29252
+ function resolveErrorResponseCandidates(customErrorResponses) {
29253
+ const errorResponses = customErrorResponses ?? [];
29254
+ const out = [];
29255
+ for (const code of [403, 404]) {
29256
+ const match = errorResponses.find((e) => e.errorCode === code);
29257
+ if (!match || !match.responsePagePath) continue;
29258
+ out.push({
29259
+ errorKey: stripLeadingSlash(match.responsePagePath),
29260
+ responseCode: match.responseCode ?? code
29261
+ });
29262
+ }
29263
+ return out;
29264
+ }
29265
+ /**
29204
29266
  * Map a request URI to an S3 object key. The query string / fragment is
29205
29267
  * dropped, the leading slash is removed, and the root path (`/` or empty)
29206
29268
  * resolves to the default root object. A URI ending in `/` is NOT auto-indexed
@@ -29297,9 +29359,10 @@ async function startCloudFrontServer(options) {
29297
29359
  const logger = getLogger().child("cloudfront");
29298
29360
  const lambdaInvokers = options.lambdaInvokers ?? /* @__PURE__ */ new Map();
29299
29361
  const edgeInvokers = options.edgeInvokers ?? /* @__PURE__ */ new Map();
29362
+ const s3OriginReaders = options.s3OriginReaders ?? /* @__PURE__ */ new Map();
29300
29363
  const state = { distribution: options.distribution };
29301
29364
  const handler = (req, res) => {
29302
- handleRequest$1(req, res, state, lambdaInvokers, edgeInvokers, logger).catch((err) => {
29365
+ handleRequest$1(req, res, state, lambdaInvokers, edgeInvokers, s3OriginReaders, logger).catch((err) => {
29303
29366
  logger.warn(`Request handling failed: ${err instanceof Error ? err.message : String(err)}`);
29304
29367
  if (!res.headersSent) {
29305
29368
  res.statusCode = 500;
@@ -29329,7 +29392,7 @@ async function startCloudFrontServer(options) {
29329
29392
  };
29330
29393
  }
29331
29394
  /** The per-request pipeline: behavior match -> viewer-request -> origin -> viewer-response. */
29332
- async function handleRequest$1(req, res, state, lambdaInvokers, edgeInvokers, logger) {
29395
+ async function handleRequest$1(req, res, state, lambdaInvokers, edgeInvokers, s3OriginReaders, logger) {
29333
29396
  const distribution = state.distribution;
29334
29397
  const rawUrl = req.url ?? "/";
29335
29398
  const queryIdx = rawUrl.indexOf("?");
@@ -29420,6 +29483,7 @@ async function handleRequest$1(req, res, state, lambdaInvokers, edgeInvokers, lo
29420
29483
  sourceIp: clientIp,
29421
29484
  distribution,
29422
29485
  lambdaInvokers,
29486
+ s3OriginReaders,
29423
29487
  logger
29424
29488
  });
29425
29489
  if (!originResult) return writePlain(res, 502, originUnavailableMessage(origin, behavior));
@@ -29591,6 +29655,20 @@ async function serveFromOrigin(origin, args) {
29591
29655
  ...result.cookies.length > 0 && { setCookies: result.cookies }
29592
29656
  };
29593
29657
  }
29658
+ if (origin.kind === "s3-deployed") {
29659
+ const reader = args.s3OriginReaders.get(origin.originId);
29660
+ if (!reader) return void 0;
29661
+ const result = await reader({
29662
+ uri: args.uri,
29663
+ ...distribution.defaultRootObject !== void 0 && { defaultRootObject: distribution.defaultRootObject },
29664
+ customErrorResponses: distribution.customErrorResponses
29665
+ });
29666
+ return {
29667
+ statusCode: result.statusCode,
29668
+ headers: result.headers,
29669
+ body: result.body
29670
+ };
29671
+ }
29594
29672
  if (origin.kind !== "s3") return void 0;
29595
29673
  const result = serveFromStaticOrigin({
29596
29674
  localDirs: origin.localDirs,
@@ -29608,6 +29686,8 @@ function originUnavailableMessage(origin, behavior) {
29608
29686
  if (!origin) return `Behavior ${behavior.pathPattern ?? "(default)"} targets unknown origin '${behavior.targetOriginId}'.\n`;
29609
29687
  if (origin.kind === "lambda-url") return `Origin '${origin.originId}' is a Lambda Function URL origin whose backing function '${origin.functionLogicalId}' was not booted (it was added after start-up). Restart start-cloudfront.\n`;
29610
29688
  if (origin.kind === "custom") return `Origin '${origin.originId}' is a custom (non-S3) origin (${origin.domainName}). cdkl start-cloudfront serves S3 origins and Lambda Function URL origins only.
29689
+ `;
29690
+ if (origin.kind === "s3-deployed") return `Origin '${origin.originId}' is a deployed-S3 origin (bucket '${origin.bucketName}') whose reader was not booted (it was promoted after start-up). Restart start-cloudfront.
29611
29691
  `;
29612
29692
  return `Origin '${origin.originId}' is an S3 origin with no resolvable local source. Point it at a directory with --origin ${origin.originId}=<dir>.\n`;
29613
29693
  }
@@ -29663,6 +29743,101 @@ function listen(server, host, port) {
29663
29743
  });
29664
29744
  }
29665
29745
 
29746
+ //#endregion
29747
+ //#region src/local/cloudfront-s3-origin.ts
29748
+ /**
29749
+ * Build a reader that serves a deployed S3 bucket on demand. The S3 client is
29750
+ * created lazily on first read (and reused) so an all-local distribution never
29751
+ * touches the SDK. Boot-time bound to one `bucketName`; one reader per origin.
29752
+ */
29753
+ function createS3OriginReader(bucketName, options = {}) {
29754
+ const fetchObject = options.fetchObject ?? defaultFetchObject(bucketName, options);
29755
+ let deniedWarned = false;
29756
+ return async (input) => {
29757
+ const key = uriToKey(input.uri, input.defaultRootObject);
29758
+ if (key !== "") {
29759
+ const direct = await fetchObject(key);
29760
+ if (direct.kind === "found") return {
29761
+ statusCode: 200,
29762
+ headers: { "content-type": contentTypeForKey(key) },
29763
+ body: direct.body
29764
+ };
29765
+ if (direct.kind === "denied" && !deniedWarned) {
29766
+ deniedWarned = true;
29767
+ getLogger().warn(`S3 denied reading '${key}' from bucket '${bucketName}'. If this is an OAC-locked / private bucket your credentials cannot read, point the origin at a local directory with --origin <originId>=<dir> (or use credentials with s3:GetObject on the bucket). ${getEmbedConfig().cliName} start-cloudfront reads the origin from real S3.`);
29768
+ }
29769
+ if (direct.kind === "error") getLogger().warn(`S3 read of '${key}' from bucket '${bucketName}' failed: ${direct.message}`);
29770
+ }
29771
+ for (const candidate of resolveErrorResponseCandidates(input.customErrorResponses)) {
29772
+ const page = await fetchObject(candidate.errorKey);
29773
+ if (page.kind === "found") return {
29774
+ statusCode: candidate.responseCode,
29775
+ headers: { "content-type": contentTypeForKey(candidate.errorKey) },
29776
+ body: page.body
29777
+ };
29778
+ }
29779
+ return {
29780
+ statusCode: 404,
29781
+ headers: { "content-type": "text/plain; charset=utf-8" },
29782
+ body: Buffer.from(`Not found: ${input.uri}\n`)
29783
+ };
29784
+ };
29785
+ }
29786
+ /** The default fetcher: a real S3 `GetObject`, classifying the SDK error into the outcome union. */
29787
+ function defaultFetchObject(bucketName, options) {
29788
+ let init = null;
29789
+ const getAccess = () => {
29790
+ if (!init) init = (async () => {
29791
+ const { S3Client, GetObjectCommand } = await import("@aws-sdk/client-s3");
29792
+ return {
29793
+ client: new S3Client({
29794
+ ...options.region && { region: options.region },
29795
+ ...options.credentials && { credentials: {
29796
+ accessKeyId: options.credentials.accessKeyId,
29797
+ secretAccessKey: options.credentials.secretAccessKey,
29798
+ ...options.credentials.sessionToken && { sessionToken: options.credentials.sessionToken }
29799
+ } }
29800
+ }),
29801
+ GetObjectCommand
29802
+ };
29803
+ })();
29804
+ return init;
29805
+ };
29806
+ return async (key) => {
29807
+ try {
29808
+ const { client, GetObjectCommand } = await getAccess();
29809
+ const res = await client.send(new GetObjectCommand({
29810
+ Bucket: bucketName,
29811
+ Key: key
29812
+ }));
29813
+ if (!res.Body) return { kind: "not-found" };
29814
+ const bytes = await res.Body.transformToByteArray();
29815
+ return {
29816
+ kind: "found",
29817
+ body: Buffer.from(bytes)
29818
+ };
29819
+ } catch (err) {
29820
+ return classifyS3Error(err);
29821
+ }
29822
+ };
29823
+ }
29824
+ /**
29825
+ * Classify an S3 SDK error: a missing key (`NoSuchKey` / 404) is `not-found`
29826
+ * (try the SPA fallback), an `AccessDenied` / 403 is `denied` (a credential /
29827
+ * OAC config problem), anything else is `error`.
29828
+ */
29829
+ function classifyS3Error(err) {
29830
+ const e = err;
29831
+ const status = e?.$metadata?.httpStatusCode;
29832
+ const name = e?.name;
29833
+ if (status === 404 || name === "NoSuchKey" || name === "NotFound") return { kind: "not-found" };
29834
+ if (status === 403 || name === "AccessDenied" || name === "Forbidden") return { kind: "denied" };
29835
+ return {
29836
+ kind: "error",
29837
+ message: err instanceof Error ? err.message : String(err)
29838
+ };
29839
+ }
29840
+
29666
29841
  //#endregion
29667
29842
  //#region src/local/cloudfront-kvs-client.ts
29668
29843
  /**
@@ -29995,7 +30170,72 @@ async function bootLambdaEdgeFunctions(distribution, stacks, opts) {
29995
30170
  function warnUnsupported(distribution) {
29996
30171
  const logger = getLogger();
29997
30172
  for (const origin of distribution.origins.values()) if (origin.kind === "custom") logger.warn(`Origin '${origin.originId}' is a custom (non-S3, non-Lambda-Function-URL) origin (${origin.domainName}); ${getEmbedConfig().cliName} start-cloudfront serves S3 origins and Lambda Function URL origins only. Requests routed to it return 502.`);
29998
- else if (origin.kind === "s3-unresolved") logger.warn(`Origin '${origin.originId}' is an S3 origin with no resolvable local source (no BucketDeployment found, or its source could not be located in the cloud assembly). Point it at a directory with --origin ${origin.originId}=<dir>. Requests routed to it return 502.`);
30173
+ else if (origin.kind === "s3-unresolved") logger.warn(`Origin '${origin.originId}' is an S3 origin with no resolvable local source (no BucketDeployment found, or its source could not be located in the cloud assembly). Pass --from-cfn-stack to serve the deployed bucket from real S3 on demand, or point it at a local directory with --origin ${origin.originId}=<dir>. Requests routed to it return 502.`);
30174
+ }
30175
+ /**
30176
+ * Promote each S3 origin with no local BucketDeployment source (`s3-unresolved`)
30177
+ * to a deployed-S3 read-through origin (issue #405), building one
30178
+ * {@link S3OriginReader} per origin. This is the front/back-split path: the CDK
30179
+ * repo defines the distribution + bucket but the static files were uploaded out
30180
+ * of band, so there is nothing in the cloud assembly to serve locally. Under
30181
+ * `--from-cfn-stack`, the bucket's physical NAME is resolved from deployed state
30182
+ * (`ListStackResources`) and the reader serves it from real S3 on demand.
30183
+ *
30184
+ * Returns the readers (keyed by origin id, handed to the server) + the
30185
+ * origin-id -> bucket-name map (re-applied on each `--watch` reload via
30186
+ * {@link annotateDeployedS3Origins}, since the pure resolver re-emits the origin
30187
+ * as `s3-unresolved`). A no-op without `--from-cfn-stack` or when the bucket's
30188
+ * physical id is not in state (the origin stays `s3-unresolved` -> the existing
30189
+ * boot WARN + 502, with `--origin <id>=<dir>` as the escape hatch).
30190
+ */
30191
+ async function resolveDeployedS3Origins(distribution, stacks, options, profileCredentials, logger) {
30192
+ const readers = /* @__PURE__ */ new Map();
30193
+ const buckets = /* @__PURE__ */ new Map();
30194
+ if (!isCfnFlagPresent(options)) return {
30195
+ readers,
30196
+ buckets
30197
+ };
30198
+ const synthRegion = stacks.find((s) => s.stackName === distribution.stackName)?.region;
30199
+ const region = options.stackRegion ?? options.region ?? synthRegion;
30200
+ const provider = createLocalStateProvider(options, distribution.stackName, synthRegion);
30201
+ const record = provider ? await provider.load(distribution.stackName, synthRegion) : void 0;
30202
+ for (const origin of [...distribution.origins.values()]) {
30203
+ if (origin.kind !== "s3-unresolved" || origin.bucketLogicalId === void 0) continue;
30204
+ const bucketName = record?.resources[origin.bucketLogicalId]?.physicalId;
30205
+ if (!bucketName) continue;
30206
+ readers.set(origin.originId, createS3OriginReader(bucketName, {
30207
+ ...region !== void 0 && { region },
30208
+ ...profileCredentials !== void 0 && { credentials: profileCredentials }
30209
+ }));
30210
+ buckets.set(origin.originId, bucketName);
30211
+ distribution.origins.set(origin.originId, {
30212
+ kind: "s3-deployed",
30213
+ originId: origin.originId,
30214
+ bucketName
30215
+ });
30216
+ logger.info(`Origin '${origin.originId}': no local BucketDeployment source; serving from deployed S3 (bucket=${bucketName}) on demand under --from-cfn-stack.`);
30217
+ }
30218
+ return {
30219
+ readers,
30220
+ buckets
30221
+ };
30222
+ }
30223
+ /**
30224
+ * Re-apply the boot-time deployed-S3 promotion to a freshly re-synthed
30225
+ * distribution on a `--watch` reload: the pure resolver re-emits the origin as
30226
+ * `s3-unresolved`, so rewrite it back to `s3-deployed` (same bucket name) so it
30227
+ * dispatches to the boot-time reader. The S3 readers themselves are boot-time
30228
+ * only (like the Function URL origin containers), so nothing is rebuilt here.
30229
+ */
30230
+ function annotateDeployedS3Origins(distribution, buckets) {
30231
+ for (const [originId, bucketName] of buckets) {
30232
+ const origin = distribution.origins.get(originId);
30233
+ if (origin && origin.kind === "s3-unresolved") distribution.origins.set(originId, {
30234
+ kind: "s3-deployed",
30235
+ originId,
30236
+ bucketName
30237
+ });
30238
+ }
29999
30239
  }
30000
30240
  async function localStartCloudFrontCommand(target, options) {
30001
30241
  const logger = getLogger();
@@ -30041,8 +30281,9 @@ async function localStartCloudFrontCommand(target, options) {
30041
30281
  };
30042
30282
  };
30043
30283
  const initial = await synthAndResolve();
30044
- warnUnsupported(initial.distribution);
30045
30284
  const profileCredentials = options.profile ? await resolveProfileCredentials(options.profile) : void 0;
30285
+ const deployedS3 = await resolveDeployedS3Origins(initial.distribution, initial.stacks, options, profileCredentials, logger);
30286
+ warnUnsupported(initial.distribution);
30046
30287
  const envOptions = {
30047
30288
  ...options.fromCfnStack !== void 0 && { fromCfnStack: options.fromCfnStack },
30048
30289
  ...options.assumeRole !== void 0 && { assumeRole: options.assumeRole },
@@ -30072,7 +30313,8 @@ async function localStartCloudFrontCommand(target, options) {
30072
30313
  port: basePort,
30073
30314
  ...tls && { tls },
30074
30315
  ...lambdaInvokers.size > 0 && { lambdaInvokers },
30075
- ...edgeInvokers.size > 0 && { edgeInvokers }
30316
+ ...edgeInvokers.size > 0 && { edgeInvokers },
30317
+ ...deployedS3.readers.size > 0 && { s3OriginReaders: deployedS3.readers }
30076
30318
  });
30077
30319
  } catch (err) {
30078
30320
  await Promise.all([...lambdaRunners, ...edgeRunners].map((r) => r.stop().catch(() => void 0)));
@@ -30098,6 +30340,7 @@ async function localStartCloudFrontCommand(target, options) {
30098
30340
  reloadChain = reloadChain.then(async () => {
30099
30341
  try {
30100
30342
  const reloaded = await synthAndResolve();
30343
+ annotateDeployedS3Origins(reloaded.distribution, deployedS3.buckets);
30101
30344
  warnUnsupported(reloaded.distribution);
30102
30345
  await attachKvsModules(reloaded.distribution, reloaded.stacks, options, profileCredentials, logger);
30103
30346
  server.update(reloaded.distribution);
@@ -30153,7 +30396,7 @@ function createLocalStartCloudFrontCommand(opts = {}) {
30153
30396
  * `cmd`.
30154
30397
  */
30155
30398
  function addStartCloudFrontSpecificOptions(cmd) {
30156
- return cmd.addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--origin <originId=dir>", "Point a distribution origin at a local directory (repeatable). Use when cdk-local cannot resolve the origin's BucketDeployment source automatically (content uploaded out of band, or a non-CDK bucket).").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--kvs-file <kvsLogicalId=file.json>", "Back a CloudFront Function's KeyValueStore reads (cf.kvs().get()) with a local JSON map (repeatable). The key is the AWS::CloudFront::KeyValueStore resource logical id; the file is a flat { \"key\": \"value\" } object. The AWS-free alternative to --from-cfn-stack, which instead reads the deployed store via the GetKey API.").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--tls", "Terminate real TLS (HTTPS). Uses --tls-cert / --tls-key when supplied, else an auto-generated self-signed cert.").default(false)).addOption(new Option("--tls-cert <path>", "PEM server certificate for --tls (implies --tls).")).addOption(new Option("--tls-key <path>", "PEM server private key for --tls (implies --tls).")).addOption(new Option("--no-pull", "Skip 'docker pull' for a Lambda Function URL origin's base image (use the locally cached image).")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Bind a Lambda Function URL origin's backing Lambda to a deployed CloudFormation stack so its env vars resolve to the deployed physical IDs / exports (ListStackResources). Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the resolved stack name; pass a value when the CFn stack name differs. No effect on a pure-S3 distribution.")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).addOption(new Option("--assume-role [arn]", "Assume a Lambda Function URL origin's deployed execution role and forward STS-issued temp credentials into its container so the handler runs with the deployed permissions. Three forms: `--assume-role <arn>` (explicit ARN); `--assume-role` (bare, auto-resolves from state — requires --from-cfn-stack); `--no-assume-role` (opt out). Off by default (the dev shell credentials are forwarded).")).addOption(new Option("--watch", "Hot-reload: re-synth + re-resolve the distribution when the CDK app's source changes (honors cdk.json watch.include/exclude; cdk.out, node_modules, .git are always excluded). The server keeps the previous version serving when synth fails mid-reload.").default(false));
30399
+ return cmd.addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--origin <originId=dir>", "Point a distribution origin at a local directory (repeatable). Use when cdk-local cannot resolve the origin's BucketDeployment source automatically (content uploaded out of band, or a non-CDK bucket).").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--kvs-file <kvsLogicalId=file.json>", "Back a CloudFront Function's KeyValueStore reads (cf.kvs().get()) with a local JSON map (repeatable). The key is the AWS::CloudFront::KeyValueStore resource logical id; the file is a flat { \"key\": \"value\" } object. The AWS-free alternative to --from-cfn-stack, which instead reads the deployed store via the GetKey API.").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--tls", "Terminate real TLS (HTTPS). Uses --tls-cert / --tls-key when supplied, else an auto-generated self-signed cert.").default(false)).addOption(new Option("--tls-cert <path>", "PEM server certificate for --tls (implies --tls).")).addOption(new Option("--tls-key <path>", "PEM server private key for --tls (implies --tls).")).addOption(new Option("--no-pull", "Skip 'docker pull' for a Lambda Function URL origin's base image (use the locally cached image).")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Bind to a deployed CloudFormation stack (ListStackResources). Resolves an S3 origin that has no local BucketDeployment source to its deployed bucket and serves it from real S3 on demand (the front/back-split case: files uploaded out of band), and resolves a Lambda Function URL / Lambda@Edge function's env vars to the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the resolved stack name; pass a value when the CFn stack name differs.")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).addOption(new Option("--assume-role [arn]", "Assume a Lambda Function URL origin's deployed execution role and forward STS-issued temp credentials into its container so the handler runs with the deployed permissions. Three forms: `--assume-role <arn>` (explicit ARN); `--assume-role` (bare, auto-resolves from state — requires --from-cfn-stack); `--no-assume-role` (opt out). Off by default (the dev shell credentials are forwarded).")).addOption(new Option("--watch", "Hot-reload: re-synth + re-resolve the distribution when the CDK app's source changes (honors cdk.json watch.include/exclude; cdk.out, node_modules, .git are always excluded). The server keeps the previous version serving when synth fails mid-reload.").default(false));
30157
30400
  }
30158
30401
 
30159
30402
  //#endregion
@@ -35188,5 +35431,5 @@ function addStudioSpecificOptions(cmd) {
35188
35431
  }
35189
35432
 
35190
35433
  //#endregion
35191
- export { resolveCloudFrontDistribution as $, matchPreflight as $n, AGENTCORE_A2A_PROTOCOL as $r, MCP_CONTAINER_PORT as $t, parseOriginOverrides as A, filterRoutesByApiIdentifiers as An, LocalStateSourceError as Ar, ImageOverrideError as At, applyEdgeRequestResult as B, verifyCognitoJwt as Bn, resolveWatchConfig as Br, buildCloudMapIndex as Bt, addListSpecificOptions as C, createFileWatcher as Cn, resolveRuntimeFileExtension as Cr, buildEcsImageResolutionContext$1 as Ct, addStartCloudFrontSpecificOptions as D, resolveEnvVars$1 as Dn, substituteAgainstStateAsync as Dr, resolveEcsAssumeRoleOption as Dt, LocalStartCloudFrontError as E, materializeLayerFromArn as En, substituteAgainstState as Er, parseRestartPolicy as Et, resolveDeployedKvsArnByName as F, resolveServiceIntegrationParameters as Fn, resolveCfnRegion as Fr, resolveImageOverrides as Ft, httpHeadersToEdge as G, evaluateCachedLambdaPolicy as Gn, discoverWebSocketApis as Gr, getContainerNetworkIp as Gt, buildEdgeRequestEvent as H, verifyJwtViaDiscovery as Hn, countTargets as Hr, DEFAULT_SHADOW_READY_TIMEOUT_MS as Ht, matchBehavior as I, defaultCredentialsLoader as In, resolveCfnStackName as Ir, runImageOverrideBuilds as It, isCloudFrontDistribution as J, attachAuthorizers as Jn, parseSelectionExpressionPath as Jr, createLocalInvokeAgentCoreCommand as Jt, CLOUDFRONT_DISTRIBUTION_TYPE as K, invokeRequestAuthorizer as Kn, discoverWebSocketApisOrThrow as Kr, attachContainerLogStreamer as Kt, startCloudFrontServer as L, buildCognitoJwksUrl as Ln, CfnLocalStateProvider as Lr, describePinnedImageUri as Lt, idFromArn as M, readMtlsMaterialsFromDisk as Mn, isCfnFlagPresent as Mr, enforceImageOverrideOrphans as Mt, resolveKvsModulesForDistribution as N, startApiServer as Nn, rejectExplicitCfnStackWithMultipleStacks as Nr, mergeForService as Nt, createLocalStartCloudFrontCommand as O, availableApiIdentifiers as On, substituteEnvVarsFromState as Or, resolveSharedSidecarCredentials as Ot, createDeployedKvsDataSource as P, resolveSelectionExpression as Pn, resolveCfnFallbackRegion as Pr, parseImageOverrideFlags as Pt, pickTargetFunctionLogicalId as Q, isFunctionUrlOacFronted as Qn, resolveLambdaArnIntrinsic as Qr, a2aInvokeOnce as Qt, serveFromStaticOrigin as R, buildJwksUrlFromIssuer as Rn, collectSsmParameterRefs as Rr, isLocalCdkAssetImage as Rt, StudioEventBus as S, createAuthorizerCache as Sn, resolveRuntimeCodeMountPath as Sr, addImageOverrideOptions as St, formatTargetListing as T, buildStageMap as Tn, EcsTaskResolutionError as Tr, parseMaxTasks as Tt, buildEdgeResponseEvent as U, buildMethodArn as Un, listTargets as Ur, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as Ut, applyEdgeResponseResult as V, verifyJwtAuthorizer as Vn, resolveSingleTarget as Vr, CloudMapRegistry as Vt, edgeHeadersToHttp as W, computeRequestIdentityHash as Wn, availableWebSocketApiIdentifiers as Wr, setShadowReadyTimeoutMs as Wt, pickKvsLogicalIdFromArn as X, buildCorsConfigByApiId as Xn, discoverRoutes as Xr, A2A_CONTAINER_PORT as Xt, pickFunctionUrlLogicalIdFromOrigin as Y, applyCorsResponseHeaders as Yn, webSocketApiMatchesIdentifier as Yr, invokeAgentCoreWs as Yt, pickLambdaEdgeFunctionLogicalId as Z, buildCorsConfigFromCloudFrontChain as Zn, pickRefLogicalId as Zr, A2A_PATH as Zt, filterStudioTargetGroups as _, createLocalInvokeCommand as _n, buildConnectEvent as _r, addRunTaskSpecificOptions as _t, createLocalStudioCommand as a, pickAgentCoreCandidateStack as ai, signAgentCoreInvocation as an, evaluateResponseParameters as ar, createLocalFileKvsDataSource as at, renderStudioHtml as b, createWatchPredicates as bn, architectureToPlatform as br, addCommonEcsServiceOptions as bt, startStudioProxy as c, formatStateRemedy as ci, waitForAgentCorePing as cn, tryParseStatus as cr, albStrategy as ct, createStudioDispatcher as d, LocalInvokeBuildError as di, buildAgentCoreCodeImage as dn, probeHostGatewaySupport as dr, resolveAlbTarget as dt, AGENTCORE_AGUI_PROTOCOL as ei, MCP_PATH as en, matchRoute as er, compileCloudFrontFunction as et, filterStudioCustomResources as f, buildStsClientConfig as fi, computeCodeImageTag as fn, bufferToBody as fr, isApplicationLoadBalancer as ft, annotatePinnedEcsTargets as g, addInvokeSpecificOptions as gn, parseConnectionsPath as gr, serviceStrategy as gt, annotateEcsTaskPinnedTargets as h, classifySourceChange as hn, handleConnectionsRequest as hr, createLocalStartServiceCommand as ht, coerceStopRequest as i, AgentCoreResolutionError as ii, AGENTCORE_SIGV4_SERVICE as in, buildRestV1Event as ir, createCloudFrontModule as it, resolveCloudFrontTarget as j, groupRoutesByServer as jn, createLocalStateProvider as jr, buildImageOverrideTag as jt, parseKvsFileOverrides as k, filterRoutesByApiIdentifier as kn, substituteEnvVarsFromStateAsync as kr, runEcsServiceEmulator as kt, relayServeRequest as l, substituteImagePlaceholders as li, downloadAndExtractS3Bundle as ln, VtlEvaluationError as lr, createLocalStartAlbCommand as lt, annotateAlbPinnedBackingServices as m, toCmdArgv as mn, buildMgmtEndpointEnvUrl as mr, addStartServiceSpecificOptions as mt, coerceRunRequest as n, AGENTCORE_MCP_PROTOCOL as ni, mcpInvokeOnce as nn, applyAuthorizerOverlay as nr, runViewerResponse as nt, resolveServeBaseUrl as o, resolveAgentCoreTarget as oi, AGENTCORE_SESSION_ID_HEADER as on, pickResponseTemplate as or, createUnboundCloudFrontModule as ot, isCustomResourceLambdaTarget as p, resolveProfileCredentials as pi, renderCodeDockerfile as pn, ConnectionRegistry as pr, resolveAlbFrontDoor as pt, extractKvsAssociations as q, invokeTokenAuthorizer as qn, filterWebSocketApisByIdentifiers as qr, addInvokeAgentCoreSpecificOptions as qt, coerceServeRequest as r, AGENTCORE_RUNTIME_TYPE as ri, parseSseForJsonRpc as rn, buildHttpApiV2Event as rr, stripCloudFrontImport as rt, createStudioServeManager as s, derivePseudoParametersFromRegion as si, invokeAgentCore as sn, selectIntegrationResponse as sr, addAlbSpecificOptions as st, addStudioSpecificOptions as t, AGENTCORE_HTTP_PROTOCOL as ti, MCP_PROTOCOL_VERSION as tn, translateLambdaResponse as tr, runViewerRequest as tt, reinvoke as u, tryResolveImageFnJoin as ui, SUPPORTED_CODE_RUNTIMES as un, HOST_GATEWAY_MIN_VERSION as ur, parseLbPortOverrides as ut, startStudioServer as v, addStartApiSpecificOptions as vn, buildDisconnectEvent as vr, createLocalRunTaskCommand as vt, createLocalListCommand as w, attachStageContext as wn, resolveRuntimeImage as wr, ecsClusterOption as wt, createStudioStore as x, resolveApiTargetSubset as xn, buildContainerImage as xr, addEcsAssumeRoleOptions as xt, toStudioTargetGroups as y, createLocalStartApiCommand as yn, buildMessageEvent as yr, MAX_TASKS_SUBNET_RANGE_CAP as yt, serveLambdaUrlOrigin as z, createJwksCache as zn, resolveSsmParameters as zr, listPinnedTargets as zt };
35192
- //# sourceMappingURL=local-studio--ndMb9dM.js.map
35434
+ export { pickKvsLogicalIdFromArn as $, buildCorsConfigByApiId as $n, discoverRoutes as $r, A2A_CONTAINER_PORT as $t, parseOriginOverrides as A, resolveEnvVars$1 as An, substituteAgainstStateAsync as Ar, resolveEcsAssumeRoleOption as At, resolveErrorResponseCandidates as B, buildCognitoJwksUrl as Bn, CfnLocalStateProvider as Br, describePinnedImageUri as Bt, addListSpecificOptions as C, createWatchPredicates as Cn, architectureToPlatform as Cr, addCommonEcsServiceOptions as Ct, addStartCloudFrontSpecificOptions as D, attachStageContext as Dn, resolveRuntimeImage as Dr, ecsClusterOption as Dt, LocalStartCloudFrontError as E, createFileWatcher as En, resolveRuntimeFileExtension as Er, buildEcsImageResolutionContext$1 as Et, resolveDeployedKvsArnByName as F, readMtlsMaterialsFromDisk as Fn, isCfnFlagPresent as Fr, enforceImageOverrideOrphans as Ft, buildEdgeRequestEvent as G, verifyJwtViaDiscovery as Gn, countTargets as Gr, DEFAULT_SHADOW_READY_TIMEOUT_MS as Gt, serveLambdaUrlOrigin as H, createJwksCache as Hn, resolveSsmParameters as Hr, listPinnedTargets as Ht, classifyS3Error as I, startApiServer as In, rejectExplicitCfnStackWithMultipleStacks as Ir, mergeForService as It, httpHeadersToEdge as J, evaluateCachedLambdaPolicy as Jn, discoverWebSocketApis as Jr, getContainerNetworkIp as Jt, buildEdgeResponseEvent as K, buildMethodArn as Kn, listTargets as Kr, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as Kt, createS3OriginReader as L, resolveSelectionExpression as Ln, resolveCfnFallbackRegion as Lr, parseImageOverrideFlags as Lt, idFromArn as M, filterRoutesByApiIdentifier as Mn, substituteEnvVarsFromStateAsync as Mr, runEcsServiceEmulator as Mt, resolveKvsModulesForDistribution as N, filterRoutesByApiIdentifiers as Nn, LocalStateSourceError as Nr, ImageOverrideError as Nt, createLocalStartCloudFrontCommand as O, buildStageMap as On, EcsTaskResolutionError as Or, parseMaxTasks as Ot, createDeployedKvsDataSource as P, groupRoutesByServer as Pn, createLocalStateProvider as Pr, buildImageOverrideTag as Pt, pickFunctionUrlLogicalIdFromOrigin as Q, applyCorsResponseHeaders as Qn, webSocketApiMatchesIdentifier as Qr, invokeAgentCoreWs as Qt, matchBehavior as R, resolveServiceIntegrationParameters as Rn, resolveCfnRegion as Rr, resolveImageOverrides as Rt, StudioEventBus as S, createLocalStartApiCommand as Sn, buildMessageEvent as Sr, MAX_TASKS_SUBNET_RANGE_CAP as St, formatTargetListing as T, createAuthorizerCache as Tn, resolveRuntimeCodeMountPath as Tr, addImageOverrideOptions as Tt, applyEdgeRequestResult as U, verifyCognitoJwt as Un, resolveWatchConfig as Ur, buildCloudMapIndex as Ut, serveFromStaticOrigin as V, buildJwksUrlFromIssuer as Vn, collectSsmParameterRefs as Vr, isLocalCdkAssetImage as Vt, applyEdgeResponseResult as W, verifyJwtAuthorizer as Wn, resolveSingleTarget as Wr, CloudMapRegistry as Wt, extractKvsAssociations as X, invokeTokenAuthorizer as Xn, filterWebSocketApisByIdentifiers as Xr, addInvokeAgentCoreSpecificOptions as Xt, CLOUDFRONT_DISTRIBUTION_TYPE as Y, invokeRequestAuthorizer as Yn, discoverWebSocketApisOrThrow as Yr, attachContainerLogStreamer as Yt, isCloudFrontDistribution as Z, attachAuthorizers as Zn, parseSelectionExpressionPath as Zr, createLocalInvokeAgentCoreCommand as Zt, filterStudioTargetGroups as _, toCmdArgv as _n, buildMgmtEndpointEnvUrl as _r, addStartServiceSpecificOptions as _t, createLocalStudioCommand as a, AGENTCORE_MCP_PROTOCOL as ai, mcpInvokeOnce as an, applyAuthorizerOverlay as ar, runViewerResponse as at, renderStudioHtml as b, createLocalInvokeCommand as bn, buildConnectEvent as br, addRunTaskSpecificOptions as bt, startStudioProxy as c, pickAgentCoreCandidateStack as ci, signAgentCoreInvocation as cn, evaluateResponseParameters as cr, createLocalFileKvsDataSource as ct, createStudioDispatcher as d, formatStateRemedy as di, waitForAgentCorePing as dn, tryParseStatus as dr, albStrategy as dt, pickRefLogicalId as ei, A2A_PATH as en, buildCorsConfigFromCloudFrontChain as er, pickLambdaEdgeFunctionLogicalId as et, filterStudioCustomResources as f, substituteImagePlaceholders as fi, downloadAndExtractS3Bundle as fn, VtlEvaluationError as fr, createLocalStartAlbCommand as ft, annotatePinnedEcsTargets as g, resolveProfileCredentials as gi, renderCodeDockerfile as gn, ConnectionRegistry as gr, resolveAlbFrontDoor as gt, annotateEcsTaskPinnedTargets as h, buildStsClientConfig as hi, computeCodeImageTag as hn, bufferToBody as hr, isApplicationLoadBalancer as ht, coerceStopRequest as i, AGENTCORE_HTTP_PROTOCOL as ii, MCP_PROTOCOL_VERSION as in, translateLambdaResponse as ir, runViewerRequest as it, resolveCloudFrontTarget as j, availableApiIdentifiers as jn, substituteEnvVarsFromState as jr, resolveSharedSidecarCredentials as jt, parseKvsFileOverrides as k, materializeLayerFromArn as kn, substituteAgainstState as kr, parseRestartPolicy as kt, relayServeRequest as l, resolveAgentCoreTarget as li, AGENTCORE_SESSION_ID_HEADER as ln, pickResponseTemplate as lr, createUnboundCloudFrontModule as lt, annotateAlbPinnedBackingServices as m, LocalInvokeBuildError as mi, buildAgentCoreCodeImage as mn, probeHostGatewaySupport as mr, resolveAlbTarget as mt, coerceRunRequest as n, AGENTCORE_A2A_PROTOCOL as ni, MCP_CONTAINER_PORT as nn, matchPreflight as nr, resolveCloudFrontDistribution as nt, resolveServeBaseUrl as o, AGENTCORE_RUNTIME_TYPE as oi, parseSseForJsonRpc as on, buildHttpApiV2Event as or, stripCloudFrontImport as ot, isCustomResourceLambdaTarget as p, tryResolveImageFnJoin as pi, SUPPORTED_CODE_RUNTIMES as pn, HOST_GATEWAY_MIN_VERSION as pr, parseLbPortOverrides as pt, edgeHeadersToHttp as q, computeRequestIdentityHash as qn, availableWebSocketApiIdentifiers as qr, setShadowReadyTimeoutMs as qt, coerceServeRequest as r, AGENTCORE_AGUI_PROTOCOL as ri, MCP_PATH as rn, matchRoute as rr, compileCloudFrontFunction as rt, createStudioServeManager as s, AgentCoreResolutionError as si, AGENTCORE_SIGV4_SERVICE as sn, buildRestV1Event as sr, createCloudFrontModule as st, addStudioSpecificOptions as t, resolveLambdaArnIntrinsic as ti, a2aInvokeOnce as tn, isFunctionUrlOacFronted as tr, pickTargetFunctionLogicalId as tt, reinvoke as u, derivePseudoParametersFromRegion as ui, invokeAgentCore as un, selectIntegrationResponse as ur, addAlbSpecificOptions as ut, startStudioServer as v, classifySourceChange as vn, handleConnectionsRequest as vr, createLocalStartServiceCommand as vt, createLocalListCommand as w, resolveApiTargetSubset as wn, buildContainerImage as wr, addEcsAssumeRoleOptions as wt, createStudioStore as x, addStartApiSpecificOptions as xn, buildDisconnectEvent as xr, createLocalRunTaskCommand as xt, toStudioTargetGroups as y, addInvokeSpecificOptions as yn, parseConnectionsPath as yr, serviceStrategy as yt, startCloudFrontServer as z, defaultCredentialsLoader as zn, resolveCfnStackName as zr, runImageOverrideBuilds as zt };
35435
+ //# sourceMappingURL=local-studio-CFgAjIjT.js.map