@go-to-k/cdkd 0.68.0 → 0.70.0

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/dist/cli.js CHANGED
@@ -4374,16 +4374,16 @@ var require_printer = __commonJS({
4374
4374
  },
4375
4375
  // Document
4376
4376
  Document: {
4377
- leave: (node) => join7(node.definitions, "\n\n")
4377
+ leave: (node) => join8(node.definitions, "\n\n")
4378
4378
  },
4379
4379
  OperationDefinition: {
4380
4380
  leave(node) {
4381
- const varDefs = hasMultilineItems(node.variableDefinitions) ? wrap("(\n", join7(node.variableDefinitions, "\n"), "\n)") : wrap("(", join7(node.variableDefinitions, ", "), ")");
4382
- const prefix = wrap("", node.description, "\n") + join7(
4381
+ const varDefs = hasMultilineItems(node.variableDefinitions) ? wrap("(\n", join8(node.variableDefinitions, "\n"), "\n)") : wrap("(", join8(node.variableDefinitions, ", "), ")");
4382
+ const prefix = wrap("", node.description, "\n") + join8(
4383
4383
  [
4384
4384
  node.operation,
4385
- join7([node.name, varDefs]),
4386
- join7(node.directives, " ")
4385
+ join8([node.name, varDefs]),
4386
+ join8(node.directives, " ")
4387
4387
  ],
4388
4388
  " "
4389
4389
  );
@@ -4391,7 +4391,7 @@ var require_printer = __commonJS({
4391
4391
  }
4392
4392
  },
4393
4393
  VariableDefinition: {
4394
- leave: ({ variable, type, defaultValue, directives, description }) => wrap("", description, "\n") + variable + ": " + type + wrap(" = ", defaultValue) + wrap(" ", join7(directives, " "))
4394
+ leave: ({ variable, type, defaultValue, directives, description }) => wrap("", description, "\n") + variable + ": " + type + wrap(" = ", defaultValue) + wrap(" ", join8(directives, " "))
4395
4395
  },
4396
4396
  SelectionSet: {
4397
4397
  leave: ({ selections }) => block(selections)
@@ -4399,11 +4399,11 @@ var require_printer = __commonJS({
4399
4399
  Field: {
4400
4400
  leave({ alias, name, arguments: args, directives, selectionSet }) {
4401
4401
  const prefix = wrap("", alias, ": ") + name;
4402
- let argsLine = prefix + wrap("(", join7(args, ", "), ")");
4402
+ let argsLine = prefix + wrap("(", join8(args, ", "), ")");
4403
4403
  if (argsLine.length > MAX_LINE_LENGTH) {
4404
- argsLine = prefix + wrap("(\n", indent(join7(args, "\n")), "\n)");
4404
+ argsLine = prefix + wrap("(\n", indent(join8(args, "\n")), "\n)");
4405
4405
  }
4406
- return join7([argsLine, join7(directives, " "), selectionSet], " ");
4406
+ return join8([argsLine, join8(directives, " "), selectionSet], " ");
4407
4407
  }
4408
4408
  },
4409
4409
  Argument: {
@@ -4411,14 +4411,14 @@ var require_printer = __commonJS({
4411
4411
  },
4412
4412
  // Fragments
4413
4413
  FragmentSpread: {
4414
- leave: ({ name, directives }) => "..." + name + wrap(" ", join7(directives, " "))
4414
+ leave: ({ name, directives }) => "..." + name + wrap(" ", join8(directives, " "))
4415
4415
  },
4416
4416
  InlineFragment: {
4417
- leave: ({ typeCondition, directives, selectionSet }) => join7(
4417
+ leave: ({ typeCondition, directives, selectionSet }) => join8(
4418
4418
  [
4419
4419
  "...",
4420
4420
  wrap("on ", typeCondition),
4421
- join7(directives, " "),
4421
+ join8(directives, " "),
4422
4422
  selectionSet
4423
4423
  ],
4424
4424
  " "
@@ -4434,7 +4434,7 @@ var require_printer = __commonJS({
4434
4434
  description
4435
4435
  }) => wrap("", description, "\n") + // Note: fragment variable definitions are experimental and may be changed
4436
4436
  // or removed in the future.
4437
- `fragment ${name}${wrap("(", join7(variableDefinitions, ", "), ")")} on ${typeCondition} ${wrap("", join7(directives, " "), " ")}` + selectionSet
4437
+ `fragment ${name}${wrap("(", join8(variableDefinitions, ", "), ")")} on ${typeCondition} ${wrap("", join8(directives, " "), " ")}` + selectionSet
4438
4438
  },
4439
4439
  // Value
4440
4440
  IntValue: {
@@ -4456,17 +4456,17 @@ var require_printer = __commonJS({
4456
4456
  leave: ({ value }) => value
4457
4457
  },
4458
4458
  ListValue: {
4459
- leave: ({ values }) => "[" + join7(values, ", ") + "]"
4459
+ leave: ({ values }) => "[" + join8(values, ", ") + "]"
4460
4460
  },
4461
4461
  ObjectValue: {
4462
- leave: ({ fields }) => "{" + join7(fields, ", ") + "}"
4462
+ leave: ({ fields }) => "{" + join8(fields, ", ") + "}"
4463
4463
  },
4464
4464
  ObjectField: {
4465
4465
  leave: ({ name, value }) => name + ": " + value
4466
4466
  },
4467
4467
  // Directive
4468
4468
  Directive: {
4469
- leave: ({ name, arguments: args }) => "@" + name + wrap("(", join7(args, ", "), ")")
4469
+ leave: ({ name, arguments: args }) => "@" + name + wrap("(", join8(args, ", "), ")")
4470
4470
  },
4471
4471
  // Type
4472
4472
  NamedType: {
@@ -4480,61 +4480,61 @@ var require_printer = __commonJS({
4480
4480
  },
4481
4481
  // Type System Definitions
4482
4482
  SchemaDefinition: {
4483
- leave: ({ description, directives, operationTypes }) => wrap("", description, "\n") + join7(["schema", join7(directives, " "), block(operationTypes)], " ")
4483
+ leave: ({ description, directives, operationTypes }) => wrap("", description, "\n") + join8(["schema", join8(directives, " "), block(operationTypes)], " ")
4484
4484
  },
4485
4485
  OperationTypeDefinition: {
4486
4486
  leave: ({ operation, type }) => operation + ": " + type
4487
4487
  },
4488
4488
  ScalarTypeDefinition: {
4489
- leave: ({ description, name, directives }) => wrap("", description, "\n") + join7(["scalar", name, join7(directives, " ")], " ")
4489
+ leave: ({ description, name, directives }) => wrap("", description, "\n") + join8(["scalar", name, join8(directives, " ")], " ")
4490
4490
  },
4491
4491
  ObjectTypeDefinition: {
4492
- leave: ({ description, name, interfaces, directives, fields }) => wrap("", description, "\n") + join7(
4492
+ leave: ({ description, name, interfaces, directives, fields }) => wrap("", description, "\n") + join8(
4493
4493
  [
4494
4494
  "type",
4495
4495
  name,
4496
- wrap("implements ", join7(interfaces, " & ")),
4497
- join7(directives, " "),
4496
+ wrap("implements ", join8(interfaces, " & ")),
4497
+ join8(directives, " "),
4498
4498
  block(fields)
4499
4499
  ],
4500
4500
  " "
4501
4501
  )
4502
4502
  },
4503
4503
  FieldDefinition: {
4504
- leave: ({ description, name, arguments: args, type, directives }) => wrap("", description, "\n") + name + (hasMultilineItems(args) ? wrap("(\n", indent(join7(args, "\n")), "\n)") : wrap("(", join7(args, ", "), ")")) + ": " + type + wrap(" ", join7(directives, " "))
4504
+ leave: ({ description, name, arguments: args, type, directives }) => wrap("", description, "\n") + name + (hasMultilineItems(args) ? wrap("(\n", indent(join8(args, "\n")), "\n)") : wrap("(", join8(args, ", "), ")")) + ": " + type + wrap(" ", join8(directives, " "))
4505
4505
  },
4506
4506
  InputValueDefinition: {
4507
- leave: ({ description, name, type, defaultValue, directives }) => wrap("", description, "\n") + join7(
4508
- [name + ": " + type, wrap("= ", defaultValue), join7(directives, " ")],
4507
+ leave: ({ description, name, type, defaultValue, directives }) => wrap("", description, "\n") + join8(
4508
+ [name + ": " + type, wrap("= ", defaultValue), join8(directives, " ")],
4509
4509
  " "
4510
4510
  )
4511
4511
  },
4512
4512
  InterfaceTypeDefinition: {
4513
- leave: ({ description, name, interfaces, directives, fields }) => wrap("", description, "\n") + join7(
4513
+ leave: ({ description, name, interfaces, directives, fields }) => wrap("", description, "\n") + join8(
4514
4514
  [
4515
4515
  "interface",
4516
4516
  name,
4517
- wrap("implements ", join7(interfaces, " & ")),
4518
- join7(directives, " "),
4517
+ wrap("implements ", join8(interfaces, " & ")),
4518
+ join8(directives, " "),
4519
4519
  block(fields)
4520
4520
  ],
4521
4521
  " "
4522
4522
  )
4523
4523
  },
4524
4524
  UnionTypeDefinition: {
4525
- leave: ({ description, name, directives, types }) => wrap("", description, "\n") + join7(
4526
- ["union", name, join7(directives, " "), wrap("= ", join7(types, " | "))],
4525
+ leave: ({ description, name, directives, types }) => wrap("", description, "\n") + join8(
4526
+ ["union", name, join8(directives, " "), wrap("= ", join8(types, " | "))],
4527
4527
  " "
4528
4528
  )
4529
4529
  },
4530
4530
  EnumTypeDefinition: {
4531
- leave: ({ description, name, directives, values }) => wrap("", description, "\n") + join7(["enum", name, join7(directives, " "), block(values)], " ")
4531
+ leave: ({ description, name, directives, values }) => wrap("", description, "\n") + join8(["enum", name, join8(directives, " "), block(values)], " ")
4532
4532
  },
4533
4533
  EnumValueDefinition: {
4534
- leave: ({ description, name, directives }) => wrap("", description, "\n") + join7([name, join7(directives, " ")], " ")
4534
+ leave: ({ description, name, directives }) => wrap("", description, "\n") + join8([name, join8(directives, " ")], " ")
4535
4535
  },
4536
4536
  InputObjectTypeDefinition: {
4537
- leave: ({ description, name, directives, fields }) => wrap("", description, "\n") + join7(["input", name, join7(directives, " "), block(fields)], " ")
4537
+ leave: ({ description, name, directives, fields }) => wrap("", description, "\n") + join8(["input", name, join8(directives, " "), block(fields)], " ")
4538
4538
  },
4539
4539
  DirectiveDefinition: {
4540
4540
  leave: ({
@@ -4544,84 +4544,84 @@ var require_printer = __commonJS({
4544
4544
  directives,
4545
4545
  repeatable,
4546
4546
  locations
4547
- }) => wrap("", description, "\n") + "directive @" + name + (hasMultilineItems(args) ? wrap("(\n", indent(join7(args, "\n")), "\n)") : wrap("(", join7(args, ", "), ")")) + wrap(" ", join7(directives, " ")) + (repeatable ? " repeatable" : "") + " on " + join7(locations, " | ")
4547
+ }) => wrap("", description, "\n") + "directive @" + name + (hasMultilineItems(args) ? wrap("(\n", indent(join8(args, "\n")), "\n)") : wrap("(", join8(args, ", "), ")")) + wrap(" ", join8(directives, " ")) + (repeatable ? " repeatable" : "") + " on " + join8(locations, " | ")
4548
4548
  },
4549
4549
  SchemaExtension: {
4550
- leave: ({ directives, operationTypes }) => join7(
4551
- ["extend schema", join7(directives, " "), block(operationTypes)],
4550
+ leave: ({ directives, operationTypes }) => join8(
4551
+ ["extend schema", join8(directives, " "), block(operationTypes)],
4552
4552
  " "
4553
4553
  )
4554
4554
  },
4555
4555
  ScalarTypeExtension: {
4556
- leave: ({ name, directives }) => join7(["extend scalar", name, join7(directives, " ")], " ")
4556
+ leave: ({ name, directives }) => join8(["extend scalar", name, join8(directives, " ")], " ")
4557
4557
  },
4558
4558
  ObjectTypeExtension: {
4559
- leave: ({ name, interfaces, directives, fields }) => join7(
4559
+ leave: ({ name, interfaces, directives, fields }) => join8(
4560
4560
  [
4561
4561
  "extend type",
4562
4562
  name,
4563
- wrap("implements ", join7(interfaces, " & ")),
4564
- join7(directives, " "),
4563
+ wrap("implements ", join8(interfaces, " & ")),
4564
+ join8(directives, " "),
4565
4565
  block(fields)
4566
4566
  ],
4567
4567
  " "
4568
4568
  )
4569
4569
  },
4570
4570
  InterfaceTypeExtension: {
4571
- leave: ({ name, interfaces, directives, fields }) => join7(
4571
+ leave: ({ name, interfaces, directives, fields }) => join8(
4572
4572
  [
4573
4573
  "extend interface",
4574
4574
  name,
4575
- wrap("implements ", join7(interfaces, " & ")),
4576
- join7(directives, " "),
4575
+ wrap("implements ", join8(interfaces, " & ")),
4576
+ join8(directives, " "),
4577
4577
  block(fields)
4578
4578
  ],
4579
4579
  " "
4580
4580
  )
4581
4581
  },
4582
4582
  UnionTypeExtension: {
4583
- leave: ({ name, directives, types }) => join7(
4583
+ leave: ({ name, directives, types }) => join8(
4584
4584
  [
4585
4585
  "extend union",
4586
4586
  name,
4587
- join7(directives, " "),
4588
- wrap("= ", join7(types, " | "))
4587
+ join8(directives, " "),
4588
+ wrap("= ", join8(types, " | "))
4589
4589
  ],
4590
4590
  " "
4591
4591
  )
4592
4592
  },
4593
4593
  EnumTypeExtension: {
4594
- leave: ({ name, directives, values }) => join7(["extend enum", name, join7(directives, " "), block(values)], " ")
4594
+ leave: ({ name, directives, values }) => join8(["extend enum", name, join8(directives, " "), block(values)], " ")
4595
4595
  },
4596
4596
  InputObjectTypeExtension: {
4597
- leave: ({ name, directives, fields }) => join7(["extend input", name, join7(directives, " "), block(fields)], " ")
4597
+ leave: ({ name, directives, fields }) => join8(["extend input", name, join8(directives, " "), block(fields)], " ")
4598
4598
  },
4599
4599
  DirectiveExtension: {
4600
- leave: ({ name, directives }) => join7(["extend directive @" + name, join7(directives, " ")], " ")
4600
+ leave: ({ name, directives }) => join8(["extend directive @" + name, join8(directives, " ")], " ")
4601
4601
  },
4602
4602
  // Schema Coordinates
4603
4603
  TypeCoordinate: {
4604
4604
  leave: ({ name }) => name
4605
4605
  },
4606
4606
  MemberCoordinate: {
4607
- leave: ({ name, memberName }) => join7([name, wrap(".", memberName)])
4607
+ leave: ({ name, memberName }) => join8([name, wrap(".", memberName)])
4608
4608
  },
4609
4609
  ArgumentCoordinate: {
4610
- leave: ({ name, fieldName, argumentName }) => join7([name, wrap(".", fieldName), wrap("(", argumentName, ":)")])
4610
+ leave: ({ name, fieldName, argumentName }) => join8([name, wrap(".", fieldName), wrap("(", argumentName, ":)")])
4611
4611
  },
4612
4612
  DirectiveCoordinate: {
4613
- leave: ({ name }) => join7(["@", name])
4613
+ leave: ({ name }) => join8(["@", name])
4614
4614
  },
4615
4615
  DirectiveArgumentCoordinate: {
4616
- leave: ({ name, argumentName }) => join7(["@", name, wrap("(", argumentName, ":)")])
4616
+ leave: ({ name, argumentName }) => join8(["@", name, wrap("(", argumentName, ":)")])
4617
4617
  }
4618
4618
  };
4619
- function join7(maybeArray, separator = "") {
4619
+ function join8(maybeArray, separator = "") {
4620
4620
  var _maybeArray$filter$jo;
4621
4621
  return (_maybeArray$filter$jo = maybeArray === null || maybeArray === void 0 ? void 0 : maybeArray.filter((x) => x).join(separator)) !== null && _maybeArray$filter$jo !== void 0 ? _maybeArray$filter$jo : "";
4622
4622
  }
4623
4623
  function block(array) {
4624
- return wrap("{\n", indent(join7(array, "\n")), "\n}");
4624
+ return wrap("{\n", indent(join8(array, "\n")), "\n}");
4625
4625
  }
4626
4626
  function wrap(start, maybeString, end = "") {
4627
4627
  return maybeString != null && maybeString !== "" ? start + maybeString + end : "";
@@ -18319,6 +18319,13 @@ var AssetError = class _AssetError extends CdkdError {
18319
18319
  Object.setPrototypeOf(this, _AssetError.prototype);
18320
18320
  }
18321
18321
  };
18322
+ var LocalInvokeBuildError = class _LocalInvokeBuildError extends CdkdError {
18323
+ constructor(message, cause) {
18324
+ super(message, "LOCAL_INVOKE_BUILD_ERROR", cause);
18325
+ this.name = "LocalInvokeBuildError";
18326
+ Object.setPrototypeOf(this, _LocalInvokeBuildError.prototype);
18327
+ }
18328
+ };
18322
18329
  var ProvisioningError = class _ProvisioningError extends CdkdError {
18323
18330
  constructor(message, resourceType, logicalId, physicalId, cause) {
18324
18331
  super(message, "PROVISIONING_ERROR", cause);
@@ -23436,11 +23443,11 @@ async function resolveStateBucketWithDefaultAndSource(cliBucket, region) {
23436
23443
  return syncResult;
23437
23444
  const logger = getLogger();
23438
23445
  logger.debug("No state bucket specified, resolving default from account...");
23439
- const { GetCallerIdentityCommand: GetCallerIdentityCommand11 } = await import("@aws-sdk/client-sts");
23446
+ const { GetCallerIdentityCommand: GetCallerIdentityCommand12 } = await import("@aws-sdk/client-sts");
23440
23447
  const { S3Client: S3Client12 } = await import("@aws-sdk/client-s3");
23441
23448
  const { getAwsClients: getAwsClients2 } = await Promise.resolve().then(() => (init_aws_clients(), aws_clients_exports));
23442
23449
  const awsClients = getAwsClients2();
23443
- const identity = await awsClients.sts.send(new GetCallerIdentityCommand11({}));
23450
+ const identity = await awsClients.sts.send(new GetCallerIdentityCommand12({}));
23444
23451
  const accountId = identity.Account;
23445
23452
  const newName = getDefaultStateBucketName(accountId);
23446
23453
  const legacyName = getLegacyStateBucketName(accountId, region);
@@ -25322,14 +25329,57 @@ var FileAssetPublisher = class {
25322
25329
  };
25323
25330
 
25324
25331
  // src/assets/docker-asset-publisher.ts
25325
- import { execFile, spawn as spawn2 } from "node:child_process";
25326
- import { promisify } from "node:util";
25332
+ import { execFile as execFile2, spawn as spawn2 } from "node:child_process";
25333
+ import { promisify as promisify2 } from "node:util";
25327
25334
  import {
25328
25335
  ECRClient,
25329
25336
  GetAuthorizationTokenCommand,
25330
25337
  DescribeImagesCommand as DescribeImagesCommand2
25331
25338
  } from "@aws-sdk/client-ecr";
25339
+
25340
+ // src/assets/docker-build.ts
25341
+ import { execFile } from "node:child_process";
25342
+ import { promisify } from "node:util";
25332
25343
  var execFileAsync = promisify(execFile);
25344
+ async function buildDockerImage(asset, cdkOutDir, tag, options) {
25345
+ const logger = getLogger().child("docker-build");
25346
+ const args = ["build", "-t", tag];
25347
+ if (options.platform) {
25348
+ args.push("--platform", options.platform);
25349
+ }
25350
+ if (asset.source.dockerFile) {
25351
+ args.push("-f", asset.source.dockerFile);
25352
+ }
25353
+ if (asset.source.dockerBuildArgs) {
25354
+ for (const [key, value] of Object.entries(asset.source.dockerBuildArgs)) {
25355
+ args.push("--build-arg", `${key}=${value}`);
25356
+ }
25357
+ }
25358
+ if (asset.source.dockerBuildTarget) {
25359
+ args.push("--target", asset.source.dockerBuildTarget);
25360
+ }
25361
+ if (asset.source.dockerOutputs) {
25362
+ for (const output of asset.source.dockerOutputs) {
25363
+ args.push("--output", output);
25364
+ }
25365
+ }
25366
+ const contextDir = `${cdkOutDir}/${asset.source.directory}`;
25367
+ args.push(contextDir);
25368
+ logger.debug(`docker ${args.join(" ")}`);
25369
+ try {
25370
+ await execFileAsync("docker", args, {
25371
+ maxBuffer: 50 * 1024 * 1024
25372
+ // 50MB for build output
25373
+ });
25374
+ } catch (error) {
25375
+ const err = error;
25376
+ const stderr = err.stderr || err.message || String(error);
25377
+ throw options.wrapError(stderr);
25378
+ }
25379
+ }
25380
+
25381
+ // src/assets/docker-asset-publisher.ts
25382
+ var execFileAsync2 = promisify2(execFile2);
25333
25383
  var DockerAssetPublisher = class {
25334
25384
  logger = getLogger().child("DockerAssetPublisher");
25335
25385
  /**
@@ -25412,38 +25462,17 @@ var DockerAssetPublisher = class {
25412
25462
  }
25413
25463
  }
25414
25464
  /**
25415
- * Build Docker image
25465
+ * Build Docker image — delegates to the shared `buildDockerImage`
25466
+ * helper so this code path stays in sync with `cdkd local invoke`'s
25467
+ * container-Lambda build path. `--platform` is currently not threaded
25468
+ * through here (publish-assets has no Architectures hint to consult);
25469
+ * a follow-up can lift this once the asset manifest carries a
25470
+ * platform field.
25416
25471
  */
25417
25472
  async buildImage(asset, cdkOutputDir, tag) {
25418
- const args = ["build", "-t", tag];
25419
- if (asset.source.dockerFile) {
25420
- args.push("-f", asset.source.dockerFile);
25421
- }
25422
- if (asset.source.dockerBuildArgs) {
25423
- for (const [key, value] of Object.entries(asset.source.dockerBuildArgs)) {
25424
- args.push("--build-arg", `${key}=${value}`);
25425
- }
25426
- }
25427
- if (asset.source.dockerBuildTarget) {
25428
- args.push("--target", asset.source.dockerBuildTarget);
25429
- }
25430
- if (asset.source.dockerOutputs) {
25431
- for (const output of asset.source.dockerOutputs) {
25432
- args.push("--output", output);
25433
- }
25434
- }
25435
- const contextDir = `${cdkOutputDir}/${asset.source.directory}`;
25436
- args.push(contextDir);
25437
- this.logger.debug(`docker ${args.join(" ")}`);
25438
- try {
25439
- await execFileAsync("docker", args, {
25440
- maxBuffer: 50 * 1024 * 1024
25441
- // 50MB for build output
25442
- });
25443
- } catch (error) {
25444
- const err = error;
25445
- throw new AssetError(`Docker build failed: ${err.stderr || err.message || String(error)}`);
25446
- }
25473
+ await buildDockerImage(asset, cdkOutputDir, tag, {
25474
+ wrapError: (stderr) => new AssetError(`Docker build failed: ${stderr}`)
25475
+ });
25447
25476
  }
25448
25477
  /**
25449
25478
  * Authenticate with ECR
@@ -25487,7 +25516,7 @@ var DockerAssetPublisher = class {
25487
25516
  * Tag Docker image
25488
25517
  */
25489
25518
  async tagImage(source, target) {
25490
- await execFileAsync("docker", ["tag", source, target]);
25519
+ await execFileAsync2("docker", ["tag", source, target]);
25491
25520
  }
25492
25521
  /**
25493
25522
  * Push Docker image
@@ -25495,7 +25524,7 @@ var DockerAssetPublisher = class {
25495
25524
  async pushImage(uri) {
25496
25525
  this.logger.debug(`Pushing: ${uri}`);
25497
25526
  try {
25498
- await execFileAsync("docker", ["push", uri], {
25527
+ await execFileAsync2("docker", ["push", uri], {
25499
25528
  maxBuffer: 50 * 1024 * 1024
25500
25529
  });
25501
25530
  } catch (error) {
@@ -25718,9 +25747,9 @@ var AssetPublisher = class {
25718
25747
  const region = options.region || process.env["AWS_REGION"] || "us-east-1";
25719
25748
  let accountId = options.accountId;
25720
25749
  if (!accountId) {
25721
- const { STSClient: STSClient10, GetCallerIdentityCommand: GetCallerIdentityCommand11 } = await import("@aws-sdk/client-sts");
25722
- const stsClient = new STSClient10({ region });
25723
- const identity = await stsClient.send(new GetCallerIdentityCommand11({}));
25750
+ const { STSClient: STSClient11, GetCallerIdentityCommand: GetCallerIdentityCommand12 } = await import("@aws-sdk/client-sts");
25751
+ const stsClient = new STSClient11({ region });
25752
+ const identity = await stsClient.send(new GetCallerIdentityCommand12({}));
25724
25753
  accountId = identity.Account;
25725
25754
  stsClient.destroy();
25726
25755
  }
@@ -65303,11 +65332,11 @@ async function deployCommand(stacks, options) {
65303
65332
  addDependencies(stack.stackName);
65304
65333
  }
65305
65334
  }
65306
- const { STSClient: STSClient10, GetCallerIdentityCommand: GetCallerIdentityCommand11 } = await import("@aws-sdk/client-sts");
65307
- const stsClient = new STSClient10({
65335
+ const { STSClient: STSClient11, GetCallerIdentityCommand: GetCallerIdentityCommand12 } = await import("@aws-sdk/client-sts");
65336
+ const stsClient = new STSClient11({
65308
65337
  region: options.region || process.env["AWS_REGION"] || "us-east-1"
65309
65338
  });
65310
- const callerIdentity = await stsClient.send(new GetCallerIdentityCommand11({}));
65339
+ const callerIdentity = await stsClient.send(new GetCallerIdentityCommand12({}));
65311
65340
  const accountId = callerIdentity.Account;
65312
65341
  stsClient.destroy();
65313
65342
  const assetPublisher = new AssetPublisher();
@@ -67780,9 +67809,9 @@ async function publishAssetsCommand(stacks, options) {
67780
67809
  );
67781
67810
  }
67782
67811
  const baseRegion = options.region || process.env["AWS_REGION"] || "us-east-1";
67783
- const { STSClient: STSClient10, GetCallerIdentityCommand: GetCallerIdentityCommand11 } = await import("@aws-sdk/client-sts");
67784
- const stsClient = new STSClient10({ region: baseRegion });
67785
- const callerIdentity = await stsClient.send(new GetCallerIdentityCommand11({}));
67812
+ const { STSClient: STSClient11, GetCallerIdentityCommand: GetCallerIdentityCommand12 } = await import("@aws-sdk/client-sts");
67813
+ const stsClient = new STSClient11({ region: baseRegion });
67814
+ const callerIdentity = await stsClient.send(new GetCallerIdentityCommand12({}));
67786
67815
  const accountId = callerIdentity.Account;
67787
67816
  stsClient.destroy();
67788
67817
  const assetPublisher = new AssetPublisher();
@@ -69963,12 +69992,13 @@ async function captureObservedForImportedResources(stackState, providerRegistry,
69963
69992
  }
69964
69993
 
69965
69994
  // src/cli/commands/local-invoke.ts
69966
- import { mkdtempSync as mkdtempSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
69995
+ import { mkdtempSync as mkdtempSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync6, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "node:fs";
69967
69996
  import { tmpdir as tmpdir2 } from "node:os";
69997
+ import { dirname as dirname2 } from "node:path";
69968
69998
  import * as path from "node:path";
69969
69999
  import { Command as Command14, Option as Option7 } from "commander";
69970
70000
 
69971
- // src/local-invoke/lambda-resolver.ts
70001
+ // src/local/lambda-resolver.ts
69972
70002
  import { existsSync as existsSync4, statSync as statSync3 } from "node:fs";
69973
70003
  import { dirname, isAbsolute, resolve as resolve4 } from "node:path";
69974
70004
  var LocalInvokeResolutionError = class _LocalInvokeResolutionError extends Error {
@@ -70067,25 +70097,38 @@ function pickStack(parsed, stacks) {
70067
70097
  }
70068
70098
  function extractLambdaProperties(stack, logicalId, resource) {
70069
70099
  const props = resource.Properties ?? {};
70070
- const runtime = typeof props["Runtime"] === "string" ? props["Runtime"] : "";
70071
- const handler = typeof props["Handler"] === "string" ? props["Handler"] : "";
70072
70100
  const memoryMb = typeof props["MemorySize"] === "number" ? props["MemorySize"] : 128;
70073
70101
  const timeoutSec = typeof props["Timeout"] === "number" ? props["Timeout"] : 3;
70102
+ const code = props["Code"] ?? {};
70103
+ const imageUri = extractImageUri(code["ImageUri"]);
70104
+ if (imageUri !== void 0) {
70105
+ return extractImageLambdaProperties({
70106
+ stack,
70107
+ logicalId,
70108
+ resource,
70109
+ memoryMb,
70110
+ timeoutSec,
70111
+ props,
70112
+ imageUri
70113
+ });
70114
+ }
70115
+ const runtime = typeof props["Runtime"] === "string" ? props["Runtime"] : "";
70116
+ const handler = typeof props["Handler"] === "string" ? props["Handler"] : "";
70074
70117
  if (!runtime) {
70075
70118
  throw new LocalInvokeResolutionError(
70076
- `Lambda '${logicalId}' has no Runtime property. Container-image Lambdas (Code.ImageUri) are not supported in cdkd local invoke v1.`
70119
+ `Lambda '${logicalId}' has no Runtime property and no Code.ImageUri. cdkd cannot tell if this is a ZIP or a container Lambda.`
70077
70120
  );
70078
70121
  }
70079
70122
  if (!handler) {
70080
70123
  throw new LocalInvokeResolutionError(`Lambda '${logicalId}' has no Handler property.`);
70081
70124
  }
70082
- const code = props["Code"] ?? {};
70083
70125
  const inlineCode = typeof code["ZipFile"] === "string" ? code["ZipFile"] : void 0;
70084
70126
  let codePath = null;
70085
70127
  if (!inlineCode) {
70086
70128
  codePath = resolveAssetCodePath(stack, logicalId, resource);
70087
70129
  }
70088
70130
  return {
70131
+ kind: "zip",
70089
70132
  stack,
70090
70133
  logicalId,
70091
70134
  resource,
@@ -70097,6 +70140,62 @@ function extractLambdaProperties(stack, logicalId, resource) {
70097
70140
  ...inlineCode !== void 0 && { inlineCode }
70098
70141
  };
70099
70142
  }
70143
+ function extractImageUri(value) {
70144
+ if (typeof value === "string" && value.length > 0)
70145
+ return value;
70146
+ if (value && typeof value === "object" && !Array.isArray(value)) {
70147
+ const obj = value;
70148
+ const sub = obj["Fn::Sub"];
70149
+ if (typeof sub === "string" && sub.length > 0)
70150
+ return sub;
70151
+ if (Array.isArray(sub) && typeof sub[0] === "string")
70152
+ return sub[0];
70153
+ }
70154
+ return void 0;
70155
+ }
70156
+ function extractImageLambdaProperties(args) {
70157
+ const { stack, logicalId, resource, memoryMb, timeoutSec, props, imageUri } = args;
70158
+ const rawImageConfig = props["ImageConfig"] ?? {};
70159
+ const imageConfig = {};
70160
+ if (Array.isArray(rawImageConfig["Command"])) {
70161
+ imageConfig.command = rawImageConfig["Command"].filter(
70162
+ (s) => typeof s === "string"
70163
+ );
70164
+ }
70165
+ if (Array.isArray(rawImageConfig["EntryPoint"])) {
70166
+ imageConfig.entryPoint = rawImageConfig["EntryPoint"].filter(
70167
+ (s) => typeof s === "string"
70168
+ );
70169
+ }
70170
+ if (typeof rawImageConfig["WorkingDirectory"] === "string") {
70171
+ imageConfig.workingDirectory = rawImageConfig["WorkingDirectory"];
70172
+ }
70173
+ const arches = props["Architectures"];
70174
+ let architecture = "x86_64";
70175
+ if (Array.isArray(arches) && arches.length > 0) {
70176
+ const first = arches[0];
70177
+ if (first === "arm64")
70178
+ architecture = "arm64";
70179
+ else if (first === "x86_64")
70180
+ architecture = "x86_64";
70181
+ else {
70182
+ throw new LocalInvokeResolutionError(
70183
+ `Lambda '${logicalId}' has unsupported Architectures value '${String(first)}'. cdkd local invoke supports x86_64 and arm64.`
70184
+ );
70185
+ }
70186
+ }
70187
+ return {
70188
+ kind: "image",
70189
+ stack,
70190
+ logicalId,
70191
+ resource,
70192
+ memoryMb,
70193
+ timeoutSec,
70194
+ imageUri,
70195
+ imageConfig,
70196
+ architecture
70197
+ };
70198
+ }
70100
70199
  function resolveAssetCodePath(stack, logicalId, resource) {
70101
70200
  const meta = resource.Metadata;
70102
70201
  const assetPath = meta?.["aws:asset:path"];
@@ -70140,7 +70239,7 @@ function notFoundError(target, stack, resources) {
70140
70239
  return new LocalInvokeResolutionError(msg.trimEnd());
70141
70240
  }
70142
70241
 
70143
- // src/local-invoke/env-resolver.ts
70242
+ // src/local/env-resolver.ts
70144
70243
  function resolveEnvVars(logicalId, templateEnv, overrides) {
70145
70244
  const resolved = {};
70146
70245
  const unresolved = [];
@@ -70177,7 +70276,184 @@ function isLiteralEnvValue(value) {
70177
70276
  return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
70178
70277
  }
70179
70278
 
70180
- // src/local-invoke/runtime-image.ts
70279
+ // src/local/state-resolver.ts
70280
+ function substituteAgainstState(value, resources) {
70281
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
70282
+ return { kind: "literal", value };
70283
+ }
70284
+ if (value === null || typeof value !== "object") {
70285
+ return {
70286
+ kind: "unresolved",
70287
+ reason: `unsupported value type: ${value === null ? "null" : typeof value}`
70288
+ };
70289
+ }
70290
+ const obj = value;
70291
+ const keys = Object.keys(obj);
70292
+ if (keys.length !== 1) {
70293
+ return {
70294
+ kind: "unresolved",
70295
+ reason: `expected an intrinsic with one key, got ${keys.length} keys`
70296
+ };
70297
+ }
70298
+ const intrinsic = keys[0];
70299
+ const arg = obj[intrinsic];
70300
+ if (intrinsic === "Ref") {
70301
+ return resolveRef(arg, resources);
70302
+ }
70303
+ if (intrinsic === "Fn::GetAtt") {
70304
+ return resolveGetAtt(arg, resources);
70305
+ }
70306
+ if (intrinsic === "Fn::Sub") {
70307
+ return resolveSub(arg, resources);
70308
+ }
70309
+ return {
70310
+ kind: "unresolved",
70311
+ reason: `unsupported intrinsic '${intrinsic}' (only Ref, Fn::GetAtt, Fn::Sub are wired in --from-state v1)`
70312
+ };
70313
+ }
70314
+ function resolveRef(arg, resources) {
70315
+ if (typeof arg !== "string" || arg.length === 0) {
70316
+ return { kind: "unresolved", reason: `Ref expects a non-empty logical ID, got ${typeof arg}` };
70317
+ }
70318
+ const resource = resources[arg];
70319
+ if (!resource) {
70320
+ return {
70321
+ kind: "unresolved",
70322
+ reason: `Ref '${arg}': no record in cdkd state (was the resource deployed?)`
70323
+ };
70324
+ }
70325
+ return { kind: "literal", value: resource.physicalId };
70326
+ }
70327
+ function resolveGetAtt(arg, resources) {
70328
+ let logicalId;
70329
+ let attr;
70330
+ if (Array.isArray(arg) && arg.length === 2 && typeof arg[0] === "string") {
70331
+ logicalId = arg[0];
70332
+ if (typeof arg[1] !== "string") {
70333
+ return {
70334
+ kind: "unresolved",
70335
+ reason: `Fn::GetAtt's second arg must be a string attribute name, got ${typeof arg[1]} (nested intrinsics in attribute names are not supported in --from-state v1)`
70336
+ };
70337
+ }
70338
+ attr = arg[1];
70339
+ } else if (typeof arg === "string") {
70340
+ const dot = arg.indexOf(".");
70341
+ if (dot <= 0 || dot === arg.length - 1) {
70342
+ return {
70343
+ kind: "unresolved",
70344
+ reason: `Fn::GetAtt string form must be '<LogicalId>.<Attribute>', got '${arg}'`
70345
+ };
70346
+ }
70347
+ logicalId = arg.slice(0, dot);
70348
+ attr = arg.slice(dot + 1);
70349
+ } else {
70350
+ return {
70351
+ kind: "unresolved",
70352
+ reason: `Fn::GetAtt expects [LogicalId, Attribute] or 'LogicalId.Attribute', got ${Array.isArray(arg) ? `array of length ${arg.length}` : typeof arg}`
70353
+ };
70354
+ }
70355
+ const resource = resources[logicalId];
70356
+ if (!resource) {
70357
+ return {
70358
+ kind: "unresolved",
70359
+ reason: `Fn::GetAtt '${logicalId}.${attr}': no record in cdkd state`
70360
+ };
70361
+ }
70362
+ const cached = resource.attributes?.[attr];
70363
+ if (cached === void 0) {
70364
+ return {
70365
+ kind: "unresolved",
70366
+ reason: `Fn::GetAtt '${logicalId}.${attr}': attribute not captured in cdkd state at deploy time`
70367
+ };
70368
+ }
70369
+ if (typeof cached === "string" || typeof cached === "number" || typeof cached === "boolean") {
70370
+ return { kind: "literal", value: cached };
70371
+ }
70372
+ return { kind: "literal", value: JSON.stringify(cached) };
70373
+ }
70374
+ function resolveSub(arg, resources) {
70375
+ let template;
70376
+ let bindings = {};
70377
+ if (typeof arg === "string") {
70378
+ template = arg;
70379
+ } else if (Array.isArray(arg) && arg.length === 2 && typeof arg[0] === "string" && arg[1] !== null && typeof arg[1] === "object" && !Array.isArray(arg[1])) {
70380
+ template = arg[0];
70381
+ bindings = arg[1];
70382
+ } else {
70383
+ return {
70384
+ kind: "unresolved",
70385
+ reason: `Fn::Sub expects a string or [string, object], got ${Array.isArray(arg) ? "malformed array" : typeof arg}`
70386
+ };
70387
+ }
70388
+ const placeholderRegex = /\$\{([^}]+)\}/g;
70389
+ const placeholders = [];
70390
+ template.replace(placeholderRegex, (_, key) => {
70391
+ placeholders.push(key);
70392
+ return "";
70393
+ });
70394
+ const resolutions = /* @__PURE__ */ new Map();
70395
+ for (const placeholder of placeholders) {
70396
+ if (resolutions.has(placeholder))
70397
+ continue;
70398
+ if (placeholder in bindings) {
70399
+ const sub = substituteAgainstState(bindings[placeholder], resources);
70400
+ if (sub.kind !== "literal") {
70401
+ return {
70402
+ kind: "unresolved",
70403
+ reason: `Fn::Sub placeholder '\${${placeholder}}': ${sub.reason}`
70404
+ };
70405
+ }
70406
+ resolutions.set(placeholder, String(sub.value));
70407
+ continue;
70408
+ }
70409
+ const dot = placeholder.indexOf(".");
70410
+ if (dot === -1) {
70411
+ const sub = resolveRef(placeholder, resources);
70412
+ if (sub.kind !== "literal") {
70413
+ return {
70414
+ kind: "unresolved",
70415
+ reason: `Fn::Sub placeholder '\${${placeholder}}': ${sub.reason}`
70416
+ };
70417
+ }
70418
+ resolutions.set(placeholder, String(sub.value));
70419
+ } else {
70420
+ const sub = resolveGetAtt(placeholder, resources);
70421
+ if (sub.kind !== "literal") {
70422
+ return {
70423
+ kind: "unresolved",
70424
+ reason: `Fn::Sub placeholder '\${${placeholder}}': ${sub.reason}`
70425
+ };
70426
+ }
70427
+ resolutions.set(placeholder, String(sub.value));
70428
+ }
70429
+ }
70430
+ const out = template.replace(placeholderRegex, (_, key) => {
70431
+ return resolutions.get(key) ?? "";
70432
+ });
70433
+ return { kind: "literal", value: out };
70434
+ }
70435
+ function substituteEnvVarsFromState(templateEnv, resources) {
70436
+ const env = {};
70437
+ const audit = { resolvedKeys: [], unresolved: [] };
70438
+ if (!templateEnv)
70439
+ return { env, audit };
70440
+ for (const [key, value] of Object.entries(templateEnv)) {
70441
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
70442
+ env[key] = value;
70443
+ continue;
70444
+ }
70445
+ const result = substituteAgainstState(value, resources);
70446
+ if (result.kind === "literal") {
70447
+ env[key] = result.value;
70448
+ audit.resolvedKeys.push(key);
70449
+ } else {
70450
+ audit.unresolved.push({ key, reason: result.reason });
70451
+ }
70452
+ }
70453
+ return { env, audit };
70454
+ }
70455
+
70456
+ // src/local/runtime-image.ts
70181
70457
  var SUPPORTED_RUNTIMES = {
70182
70458
  "nodejs18.x": { image: "public.ecr.aws/lambda/nodejs:18", fileExtension: ".js" },
70183
70459
  "nodejs20.x": { image: "public.ecr.aws/lambda/nodejs:20", fileExtension: ".js" },
@@ -70204,7 +70480,7 @@ function resolveRuntimeSpec(runtime) {
70204
70480
  if (typeof runtime !== "string" || runtime.length === 0) {
70205
70481
  throw new UnsupportedRuntimeError(
70206
70482
  String(runtime),
70207
- "Lambda function has no Runtime property. Container-image Lambdas (Code.ImageUri) are not supported in cdkd local invoke v1."
70483
+ "Lambda function has no Runtime property. This branch is only reached for ZIP Lambdas; container-image Lambdas (Code.ImageUri) take a different code path that does not consult the Runtime property."
70208
70484
  );
70209
70485
  }
70210
70486
  const spec = SUPPORTED_RUNTIMES[runtime];
@@ -70222,11 +70498,11 @@ function resolveRuntimeSpec(runtime) {
70222
70498
  );
70223
70499
  }
70224
70500
 
70225
- // src/local-invoke/docker-runner.ts
70226
- import { execFile as execFile2, spawn as spawn3 } from "node:child_process";
70501
+ // src/local/docker-runner.ts
70502
+ import { execFile as execFile3, spawn as spawn3 } from "node:child_process";
70227
70503
  import { createServer } from "node:net";
70228
- import { promisify as promisify2 } from "node:util";
70229
- var execFileAsync2 = promisify2(execFile2);
70504
+ import { promisify as promisify3 } from "node:util";
70505
+ var execFileAsync3 = promisify3(execFile3);
70230
70506
  var DockerRunnerError = class _DockerRunnerError extends Error {
70231
70507
  constructor(message) {
70232
70508
  super(message);
@@ -70245,6 +70521,12 @@ async function pullImage(image, skipPull) {
70245
70521
  }
70246
70522
  async function runDetached(opts) {
70247
70523
  const args = ["run", "-d", "--rm"];
70524
+ if (opts.name) {
70525
+ args.push("--name", opts.name);
70526
+ }
70527
+ if (opts.platform) {
70528
+ args.push("--platform", opts.platform);
70529
+ }
70248
70530
  const host = opts.host ?? "127.0.0.1";
70249
70531
  args.push("-p", `${host}:${opts.hostPort}:8080`);
70250
70532
  if (opts.debugPort !== void 0) {
@@ -70257,11 +70539,19 @@ async function runDetached(opts) {
70257
70539
  for (const [k, v] of Object.entries(opts.env)) {
70258
70540
  args.push("-e", `${k}=${v}`);
70259
70541
  }
70260
- args.push(opts.image, ...opts.cmd);
70542
+ if (opts.workingDir) {
70543
+ args.push("--workdir", opts.workingDir);
70544
+ }
70545
+ let entryPointTail = [];
70546
+ if (opts.entryPoint && opts.entryPoint.length > 0) {
70547
+ args.push("--entrypoint", opts.entryPoint[0]);
70548
+ entryPointTail = opts.entryPoint.slice(1);
70549
+ }
70550
+ args.push(opts.image, ...entryPointTail, ...opts.cmd);
70261
70551
  const logger = getLogger().child("docker");
70262
- logger.debug(`docker ${args.join(" ")}`);
70552
+ logger.debug(`docker ${redactAwsCredentialsInArgs(args).join(" ")}`);
70263
70553
  try {
70264
- const { stdout } = await execFileAsync2("docker", args, {
70554
+ const { stdout } = await execFileAsync3("docker", args, {
70265
70555
  maxBuffer: 10 * 1024 * 1024
70266
70556
  });
70267
70557
  return stdout.trim();
@@ -70290,7 +70580,7 @@ async function removeContainer(containerId) {
70290
70580
  return;
70291
70581
  const logger = getLogger().child("docker");
70292
70582
  try {
70293
- await execFileAsync2("docker", ["rm", "-f", containerId]);
70583
+ await execFileAsync3("docker", ["rm", "-f", containerId]);
70294
70584
  logger.debug(`Removed container ${containerId}`);
70295
70585
  } catch (error) {
70296
70586
  const err = error;
@@ -70301,7 +70591,7 @@ async function removeContainer(containerId) {
70301
70591
  }
70302
70592
  async function ensureDockerAvailable() {
70303
70593
  try {
70304
- await execFileAsync2("docker", ["version", "--format", "{{.Server.Version}}"]);
70594
+ await execFileAsync3("docker", ["version", "--format", "{{.Server.Version}}"]);
70305
70595
  } catch (error) {
70306
70596
  const err = error;
70307
70597
  if (err.code === "ENOENT") {
@@ -70331,6 +70621,31 @@ function pickFreePort() {
70331
70621
  });
70332
70622
  });
70333
70623
  }
70624
+ var REDACTED_ENV_KEYS = /* @__PURE__ */ new Set([
70625
+ "AWS_ACCESS_KEY_ID",
70626
+ "AWS_SECRET_ACCESS_KEY",
70627
+ "AWS_SESSION_TOKEN"
70628
+ ]);
70629
+ function redactAwsCredentialsInArgs(args) {
70630
+ const out = [];
70631
+ for (let i = 0; i < args.length; i++) {
70632
+ const cur = args[i];
70633
+ const next = args[i + 1];
70634
+ if (cur === "-e" && typeof next === "string") {
70635
+ const eqIdx = next.indexOf("=");
70636
+ if (eqIdx > 0) {
70637
+ const key = next.substring(0, eqIdx);
70638
+ if (REDACTED_ENV_KEYS.has(key)) {
70639
+ out.push("-e", `${key}=***`);
70640
+ i++;
70641
+ continue;
70642
+ }
70643
+ }
70644
+ }
70645
+ out.push(cur);
70646
+ }
70647
+ return out;
70648
+ }
70334
70649
  function runForeground(cmd, args) {
70335
70650
  return new Promise((resolveProc, rejectProc) => {
70336
70651
  const proc = spawn3(cmd, args, { stdio: "inherit" });
@@ -70344,7 +70659,164 @@ function runForeground(cmd, args) {
70344
70659
  });
70345
70660
  }
70346
70661
 
70347
- // src/local-invoke/rie-client.ts
70662
+ // src/local/docker-image-builder.ts
70663
+ import { createHash as createHash2 } from "node:crypto";
70664
+ async function buildContainerImage(asset, cdkOutDir, options) {
70665
+ const tag = computeLocalTag(asset.source);
70666
+ const platform = architectureToPlatform(options.architecture);
70667
+ const logger = getLogger().child("local-invoke-build");
70668
+ logger.info(`Building container image (platform=${platform})...`);
70669
+ logger.debug(`Local tag: ${tag}`);
70670
+ await buildDockerImage(asset, cdkOutDir, tag, {
70671
+ platform,
70672
+ wrapError: (stderr) => new LocalInvokeBuildError(
70673
+ `docker build failed for container Lambda asset (${asset.source.directory}): ${stderr}`
70674
+ )
70675
+ });
70676
+ return tag;
70677
+ }
70678
+ function architectureToPlatform(architecture) {
70679
+ return architecture === "arm64" ? "linux/arm64" : "linux/amd64";
70680
+ }
70681
+ function computeLocalTag(source) {
70682
+ const hash = createHash2("sha256");
70683
+ hash.update(source.directory);
70684
+ hash.update("\0");
70685
+ hash.update(source.dockerFile ?? "");
70686
+ hash.update("\0");
70687
+ hash.update(source.dockerBuildTarget ?? "");
70688
+ hash.update("\0");
70689
+ if (source.dockerBuildArgs) {
70690
+ for (const [k, v] of Object.entries(source.dockerBuildArgs)) {
70691
+ hash.update(k);
70692
+ hash.update("=");
70693
+ hash.update(v);
70694
+ hash.update("\0");
70695
+ }
70696
+ }
70697
+ return `cdkd-local-invoke-${hash.digest("hex").slice(0, 16)}`;
70698
+ }
70699
+
70700
+ // src/local/ecr-puller.ts
70701
+ import { execFile as execFile4, spawn as spawn4 } from "node:child_process";
70702
+ import { promisify as promisify4 } from "node:util";
70703
+ import { ECRClient as ECRClient3, GetAuthorizationTokenCommand as GetAuthorizationTokenCommand2 } from "@aws-sdk/client-ecr";
70704
+ import { GetCallerIdentityCommand as GetCallerIdentityCommand11, STSClient as STSClient10 } from "@aws-sdk/client-sts";
70705
+ var execFileAsync4 = promisify4(execFile4);
70706
+ var ECR_URI_REGEX = /^(\d{12})\.dkr\.ecr\.([^.]+)\.amazonaws\.com(?:\.cn)?\/([^:]+):(.+)$/;
70707
+ function parseEcrUri(imageUri) {
70708
+ const m = ECR_URI_REGEX.exec(imageUri);
70709
+ if (!m)
70710
+ return void 0;
70711
+ return {
70712
+ accountId: m[1],
70713
+ region: m[2],
70714
+ repository: m[3],
70715
+ tag: m[4]
70716
+ };
70717
+ }
70718
+ async function pullEcrImage(imageUri, options) {
70719
+ const logger = getLogger().child("ecr-puller");
70720
+ const parsed = parseEcrUri(imageUri);
70721
+ if (!parsed) {
70722
+ throw new LocalInvokeBuildError(
70723
+ `Image URI '${imageUri}' is not an ECR URI. cdkd local invoke v1 only authenticates against ECR for the deployed-image fallback path.`
70724
+ );
70725
+ }
70726
+ const sts = new STSClient10({ region: parsed.region });
70727
+ let callerAccount;
70728
+ try {
70729
+ const identity = await sts.send(new GetCallerIdentityCommand11({}));
70730
+ if (!identity.Account) {
70731
+ throw new LocalInvokeBuildError(
70732
+ "STS GetCallerIdentity returned no Account. Verify your AWS credentials."
70733
+ );
70734
+ }
70735
+ callerAccount = identity.Account;
70736
+ } finally {
70737
+ sts.destroy();
70738
+ }
70739
+ if (callerAccount !== parsed.accountId) {
70740
+ throw new LocalInvokeBuildError(
70741
+ `Image URI '${imageUri}' is in account ${parsed.accountId}, but the caller is ${callerAccount}. Cross-account ECR pull is not supported in cdkd local invoke v1 \u2014 deferred to a follow-up PR. Workaround: assume a role in the target account before invoking, or build the image locally with \`cdkd local invoke -a cdk.out\` (no ECR pull).`
70742
+ );
70743
+ }
70744
+ const callerRegion = options.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"];
70745
+ if (callerRegion && callerRegion !== parsed.region) {
70746
+ throw new LocalInvokeBuildError(
70747
+ `Image URI '${imageUri}' is in region ${parsed.region}, but the caller's region is ${callerRegion}. Cross-region ECR pull is not supported in cdkd local invoke v1 \u2014 deferred to a follow-up PR. Workaround: re-run with AWS_REGION=${parsed.region} set, or build the image locally with -a cdk.out.`
70748
+ );
70749
+ }
70750
+ if (options.skipPull) {
70751
+ logger.info(`Skipping ECR pull (--no-pull). Verifying ${imageUri} is in local cache...`);
70752
+ await verifyImageInLocalCache(imageUri);
70753
+ return imageUri;
70754
+ }
70755
+ const ecr = new ECRClient3({ region: parsed.region });
70756
+ try {
70757
+ await ecrLogin(ecr, parsed.accountId, parsed.region);
70758
+ } finally {
70759
+ ecr.destroy();
70760
+ }
70761
+ logger.info(`Pulling ${imageUri}...`);
70762
+ await runForeground2("docker", ["pull", imageUri]);
70763
+ return imageUri;
70764
+ }
70765
+ async function ecrLogin(client, accountId, region) {
70766
+ const logger = getLogger().child("ecr-puller");
70767
+ logger.debug(`ECR login (account=${accountId}, region=${region})`);
70768
+ const response = await client.send(new GetAuthorizationTokenCommand2({}));
70769
+ const authData = response.authorizationData?.[0];
70770
+ if (!authData?.authorizationToken) {
70771
+ throw new LocalInvokeBuildError("Failed to get ECR authorization token");
70772
+ }
70773
+ const token = Buffer.from(authData.authorizationToken, "base64").toString();
70774
+ const [username, password] = token.split(":");
70775
+ const endpoint = authData.proxyEndpoint || `https://${accountId}.dkr.ecr.${region}.amazonaws.com`;
70776
+ await new Promise((resolve5, reject) => {
70777
+ const proc = spawn4("docker", ["login", "--username", username, "--password-stdin", endpoint], {
70778
+ stdio: ["pipe", "pipe", "pipe"]
70779
+ });
70780
+ let stderr = "";
70781
+ proc.stderr?.on("data", (data) => {
70782
+ stderr += data.toString();
70783
+ });
70784
+ proc.on("close", (code) => {
70785
+ if (code === 0)
70786
+ resolve5();
70787
+ else
70788
+ reject(new LocalInvokeBuildError(`ECR login failed: ${stderr.trim()}`));
70789
+ });
70790
+ proc.on("error", (err) => {
70791
+ reject(new LocalInvokeBuildError(`ECR login failed: ${err.message}`));
70792
+ });
70793
+ proc.stdin?.write(password);
70794
+ proc.stdin?.end();
70795
+ });
70796
+ }
70797
+ async function verifyImageInLocalCache(imageUri) {
70798
+ try {
70799
+ await execFileAsync4("docker", ["image", "inspect", imageUri]);
70800
+ } catch {
70801
+ throw new LocalInvokeBuildError(
70802
+ `Image '${imageUri}' is not in the local docker cache and --no-pull was set. Either remove --no-pull (cdkd will pull from ECR) or pre-pull the image manually with \`docker pull\`.`
70803
+ );
70804
+ }
70805
+ }
70806
+ function runForeground2(cmd, args) {
70807
+ return new Promise((resolve5, reject) => {
70808
+ const proc = spawn4(cmd, args, { stdio: "inherit" });
70809
+ proc.on("error", (err) => reject(new LocalInvokeBuildError(`${cmd} failed: ${err.message}`)));
70810
+ proc.on("close", (code) => {
70811
+ if (code === 0)
70812
+ resolve5();
70813
+ else
70814
+ reject(new LocalInvokeBuildError(`${cmd} exited with code ${code}`));
70815
+ });
70816
+ });
70817
+ }
70818
+
70819
+ // src/local/rie-client.ts
70348
70820
  import { setTimeout as delay } from "node:timers/promises";
70349
70821
  var INVOKE_PATH = "/2015-03-31/functions/function/invocations";
70350
70822
  async function waitForRieReady(host, port, timeoutMs = 5e3) {
@@ -70353,8 +70825,10 @@ async function waitForRieReady(host, port, timeoutMs = 5e3) {
70353
70825
  while (Date.now() < deadline) {
70354
70826
  try {
70355
70827
  const ok = await httpProbe(host, port, 500);
70356
- if (ok)
70828
+ if (ok) {
70829
+ await delay(250);
70357
70830
  return;
70831
+ }
70358
70832
  } catch (err) {
70359
70833
  lastError = err;
70360
70834
  }
@@ -70408,12 +70882,7 @@ async function invokeRie(host, port, event, timeoutMs) {
70408
70882
  const timer = setTimeout(() => controller.abort(), timeoutMs);
70409
70883
  let response;
70410
70884
  try {
70411
- response = await fetch(url, {
70412
- method: "POST",
70413
- headers: { "Content-Type": "application/json" },
70414
- body,
70415
- signal: controller.signal
70416
- });
70885
+ response = await fetchWithStartupRetry(url, body, controller.signal);
70417
70886
  } catch (err) {
70418
70887
  if (err.name === "AbortError") {
70419
70888
  throw new Error(
@@ -70432,8 +70901,130 @@ async function invokeRie(host, port, event, timeoutMs) {
70432
70901
  }
70433
70902
  return { payload, raw };
70434
70903
  }
70904
+ async function fetchWithStartupRetry(url, body, signal) {
70905
+ const maxAttempts = 3;
70906
+ let lastError;
70907
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
70908
+ try {
70909
+ return await fetch(url, {
70910
+ method: "POST",
70911
+ headers: { "Content-Type": "application/json" },
70912
+ body,
70913
+ signal
70914
+ });
70915
+ } catch (err) {
70916
+ const name = err.name;
70917
+ if (name === "AbortError")
70918
+ throw err;
70919
+ lastError = err;
70920
+ if (attempt === maxAttempts)
70921
+ break;
70922
+ await delay(200);
70923
+ }
70924
+ }
70925
+ throw lastError;
70926
+ }
70927
+
70928
+ // src/assets/asset-manifest-loader.ts
70929
+ import { readFile } from "fs/promises";
70930
+ import { join as join6 } from "path";
70931
+ var AssetManifestLoader = class {
70932
+ logger = getLogger().child("AssetManifestLoader");
70933
+ /**
70934
+ * Load asset manifest from CDK output directory
70935
+ *
70936
+ * @param cdkOutputDir CDK output directory (e.g., "cdk.out")
70937
+ * @param stackName Stack name
70938
+ * @returns Asset manifest or null if not found
70939
+ */
70940
+ async loadManifest(cdkOutputDir, stackName) {
70941
+ const manifestPath = join6(cdkOutputDir, `${stackName}.assets.json`);
70942
+ try {
70943
+ this.logger.debug(`Loading asset manifest from: ${manifestPath}`);
70944
+ const content = await readFile(manifestPath, "utf-8");
70945
+ const manifest = JSON.parse(content);
70946
+ this.logger.debug(
70947
+ `Loaded asset manifest: ${Object.keys(manifest.files).length} file assets, ${Object.keys(manifest.dockerImages).length} docker image assets`
70948
+ );
70949
+ return manifest;
70950
+ } catch (error) {
70951
+ if (error.code === "ENOENT") {
70952
+ this.logger.debug(`Asset manifest not found: ${manifestPath}`);
70953
+ return null;
70954
+ }
70955
+ throw new Error(
70956
+ `Failed to load asset manifest from ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`
70957
+ );
70958
+ }
70959
+ }
70960
+ /**
70961
+ * Get file assets from manifest (excludes CloudFormation templates)
70962
+ *
70963
+ * @param manifest Asset manifest
70964
+ * @returns Map of asset hash to file asset
70965
+ */
70966
+ getFileAssets(manifest) {
70967
+ const fileAssets = /* @__PURE__ */ new Map();
70968
+ for (const [assetHash, asset] of Object.entries(manifest.files)) {
70969
+ if (asset.source.path.endsWith(".json") || asset.source.path.endsWith(".template.json")) {
70970
+ this.logger.debug(`Skipping CloudFormation template asset: ${asset.displayName}`);
70971
+ continue;
70972
+ }
70973
+ fileAssets.set(assetHash, asset);
70974
+ }
70975
+ this.logger.debug(`Found ${fileAssets.size} file assets (excluding templates)`);
70976
+ return fileAssets;
70977
+ }
70978
+ /**
70979
+ * Get asset source path (absolute path)
70980
+ *
70981
+ * @param cdkOutputDir CDK output directory
70982
+ * @param asset File asset
70983
+ * @returns Absolute path to asset source
70984
+ */
70985
+ getAssetSourcePath(cdkOutputDir, asset) {
70986
+ return join6(cdkOutputDir, asset.source.path);
70987
+ }
70988
+ /**
70989
+ * Resolve asset destination values (replace ${AWS::AccountId}, ${AWS::Region}, etc.)
70990
+ *
70991
+ * @param value Value with placeholders
70992
+ * @param accountId AWS account ID
70993
+ * @param region AWS region
70994
+ * @param partition AWS partition (default: "aws")
70995
+ * @returns Resolved value
70996
+ */
70997
+ resolveAssetDestinationValue(value, accountId, region, partition = "aws") {
70998
+ return value.replace(/\$\{AWS::AccountId\}/g, accountId).replace(/\$\{AWS::Region\}/g, region).replace(/\$\{AWS::Partition\}/g, partition);
70999
+ }
71000
+ };
71001
+ function getDockerImageBySourceHash(manifest, imageUri) {
71002
+ const dockerImages = manifest.dockerImages ?? {};
71003
+ const entries = Object.entries(dockerImages);
71004
+ if (entries.length === 0)
71005
+ return void 0;
71006
+ const hash = extractHashFromImageUri(imageUri);
71007
+ if (hash !== void 0) {
71008
+ const asset = dockerImages[hash];
71009
+ if (asset) {
71010
+ return { hash, asset };
71011
+ }
71012
+ }
71013
+ if (entries.length === 1) {
71014
+ const [singleHash, singleAsset] = entries[0];
71015
+ return { hash: singleHash, asset: singleAsset };
71016
+ }
71017
+ return void 0;
71018
+ }
71019
+ function extractHashFromImageUri(imageUri) {
71020
+ if (imageUri.includes("@sha256:"))
71021
+ return void 0;
71022
+ const match = /:([a-f0-9]{8,})$/.exec(imageUri);
71023
+ return match?.[1];
71024
+ }
70435
71025
 
70436
71026
  // src/cli/commands/local-invoke.ts
71027
+ init_aws_clients();
70437
71028
  async function localInvokeCommand(target, options) {
70438
71029
  const logger = getLogger();
70439
71030
  if (options.verbose) {
@@ -70458,21 +71049,48 @@ async function localInvokeCommand(target, options) {
70458
71049
  };
70459
71050
  const { stacks } = await synthesizer.synthesize(synthOpts);
70460
71051
  const lambda = resolveLambdaTarget(target, stacks);
70461
- logger.info(`Target: ${lambda.stack.stackName}/${lambda.logicalId} (${lambda.runtime})`);
70462
- const codeDir = lambda.codePath ?? materializeInlineCode(
70463
- lambda.handler,
70464
- lambda.inlineCode ?? "",
70465
- resolveRuntimeFileExtension(lambda.runtime)
70466
- );
71052
+ const targetLabel = lambda.kind === "zip" ? lambda.runtime : "container image";
71053
+ logger.info(`Target: ${lambda.stack.stackName}/${lambda.logicalId} (${targetLabel})`);
71054
+ const imagePlan = await resolveImagePlan(lambda, options);
71055
+ let stateAudit;
71056
+ let templateEnv = getTemplateEnv(lambda.resource);
71057
+ let stateForRoleHint;
71058
+ if (options.fromState) {
71059
+ const loaded = await loadStateForStack(lambda.stack.stackName, lambda.stack.region, {
71060
+ ...options.stackRegion !== void 0 && { stackRegion: options.stackRegion },
71061
+ ...options.stateBucket !== void 0 && { stateBucket: options.stateBucket },
71062
+ statePrefix: options.statePrefix,
71063
+ ...options.region !== void 0 && { region: options.region },
71064
+ ...options.profile !== void 0 && { profile: options.profile }
71065
+ });
71066
+ if (loaded) {
71067
+ stateForRoleHint = loaded.state;
71068
+ const { env, audit } = substituteEnvVarsFromState(templateEnv, loaded.state.resources);
71069
+ templateEnv = env;
71070
+ stateAudit = audit;
71071
+ for (const key of audit.resolvedKeys) {
71072
+ logger.debug(`--from-state: substituted env var ${key} from cdkd state`);
71073
+ }
71074
+ for (const { key, reason } of audit.unresolved) {
71075
+ logger.warn(
71076
+ `--from-state: could not substitute env var ${key} (${reason}). Override it via --env-vars or it will be dropped.`
71077
+ );
71078
+ }
71079
+ }
71080
+ }
70467
71081
  const overrides = readEnvOverridesFile(options.envVars);
70468
- const envResult = resolveEnvVars(lambda.logicalId, getTemplateEnv(lambda.resource), overrides);
71082
+ const envResult = resolveEnvVars(lambda.logicalId, templateEnv, overrides);
70469
71083
  for (const key of envResult.unresolved) {
71084
+ if (stateAudit && stateAudit.unresolved.some((u) => u.key === key))
71085
+ continue;
70470
71086
  logger.warn(
70471
- `Environment variable ${key} contains a CloudFormation intrinsic and was dropped. Override it with --env-vars (e.g. {"${lambda.logicalId}":{"${key}":"<literal>"}}) or wait for --from-state in PR 2.`
71087
+ `Environment variable ${key} contains a CloudFormation intrinsic and was dropped. Override it with --env-vars (e.g. {"${lambda.logicalId}":{"${key}":"<literal>"}}) or pass --from-state to recover deployed values.`
70472
71088
  );
70473
71089
  }
71090
+ if (options.fromState && !options.assumeRole && stateForRoleHint) {
71091
+ suggestAssumeRoleFromState(stateForRoleHint, lambda.logicalId);
71092
+ }
70474
71093
  const event = await readEvent(options);
70475
- const image = resolveRuntimeImage(lambda.runtime);
70476
71094
  const dockerEnv = {
70477
71095
  AWS_LAMBDA_FUNCTION_NAME: lambda.logicalId,
70478
71096
  AWS_LAMBDA_FUNCTION_MEMORY_SIZE: String(lambda.memoryMb),
@@ -70500,19 +71118,26 @@ async function localInvokeCommand(target, options) {
70500
71118
  throw new Error(`--debug-port must be an integer in 1..65535, got '${options.debugPort}'`);
70501
71119
  }
70502
71120
  dockerEnv["NODE_OPTIONS"] = `--inspect-brk=0.0.0.0:${debugPort}`;
71121
+ if (lambda.kind === "image") {
71122
+ logger.warn(
71123
+ "--debug-port sets NODE_OPTIONS unconditionally on container Lambdas. If the image's runtime is not Node.js, this flag is a no-op."
71124
+ );
71125
+ }
70503
71126
  }
70504
- await pullImage(image, options.pull === false);
70505
71127
  const hostPort = await pickFreePort();
70506
- const containerHost = options.containerHost || "127.0.0.1";
70507
- logger.info(`Starting container (image=${image}, port=${hostPort})...`);
71128
+ const containerHost = options.containerHost;
71129
+ logger.info(`Starting container (image=${imagePlan.image}, port=${hostPort})...`);
70508
71130
  const containerId = await runDetached({
70509
- image,
70510
- mounts: [{ hostPath: codeDir, containerPath: "/var/task", readOnly: true }],
71131
+ image: imagePlan.image,
71132
+ mounts: imagePlan.mounts,
70511
71133
  env: dockerEnv,
70512
- cmd: [lambda.handler],
71134
+ cmd: imagePlan.cmd,
70513
71135
  hostPort,
70514
71136
  host: containerHost,
70515
- ...debugPort !== void 0 && { debugPort }
71137
+ ...debugPort !== void 0 && { debugPort },
71138
+ ...imagePlan.platform !== void 0 && { platform: imagePlan.platform },
71139
+ ...imagePlan.entryPoint !== void 0 && { entryPoint: imagePlan.entryPoint },
71140
+ ...imagePlan.workingDir !== void 0 && { workingDir: imagePlan.workingDir }
70516
71141
  });
70517
71142
  const stopLogs = streamLogs(containerId);
70518
71143
  const sigintHandler = () => {
@@ -70533,7 +71158,92 @@ async function localInvokeCommand(target, options) {
70533
71158
  process.off("SIGINT", sigintHandler);
70534
71159
  stopLogs();
70535
71160
  await removeContainer(containerId);
71161
+ if (imagePlan.inlineTmpDir) {
71162
+ try {
71163
+ rmSync2(imagePlan.inlineTmpDir, { recursive: true, force: true });
71164
+ } catch (err) {
71165
+ getLogger().debug(
71166
+ `Failed to remove inline-code tmpdir ${imagePlan.inlineTmpDir}: ${err instanceof Error ? err.message : String(err)}`
71167
+ );
71168
+ }
71169
+ }
71170
+ }
71171
+ }
71172
+ async function resolveImagePlan(lambda, options) {
71173
+ if (lambda.kind === "zip") {
71174
+ return resolveZipImagePlan(lambda, options);
71175
+ }
71176
+ return resolveContainerImagePlan(lambda, options);
71177
+ }
71178
+ async function resolveZipImagePlan(lambda, options) {
71179
+ let inlineTmpDir;
71180
+ let codeDir = lambda.codePath;
71181
+ if (codeDir === null) {
71182
+ inlineTmpDir = materializeInlineCode(
71183
+ lambda.handler,
71184
+ lambda.inlineCode ?? "",
71185
+ resolveRuntimeFileExtension(lambda.runtime)
71186
+ );
71187
+ codeDir = inlineTmpDir;
70536
71188
  }
71189
+ const image = resolveRuntimeImage(lambda.runtime);
71190
+ await pullImage(image, options.pull === false);
71191
+ return {
71192
+ image,
71193
+ mounts: [{ hostPath: codeDir, containerPath: "/var/task", readOnly: true }],
71194
+ cmd: [lambda.handler],
71195
+ ...inlineTmpDir !== void 0 && { inlineTmpDir }
71196
+ };
71197
+ }
71198
+ async function resolveContainerImagePlan(lambda, options) {
71199
+ const logger = getLogger();
71200
+ const platform = architectureToPlatform(lambda.architecture);
71201
+ const localBuild = await resolveLocalBuildPlan(lambda);
71202
+ let imageRef;
71203
+ if (localBuild) {
71204
+ imageRef = await buildContainerImage(localBuild.asset, localBuild.cdkOutDir, {
71205
+ architecture: lambda.architecture
71206
+ });
71207
+ } else {
71208
+ if (!parseEcrUri(lambda.imageUri)) {
71209
+ throw new Error(
71210
+ `Container Lambda '${lambda.logicalId}' has no matching asset in cdk.out, and Code.ImageUri '${lambda.imageUri}' is not an ECR URI cdkd can authenticate against. Re-synthesize the CDK app (so cdk.out includes the build context) or deploy the image to ECR first.`
71211
+ );
71212
+ }
71213
+ logger.info(
71214
+ `No matching cdk.out asset for ${lambda.imageUri}; falling back to ECR pull (same-acct/region only)...`
71215
+ );
71216
+ imageRef = await pullEcrImage(lambda.imageUri, {
71217
+ skipPull: options.pull === false,
71218
+ ...options.region !== void 0 && { region: options.region }
71219
+ });
71220
+ }
71221
+ return {
71222
+ image: imageRef,
71223
+ mounts: [],
71224
+ cmd: lambda.imageConfig.command ?? [],
71225
+ platform,
71226
+ ...lambda.imageConfig.entryPoint && lambda.imageConfig.entryPoint.length > 0 && {
71227
+ entryPoint: lambda.imageConfig.entryPoint
71228
+ },
71229
+ ...lambda.imageConfig.workingDirectory !== void 0 && {
71230
+ workingDir: lambda.imageConfig.workingDirectory
71231
+ }
71232
+ };
71233
+ }
71234
+ async function resolveLocalBuildPlan(lambda) {
71235
+ const manifestPath = lambda.stack.assetManifestPath;
71236
+ if (!manifestPath)
71237
+ return void 0;
71238
+ const cdkOutDir = dirname2(manifestPath);
71239
+ const loader = new AssetManifestLoader();
71240
+ const manifest = await loader.loadManifest(cdkOutDir, lambda.stack.stackName);
71241
+ if (!manifest)
71242
+ return void 0;
71243
+ const entry = getDockerImageBySourceHash(manifest, lambda.imageUri);
71244
+ if (!entry)
71245
+ return void 0;
71246
+ return { asset: entry.asset, cdkOutDir };
70537
71247
  }
70538
71248
  function getTemplateEnv(resource) {
70539
71249
  const props = resource.Properties ?? {};
@@ -70600,8 +71310,8 @@ async function readStdin() {
70600
71310
  return Buffer.concat(chunks).toString("utf-8");
70601
71311
  }
70602
71312
  async function assumeLambdaExecutionRole(roleArn, region) {
70603
- const { STSClient: STSClient10, AssumeRoleCommand: AssumeRoleCommand2 } = await import("@aws-sdk/client-sts");
70604
- const sts = new STSClient10({ ...region && { region } });
71313
+ const { STSClient: STSClient11, AssumeRoleCommand: AssumeRoleCommand2 } = await import("@aws-sdk/client-sts");
71314
+ const sts = new STSClient11({ ...region && { region } });
70605
71315
  try {
70606
71316
  const response = await sts.send(
70607
71317
  new AssumeRoleCommand2({
@@ -70649,6 +71359,109 @@ function materializeInlineCode(handler, source, fileExtension) {
70649
71359
  writeFileSync5(filePath, source, "utf-8");
70650
71360
  return dir;
70651
71361
  }
71362
+ async function loadStateForStack(stackName, synthRegion, opts) {
71363
+ const logger = getLogger();
71364
+ const region = opts.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"] ?? synthRegion ?? "us-east-1";
71365
+ let stateBucket;
71366
+ try {
71367
+ stateBucket = await resolveStateBucketWithDefault(opts.stateBucket, region);
71368
+ } catch (err) {
71369
+ logger.warn(
71370
+ `--from-state: could not resolve state bucket: ${err instanceof Error ? err.message : String(err)}. Falling back to PR 1 warn-and-drop semantics.`
71371
+ );
71372
+ return void 0;
71373
+ }
71374
+ const awsClients = new AwsClients({
71375
+ ...opts.region !== void 0 && { region: opts.region },
71376
+ ...opts.profile !== void 0 && { profile: opts.profile }
71377
+ });
71378
+ setAwsClients(awsClients);
71379
+ try {
71380
+ const stateConfig = { bucket: stateBucket, prefix: opts.statePrefix };
71381
+ const stateBackend = new S3StateBackend(awsClients.s3, stateConfig, {
71382
+ ...opts.region !== void 0 && { region: opts.region },
71383
+ ...opts.profile !== void 0 && { profile: opts.profile }
71384
+ });
71385
+ await stateBackend.verifyBucketExists();
71386
+ const refs = (await stateBackend.listStacks()).filter((r) => r.stackName === stackName);
71387
+ if (refs.length === 0) {
71388
+ logger.warn(
71389
+ `--from-state: no cdkd state found for stack '${stackName}' in bucket '${stateBucket}'. Was it deployed via 'cdkd deploy'? Falling back to PR 1 warn-and-drop semantics.`
71390
+ );
71391
+ return void 0;
71392
+ }
71393
+ let targetRegion;
71394
+ if (opts.stackRegion) {
71395
+ const found = refs.find((r) => r.region === opts.stackRegion);
71396
+ if (!found) {
71397
+ const seen = refs.map((r) => r.region ?? "(legacy)").join(", ");
71398
+ logger.warn(
71399
+ `--from-state: stack '${stackName}' has no state in region '${opts.stackRegion}' (available: ${seen}). Falling back.`
71400
+ );
71401
+ return void 0;
71402
+ }
71403
+ targetRegion = opts.stackRegion;
71404
+ } else if (synthRegion && refs.some((r) => r.region === synthRegion)) {
71405
+ targetRegion = synthRegion;
71406
+ } else if (refs.length === 1) {
71407
+ targetRegion = refs[0].region ?? synthRegion ?? region;
71408
+ } else {
71409
+ const seen = refs.map((r) => r.region ?? "(legacy)").join(", ");
71410
+ logger.warn(
71411
+ `--from-state: stack '${stackName}' has state in multiple regions (${seen}). Re-run with --stack-region <region>. Falling back.`
71412
+ );
71413
+ return void 0;
71414
+ }
71415
+ const stateData = await stateBackend.getState(stackName, targetRegion);
71416
+ if (!stateData) {
71417
+ logger.warn(
71418
+ `--from-state: state record for '${stackName}' (${targetRegion}) returned empty. Falling back.`
71419
+ );
71420
+ return void 0;
71421
+ }
71422
+ logger.debug(`--from-state: loaded state for ${stackName} (${targetRegion})`);
71423
+ return { state: stateData.state, region: targetRegion };
71424
+ } finally {
71425
+ awsClients.destroy();
71426
+ }
71427
+ }
71428
+ function suggestAssumeRoleFromState(state, logicalId) {
71429
+ const logger = getLogger();
71430
+ const lambda = state.resources[logicalId];
71431
+ if (!lambda)
71432
+ return;
71433
+ const roleRef = lambda.properties?.["Role"] ?? lambda.observedProperties?.["Role"];
71434
+ let roleArn;
71435
+ if (typeof roleRef === "string" && roleRef.startsWith("arn:")) {
71436
+ roleArn = roleRef;
71437
+ } else if (typeof roleRef === "object" && roleRef !== null) {
71438
+ const refLogicalId = pickReferencedLogicalId(roleRef);
71439
+ if (refLogicalId) {
71440
+ const roleResource = state.resources[refLogicalId];
71441
+ const cached = roleResource?.attributes?.["Arn"];
71442
+ if (typeof cached === "string" && cached.startsWith("arn:")) {
71443
+ roleArn = cached;
71444
+ }
71445
+ }
71446
+ }
71447
+ if (roleArn) {
71448
+ logger.info(
71449
+ `Hint: the deployed function uses execution role ${roleArn}. Re-run with --assume-role <that-arn> to invoke under the deployed function's narrow permissions.`
71450
+ );
71451
+ }
71452
+ }
71453
+ function pickReferencedLogicalId(intrinsic) {
71454
+ if ("Ref" in intrinsic && typeof intrinsic["Ref"] === "string")
71455
+ return intrinsic["Ref"];
71456
+ if ("Fn::GetAtt" in intrinsic) {
71457
+ const arg = intrinsic["Fn::GetAtt"];
71458
+ if (Array.isArray(arg) && typeof arg[0] === "string")
71459
+ return arg[0];
71460
+ if (typeof arg === "string")
71461
+ return arg.split(".")[0];
71462
+ }
71463
+ return void 0;
71464
+ }
70652
71465
  function createLocalCommand() {
70653
71466
  const local = new Command14("local").description(
70654
71467
  "Local Lambda execution against the AWS Lambda Runtime Interface Emulator (Docker required)"
@@ -70660,15 +71473,32 @@ function createLocalCommand() {
70660
71473
  "--env-vars <file>",
70661
71474
  'JSON env-var overrides (SAM-compatible: {"LogicalId":{"KEY":"VALUE"}})'
70662
71475
  )
70663
- ).addOption(new Option7("--no-pull", "Skip docker pull (use cached image)")).addOption(new Option7("--debug-port <port>", "Node --inspect-brk port (default: off)")).addOption(
71476
+ ).addOption(
71477
+ new Option7(
71478
+ "--no-pull",
71479
+ "Skip docker pull (use cached image) \u2014 no-op for IMAGE local-build path; `docker build` does not pull base layers by default"
71480
+ )
71481
+ ).addOption(new Option7("--debug-port <port>", "Node --inspect-brk port (default: off)")).addOption(
70664
71482
  new Option7("--container-host <host>", "Host to bind the RIE port to").default("127.0.0.1")
70665
71483
  ).addOption(
70666
71484
  new Option7(
70667
71485
  "--assume-role <arn>",
70668
71486
  `Assume the Lambda's deployed execution role and forward STS-issued temp credentials to the container so the handler runs with the deployed function's narrow permissions (closes the "developer admin / function narrow" skew). Off by default \u2014 when omitted, the developer's shell credentials are forwarded unchanged (SAM-compatible default).`
70669
71487
  )
71488
+ ).addOption(
71489
+ new Option7(
71490
+ "--from-state",
71491
+ "Read cdkd S3 state for the target stack and substitute Ref / Fn::GetAtt / Fn::Sub in env vars with the deployed physical IDs / attributes. Off by default \u2014 keep PR 1 warn-and-drop semantics; turn on for stacks already deployed via cdkd deploy."
71492
+ ).default(false)
71493
+ ).addOption(
71494
+ new Option7(
71495
+ "--stack-region <region>",
71496
+ "Region of the cdkd state record to read (used with --from-state when the same stack name has state in multiple regions)."
71497
+ )
70670
71498
  ).action(withErrorHandling(localInvokeCommand));
70671
- [...commonOptions, ...appOptions, ...contextOptions].forEach((opt) => invoke.addOption(opt));
71499
+ [...commonOptions, ...appOptions, ...contextOptions, ...stateOptions].forEach(
71500
+ (opt) => invoke.addOption(opt)
71501
+ );
70672
71502
  invoke.addOption(deprecatedRegionOption);
70673
71503
  local.addCommand(invoke);
70674
71504
  return local;
@@ -70703,7 +71533,7 @@ function reorderArgs(argv) {
70703
71533
  }
70704
71534
  async function main() {
70705
71535
  const program = new Command15();
70706
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.68.0");
71536
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.70.0");
70707
71537
  program.addCommand(createBootstrapCommand());
70708
71538
  program.addCommand(createSynthCommand());
70709
71539
  program.addCommand(createListCommand());