@go-to-k/cdkd 0.88.0 → 0.90.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
@@ -79381,6 +79381,7 @@ async function exportCommand(stackArg, options) {
79381
79381
  let template;
79382
79382
  let resolvedStackName;
79383
79383
  let synthedRegion;
79384
+ let allSynthStacks = [];
79384
79385
  if (options.template) {
79385
79386
  if (!stackArg) {
79386
79387
  throw new Error(
@@ -79424,6 +79425,10 @@ async function exportCommand(stackArg, options) {
79424
79425
  template = stackInfo.template;
79425
79426
  resolvedStackName = stackInfo.stackName;
79426
79427
  synthedRegion = stackInfo.region;
79428
+ allSynthStacks = result.stacks.map((s) => ({
79429
+ stackName: s.stackName,
79430
+ template: s.template
79431
+ }));
79427
79432
  }
79428
79433
  const cfnStackName = options.cfnStackName ?? resolvedStackName;
79429
79434
  const targetRegion = await pickStackRegion2(
@@ -79512,6 +79517,26 @@ async function exportCommand(stackArg, options) {
79512
79517
  return;
79513
79518
  }
79514
79519
  }
79520
+ reportDriftBaselineGaps(state, logger);
79521
+ if (allSynthStacks.length > 0) {
79522
+ const crossRefs = scanCrossStackReferences(allSynthStacks, resolvedStackName);
79523
+ if (crossRefs.length > 0) {
79524
+ const lines = crossRefs.map(
79525
+ (r) => ` ${r.consumerStackName} \u2192 ${resolvedStackName}.${r.outputName} at ${r.location}`
79526
+ );
79527
+ if (options.strictCrossStack) {
79528
+ throw new Error(
79529
+ `Refusing to export: ${crossRefs.length} cross-stack reference(s) to ${resolvedStackName} found in sibling stacks. After migration, those references will break (cdkd's Fn::GetStackOutput reads cdkd state; the migrated stack's outputs live in CFn). Migrate consumers first, or remove the references, or drop --strict-cross-stack to proceed with a warning:
79530
+ ` + lines.join("\n")
79531
+ );
79532
+ }
79533
+ logger.warn(
79534
+ `${crossRefs.length} cross-stack reference(s) to '${resolvedStackName}' from sibling stacks. These will break the next time those stacks deploy via cdkd (cdkd's Fn::GetStackOutput resolver reads cdkd state; the migrated stack's outputs are now in CFn). Plan multi-stack migrations from the leaves up.`
79535
+ );
79536
+ for (const line of lines)
79537
+ logger.warn(line);
79538
+ }
79539
+ }
79515
79540
  const userParameters = parseParameterOverrides(options.parameter);
79516
79541
  const { parameters: cfnParameters, missing } = resolveTemplateParameters(
79517
79542
  template,
@@ -79862,6 +79887,76 @@ function filterTemplateForImport(template, plan) {
79862
79887
  }
79863
79888
  return result;
79864
79889
  }
79890
+ function reportDriftBaselineGaps(state, logger) {
79891
+ const entries = Object.entries(state.resources ?? {});
79892
+ if (entries.length === 0)
79893
+ return;
79894
+ const missing = entries.filter(([, r]) => r.observedProperties === void 0);
79895
+ if (missing.length === 0)
79896
+ return;
79897
+ if (state.version !== void 0 && state.version < 3) {
79898
+ logger.warn(
79899
+ `cdkd state schema is v${state.version} (pre-observedProperties). cdkd drift cannot reliably compare against AWS for this stack; the next \`cdk deploy\` after migration may surface spurious changes if AWS has drifted from the template. Run \`cdkd state refresh-observed ${state.stackName}\` (or any redeploy) before export to capture an AWS-current baseline.`
79900
+ );
79901
+ return;
79902
+ }
79903
+ logger.warn(
79904
+ `${missing.length} of ${entries.length} resource(s) in cdkd state lack an AWS-current baseline (observedProperties). cdkd drift may produce false positives for them; the next \`cdk deploy\` after migration may surface unexpected changes. Run \`cdkd state refresh-observed ${state.stackName}\` to capture a baseline before export, then \`cdkd drift\` to verify the stack matches AWS.`
79905
+ );
79906
+ for (const [logicalId] of missing.slice(0, 10)) {
79907
+ logger.warn(` ${logicalId}`);
79908
+ }
79909
+ if (missing.length > 10) {
79910
+ logger.warn(` ... and ${missing.length - 10} more`);
79911
+ }
79912
+ }
79913
+ function scanCrossStackReferences(stacks, exportingStackName) {
79914
+ const refs = [];
79915
+ for (const stack of stacks) {
79916
+ if (stack.stackName === exportingStackName)
79917
+ continue;
79918
+ walkForGetStackOutput(stack.template, "", (ref) => {
79919
+ if (ref.stackName === exportingStackName) {
79920
+ refs.push({
79921
+ consumerStackName: stack.stackName,
79922
+ outputName: ref.outputName,
79923
+ location: ref.location
79924
+ });
79925
+ }
79926
+ });
79927
+ }
79928
+ return refs;
79929
+ }
79930
+ function walkForGetStackOutput(node, path3, emit) {
79931
+ if (!node || typeof node !== "object")
79932
+ return;
79933
+ if (Array.isArray(node)) {
79934
+ node.forEach((item, i) => walkForGetStackOutput(item, `${path3}[${i}]`, emit));
79935
+ return;
79936
+ }
79937
+ const obj = node;
79938
+ const intrinsic = obj["Fn::GetStackOutput"];
79939
+ if (intrinsic !== void 0) {
79940
+ if (intrinsic && typeof intrinsic === "object" && !Array.isArray(intrinsic)) {
79941
+ const i = intrinsic;
79942
+ const stackName = typeof i["StackName"] === "string" ? i["StackName"] : void 0;
79943
+ const outputName = typeof i["OutputName"] === "string" ? i["OutputName"] : void 0;
79944
+ if (stackName && outputName) {
79945
+ emit({ stackName, outputName, location: path3 });
79946
+ }
79947
+ } else if (Array.isArray(intrinsic) && intrinsic.length === 2) {
79948
+ const arr = intrinsic;
79949
+ const stackName = arr[0];
79950
+ const outputName = arr[1];
79951
+ if (typeof stackName === "string" && typeof outputName === "string") {
79952
+ emit({ stackName, outputName, location: path3 });
79953
+ }
79954
+ }
79955
+ }
79956
+ for (const [key, value] of Object.entries(obj)) {
79957
+ walkForGetStackOutput(value, path3 ? `${path3}.${key}` : key, emit);
79958
+ }
79959
+ }
79865
79960
  function referencesOnly(node, allow) {
79866
79961
  if (!node || typeof node !== "object")
79867
79962
  return true;
@@ -80106,6 +80201,10 @@ function createExportCommand() {
80106
80201
  ).option(
80107
80202
  "--parameter <key=value...>",
80108
80203
  "CFn template Parameter override, repeatable. Required when the synthesized template has Parameters without Default values; otherwise overrides the template's default value. Format: --parameter Key=Value."
80204
+ ).option(
80205
+ "--strict-cross-stack",
80206
+ "Refuse to export when sibling cdkd stacks in the same CDK app reference the exporting stack via Fn::GetStackOutput. Without the flag, cdkd warns but proceeds \u2014 the user is expected to migrate the consumer stacks in a follow-up.",
80207
+ false
80109
80208
  ).action(withErrorHandling(exportCommand));
80110
80209
  [...commonOptions, ...appOptions, ...stateOptions, ...contextOptions].forEach(
80111
80210
  (opt) => cmd.addOption(opt)
@@ -80144,7 +80243,7 @@ function reorderArgs(argv) {
80144
80243
  }
80145
80244
  async function main() {
80146
80245
  const program = new Command18();
80147
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.88.0");
80246
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.90.0");
80148
80247
  program.addCommand(createBootstrapCommand());
80149
80248
  program.addCommand(createSynthCommand());
80150
80249
  program.addCommand(createListCommand());