@go-to-k/cdkd 0.69.0 → 0.71.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
@@ -708,10 +708,10 @@ var require_GraphQLError = __commonJS({
708
708
  */
709
709
  constructor(message, ...rawArgs) {
710
710
  var _this$nodes, _nodeLocations$, _ref;
711
- const { nodes, source, positions, path: path2, originalError, extensions } = toNormalizedOptions(rawArgs);
711
+ const { nodes, source, positions, path: path3, originalError, extensions } = toNormalizedOptions(rawArgs);
712
712
  super(message);
713
713
  this.name = "GraphQLError";
714
- this.path = path2 !== null && path2 !== void 0 ? path2 : void 0;
714
+ this.path = path3 !== null && path3 !== void 0 ? path3 : void 0;
715
715
  this.originalError = originalError !== null && originalError !== void 0 ? originalError : void 0;
716
716
  this.nodes = undefinedIfEmpty(
717
717
  Array.isArray(nodes) ? nodes : nodes ? [nodes] : void 0
@@ -4173,14 +4173,14 @@ var require_visitor = __commonJS({
4173
4173
  let node = root;
4174
4174
  let key = void 0;
4175
4175
  let parent = void 0;
4176
- const path2 = [];
4176
+ const path3 = [];
4177
4177
  const ancestors = [];
4178
4178
  do {
4179
4179
  index++;
4180
4180
  const isLeaving = index === keys.length;
4181
4181
  const isEdited = isLeaving && edits.length !== 0;
4182
4182
  if (isLeaving) {
4183
- key = ancestors.length === 0 ? void 0 : path2[path2.length - 1];
4183
+ key = ancestors.length === 0 ? void 0 : path3[path3.length - 1];
4184
4184
  node = parent;
4185
4185
  parent = ancestors.pop();
4186
4186
  if (isEdited) {
@@ -4214,7 +4214,7 @@ var require_visitor = __commonJS({
4214
4214
  if (node === null || node === void 0) {
4215
4215
  continue;
4216
4216
  }
4217
- path2.push(key);
4217
+ path3.push(key);
4218
4218
  }
4219
4219
  let result;
4220
4220
  if (!Array.isArray(node)) {
@@ -4224,13 +4224,13 @@ var require_visitor = __commonJS({
4224
4224
  `Invalid AST Node: ${(0, _inspect.inspect)(node)}.`
4225
4225
  );
4226
4226
  const visitFn = isLeaving ? (_enterLeaveMap$get = enterLeaveMap.get(node.kind)) === null || _enterLeaveMap$get === void 0 ? void 0 : _enterLeaveMap$get.leave : (_enterLeaveMap$get2 = enterLeaveMap.get(node.kind)) === null || _enterLeaveMap$get2 === void 0 ? void 0 : _enterLeaveMap$get2.enter;
4227
- result = visitFn === null || visitFn === void 0 ? void 0 : visitFn.call(visitor, node, key, parent, path2, ancestors);
4227
+ result = visitFn === null || visitFn === void 0 ? void 0 : visitFn.call(visitor, node, key, parent, path3, ancestors);
4228
4228
  if (result === BREAK) {
4229
4229
  break;
4230
4230
  }
4231
4231
  if (result === false) {
4232
4232
  if (!isLeaving) {
4233
- path2.pop();
4233
+ path3.pop();
4234
4234
  continue;
4235
4235
  }
4236
4236
  } else if (result !== void 0) {
@@ -4239,7 +4239,7 @@ var require_visitor = __commonJS({
4239
4239
  if ((0, _ast.isNode)(result)) {
4240
4240
  node = result;
4241
4241
  } else {
4242
- path2.pop();
4242
+ path3.pop();
4243
4243
  continue;
4244
4244
  }
4245
4245
  }
@@ -4249,7 +4249,7 @@ var require_visitor = __commonJS({
4249
4249
  edits.push([key, node]);
4250
4250
  }
4251
4251
  if (isLeaving) {
4252
- path2.pop();
4252
+ path3.pop();
4253
4253
  } else {
4254
4254
  var _node$kind;
4255
4255
  stack = {
@@ -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) => join9(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", join9(node.variableDefinitions, "\n"), "\n)") : wrap("(", join9(node.variableDefinitions, ", "), ")");
4382
+ const prefix = wrap("", node.description, "\n") + join9(
4383
4383
  [
4384
4384
  node.operation,
4385
- join7([node.name, varDefs]),
4386
- join7(node.directives, " ")
4385
+ join9([node.name, varDefs]),
4386
+ join9(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(" ", join9(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("(", join9(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(join9(args, "\n")), "\n)");
4405
4405
  }
4406
- return join7([argsLine, join7(directives, " "), selectionSet], " ");
4406
+ return join9([argsLine, join9(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(" ", join9(directives, " "))
4415
4415
  },
4416
4416
  InlineFragment: {
4417
- leave: ({ typeCondition, directives, selectionSet }) => join7(
4417
+ leave: ({ typeCondition, directives, selectionSet }) => join9(
4418
4418
  [
4419
4419
  "...",
4420
4420
  wrap("on ", typeCondition),
4421
- join7(directives, " "),
4421
+ join9(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("(", join9(variableDefinitions, ", "), ")")} on ${typeCondition} ${wrap("", join9(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 }) => "[" + join9(values, ", ") + "]"
4460
4460
  },
4461
4461
  ObjectValue: {
4462
- leave: ({ fields }) => "{" + join7(fields, ", ") + "}"
4462
+ leave: ({ fields }) => "{" + join9(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("(", join9(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") + join9(["schema", join9(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") + join9(["scalar", name, join9(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") + join9(
4493
4493
  [
4494
4494
  "type",
4495
4495
  name,
4496
- wrap("implements ", join7(interfaces, " & ")),
4497
- join7(directives, " "),
4496
+ wrap("implements ", join9(interfaces, " & ")),
4497
+ join9(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(join9(args, "\n")), "\n)") : wrap("(", join9(args, ", "), ")")) + ": " + type + wrap(" ", join9(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") + join9(
4508
+ [name + ": " + type, wrap("= ", defaultValue), join9(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") + join9(
4514
4514
  [
4515
4515
  "interface",
4516
4516
  name,
4517
- wrap("implements ", join7(interfaces, " & ")),
4518
- join7(directives, " "),
4517
+ wrap("implements ", join9(interfaces, " & ")),
4518
+ join9(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") + join9(
4526
+ ["union", name, join9(directives, " "), wrap("= ", join9(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") + join9(["enum", name, join9(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") + join9([name, join9(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") + join9(["input", name, join9(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(join9(args, "\n")), "\n)") : wrap("(", join9(args, ", "), ")")) + wrap(" ", join9(directives, " ")) + (repeatable ? " repeatable" : "") + " on " + join9(locations, " | ")
4548
4548
  },
4549
4549
  SchemaExtension: {
4550
- leave: ({ directives, operationTypes }) => join7(
4551
- ["extend schema", join7(directives, " "), block(operationTypes)],
4550
+ leave: ({ directives, operationTypes }) => join9(
4551
+ ["extend schema", join9(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 }) => join9(["extend scalar", name, join9(directives, " ")], " ")
4557
4557
  },
4558
4558
  ObjectTypeExtension: {
4559
- leave: ({ name, interfaces, directives, fields }) => join7(
4559
+ leave: ({ name, interfaces, directives, fields }) => join9(
4560
4560
  [
4561
4561
  "extend type",
4562
4562
  name,
4563
- wrap("implements ", join7(interfaces, " & ")),
4564
- join7(directives, " "),
4563
+ wrap("implements ", join9(interfaces, " & ")),
4564
+ join9(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 }) => join9(
4572
4572
  [
4573
4573
  "extend interface",
4574
4574
  name,
4575
- wrap("implements ", join7(interfaces, " & ")),
4576
- join7(directives, " "),
4575
+ wrap("implements ", join9(interfaces, " & ")),
4576
+ join9(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 }) => join9(
4584
4584
  [
4585
4585
  "extend union",
4586
4586
  name,
4587
- join7(directives, " "),
4588
- wrap("= ", join7(types, " | "))
4587
+ join9(directives, " "),
4588
+ wrap("= ", join9(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 }) => join9(["extend enum", name, join9(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 }) => join9(["extend input", name, join9(directives, " "), block(fields)], " ")
4598
4598
  },
4599
4599
  DirectiveExtension: {
4600
- leave: ({ name, directives }) => join7(["extend directive @" + name, join7(directives, " ")], " ")
4600
+ leave: ({ name, directives }) => join9(["extend directive @" + name, join9(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 }) => join9([name, wrap(".", memberName)])
4608
4608
  },
4609
4609
  ArgumentCoordinate: {
4610
- leave: ({ name, fieldName, argumentName }) => join7([name, wrap(".", fieldName), wrap("(", argumentName, ":)")])
4610
+ leave: ({ name, fieldName, argumentName }) => join9([name, wrap(".", fieldName), wrap("(", argumentName, ":)")])
4611
4611
  },
4612
4612
  DirectiveCoordinate: {
4613
- leave: ({ name }) => join7(["@", name])
4613
+ leave: ({ name }) => join9(["@", name])
4614
4614
  },
4615
4615
  DirectiveArgumentCoordinate: {
4616
- leave: ({ name, argumentName }) => join7(["@", name, wrap("(", argumentName, ":)")])
4616
+ leave: ({ name, argumentName }) => join9(["@", name, wrap("(", argumentName, ":)")])
4617
4617
  }
4618
4618
  };
4619
- function join7(maybeArray, separator = "") {
4619
+ function join9(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(join9(array, "\n")), "\n}");
4625
4625
  }
4626
4626
  function wrap(start, maybeString, end = "") {
4627
4627
  return maybeString != null && maybeString !== "" ? start + maybeString + end : "";
@@ -9578,8 +9578,8 @@ var require_printPathArray = __commonJS({
9578
9578
  value: true
9579
9579
  });
9580
9580
  exports.printPathArray = printPathArray;
9581
- function printPathArray(path2) {
9582
- return path2.map(
9581
+ function printPathArray(path3) {
9582
+ return path3.map(
9583
9583
  (key) => typeof key === "number" ? "[" + key.toString() + "]" : "." + key
9584
9584
  ).join("");
9585
9585
  }
@@ -9602,9 +9602,9 @@ var require_Path = __commonJS({
9602
9602
  typename
9603
9603
  };
9604
9604
  }
9605
- function pathToArray(path2) {
9605
+ function pathToArray(path3) {
9606
9606
  const flattened = [];
9607
- let curr = path2;
9607
+ let curr = path3;
9608
9608
  while (curr) {
9609
9609
  flattened.push(curr.key);
9610
9610
  curr = curr.prev;
@@ -9635,21 +9635,21 @@ var require_coerceInputValue = __commonJS({
9635
9635
  function coerceInputValue(inputValue, type, onError = defaultOnError) {
9636
9636
  return coerceInputValueImpl(inputValue, type, onError, void 0);
9637
9637
  }
9638
- function defaultOnError(path2, invalidValue, error) {
9638
+ function defaultOnError(path3, invalidValue, error) {
9639
9639
  let errorPrefix = "Invalid value " + (0, _inspect.inspect)(invalidValue);
9640
- if (path2.length > 0) {
9641
- errorPrefix += ` at "value${(0, _printPathArray.printPathArray)(path2)}"`;
9640
+ if (path3.length > 0) {
9641
+ errorPrefix += ` at "value${(0, _printPathArray.printPathArray)(path3)}"`;
9642
9642
  }
9643
9643
  error.message = errorPrefix + ": " + error.message;
9644
9644
  throw error;
9645
9645
  }
9646
- function coerceInputValueImpl(inputValue, type, onError, path2) {
9646
+ function coerceInputValueImpl(inputValue, type, onError, path3) {
9647
9647
  if ((0, _definition.isNonNullType)(type)) {
9648
9648
  if (inputValue != null) {
9649
- return coerceInputValueImpl(inputValue, type.ofType, onError, path2);
9649
+ return coerceInputValueImpl(inputValue, type.ofType, onError, path3);
9650
9650
  }
9651
9651
  onError(
9652
- (0, _Path.pathToArray)(path2),
9652
+ (0, _Path.pathToArray)(path3),
9653
9653
  inputValue,
9654
9654
  new _GraphQLError.GraphQLError(
9655
9655
  `Expected non-nullable type "${(0, _inspect.inspect)(
@@ -9666,16 +9666,16 @@ var require_coerceInputValue = __commonJS({
9666
9666
  const itemType = type.ofType;
9667
9667
  if ((0, _isIterableObject.isIterableObject)(inputValue)) {
9668
9668
  return Array.from(inputValue, (itemValue, index) => {
9669
- const itemPath = (0, _Path.addPath)(path2, index, void 0);
9669
+ const itemPath = (0, _Path.addPath)(path3, index, void 0);
9670
9670
  return coerceInputValueImpl(itemValue, itemType, onError, itemPath);
9671
9671
  });
9672
9672
  }
9673
- return [coerceInputValueImpl(inputValue, itemType, onError, path2)];
9673
+ return [coerceInputValueImpl(inputValue, itemType, onError, path3)];
9674
9674
  }
9675
9675
  if ((0, _definition.isInputObjectType)(type)) {
9676
9676
  if (!(0, _isObjectLike.isObjectLike)(inputValue) || Array.isArray(inputValue)) {
9677
9677
  onError(
9678
- (0, _Path.pathToArray)(path2),
9678
+ (0, _Path.pathToArray)(path3),
9679
9679
  inputValue,
9680
9680
  new _GraphQLError.GraphQLError(
9681
9681
  `Expected type "${type.name}" to be an object.`
@@ -9693,7 +9693,7 @@ var require_coerceInputValue = __commonJS({
9693
9693
  } else if ((0, _definition.isNonNullType)(field.type)) {
9694
9694
  const typeStr = (0, _inspect.inspect)(field.type);
9695
9695
  onError(
9696
- (0, _Path.pathToArray)(path2),
9696
+ (0, _Path.pathToArray)(path3),
9697
9697
  inputValue,
9698
9698
  new _GraphQLError.GraphQLError(
9699
9699
  `Field "${field.name}" of required type "${typeStr}" was not provided.`
@@ -9706,7 +9706,7 @@ var require_coerceInputValue = __commonJS({
9706
9706
  fieldValue,
9707
9707
  field.type,
9708
9708
  onError,
9709
- (0, _Path.addPath)(path2, field.name, type.name)
9709
+ (0, _Path.addPath)(path3, field.name, type.name)
9710
9710
  );
9711
9711
  }
9712
9712
  for (const fieldName of Object.keys(inputValue)) {
@@ -9716,7 +9716,7 @@ var require_coerceInputValue = __commonJS({
9716
9716
  Object.keys(type.getFields())
9717
9717
  );
9718
9718
  onError(
9719
- (0, _Path.pathToArray)(path2),
9719
+ (0, _Path.pathToArray)(path3),
9720
9720
  inputValue,
9721
9721
  new _GraphQLError.GraphQLError(
9722
9722
  `Field "${fieldName}" is not defined by type "${type.name}".` + (0, _didYouMean.didYouMean)(suggestions)
@@ -9728,7 +9728,7 @@ var require_coerceInputValue = __commonJS({
9728
9728
  const keys = Object.keys(coercedValue);
9729
9729
  if (keys.length !== 1) {
9730
9730
  onError(
9731
- (0, _Path.pathToArray)(path2),
9731
+ (0, _Path.pathToArray)(path3),
9732
9732
  inputValue,
9733
9733
  new _GraphQLError.GraphQLError(
9734
9734
  `Exactly one key must be specified for OneOf type "${type.name}".`
@@ -9739,7 +9739,7 @@ var require_coerceInputValue = __commonJS({
9739
9739
  const value = coercedValue[key];
9740
9740
  if (value === null) {
9741
9741
  onError(
9742
- (0, _Path.pathToArray)(path2).concat(key),
9742
+ (0, _Path.pathToArray)(path3).concat(key),
9743
9743
  value,
9744
9744
  new _GraphQLError.GraphQLError(`Field "${key}" must be non-null.`)
9745
9745
  );
@@ -9753,10 +9753,10 @@ var require_coerceInputValue = __commonJS({
9753
9753
  parseResult = type.parseValue(inputValue);
9754
9754
  } catch (error) {
9755
9755
  if (error instanceof _GraphQLError.GraphQLError) {
9756
- onError((0, _Path.pathToArray)(path2), inputValue, error);
9756
+ onError((0, _Path.pathToArray)(path3), inputValue, error);
9757
9757
  } else {
9758
9758
  onError(
9759
- (0, _Path.pathToArray)(path2),
9759
+ (0, _Path.pathToArray)(path3),
9760
9760
  inputValue,
9761
9761
  new _GraphQLError.GraphQLError(
9762
9762
  `Expected type "${type.name}". ` + error.message,
@@ -9770,7 +9770,7 @@ var require_coerceInputValue = __commonJS({
9770
9770
  }
9771
9771
  if (parseResult === void 0) {
9772
9772
  onError(
9773
- (0, _Path.pathToArray)(path2),
9773
+ (0, _Path.pathToArray)(path3),
9774
9774
  inputValue,
9775
9775
  new _GraphQLError.GraphQLError(`Expected type "${type.name}".`)
9776
9776
  );
@@ -10011,11 +10011,11 @@ var require_values = __commonJS({
10011
10011
  coercedValues[varName] = (0, _coerceInputValue.coerceInputValue)(
10012
10012
  value,
10013
10013
  varType,
10014
- (path2, invalidValue, error) => {
10014
+ (path3, invalidValue, error) => {
10015
10015
  let prefix = `Variable "$${varName}" got invalid value ` + (0, _inspect.inspect)(invalidValue);
10016
- if (path2.length > 0) {
10016
+ if (path3.length > 0) {
10017
10017
  prefix += ` at "${varName}${(0, _printPathArray.printPathArray)(
10018
- path2
10018
+ path3
10019
10019
  )}"`;
10020
10020
  }
10021
10021
  onError(
@@ -11745,7 +11745,7 @@ var require_locatedError = __commonJS({
11745
11745
  exports.locatedError = locatedError;
11746
11746
  var _toError = require_toError();
11747
11747
  var _GraphQLError = require_GraphQLError();
11748
- function locatedError(rawOriginalError, nodes, path2) {
11748
+ function locatedError(rawOriginalError, nodes, path3) {
11749
11749
  var _nodes;
11750
11750
  const originalError = (0, _toError.toError)(rawOriginalError);
11751
11751
  if (isLocatedGraphQLError(originalError)) {
@@ -11755,7 +11755,7 @@ var require_locatedError = __commonJS({
11755
11755
  nodes: (_nodes = originalError.nodes) !== null && _nodes !== void 0 ? _nodes : nodes,
11756
11756
  source: originalError.source,
11757
11757
  positions: originalError.positions,
11758
- path: path2,
11758
+ path: path3,
11759
11759
  originalError
11760
11760
  });
11761
11761
  }
@@ -11815,20 +11815,20 @@ var require_execute = __commonJS({
11815
11815
  get errors() {
11816
11816
  return this._errors;
11817
11817
  }
11818
- add(error, path2) {
11819
- if (this._hasNulledPosition(path2)) {
11818
+ add(error, path3) {
11819
+ if (this._hasNulledPosition(path3)) {
11820
11820
  return;
11821
11821
  }
11822
- this._errorPositions.add(path2);
11822
+ this._errorPositions.add(path3);
11823
11823
  this._errors.push(error);
11824
11824
  }
11825
11825
  _hasNulledPosition(startPath) {
11826
- let path2 = startPath;
11827
- while (path2 !== void 0) {
11828
- if (this._errorPositions.has(path2)) {
11826
+ let path3 = startPath;
11827
+ while (path3 !== void 0) {
11828
+ if (this._errorPositions.has(path3)) {
11829
11829
  return true;
11830
11830
  }
11831
- path2 = path2.prev;
11831
+ path3 = path3.prev;
11832
11832
  }
11833
11833
  return this._errorPositions.has(void 0);
11834
11834
  }
@@ -11977,27 +11977,27 @@ var require_execute = __commonJS({
11977
11977
  rootType,
11978
11978
  operation.selectionSet
11979
11979
  );
11980
- const path2 = void 0;
11980
+ const path3 = void 0;
11981
11981
  switch (operation.operation) {
11982
11982
  case _ast.OperationTypeNode.QUERY:
11983
- return executeFields(exeContext, rootType, rootValue, path2, rootFields);
11983
+ return executeFields(exeContext, rootType, rootValue, path3, rootFields);
11984
11984
  case _ast.OperationTypeNode.MUTATION:
11985
11985
  return executeFieldsSerially(
11986
11986
  exeContext,
11987
11987
  rootType,
11988
11988
  rootValue,
11989
- path2,
11989
+ path3,
11990
11990
  rootFields
11991
11991
  );
11992
11992
  case _ast.OperationTypeNode.SUBSCRIPTION:
11993
- return executeFields(exeContext, rootType, rootValue, path2, rootFields);
11993
+ return executeFields(exeContext, rootType, rootValue, path3, rootFields);
11994
11994
  }
11995
11995
  }
11996
- function executeFieldsSerially(exeContext, parentType, sourceValue, path2, fields) {
11996
+ function executeFieldsSerially(exeContext, parentType, sourceValue, path3, fields) {
11997
11997
  return (0, _promiseReduce.promiseReduce)(
11998
11998
  fields.entries(),
11999
11999
  (results, [responseName, fieldNodes]) => {
12000
- const fieldPath = (0, _Path.addPath)(path2, responseName, parentType.name);
12000
+ const fieldPath = (0, _Path.addPath)(path3, responseName, parentType.name);
12001
12001
  const result = executeField(
12002
12002
  exeContext,
12003
12003
  parentType,
@@ -12020,12 +12020,12 @@ var require_execute = __commonJS({
12020
12020
  /* @__PURE__ */ Object.create(null)
12021
12021
  );
12022
12022
  }
12023
- function executeFields(exeContext, parentType, sourceValue, path2, fields) {
12023
+ function executeFields(exeContext, parentType, sourceValue, path3, fields) {
12024
12024
  const results = /* @__PURE__ */ Object.create(null);
12025
12025
  let containsPromise = false;
12026
12026
  try {
12027
12027
  for (const [responseName, fieldNodes] of fields.entries()) {
12028
- const fieldPath = (0, _Path.addPath)(path2, responseName, parentType.name);
12028
+ const fieldPath = (0, _Path.addPath)(path3, responseName, parentType.name);
12029
12029
  const result = executeField(
12030
12030
  exeContext,
12031
12031
  parentType,
@@ -12053,7 +12053,7 @@ var require_execute = __commonJS({
12053
12053
  }
12054
12054
  return (0, _promiseForObject.promiseForObject)(results);
12055
12055
  }
12056
- function executeField(exeContext, parentType, source, fieldNodes, path2) {
12056
+ function executeField(exeContext, parentType, source, fieldNodes, path3) {
12057
12057
  var _fieldDef$resolve;
12058
12058
  const fieldDef = getFieldDef(exeContext.schema, parentType, fieldNodes[0]);
12059
12059
  if (!fieldDef) {
@@ -12066,7 +12066,7 @@ var require_execute = __commonJS({
12066
12066
  fieldDef,
12067
12067
  fieldNodes,
12068
12068
  parentType,
12069
- path2
12069
+ path3
12070
12070
  );
12071
12071
  try {
12072
12072
  const args = (0, _values.getArgumentValues)(
@@ -12079,7 +12079,7 @@ var require_execute = __commonJS({
12079
12079
  let completed;
12080
12080
  if ((0, _isPromise.isPromise)(result)) {
12081
12081
  completed = result.then(
12082
- (resolved) => completeValue(exeContext, returnType, fieldNodes, info, path2, resolved)
12082
+ (resolved) => completeValue(exeContext, returnType, fieldNodes, info, path3, resolved)
12083
12083
  );
12084
12084
  } else {
12085
12085
  completed = completeValue(
@@ -12087,7 +12087,7 @@ var require_execute = __commonJS({
12087
12087
  returnType,
12088
12088
  fieldNodes,
12089
12089
  info,
12090
- path2,
12090
+ path3,
12091
12091
  result
12092
12092
  );
12093
12093
  }
@@ -12096,9 +12096,9 @@ var require_execute = __commonJS({
12096
12096
  const error = (0, _locatedError.locatedError)(
12097
12097
  rawError,
12098
12098
  fieldNodes,
12099
- (0, _Path.pathToArray)(path2)
12099
+ (0, _Path.pathToArray)(path3)
12100
12100
  );
12101
- return handleFieldError(error, returnType, path2, exeContext);
12101
+ return handleFieldError(error, returnType, path3, exeContext);
12102
12102
  });
12103
12103
  }
12104
12104
  return completed;
@@ -12106,18 +12106,18 @@ var require_execute = __commonJS({
12106
12106
  const error = (0, _locatedError.locatedError)(
12107
12107
  rawError,
12108
12108
  fieldNodes,
12109
- (0, _Path.pathToArray)(path2)
12109
+ (0, _Path.pathToArray)(path3)
12110
12110
  );
12111
- return handleFieldError(error, returnType, path2, exeContext);
12111
+ return handleFieldError(error, returnType, path3, exeContext);
12112
12112
  }
12113
12113
  }
12114
- function buildResolveInfo(exeContext, fieldDef, fieldNodes, parentType, path2) {
12114
+ function buildResolveInfo(exeContext, fieldDef, fieldNodes, parentType, path3) {
12115
12115
  return {
12116
12116
  fieldName: fieldDef.name,
12117
12117
  fieldNodes,
12118
12118
  returnType: fieldDef.type,
12119
12119
  parentType,
12120
- path: path2,
12120
+ path: path3,
12121
12121
  schema: exeContext.schema,
12122
12122
  fragments: exeContext.fragments,
12123
12123
  rootValue: exeContext.rootValue,
@@ -12125,14 +12125,14 @@ var require_execute = __commonJS({
12125
12125
  variableValues: exeContext.variableValues
12126
12126
  };
12127
12127
  }
12128
- function handleFieldError(error, returnType, path2, exeContext) {
12128
+ function handleFieldError(error, returnType, path3, exeContext) {
12129
12129
  if ((0, _definition.isNonNullType)(returnType)) {
12130
12130
  throw error;
12131
12131
  }
12132
- exeContext.collectedErrors.add(error, path2);
12132
+ exeContext.collectedErrors.add(error, path3);
12133
12133
  return null;
12134
12134
  }
12135
- function completeValue(exeContext, returnType, fieldNodes, info, path2, result) {
12135
+ function completeValue(exeContext, returnType, fieldNodes, info, path3, result) {
12136
12136
  if (result instanceof Error) {
12137
12137
  throw result;
12138
12138
  }
@@ -12142,7 +12142,7 @@ var require_execute = __commonJS({
12142
12142
  returnType.ofType,
12143
12143
  fieldNodes,
12144
12144
  info,
12145
- path2,
12145
+ path3,
12146
12146
  result
12147
12147
  );
12148
12148
  if (completed === null) {
@@ -12161,7 +12161,7 @@ var require_execute = __commonJS({
12161
12161
  returnType,
12162
12162
  fieldNodes,
12163
12163
  info,
12164
- path2,
12164
+ path3,
12165
12165
  result
12166
12166
  );
12167
12167
  }
@@ -12174,7 +12174,7 @@ var require_execute = __commonJS({
12174
12174
  returnType,
12175
12175
  fieldNodes,
12176
12176
  info,
12177
- path2,
12177
+ path3,
12178
12178
  result
12179
12179
  );
12180
12180
  }
@@ -12184,7 +12184,7 @@ var require_execute = __commonJS({
12184
12184
  returnType,
12185
12185
  fieldNodes,
12186
12186
  info,
12187
- path2,
12187
+ path3,
12188
12188
  result
12189
12189
  );
12190
12190
  }
@@ -12193,7 +12193,7 @@ var require_execute = __commonJS({
12193
12193
  "Cannot complete value of unexpected output type: " + (0, _inspect.inspect)(returnType)
12194
12194
  );
12195
12195
  }
12196
- function completeListValue(exeContext, returnType, fieldNodes, info, path2, result) {
12196
+ function completeListValue(exeContext, returnType, fieldNodes, info, path3, result) {
12197
12197
  if (!(0, _isIterableObject.isIterableObject)(result)) {
12198
12198
  throw new _GraphQLError.GraphQLError(
12199
12199
  `Expected Iterable, but did not find one for field "${info.parentType.name}.${info.fieldName}".`
@@ -12202,7 +12202,7 @@ var require_execute = __commonJS({
12202
12202
  const itemType = returnType.ofType;
12203
12203
  let containsPromise = false;
12204
12204
  const completedResults = Array.from(result, (item, index) => {
12205
- const itemPath = (0, _Path.addPath)(path2, index, void 0);
12205
+ const itemPath = (0, _Path.addPath)(path3, index, void 0);
12206
12206
  try {
12207
12207
  let completedItem;
12208
12208
  if ((0, _isPromise.isPromise)(item)) {
@@ -12260,7 +12260,7 @@ var require_execute = __commonJS({
12260
12260
  }
12261
12261
  return serializedResult;
12262
12262
  }
12263
- function completeAbstractValue(exeContext, returnType, fieldNodes, info, path2, result) {
12263
+ function completeAbstractValue(exeContext, returnType, fieldNodes, info, path3, result) {
12264
12264
  var _returnType$resolveTy;
12265
12265
  const resolveTypeFn = (_returnType$resolveTy = returnType.resolveType) !== null && _returnType$resolveTy !== void 0 ? _returnType$resolveTy : exeContext.typeResolver;
12266
12266
  const contextValue = exeContext.contextValue;
@@ -12279,7 +12279,7 @@ var require_execute = __commonJS({
12279
12279
  ),
12280
12280
  fieldNodes,
12281
12281
  info,
12282
- path2,
12282
+ path3,
12283
12283
  result
12284
12284
  )
12285
12285
  );
@@ -12296,7 +12296,7 @@ var require_execute = __commonJS({
12296
12296
  ),
12297
12297
  fieldNodes,
12298
12298
  info,
12299
- path2,
12299
+ path3,
12300
12300
  result
12301
12301
  );
12302
12302
  }
@@ -12344,7 +12344,7 @@ var require_execute = __commonJS({
12344
12344
  }
12345
12345
  return runtimeType;
12346
12346
  }
12347
- function completeObjectValue(exeContext, returnType, fieldNodes, info, path2, result) {
12347
+ function completeObjectValue(exeContext, returnType, fieldNodes, info, path3, result) {
12348
12348
  const subFieldNodes = collectSubfields(exeContext, returnType, fieldNodes);
12349
12349
  if (returnType.isTypeOf) {
12350
12350
  const isTypeOf = returnType.isTypeOf(result, exeContext.contextValue, info);
@@ -12357,7 +12357,7 @@ var require_execute = __commonJS({
12357
12357
  exeContext,
12358
12358
  returnType,
12359
12359
  result,
12360
- path2,
12360
+ path3,
12361
12361
  subFieldNodes
12362
12362
  );
12363
12363
  });
@@ -12366,7 +12366,7 @@ var require_execute = __commonJS({
12366
12366
  throw invalidReturnTypeError(returnType, result, fieldNodes);
12367
12367
  }
12368
12368
  }
12369
- return executeFields(exeContext, returnType, result, path2, subFieldNodes);
12369
+ return executeFields(exeContext, returnType, result, path3, subFieldNodes);
12370
12370
  }
12371
12371
  function invalidReturnTypeError(returnType, result, fieldNodes) {
12372
12372
  return new _GraphQLError.GraphQLError(
@@ -12448,7 +12448,7 @@ var require_graphql = __commonJS({
12448
12448
  var _validate2 = require_validate2();
12449
12449
  var _execute = require_execute();
12450
12450
  function graphql(args) {
12451
- return new Promise((resolve5) => resolve5(graphqlImpl(args)));
12451
+ return new Promise((resolve6) => resolve6(graphqlImpl(args)));
12452
12452
  }
12453
12453
  function graphqlSync(args) {
12454
12454
  const result = graphqlImpl(args);
@@ -13450,13 +13450,13 @@ var require_subscribe = __commonJS({
13450
13450
  }
13451
13451
  );
13452
13452
  }
13453
- const path2 = (0, _Path.addPath)(void 0, responseName, rootType.name);
13453
+ const path3 = (0, _Path.addPath)(void 0, responseName, rootType.name);
13454
13454
  const info = (0, _execute.buildResolveInfo)(
13455
13455
  exeContext,
13456
13456
  fieldDef,
13457
13457
  fieldNodes,
13458
13458
  rootType,
13459
- path2
13459
+ path3
13460
13460
  );
13461
13461
  try {
13462
13462
  var _fieldDef$subscribe;
@@ -13476,7 +13476,7 @@ var require_subscribe = __commonJS({
13476
13476
  throw (0, _locatedError.locatedError)(
13477
13477
  error,
13478
13478
  fieldNodes,
13479
- (0, _Path.pathToArray)(path2)
13479
+ (0, _Path.pathToArray)(path3)
13480
13480
  );
13481
13481
  }
13482
13482
  }
@@ -17797,7 +17797,7 @@ var require_graphql2 = __commonJS({
17797
17797
  });
17798
17798
 
17799
17799
  // src/cli/index.ts
17800
- import { Command as Command15 } from "commander";
17800
+ import { Command as Command16 } from "commander";
17801
17801
 
17802
17802
  // src/cli/commands/bootstrap.ts
17803
17803
  import { Command, Option as Option2 } from "commander";
@@ -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);
@@ -18405,6 +18412,13 @@ var StackTerminationProtectionError = class _StackTerminationProtectionError ext
18405
18412
  Object.setPrototypeOf(this, _StackTerminationProtectionError.prototype);
18406
18413
  }
18407
18414
  };
18415
+ var RouteDiscoveryError = class _RouteDiscoveryError extends CdkdError {
18416
+ constructor(message, cause) {
18417
+ super(message, "ROUTE_DISCOVERY_ERROR", cause);
18418
+ this.name = "RouteDiscoveryError";
18419
+ Object.setPrototypeOf(this, _RouteDiscoveryError.prototype);
18420
+ }
18421
+ };
18408
18422
  function isCdkdError(error) {
18409
18423
  return error instanceof CdkdError;
18410
18424
  }
@@ -18855,7 +18869,7 @@ var IntrinsicFunctionResolver = class {
18855
18869
  this.logger.debug(
18856
18870
  `VPC ${physicalId} IPv6 CIDR still associating (attempt ${attempt}/${maxAttempts}), waiting...`
18857
18871
  );
18858
- await new Promise((resolve5) => setTimeout(resolve5, 2e3));
18872
+ await new Promise((resolve6) => setTimeout(resolve6, 2e3));
18859
18873
  }
18860
18874
  this.logger.warn(
18861
18875
  `VPC ${physicalId} IPv6 CIDR did not reach 'associated' state after ${maxAttempts} attempts`
@@ -19740,7 +19754,7 @@ var DagExecutor = class {
19740
19754
  async execute(concurrency, fn, cancelled = () => false) {
19741
19755
  let active = 0;
19742
19756
  const errors = [];
19743
- return new Promise((resolve5, reject) => {
19757
+ return new Promise((resolve6, reject) => {
19744
19758
  const dispatch = () => {
19745
19759
  let changed = true;
19746
19760
  while (changed) {
@@ -19802,7 +19816,7 @@ var DagExecutor = class {
19802
19816
  );
19803
19817
  return;
19804
19818
  }
19805
- resolve5();
19819
+ resolve6();
19806
19820
  }
19807
19821
  };
19808
19822
  dispatch();
@@ -20483,7 +20497,7 @@ Error: ${err.message || "Unknown error"}`,
20483
20497
  * Sleep for specified milliseconds
20484
20498
  */
20485
20499
  sleep(ms) {
20486
- return new Promise((resolve5) => setTimeout(resolve5, ms));
20500
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
20487
20501
  }
20488
20502
  /**
20489
20503
  * Check if a resource type is supported by Cloud Control API
@@ -21217,7 +21231,7 @@ var CustomResourceProvider = class _CustomResourceProvider {
21217
21231
  return result;
21218
21232
  }
21219
21233
  sleep(ms) {
21220
- return new Promise((resolve5) => setTimeout(resolve5, ms));
21234
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
21221
21235
  }
21222
21236
  /**
21223
21237
  * Adopt an existing custom resource into cdkd state.
@@ -21647,7 +21661,7 @@ function isRetryableTransientError(error, message) {
21647
21661
  }
21648
21662
 
21649
21663
  // src/deployment/retry.ts
21650
- var defaultSleep = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
21664
+ var defaultSleep = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
21651
21665
  async function withRetry(operation, logicalId, opts = {}) {
21652
21666
  const maxRetries = opts.maxRetries ?? 8;
21653
21667
  const initialDelayMs = opts.initialDelayMs ?? 1e3;
@@ -21702,7 +21716,7 @@ function validateOptions(opts) {
21702
21716
  async function withResourceDeadline(operation, opts) {
21703
21717
  validateOptions(opts);
21704
21718
  const startedAt = Date.now();
21705
- return new Promise((resolve5, reject) => {
21719
+ return new Promise((resolve6, reject) => {
21706
21720
  let settled = false;
21707
21721
  let warnTimer;
21708
21722
  let timeoutTimer;
@@ -21742,7 +21756,7 @@ async function withResourceDeadline(operation, opts) {
21742
21756
  return;
21743
21757
  settled = true;
21744
21758
  cleanup();
21745
- resolve5(value);
21759
+ resolve6(value);
21746
21760
  },
21747
21761
  (err) => {
21748
21762
  if (settled)
@@ -23313,6 +23327,41 @@ var contextOptions = [
23313
23327
  "Set context values (can be specified multiple times)"
23314
23328
  )
23315
23329
  ];
23330
+ var IAM_ROLE_ARN_REGEX = /^arn:[^:]+:iam::\d+:role\//;
23331
+ function parseAssumeRoleToken(raw, previous) {
23332
+ const acc = previous ?? { perLambda: {} };
23333
+ if (!acc.perLambda)
23334
+ acc.perLambda = {};
23335
+ const eqIndex = raw.indexOf("=");
23336
+ if (eqIndex === -1) {
23337
+ if (!IAM_ROLE_ARN_REGEX.test(raw)) {
23338
+ throw new Error(
23339
+ `Invalid --assume-role value "${raw}": expected an IAM role ARN like arn:aws:iam::123456789012:role/MyRole, or LogicalId=<arn>.`
23340
+ );
23341
+ }
23342
+ acc.globalArn = raw;
23343
+ return acc;
23344
+ }
23345
+ const logicalId = raw.substring(0, eqIndex).trim();
23346
+ const arn = raw.substring(eqIndex + 1).trim();
23347
+ if (!/^[A-Za-z][A-Za-z0-9]*$/.test(logicalId)) {
23348
+ throw new Error(
23349
+ `Invalid --assume-role value "${raw}": left-hand side "${logicalId}" must be a CloudFormation logical ID (alphanumeric, leading letter).`
23350
+ );
23351
+ }
23352
+ if (!IAM_ROLE_ARN_REGEX.test(arn)) {
23353
+ throw new Error(
23354
+ `Invalid --assume-role value "${raw}": right-hand side "${arn}" must be an IAM role ARN like arn:aws:iam::123456789012:role/MyRole.`
23355
+ );
23356
+ }
23357
+ acc.perLambda[logicalId] = arn;
23358
+ return acc;
23359
+ }
23360
+ function effectiveAssumeRoleArn(logicalId, opt) {
23361
+ if (!opt)
23362
+ return void 0;
23363
+ return opt.perLambda?.[logicalId] ?? opt.globalArn;
23364
+ }
23316
23365
  var destroyOptions = [
23317
23366
  new Option("-f, --force", "Do not ask for confirmation before destroying the stacks").default(
23318
23367
  false
@@ -23436,11 +23485,11 @@ async function resolveStateBucketWithDefaultAndSource(cliBucket, region) {
23436
23485
  return syncResult;
23437
23486
  const logger = getLogger();
23438
23487
  logger.debug("No state bucket specified, resolving default from account...");
23439
- const { GetCallerIdentityCommand: GetCallerIdentityCommand11 } = await import("@aws-sdk/client-sts");
23488
+ const { GetCallerIdentityCommand: GetCallerIdentityCommand12 } = await import("@aws-sdk/client-sts");
23440
23489
  const { S3Client: S3Client12 } = await import("@aws-sdk/client-s3");
23441
23490
  const { getAwsClients: getAwsClients2 } = await Promise.resolve().then(() => (init_aws_clients(), aws_clients_exports));
23442
23491
  const awsClients = getAwsClients2();
23443
- const identity = await awsClients.sts.send(new GetCallerIdentityCommand11({}));
23492
+ const identity = await awsClients.sts.send(new GetCallerIdentityCommand12({}));
23444
23493
  const accountId = identity.Account;
23445
23494
  const newName = getDefaultStateBucketName(accountId);
23446
23495
  const legacyName = getLegacyStateBucketName(accountId, region);
@@ -23742,7 +23791,7 @@ var AppExecutor = class {
23742
23791
  * Spawn subprocess and wait for completion
23743
23792
  */
23744
23793
  spawn(commandLine, env) {
23745
- return new Promise((resolve5, reject) => {
23794
+ return new Promise((resolve6, reject) => {
23746
23795
  const proc = spawn(commandLine, {
23747
23796
  stdio: ["ignore", "pipe", "pipe"],
23748
23797
  shell: true,
@@ -23768,7 +23817,7 @@ var AppExecutor = class {
23768
23817
  });
23769
23818
  proc.on("close", (code) => {
23770
23819
  if (code === 0) {
23771
- resolve5();
23820
+ resolve6();
23772
23821
  } else {
23773
23822
  const stderr = stderrChunks.join("\n");
23774
23823
  reject(
@@ -24480,8 +24529,8 @@ var CcApiContextProvider = class {
24480
24529
  /**
24481
24530
  * Get nested property value using dot notation
24482
24531
  */
24483
- getNestedProperty(obj, path2) {
24484
- const parts = path2.split(".");
24532
+ getNestedProperty(obj, path3) {
24533
+ const parts = path3.split(".");
24485
24534
  let current = obj;
24486
24535
  for (const part of parts) {
24487
24536
  if (current === null || current === void 0 || typeof current !== "object") {
@@ -25290,11 +25339,11 @@ var FileAssetPublisher = class {
25290
25339
  */
25291
25340
  async uploadZip(client, dirPath, bucket, key) {
25292
25341
  const archiver = await import("archiver");
25293
- const body = await new Promise((resolve5, reject) => {
25342
+ const body = await new Promise((resolve6, reject) => {
25294
25343
  const chunks = [];
25295
25344
  const archive = archiver.default("zip", { zlib: { level: 9 } });
25296
25345
  archive.on("data", (chunk) => chunks.push(chunk));
25297
- archive.on("end", () => resolve5(Buffer.concat(chunks)));
25346
+ archive.on("end", () => resolve6(Buffer.concat(chunks)));
25298
25347
  archive.on("error", reject);
25299
25348
  const stat = statSync2(dirPath);
25300
25349
  if (stat.isDirectory()) {
@@ -25322,14 +25371,57 @@ var FileAssetPublisher = class {
25322
25371
  };
25323
25372
 
25324
25373
  // src/assets/docker-asset-publisher.ts
25325
- import { execFile, spawn as spawn2 } from "node:child_process";
25326
- import { promisify } from "node:util";
25374
+ import { execFile as execFile2, spawn as spawn2 } from "node:child_process";
25375
+ import { promisify as promisify2 } from "node:util";
25327
25376
  import {
25328
25377
  ECRClient,
25329
25378
  GetAuthorizationTokenCommand,
25330
25379
  DescribeImagesCommand as DescribeImagesCommand2
25331
25380
  } from "@aws-sdk/client-ecr";
25381
+
25382
+ // src/assets/docker-build.ts
25383
+ import { execFile } from "node:child_process";
25384
+ import { promisify } from "node:util";
25332
25385
  var execFileAsync = promisify(execFile);
25386
+ async function buildDockerImage(asset, cdkOutDir, tag, options) {
25387
+ const logger = getLogger().child("docker-build");
25388
+ const args = ["build", "-t", tag];
25389
+ if (options.platform) {
25390
+ args.push("--platform", options.platform);
25391
+ }
25392
+ if (asset.source.dockerFile) {
25393
+ args.push("-f", asset.source.dockerFile);
25394
+ }
25395
+ if (asset.source.dockerBuildArgs) {
25396
+ for (const [key, value] of Object.entries(asset.source.dockerBuildArgs)) {
25397
+ args.push("--build-arg", `${key}=${value}`);
25398
+ }
25399
+ }
25400
+ if (asset.source.dockerBuildTarget) {
25401
+ args.push("--target", asset.source.dockerBuildTarget);
25402
+ }
25403
+ if (asset.source.dockerOutputs) {
25404
+ for (const output of asset.source.dockerOutputs) {
25405
+ args.push("--output", output);
25406
+ }
25407
+ }
25408
+ const contextDir = `${cdkOutDir}/${asset.source.directory}`;
25409
+ args.push(contextDir);
25410
+ logger.debug(`docker ${args.join(" ")}`);
25411
+ try {
25412
+ await execFileAsync("docker", args, {
25413
+ maxBuffer: 50 * 1024 * 1024
25414
+ // 50MB for build output
25415
+ });
25416
+ } catch (error) {
25417
+ const err = error;
25418
+ const stderr = err.stderr || err.message || String(error);
25419
+ throw options.wrapError(stderr);
25420
+ }
25421
+ }
25422
+
25423
+ // src/assets/docker-asset-publisher.ts
25424
+ var execFileAsync2 = promisify2(execFile2);
25333
25425
  var DockerAssetPublisher = class {
25334
25426
  logger = getLogger().child("DockerAssetPublisher");
25335
25427
  /**
@@ -25412,38 +25504,17 @@ var DockerAssetPublisher = class {
25412
25504
  }
25413
25505
  }
25414
25506
  /**
25415
- * Build Docker image
25507
+ * Build Docker image — delegates to the shared `buildDockerImage`
25508
+ * helper so this code path stays in sync with `cdkd local invoke`'s
25509
+ * container-Lambda build path. `--platform` is currently not threaded
25510
+ * through here (publish-assets has no Architectures hint to consult);
25511
+ * a follow-up can lift this once the asset manifest carries a
25512
+ * platform field.
25416
25513
  */
25417
25514
  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
- }
25515
+ await buildDockerImage(asset, cdkOutputDir, tag, {
25516
+ wrapError: (stderr) => new AssetError(`Docker build failed: ${stderr}`)
25517
+ });
25447
25518
  }
25448
25519
  /**
25449
25520
  * Authenticate with ECR
@@ -25457,7 +25528,7 @@ var DockerAssetPublisher = class {
25457
25528
  const token = Buffer.from(authData.authorizationToken, "base64").toString();
25458
25529
  const [username, password] = token.split(":");
25459
25530
  const endpoint = authData.proxyEndpoint || `https://${accountId}.dkr.ecr.${region}.amazonaws.com`;
25460
- await new Promise((resolve5, reject) => {
25531
+ await new Promise((resolve6, reject) => {
25461
25532
  const proc = spawn2(
25462
25533
  "docker",
25463
25534
  ["login", "--username", username, "--password-stdin", endpoint],
@@ -25471,7 +25542,7 @@ var DockerAssetPublisher = class {
25471
25542
  });
25472
25543
  proc.on("close", (code) => {
25473
25544
  if (code === 0) {
25474
- resolve5();
25545
+ resolve6();
25475
25546
  } else {
25476
25547
  reject(new AssetError(`ECR login failed: ${stderr.trim()}`));
25477
25548
  }
@@ -25487,7 +25558,7 @@ var DockerAssetPublisher = class {
25487
25558
  * Tag Docker image
25488
25559
  */
25489
25560
  async tagImage(source, target) {
25490
- await execFileAsync("docker", ["tag", source, target]);
25561
+ await execFileAsync2("docker", ["tag", source, target]);
25491
25562
  }
25492
25563
  /**
25493
25564
  * Push Docker image
@@ -25495,7 +25566,7 @@ var DockerAssetPublisher = class {
25495
25566
  async pushImage(uri) {
25496
25567
  this.logger.debug(`Pushing: ${uri}`);
25497
25568
  try {
25498
- await execFileAsync("docker", ["push", uri], {
25569
+ await execFileAsync2("docker", ["push", uri], {
25499
25570
  maxBuffer: 50 * 1024 * 1024
25500
25571
  });
25501
25572
  } catch (error) {
@@ -25524,7 +25595,7 @@ var WorkGraph = class {
25524
25595
  async execute(concurrency, fn) {
25525
25596
  const active = { "asset-build": 0, "asset-publish": 0, stack: 0 };
25526
25597
  const errors = [];
25527
- return new Promise((resolve5, reject) => {
25598
+ return new Promise((resolve6, reject) => {
25528
25599
  const dispatch = () => {
25529
25600
  const ready = [];
25530
25601
  for (const node of this.nodes.values()) {
@@ -25596,7 +25667,7 @@ ${msg}`
25596
25667
  );
25597
25668
  return;
25598
25669
  }
25599
- resolve5();
25670
+ resolve6();
25600
25671
  }
25601
25672
  };
25602
25673
  dispatch();
@@ -25718,9 +25789,9 @@ var AssetPublisher = class {
25718
25789
  const region = options.region || process.env["AWS_REGION"] || "us-east-1";
25719
25790
  let accountId = options.accountId;
25720
25791
  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({}));
25792
+ const { STSClient: STSClient11, GetCallerIdentityCommand: GetCallerIdentityCommand12 } = await import("@aws-sdk/client-sts");
25793
+ const stsClient = new STSClient11({ region });
25794
+ const identity = await stsClient.send(new GetCallerIdentityCommand12({}));
25724
25795
  accountId = identity.Account;
25725
25796
  stsClient.destroy();
25726
25797
  }
@@ -26587,7 +26658,7 @@ var LockManager = class {
26587
26658
  this.logger.info(
26588
26659
  `Stack '${stackName}' (${region}) is locked by ${lockInfo2.owner}${lockInfo2.operation ? ` (operation: ${lockInfo2.operation})` : ""}. Lock expires in ${this.formatDuration(remainingMs)}. Retrying in ${this.formatDuration(retryDelay)}... (attempt ${attempt + 1}/${maxRetries})`
26589
26660
  );
26590
- await new Promise((resolve5) => setTimeout(resolve5, retryDelay));
26661
+ await new Promise((resolve6) => setTimeout(resolve6, retryDelay));
26591
26662
  continue;
26592
26663
  }
26593
26664
  }
@@ -26835,11 +26906,11 @@ var DagBuilder = class {
26835
26906
  const cycles = [];
26836
26907
  const visited = /* @__PURE__ */ new Set();
26837
26908
  const recursionStack = /* @__PURE__ */ new Set();
26838
- const path2 = [];
26909
+ const path3 = [];
26839
26910
  const dfs = (node) => {
26840
26911
  visited.add(node);
26841
26912
  recursionStack.add(node);
26842
- path2.push(node);
26913
+ path3.push(node);
26843
26914
  const successors = graph.successors(node) || [];
26844
26915
  for (const successor of successors) {
26845
26916
  if (!visited.has(successor)) {
@@ -26847,14 +26918,14 @@ var DagBuilder = class {
26847
26918
  return true;
26848
26919
  }
26849
26920
  } else if (recursionStack.has(successor)) {
26850
- const cycleStart = path2.indexOf(successor);
26851
- const cycle = path2.slice(cycleStart);
26921
+ const cycleStart = path3.indexOf(successor);
26922
+ const cycle = path3.slice(cycleStart);
26852
26923
  cycle.push(successor);
26853
26924
  cycles.push(cycle);
26854
26925
  return true;
26855
26926
  }
26856
26927
  }
26857
- path2.pop();
26928
+ path3.pop();
26858
26929
  recursionStack.delete(node);
26859
26930
  return false;
26860
26931
  };
@@ -28882,13 +28953,13 @@ var IAMInstanceProfileProvider = class {
28882
28953
  properties["InstanceProfileName"] || logicalId,
28883
28954
  { maxLength: 128 }
28884
28955
  );
28885
- const path2 = properties["Path"] || "/";
28956
+ const path3 = properties["Path"] || "/";
28886
28957
  const roles = properties["Roles"];
28887
28958
  try {
28888
28959
  const response = await this.iamClient.send(
28889
28960
  new CreateInstanceProfileCommand({
28890
28961
  InstanceProfileName: instanceProfileName,
28891
- Path: path2
28962
+ Path: path3
28892
28963
  })
28893
28964
  );
28894
28965
  this.logger.debug(`Created IAM instance profile: ${instanceProfileName}`);
@@ -35081,7 +35152,7 @@ var LambdaFunctionProvider = class {
35081
35152
  return enis;
35082
35153
  }
35083
35154
  sleep(ms) {
35084
- return new Promise((resolve5) => setTimeout(resolve5, ms));
35155
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
35085
35156
  }
35086
35157
  /**
35087
35158
  * Build Lambda Code parameter from CDK properties
@@ -36958,7 +37029,7 @@ var DynamoDBTableProvider = class {
36958
37029
  if (status !== "CREATING") {
36959
37030
  throw new Error(`Unexpected table status: ${status}`);
36960
37031
  }
36961
- await new Promise((resolve5) => setTimeout(resolve5, 1e3));
37032
+ await new Promise((resolve6) => setTimeout(resolve6, 1e3));
36962
37033
  }
36963
37034
  throw new Error(`Table ${tableName} did not reach ACTIVE status within ${maxAttempts} seconds`);
36964
37035
  }
@@ -36978,7 +37049,7 @@ var DynamoDBTableProvider = class {
36978
37049
  if (status === "ACTIVE") {
36979
37050
  return;
36980
37051
  }
36981
- await new Promise((resolve5) => setTimeout(resolve5, 1e3));
37052
+ await new Promise((resolve6) => setTimeout(resolve6, 1e3));
36982
37053
  }
36983
37054
  throw new Error(
36984
37055
  `Table ${tableName} did not reach ACTIVE status within ${maxAttempts} seconds after UpdateTable`
@@ -40158,7 +40229,7 @@ var EC2Provider = class {
40158
40229
  this.logger.debug(
40159
40230
  `VPC ${physicalId} has dependencies (attempt ${attempt}/${maxAttempts}), retrying in ${attempt * 5}s...`
40160
40231
  );
40161
- await new Promise((resolve5) => setTimeout(resolve5, attempt * 5e3));
40232
+ await new Promise((resolve6) => setTimeout(resolve6, attempt * 5e3));
40162
40233
  continue;
40163
40234
  }
40164
40235
  const cause = error instanceof Error ? error : void 0;
@@ -40322,7 +40393,7 @@ var EC2Provider = class {
40322
40393
  this.logger.debug(
40323
40394
  `Subnet ${physicalId} has dependencies (attempt ${attempt}/${maxAttempts}), retrying in ${attempt * 5}s...`
40324
40395
  );
40325
- await new Promise((resolve5) => setTimeout(resolve5, attempt * 5e3));
40396
+ await new Promise((resolve6) => setTimeout(resolve6, attempt * 5e3));
40326
40397
  continue;
40327
40398
  }
40328
40399
  const cause = error instanceof Error ? error : void 0;
@@ -41080,7 +41151,7 @@ var EC2Provider = class {
41080
41151
  this.logger.debug(
41081
41152
  `SecurityGroup ${physicalId} has dependent objects (attempt ${attempt}/${maxAttempts}), retrying in ${attempt * 5}s...`
41082
41153
  );
41083
- await new Promise((resolve5) => setTimeout(resolve5, attempt * 5e3));
41154
+ await new Promise((resolve6) => setTimeout(resolve6, attempt * 5e3));
41084
41155
  continue;
41085
41156
  }
41086
41157
  const cause = error instanceof Error ? error : void 0;
@@ -42024,7 +42095,7 @@ var EC2Provider = class {
42024
42095
  * `setTimeout` globally.
42025
42096
  */
42026
42097
  sleep(ms) {
42027
- return new Promise((resolve5) => setTimeout(resolve5, ms));
42098
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
42028
42099
  }
42029
42100
  /**
42030
42101
  * Check if an error indicates the resource was not found
@@ -43305,13 +43376,13 @@ var ApiGatewayProvider = class _ApiGatewayProvider {
43305
43376
  { key: "IdentityValidationExpression", path: "/identityValidationExpression" },
43306
43377
  { key: "AuthorizerResultTtlInSeconds", path: "/authorizerResultTtlInSeconds" }
43307
43378
  ];
43308
- for (const { key, path: path2 } of primitiveFields) {
43379
+ for (const { key, path: path3 } of primitiveFields) {
43309
43380
  const newVal = properties[key];
43310
43381
  const prevVal = previousProperties[key];
43311
43382
  if (newVal !== prevVal) {
43312
43383
  patchOperations.push({
43313
43384
  op: "replace",
43314
- path: path2,
43385
+ path: path3,
43315
43386
  value: newVal !== void 0 ? String(newVal) : ""
43316
43387
  });
43317
43388
  }
@@ -43947,13 +44018,13 @@ var ApiGatewayProvider = class _ApiGatewayProvider {
43947
44018
  { key: "OperationName", path: "/operationName" },
43948
44019
  { key: "RequestValidatorId", path: "/requestValidatorId" }
43949
44020
  ];
43950
- for (const { key, path: path2 } of primitiveFields) {
44021
+ for (const { key, path: path3 } of primitiveFields) {
43951
44022
  const newVal = properties[key];
43952
44023
  const prevVal = previousProperties[key];
43953
44024
  if (newVal !== prevVal) {
43954
44025
  patchOperations.push({
43955
44026
  op: "replace",
43956
- path: path2,
44027
+ path: path3,
43957
44028
  value: newVal !== void 0 ? String(newVal) : ""
43958
44029
  });
43959
44030
  }
@@ -44124,7 +44195,7 @@ var ApiGatewayProvider = class _ApiGatewayProvider {
44124
44195
  * Sleep for specified milliseconds
44125
44196
  */
44126
44197
  sleep(ms) {
44127
- return new Promise((resolve5) => setTimeout(resolve5, ms));
44198
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
44128
44199
  }
44129
44200
  /**
44130
44201
  * Convert CloudFormation Tags (Array<{Key, Value}>) to SDK tags (Record<string, string>).
@@ -44326,12 +44397,12 @@ var ApiGatewayProvider = class _ApiGatewayProvider {
44326
44397
  function appendMapPatchOps(ops, basePath, next, prev) {
44327
44398
  const escape = (k) => k.replace(/~/g, "~0").replace(/\//g, "~1");
44328
44399
  for (const [key, val] of Object.entries(next)) {
44329
- const path2 = `${basePath}/${escape(key)}`;
44400
+ const path3 = `${basePath}/${escape(key)}`;
44330
44401
  const stringValue = String(val);
44331
44402
  if (!(key in prev)) {
44332
- ops.push({ op: "add", path: path2, value: stringValue });
44403
+ ops.push({ op: "add", path: path3, value: stringValue });
44333
44404
  } else if (String(prev[key]) !== stringValue) {
44334
- ops.push({ op: "replace", path: path2, value: stringValue });
44405
+ ops.push({ op: "replace", path: path3, value: stringValue });
44335
44406
  }
44336
44407
  }
44337
44408
  for (const key of Object.keys(prev)) {
@@ -46016,7 +46087,7 @@ var CloudFrontDistributionProvider = class {
46016
46087
  );
46017
46088
  const sleepEnd = Date.now() + delay2;
46018
46089
  while (Date.now() < sleepEnd && !interrupted) {
46019
- await new Promise((resolve5) => setTimeout(resolve5, 1e3));
46090
+ await new Promise((resolve6) => setTimeout(resolve6, 1e3));
46020
46091
  }
46021
46092
  delay2 = Math.min(delay2 * 1.5, maxDelay);
46022
46093
  }
@@ -46136,17 +46207,17 @@ var CloudFrontDistributionProvider = class {
46136
46207
  /**
46137
46208
  * Apply Quantity wrapping at a nested path (e.g., "ForwardedValues.Headers").
46138
46209
  */
46139
- applyQuantityAtPath(obj, path2) {
46140
- if (path2.length === 0)
46210
+ applyQuantityAtPath(obj, path3) {
46211
+ if (path3.length === 0)
46141
46212
  return;
46142
- if (path2.length === 1) {
46143
- const key = path2[0];
46213
+ if (path3.length === 1) {
46214
+ const key = path3[0];
46144
46215
  if (obj[key] !== void 0) {
46145
46216
  obj[key] = this.wrapWithQuantity(obj[key]);
46146
46217
  }
46147
46218
  return;
46148
46219
  }
46149
- const [head, ...rest] = path2;
46220
+ const [head, ...rest] = path3;
46150
46221
  const headKey = head;
46151
46222
  if (obj[headKey] && typeof obj[headKey] === "object") {
46152
46223
  const nested = { ...obj[headKey] };
@@ -49828,7 +49899,7 @@ var RDSProvider = class {
49828
49899
  throw new Error(`Timed out waiting for DBInstance ${dbInstanceIdentifier} to be deleted`);
49829
49900
  }
49830
49901
  sleep(ms) {
49831
- return new Promise((resolve5) => setTimeout(resolve5, ms));
49902
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
49832
49903
  }
49833
49904
  /**
49834
49905
  * Adopt an existing RDS resource into cdkd state.
@@ -50813,7 +50884,7 @@ var DocDBProvider = class {
50813
50884
  throw new Error(`Timed out waiting for DocDB DBInstance ${dbInstanceIdentifier} to be deleted`);
50814
50885
  }
50815
50886
  sleep(ms) {
50816
- return new Promise((resolve5) => setTimeout(resolve5, ms));
50887
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
50817
50888
  }
50818
50889
  /**
50819
50890
  * Adopt an existing DocDB resource into cdkd state.
@@ -51803,7 +51874,7 @@ var NeptuneProvider = class {
51803
51874
  );
51804
51875
  }
51805
51876
  sleep(ms) {
51806
- return new Promise((resolve5) => setTimeout(resolve5, ms));
51877
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
51807
51878
  }
51808
51879
  /**
51809
51880
  * Adopt an existing Neptune resource into cdkd state.
@@ -54343,7 +54414,7 @@ var ElastiCacheProvider = class {
54343
54414
  throw new Error(`Timed out waiting for CacheCluster ${cacheClusterId} to be deleted`);
54344
54415
  }
54345
54416
  sleep(ms) {
54346
- return new Promise((resolve5) => setTimeout(resolve5, ms));
54417
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
54347
54418
  }
54348
54419
  /**
54349
54420
  * Read the AWS-current ElastiCache resource configuration in CFn-property shape.
@@ -55058,7 +55129,7 @@ var ServiceDiscoveryProvider = class {
55058
55129
  logicalId
55059
55130
  );
55060
55131
  }
55061
- await new Promise((resolve5) => setTimeout(resolve5, delay2));
55132
+ await new Promise((resolve6) => setTimeout(resolve6, delay2));
55062
55133
  delay2 = Math.min(delay2 * 2, 1e4);
55063
55134
  }
55064
55135
  throw new ProvisioningError(
@@ -59583,7 +59654,7 @@ var KinesisStreamProvider = class {
59583
59654
  if (status !== "CREATING" && status !== "UPDATING") {
59584
59655
  throw new Error(`Unexpected stream status: ${status}`);
59585
59656
  }
59586
- await new Promise((resolve5) => setTimeout(resolve5, 2e3));
59657
+ await new Promise((resolve6) => setTimeout(resolve6, 2e3));
59587
59658
  }
59588
59659
  throw new Error(
59589
59660
  `Stream ${streamName} did not reach ACTIVE status within ${maxAttempts * 2} seconds`
@@ -59916,7 +59987,7 @@ var KinesisStreamConsumerProvider = class {
59916
59987
  if (status !== "CREATING") {
59917
59988
  throw new Error(`Unexpected consumer status: ${status}`);
59918
59989
  }
59919
- await new Promise((resolve5) => setTimeout(resolve5, 1e3));
59990
+ await new Promise((resolve6) => setTimeout(resolve6, 1e3));
59920
59991
  }
59921
59992
  throw new Error(
59922
59993
  `Consumer ${consumerArn} did not reach ACTIVE status within ${maxAttempts} seconds`
@@ -60221,7 +60292,7 @@ var EFSProvider = class {
60221
60292
  this.logger.debug(
60222
60293
  `FileSystem ${fileSystemId} state: ${fs?.LifeCycleState ?? "unknown"}, waiting...`
60223
60294
  );
60224
- await new Promise((resolve5) => setTimeout(resolve5, pollIntervalMs));
60295
+ await new Promise((resolve6) => setTimeout(resolve6, pollIntervalMs));
60225
60296
  }
60226
60297
  throw new ProvisioningError(
60227
60298
  `Timed out waiting for EFS FileSystem ${fileSystemId} to become available (60s)`,
@@ -60299,7 +60370,7 @@ var EFSProvider = class {
60299
60370
  this.logger.debug(
60300
60371
  `MountTarget ${mountTargetId} state: ${mountTarget?.LifeCycleState ?? "unknown"}, waiting...`
60301
60372
  );
60302
- await new Promise((resolve5) => setTimeout(resolve5, pollIntervalMs));
60373
+ await new Promise((resolve6) => setTimeout(resolve6, pollIntervalMs));
60303
60374
  }
60304
60375
  throw new ProvisioningError(
60305
60376
  `Timed out waiting for EFS MountTarget ${mountTargetId} to become available (120s)`,
@@ -60365,7 +60436,7 @@ var EFSProvider = class {
60365
60436
  }
60366
60437
  throw error;
60367
60438
  }
60368
- await new Promise((resolve5) => setTimeout(resolve5, pollIntervalMs));
60439
+ await new Promise((resolve6) => setTimeout(resolve6, pollIntervalMs));
60369
60440
  }
60370
60441
  this.logger.warn(
60371
60442
  `Timed out waiting for EFS MountTarget ${mountTargetId} deletion for ${logicalId} (120s)`
@@ -61323,7 +61394,7 @@ var FirehoseProvider = class {
61323
61394
  this.logger.debug(
61324
61395
  `Firehose ${logicalId} status: ${status} (attempt ${attempt}/${maxAttempts})`
61325
61396
  );
61326
- await new Promise((resolve5) => setTimeout(resolve5, 2e3));
61397
+ await new Promise((resolve6) => setTimeout(resolve6, 2e3));
61327
61398
  }
61328
61399
  this.logger.warn(`Firehose ${logicalId} did not reach ACTIVE after ${maxAttempts} attempts`);
61329
61400
  }
@@ -64793,7 +64864,7 @@ var ASGProvider = class {
64793
64864
  );
64794
64865
  }
64795
64866
  sleep(ms) {
64796
- return new Promise((resolve5) => setTimeout(resolve5, ms));
64867
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
64797
64868
  }
64798
64869
  // ─── Sub-shape diff helpers ───────────────────────────────────────
64799
64870
  // Each helper is a no-op when before/after JSON is identical (the cheap
@@ -65303,11 +65374,11 @@ async function deployCommand(stacks, options) {
65303
65374
  addDependencies(stack.stackName);
65304
65375
  }
65305
65376
  }
65306
- const { STSClient: STSClient10, GetCallerIdentityCommand: GetCallerIdentityCommand11 } = await import("@aws-sdk/client-sts");
65307
- const stsClient = new STSClient10({
65377
+ const { STSClient: STSClient11, GetCallerIdentityCommand: GetCallerIdentityCommand12 } = await import("@aws-sdk/client-sts");
65378
+ const stsClient = new STSClient11({
65308
65379
  region: options.region || process.env["AWS_REGION"] || "us-east-1"
65309
65380
  });
65310
- const callerIdentity = await stsClient.send(new GetCallerIdentityCommand11({}));
65381
+ const callerIdentity = await stsClient.send(new GetCallerIdentityCommand12({}));
65311
65382
  const accountId = callerIdentity.Account;
65312
65383
  stsClient.destroy();
65313
65384
  const assetPublisher = new AssetPublisher();
@@ -65714,29 +65785,29 @@ function calculateResourceDrift(stateProperties, awsProperties, options) {
65714
65785
  }
65715
65786
  return drifts;
65716
65787
  }
65717
- function isIgnoredPath(path2, ignorePaths) {
65788
+ function isIgnoredPath(path3, ignorePaths) {
65718
65789
  for (const entry of ignorePaths) {
65719
- if (path2 === entry)
65790
+ if (path3 === entry)
65720
65791
  return true;
65721
- if (path2.startsWith(`${entry}.`))
65792
+ if (path3.startsWith(`${entry}.`))
65722
65793
  return true;
65723
65794
  }
65724
65795
  return false;
65725
65796
  }
65726
- function diffAt(path2, stateValue, awsValue, out, ignorePaths, unionWalkObjects) {
65797
+ function diffAt(path3, stateValue, awsValue, out, ignorePaths, unionWalkObjects) {
65727
65798
  if (deepEqual(stateValue, awsValue))
65728
65799
  return;
65729
65800
  if (isPlainObject(stateValue) && isPlainObject(awsValue) && !Array.isArray(stateValue) && !Array.isArray(awsValue)) {
65730
65801
  const keys = unionWalkObjects ? /* @__PURE__ */ new Set([...Object.keys(stateValue), ...Object.keys(awsValue)]) : Object.keys(stateValue);
65731
65802
  for (const key of keys) {
65732
- const childPath = `${path2}.${key}`;
65803
+ const childPath = `${path3}.${key}`;
65733
65804
  if (isIgnoredPath(childPath, ignorePaths))
65734
65805
  continue;
65735
65806
  diffAt(childPath, stateValue[key], awsValue[key], out, ignorePaths, unionWalkObjects);
65736
65807
  }
65737
65808
  return;
65738
65809
  }
65739
- out.push({ path: path2, stateValue, awsValue });
65810
+ out.push({ path: path3, stateValue, awsValue });
65740
65811
  }
65741
65812
  function deepEqual(a, b) {
65742
65813
  if (a === b)
@@ -66139,11 +66210,11 @@ async function runDriftForStack(stackName, region, stateBackend, providerRegistr
66139
66210
  };
66140
66211
  });
66141
66212
  }
66142
- function setAtPath(target, path2, value) {
66143
- if (path2.length === 0) {
66213
+ function setAtPath(target, path3, value) {
66214
+ if (path3.length === 0) {
66144
66215
  return;
66145
66216
  }
66146
- const segments = path2.split(".");
66217
+ const segments = path3.split(".");
66147
66218
  let cursor = target;
66148
66219
  for (let i = 0; i < segments.length - 1; i++) {
66149
66220
  const key = segments[i];
@@ -66733,7 +66804,7 @@ Acquiring lock for stack ${stackName}...`);
66733
66804
  logger.debug(
66734
66805
  ` \u23F3 Retrying delete ${logicalId} in ${delay2 / 1e3}s (attempt ${attempt + 1}/${maxAttempts})`
66735
66806
  );
66736
- await new Promise((resolve5) => setTimeout(resolve5, delay2));
66807
+ await new Promise((resolve6) => setTimeout(resolve6, delay2));
66737
66808
  }
66738
66809
  }
66739
66810
  if (lastDeleteError)
@@ -67043,19 +67114,19 @@ function buildCdkPathIndex(template) {
67043
67114
  for (const [logicalId, resource] of Object.entries(template.Resources)) {
67044
67115
  if (resource.Type === "AWS::CDK::Metadata")
67045
67116
  continue;
67046
- const path2 = readCdkPath(resource);
67047
- if (path2)
67048
- index.set(path2, logicalId);
67117
+ const path3 = readCdkPath(resource);
67118
+ if (path3)
67119
+ index.set(path3, logicalId);
67049
67120
  }
67050
67121
  return index;
67051
67122
  }
67052
67123
  function resolveCdkPathToLogicalIds(input, index) {
67053
67124
  const seen = /* @__PURE__ */ new Map();
67054
67125
  const prefix = `${input}/`;
67055
- for (const [path2, logicalId] of index) {
67056
- if (path2 === input || path2.startsWith(prefix)) {
67126
+ for (const [path3, logicalId] of index) {
67127
+ if (path3 === input || path3.startsWith(prefix)) {
67057
67128
  if (!seen.has(logicalId))
67058
- seen.set(logicalId, path2);
67129
+ seen.set(logicalId, path3);
67059
67130
  }
67060
67131
  }
67061
67132
  return [...seen.entries()].map(([logicalId, cdkPath]) => ({ logicalId, cdkPath }));
@@ -67780,9 +67851,9 @@ async function publishAssetsCommand(stacks, options) {
67780
67851
  );
67781
67852
  }
67782
67853
  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({}));
67854
+ const { STSClient: STSClient11, GetCallerIdentityCommand: GetCallerIdentityCommand12 } = await import("@aws-sdk/client-sts");
67855
+ const stsClient = new STSClient11({ region: baseRegion });
67856
+ const callerIdentity = await stsClient.send(new GetCallerIdentityCommand12({}));
67786
67857
  const accountId = callerIdentity.Account;
67787
67858
  stsClient.destroy();
67788
67859
  const assetPublisher = new AssetPublisher();
@@ -69963,12 +70034,13 @@ async function captureObservedForImportedResources(stackState, providerRegistry,
69963
70034
  }
69964
70035
 
69965
70036
  // src/cli/commands/local-invoke.ts
69966
- import { mkdtempSync as mkdtempSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
69967
- import { tmpdir as tmpdir2 } from "node:os";
69968
- import * as path from "node:path";
69969
- import { Command as Command14, Option as Option7 } from "commander";
70037
+ import { mkdtempSync as mkdtempSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync7, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "node:fs";
70038
+ import { tmpdir as tmpdir3 } from "node:os";
70039
+ import { dirname as dirname3 } from "node:path";
70040
+ import * as path2 from "node:path";
70041
+ import { Command as Command15, Option as Option8 } from "commander";
69970
70042
 
69971
- // src/local-invoke/lambda-resolver.ts
70043
+ // src/local/lambda-resolver.ts
69972
70044
  import { existsSync as existsSync4, statSync as statSync3 } from "node:fs";
69973
70045
  import { dirname, isAbsolute, resolve as resolve4 } from "node:path";
69974
70046
  var LocalInvokeResolutionError = class _LocalInvokeResolutionError extends Error {
@@ -70067,25 +70139,38 @@ function pickStack(parsed, stacks) {
70067
70139
  }
70068
70140
  function extractLambdaProperties(stack, logicalId, resource) {
70069
70141
  const props = resource.Properties ?? {};
70070
- const runtime = typeof props["Runtime"] === "string" ? props["Runtime"] : "";
70071
- const handler = typeof props["Handler"] === "string" ? props["Handler"] : "";
70072
70142
  const memoryMb = typeof props["MemorySize"] === "number" ? props["MemorySize"] : 128;
70073
70143
  const timeoutSec = typeof props["Timeout"] === "number" ? props["Timeout"] : 3;
70144
+ const code = props["Code"] ?? {};
70145
+ const imageUri = extractImageUri(code["ImageUri"]);
70146
+ if (imageUri !== void 0) {
70147
+ return extractImageLambdaProperties({
70148
+ stack,
70149
+ logicalId,
70150
+ resource,
70151
+ memoryMb,
70152
+ timeoutSec,
70153
+ props,
70154
+ imageUri
70155
+ });
70156
+ }
70157
+ const runtime = typeof props["Runtime"] === "string" ? props["Runtime"] : "";
70158
+ const handler = typeof props["Handler"] === "string" ? props["Handler"] : "";
70074
70159
  if (!runtime) {
70075
70160
  throw new LocalInvokeResolutionError(
70076
- `Lambda '${logicalId}' has no Runtime property. Container-image Lambdas (Code.ImageUri) are not supported in cdkd local invoke v1.`
70161
+ `Lambda '${logicalId}' has no Runtime property and no Code.ImageUri. cdkd cannot tell if this is a ZIP or a container Lambda.`
70077
70162
  );
70078
70163
  }
70079
70164
  if (!handler) {
70080
70165
  throw new LocalInvokeResolutionError(`Lambda '${logicalId}' has no Handler property.`);
70081
70166
  }
70082
- const code = props["Code"] ?? {};
70083
70167
  const inlineCode = typeof code["ZipFile"] === "string" ? code["ZipFile"] : void 0;
70084
70168
  let codePath = null;
70085
70169
  if (!inlineCode) {
70086
70170
  codePath = resolveAssetCodePath(stack, logicalId, resource);
70087
70171
  }
70088
70172
  return {
70173
+ kind: "zip",
70089
70174
  stack,
70090
70175
  logicalId,
70091
70176
  resource,
@@ -70097,6 +70182,62 @@ function extractLambdaProperties(stack, logicalId, resource) {
70097
70182
  ...inlineCode !== void 0 && { inlineCode }
70098
70183
  };
70099
70184
  }
70185
+ function extractImageUri(value) {
70186
+ if (typeof value === "string" && value.length > 0)
70187
+ return value;
70188
+ if (value && typeof value === "object" && !Array.isArray(value)) {
70189
+ const obj = value;
70190
+ const sub = obj["Fn::Sub"];
70191
+ if (typeof sub === "string" && sub.length > 0)
70192
+ return sub;
70193
+ if (Array.isArray(sub) && typeof sub[0] === "string")
70194
+ return sub[0];
70195
+ }
70196
+ return void 0;
70197
+ }
70198
+ function extractImageLambdaProperties(args) {
70199
+ const { stack, logicalId, resource, memoryMb, timeoutSec, props, imageUri } = args;
70200
+ const rawImageConfig = props["ImageConfig"] ?? {};
70201
+ const imageConfig = {};
70202
+ if (Array.isArray(rawImageConfig["Command"])) {
70203
+ imageConfig.command = rawImageConfig["Command"].filter(
70204
+ (s) => typeof s === "string"
70205
+ );
70206
+ }
70207
+ if (Array.isArray(rawImageConfig["EntryPoint"])) {
70208
+ imageConfig.entryPoint = rawImageConfig["EntryPoint"].filter(
70209
+ (s) => typeof s === "string"
70210
+ );
70211
+ }
70212
+ if (typeof rawImageConfig["WorkingDirectory"] === "string") {
70213
+ imageConfig.workingDirectory = rawImageConfig["WorkingDirectory"];
70214
+ }
70215
+ const arches = props["Architectures"];
70216
+ let architecture = "x86_64";
70217
+ if (Array.isArray(arches) && arches.length > 0) {
70218
+ const first = arches[0];
70219
+ if (first === "arm64")
70220
+ architecture = "arm64";
70221
+ else if (first === "x86_64")
70222
+ architecture = "x86_64";
70223
+ else {
70224
+ throw new LocalInvokeResolutionError(
70225
+ `Lambda '${logicalId}' has unsupported Architectures value '${String(first)}'. cdkd local invoke supports x86_64 and arm64.`
70226
+ );
70227
+ }
70228
+ }
70229
+ return {
70230
+ kind: "image",
70231
+ stack,
70232
+ logicalId,
70233
+ resource,
70234
+ memoryMb,
70235
+ timeoutSec,
70236
+ imageUri,
70237
+ imageConfig,
70238
+ architecture
70239
+ };
70240
+ }
70100
70241
  function resolveAssetCodePath(stack, logicalId, resource) {
70101
70242
  const meta = resource.Metadata;
70102
70243
  const assetPath = meta?.["aws:asset:path"];
@@ -70140,7 +70281,7 @@ function notFoundError(target, stack, resources) {
70140
70281
  return new LocalInvokeResolutionError(msg.trimEnd());
70141
70282
  }
70142
70283
 
70143
- // src/local-invoke/env-resolver.ts
70284
+ // src/local/env-resolver.ts
70144
70285
  function resolveEnvVars(logicalId, templateEnv, overrides) {
70145
70286
  const resolved = {};
70146
70287
  const unresolved = [];
@@ -70177,7 +70318,7 @@ function isLiteralEnvValue(value) {
70177
70318
  return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
70178
70319
  }
70179
70320
 
70180
- // src/local-invoke/state-resolver.ts
70321
+ // src/local/state-resolver.ts
70181
70322
  function substituteAgainstState(value, resources) {
70182
70323
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
70183
70324
  return { kind: "literal", value };
@@ -70354,7 +70495,7 @@ function substituteEnvVarsFromState(templateEnv, resources) {
70354
70495
  return { env, audit };
70355
70496
  }
70356
70497
 
70357
- // src/local-invoke/runtime-image.ts
70498
+ // src/local/runtime-image.ts
70358
70499
  var SUPPORTED_RUNTIMES = {
70359
70500
  "nodejs18.x": { image: "public.ecr.aws/lambda/nodejs:18", fileExtension: ".js" },
70360
70501
  "nodejs20.x": { image: "public.ecr.aws/lambda/nodejs:20", fileExtension: ".js" },
@@ -70381,7 +70522,7 @@ function resolveRuntimeSpec(runtime) {
70381
70522
  if (typeof runtime !== "string" || runtime.length === 0) {
70382
70523
  throw new UnsupportedRuntimeError(
70383
70524
  String(runtime),
70384
- "Lambda function has no Runtime property. Container-image Lambdas (Code.ImageUri) are not supported in cdkd local invoke v1."
70525
+ "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."
70385
70526
  );
70386
70527
  }
70387
70528
  const spec = SUPPORTED_RUNTIMES[runtime];
@@ -70399,11 +70540,11 @@ function resolveRuntimeSpec(runtime) {
70399
70540
  );
70400
70541
  }
70401
70542
 
70402
- // src/local-invoke/docker-runner.ts
70403
- import { execFile as execFile2, spawn as spawn3 } from "node:child_process";
70543
+ // src/local/docker-runner.ts
70544
+ import { execFile as execFile3, spawn as spawn3 } from "node:child_process";
70404
70545
  import { createServer } from "node:net";
70405
- import { promisify as promisify2 } from "node:util";
70406
- var execFileAsync2 = promisify2(execFile2);
70546
+ import { promisify as promisify3 } from "node:util";
70547
+ var execFileAsync3 = promisify3(execFile3);
70407
70548
  var DockerRunnerError = class _DockerRunnerError extends Error {
70408
70549
  constructor(message) {
70409
70550
  super(message);
@@ -70422,6 +70563,12 @@ async function pullImage(image, skipPull) {
70422
70563
  }
70423
70564
  async function runDetached(opts) {
70424
70565
  const args = ["run", "-d", "--rm"];
70566
+ if (opts.name) {
70567
+ args.push("--name", opts.name);
70568
+ }
70569
+ if (opts.platform) {
70570
+ args.push("--platform", opts.platform);
70571
+ }
70425
70572
  const host = opts.host ?? "127.0.0.1";
70426
70573
  args.push("-p", `${host}:${opts.hostPort}:8080`);
70427
70574
  if (opts.debugPort !== void 0) {
@@ -70434,11 +70581,19 @@ async function runDetached(opts) {
70434
70581
  for (const [k, v] of Object.entries(opts.env)) {
70435
70582
  args.push("-e", `${k}=${v}`);
70436
70583
  }
70437
- args.push(opts.image, ...opts.cmd);
70584
+ if (opts.workingDir) {
70585
+ args.push("--workdir", opts.workingDir);
70586
+ }
70587
+ let entryPointTail = [];
70588
+ if (opts.entryPoint && opts.entryPoint.length > 0) {
70589
+ args.push("--entrypoint", opts.entryPoint[0]);
70590
+ entryPointTail = opts.entryPoint.slice(1);
70591
+ }
70592
+ args.push(opts.image, ...entryPointTail, ...opts.cmd);
70438
70593
  const logger = getLogger().child("docker");
70439
- logger.debug(`docker ${args.join(" ")}`);
70594
+ logger.debug(`docker ${redactAwsCredentialsInArgs(args).join(" ")}`);
70440
70595
  try {
70441
- const { stdout } = await execFileAsync2("docker", args, {
70596
+ const { stdout } = await execFileAsync3("docker", args, {
70442
70597
  maxBuffer: 10 * 1024 * 1024
70443
70598
  });
70444
70599
  return stdout.trim();
@@ -70467,7 +70622,7 @@ async function removeContainer(containerId) {
70467
70622
  return;
70468
70623
  const logger = getLogger().child("docker");
70469
70624
  try {
70470
- await execFileAsync2("docker", ["rm", "-f", containerId]);
70625
+ await execFileAsync3("docker", ["rm", "-f", containerId]);
70471
70626
  logger.debug(`Removed container ${containerId}`);
70472
70627
  } catch (error) {
70473
70628
  const err = error;
@@ -70478,7 +70633,7 @@ async function removeContainer(containerId) {
70478
70633
  }
70479
70634
  async function ensureDockerAvailable() {
70480
70635
  try {
70481
- await execFileAsync2("docker", ["version", "--format", "{{.Server.Version}}"]);
70636
+ await execFileAsync3("docker", ["version", "--format", "{{.Server.Version}}"]);
70482
70637
  } catch (error) {
70483
70638
  const err = error;
70484
70639
  if (err.code === "ENOENT") {
@@ -70508,6 +70663,31 @@ function pickFreePort() {
70508
70663
  });
70509
70664
  });
70510
70665
  }
70666
+ var REDACTED_ENV_KEYS = /* @__PURE__ */ new Set([
70667
+ "AWS_ACCESS_KEY_ID",
70668
+ "AWS_SECRET_ACCESS_KEY",
70669
+ "AWS_SESSION_TOKEN"
70670
+ ]);
70671
+ function redactAwsCredentialsInArgs(args) {
70672
+ const out = [];
70673
+ for (let i = 0; i < args.length; i++) {
70674
+ const cur = args[i];
70675
+ const next = args[i + 1];
70676
+ if (cur === "-e" && typeof next === "string") {
70677
+ const eqIdx = next.indexOf("=");
70678
+ if (eqIdx > 0) {
70679
+ const key = next.substring(0, eqIdx);
70680
+ if (REDACTED_ENV_KEYS.has(key)) {
70681
+ out.push("-e", `${key}=***`);
70682
+ i++;
70683
+ continue;
70684
+ }
70685
+ }
70686
+ }
70687
+ out.push(cur);
70688
+ }
70689
+ return out;
70690
+ }
70511
70691
  function runForeground(cmd, args) {
70512
70692
  return new Promise((resolveProc, rejectProc) => {
70513
70693
  const proc = spawn3(cmd, args, { stdio: "inherit" });
@@ -70521,7 +70701,164 @@ function runForeground(cmd, args) {
70521
70701
  });
70522
70702
  }
70523
70703
 
70524
- // src/local-invoke/rie-client.ts
70704
+ // src/local/docker-image-builder.ts
70705
+ import { createHash as createHash2 } from "node:crypto";
70706
+ async function buildContainerImage(asset, cdkOutDir, options) {
70707
+ const tag = computeLocalTag(asset.source);
70708
+ const platform = architectureToPlatform(options.architecture);
70709
+ const logger = getLogger().child("local-invoke-build");
70710
+ logger.info(`Building container image (platform=${platform})...`);
70711
+ logger.debug(`Local tag: ${tag}`);
70712
+ await buildDockerImage(asset, cdkOutDir, tag, {
70713
+ platform,
70714
+ wrapError: (stderr) => new LocalInvokeBuildError(
70715
+ `docker build failed for container Lambda asset (${asset.source.directory}): ${stderr}`
70716
+ )
70717
+ });
70718
+ return tag;
70719
+ }
70720
+ function architectureToPlatform(architecture) {
70721
+ return architecture === "arm64" ? "linux/arm64" : "linux/amd64";
70722
+ }
70723
+ function computeLocalTag(source) {
70724
+ const hash = createHash2("sha256");
70725
+ hash.update(source.directory);
70726
+ hash.update("\0");
70727
+ hash.update(source.dockerFile ?? "");
70728
+ hash.update("\0");
70729
+ hash.update(source.dockerBuildTarget ?? "");
70730
+ hash.update("\0");
70731
+ if (source.dockerBuildArgs) {
70732
+ for (const [k, v] of Object.entries(source.dockerBuildArgs)) {
70733
+ hash.update(k);
70734
+ hash.update("=");
70735
+ hash.update(v);
70736
+ hash.update("\0");
70737
+ }
70738
+ }
70739
+ return `cdkd-local-invoke-${hash.digest("hex").slice(0, 16)}`;
70740
+ }
70741
+
70742
+ // src/local/ecr-puller.ts
70743
+ import { execFile as execFile4, spawn as spawn4 } from "node:child_process";
70744
+ import { promisify as promisify4 } from "node:util";
70745
+ import { ECRClient as ECRClient3, GetAuthorizationTokenCommand as GetAuthorizationTokenCommand2 } from "@aws-sdk/client-ecr";
70746
+ import { GetCallerIdentityCommand as GetCallerIdentityCommand11, STSClient as STSClient10 } from "@aws-sdk/client-sts";
70747
+ var execFileAsync4 = promisify4(execFile4);
70748
+ var ECR_URI_REGEX = /^(\d{12})\.dkr\.ecr\.([^.]+)\.amazonaws\.com(?:\.cn)?\/([^:]+):(.+)$/;
70749
+ function parseEcrUri(imageUri) {
70750
+ const m = ECR_URI_REGEX.exec(imageUri);
70751
+ if (!m)
70752
+ return void 0;
70753
+ return {
70754
+ accountId: m[1],
70755
+ region: m[2],
70756
+ repository: m[3],
70757
+ tag: m[4]
70758
+ };
70759
+ }
70760
+ async function pullEcrImage(imageUri, options) {
70761
+ const logger = getLogger().child("ecr-puller");
70762
+ const parsed = parseEcrUri(imageUri);
70763
+ if (!parsed) {
70764
+ throw new LocalInvokeBuildError(
70765
+ `Image URI '${imageUri}' is not an ECR URI. cdkd local invoke v1 only authenticates against ECR for the deployed-image fallback path.`
70766
+ );
70767
+ }
70768
+ const sts = new STSClient10({ region: parsed.region });
70769
+ let callerAccount;
70770
+ try {
70771
+ const identity = await sts.send(new GetCallerIdentityCommand11({}));
70772
+ if (!identity.Account) {
70773
+ throw new LocalInvokeBuildError(
70774
+ "STS GetCallerIdentity returned no Account. Verify your AWS credentials."
70775
+ );
70776
+ }
70777
+ callerAccount = identity.Account;
70778
+ } finally {
70779
+ sts.destroy();
70780
+ }
70781
+ if (callerAccount !== parsed.accountId) {
70782
+ throw new LocalInvokeBuildError(
70783
+ `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).`
70784
+ );
70785
+ }
70786
+ const callerRegion = options.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"];
70787
+ if (callerRegion && callerRegion !== parsed.region) {
70788
+ throw new LocalInvokeBuildError(
70789
+ `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.`
70790
+ );
70791
+ }
70792
+ if (options.skipPull) {
70793
+ logger.info(`Skipping ECR pull (--no-pull). Verifying ${imageUri} is in local cache...`);
70794
+ await verifyImageInLocalCache(imageUri);
70795
+ return imageUri;
70796
+ }
70797
+ const ecr = new ECRClient3({ region: parsed.region });
70798
+ try {
70799
+ await ecrLogin(ecr, parsed.accountId, parsed.region);
70800
+ } finally {
70801
+ ecr.destroy();
70802
+ }
70803
+ logger.info(`Pulling ${imageUri}...`);
70804
+ await runForeground2("docker", ["pull", imageUri]);
70805
+ return imageUri;
70806
+ }
70807
+ async function ecrLogin(client, accountId, region) {
70808
+ const logger = getLogger().child("ecr-puller");
70809
+ logger.debug(`ECR login (account=${accountId}, region=${region})`);
70810
+ const response = await client.send(new GetAuthorizationTokenCommand2({}));
70811
+ const authData = response.authorizationData?.[0];
70812
+ if (!authData?.authorizationToken) {
70813
+ throw new LocalInvokeBuildError("Failed to get ECR authorization token");
70814
+ }
70815
+ const token = Buffer.from(authData.authorizationToken, "base64").toString();
70816
+ const [username, password] = token.split(":");
70817
+ const endpoint = authData.proxyEndpoint || `https://${accountId}.dkr.ecr.${region}.amazonaws.com`;
70818
+ await new Promise((resolve6, reject) => {
70819
+ const proc = spawn4("docker", ["login", "--username", username, "--password-stdin", endpoint], {
70820
+ stdio: ["pipe", "pipe", "pipe"]
70821
+ });
70822
+ let stderr = "";
70823
+ proc.stderr?.on("data", (data) => {
70824
+ stderr += data.toString();
70825
+ });
70826
+ proc.on("close", (code) => {
70827
+ if (code === 0)
70828
+ resolve6();
70829
+ else
70830
+ reject(new LocalInvokeBuildError(`ECR login failed: ${stderr.trim()}`));
70831
+ });
70832
+ proc.on("error", (err) => {
70833
+ reject(new LocalInvokeBuildError(`ECR login failed: ${err.message}`));
70834
+ });
70835
+ proc.stdin?.write(password);
70836
+ proc.stdin?.end();
70837
+ });
70838
+ }
70839
+ async function verifyImageInLocalCache(imageUri) {
70840
+ try {
70841
+ await execFileAsync4("docker", ["image", "inspect", imageUri]);
70842
+ } catch {
70843
+ throw new LocalInvokeBuildError(
70844
+ `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\`.`
70845
+ );
70846
+ }
70847
+ }
70848
+ function runForeground2(cmd, args) {
70849
+ return new Promise((resolve6, reject) => {
70850
+ const proc = spawn4(cmd, args, { stdio: "inherit" });
70851
+ proc.on("error", (err) => reject(new LocalInvokeBuildError(`${cmd} failed: ${err.message}`)));
70852
+ proc.on("close", (code) => {
70853
+ if (code === 0)
70854
+ resolve6();
70855
+ else
70856
+ reject(new LocalInvokeBuildError(`${cmd} exited with code ${code}`));
70857
+ });
70858
+ });
70859
+ }
70860
+
70861
+ // src/local/rie-client.ts
70525
70862
  import { setTimeout as delay } from "node:timers/promises";
70526
70863
  var INVOKE_PATH = "/2015-03-31/functions/function/invocations";
70527
70864
  async function waitForRieReady(host, port, timeoutMs = 5e3) {
@@ -70630,9 +70967,1301 @@ async function fetchWithStartupRetry(url, body, signal) {
70630
70967
  throw lastError;
70631
70968
  }
70632
70969
 
70970
+ // src/assets/asset-manifest-loader.ts
70971
+ import { readFile } from "fs/promises";
70972
+ import { join as join6 } from "path";
70973
+ var AssetManifestLoader = class {
70974
+ logger = getLogger().child("AssetManifestLoader");
70975
+ /**
70976
+ * Load asset manifest from CDK output directory
70977
+ *
70978
+ * @param cdkOutputDir CDK output directory (e.g., "cdk.out")
70979
+ * @param stackName Stack name
70980
+ * @returns Asset manifest or null if not found
70981
+ */
70982
+ async loadManifest(cdkOutputDir, stackName) {
70983
+ const manifestPath = join6(cdkOutputDir, `${stackName}.assets.json`);
70984
+ try {
70985
+ this.logger.debug(`Loading asset manifest from: ${manifestPath}`);
70986
+ const content = await readFile(manifestPath, "utf-8");
70987
+ const manifest = JSON.parse(content);
70988
+ this.logger.debug(
70989
+ `Loaded asset manifest: ${Object.keys(manifest.files).length} file assets, ${Object.keys(manifest.dockerImages).length} docker image assets`
70990
+ );
70991
+ return manifest;
70992
+ } catch (error) {
70993
+ if (error.code === "ENOENT") {
70994
+ this.logger.debug(`Asset manifest not found: ${manifestPath}`);
70995
+ return null;
70996
+ }
70997
+ throw new Error(
70998
+ `Failed to load asset manifest from ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`
70999
+ );
71000
+ }
71001
+ }
71002
+ /**
71003
+ * Get file assets from manifest (excludes CloudFormation templates)
71004
+ *
71005
+ * @param manifest Asset manifest
71006
+ * @returns Map of asset hash to file asset
71007
+ */
71008
+ getFileAssets(manifest) {
71009
+ const fileAssets = /* @__PURE__ */ new Map();
71010
+ for (const [assetHash, asset] of Object.entries(manifest.files)) {
71011
+ if (asset.source.path.endsWith(".json") || asset.source.path.endsWith(".template.json")) {
71012
+ this.logger.debug(`Skipping CloudFormation template asset: ${asset.displayName}`);
71013
+ continue;
71014
+ }
71015
+ fileAssets.set(assetHash, asset);
71016
+ }
71017
+ this.logger.debug(`Found ${fileAssets.size} file assets (excluding templates)`);
71018
+ return fileAssets;
71019
+ }
71020
+ /**
71021
+ * Get asset source path (absolute path)
71022
+ *
71023
+ * @param cdkOutputDir CDK output directory
71024
+ * @param asset File asset
71025
+ * @returns Absolute path to asset source
71026
+ */
71027
+ getAssetSourcePath(cdkOutputDir, asset) {
71028
+ return join6(cdkOutputDir, asset.source.path);
71029
+ }
71030
+ /**
71031
+ * Resolve asset destination values (replace ${AWS::AccountId}, ${AWS::Region}, etc.)
71032
+ *
71033
+ * @param value Value with placeholders
71034
+ * @param accountId AWS account ID
71035
+ * @param region AWS region
71036
+ * @param partition AWS partition (default: "aws")
71037
+ * @returns Resolved value
71038
+ */
71039
+ resolveAssetDestinationValue(value, accountId, region, partition = "aws") {
71040
+ return value.replace(/\$\{AWS::AccountId\}/g, accountId).replace(/\$\{AWS::Region\}/g, region).replace(/\$\{AWS::Partition\}/g, partition);
71041
+ }
71042
+ };
71043
+ function getDockerImageBySourceHash(manifest, imageUri) {
71044
+ const dockerImages = manifest.dockerImages ?? {};
71045
+ const entries = Object.entries(dockerImages);
71046
+ if (entries.length === 0)
71047
+ return void 0;
71048
+ const hash = extractHashFromImageUri(imageUri);
71049
+ if (hash !== void 0) {
71050
+ const asset = dockerImages[hash];
71051
+ if (asset) {
71052
+ return { hash, asset };
71053
+ }
71054
+ }
71055
+ if (entries.length === 1) {
71056
+ const [singleHash, singleAsset] = entries[0];
71057
+ return { hash: singleHash, asset: singleAsset };
71058
+ }
71059
+ return void 0;
71060
+ }
71061
+ function extractHashFromImageUri(imageUri) {
71062
+ if (imageUri.includes("@sha256:"))
71063
+ return void 0;
71064
+ const match = /:([a-f0-9]{8,})$/.exec(imageUri);
71065
+ return match?.[1];
71066
+ }
71067
+
70633
71068
  // src/cli/commands/local-invoke.ts
70634
71069
  init_aws_clients();
70635
- async function localInvokeCommand(target, options) {
71070
+
71071
+ // src/cli/commands/local-start-api.ts
71072
+ import { mkdirSync as mkdirSync2, mkdtempSync as mkdtempSync2, readFileSync as readFileSync6, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "node:fs";
71073
+ import { tmpdir as tmpdir2 } from "node:os";
71074
+ import * as path from "node:path";
71075
+ import { Command as Command14, Option as Option7 } from "commander";
71076
+
71077
+ // src/local/route-discovery.ts
71078
+ function discoverRoutes(stacks) {
71079
+ const routes = [];
71080
+ const errors = [];
71081
+ for (const stack of stacks) {
71082
+ const template = stack.template;
71083
+ const resources = template.Resources ?? {};
71084
+ for (const [logicalId, resource] of Object.entries(resources)) {
71085
+ try {
71086
+ switch (resource.Type) {
71087
+ case "AWS::ApiGateway::Method":
71088
+ routes.push(...discoverRestV1Method(logicalId, resource, template, stack.stackName));
71089
+ break;
71090
+ case "AWS::ApiGatewayV2::Route":
71091
+ routes.push(...discoverHttpApiRoute(logicalId, resource, template, stack.stackName));
71092
+ break;
71093
+ case "AWS::Lambda::Url":
71094
+ routes.push(...discoverFunctionUrl(logicalId, resource, stack.stackName));
71095
+ break;
71096
+ default:
71097
+ break;
71098
+ }
71099
+ } catch (err) {
71100
+ errors.push(err instanceof Error ? err.message : String(err));
71101
+ }
71102
+ }
71103
+ }
71104
+ if (errors.length > 0) {
71105
+ throw new RouteDiscoveryError(
71106
+ `cdkd local start-api: ${errors.length} unsupported route(s) in the synthesized template:
71107
+ ` + errors.map((e) => ` - ${e}`).join("\n")
71108
+ );
71109
+ }
71110
+ return routes;
71111
+ }
71112
+ function discoverRestV1Method(logicalId, resource, template, stackName) {
71113
+ const props = resource.Properties ?? {};
71114
+ const integration = props["Integration"];
71115
+ if (!integration) {
71116
+ throw new Error(
71117
+ `${stackName}/${logicalId} (AWS::ApiGateway::Method): missing Integration property`
71118
+ );
71119
+ }
71120
+ const integrationType = integration["Type"];
71121
+ if (integrationType !== "AWS_PROXY") {
71122
+ throw new Error(
71123
+ `${stackName}/${logicalId} (AWS::ApiGateway::Method): integration type '${String(
71124
+ integrationType
71125
+ )}' is not supported (only AWS_PROXY). MOCK / AWS / HTTP / HTTP_PROXY require mapping templates that cdkd cannot emulate.`
71126
+ );
71127
+ }
71128
+ const integrationUri = integration["Uri"];
71129
+ const lambdaLogicalId = resolveLambdaArnIntrinsic(
71130
+ integrationUri,
71131
+ `${stackName}/${logicalId}.Integration.Uri`
71132
+ );
71133
+ const restApiId = props["RestApiId"];
71134
+ const restApiLogicalId = pickRefLogicalId(restApiId);
71135
+ if (!restApiLogicalId) {
71136
+ throw new Error(
71137
+ `${stackName}/${logicalId} (AWS::ApiGateway::Method): RestApiId must be a { Ref: '...' } reference (got ${shortJson(
71138
+ restApiId
71139
+ )}).`
71140
+ );
71141
+ }
71142
+ const resourceId = props["ResourceId"];
71143
+ const path3 = buildRestV1Path(resourceId, restApiLogicalId, template, stackName, logicalId);
71144
+ const httpMethod = String(props["HttpMethod"] ?? "ANY");
71145
+ const stage = pickRestV1Stage(restApiLogicalId, template);
71146
+ return [
71147
+ {
71148
+ method: httpMethod,
71149
+ pathPattern: path3,
71150
+ lambdaLogicalId,
71151
+ source: "rest-v1",
71152
+ apiVersion: "v1",
71153
+ stage,
71154
+ declaredAt: `${stackName}/${logicalId}`
71155
+ }
71156
+ ];
71157
+ }
71158
+ function buildRestV1Path(resourceIdIntrinsic, restApiLogicalId, template, stackName, methodLogicalId) {
71159
+ if (resourceIdIntrinsic && typeof resourceIdIntrinsic === "object" && !Array.isArray(resourceIdIntrinsic)) {
71160
+ const obj = resourceIdIntrinsic;
71161
+ if ("Fn::GetAtt" in obj) {
71162
+ const arg = obj["Fn::GetAtt"];
71163
+ if (Array.isArray(arg) && arg.length === 2 && arg[1] === "RootResourceId") {
71164
+ return "/";
71165
+ }
71166
+ }
71167
+ }
71168
+ const resourceLogicalId = pickRefLogicalId(resourceIdIntrinsic);
71169
+ if (!resourceLogicalId) {
71170
+ throw new Error(
71171
+ `${stackName}/${methodLogicalId}: ResourceId must be { Ref: '...' } or { 'Fn::GetAtt': [..., 'RootResourceId'] } (got ${shortJson(
71172
+ resourceIdIntrinsic
71173
+ )}).`
71174
+ );
71175
+ }
71176
+ const segments = [];
71177
+ const visited = /* @__PURE__ */ new Set();
71178
+ let cursor = resourceLogicalId;
71179
+ while (cursor && cursor !== restApiLogicalId) {
71180
+ if (visited.has(cursor)) {
71181
+ throw new Error(
71182
+ `${stackName}/${methodLogicalId}: cycle detected in AWS::ApiGateway::Resource ParentId chain at ${cursor}`
71183
+ );
71184
+ }
71185
+ visited.add(cursor);
71186
+ const node = template.Resources?.[cursor];
71187
+ if (!node) {
71188
+ throw new Error(
71189
+ `${stackName}/${methodLogicalId}: ParentId chain references missing resource '${cursor}'`
71190
+ );
71191
+ }
71192
+ if (node.Type !== "AWS::ApiGateway::Resource") {
71193
+ throw new Error(
71194
+ `${stackName}/${methodLogicalId}: ParentId chain hit ${node.Type} (expected AWS::ApiGateway::Resource or RestApi root)`
71195
+ );
71196
+ }
71197
+ const nodeProps = node.Properties ?? {};
71198
+ const pathPart = nodeProps["PathPart"];
71199
+ if (typeof pathPart !== "string") {
71200
+ throw new Error(
71201
+ `${stackName}/${methodLogicalId}: AWS::ApiGateway::Resource '${cursor}' missing PathPart`
71202
+ );
71203
+ }
71204
+ segments.unshift(pathPart);
71205
+ const parentId = nodeProps["ParentId"];
71206
+ if (parentId && typeof parentId === "object" && !Array.isArray(parentId) && "Fn::GetAtt" in parentId) {
71207
+ const arg = parentId["Fn::GetAtt"];
71208
+ if (Array.isArray(arg) && arg[1] === "RootResourceId")
71209
+ break;
71210
+ }
71211
+ cursor = pickRefLogicalId(parentId) ?? void 0;
71212
+ }
71213
+ return "/" + segments.join("/");
71214
+ }
71215
+ function pickRestV1Stage(restApiLogicalId, template) {
71216
+ const resources = template.Resources ?? {};
71217
+ for (const [, resource] of Object.entries(resources)) {
71218
+ if (resource.Type !== "AWS::ApiGateway::Stage")
71219
+ continue;
71220
+ const props = resource.Properties ?? {};
71221
+ const ref = pickRefLogicalId(props["RestApiId"]);
71222
+ if (ref === restApiLogicalId) {
71223
+ const stageName = props["StageName"];
71224
+ if (typeof stageName === "string")
71225
+ return stageName;
71226
+ }
71227
+ }
71228
+ return "$default";
71229
+ }
71230
+ function discoverHttpApiRoute(logicalId, resource, template, stackName) {
71231
+ const props = resource.Properties ?? {};
71232
+ const apiId = props["ApiId"];
71233
+ const apiLogicalId = pickRefLogicalId(apiId);
71234
+ if (!apiLogicalId) {
71235
+ throw new Error(
71236
+ `${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): ApiId must be { Ref: '...' } (got ${shortJson(
71237
+ apiId
71238
+ )}).`
71239
+ );
71240
+ }
71241
+ const apiResource = template.Resources?.[apiLogicalId];
71242
+ if (apiResource?.Type === "AWS::ApiGatewayV2::Api") {
71243
+ const protocolType = (apiResource.Properties ?? {})["ProtocolType"];
71244
+ if (protocolType === "WEBSOCKET") {
71245
+ throw new Error(
71246
+ `${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): WebSocket APIs are not supported in cdkd local start-api (deferred follow-up PR).`
71247
+ );
71248
+ }
71249
+ }
71250
+ const routeKey = props["RouteKey"];
71251
+ if (typeof routeKey !== "string" || routeKey.length === 0) {
71252
+ throw new Error(
71253
+ `${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): RouteKey must be a string`
71254
+ );
71255
+ }
71256
+ const target = props["Target"];
71257
+ const integrationLogicalId = parseHttpApiTargetIntegration(
71258
+ target,
71259
+ `${stackName}/${logicalId}.Target`
71260
+ );
71261
+ const integration = template.Resources?.[integrationLogicalId];
71262
+ if (!integration || integration.Type !== "AWS::ApiGatewayV2::Integration") {
71263
+ throw new Error(
71264
+ `${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): Target points at '${integrationLogicalId}' which is not an AWS::ApiGatewayV2::Integration`
71265
+ );
71266
+ }
71267
+ const integrationProps = integration.Properties ?? {};
71268
+ const integrationType = integrationProps["IntegrationType"];
71269
+ if (integrationType !== "AWS_PROXY") {
71270
+ throw new Error(
71271
+ `${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): integration type '${String(
71272
+ integrationType
71273
+ )}' is not supported (only AWS_PROXY).`
71274
+ );
71275
+ }
71276
+ if (integrationProps["IntegrationSubtype"] !== void 0) {
71277
+ throw new Error(
71278
+ `${stackName}/${logicalId} (AWS::ApiGatewayV2::Route): IntegrationSubtype '${String(
71279
+ integrationProps["IntegrationSubtype"]
71280
+ )}' is not supported (ApiGatewayV2 service integrations like SQS/EventBridge cannot run locally).`
71281
+ );
71282
+ }
71283
+ const lambdaLogicalId = resolveLambdaArnIntrinsic(
71284
+ integrationProps["IntegrationUri"],
71285
+ `${stackName}/${integrationLogicalId}.IntegrationUri`
71286
+ );
71287
+ const { method, pathPattern } = parseRouteKey(routeKey);
71288
+ return [
71289
+ {
71290
+ method,
71291
+ pathPattern,
71292
+ lambdaLogicalId,
71293
+ source: "http-api",
71294
+ apiVersion: "v2",
71295
+ stage: "$default",
71296
+ declaredAt: `${stackName}/${logicalId}`
71297
+ }
71298
+ ];
71299
+ }
71300
+ function discoverFunctionUrl(logicalId, resource, stackName) {
71301
+ const props = resource.Properties ?? {};
71302
+ const authType = props["AuthType"];
71303
+ if (authType !== "NONE") {
71304
+ throw new Error(
71305
+ `${stackName}/${logicalId} (AWS::Lambda::Url): AuthType '${String(
71306
+ authType
71307
+ )}' is not supported (only NONE \u2014 IAM auth requires SigV4 verification cdkd cannot emulate locally; deferred follow-up PR).`
71308
+ );
71309
+ }
71310
+ const invokeMode = props["InvokeMode"];
71311
+ if (invokeMode === "RESPONSE_STREAM") {
71312
+ throw new Error(
71313
+ `${stackName}/${logicalId} (AWS::Lambda::Url): InvokeMode RESPONSE_STREAM is not supported (deferred follow-up PR).`
71314
+ );
71315
+ }
71316
+ const targetArn = props["TargetFunctionArn"];
71317
+ const lambdaLogicalId = resolveLambdaArnIntrinsic(
71318
+ targetArn,
71319
+ `${stackName}/${logicalId}.TargetFunctionArn`
71320
+ );
71321
+ return [
71322
+ {
71323
+ method: "ANY",
71324
+ pathPattern: "/{proxy+}",
71325
+ lambdaLogicalId,
71326
+ source: "function-url",
71327
+ apiVersion: "v2",
71328
+ stage: "$default",
71329
+ declaredAt: `${stackName}/${logicalId}`
71330
+ }
71331
+ ];
71332
+ }
71333
+ function resolveLambdaArnIntrinsic(value, location) {
71334
+ if (value && typeof value === "object" && !Array.isArray(value)) {
71335
+ const obj = value;
71336
+ if ("Ref" in obj && typeof obj["Ref"] === "string") {
71337
+ return obj["Ref"];
71338
+ }
71339
+ if ("Fn::GetAtt" in obj) {
71340
+ const arg = obj["Fn::GetAtt"];
71341
+ if (Array.isArray(arg) && arg.length === 2 && typeof arg[0] === "string" && arg[1] === "Arn") {
71342
+ return arg[0];
71343
+ }
71344
+ }
71345
+ if ("Fn::Join" in obj) {
71346
+ const join9 = obj["Fn::Join"];
71347
+ if (Array.isArray(join9) && join9.length === 2 && Array.isArray(join9[1])) {
71348
+ const parts = join9[1];
71349
+ const literalParts = parts.filter((p) => typeof p === "string").join("");
71350
+ if (literalParts.includes(":lambda:path/2015-03-31/functions/")) {
71351
+ for (const p of parts) {
71352
+ if (p && typeof p === "object" && !Array.isArray(p)) {
71353
+ const inner = p;
71354
+ const arg = inner["Fn::GetAtt"];
71355
+ if (Array.isArray(arg) && arg.length === 2 && typeof arg[0] === "string" && arg[1] === "Arn") {
71356
+ return arg[0];
71357
+ }
71358
+ }
71359
+ }
71360
+ }
71361
+ }
71362
+ }
71363
+ }
71364
+ throw new Error(
71365
+ `${location}: only { Ref: <LambdaLogicalId> }, { 'Fn::GetAtt': [<LambdaLogicalId>, 'Arn'] }, or the REST v1 invoke-ARN Fn::Join wrapper are supported (got ${shortJson(
71366
+ value
71367
+ )}). Other intrinsics (Fn::Sub against arbitrary templates, etc.) require deploy-state and are not supported in cdkd local start-api.`
71368
+ );
71369
+ }
71370
+ function parseHttpApiTargetIntegration(target, location) {
71371
+ if (typeof target === "string") {
71372
+ const m = /^integrations\/(.+)$/.exec(target);
71373
+ if (m)
71374
+ return m[1];
71375
+ throw new Error(`${location}: literal Target '${target}' must start with 'integrations/'`);
71376
+ }
71377
+ if (target && typeof target === "object" && !Array.isArray(target)) {
71378
+ const obj = target;
71379
+ const join9 = obj["Fn::Join"];
71380
+ if (Array.isArray(join9) && join9.length === 2 && Array.isArray(join9[1])) {
71381
+ const sep = join9[0];
71382
+ const parts = join9[1];
71383
+ if (sep === "/" && parts.length === 2 && parts[0] === "integrations") {
71384
+ const ref = pickRefLogicalId(parts[1]);
71385
+ if (ref)
71386
+ return ref;
71387
+ }
71388
+ if (sep === "" && parts.length === 2 && parts[0] === "integrations/") {
71389
+ const ref = pickRefLogicalId(parts[1]);
71390
+ if (ref)
71391
+ return ref;
71392
+ }
71393
+ }
71394
+ }
71395
+ throw new Error(
71396
+ `${location}: Target must be 'integrations/<id>' or Fn::Join with one of the documented shapes (got ${shortJson(
71397
+ target
71398
+ )}).`
71399
+ );
71400
+ }
71401
+ function parseRouteKey(routeKey) {
71402
+ if (routeKey === "$default") {
71403
+ return { method: "ANY", pathPattern: "$default" };
71404
+ }
71405
+ const m = /^([A-Za-z]+)\s+(\S+)$/.exec(routeKey);
71406
+ if (!m) {
71407
+ throw new Error(
71408
+ `RouteKey '${routeKey}' is malformed: expected '<METHOD> <path>' (e.g. 'GET /items/{id}') or '$default'.`
71409
+ );
71410
+ }
71411
+ return { method: m[1].toUpperCase(), pathPattern: m[2] };
71412
+ }
71413
+ function pickRefLogicalId(value) {
71414
+ if (value && typeof value === "object" && !Array.isArray(value)) {
71415
+ const ref = value["Ref"];
71416
+ if (typeof ref === "string")
71417
+ return ref;
71418
+ }
71419
+ return null;
71420
+ }
71421
+ function shortJson(value) {
71422
+ try {
71423
+ const s = JSON.stringify(value);
71424
+ return s.length > 200 ? `${s.slice(0, 200)}\u2026` : s;
71425
+ } catch {
71426
+ return String(value);
71427
+ }
71428
+ }
71429
+
71430
+ // src/local/container-pool.ts
71431
+ var DEFAULT_IDLE_MS = 6e4;
71432
+ var MAX_PER_LAMBDA_CONCURRENCY = 4;
71433
+ var MIN_PER_LAMBDA_CONCURRENCY = 1;
71434
+ function createContainerPool(specs, options) {
71435
+ const logger = getLogger().child("container-pool");
71436
+ const concurrencyCap = clampConcurrency(options.perLambdaConcurrency);
71437
+ const idleMs = options.idleMs ?? DEFAULT_IDLE_MS;
71438
+ const streamingEnabled = options.streamLogs !== false;
71439
+ const entries = /* @__PURE__ */ new Map();
71440
+ const inFlightStarts = /* @__PURE__ */ new Set();
71441
+ for (const logicalId of specs.keys()) {
71442
+ entries.set(logicalId, emptyEntry(logicalId));
71443
+ }
71444
+ function emptyEntry(logicalId) {
71445
+ return {
71446
+ logicalId,
71447
+ warm: [],
71448
+ inUse: /* @__PURE__ */ new Set(),
71449
+ waitQueue: [],
71450
+ idleTimer: null,
71451
+ growthMutex: Promise.resolve()
71452
+ };
71453
+ }
71454
+ async function startOne(spec) {
71455
+ const image = resolveRuntimeImage(spec.lambda.runtime);
71456
+ const hostPort = await pickFreePort();
71457
+ const name = `cdkd-local-${spec.lambda.logicalId}-${process.pid}-${Math.floor(
71458
+ Math.random() * 1e6
71459
+ )}`;
71460
+ logger.debug(
71461
+ `Starting container ${name} for ${spec.lambda.logicalId} on ${spec.containerHost}:${hostPort}`
71462
+ );
71463
+ const containerId = await runDetached({
71464
+ image,
71465
+ mounts: [{ hostPath: spec.codeDir, containerPath: "/var/task", readOnly: true }],
71466
+ env: spec.env,
71467
+ cmd: [spec.lambda.handler],
71468
+ hostPort,
71469
+ host: spec.containerHost,
71470
+ name,
71471
+ ...spec.debugPort !== void 0 && { debugPort: spec.debugPort }
71472
+ });
71473
+ const stopLogStream = streamingEnabled ? streamLogs(containerId) : () => void 0;
71474
+ try {
71475
+ await waitForRieReady(spec.containerHost, hostPort, 3e4);
71476
+ } catch (err) {
71477
+ stopLogStream();
71478
+ await removeContainer(containerId).catch(() => void 0);
71479
+ throw err;
71480
+ }
71481
+ return {
71482
+ logicalId: spec.lambda.logicalId,
71483
+ containerId,
71484
+ containerName: name,
71485
+ hostPort,
71486
+ containerHost: spec.containerHost,
71487
+ stopLogStream
71488
+ };
71489
+ }
71490
+ async function withMutex(entry, body) {
71491
+ const previous = entry.growthMutex;
71492
+ let release;
71493
+ entry.growthMutex = new Promise((r) => release = r);
71494
+ try {
71495
+ await previous;
71496
+ return await body();
71497
+ } finally {
71498
+ release();
71499
+ }
71500
+ }
71501
+ async function tearDown(handle) {
71502
+ try {
71503
+ handle.stopLogStream();
71504
+ } catch (err) {
71505
+ logger.debug(
71506
+ `stopLogStream(${handle.containerName}) failed: ${err instanceof Error ? err.message : String(err)}`
71507
+ );
71508
+ }
71509
+ try {
71510
+ await removeContainer(handle.containerId);
71511
+ } catch (err) {
71512
+ logger.warn(
71513
+ `Failed to remove container ${handle.containerName}: ${err instanceof Error ? err.message : String(err)}. Continuing cleanup.`
71514
+ );
71515
+ }
71516
+ }
71517
+ function poolSize(entry) {
71518
+ return entry.warm.length + entry.inUse.size;
71519
+ }
71520
+ function resetIdleTimer(entry) {
71521
+ if (entry.idleTimer) {
71522
+ clearTimeout(entry.idleTimer);
71523
+ entry.idleTimer = null;
71524
+ }
71525
+ if (entry.warm.length === 0)
71526
+ return;
71527
+ entry.idleTimer = setTimeout(() => {
71528
+ void gcIdle(entry);
71529
+ }, idleMs);
71530
+ entry.idleTimer.unref?.();
71531
+ }
71532
+ async function gcIdle(entry) {
71533
+ const handles = entry.warm.splice(0, entry.warm.length);
71534
+ entry.idleTimer = null;
71535
+ if (handles.length === 0)
71536
+ return;
71537
+ logger.debug(`Idle GC: tearing down ${handles.length} container(s) for ${entry.logicalId}`);
71538
+ await Promise.allSettled(handles.map((h) => tearDown(h)));
71539
+ }
71540
+ return {
71541
+ async acquire(logicalId) {
71542
+ const entry = entries.get(logicalId);
71543
+ if (!entry) {
71544
+ throw new Error(
71545
+ `containerPool.acquire: no spec registered for Lambda '${logicalId}'. This is a bug \u2014 every reachable route's Lambda should be registered at server boot.`
71546
+ );
71547
+ }
71548
+ if (entry.warm.length > 0) {
71549
+ const handle = entry.warm.shift();
71550
+ entry.inUse.add(handle);
71551
+ if (entry.idleTimer) {
71552
+ clearTimeout(entry.idleTimer);
71553
+ entry.idleTimer = null;
71554
+ }
71555
+ return handle;
71556
+ }
71557
+ return await withMutex(entry, async () => {
71558
+ if (entry.warm.length > 0) {
71559
+ const handle = entry.warm.shift();
71560
+ entry.inUse.add(handle);
71561
+ return handle;
71562
+ }
71563
+ if (poolSize(entry) < concurrencyCap) {
71564
+ const spec = specs.get(logicalId);
71565
+ const startPromise = startOne(spec);
71566
+ inFlightStarts.add(startPromise);
71567
+ let handle;
71568
+ try {
71569
+ handle = await startPromise;
71570
+ } finally {
71571
+ inFlightStarts.delete(startPromise);
71572
+ }
71573
+ entry.inUse.add(handle);
71574
+ return handle;
71575
+ }
71576
+ return await new Promise((resolveAcquire, rejectAcquire) => {
71577
+ entry.waitQueue.push({ resolve: resolveAcquire, reject: rejectAcquire });
71578
+ });
71579
+ });
71580
+ },
71581
+ release(handle) {
71582
+ const entry = entries.get(handle.logicalId);
71583
+ if (!entry)
71584
+ return;
71585
+ entry.inUse.delete(handle);
71586
+ const waiter = entry.waitQueue.shift();
71587
+ if (waiter) {
71588
+ entry.inUse.add(handle);
71589
+ waiter.resolve(handle);
71590
+ return;
71591
+ }
71592
+ entry.warm.push(handle);
71593
+ resetIdleTimer(entry);
71594
+ },
71595
+ async dispose() {
71596
+ logger.debug("Disposing container pool");
71597
+ const allHandles = [];
71598
+ for (const entry of entries.values()) {
71599
+ if (entry.idleTimer) {
71600
+ clearTimeout(entry.idleTimer);
71601
+ entry.idleTimer = null;
71602
+ }
71603
+ for (const waiter of entry.waitQueue.splice(0, entry.waitQueue.length)) {
71604
+ try {
71605
+ waiter.reject(
71606
+ new Error(`Container pool disposed while ${entry.logicalId} was waiting`)
71607
+ );
71608
+ } catch {
71609
+ }
71610
+ }
71611
+ allHandles.push(...entry.warm.splice(0, entry.warm.length));
71612
+ for (const h of entry.inUse)
71613
+ allHandles.push(h);
71614
+ entry.inUse.clear();
71615
+ }
71616
+ const startPromises = [...inFlightStarts];
71617
+ if (startPromises.length > 0) {
71618
+ logger.debug(
71619
+ `Waiting for ${startPromises.length} in-flight container start(s) to settle before teardown`
71620
+ );
71621
+ const drainTimeoutMs = 5e3;
71622
+ const wrapped = startPromises.map(
71623
+ (p) => Promise.race([
71624
+ p.then((h) => ({ kind: "ok", handle: h })),
71625
+ new Promise((r) => {
71626
+ const t = setTimeout(() => r({ kind: "timeout" }), drainTimeoutMs);
71627
+ t.unref?.();
71628
+ })
71629
+ ]).catch((err) => {
71630
+ logger.debug(
71631
+ `In-flight startOne rejected during dispose: ${err instanceof Error ? err.message : String(err)}`
71632
+ );
71633
+ return { kind: "rejected" };
71634
+ })
71635
+ );
71636
+ const results = await Promise.all(wrapped);
71637
+ let timedOut = 0;
71638
+ for (const r of results) {
71639
+ if (r.kind === "ok") {
71640
+ allHandles.push(r.handle);
71641
+ } else if (r.kind === "timeout") {
71642
+ timedOut++;
71643
+ }
71644
+ }
71645
+ if (timedOut > 0) {
71646
+ logger.warn(
71647
+ `Container pool disposed with ${timedOut} in-flight start(s) still pending after ${drainTimeoutMs}ms; relying on docker --rm + the verify.sh sweep to clean up.`
71648
+ );
71649
+ }
71650
+ inFlightStarts.clear();
71651
+ }
71652
+ await Promise.allSettled(allHandles.map((h) => tearDown(h)));
71653
+ entries.clear();
71654
+ }
71655
+ };
71656
+ }
71657
+ function clampConcurrency(input) {
71658
+ if (!Number.isFinite(input))
71659
+ return 2;
71660
+ return Math.min(
71661
+ MAX_PER_LAMBDA_CONCURRENCY,
71662
+ Math.max(MIN_PER_LAMBDA_CONCURRENCY, Math.trunc(input))
71663
+ );
71664
+ }
71665
+
71666
+ // src/local/http-server.ts
71667
+ import { createServer as createServer2 } from "node:http";
71668
+
71669
+ // src/local/api-gateway-event.ts
71670
+ import { randomUUID } from "node:crypto";
71671
+ var MOCK_ACCOUNT_ID = "123456789012";
71672
+ var MOCK_DOMAIN_PREFIX = "local";
71673
+ var MOCK_DOMAIN_NAME = "localhost";
71674
+ var MOCK_API_ID = "local";
71675
+ function buildHttpApiV2Event(req, ctx, opts = {}) {
71676
+ const { rawPath, rawQueryString } = splitRawUrl(req.rawUrl);
71677
+ const { headers, cookies } = normalizeHeadersV2(req.headers);
71678
+ const queryStringParameters = parseQueryStringV2(rawQueryString);
71679
+ const userAgent = headers["user-agent"] ?? "";
71680
+ const contentType = headers["content-type"] ?? "";
71681
+ const { body, isBase64Encoded } = encodeBody(req.body, contentType);
71682
+ const now = opts.now ? opts.now() : /* @__PURE__ */ new Date();
71683
+ const routeKey = ctx.route.pathPattern === "$default" ? "$default" : `${ctx.route.method} ${ctx.route.pathPattern}`;
71684
+ const event = {
71685
+ version: "2.0",
71686
+ routeKey,
71687
+ rawPath,
71688
+ rawQueryString,
71689
+ cookies,
71690
+ headers,
71691
+ queryStringParameters,
71692
+ pathParameters: decodePathParameters(ctx.pathParameters),
71693
+ stageVariables: null,
71694
+ requestContext: {
71695
+ accountId: MOCK_ACCOUNT_ID,
71696
+ apiId: MOCK_API_ID,
71697
+ domainName: MOCK_DOMAIN_NAME,
71698
+ domainPrefix: MOCK_DOMAIN_PREFIX,
71699
+ http: {
71700
+ method: req.method.toUpperCase(),
71701
+ path: ctx.matchedPath,
71702
+ protocol: "HTTP/1.1",
71703
+ sourceIp: req.sourceIp ?? "127.0.0.1",
71704
+ userAgent
71705
+ },
71706
+ requestId: randomUUID(),
71707
+ routeKey,
71708
+ stage: ctx.route.stage,
71709
+ time: formatRequestTime(now),
71710
+ timeEpoch: now.getTime(),
71711
+ authentication: null,
71712
+ authorizer: null
71713
+ },
71714
+ body,
71715
+ isBase64Encoded
71716
+ };
71717
+ return event;
71718
+ }
71719
+ function buildRestV1Event(req, ctx, opts = {}) {
71720
+ const { rawPath, rawQueryString } = splitRawUrl(req.rawUrl);
71721
+ const { singular: headers, multi: multiValueHeaders } = normalizeHeadersV1(req.headers);
71722
+ const { singular: queryStringParameters, multi: multiValueQueryStringParameters } = parseQueryStringV1(rawQueryString);
71723
+ const contentType = headers["content-type"] ?? "";
71724
+ const { body, isBase64Encoded } = encodeBody(req.body, contentType);
71725
+ const now = opts.now ? opts.now() : /* @__PURE__ */ new Date();
71726
+ const pathParams = decodePathParameters(ctx.pathParameters);
71727
+ const event = {
71728
+ resource: ctx.route.pathPattern,
71729
+ path: ctx.matchedPath,
71730
+ httpMethod: req.method.toUpperCase(),
71731
+ headers,
71732
+ multiValueHeaders,
71733
+ queryStringParameters: Object.keys(queryStringParameters).length > 0 ? queryStringParameters : null,
71734
+ multiValueQueryStringParameters: Object.keys(multiValueQueryStringParameters).length > 0 ? multiValueQueryStringParameters : null,
71735
+ pathParameters: Object.keys(pathParams).length > 0 ? pathParams : null,
71736
+ stageVariables: null,
71737
+ requestContext: {
71738
+ accountId: MOCK_ACCOUNT_ID,
71739
+ apiId: MOCK_API_ID,
71740
+ domainName: MOCK_DOMAIN_NAME,
71741
+ domainPrefix: MOCK_DOMAIN_PREFIX,
71742
+ httpMethod: req.method.toUpperCase(),
71743
+ identity: {
71744
+ sourceIp: req.sourceIp ?? "127.0.0.1",
71745
+ userAgent: headers["user-agent"] ?? ""
71746
+ },
71747
+ path: `/${ctx.route.stage}${ctx.matchedPath}`,
71748
+ protocol: "HTTP/1.1",
71749
+ requestId: randomUUID(),
71750
+ requestTime: formatRequestTime(now),
71751
+ requestTimeEpoch: now.getTime(),
71752
+ resourcePath: ctx.route.pathPattern,
71753
+ stage: ctx.route.stage,
71754
+ authorizer: null
71755
+ },
71756
+ body: req.body.length === 0 ? null : body,
71757
+ isBase64Encoded
71758
+ };
71759
+ return event;
71760
+ }
71761
+ function splitRawUrl(rawUrl) {
71762
+ const q = rawUrl.indexOf("?");
71763
+ if (q === -1)
71764
+ return { rawPath: rawUrl, rawQueryString: "" };
71765
+ return { rawPath: rawUrl.slice(0, q), rawQueryString: rawUrl.slice(q + 1) };
71766
+ }
71767
+ function normalizeHeadersV2(rawHeaders) {
71768
+ const headers = {};
71769
+ let cookies = [];
71770
+ for (const [name, values] of Object.entries(rawHeaders)) {
71771
+ const lower = name.toLowerCase();
71772
+ if (lower === "cookie") {
71773
+ cookies = values.flatMap((v) => v.split(";")).map((s) => s.trim()).filter((s) => s.length > 0);
71774
+ continue;
71775
+ }
71776
+ headers[lower] = values.join(",");
71777
+ }
71778
+ return { headers, cookies };
71779
+ }
71780
+ function normalizeHeadersV1(rawHeaders) {
71781
+ const singular = {};
71782
+ const multi = {};
71783
+ for (const [name, values] of Object.entries(rawHeaders)) {
71784
+ const lower = name.toLowerCase();
71785
+ if (values.length === 0)
71786
+ continue;
71787
+ multi[lower] = [...values];
71788
+ singular[lower] = values[values.length - 1];
71789
+ }
71790
+ return { singular, multi };
71791
+ }
71792
+ function parseQueryStringV2(rawQueryString) {
71793
+ if (rawQueryString.length === 0)
71794
+ return {};
71795
+ const out = {};
71796
+ for (const pair of rawQueryString.split("&")) {
71797
+ if (pair.length === 0)
71798
+ continue;
71799
+ const eq = pair.indexOf("=");
71800
+ const rawKey = eq === -1 ? pair : pair.slice(0, eq);
71801
+ const rawValue = eq === -1 ? "" : pair.slice(eq + 1);
71802
+ const key = safeDecode(rawKey);
71803
+ const value = safeDecode(rawValue);
71804
+ if (!out[key])
71805
+ out[key] = [];
71806
+ out[key].push(value);
71807
+ }
71808
+ const result = {};
71809
+ for (const [k, vs] of Object.entries(out))
71810
+ result[k] = vs.join(",");
71811
+ return result;
71812
+ }
71813
+ function parseQueryStringV1(rawQueryString) {
71814
+ const multi = {};
71815
+ if (rawQueryString.length > 0) {
71816
+ for (const pair of rawQueryString.split("&")) {
71817
+ if (pair.length === 0)
71818
+ continue;
71819
+ const eq = pair.indexOf("=");
71820
+ const rawKey = eq === -1 ? pair : pair.slice(0, eq);
71821
+ const rawValue = eq === -1 ? "" : pair.slice(eq + 1);
71822
+ const key = safeDecode(rawKey);
71823
+ const value = safeDecode(rawValue);
71824
+ if (!multi[key])
71825
+ multi[key] = [];
71826
+ multi[key].push(value);
71827
+ }
71828
+ }
71829
+ const singular = {};
71830
+ for (const [k, vs] of Object.entries(multi)) {
71831
+ if (vs.length > 0)
71832
+ singular[k] = vs[vs.length - 1];
71833
+ }
71834
+ return { singular, multi };
71835
+ }
71836
+ function decodePathParameters(pathParameters) {
71837
+ const out = {};
71838
+ for (const [k, v] of Object.entries(pathParameters)) {
71839
+ out[k] = safeDecode(v);
71840
+ }
71841
+ return out;
71842
+ }
71843
+ function safeDecode(s) {
71844
+ try {
71845
+ return decodeURIComponent(s);
71846
+ } catch {
71847
+ return s;
71848
+ }
71849
+ }
71850
+ function encodeBody(body, contentType) {
71851
+ if (body.length === 0) {
71852
+ return { body: "", isBase64Encoded: false };
71853
+ }
71854
+ if (isTextualContentType(contentType)) {
71855
+ return { body: body.toString("utf-8"), isBase64Encoded: false };
71856
+ }
71857
+ return { body: body.toString("base64"), isBase64Encoded: true };
71858
+ }
71859
+ var TEXT_PREFIXES = [
71860
+ "text/",
71861
+ "application/json",
71862
+ "application/xml",
71863
+ "application/javascript",
71864
+ "application/x-www-form-urlencoded",
71865
+ "application/graphql"
71866
+ ];
71867
+ function isTextualContentType(contentType) {
71868
+ if (!contentType)
71869
+ return false;
71870
+ const lower = contentType.toLowerCase();
71871
+ return TEXT_PREFIXES.some((p) => lower.startsWith(p));
71872
+ }
71873
+ function formatRequestTime(d) {
71874
+ const months = [
71875
+ "Jan",
71876
+ "Feb",
71877
+ "Mar",
71878
+ "Apr",
71879
+ "May",
71880
+ "Jun",
71881
+ "Jul",
71882
+ "Aug",
71883
+ "Sep",
71884
+ "Oct",
71885
+ "Nov",
71886
+ "Dec"
71887
+ ];
71888
+ const dd = String(d.getUTCDate()).padStart(2, "0");
71889
+ const mmm = months[d.getUTCMonth()];
71890
+ const yyyy = d.getUTCFullYear();
71891
+ const HH = String(d.getUTCHours()).padStart(2, "0");
71892
+ const MM = String(d.getUTCMinutes()).padStart(2, "0");
71893
+ const SS = String(d.getUTCSeconds()).padStart(2, "0");
71894
+ return `${dd}/${mmm}/${yyyy}:${HH}:${MM}:${SS} +0000`;
71895
+ }
71896
+
71897
+ // src/local/api-gateway-response.ts
71898
+ function translateLambdaResponse(payload, version) {
71899
+ if (isErrorEnvelope(payload)) {
71900
+ return errorEnvelopeResponse();
71901
+ }
71902
+ if (isShapedResponse(payload)) {
71903
+ return translateShapedResponse(payload, version);
71904
+ }
71905
+ return autoFormatResponse(payload);
71906
+ }
71907
+ function isErrorEnvelope(payload) {
71908
+ if (!payload || typeof payload !== "object" || Array.isArray(payload))
71909
+ return false;
71910
+ const obj = payload;
71911
+ if ("statusCode" in obj)
71912
+ return false;
71913
+ return typeof obj["errorMessage"] === "string";
71914
+ }
71915
+ function isShapedResponse(payload) {
71916
+ if (!payload || typeof payload !== "object" || Array.isArray(payload))
71917
+ return false;
71918
+ const status = payload["statusCode"];
71919
+ return typeof status === "number";
71920
+ }
71921
+ function errorEnvelopeResponse() {
71922
+ const body = Buffer.from('{"message":"Internal server error"}', "utf-8");
71923
+ return {
71924
+ statusCode: 502,
71925
+ headers: {
71926
+ "content-type": "application/json",
71927
+ "content-length": String(body.length)
71928
+ },
71929
+ cookies: [],
71930
+ body
71931
+ };
71932
+ }
71933
+ function translateShapedResponse(payload, version) {
71934
+ const statusCode = Number(payload["statusCode"]);
71935
+ const isBase64 = payload["isBase64Encoded"] === true;
71936
+ const rawBody = payload["body"];
71937
+ let body;
71938
+ if (rawBody === void 0 || rawBody === null) {
71939
+ body = Buffer.alloc(0);
71940
+ } else if (typeof rawBody === "string") {
71941
+ body = isBase64 ? Buffer.from(rawBody, "base64") : Buffer.from(rawBody, "utf-8");
71942
+ } else {
71943
+ body = Buffer.from(JSON.stringify(rawBody), "utf-8");
71944
+ }
71945
+ const headers = {};
71946
+ const cookies = [];
71947
+ const headersIn = payload["headers"];
71948
+ if (headersIn && typeof headersIn === "object" && !Array.isArray(headersIn)) {
71949
+ for (const [name, value] of Object.entries(headersIn)) {
71950
+ const lower = name.toLowerCase();
71951
+ const stringValue = stringifyHeaderValue(value);
71952
+ if (lower === "set-cookie") {
71953
+ cookies.push(stringValue);
71954
+ continue;
71955
+ }
71956
+ headers[lower] = stringValue;
71957
+ }
71958
+ }
71959
+ if (version === "v1") {
71960
+ const mvh = payload["multiValueHeaders"];
71961
+ if (mvh && typeof mvh === "object" && !Array.isArray(mvh)) {
71962
+ for (const [name, values] of Object.entries(mvh)) {
71963
+ if (!Array.isArray(values))
71964
+ continue;
71965
+ const lower = name.toLowerCase();
71966
+ const stringified = values.map((v) => stringifyHeaderValue(v));
71967
+ if (lower === "set-cookie") {
71968
+ for (const c of stringified)
71969
+ cookies.push(c);
71970
+ continue;
71971
+ }
71972
+ headers[lower] = stringified.join(",");
71973
+ }
71974
+ }
71975
+ }
71976
+ if (version === "v2") {
71977
+ const cookieList = payload["cookies"];
71978
+ if (Array.isArray(cookieList)) {
71979
+ for (const c of cookieList) {
71980
+ if (typeof c === "string")
71981
+ cookies.push(c);
71982
+ }
71983
+ }
71984
+ }
71985
+ if (!("content-length" in headers)) {
71986
+ headers["content-length"] = String(body.length);
71987
+ }
71988
+ return { statusCode, headers, cookies, body };
71989
+ }
71990
+ function autoFormatResponse(payload) {
71991
+ const body = payload === void 0 ? Buffer.alloc(0) : Buffer.from(JSON.stringify(payload), "utf-8");
71992
+ return {
71993
+ statusCode: 200,
71994
+ headers: {
71995
+ "content-type": "application/json",
71996
+ "content-length": String(body.length)
71997
+ },
71998
+ cookies: [],
71999
+ body
72000
+ };
72001
+ }
72002
+ function stringifyHeaderValue(value) {
72003
+ if (value === null || value === void 0)
72004
+ return "";
72005
+ if (Array.isArray(value))
72006
+ return value.map((v) => String(v)).join(",");
72007
+ return String(value);
72008
+ }
72009
+
72010
+ // src/local/route-matcher.ts
72011
+ function matchRoute(method, requestPath, routes) {
72012
+ const methodUpper = method.toUpperCase();
72013
+ const normalizedPath = requestPath.length > 1 ? requestPath.replace(/\/+$/, "") : requestPath;
72014
+ const requestSegments = splitPath(normalizedPath);
72015
+ let bestFull = null;
72016
+ for (const route of routes) {
72017
+ if (!methodMatches(route.method, methodUpper))
72018
+ continue;
72019
+ if (route.pathPattern === "$default")
72020
+ continue;
72021
+ if (isProxyRoute(route.pathPattern))
72022
+ continue;
72023
+ const result = matchFullPattern(requestSegments, route.pathPattern);
72024
+ if (!result)
72025
+ continue;
72026
+ if (!bestFull || result.literalCount > bestFull.literalCount) {
72027
+ bestFull = {
72028
+ route,
72029
+ pathParameters: result.pathParameters,
72030
+ literalCount: result.literalCount
72031
+ };
72032
+ }
72033
+ }
72034
+ if (bestFull)
72035
+ return { route: bestFull.route, pathParameters: bestFull.pathParameters };
72036
+ let bestProxy = null;
72037
+ for (const route of routes) {
72038
+ if (!methodMatches(route.method, methodUpper))
72039
+ continue;
72040
+ if (route.pathPattern === "$default")
72041
+ continue;
72042
+ if (!isProxyRoute(route.pathPattern))
72043
+ continue;
72044
+ const result = matchProxyPattern(requestSegments, route.pathPattern);
72045
+ if (!result)
72046
+ continue;
72047
+ if (!bestProxy || result.literalCount > bestProxy.literalCount) {
72048
+ bestProxy = {
72049
+ route,
72050
+ pathParameters: result.pathParameters,
72051
+ literalCount: result.literalCount
72052
+ };
72053
+ }
72054
+ }
72055
+ if (bestProxy)
72056
+ return { route: bestProxy.route, pathParameters: bestProxy.pathParameters };
72057
+ for (const route of routes) {
72058
+ if (!methodMatches(route.method, methodUpper))
72059
+ continue;
72060
+ if (route.pathPattern === "$default")
72061
+ return { route, pathParameters: {} };
72062
+ }
72063
+ return null;
72064
+ }
72065
+ function splitPath(path3) {
72066
+ return path3.split("/").filter((s) => s.length > 0);
72067
+ }
72068
+ function methodMatches(routeMethod, requestMethodUpper) {
72069
+ if (routeMethod === "ANY")
72070
+ return true;
72071
+ return routeMethod.toUpperCase() === requestMethodUpper;
72072
+ }
72073
+ function isProxyRoute(pattern) {
72074
+ return /\/\{[^/{}]+\+\}$/.test(pattern) || pattern === "/{proxy+}";
72075
+ }
72076
+ function matchFullPattern(requestSegments, pattern) {
72077
+ const patternSegments = splitPath(pattern);
72078
+ if (patternSegments.length !== requestSegments.length)
72079
+ return null;
72080
+ const pathParameters = {};
72081
+ let literalCount = 0;
72082
+ for (let i = 0; i < patternSegments.length; i++) {
72083
+ const ps = patternSegments[i];
72084
+ const rs = requestSegments[i];
72085
+ if (isPlaceholder(ps)) {
72086
+ const name = ps.slice(1, -1);
72087
+ pathParameters[name] = rs;
72088
+ } else if (ps === rs) {
72089
+ literalCount++;
72090
+ } else {
72091
+ return null;
72092
+ }
72093
+ }
72094
+ return { pathParameters, literalCount };
72095
+ }
72096
+ function matchProxyPattern(requestSegments, pattern) {
72097
+ const patternSegments = splitPath(pattern);
72098
+ if (patternSegments.length === 0)
72099
+ return null;
72100
+ const tail = patternSegments[patternSegments.length - 1];
72101
+ if (!/^\{[^/{}]+\+\}$/.test(tail))
72102
+ return null;
72103
+ const proxyName = tail.slice(1, -2);
72104
+ const fixedPrefixLen = patternSegments.length - 1;
72105
+ if (requestSegments.length < fixedPrefixLen)
72106
+ return null;
72107
+ const pathParameters = {};
72108
+ let literalCount = 0;
72109
+ for (let i = 0; i < fixedPrefixLen; i++) {
72110
+ const ps = patternSegments[i];
72111
+ const rs = requestSegments[i];
72112
+ if (isPlaceholder(ps)) {
72113
+ pathParameters[ps.slice(1, -1)] = rs;
72114
+ } else if (ps === rs) {
72115
+ literalCount++;
72116
+ } else {
72117
+ return null;
72118
+ }
72119
+ }
72120
+ pathParameters[proxyName] = requestSegments.slice(fixedPrefixLen).join("/");
72121
+ return { pathParameters, literalCount };
72122
+ }
72123
+ function isPlaceholder(segment) {
72124
+ return /^\{[^/{}+]+\}$/.test(segment);
72125
+ }
72126
+
72127
+ // src/local/http-server.ts
72128
+ async function startApiServer(opts) {
72129
+ const logger = getLogger().child("start-api");
72130
+ const server = createServer2((req, res) => {
72131
+ handleRequest(req, res, opts).catch((err) => {
72132
+ logger.error(
72133
+ `Unhandled request error: ${err instanceof Error ? err.stack ?? err.message : String(err)}`
72134
+ );
72135
+ if (!res.headersSent) {
72136
+ writeError(res, 502);
72137
+ }
72138
+ });
72139
+ });
72140
+ server.on("connection", (socket) => {
72141
+ socket.setNoDelay(true);
72142
+ });
72143
+ const { actualPort, actualHost } = await new Promise(
72144
+ (resolveListen, rejectListen) => {
72145
+ server.once("error", rejectListen);
72146
+ server.listen(opts.port, opts.host, () => {
72147
+ const addr = server.address();
72148
+ if (addr === null || typeof addr === "string") {
72149
+ rejectListen(new Error("Could not determine listening address"));
72150
+ return;
72151
+ }
72152
+ resolveListen({ actualPort: addr.port, actualHost: opts.host });
72153
+ });
72154
+ }
72155
+ );
72156
+ let closed = false;
72157
+ return {
72158
+ port: actualPort,
72159
+ host: actualHost,
72160
+ server,
72161
+ close: async () => {
72162
+ if (closed)
72163
+ return;
72164
+ closed = true;
72165
+ await new Promise((resolveClose) => {
72166
+ server.close(() => resolveClose());
72167
+ server.closeAllConnections?.();
72168
+ });
72169
+ }
72170
+ };
72171
+ }
72172
+ async function handleRequest(req, res, opts) {
72173
+ const logger = getLogger().child("start-api");
72174
+ const bodyBuf = await readBody(req);
72175
+ const rawUrl = req.url ?? "/";
72176
+ const method = (req.method ?? "GET").toUpperCase();
72177
+ const requestPath = rawUrl.split("?")[0] ?? "/";
72178
+ const match = matchRoute(method, requestPath, opts.routes);
72179
+ if (!match) {
72180
+ writeError(res, 404, '{"message":"Not Found"}');
72181
+ return;
72182
+ }
72183
+ const snapshot = {
72184
+ method,
72185
+ rawUrl,
72186
+ headers: collectHeaders(req),
72187
+ body: bodyBuf,
72188
+ ...req.socket.remoteAddress !== void 0 && { sourceIp: req.socket.remoteAddress }
72189
+ };
72190
+ const matchCtx = {
72191
+ route: match.route,
72192
+ pathParameters: match.pathParameters,
72193
+ matchedPath: requestPath
72194
+ };
72195
+ const event = match.route.apiVersion === "v1" ? buildRestV1Event(snapshot, matchCtx) : buildHttpApiV2Event(snapshot, matchCtx);
72196
+ let handle;
72197
+ try {
72198
+ handle = await opts.pool.acquire(match.route.lambdaLogicalId);
72199
+ } catch (err) {
72200
+ logger.error(
72201
+ `Failed to acquire container for ${match.route.lambdaLogicalId}: ${err instanceof Error ? err.message : String(err)}`
72202
+ );
72203
+ writeError(res, 502);
72204
+ return;
72205
+ }
72206
+ try {
72207
+ const invokeResult = await invokeRie(
72208
+ handle.containerHost,
72209
+ handle.hostPort,
72210
+ event,
72211
+ opts.rieTimeoutMs
72212
+ );
72213
+ const translated = translateLambdaResponse(invokeResult.payload, match.route.apiVersion);
72214
+ res.statusCode = translated.statusCode;
72215
+ for (const [name, value] of Object.entries(translated.headers)) {
72216
+ res.setHeader(name, value);
72217
+ }
72218
+ if (translated.cookies.length > 0) {
72219
+ res.setHeader("set-cookie", translated.cookies);
72220
+ }
72221
+ res.end(translated.body);
72222
+ } catch (err) {
72223
+ logger.error(
72224
+ `RIE invoke failed for ${match.route.lambdaLogicalId}: ${err instanceof Error ? err.message : String(err)}`
72225
+ );
72226
+ if (!res.headersSent) {
72227
+ writeError(res, 502);
72228
+ } else {
72229
+ res.end();
72230
+ }
72231
+ } finally {
72232
+ opts.pool.release(handle);
72233
+ }
72234
+ }
72235
+ function readBody(req) {
72236
+ return new Promise((resolveBody, rejectBody) => {
72237
+ const chunks = [];
72238
+ req.on("data", (chunk) => {
72239
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
72240
+ });
72241
+ req.on("end", () => resolveBody(Buffer.concat(chunks)));
72242
+ req.on("error", rejectBody);
72243
+ });
72244
+ }
72245
+ function collectHeaders(req) {
72246
+ const out = {};
72247
+ for (const [name, value] of Object.entries(req.headers)) {
72248
+ if (Array.isArray(value)) {
72249
+ out[name] = value;
72250
+ } else if (typeof value === "string") {
72251
+ out[name] = [value];
72252
+ }
72253
+ }
72254
+ return out;
72255
+ }
72256
+ function writeError(res, statusCode, body = '{"message":"Internal server error"}') {
72257
+ res.statusCode = statusCode;
72258
+ res.setHeader("content-type", "application/json");
72259
+ res.setHeader("content-length", String(Buffer.byteLength(body, "utf-8")));
72260
+ res.end(body);
72261
+ }
72262
+
72263
+ // src/cli/commands/local-start-api.ts
72264
+ async function localStartApiCommand(options) {
70636
72265
  const logger = getLogger();
70637
72266
  if (options.verbose) {
70638
72267
  logger.setLevel("debug");
@@ -70655,15 +72284,469 @@ async function localInvokeCommand(target, options) {
70655
72284
  ...Object.keys(context).length > 0 && { context }
70656
72285
  };
70657
72286
  const { stacks } = await synthesizer.synthesize(synthOpts);
70658
- const lambda = resolveLambdaTarget(target, stacks);
70659
- logger.info(`Target: ${lambda.stack.stackName}/${lambda.logicalId} (${lambda.runtime})`);
72287
+ const targetStacks = pickTargetStacks(stacks, options.stack);
72288
+ if (targetStacks.length === 0) {
72289
+ throw new Error("No stacks matched. Pass --stack <name> or run from a single-stack app.");
72290
+ }
72291
+ const routes = discoverRoutes(targetStacks);
72292
+ if (routes.length === 0) {
72293
+ throw new Error(
72294
+ "No supported API routes were discovered. cdkd local start-api supports AWS::ApiGateway::* (REST v1), AWS::ApiGatewayV2::* (HTTP), and AWS::Lambda::Url (Function URL) with AWS_PROXY integrations only."
72295
+ );
72296
+ }
72297
+ const lambdaIds = uniqueLambdaIds(routes);
72298
+ const overrides = readEnvOverridesFile(options.envVars);
72299
+ const debugPortBase = options.debugPortBase ? parseDebugPort(options.debugPortBase) : void 0;
72300
+ const specs = /* @__PURE__ */ new Map();
72301
+ const inlineTmpDirs = /* @__PURE__ */ new Set();
72302
+ for (let i = 0; i < lambdaIds.length; i++) {
72303
+ const logicalId = lambdaIds[i];
72304
+ const spec = await buildContainerSpec({
72305
+ logicalId,
72306
+ stacks: targetStacks,
72307
+ overrides,
72308
+ assumeRole: options.assumeRole,
72309
+ containerHost: options.containerHost,
72310
+ ...debugPortBase !== void 0 && { debugPort: debugPortBase + i },
72311
+ stsRegion: options.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"],
72312
+ inlineTmpDirs
72313
+ });
72314
+ specs.set(logicalId, spec);
72315
+ }
72316
+ const distinctImages = /* @__PURE__ */ new Set();
72317
+ for (const spec of specs.values()) {
72318
+ distinctImages.add(resolveRuntimeImage(spec.lambda.runtime));
72319
+ }
72320
+ for (const image of distinctImages) {
72321
+ await pullImage(image, options.pull === false);
72322
+ }
72323
+ const perLambdaConcurrency = parsePerLambdaConcurrency(options.perLambdaConcurrency);
72324
+ const pool = createContainerPool(specs, {
72325
+ perLambdaConcurrency,
72326
+ skipPull: options.pull === false
72327
+ });
72328
+ if (options.warm) {
72329
+ logger.info(`Pre-warming ${specs.size} container(s)...`);
72330
+ const handles = await Promise.allSettled([...specs.keys()].map((id) => pool.acquire(id)));
72331
+ for (const result of handles) {
72332
+ if (result.status === "fulfilled") {
72333
+ pool.release(result.value);
72334
+ } else {
72335
+ logger.warn(
72336
+ `Pre-warm failed for one Lambda (cold start cost will apply on first request): ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`
72337
+ );
72338
+ }
72339
+ }
72340
+ }
72341
+ let maxTimeoutSec = 0;
72342
+ for (const spec of specs.values()) {
72343
+ if (spec.lambda.timeoutSec > maxTimeoutSec)
72344
+ maxTimeoutSec = spec.lambda.timeoutSec;
72345
+ }
72346
+ const rieTimeoutMs = Math.max(3e4, maxTimeoutSec * 2 * 1e3);
72347
+ const port = parseInt(options.port, 10);
72348
+ if (!Number.isFinite(port) || port < 0 || port > 65535) {
72349
+ throw new Error(`--port must be 0..65535 (got ${options.port}).`);
72350
+ }
72351
+ const server = await startApiServer({
72352
+ routes,
72353
+ pool,
72354
+ rieTimeoutMs,
72355
+ host: options.host,
72356
+ port
72357
+ });
72358
+ printRouteTable(routes);
72359
+ logger.info(
72360
+ `Per-Lambda concurrency: ${perLambdaConcurrency} (override with --per-lambda-concurrency)`
72361
+ );
72362
+ process.stdout.write(`Server listening on http://${server.host}:${server.port}
72363
+ `);
72364
+ process.stdout.write("^C to stop and clean up containers.\n");
72365
+ let shuttingDown = false;
72366
+ let forceExitArmed = false;
72367
+ const shutdown = async (signal, exitCode) => {
72368
+ if (shuttingDown) {
72369
+ if (!forceExitArmed) {
72370
+ forceExitArmed = true;
72371
+ logger.warn(
72372
+ `Received second ${signal}; force-exiting. Orphan containers may remain \u2014 run 'docker ps --filter name=cdkd-local-' and 'docker rm -f' to clean up.`
72373
+ );
72374
+ process.exit(130);
72375
+ }
72376
+ return;
72377
+ }
72378
+ shuttingDown = true;
72379
+ logger.info(`Received ${signal}, shutting down...`);
72380
+ try {
72381
+ await server.close();
72382
+ } catch (err) {
72383
+ logger.warn(`server.close() failed: ${err instanceof Error ? err.message : String(err)}`);
72384
+ }
72385
+ try {
72386
+ await pool.dispose();
72387
+ } catch (err) {
72388
+ logger.warn(`pool.dispose() failed: ${err instanceof Error ? err.message : String(err)}`);
72389
+ }
72390
+ for (const dir of inlineTmpDirs) {
72391
+ try {
72392
+ rmSync2(dir, { recursive: true, force: true });
72393
+ } catch (err) {
72394
+ logger.warn(
72395
+ `Failed to remove inline-code tmpdir ${dir}: ${err instanceof Error ? err.message : String(err)}`
72396
+ );
72397
+ }
72398
+ }
72399
+ process.exit(exitCode);
72400
+ };
72401
+ process.on("SIGINT", () => {
72402
+ void shutdown("SIGINT", 130);
72403
+ });
72404
+ process.on("SIGTERM", () => {
72405
+ void shutdown("SIGTERM", 0);
72406
+ });
72407
+ process.on("uncaughtException", (err) => {
72408
+ logger.error(
72409
+ `Uncaught exception: ${err instanceof Error ? err.stack ?? err.message : String(err)}`
72410
+ );
72411
+ void shutdown("uncaughtException", 1);
72412
+ });
72413
+ process.on("unhandledRejection", (reason) => {
72414
+ logger.error(
72415
+ `Unhandled rejection: ${reason instanceof Error ? reason.stack ?? reason.message : String(reason)}`
72416
+ );
72417
+ void shutdown("unhandledRejection", 1);
72418
+ });
72419
+ await new Promise(() => void 0);
72420
+ }
72421
+ function pickTargetStacks(stacks, pattern) {
72422
+ if (pattern) {
72423
+ return matchStacks(stacks, [pattern]);
72424
+ }
72425
+ if (stacks.length === 1)
72426
+ return stacks;
72427
+ if (stacks.length === 0)
72428
+ return [];
72429
+ throw new Error(
72430
+ `Multi-stack app: pass --stack <name> to pick a target. Available stacks: ${stacks.map((s) => s.stackName).join(", ")}.`
72431
+ );
72432
+ }
72433
+ function uniqueLambdaIds(routes) {
72434
+ const seen = /* @__PURE__ */ new Set();
72435
+ const out = [];
72436
+ for (const r of routes) {
72437
+ if (!seen.has(r.lambdaLogicalId)) {
72438
+ seen.add(r.lambdaLogicalId);
72439
+ out.push(r.lambdaLogicalId);
72440
+ }
72441
+ }
72442
+ return out;
72443
+ }
72444
+ async function buildContainerSpec(args) {
72445
+ const {
72446
+ logicalId,
72447
+ stacks,
72448
+ overrides,
72449
+ assumeRole,
72450
+ containerHost,
72451
+ debugPort,
72452
+ stsRegion,
72453
+ inlineTmpDirs
72454
+ } = args;
72455
+ const lambda = resolveLambdaByLogicalId(logicalId, stacks);
70660
72456
  const codeDir = lambda.codePath ?? materializeInlineCode(
70661
72457
  lambda.handler,
70662
72458
  lambda.inlineCode ?? "",
70663
- resolveRuntimeFileExtension(lambda.runtime)
72459
+ resolveRuntimeFileExtension(lambda.runtime),
72460
+ inlineTmpDirs
70664
72461
  );
72462
+ const templateEnv = getTemplateEnv(lambda.resource);
72463
+ const envResult = resolveEnvVars(logicalId, templateEnv, overrides);
72464
+ for (const key of envResult.unresolved) {
72465
+ getLogger().warn(
72466
+ `Lambda ${logicalId}: env var ${key} contains a CloudFormation intrinsic and was dropped. Override it with --env-vars (e.g. {"${logicalId}":{"${key}":"<literal>"}}) to surface a literal value.`
72467
+ );
72468
+ }
72469
+ const dockerEnv = {
72470
+ AWS_LAMBDA_FUNCTION_NAME: logicalId,
72471
+ AWS_LAMBDA_FUNCTION_MEMORY_SIZE: String(lambda.memoryMb),
72472
+ AWS_LAMBDA_FUNCTION_TIMEOUT: String(lambda.timeoutSec),
72473
+ AWS_LAMBDA_FUNCTION_VERSION: "$LATEST",
72474
+ AWS_LAMBDA_LOG_GROUP_NAME: `/aws/lambda/${logicalId}`,
72475
+ AWS_LAMBDA_LOG_STREAM_NAME: "local",
72476
+ ...envResult.resolved
72477
+ };
72478
+ const roleArn = effectiveAssumeRoleArn(logicalId, assumeRole);
72479
+ if (roleArn) {
72480
+ const creds = await assumeLambdaExecutionRole(roleArn, stsRegion);
72481
+ dockerEnv["AWS_ACCESS_KEY_ID"] = creds.accessKeyId;
72482
+ dockerEnv["AWS_SECRET_ACCESS_KEY"] = creds.secretAccessKey;
72483
+ dockerEnv["AWS_SESSION_TOKEN"] = creds.sessionToken;
72484
+ if (stsRegion)
72485
+ dockerEnv["AWS_REGION"] = stsRegion;
72486
+ } else {
72487
+ forwardAwsEnv(dockerEnv);
72488
+ }
72489
+ if (debugPort !== void 0) {
72490
+ dockerEnv["NODE_OPTIONS"] = `--inspect-brk=0.0.0.0:${debugPort}`;
72491
+ }
72492
+ const spec = {
72493
+ lambda,
72494
+ codeDir,
72495
+ env: dockerEnv,
72496
+ containerHost,
72497
+ ...debugPort !== void 0 && { debugPort }
72498
+ };
72499
+ return spec;
72500
+ }
72501
+ function resolveLambdaByLogicalId(logicalId, stacks) {
72502
+ for (const stack of stacks) {
72503
+ const resource = stack.template.Resources?.[logicalId];
72504
+ if (!resource || resource.Type !== "AWS::Lambda::Function")
72505
+ continue;
72506
+ const props = resource.Properties ?? {};
72507
+ const runtime = typeof props["Runtime"] === "string" ? props["Runtime"] : "";
72508
+ const handler = typeof props["Handler"] === "string" ? props["Handler"] : "";
72509
+ const memoryMb = typeof props["MemorySize"] === "number" ? props["MemorySize"] : 128;
72510
+ const timeoutSec = typeof props["Timeout"] === "number" ? props["Timeout"] : 3;
72511
+ if (!runtime) {
72512
+ throw new Error(
72513
+ `Lambda '${logicalId}' has no Runtime property. Container-image Lambdas (Code.ImageUri) are not supported in cdkd local start-api v1.`
72514
+ );
72515
+ }
72516
+ if (!handler) {
72517
+ throw new Error(`Lambda '${logicalId}' has no Handler property.`);
72518
+ }
72519
+ const code = props["Code"] ?? {};
72520
+ const imageUri = code["ImageUri"];
72521
+ if (typeof imageUri === "string" || typeof imageUri === "object" && imageUri !== null && "Fn::Sub" in imageUri) {
72522
+ throw new Error(
72523
+ `Lambda '${logicalId}' uses Code.ImageUri (container-image Lambda). 'cdkd local start-api' v1 supports ZIP Lambdas only \u2014 container-image support is deferred to a follow-up PR. Use 'cdkd local invoke' to exercise this function locally.`
72524
+ );
72525
+ }
72526
+ const inlineCode = typeof code["ZipFile"] === "string" ? code["ZipFile"] : void 0;
72527
+ let codePath = null;
72528
+ if (!inlineCode) {
72529
+ codePath = resolveAssetCodePath2(stack, logicalId, resource);
72530
+ }
72531
+ return {
72532
+ kind: "zip",
72533
+ stack,
72534
+ logicalId,
72535
+ resource,
72536
+ runtime,
72537
+ handler,
72538
+ memoryMb,
72539
+ timeoutSec,
72540
+ codePath,
72541
+ ...inlineCode !== void 0 && { inlineCode }
72542
+ };
72543
+ }
72544
+ throw new Error(
72545
+ `No AWS::Lambda::Function resource named '${logicalId}' found in target stacks. This is likely a synthesis bug \u2014 the route-discovery phase resolved a route to this logical ID.`
72546
+ );
72547
+ }
72548
+ function resolveAssetCodePath2(stack, logicalId, resource) {
72549
+ const meta = resource.Metadata;
72550
+ const assetPath = meta?.["aws:asset:path"];
72551
+ if (typeof assetPath !== "string" || assetPath.length === 0) {
72552
+ throw new Error(
72553
+ `Lambda '${logicalId}' has no Metadata['aws:asset:path']. cdkd local start-api needs this hint to find the local asset directory. Re-synthesize the app and retry.`
72554
+ );
72555
+ }
72556
+ const cdkOutDir = stack.assetManifestPath ? path.dirname(stack.assetManifestPath) : process.cwd();
72557
+ return path.isAbsolute(assetPath) ? assetPath : path.resolve(cdkOutDir, assetPath);
72558
+ }
72559
+ function printRouteTable(routes) {
72560
+ const sorted = [...routes].sort((a, b) => {
72561
+ if (a.pathPattern !== b.pathPattern)
72562
+ return a.pathPattern.localeCompare(b.pathPattern);
72563
+ return a.method.localeCompare(b.method);
72564
+ });
72565
+ const methodWidth = Math.max(...sorted.map((r) => r.method.length), 6);
72566
+ const pathWidth = Math.max(...sorted.map((r) => r.pathPattern.length), 8);
72567
+ process.stdout.write("Discovered routes:\n");
72568
+ for (const r of sorted) {
72569
+ const sourceLabel = r.source === "http-api" ? "HTTP API" : r.source === "rest-v1" ? `REST v1, stage '${r.stage}'` : "Function URL";
72570
+ process.stdout.write(
72571
+ ` ${r.method.padEnd(methodWidth)} ${r.pathPattern.padEnd(pathWidth)} -> ${r.lambdaLogicalId} (${sourceLabel})
72572
+ `
72573
+ );
72574
+ }
72575
+ process.stdout.write("\n");
72576
+ }
72577
+ function materializeInlineCode(handler, source, fileExtension, tmpDirsOut) {
72578
+ const lastDot = handler.lastIndexOf(".");
72579
+ if (lastDot <= 0) {
72580
+ throw new Error(`Handler '${handler}' is malformed: expected '<modulePath>.<exportName>'.`);
72581
+ }
72582
+ const modulePath = handler.substring(0, lastDot);
72583
+ const dir = mkdtempSync2(path.join(tmpdir2(), "cdkd-local-start-api-"));
72584
+ tmpDirsOut.add(dir);
72585
+ const filePath = path.join(dir, `${modulePath}${fileExtension}`);
72586
+ mkdirSync2(path.dirname(filePath), { recursive: true });
72587
+ writeFileSync5(filePath, source, "utf-8");
72588
+ return dir;
72589
+ }
72590
+ function getTemplateEnv(resource) {
72591
+ const props = resource.Properties ?? {};
72592
+ const env = props["Environment"];
72593
+ if (!env || typeof env !== "object")
72594
+ return void 0;
72595
+ const vars = env["Variables"];
72596
+ if (!vars || typeof vars !== "object")
72597
+ return void 0;
72598
+ return vars;
72599
+ }
72600
+ function readEnvOverridesFile(filePath) {
72601
+ if (!filePath)
72602
+ return void 0;
72603
+ let raw;
72604
+ try {
72605
+ raw = readFileSync6(filePath, "utf-8");
72606
+ } catch (err) {
72607
+ throw new Error(
72608
+ `Failed to read --env-vars file '${filePath}': ${err instanceof Error ? err.message : String(err)}`
72609
+ );
72610
+ }
72611
+ let parsed;
72612
+ try {
72613
+ parsed = JSON.parse(raw);
72614
+ } catch (err) {
72615
+ throw new Error(
72616
+ `Failed to parse --env-vars file '${filePath}' as JSON: ${err instanceof Error ? err.message : String(err)}`
72617
+ );
72618
+ }
72619
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
72620
+ throw new Error(`--env-vars file '${filePath}' must contain a JSON object at the top level.`);
72621
+ }
72622
+ return parsed;
72623
+ }
72624
+ function forwardAwsEnv(env) {
72625
+ const passThrough = [
72626
+ "AWS_ACCESS_KEY_ID",
72627
+ "AWS_SECRET_ACCESS_KEY",
72628
+ "AWS_SESSION_TOKEN",
72629
+ "AWS_REGION",
72630
+ "AWS_DEFAULT_REGION"
72631
+ ];
72632
+ for (const key of passThrough) {
72633
+ const value = process.env[key];
72634
+ if (value !== void 0)
72635
+ env[key] = value;
72636
+ }
72637
+ }
72638
+ async function assumeLambdaExecutionRole(roleArn, region) {
72639
+ const { STSClient: STSClient11, AssumeRoleCommand: AssumeRoleCommand2 } = await import("@aws-sdk/client-sts");
72640
+ const sts = new STSClient11({ ...region && { region } });
72641
+ try {
72642
+ const response = await sts.send(
72643
+ new AssumeRoleCommand2({
72644
+ RoleArn: roleArn,
72645
+ RoleSessionName: `cdkd-local-start-api-${Date.now()}`,
72646
+ DurationSeconds: 3600
72647
+ })
72648
+ );
72649
+ const creds = response.Credentials;
72650
+ if (!creds?.AccessKeyId || !creds.SecretAccessKey || !creds.SessionToken) {
72651
+ throw new Error(`AssumeRole(${roleArn}) returned no usable credentials.`);
72652
+ }
72653
+ return {
72654
+ accessKeyId: creds.AccessKeyId,
72655
+ secretAccessKey: creds.SecretAccessKey,
72656
+ sessionToken: creds.SessionToken
72657
+ };
72658
+ } finally {
72659
+ sts.destroy();
72660
+ }
72661
+ }
72662
+ function parsePerLambdaConcurrency(raw) {
72663
+ const parsed = parseInt(raw, 10);
72664
+ if (!Number.isFinite(parsed) || parsed < 1) {
72665
+ throw new Error(`--per-lambda-concurrency must be a positive integer (got '${raw}')`);
72666
+ }
72667
+ if (parsed > 4) {
72668
+ getLogger().warn(
72669
+ `--per-lambda-concurrency ${parsed} exceeds the v1 cap of 4; clamping to 4. (Raise this in a follow-up PR if your workload needs more.)`
72670
+ );
72671
+ return 4;
72672
+ }
72673
+ return parsed;
72674
+ }
72675
+ function parseDebugPort(raw) {
72676
+ const parsed = parseInt(raw, 10);
72677
+ if (!Number.isFinite(parsed) || parsed < 1 || parsed > 65535) {
72678
+ throw new Error(`--debug-port-base must be 1..65535 (got '${raw}')`);
72679
+ }
72680
+ return parsed;
72681
+ }
72682
+ function createLocalStartApiCommand() {
72683
+ const startApi = new Command14("start-api").description(
72684
+ "Run a long-running local HTTP server that maps API Gateway routes (REST v1, HTTP API, Function URL) to Lambda invocations against the AWS Lambda Runtime Interface Emulator (Docker required)."
72685
+ ).addOption(
72686
+ new Option7("--port <port>", "HTTP server port (default: auto-allocate)").default("0")
72687
+ ).addOption(new Option7("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option7("--stack <name>", "Stack to start (single-stack apps auto-detect)")).addOption(
72688
+ new Option7("--warm", "Pre-start one container per Lambda at server boot").default(false)
72689
+ ).addOption(
72690
+ new Option7(
72691
+ "--per-lambda-concurrency <n>",
72692
+ "Pool size cap per Lambda (default 2, max 4)"
72693
+ ).default("2")
72694
+ ).addOption(new Option7("--no-pull", "Skip docker pull (cached image)")).addOption(
72695
+ new Option7(
72696
+ "--container-host <host>",
72697
+ "Hostname/IP the container reaches the host on"
72698
+ ).default("host.docker.internal")
72699
+ ).addOption(
72700
+ new Option7(
72701
+ "--debug-port-base <port>",
72702
+ "Reserve a contiguous --debug-port range (one per Lambda)"
72703
+ )
72704
+ ).addOption(
72705
+ new Option7(
72706
+ "--env-vars <file>",
72707
+ 'JSON env-var overrides (SAM-compatible: {"LogicalId":{"KEY":"VALUE"}, "Parameters": {...}})'
72708
+ )
72709
+ ).addOption(
72710
+ new Option7(
72711
+ "--assume-role <arn-or-pair>",
72712
+ "Assume the Lambda's execution role and forward STS-issued temp creds. Bare <arn> = global default; <LogicalId>=<arn> = per-Lambda override (repeatable). Per-Lambda > global > unset (developer creds passed through)."
72713
+ ).argParser((raw, prev) => parseAssumeRoleToken(raw, prev))
72714
+ ).action(withErrorHandling(localStartApiCommand));
72715
+ [...commonOptions, ...appOptions, ...contextOptions].forEach((opt) => startApi.addOption(opt));
72716
+ startApi.addOption(deprecatedRegionOption);
72717
+ return startApi;
72718
+ }
72719
+
72720
+ // src/cli/commands/local-invoke.ts
72721
+ async function localInvokeCommand(target, options) {
72722
+ const logger = getLogger();
72723
+ if (options.verbose) {
72724
+ logger.setLevel("debug");
72725
+ }
72726
+ warnIfDeprecatedRegion(options);
72727
+ await applyRoleArnIfSet({ roleArn: options.roleArn, region: options.region });
72728
+ await ensureDockerAvailable();
72729
+ const appCmd = resolveApp(options.app);
72730
+ if (!appCmd) {
72731
+ throw new Error('No CDK app specified. Pass --app, set CDKD_APP, or add "app" to cdk.json.');
72732
+ }
72733
+ logger.info("Synthesizing CDK app...");
72734
+ const synthesizer = new Synthesizer();
72735
+ const context = parseContextOptions(options.context);
72736
+ const synthOpts = {
72737
+ app: appCmd,
72738
+ output: options.output,
72739
+ ...options.region && { region: options.region },
72740
+ ...options.profile && { profile: options.profile },
72741
+ ...Object.keys(context).length > 0 && { context }
72742
+ };
72743
+ const { stacks } = await synthesizer.synthesize(synthOpts);
72744
+ const lambda = resolveLambdaTarget(target, stacks);
72745
+ const targetLabel = lambda.kind === "zip" ? lambda.runtime : "container image";
72746
+ logger.info(`Target: ${lambda.stack.stackName}/${lambda.logicalId} (${targetLabel})`);
72747
+ const imagePlan = await resolveImagePlan(lambda, options);
70665
72748
  let stateAudit;
70666
- let templateEnv = getTemplateEnv(lambda.resource);
72749
+ let templateEnv = getTemplateEnv2(lambda.resource);
70667
72750
  let stateForRoleHint;
70668
72751
  if (options.fromState) {
70669
72752
  const loaded = await loadStateForStack(lambda.stack.stackName, lambda.stack.region, {
@@ -70688,7 +72771,7 @@ async function localInvokeCommand(target, options) {
70688
72771
  }
70689
72772
  }
70690
72773
  }
70691
- const overrides = readEnvOverridesFile(options.envVars);
72774
+ const overrides = readEnvOverridesFile2(options.envVars);
70692
72775
  const envResult = resolveEnvVars(lambda.logicalId, templateEnv, overrides);
70693
72776
  for (const key of envResult.unresolved) {
70694
72777
  if (stateAudit && stateAudit.unresolved.some((u) => u.key === key))
@@ -70701,7 +72784,6 @@ async function localInvokeCommand(target, options) {
70701
72784
  suggestAssumeRoleFromState(stateForRoleHint, lambda.logicalId);
70702
72785
  }
70703
72786
  const event = await readEvent(options);
70704
- const image = resolveRuntimeImage(lambda.runtime);
70705
72787
  const dockerEnv = {
70706
72788
  AWS_LAMBDA_FUNCTION_NAME: lambda.logicalId,
70707
72789
  AWS_LAMBDA_FUNCTION_MEMORY_SIZE: String(lambda.memoryMb),
@@ -70713,14 +72795,14 @@ async function localInvokeCommand(target, options) {
70713
72795
  };
70714
72796
  if (options.assumeRole) {
70715
72797
  const stsRegion = options.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"];
70716
- const creds = await assumeLambdaExecutionRole(options.assumeRole, stsRegion);
72798
+ const creds = await assumeLambdaExecutionRole2(options.assumeRole, stsRegion);
70717
72799
  dockerEnv["AWS_ACCESS_KEY_ID"] = creds.accessKeyId;
70718
72800
  dockerEnv["AWS_SECRET_ACCESS_KEY"] = creds.secretAccessKey;
70719
72801
  dockerEnv["AWS_SESSION_TOKEN"] = creds.sessionToken;
70720
72802
  if (stsRegion)
70721
72803
  dockerEnv["AWS_REGION"] = stsRegion;
70722
72804
  } else {
70723
- forwardAwsEnv(dockerEnv);
72805
+ forwardAwsEnv2(dockerEnv);
70724
72806
  }
70725
72807
  let debugPort;
70726
72808
  if (options.debugPort) {
@@ -70729,19 +72811,26 @@ async function localInvokeCommand(target, options) {
70729
72811
  throw new Error(`--debug-port must be an integer in 1..65535, got '${options.debugPort}'`);
70730
72812
  }
70731
72813
  dockerEnv["NODE_OPTIONS"] = `--inspect-brk=0.0.0.0:${debugPort}`;
72814
+ if (lambda.kind === "image") {
72815
+ logger.warn(
72816
+ "--debug-port sets NODE_OPTIONS unconditionally on container Lambdas. If the image's runtime is not Node.js, this flag is a no-op."
72817
+ );
72818
+ }
70732
72819
  }
70733
- await pullImage(image, options.pull === false);
70734
72820
  const hostPort = await pickFreePort();
70735
- const containerHost = options.containerHost || "127.0.0.1";
70736
- logger.info(`Starting container (image=${image}, port=${hostPort})...`);
72821
+ const containerHost = options.containerHost;
72822
+ logger.info(`Starting container (image=${imagePlan.image}, port=${hostPort})...`);
70737
72823
  const containerId = await runDetached({
70738
- image,
70739
- mounts: [{ hostPath: codeDir, containerPath: "/var/task", readOnly: true }],
72824
+ image: imagePlan.image,
72825
+ mounts: imagePlan.mounts,
70740
72826
  env: dockerEnv,
70741
- cmd: [lambda.handler],
72827
+ cmd: imagePlan.cmd,
70742
72828
  hostPort,
70743
72829
  host: containerHost,
70744
- ...debugPort !== void 0 && { debugPort }
72830
+ ...debugPort !== void 0 && { debugPort },
72831
+ ...imagePlan.platform !== void 0 && { platform: imagePlan.platform },
72832
+ ...imagePlan.entryPoint !== void 0 && { entryPoint: imagePlan.entryPoint },
72833
+ ...imagePlan.workingDir !== void 0 && { workingDir: imagePlan.workingDir }
70745
72834
  });
70746
72835
  const stopLogs = streamLogs(containerId);
70747
72836
  const sigintHandler = () => {
@@ -70762,9 +72851,94 @@ async function localInvokeCommand(target, options) {
70762
72851
  process.off("SIGINT", sigintHandler);
70763
72852
  stopLogs();
70764
72853
  await removeContainer(containerId);
72854
+ if (imagePlan.inlineTmpDir) {
72855
+ try {
72856
+ rmSync3(imagePlan.inlineTmpDir, { recursive: true, force: true });
72857
+ } catch (err) {
72858
+ getLogger().debug(
72859
+ `Failed to remove inline-code tmpdir ${imagePlan.inlineTmpDir}: ${err instanceof Error ? err.message : String(err)}`
72860
+ );
72861
+ }
72862
+ }
70765
72863
  }
70766
72864
  }
70767
- function getTemplateEnv(resource) {
72865
+ async function resolveImagePlan(lambda, options) {
72866
+ if (lambda.kind === "zip") {
72867
+ return resolveZipImagePlan(lambda, options);
72868
+ }
72869
+ return resolveContainerImagePlan(lambda, options);
72870
+ }
72871
+ async function resolveZipImagePlan(lambda, options) {
72872
+ let inlineTmpDir;
72873
+ let codeDir = lambda.codePath;
72874
+ if (codeDir === null) {
72875
+ inlineTmpDir = materializeInlineCode2(
72876
+ lambda.handler,
72877
+ lambda.inlineCode ?? "",
72878
+ resolveRuntimeFileExtension(lambda.runtime)
72879
+ );
72880
+ codeDir = inlineTmpDir;
72881
+ }
72882
+ const image = resolveRuntimeImage(lambda.runtime);
72883
+ await pullImage(image, options.pull === false);
72884
+ return {
72885
+ image,
72886
+ mounts: [{ hostPath: codeDir, containerPath: "/var/task", readOnly: true }],
72887
+ cmd: [lambda.handler],
72888
+ ...inlineTmpDir !== void 0 && { inlineTmpDir }
72889
+ };
72890
+ }
72891
+ async function resolveContainerImagePlan(lambda, options) {
72892
+ const logger = getLogger();
72893
+ const platform = architectureToPlatform(lambda.architecture);
72894
+ const localBuild = await resolveLocalBuildPlan(lambda);
72895
+ let imageRef;
72896
+ if (localBuild) {
72897
+ imageRef = await buildContainerImage(localBuild.asset, localBuild.cdkOutDir, {
72898
+ architecture: lambda.architecture
72899
+ });
72900
+ } else {
72901
+ if (!parseEcrUri(lambda.imageUri)) {
72902
+ throw new Error(
72903
+ `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.`
72904
+ );
72905
+ }
72906
+ logger.info(
72907
+ `No matching cdk.out asset for ${lambda.imageUri}; falling back to ECR pull (same-acct/region only)...`
72908
+ );
72909
+ imageRef = await pullEcrImage(lambda.imageUri, {
72910
+ skipPull: options.pull === false,
72911
+ ...options.region !== void 0 && { region: options.region }
72912
+ });
72913
+ }
72914
+ return {
72915
+ image: imageRef,
72916
+ mounts: [],
72917
+ cmd: lambda.imageConfig.command ?? [],
72918
+ platform,
72919
+ ...lambda.imageConfig.entryPoint && lambda.imageConfig.entryPoint.length > 0 && {
72920
+ entryPoint: lambda.imageConfig.entryPoint
72921
+ },
72922
+ ...lambda.imageConfig.workingDirectory !== void 0 && {
72923
+ workingDir: lambda.imageConfig.workingDirectory
72924
+ }
72925
+ };
72926
+ }
72927
+ async function resolveLocalBuildPlan(lambda) {
72928
+ const manifestPath = lambda.stack.assetManifestPath;
72929
+ if (!manifestPath)
72930
+ return void 0;
72931
+ const cdkOutDir = dirname3(manifestPath);
72932
+ const loader = new AssetManifestLoader();
72933
+ const manifest = await loader.loadManifest(cdkOutDir, lambda.stack.stackName);
72934
+ if (!manifest)
72935
+ return void 0;
72936
+ const entry = getDockerImageBySourceHash(manifest, lambda.imageUri);
72937
+ if (!entry)
72938
+ return void 0;
72939
+ return { asset: entry.asset, cdkOutDir };
72940
+ }
72941
+ function getTemplateEnv2(resource) {
70768
72942
  const props = resource.Properties ?? {};
70769
72943
  const env = props["Environment"];
70770
72944
  if (!env || typeof env !== "object")
@@ -70774,12 +72948,12 @@ function getTemplateEnv(resource) {
70774
72948
  return void 0;
70775
72949
  return vars;
70776
72950
  }
70777
- function readEnvOverridesFile(filePath) {
72951
+ function readEnvOverridesFile2(filePath) {
70778
72952
  if (!filePath)
70779
72953
  return void 0;
70780
72954
  let raw;
70781
72955
  try {
70782
- raw = readFileSync6(filePath, "utf-8");
72956
+ raw = readFileSync7(filePath, "utf-8");
70783
72957
  } catch (err) {
70784
72958
  throw new Error(
70785
72959
  `Failed to read --env-vars file '${filePath}': ${err instanceof Error ? err.message : String(err)}`
@@ -70807,7 +72981,7 @@ async function readEvent(options) {
70807
72981
  return parseEvent(raw, "<stdin>");
70808
72982
  }
70809
72983
  if (options.event) {
70810
- const raw = readFileSync6(options.event, "utf-8");
72984
+ const raw = readFileSync7(options.event, "utf-8");
70811
72985
  return parseEvent(raw, options.event);
70812
72986
  }
70813
72987
  return {};
@@ -70828,9 +73002,9 @@ async function readStdin() {
70828
73002
  }
70829
73003
  return Buffer.concat(chunks).toString("utf-8");
70830
73004
  }
70831
- async function assumeLambdaExecutionRole(roleArn, region) {
70832
- const { STSClient: STSClient10, AssumeRoleCommand: AssumeRoleCommand2 } = await import("@aws-sdk/client-sts");
70833
- const sts = new STSClient10({ ...region && { region } });
73005
+ async function assumeLambdaExecutionRole2(roleArn, region) {
73006
+ const { STSClient: STSClient11, AssumeRoleCommand: AssumeRoleCommand2 } = await import("@aws-sdk/client-sts");
73007
+ const sts = new STSClient11({ ...region && { region } });
70834
73008
  try {
70835
73009
  const response = await sts.send(
70836
73010
  new AssumeRoleCommand2({
@@ -70852,7 +73026,7 @@ async function assumeLambdaExecutionRole(roleArn, region) {
70852
73026
  sts.destroy();
70853
73027
  }
70854
73028
  }
70855
- function forwardAwsEnv(env) {
73029
+ function forwardAwsEnv2(env) {
70856
73030
  const passThrough = [
70857
73031
  "AWS_ACCESS_KEY_ID",
70858
73032
  "AWS_SECRET_ACCESS_KEY",
@@ -70866,16 +73040,16 @@ function forwardAwsEnv(env) {
70866
73040
  env[key] = value;
70867
73041
  }
70868
73042
  }
70869
- function materializeInlineCode(handler, source, fileExtension) {
73043
+ function materializeInlineCode2(handler, source, fileExtension) {
70870
73044
  const lastDot = handler.lastIndexOf(".");
70871
73045
  if (lastDot <= 0) {
70872
73046
  throw new Error(`Handler '${handler}' is malformed: expected '<modulePath>.<exportName>'.`);
70873
73047
  }
70874
73048
  const modulePath = handler.substring(0, lastDot);
70875
- const dir = mkdtempSync2(path.join(tmpdir2(), "cdkd-local-invoke-"));
70876
- const filePath = path.join(dir, `${modulePath}${fileExtension}`);
70877
- mkdirSync2(path.dirname(filePath), { recursive: true });
70878
- writeFileSync5(filePath, source, "utf-8");
73049
+ const dir = mkdtempSync3(path2.join(tmpdir3(), "cdkd-local-invoke-"));
73050
+ const filePath = path2.join(dir, `${modulePath}${fileExtension}`);
73051
+ mkdirSync3(path2.dirname(filePath), { recursive: true });
73052
+ writeFileSync6(filePath, source, "utf-8");
70879
73053
  return dir;
70880
73054
  }
70881
73055
  async function loadStateForStack(stackName, synthRegion, opts) {
@@ -70982,30 +73156,35 @@ function pickReferencedLogicalId(intrinsic) {
70982
73156
  return void 0;
70983
73157
  }
70984
73158
  function createLocalCommand() {
70985
- const local = new Command14("local").description(
73159
+ const local = new Command15("local").description(
70986
73160
  "Local Lambda execution against the AWS Lambda Runtime Interface Emulator (Docker required)"
70987
73161
  );
70988
- const invoke = new Command14("invoke").description(
73162
+ const invoke = new Command15("invoke").description(
70989
73163
  "Run a Lambda function locally in a Docker container (RIE-backed). Target accepts a CDK display path (MyStack/MyApi/Handler) or stack-qualified logical ID (MyStack:MyApiHandler1234ABCD). Single-stack apps may omit the stack prefix."
70990
- ).argument("<target>", "CDK display path or stack-qualified logical ID of the Lambda to invoke").addOption(new Option7("-e, --event <file>", "JSON event payload file (default: {})")).addOption(new Option7("--event-stdin", "Read event JSON from stdin").default(false)).addOption(
70991
- new Option7(
73164
+ ).argument("<target>", "CDK display path or stack-qualified logical ID of the Lambda to invoke").addOption(new Option8("-e, --event <file>", "JSON event payload file (default: {})")).addOption(new Option8("--event-stdin", "Read event JSON from stdin").default(false)).addOption(
73165
+ new Option8(
70992
73166
  "--env-vars <file>",
70993
73167
  'JSON env-var overrides (SAM-compatible: {"LogicalId":{"KEY":"VALUE"}})'
70994
73168
  )
70995
- ).addOption(new Option7("--no-pull", "Skip docker pull (use cached image)")).addOption(new Option7("--debug-port <port>", "Node --inspect-brk port (default: off)")).addOption(
70996
- new Option7("--container-host <host>", "Host to bind the RIE port to").default("127.0.0.1")
70997
73169
  ).addOption(
70998
- new Option7(
73170
+ new Option8(
73171
+ "--no-pull",
73172
+ "Skip docker pull (use cached image) \u2014 no-op for IMAGE local-build path; `docker build` does not pull base layers by default"
73173
+ )
73174
+ ).addOption(new Option8("--debug-port <port>", "Node --inspect-brk port (default: off)")).addOption(
73175
+ new Option8("--container-host <host>", "Host to bind the RIE port to").default("127.0.0.1")
73176
+ ).addOption(
73177
+ new Option8(
70999
73178
  "--assume-role <arn>",
71000
73179
  `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).`
71001
73180
  )
71002
73181
  ).addOption(
71003
- new Option7(
73182
+ new Option8(
71004
73183
  "--from-state",
71005
73184
  "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."
71006
73185
  ).default(false)
71007
73186
  ).addOption(
71008
- new Option7(
73187
+ new Option8(
71009
73188
  "--stack-region <region>",
71010
73189
  "Region of the cdkd state record to read (used with --from-state when the same stack name has state in multiple regions)."
71011
73190
  )
@@ -71015,6 +73194,7 @@ function createLocalCommand() {
71015
73194
  );
71016
73195
  invoke.addOption(deprecatedRegionOption);
71017
73196
  local.addCommand(invoke);
73197
+ local.addCommand(createLocalStartApiCommand());
71018
73198
  return local;
71019
73199
  }
71020
73200
 
@@ -71046,8 +73226,8 @@ function reorderArgs(argv) {
71046
73226
  return [...prefix, ...cmdAndAfter, ...beforeCmd];
71047
73227
  }
71048
73228
  async function main() {
71049
- const program = new Command15();
71050
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.69.0");
73229
+ const program = new Command16();
73230
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.71.0");
71051
73231
  program.addCommand(createBootstrapCommand());
71052
73232
  program.addCommand(createSynthCommand());
71053
73233
  program.addCommand(createListCommand());