@go-to-k/cdkd 0.95.0 → 0.96.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -420,8 +420,8 @@ and same-stack Lambda Layers bind-mounted at `/opt`.
420
420
  ```bash
421
421
  cdkd local start-api # one HTTP server per discovered API
422
422
  cdkd local start-api --port 3000 # pin the first server's port
423
- cdkd local start-api --api MyHttpApi # filter by logical id
424
- cdkd local start-api --api MyStack/MyHttpApi # OR: CDK Construct path
423
+ cdkd local start-api MyHttpApi # filter to one API (logical id, single-stack apps)
424
+ cdkd local start-api MyStack/MyHttpApi # OR: CDK Construct path
425
425
  cdkd local start-api --warm --watch # pre-start + hot reload
426
426
  ```
427
427
 
@@ -455,6 +455,16 @@ v1 scope notes.
455
455
  `cdk deploy`, manual creation, or another tool) into cdkd state so the
456
456
  next `cdkd deploy` updates them in-place instead of CREATEing duplicates.
457
457
 
458
+ `cdkd import --migrate-from-cloudformation` extends this to migrate a
459
+ **whole CloudFormation stack** off CFn in a single command: cdkd reads
460
+ the source CFn stack's `(logicalId, physicalId)` mappings, adopts every
461
+ resource into cdkd state, then retires the source CFn stack (injects
462
+ `DeletionPolicy: Retain` + `UpdateReplacePolicy: Retain` on every
463
+ resource → `UpdateStack` → `DeleteStack`) so the AWS resources stay
464
+ intact but are no longer tracked by CFn. After the command finishes,
465
+ the stack is managed by `cdkd deploy`. This is the reverse direction
466
+ of `cdkd export` (see below).
467
+
458
468
  ```bash
459
469
  # Adopt a whole stack previously deployed by cdk deploy (tag-based auto-lookup).
460
470
  cdkd import MyStack --yes
@@ -479,17 +489,28 @@ AWS resources are unchanged across the migration; cdkd state for the
479
489
  exported stack is deleted on success. From then on the stack is managed
480
490
  by `cdk deploy` / `aws cloudformation`.
481
491
 
492
+ Lambda-backed Custom Resources (`Custom::*` and
493
+ `AWS::CloudFormation::CustomResource`) are NOT directly CFn-importable.
494
+ `cdkd export --include-non-importable` opts into a 2-phase migration
495
+ to handle them: phase 1 IMPORT changeset adopts every importable
496
+ resource, then phase 2 UPDATE changeset re-CREATEs the Custom Resources
497
+ through CFn — which re-invokes each backing Lambda's onCreate handler.
498
+ The Custom Resource Lambda must be idempotent AND must POST to
499
+ `event.ResponseURL` per the cfn-response protocol. Without the flag,
500
+ the command refuses to proceed and the user is expected to destroy
501
+ the offending resources (or accept abandoning them) first. Nested
502
+ `AWS::CloudFormation::Stack` references always block (CFn can neither
503
+ adopt nor recreate them).
504
+
482
505
  ```bash
483
506
  cdkd export MyStack # confirmation prompt; CFn stack name = cdkd stack name
484
507
  cdkd export MyStack --cfn-stack-name MyStack-CFn
485
508
  cdkd export MyStack --dry-run # print the import plan, do not call CFn
486
509
  cdkd export MyStack --template path.json # skip synth, use a pre-rendered JSON template
