@go-to-k/cdkd 0.157.0 → 0.158.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
@@ -1,14 +1,14 @@
1
1
  # cdkd (CDK Direct)
2
2
 
3
- Drop-in CDK CLI for existing CDK apps — faster deploys via AWS SDK instead of CloudFormation, with local emulation for Lambda, API Gateway, and ECS.
3
+ Drop-in CDK CLI for existing CDK apps — faster deploys via AWS SDK instead of CloudFormation, plus local emulation for Lambda, API Gateway, and ECS.
4
4
 
5
5
  - **Drop-in CDK compatible** — your existing CDK app code runs as-is.
6
6
  - **Up to 15x faster deploys than the AWS CDK CLI (CloudFormation)**
7
- - **Local dev for CDK apps** — invoke Lambdas, serve API Gateway routes, and run ECS tasks and services directly from your CDK code, no `cdk synth → sam local` round-trip.
7
+ - **Local dev for any CDK app** — invoke Lambdas, serve API Gateway routes, run ECS tasks/services directly from your CDK code. Works against both `cdkd deploy`-managed AND `cdk deploy`-managed (CloudFormation) stacks via `--from-state` / `--from-cfn-stack` — no migration, no `cdk synth → sam local` round-trip.
8
8
 
9
9
  ![cdk deploy vs cdkd deploy — side-by-side, 35s recording, real AWS deploy. cdkd finishes while cdk is still creating its CloudFormation changeset.](assets/cdk-vs-cdkd.gif)
10
10
 
11
- **cdkd complements the AWS CDK CLI rather than replacing it.** Use cdkd in dev/test for rapid iteration and SAM-style local execution; use the AWS CDK CLI in production for full CloudFormation tooling. Bidirectional migration is supported — [import an existing CloudFormation stack](#importing-existing-resources) into cdkd for iteration, or [export back to CloudFormation](#exporting-a-stack-back-to-cloudformation) when ready for production.
11
+ **cdkd complements the AWS CDK CLI rather than replacing it.** Use cdkd in dev/test for rapid iteration and SAM-style local execution; use the AWS CDK CLI in production for full CloudFormation tooling. Install cdkd alongside an existing `cdk deploy` workflow — no migration needed, `cdkd local *` reads deployed state directly via `--from-cfn-stack`. Bidirectional migration is also supported — [import](#importing-existing-resources) into cdkd or [export](#exporting-a-stack-back-to-cloudformation) back to CloudFormation when ready.
12
12
 
13
13
  > [!IMPORTANT]
14
14
  > cdkd is for dev/test workflows only — early in development, not yet production-ready.
@@ -25,10 +25,10 @@ Drop-in CDK CLI for existing CDK apps — faster deploys via AWS SDK instead of
25
25
  - **Rollback on failure**: When a deploy errors mid-stack, cdkd rolls back the resources it just created so the stack state stays consistent (CloudFormation parity — but cdkd does this without round-tripping through CFn). Pass `cdkd deploy --no-rollback` to skip rollback and keep the partial state for Terraform-style inspection / repair. See [Rollback behavior](#rollback-behavior).
26
26
  - **`--no-wait` for async resources**: Skip the multi-minute wait on CloudFront / RDS / ElastiCache / NAT Gateway and return as soon as the create call returns (CloudFormation always blocks)
27
27
  - **VPC route DependsOn relaxation (on by default)**: Drop CDK-injected defensive `DependsOn` edges from VPC Lambdas onto private-subnet routes so `CloudFront::Distribution` and `Lambda::Url` start their ~3-min propagation in parallel with NAT Gateway stabilization (~50% faster on VPC + Lambda + CloudFront stacks). Pass `--no-aggressive-vpc-parallel` to opt out.
28
- - **Local execution without deploying** (`cdkd local invoke` / `cdkd local start-api` / `cdkd local run-task` / `cdkd local start-service`): run any Lambda — stand up every API Gateway route as a local HTTP server — start every container in an `AWS::ECS::TaskDefinition` on a per-task docker network with the AWS-published metadata-endpoints sidecar — or boot an `AWS::ECS::Service` long-running with `DesiredCount` replicas + restart-on-exit + cross-service Service Connect / Cloud Map DNS discovery (boot multiple services in one invocation, peer containers reach each other by `<discoveryName>.<namespace>` / bare alias via docker `--add-host` overlay from an in-process Cloud Map registry). SAM-compatible mental model but reuses cdkd's synthesis / asset / route-discovery (no `template.yaml` round-trip). All AWS Lambda runtimes (Node.js / Python / Ruby / Java / .NET / `provided.*`) and one server per discovered API (HTTP API v2 / REST v1 / Function URL) with their own port / authorizers / CORS configs. `local start-service` covers the long-running counterpart of `run-task` (ECS Services with DesiredCount replicas); local load-balancer emulation and `--watch` hot-reload are tracked as follow-ups. `cdkd local run-task --from-state` (also honored by `local start-service`) substitutes intrinsic-valued container `Environment[].Value` (`Ref` / `Fn::GetAtt` / `Fn::Sub` / `Fn::Join` / `Fn::ImportValue` / `Fn::GetStackOutput`) and `Secrets[].ValueFrom` against the deployed cdkd state — `table.tableName` / `ecs.Secret.fromSecretsManager(secret)` / `ecs.Secret.fromSsmParameter(param)` / cross-stack output refs Just Work locally instead of silently dropping.
29
- - **Bidirectional CloudFormation migration**: `cdkd import` adopts AWS-deployed resources (including `cdk deploy`-managed CloudFormation stacks via `--migrate-from-cloudformation`) into cdkd state without re-creating them; `cdkd export` hands a cdkd-managed stack back to CloudFormation when you're ready to move to production. See [Importing existing resources](#importing-existing-resources) and [Exporting a stack back to CloudFormation](#exporting-a-stack-back-to-cloudformation).
28
+ - **Local execution** (`cdkd local invoke` / `start-api` / `run-task` / `start-service`): run Lambdas, API Gateway routes, ECS tasks and long-running ECS services from your CDK code via Docker. All AWS Lambda runtimes, container Lambdas, REST v1 / HTTP v2 / Function URL routes, Service Connect / Cloud Map. Works for both `cdkd deploy`-managed (`--from-state`) AND `cdk deploy`-managed (`--from-cfn-stack`) stacks. See [Local execution](#local-execution).
29
+ - **Bidirectional CloudFormation migration**: `cdkd import --migrate-from-cloudformation` adopts existing CFn stacks (including `cdk deploy`-managed) into cdkd state without re-creating resources; `cdkd export` hands a cdkd stack back to CloudFormation when production-ready. See [Importing](#importing-existing-resources) / [Exporting](#exporting-a-stack-back-to-cloudformation).
30
30
 
31
- > **Note**: Resource types not covered by either SDK Providers or Cloud Control API cannot be deployed with cdkd. If you encounter an unsupported resource type, deployment will fail with a clear error message.
31
+ > **Note**: Resource types not covered by either SDK Providers or Cloud Control API cannot be deployed with cdkd. Deployment fails with a clear error message naming the type + a 1-click issue link.
32
32
 
33
33
  ## Benchmark
34
34
 
@@ -360,34 +360,7 @@ full reference. For per-resource-type provisioning support (SDK Providers
360
360
  vs Cloud Control API fallback), see
361
361
  **[docs/supported-resources.md](docs/supported-resources.md)**.
362
362
 
363
- ### Cross-stack references strong vs weak
364
-
365
- `Fn::ImportValue` is a **strong reference**: `cdkd destroy <producer>`
366
- refuses to delete a stack while any other stack still imports one of
367
- its exports via `Fn::ImportValue`. Matches CloudFormation's behavior.
368
- The error message names every offending consumer and points at the
369
- two valid resolution paths (destroy the consumer first, or remove
370
- the `Fn::ImportValue` from the consumer's template and redeploy).
371
-
372
- `Fn::GetStackOutput` (cdkd-specific) is a **weak reference**: the
373
- producer stays deletable independently of consumers. Use it when you
374
- intentionally want decoupled lifecycles (cross-region / cross-stage /
375
- staging environments).
376
-
377
- A persistent per-region exports index at
378
- `s3://{state-bucket}/cdkd/_index/{region}/exports.json` makes
379
- `Fn::ImportValue` resolution O(1) at scale (200-stack environments
380
- resolve in ~100ms vs minutes with the pre-#343 per-resolve scan).
381
- The index is a derived view rebuilt from `state.json` on demand —
382
- state.json remains the canonical source of truth, and strong-reference
383
- safety checks scan it directly rather than trusting the index.
384
-
385
- See **[docs/cross-stack-references.md](docs/cross-stack-references.md)**
386
- for the full design (`Fn::ImportValue` strong-reference rules added in
387
- state schema v4, lifecycle, locking, failure modes). State schema is at
388
- v5 since v0.100.0; `DeletionPolicy` / `UpdateReplacePolicy` changes
389
- between deploys are now detected and surfaced (see
390
- [docs/state-management.md](docs/state-management.md)).
363
+ **Property-level coverage is incremental.** SDK Providers wire most but not every CFn property of a supported type. cdkd fails fast at pre-flight when a template uses a not-yet-implemented property, with the property name + a 1-click issue link. `--allow-unsupported-properties <Type>:<Prop>,...` is the safety valve when this is too strict (e.g. mid-life update on an existing resource); avoid it on security-meaningful properties (encryption / IAM / TLS). See [docs/cli-reference.md](docs/cli-reference.md#--allow-unsupported-properties-deploy).
391
364
 
392
365
  ## Rollback behavior
393
366
 
@@ -453,90 +426,63 @@ maintain, no `cdk synth | sam ...` round-trip.
453
426
  | `cdkd local run-task <target>` | ECS RunTask — every container in a task definition started on a per-task docker network |
454
427
  | `cdkd local start-service <target>` | Long-running ECS Service emulator — `DesiredCount` replicas with restart-on-exit (no local load balancer in v1) |
455
428
 
456
- Requires Docker. Pass `--from-state` to substitute deployed physical
457
- IDs into intrinsic-valued properties (`Ref` / `Fn::GetAtt` / `Fn::Sub` /
458
- `Fn::Join` against the same stack's state plus AWS pseudo parameters
459
- via STS, AND `Fn::ImportValue` / `Fn::GetStackOutput` against the
460
- persistent exports index for cross-stack references same-account /
461
- same-region); without it, intrinsic values are dropped with a per-key
462
- warning (matches `sam local *` semantics).
429
+ Requires Docker. Pass `--from-state` (cdkd-deployed) or
430
+ `--from-cfn-stack` (cdk-deployed / CFn-managed) to substitute deployed
431
+ physical IDs into intrinsic-valued env vars / secrets / image URIs;
432
+ without either, intrinsic values are dropped with a per-key warning
433
+ (matches `sam local *`). The two flags are mutually exclusive.
463
434
 
464
435
  ### `local invoke`
465
436
 
466
437
  ```bash
467
- cdkd local invoke MyStack/MyApi/Handler # one-shot invoke
438
+ cdkd local invoke MyStack/Handler # one-shot invoke
468
439
  cdkd local invoke MyStack/Handler --event events/get.json
469
- cdkd local invoke MyStack/Handler --from-state # recover deployed env vars
440
+ cdkd local invoke MyStack/Handler --from-state # OR --from-cfn-stack
470
441
  ```
471
442
 
472
- Supports every current AWS Lambda runtime (Node.js / Python / Ruby /
473
- Java / .NET / `provided.al2023`), container Lambdas
474
- (`DockerImageFunction` / `Code.ImageUri`) via local-build or ECR pull,
475
- and same-stack Lambda Layers bind-mounted at `/opt`.
443
+ All AWS Lambda runtimes (Node.js / Python / Ruby / Java / .NET /
444
+ `provided.al2023`), ZIP and container Lambdas, same-stack Lambda Layers
445
+ bind-mounted at `/opt`.
476
446
 
477
447
  ### `local start-api`
478
448
 
479
449
  ```bash
480
- cdkd local start-api # one HTTP server per discovered API
481
- cdkd local start-api --port 3000 # pin the first server's port
482
- cdkd local start-api MyHttpApi # filter to one API (logical id, single-stack apps)
483
- cdkd local start-api MyStack/MyHttpApi # OR: CDK Construct path
484
- cdkd local start-api --warm --watch # pre-start + hot reload
485
- cdkd local start-api --from-state # substitute deployed env vars in Lambda Environment
450
+ cdkd local start-api # one HTTP server per discovered API
451
+ cdkd local start-api MyStack/MyHttpApi --watch # filter + hot reload
452
+ cdkd local start-api --from-state # OR --from-cfn-stack
486
453
  ```
487
454
 
488
- One server per discovered API authorizers, CORS configs, and stage
489
- variables stay scoped to the owning API. Supports REST v1 + HTTP API +
490
- Function URL with **AWS_PROXY** integrations AND every REST v1
491
- non-AWS_PROXY integration kind: **MOCK** (status-code selection via
492
- request template + response-template VTL), **HTTP_PROXY** (verbatim
493
- upstream forward with `RequestParameters` mappings), **HTTP**
494
- (HTTP_PROXY + bidirectional VTL), and **AWS** Lambda non-proxy
495
- (request + response VTL via the hand-rolled engine at
496
- `src/local/vtl-engine.ts`).
497
- Direct AWS-service integrations (S3 / SQS / SNS / DynamoDB / etc.) are
498
- NOT emulated — deploy to AWS or use HTTP_PROXY to a local mock instead.
499
- Authorizers: Lambda TOKEN / REQUEST, Cognito User Pool, HTTP v2 JWT
500
- (JWKS-verified), and REST v1 `AuthorizationType: 'AWS_IAM'` (SigV4
501
- signature verification only — IAM policy evaluation is not emulated;
502
- see `docs/local-emulation.md`). CORS preflight (HTTP API v2
503
- `CorsConfiguration` + REST v1 OPTIONS MOCK preflight from
504
- `defaultCorsPreflightOptions`); hot reload via `--watch`;
505
- deploy-state-backed env var substitution via `--from-state`.
506
-
507
- Function URL `InvokeMode: RESPONSE_STREAM` is supported (issue #467):
508
- streaming Lambdas are invoked via the RIE streaming protocol and the
509
- response is piped to the HTTP client with `Transfer-Encoding: chunked`.
510
- Note that AWS's local RIE buffers the response — incremental chunk
511
- delivery only manifests against the deployed Lambda runtime; locally
512
- the response shape is correct but arrives in one block.
513
-
514
- Routes whose integration cdkd cannot emulate (REST v1 AWS integration
515
- to a non-Lambda service, HTTP_PROXY / HTTP with non-literal `Uri`, HTTP
516
- API v2 service integrations, WebSocket APIs, Function URLs with IAM
517
- auth, cross-stack Lambda Arn references) **do not block boot** — the
518
- server starts with a per-route `[warn]` summary and returns HTTP 501 +
519
- the reason in the JSON body if and when the route is hit. This lets
520
- you run the rest of your API surface locally while the unsupported
521
- routes stay on the deployed API.
455
+ REST v1 + HTTP API v2 + Function URL with all integration kinds
456
+ (AWS_PROXY / MOCK / HTTP_PROXY / HTTP / AWS Lambda non-proxy via
457
+ hand-rolled VTL), authorizers (Lambda / Cognito / HTTP v2 JWT /
458
+ REST v1 AWS_IAM SigV4), CORS, stage variables, `--watch` hot reload.
522
459
 
523
460
  ### `local run-task`
524
461
 
525
462
  ```bash
526
463
  cdkd local run-task MyStack/MyService/TaskDef
527
- cdkd local run-task MyTaskDef --from-state # resolve deployed secrets / env intrinsics
464
+ cdkd local run-task MyTaskDef --from-state # OR --from-cfn-stack
528
465
  ```
529
466
 
530
- Starts every container in the task definition on a per-task docker
531
- network with the AWS-published ECS metadata sidecar
532
- (`amazon/amazon-ecs-local-container-endpoints`). `DependsOn` /
533
- `Secrets` / `Volumes` (Host / Docker) are honored; `Secrets[].ValueFrom`
534
- is resolved from SecretsManager / SSM at startup.
467
+ Every container in the task definition on a per-task docker network
468
+ with the AWS-published ECS metadata sidecar.
535
469
 
536
- See [docs/local-emulation.md](docs/local-emulation.md) for the full
537
- reference — supported runtimes, target resolution, every flag, exit
538
- codes, route precedence, container-pool semantics, networking model,
539
- v1 scope notes.
470
+ ### `local start-service`
471
+
472
+ ```bash
473
+ cdkd local start-service MyStack/Orders MyStack/Web # multiple services in one invocation
474
+ cdkd local start-service MyStack/Orders --from-state # OR --from-cfn-stack
475
+ ```
476
+
477
+ Long-running ECS Service emulator: `DesiredCount` replicas with
478
+ restart-on-exit, cross-service Service Connect / Cloud Map DNS
479
+ discovery (peer containers reach each other by `<discoveryName>.<namespace>`).
480
+ No local load-balancer in v1.
481
+
482
+ See **[docs/local-emulation.md](docs/local-emulation.md)** for the
483
+ full reference — runtimes, target resolution, every flag, integration
484
+ and authorizer detail, route precedence, container pool, networking,
485
+ `--from-cfn-stack` semantics, v1 scope.
540
486
 
541
487
  ## Importing existing resources
542
488
 
@@ -573,63 +519,31 @@ parity matrix vs upstream `cdk import`.
573
519
  ## Exporting a stack back to CloudFormation
574
520
 
575
521
  `cdkd export` is the mirror of `cdkd import`: it hands a cdkd-managed
576
- stack over to CloudFormation via a CFn `ChangeSetType=IMPORT` changeset.
522
+ stack back to CloudFormation via a CFn `ChangeSetType=IMPORT` changeset.
577
523
  AWS resources are unchanged across the migration; cdkd state for the
578
524
  exported stack is deleted on success. From then on the stack is managed
579
- by `cdk deploy` / `aws cloudformation`.
580
-
581
- Lambda-backed Custom Resources (`Custom::*` and
582
- `AWS::CloudFormation::CustomResource`) are NOT directly CFn-importable.
583
- `cdkd export --include-non-importable` opts into a 2-phase migration
584
- to handle them: phase 1 IMPORT changeset adopts every importable
585
- resource, then phase 2 UPDATE changeset re-CREATEs the Custom Resources
586
- through CFn — which re-invokes each backing Lambda's onCreate handler.
587
- The Custom Resource Lambda must be idempotent AND must POST to
588
- `event.ResponseURL` per the cfn-response protocol. Without the flag,
589
- the command refuses to proceed and the user is expected to destroy
590
- the offending resources (or accept abandoning them) first. Nested
591
- `AWS::CloudFormation::Stack` rows are fully supported as of
592
- [#464](https://github.com/go-to-k/cdkd/issues/464) PR B2: `cdkd export`
593
- recursively walks the cdkd state tree, validates every parent → child
594
- link, and submits **IMPORT changesets per cdkd-managed stack** in
595
- leaf-first order — leaf stacks via one CREATE-via-IMPORT changeset, non-leaf
596
- parents via two changesets (Phase 1A CREATE-via-IMPORT for the parent's
597
- leaf resources only, then Phase 1B UPDATE-via-IMPORT for the just-imported
598
- child adoption per AWS's
599
- ["Nest an existing stack"](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resource-import-nested-stacks.html)
600
- pattern with `DeletionPolicy: Retain` plus
601
- `ResourceIdentifier: { StackId: <child arn> }` plus AWS-validated
602
- child-Tag forwarding). Between phases cdkd flips each
603
- stack's status from `IMPORT_COMPLETE` to `UPDATE_COMPLETE` via a no-op
604
- tag-only `UpdateStack` (AWS rejects `IMPORT_COMPLETE` as a non-importable
605
- status for nested adoption). The original "one atomic
606
- `--include-nested-stacks` IMPORT changeset" design was found infeasible
607
- by the 2026-05-24 AWS spike — AWS rejects that flag combination with
608
- `ValidationError: IncludeNestedStacks is not supported for changeSet type: IMPORT`;
609
- see [docs/design/464-nested-stacks-export-import.md](docs/design/464-nested-stacks-export-import.md)
610
- §4.0 / §4.3 for the per-stack-loop algorithm. Each child cdkd stack
611
- (`<parent>~<childLogicalId>`) becomes its own CFn stack named
612
- `<parent>-<childLogicalId>` by default (`~` is illegal in CFn stack
613
- names); override per child with `--cfn-child-stack-name '<cdkd>=<cfn>'`
614
- (repeatable). Fresh `cdkd deploy` of nested stacks works via
615
- [#459](https://github.com/go-to-k/cdkd/issues/459).
525
+ by `cdk deploy` / `aws cloudformation`. Accepts JSON and YAML templates
526
+ (shorthand intrinsics round-trip).
616
527
 
617
528
  ```bash
618
529
  cdkd export MyStack # confirmation prompt; CFn stack name = cdkd stack name
619
530
  cdkd export MyStack --cfn-stack-name MyStack-CFn
620
531
  cdkd export MyStack --dry-run # print the import plan, do not call CFn
621
- cdkd export MyStack --template path.json # skip synth, use a pre-rendered template (JSON or YAML — format auto-detected)
622
532
  cdkd export MyStack --include-non-importable # 2-phase: IMPORT importable + CFn-CREATE Custom Resources
623
-
624
- # Nested-stack tree (parent + children). Default child CFn names: '<parent>-<childLogicalId>'.
625
- cdkd export MyApp # leaf-first per-stack IMPORT loop
626
- cdkd export MyApp --cfn-child-stack-name 'MyApp~Database=my-app-db' # per-child name override
533
+ cdkd export MyApp # nested-stack tree: leaf-first per-stack IMPORT loop
627
534
  ```
628
535
 
629
- Accepts JSON and YAML templates. YAML round-trips through a CFn-aware codec
630
- (`src/cli/yaml-cfn.ts`) that preserves every shorthand intrinsic (`!Ref` /
631
- `!GetAtt` / `!Sub` / `!Join` / etc.), so a YAML-authored CFn stack stays YAML
632
- on the phase-1 IMPORT and phase-2 UPDATE changesets.
536
+ **Lambda-backed Custom Resources** (`Custom::*` /
537
+ `AWS::CloudFormation::CustomResource`) are NOT directly CFn-importable.
538
+ `--include-non-importable` opts into a 2-phase migration that re-CREATEs
539
+ them through CFn — the Custom Resource Lambda must be idempotent.
540
+ **Nested stacks** are supported via a leaf-first per-stack IMPORT loop
541
+ (AWS rejects `--include-nested-stacks` for IMPORT changesets).
542
+
543
+ See **[docs/import.md](docs/import.md)** for the full guide — Custom Resource
544
+ 2-phase flow, nested-stack adoption mechanics (`--cfn-child-stack-name`
545
+ per-child overrides, AWS's "Nest an existing stack" pattern), and the
546
+ design rationale at [docs/design/464-nested-stacks-export-import.md](docs/design/464-nested-stacks-export-import.md).
633
547
 
634
548
  ## Drift detection
635
549
 
@@ -671,22 +585,11 @@ Both `cdkd destroy` (synth-driven) and `cdkd state destroy`
671
585
 
672
586
  ## `--remove-protection`: one-shot bypass for protected resources
673
587
 
674
- CDK's `new Stack(app, 'X', { terminationProtection: true })` is honored
675
- by `cdkd destroy` (refused before any per-resource delete). The
676
- state-only path `cdkd state destroy` does NOT honor it that's the
677
- explicit "I know what I'm doing, ignore CDK guards" escape hatch.
678
-
679
- For resource-level protection (`DeletionProtection` etc.), the standard
680
- workflow is edit CDK → redeploy → destroy. `--remove-protection` is the
681
- one-shot bypass:
682
-
683
- `cdkd destroy --remove-protection` and `cdkd state destroy
684
- --remove-protection` flip every protection flag off in-place
685
- before each provider's delete API call so the destroy proceeds
686
- without an intermediate edit / redeploy. The flag covers both
687
- stack-level `terminationProtection` (the bypass logs a WARN line
688
- naming the stack) and resource-level protection on the following
689
- types:
588
+ `cdkd destroy --remove-protection` (and `cdkd state destroy --remove-protection`)
589
+ flips every protection flag off in-place before each provider's delete
590
+ API call, so a destroy proceeds without an intermediate edit / redeploy.
591
+ Covers stack-level `terminationProtection` (logged as a WARN) AND
592
+ resource-level protection on these types:
690
593
 
691
594
  | Resource type | Protection field |
692
595
  | --- | --- |