510
+ cdkd export MyStack --include-non-importable # 2-phase: IMPORT importable + CFn-CREATE Custom Resources
487
511
  ```
488
512
 
489
- MVP scope: JSON templates only (CDK-generated). The command refuses to
490
- proceed if any resource is not CFn-importable (Lambda-backed Custom
491
- Resources, nested `AWS::CloudFormation::Stack` references); destroy or
492
- accept abandoning those resources first.
513
+ MVP scope: JSON templates only (CDK-generated).
493
514
 
494
515
  ## Drift detection
495
516
 
package/dist/cli.js CHANGED
@@ -37882,19 +37882,20 @@ function groupRoutesByServer(routes) {
37882
37882
  let kind;
37883
37883
  let identifier;
37884
37884
  let displayName;
37885
+ const stackPrefix = r.apiStackName ? `${r.apiStackName}:` : "";
37885
37886
  if (r.source === "function-url") {
37886
37887
  identifier = r.lambdaLogicalId;
37887
- serverKey = `function-url:${identifier}`;
37888
+ serverKey = `function-url:${stackPrefix}${identifier}`;
37888
37889
  kind = "function-url";
37889
37890
  displayName = `${identifier} (Function URL)`;
37890
37891
  } else if (r.source === "http-api") {
37891
37892
  identifier = r.apiLogicalId ?? "<unknown>";
37892
- serverKey = `http-api:${identifier}`;
37893
+ serverKey = `http-api:${stackPrefix}${identifier}`;
37893
37894
  kind = "http-api";
37894
37895
  displayName = `${identifier} (HTTP API v2)`;
37895
37896
  } else {
37896
37897
  identifier = r.apiLogicalId ?? "<unknown>";
37897
- serverKey = `rest-v1:${identifier}`;
37898
+ serverKey = `rest-v1:${stackPrefix}${identifier}`;
37898
37899
  kind = "rest-v1";
37899
37900
  displayName = `${identifier} (REST API v1)`;
37900
37901
  }
@@ -38300,9 +38301,15 @@ function createAuthorizerCache(opts = {}) {
38300
38301
  * See [docs/cli-reference.md](../../../docs/cli-reference.md) for the
38301
38302
  * full surface and out-of-scope items.
38302
38303
  */
38303
- async function localStartApiCommand(options) {
38304
+ async function localStartApiCommand(target, options) {
38304
38305
  const logger = getLogger();
38305
38306
  if (options.verbose) logger.setLevel("debug");
38307
+ let apiFilter = target;
38308
+ if (options.api !== void 0) {
38309
+ if (target !== void 0) throw new Error(`Cannot specify both positional target ('${target}') and --api flag ('${options.api}'). Use one or the other. The positional form is preferred — '--api' is a deprecated alias.`);
38310
+ logger.warn("[deprecated] --api <id> will be removed in a future major release. Use the positional argument instead: 'cdkd local start-api <id>'.");
38311
+ apiFilter = options.api;
38312
+ }
38306
38313
  warnIfDeprecatedRegion(options);
38307
38314
  await applyRoleArnIfSet({
38308
38315
  roleArn: options.roleArn,
@@ -38362,11 +38369,12 @@ async function localStartApiCommand(options) {
38362
38369
  }
38363
38370
  attachStageContext(routes, stageMap);
38364
38371
  let routesWithAuth = attachAuthorizers(targetStacks, routes);
38365
- if (options.api) {
38366
- const filtered = filterRoutesByApiIdentifier(routesWithAuth, options.api);
38372
+ if (apiFilter !== void 0) {
38373
+ if (!apiFilter.includes(":") && !apiFilter.includes("/") && targetStacks.length > 1) throw new Error(`Multiple stacks in app, target '${apiFilter}' is missing a stack prefix. Use 'StackName:${apiFilter}' or 'StackName/${apiFilter}' (Construct path form). Available stacks: ${targetStacks.map((s) => s.stackName).join(", ")}.`);
38374
+ const filtered = filterRoutesByApiIdentifier(routesWithAuth, apiFilter);
38367
38375
  if (filtered.length === 0) {
38368
38376
  const available = availableApiIdentifiers(routesWithAuth).join(", ") || "(none)";
38369
- throw new Error(`--api '${options.api}' did not match any discovered API. Available identifiers: ${available}.`);
38377
+ throw new Error(`Target '${apiFilter}' did not match any discovered API. Available identifiers: ${available}.`);
38370
38378
  }
38371
38379
  routesWithAuth = filtered;
38372
38380
  }
@@ -38990,7 +38998,7 @@ function parseDebugPort(raw) {
38990
38998
  * Builder for the `start-api` subcommand. Wired up by `local.ts`.
38991
38999
  */
38992
39000
  function createLocalStartApiCommand() {
38993
- const startApi = new Command("start-api").description("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). Supports Lambda TOKEN/REQUEST authorizers and Cognito User Pool / HTTP v2 JWT authorizers; when JWKS is unreachable, JWT authorizers fall back to pass-through (every token accepted) with a warn line — local dev fallback. VPC-config Lambdas run locally and surface a warn line at startup; their containers do NOT get attached to the deployed VPC subnets, so calls to private RDS / ElastiCache will fail.").addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--stack <name>", "Stack to start (single-stack apps auto-detect)")).addOption(new Option("--warm", "Pre-start one container per Lambda at server boot").default(false)).addOption(new Option("--per-lambda-concurrency <n>", "Pool size cap per Lambda (default 2, max 4)").default("2")).addOption(new Option("--no-pull", "Skip docker pull (cached image)")).addOption(new Option("--container-host <host>", "IP the host uses to bind/probe the RIE port (must be a numeric IP — `docker run -p <ip>:<port>:8080` rejects hostnames). Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--debug-port-base <port>", "Reserve a contiguous --debug-port range (one per Lambda)")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--assume-role <arn-or-pair>", "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).").argParser((raw, prev) => parseAssumeRoleToken(raw, prev))).addOption(new Option("--watch", "Hot-reload: re-synth + re-discover routes when cdk.out/ or asset directories change. Off by default; the server keeps the previous version serving when synth fails mid-reload.").default(false)).addOption(new Option("--stage <name>", "Select an API Gateway Stage by its 'StageName'. Default: the first Stage attached to each API. Drives event.stageVariables for both REST v1 and HTTP API v2. NOTE: For HTTP API v2 routes, requestContext.stage is always '$default' regardless of this flag (AWS-side limitation — HTTP API only exposes one stage to the integration event); only event.stageVariables is affected for v2 routes. For REST v1 routes the selected StageName is also threaded into requestContext.stage.")).addOption(new Option("--api <id>", "Restrict to a single API surface. Accepts the bare CDK logical id (e.g. 'MyHttpApi'), the stack-qualified logical id ('MyStack:MyHttpApi'), the full CDK Construct path ('MyStack/MyHttpApi/Resource'), or an ancestor Construct path that prefix-matches ('MyStack/MyHttpApi'). For Function URLs, the path forms reference the backing Lambda's aws:cdk:path. When unset, every discovered API gets its own server on its own port (basePort, basePort+1, ... when --port is set; auto-allocated otherwise).")).action(withErrorHandling(localStartApiCommand));
39001
+ const startApi = new Command("start-api").description("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). Supports Lambda TOKEN/REQUEST authorizers and Cognito User Pool / HTTP v2 JWT authorizers; when JWKS is unreachable, JWT authorizers fall back to pass-through (every token accepted) with a warn line — local dev fallback. VPC-config Lambdas run locally and surface a warn line at startup; their containers do NOT get attached to the deployed VPC subnets, so calls to private RDS / ElastiCache will fail.").argument("[target]", "Optional API filter. Accepts the bare CDK logical id ('MyHttpApi'; single-stack apps only), stack-qualified logical id ('MyStack:MyHttpApi'), full CDK Construct path ('MyStack/MyHttpApi/Resource'), or an ancestor Construct path that prefix-matches ('MyStack/MyHttpApi'). When omitted, every discovered API gets its own server. Mirrors `cdkd local invoke` / `cdkd local run-task` target syntax.").addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--stack <name>", "Stack to start (single-stack apps auto-detect)")).addOption(new Option("--warm", "Pre-start one container per Lambda at server boot").default(false)).addOption(new Option("--per-lambda-concurrency <n>", "Pool size cap per Lambda (default 2, max 4)").default("2")).addOption(new Option("--no-pull", "Skip docker pull (cached image)")).addOption(new Option("--container-host <host>", "IP the host uses to bind/probe the RIE port (must be a numeric IP — `docker run -p <ip>:<port>:8080` rejects hostnames). Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--debug-port-base <port>", "Reserve a contiguous --debug-port range (one per Lambda)")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--assume-role <arn-or-pair>", "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).").argParser((raw, prev) => parseAssumeRoleToken(raw, prev))).addOption(new Option("--watch", "Hot-reload: re-synth + re-discover routes when cdk.out/ or asset directories change. Off by default; the server keeps the previous version serving when synth fails mid-reload.").default(false)).addOption(new Option("--stage <name>", "Select an API Gateway Stage by its 'StageName'. Default: the first Stage attached to each API. Drives event.stageVariables for both REST v1 and HTTP API v2. NOTE: For HTTP API v2 routes, requestContext.stage is always '$default' regardless of this flag (AWS-side limitation — HTTP API only exposes one stage to the integration event); only event.stageVariables is affected for v2 routes. For REST v1 routes the selected StageName is also threaded into requestContext.stage.")).addOption(new Option("--api <id>", "DEPRECATED use the positional <target> argument instead. Same accepted forms (bare logical id, stack-qualified, Construct path, ancestor prefix). Will be removed in a future major release.")).action(withErrorHandling(localStartApiCommand));
38994
39002
  [
38995
39003
  ...commonOptions,
38996
39004
  ...appOptions,
@@ -41829,7 +41837,7 @@ function reorderArgs(argv) {
41829
41837
  */
41830
41838
  async function main() {
41831
41839
  const program = new Command();
41832
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.94.15");
41840
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.96.0");
41833
41841
  program.addCommand(createBootstrapCommand());
41834
41842
  program.addCommand(createSynthCommand());
41835
41843
  program.addCommand(createListCommand());