@aws-blocks/core 0.1.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/LICENSE +174 -0
- package/dist/api.d.ts +147 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +10 -0
- package/dist/api.test.d.ts +2 -0
- package/dist/api.test.d.ts.map +1 -0
- package/dist/api.test.js +19 -0
- package/dist/bb-utils.d.ts +11 -0
- package/dist/bb-utils.d.ts.map +1 -0
- package/dist/bb-utils.js +12 -0
- package/dist/builtin-routes.d.ts +6 -0
- package/dist/builtin-routes.d.ts.map +1 -0
- package/dist/builtin-routes.js +57 -0
- package/dist/cdk/__fixtures__/factory-backend.d.ts +3 -0
- package/dist/cdk/__fixtures__/factory-backend.d.ts.map +1 -0
- package/dist/cdk/__fixtures__/factory-backend.js +6 -0
- package/dist/cdk/__fixtures__/fullid-construct-backend.d.ts +2 -0
- package/dist/cdk/__fixtures__/fullid-construct-backend.d.ts.map +1 -0
- package/dist/cdk/__fixtures__/fullid-construct-backend.js +37 -0
- package/dist/cdk/__fixtures__/handler.d.ts +5 -0
- package/dist/cdk/__fixtures__/handler.d.ts.map +1 -0
- package/dist/cdk/__fixtures__/handler.js +3 -0
- package/dist/cdk/__fixtures__/side-effect-backend.d.ts +2 -0
- package/dist/cdk/__fixtures__/side-effect-backend.d.ts.map +1 -0
- package/dist/cdk/__fixtures__/side-effect-backend.js +5 -0
- package/dist/cdk/blocks-backend.d.ts +68 -0
- package/dist/cdk/blocks-backend.d.ts.map +1 -0
- package/dist/cdk/blocks-backend.js +214 -0
- package/dist/cdk/blocks-backend.test.d.ts +2 -0
- package/dist/cdk/blocks-backend.test.d.ts.map +1 -0
- package/dist/cdk/blocks-backend.test.js +151 -0
- package/dist/cdk/blocks-stack.test.d.ts +2 -0
- package/dist/cdk/blocks-stack.test.d.ts.map +1 -0
- package/dist/cdk/blocks-stack.test.js +78 -0
- package/dist/cdk/config-registry.d.ts +26 -0
- package/dist/cdk/config-registry.d.ts.map +1 -0
- package/dist/cdk/config-registry.js +80 -0
- package/dist/cdk/index.d.ts +35 -0
- package/dist/cdk/index.d.ts.map +1 -0
- package/dist/cdk/index.js +90 -0
- package/dist/cdk/mixins.d.ts +28 -0
- package/dist/cdk/mixins.d.ts.map +1 -0
- package/dist/cdk/mixins.js +37 -0
- package/dist/cdk/mixins.test.d.ts +2 -0
- package/dist/cdk/mixins.test.d.ts.map +1 -0
- package/dist/cdk/mixins.test.js +108 -0
- package/dist/cdk/node-version.d.ts +14 -0
- package/dist/cdk/node-version.d.ts.map +1 -0
- package/dist/cdk/node-version.js +15 -0
- package/dist/cdk/stack-metadata.d.ts +12 -0
- package/dist/cdk/stack-metadata.d.ts.map +1 -0
- package/dist/cdk/stack-metadata.js +22 -0
- package/dist/cdk/stack-metadata.test.d.ts +2 -0
- package/dist/cdk/stack-metadata.test.d.ts.map +1 -0
- package/dist/cdk/stack-metadata.test.js +56 -0
- package/dist/cdk/synth-guard.d.ts +14 -0
- package/dist/cdk/synth-guard.d.ts.map +1 -0
- package/dist/cdk/synth-guard.js +20 -0
- package/dist/cdk/synth-guard.test.d.ts +2 -0
- package/dist/cdk/synth-guard.test.d.ts.map +1 -0
- package/dist/cdk/synth-guard.test.js +15 -0
- package/dist/client/index.d.ts +97 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +238 -0
- package/dist/client/index.test.d.ts +2 -0
- package/dist/client/index.test.d.ts.map +1 -0
- package/dist/client/index.test.js +113 -0
- package/dist/common/config.d.ts +45 -0
- package/dist/common/config.d.ts.map +1 -0
- package/dist/common/config.js +154 -0
- package/dist/common/config.test.d.ts +2 -0
- package/dist/common/config.test.d.ts.map +1 -0
- package/dist/common/config.test.js +173 -0
- package/dist/common/constants.d.ts +11 -0
- package/dist/common/constants.d.ts.map +1 -0
- package/dist/common/constants.js +12 -0
- package/dist/common/crypto.d.ts +6 -0
- package/dist/common/crypto.d.ts.map +1 -0
- package/dist/common/crypto.js +14 -0
- package/dist/common/index.d.ts +220 -0
- package/dist/common/index.d.ts.map +1 -0
- package/dist/common/index.js +180 -0
- package/dist/common/index.test.d.ts +2 -0
- package/dist/common/index.test.d.ts.map +1 -0
- package/dist/common/index.test.js +195 -0
- package/dist/common/mock-data.d.ts +40 -0
- package/dist/common/mock-data.d.ts.map +1 -0
- package/dist/common/mock-data.js +39 -0
- package/dist/common/official-bb-names.generated.d.ts +7 -0
- package/dist/common/official-bb-names.generated.d.ts.map +1 -0
- package/dist/common/official-bb-names.generated.js +28 -0
- package/dist/common/sdk-registry.d.ts +136 -0
- package/dist/common/sdk-registry.d.ts.map +1 -0
- package/dist/common/sdk-registry.js +125 -0
- package/dist/constants.d.ts +27 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +28 -0
- package/dist/cors.d.ts +39 -0
- package/dist/cors.d.ts.map +1 -0
- package/dist/cors.js +85 -0
- package/dist/cors.test.d.ts +2 -0
- package/dist/cors.test.d.ts.map +1 -0
- package/dist/cors.test.js +241 -0
- package/dist/db-naming.d.ts +21 -0
- package/dist/db-naming.d.ts.map +1 -0
- package/dist/db-naming.js +38 -0
- package/dist/db-naming.test.d.ts +2 -0
- package/dist/db-naming.test.d.ts.map +1 -0
- package/dist/db-naming.test.js +29 -0
- package/dist/errors.d.ts +67 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +69 -0
- package/dist/hosting.d.ts +258 -0
- package/dist/hosting.d.ts.map +1 -0
- package/dist/hosting.js +340 -0
- package/dist/hosting.test.d.ts +2 -0
- package/dist/hosting.test.d.ts.map +1 -0
- package/dist/hosting.test.js +1077 -0
- package/dist/index.cdk.d.ts +13 -0
- package/dist/index.cdk.d.ts.map +1 -0
- package/dist/index.cdk.js +13 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/lambda-handler.d.ts +131 -0
- package/dist/lambda-handler.d.ts.map +1 -0
- package/dist/lambda-handler.js +610 -0
- package/dist/lambda-handler.test.d.ts +2 -0
- package/dist/lambda-handler.test.d.ts.map +1 -0
- package/dist/lambda-handler.test.js +835 -0
- package/dist/pipeline/index.d.ts +4 -0
- package/dist/pipeline/index.d.ts.map +1 -0
- package/dist/pipeline/index.js +3 -0
- package/dist/pipeline/pipeline-construct.d.ts +130 -0
- package/dist/pipeline/pipeline-construct.d.ts.map +1 -0
- package/dist/pipeline/pipeline-construct.js +484 -0
- package/dist/pipeline/pipeline.test.d.ts +2 -0
- package/dist/pipeline/pipeline.test.d.ts.map +1 -0
- package/dist/pipeline/pipeline.test.js +1231 -0
- package/dist/pipeline/types.d.ts +351 -0
- package/dist/pipeline/types.d.ts.map +1 -0
- package/dist/pipeline/types.js +3 -0
- package/dist/raw-route.cdk.d.ts +47 -0
- package/dist/raw-route.cdk.d.ts.map +1 -0
- package/dist/raw-route.cdk.js +51 -0
- package/dist/raw-route.d.ts +119 -0
- package/dist/raw-route.d.ts.map +1 -0
- package/dist/raw-route.js +239 -0
- package/dist/raw-route.mock.d.ts +47 -0
- package/dist/raw-route.mock.d.ts.map +1 -0
- package/dist/raw-route.mock.js +51 -0
- package/dist/raw-route.test.d.ts +2 -0
- package/dist/raw-route.test.d.ts.map +1 -0
- package/dist/raw-route.test.js +597 -0
- package/dist/redact.d.ts +51 -0
- package/dist/redact.d.ts.map +1 -0
- package/dist/redact.js +134 -0
- package/dist/redact.test.d.ts +2 -0
- package/dist/redact.test.d.ts.map +1 -0
- package/dist/redact.test.js +199 -0
- package/dist/rpc.d.ts +54 -0
- package/dist/rpc.d.ts.map +1 -0
- package/dist/rpc.js +127 -0
- package/dist/rpc.test.d.ts +2 -0
- package/dist/rpc.test.d.ts.map +1 -0
- package/dist/rpc.test.js +60 -0
- package/dist/scripts/cdk-telemetry-env.d.ts +13 -0
- package/dist/scripts/cdk-telemetry-env.d.ts.map +1 -0
- package/dist/scripts/cdk-telemetry-env.js +21 -0
- package/dist/scripts/cdk-telemetry-env.test.d.ts +2 -0
- package/dist/scripts/cdk-telemetry-env.test.d.ts.map +1 -0
- package/dist/scripts/cdk-telemetry-env.test.js +56 -0
- package/dist/scripts/cleanup.d.ts +3 -0
- package/dist/scripts/cleanup.d.ts.map +1 -0
- package/dist/scripts/cleanup.js +35 -0
- package/dist/scripts/console.d.ts +6 -0
- package/dist/scripts/console.d.ts.map +1 -0
- package/dist/scripts/console.js +25 -0
- package/dist/scripts/deploy.d.ts +6 -0
- package/dist/scripts/deploy.d.ts.map +1 -0
- package/dist/scripts/deploy.js +82 -0
- package/dist/scripts/destroy.d.ts +6 -0
- package/dist/scripts/destroy.d.ts.map +1 -0
- package/dist/scripts/destroy.js +30 -0
- package/dist/scripts/dev-server-cors.test.d.ts +2 -0
- package/dist/scripts/dev-server-cors.test.d.ts.map +1 -0
- package/dist/scripts/dev-server-cors.test.js +23 -0
- package/dist/scripts/dev-server-telemetry.test.d.ts +2 -0
- package/dist/scripts/dev-server-telemetry.test.d.ts.map +1 -0
- package/dist/scripts/dev-server-telemetry.test.js +113 -0
- package/dist/scripts/dev-server.d.ts +21 -0
- package/dist/scripts/dev-server.d.ts.map +1 -0
- package/dist/scripts/dev-server.js +456 -0
- package/dist/scripts/ensure-secrets.d.ts +31 -0
- package/dist/scripts/ensure-secrets.d.ts.map +1 -0
- package/dist/scripts/ensure-secrets.js +100 -0
- package/dist/scripts/ensure-secrets.test.d.ts +2 -0
- package/dist/scripts/ensure-secrets.test.d.ts.map +1 -0
- package/dist/scripts/ensure-secrets.test.js +44 -0
- package/dist/scripts/external-migrations-step.d.ts +62 -0
- package/dist/scripts/external-migrations-step.d.ts.map +1 -0
- package/dist/scripts/external-migrations-step.js +243 -0
- package/dist/scripts/external-migrations-step.test.d.ts +2 -0
- package/dist/scripts/external-migrations-step.test.d.ts.map +1 -0
- package/dist/scripts/external-migrations-step.test.js +47 -0
- package/dist/scripts/extract-ts-types.d.ts +65 -0
- package/dist/scripts/extract-ts-types.d.ts.map +1 -0
- package/dist/scripts/extract-ts-types.js +664 -0
- package/dist/scripts/extract-ts-types.test.d.ts +2 -0
- package/dist/scripts/extract-ts-types.test.d.ts.map +1 -0
- package/dist/scripts/extract-ts-types.test.js +497 -0
- package/dist/scripts/generate-client-worker.d.ts +2 -0
- package/dist/scripts/generate-client-worker.d.ts.map +1 -0
- package/dist/scripts/generate-client-worker.js +13 -0
- package/dist/scripts/generate-client.d.ts +14 -0
- package/dist/scripts/generate-client.d.ts.map +1 -0
- package/dist/scripts/generate-client.js +73 -0
- package/dist/scripts/generate-client.test.d.ts +2 -0
- package/dist/scripts/generate-client.test.d.ts.map +1 -0
- package/dist/scripts/generate-client.test.js +48 -0
- package/dist/scripts/generate-spec-cli.d.ts +3 -0
- package/dist/scripts/generate-spec-cli.d.ts.map +1 -0
- package/dist/scripts/generate-spec-cli.js +77 -0
- package/dist/scripts/generate-spec-cli.test.d.ts +14 -0
- package/dist/scripts/generate-spec-cli.test.d.ts.map +1 -0
- package/dist/scripts/generate-spec-cli.test.js +90 -0
- package/dist/scripts/generate-spec.d.ts +61 -0
- package/dist/scripts/generate-spec.d.ts.map +1 -0
- package/dist/scripts/generate-spec.js +746 -0
- package/dist/scripts/generate-spec.test.d.ts +12 -0
- package/dist/scripts/generate-spec.test.d.ts.map +1 -0
- package/dist/scripts/generate-spec.test.js +88 -0
- package/dist/scripts/index.d.ts +12 -0
- package/dist/scripts/index.d.ts.map +1 -0
- package/dist/scripts/index.js +13 -0
- package/dist/scripts/sandbox.d.ts +11 -0
- package/dist/scripts/sandbox.d.ts.map +1 -0
- package/dist/scripts/sandbox.js +200 -0
- package/dist/scripts/telemetry-cli.d.ts +3 -0
- package/dist/scripts/telemetry-cli.d.ts.map +1 -0
- package/dist/scripts/telemetry-cli.js +8 -0
- package/dist/scripts/telemetry.d.ts +17 -0
- package/dist/scripts/telemetry.d.ts.map +1 -0
- package/dist/scripts/telemetry.js +150 -0
- package/dist/scripts/telemetry.test.d.ts +2 -0
- package/dist/scripts/telemetry.test.d.ts.map +1 -0
- package/dist/scripts/telemetry.test.js +203 -0
- package/dist/scripts/validate-spec.d.ts +22 -0
- package/dist/scripts/validate-spec.d.ts.map +1 -0
- package/dist/scripts/validate-spec.js +159 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +3 -0
- package/dist/server/withAuth.d.ts +142 -0
- package/dist/server/withAuth.d.ts.map +1 -0
- package/dist/server/withAuth.js +261 -0
- package/dist/server/withAuth.test.d.ts +2 -0
- package/dist/server/withAuth.test.d.ts.map +1 -0
- package/dist/server/withAuth.test.js +278 -0
- package/dist/telemetry/client.d.ts +59 -0
- package/dist/telemetry/client.d.ts.map +1 -0
- package/dist/telemetry/client.js +215 -0
- package/dist/telemetry/config-writer.d.ts +16 -0
- package/dist/telemetry/config-writer.d.ts.map +1 -0
- package/dist/telemetry/config-writer.js +36 -0
- package/dist/telemetry/consent-commands.test.d.ts +2 -0
- package/dist/telemetry/consent-commands.test.d.ts.map +1 -0
- package/dist/telemetry/consent-commands.test.js +161 -0
- package/dist/telemetry/consent.d.ts +60 -0
- package/dist/telemetry/consent.d.ts.map +1 -0
- package/dist/telemetry/consent.js +122 -0
- package/dist/telemetry/environment.d.ts +33 -0
- package/dist/telemetry/environment.d.ts.map +1 -0
- package/dist/telemetry/environment.js +87 -0
- package/dist/telemetry/identifiers.d.ts +20 -0
- package/dist/telemetry/identifiers.d.ts.map +1 -0
- package/dist/telemetry/identifiers.js +86 -0
- package/dist/telemetry/index.d.ts +6 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +4 -0
- package/dist/telemetry/telemetry.test.d.ts +2 -0
- package/dist/telemetry/telemetry.test.d.ts.map +1 -0
- package/dist/telemetry/telemetry.test.js +1131 -0
- package/dist/telemetry/trackCommand.d.ts +32 -0
- package/dist/telemetry/trackCommand.d.ts.map +1 -0
- package/dist/telemetry/trackCommand.js +102 -0
- package/dist/telemetry/types.d.ts +92 -0
- package/dist/telemetry/types.d.ts.map +1 -0
- package/dist/telemetry/types.js +1 -0
- package/dist/types.d.ts +24 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/package.json +83 -0
- package/src/api.test.ts +25 -0
- package/src/api.ts +163 -0
- package/src/bb-utils.ts +13 -0
- package/src/builtin-routes.ts +62 -0
- package/src/cdk/__fixtures__/factory-backend.ts +8 -0
- package/src/cdk/__fixtures__/fullid-construct-backend.ts +42 -0
- package/src/cdk/__fixtures__/handler.ts +4 -0
- package/src/cdk/__fixtures__/side-effect-backend.ts +7 -0
- package/src/cdk/blocks-backend.test.ts +207 -0
- package/src/cdk/blocks-backend.ts +249 -0
- package/src/cdk/blocks-stack.test.ts +106 -0
- package/src/cdk/config-registry.ts +106 -0
- package/src/cdk/index.ts +115 -0
- package/src/cdk/mixins.test.ts +129 -0
- package/src/cdk/mixins.ts +41 -0
- package/src/cdk/node-version.ts +17 -0
- package/src/cdk/stack-metadata.test.ts +71 -0
- package/src/cdk/stack-metadata.ts +29 -0
- package/src/cdk/synth-guard.test.ts +21 -0
- package/src/cdk/synth-guard.ts +23 -0
- package/src/client/index.test.ts +118 -0
- package/src/client/index.ts +320 -0
- package/src/common/config.test.ts +236 -0
- package/src/common/config.ts +169 -0
- package/src/common/constants.ts +15 -0
- package/src/common/crypto.ts +15 -0
- package/src/common/index.test.ts +242 -0
- package/src/common/index.ts +335 -0
- package/src/common/mock-data.ts +52 -0
- package/src/common/official-bb-names.generated.ts +29 -0
- package/src/common/sdk-registry.ts +150 -0
- package/src/constants.ts +31 -0
- package/src/cors.test.ts +279 -0
- package/src/cors.ts +91 -0
- package/src/db-naming.test.ts +48 -0
- package/src/db-naming.ts +41 -0
- package/src/errors.ts +72 -0
- package/src/hosting.test.ts +1431 -0
- package/src/hosting.ts +626 -0
- package/src/index.cdk.ts +45 -0
- package/src/index.ts +22 -0
- package/src/lambda-handler.test.ts +1005 -0
- package/src/lambda-handler.ts +706 -0
- package/src/pipeline/index.ts +12 -0
- package/src/pipeline/pipeline-construct.ts +662 -0
- package/src/pipeline/pipeline.test.ts +1565 -0
- package/src/pipeline/types.ts +384 -0
- package/src/raw-route.cdk.ts +56 -0
- package/src/raw-route.mock.ts +56 -0
- package/src/raw-route.test.ts +819 -0
- package/src/raw-route.ts +316 -0
- package/src/redact.test.ts +222 -0
- package/src/redact.ts +143 -0
- package/src/rpc.test.ts +73 -0
- package/src/rpc.ts +174 -0
- package/src/scripts/cdk-telemetry-env.test.ts +75 -0
- package/src/scripts/cdk-telemetry-env.ts +23 -0
- package/src/scripts/cleanup.ts +39 -0
- package/src/scripts/console.ts +34 -0
- package/src/scripts/deploy.ts +106 -0
- package/src/scripts/destroy.ts +42 -0
- package/src/scripts/dev-server-cors.test.ts +28 -0
- package/src/scripts/dev-server-telemetry.test.ts +127 -0
- package/src/scripts/dev-server.ts +515 -0
- package/src/scripts/ensure-secrets.test.ts +50 -0
- package/src/scripts/ensure-secrets.ts +113 -0
- package/src/scripts/external-migrations-step.test.ts +64 -0
- package/src/scripts/external-migrations-step.ts +269 -0
- package/src/scripts/extract-ts-types.test.ts +516 -0
- package/src/scripts/extract-ts-types.ts +773 -0
- package/src/scripts/generate-client-worker.ts +15 -0
- package/src/scripts/generate-client.test.ts +69 -0
- package/src/scripts/generate-client.ts +86 -0
- package/src/scripts/generate-spec-cli.test.ts +106 -0
- package/src/scripts/generate-spec-cli.ts +92 -0
- package/src/scripts/generate-spec.test.ts +99 -0
- package/src/scripts/generate-spec.ts +833 -0
- package/src/scripts/index.ts +21 -0
- package/src/scripts/sandbox.ts +230 -0
- package/src/scripts/telemetry-cli.ts +10 -0
- package/src/scripts/telemetry.test.ts +239 -0
- package/src/scripts/telemetry.ts +173 -0
- package/src/scripts/validate-spec.ts +199 -0
- package/src/server/index.ts +5 -0
- package/src/server/withAuth.test.ts +348 -0
- package/src/server/withAuth.ts +323 -0
- package/src/telemetry/client.ts +226 -0
- package/src/telemetry/config-writer.ts +52 -0
- package/src/telemetry/consent-commands.test.ts +196 -0
- package/src/telemetry/consent.ts +154 -0
- package/src/telemetry/environment.ts +100 -0
- package/src/telemetry/identifiers.ts +94 -0
- package/src/telemetry/index.ts +11 -0
- package/src/telemetry/telemetry.test.ts +1343 -0
- package/src/telemetry/trackCommand.ts +110 -0
- package/src/telemetry/types.ts +92 -0
- package/src/types.ts +33 -0
- package/src/version.ts +2 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import * as cdk from 'aws-cdk-lib';
|
|
5
|
+
import * as s3 from 'aws-cdk-lib/aws-s3';
|
|
6
|
+
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment';
|
|
7
|
+
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
8
|
+
import type { Construct } from 'constructs';
|
|
9
|
+
|
|
10
|
+
const REGISTRY_KEY = Symbol.for('BLOCKS_CONFIG_REGISTRY');
|
|
11
|
+
|
|
12
|
+
interface ConfigRegistryState {
|
|
13
|
+
entries: Map<string, unknown>;
|
|
14
|
+
finalized: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get or create the config registry for a given stack.
|
|
19
|
+
* The registry collects BB config entries (env var key → CDK token value)
|
|
20
|
+
* and serializes them to an S3 JSON file at synth time.
|
|
21
|
+
*/
|
|
22
|
+
function getRegistry(stack: cdk.Stack): ConfigRegistryState {
|
|
23
|
+
let state = (stack as any)[REGISTRY_KEY] as ConfigRegistryState | undefined;
|
|
24
|
+
if (!state) {
|
|
25
|
+
state = { entries: new Map(), finalized: false };
|
|
26
|
+
(stack as any)[REGISTRY_KEY] = state;
|
|
27
|
+
}
|
|
28
|
+
return state;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Register a config entry for a Building Block. This replaces
|
|
33
|
+
* `handler.addEnvironment(key, value)` for BB resource mappings.
|
|
34
|
+
*
|
|
35
|
+
* The entry will be serialized into a JSON config file in S3, loaded
|
|
36
|
+
* by the Lambda at cold start. This avoids the 4KB env var limit.
|
|
37
|
+
*
|
|
38
|
+
* @param scope - The CDK construct (used to find the parent stack)
|
|
39
|
+
* @param key - The config key (same string the runtime will use to look it up)
|
|
40
|
+
* @param value - The config value (can be a CDK token that resolves at deploy time)
|
|
41
|
+
*/
|
|
42
|
+
export function registerConfig(scope: Construct, key: string, value: unknown): void {
|
|
43
|
+
const stack = cdk.Stack.of(scope);
|
|
44
|
+
const registry = getRegistry(stack);
|
|
45
|
+
registry.entries.set(key, value);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Finalize the config registry: create an S3 bucket, upload the config JSON,
|
|
50
|
+
* set env vars on the handler, and grant read access.
|
|
51
|
+
*
|
|
52
|
+
* Must be called after all BBs are constructed (i.e., after the backendCDKPath
|
|
53
|
+
* import completes in BlocksStack.create() / BlocksBackend.create()).
|
|
54
|
+
*
|
|
55
|
+
* @param scope - The CDK construct to create resources under
|
|
56
|
+
* @param handler - The Lambda function that needs to read the config
|
|
57
|
+
*/
|
|
58
|
+
export function finalizeConfigRegistry(
|
|
59
|
+
scope: Construct,
|
|
60
|
+
handler: cdk.aws_lambda.IFunction,
|
|
61
|
+
): void {
|
|
62
|
+
const stack = cdk.Stack.of(scope);
|
|
63
|
+
const registry = getRegistry(stack);
|
|
64
|
+
|
|
65
|
+
if (registry.finalized) return;
|
|
66
|
+
registry.finalized = true;
|
|
67
|
+
|
|
68
|
+
if (registry.entries.size === 0) return;
|
|
69
|
+
|
|
70
|
+
const configBucket = new s3.Bucket(scope, 'BlocksConfigBucket', {
|
|
71
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
72
|
+
autoDeleteObjects: true,
|
|
73
|
+
encryption: s3.BucketEncryption.S3_MANAGED,
|
|
74
|
+
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
|
|
75
|
+
lifecycleRules: [
|
|
76
|
+
{ noncurrentVersionExpiration: cdk.Duration.days(1) },
|
|
77
|
+
],
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const configKey = 'blocks-config.json';
|
|
81
|
+
|
|
82
|
+
const configObject = cdk.Lazy.any({
|
|
83
|
+
produce: () => Object.fromEntries(registry.entries),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const deployment = new s3deploy.BucketDeployment(scope, 'BlocksConfigDeployment', {
|
|
87
|
+
sources: [s3deploy.Source.jsonData(configKey, configObject)],
|
|
88
|
+
destinationBucket: configBucket,
|
|
89
|
+
prune: false,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
(handler as cdk.aws_lambda.Function).addEnvironment(
|
|
93
|
+
'BLOCKS_CONFIG_BUCKET',
|
|
94
|
+
configBucket.bucketName,
|
|
95
|
+
);
|
|
96
|
+
(handler as cdk.aws_lambda.Function).addEnvironment(
|
|
97
|
+
'BLOCKS_CONFIG_KEY',
|
|
98
|
+
configKey,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// Scope IAM grant to the specific config key
|
|
102
|
+
(handler as cdk.aws_lambda.Function).addToRolePolicy(new iam.PolicyStatement({
|
|
103
|
+
actions: ['s3:GetObject'],
|
|
104
|
+
resources: [`${configBucket.bucketArn}/${configKey}`],
|
|
105
|
+
}));
|
|
106
|
+
}
|
package/src/cdk/index.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import * as cdk from 'aws-cdk-lib';
|
|
5
|
+
import { Construct } from 'constructs';
|
|
6
|
+
import {
|
|
7
|
+
type BlocksStackProps,
|
|
8
|
+
type BlocksStack as BaseBlocksStack,
|
|
9
|
+
type ScopeParent,
|
|
10
|
+
type ScopeOptions,
|
|
11
|
+
computeScopeFullId,
|
|
12
|
+
} from '../common/index.js';
|
|
13
|
+
import { setupBlocksInfra, BlocksBackend, assertCdkConditionActive } from './blocks-backend.js';
|
|
14
|
+
import { addBlocksStackMetadata } from './stack-metadata.js';
|
|
15
|
+
import { finalizeConfigRegistry } from './config-registry.js';
|
|
16
|
+
|
|
17
|
+
export { BlocksBackend, type BlocksBackendProps } from './blocks-backend.js';
|
|
18
|
+
export { DEFAULT_NODE_RUNTIME } from './node-version.js';
|
|
19
|
+
export { SandboxDisableDeletionProtection } from './mixins.js';
|
|
20
|
+
export { registerConfig, finalizeConfigRegistry } from './config-registry.js';
|
|
21
|
+
export { synthGuard } from './synth-guard.js';
|
|
22
|
+
export type { ScopeOptions } from '../index.js';
|
|
23
|
+
export { ApiError, isBlocksError } from '../errors.js';
|
|
24
|
+
|
|
25
|
+
export class BlocksStack extends cdk.Stack implements BaseBlocksStack {
|
|
26
|
+
public readonly id: string;
|
|
27
|
+
public readonly apiUrl: string;
|
|
28
|
+
public readonly gateway: cdk.aws_apigateway.RestApi;
|
|
29
|
+
public readonly handler: cdk.aws_lambda_nodejs.NodejsFunction;
|
|
30
|
+
public readonly backendHandlerPath: string;
|
|
31
|
+
|
|
32
|
+
private constructor(scope: Construct, id: string, props: BlocksStackProps) {
|
|
33
|
+
super(scope, id, props);
|
|
34
|
+
this.id = id;
|
|
35
|
+
this.backendHandlerPath = props.backendHandlerPath;
|
|
36
|
+
|
|
37
|
+
// Set globalThis so Building Blocks attach directly to this stack
|
|
38
|
+
(globalThis as any).CURRENT_BLOCKS_STACK = this;
|
|
39
|
+
|
|
40
|
+
const infra = setupBlocksInfra(this, props, id);
|
|
41
|
+
this.handler = infra.handler;
|
|
42
|
+
this.gateway = infra.gateway;
|
|
43
|
+
this.apiUrl = infra.apiUrl;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static async create(scope: Construct, id: string, props: BlocksStackProps) {
|
|
47
|
+
assertCdkConditionActive();
|
|
48
|
+
|
|
49
|
+
// Detect ambient pipeline stage scope set by Pipeline appFile imports
|
|
50
|
+
const pipelineScope = (globalThis as any).__PIPELINE_STAGE_SCOPE__;
|
|
51
|
+
const actualScope = pipelineScope || scope;
|
|
52
|
+
|
|
53
|
+
const stack = new BlocksStack(actualScope, id, props);
|
|
54
|
+
// ESM caches modules by URL — append a unique query string so each stage re-executes the module body
|
|
55
|
+
const mod = await import(`${props.backendCDKPath}?stack=${id}`);
|
|
56
|
+
if (typeof mod.default === 'function') {
|
|
57
|
+
try {
|
|
58
|
+
await mod.default(stack);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
throw new Error(`Error executing default export function for stack "${id}": ${error instanceof Error ? error.message : error}`, { cause: error });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Finalize BB config → S3 (after all BBs have registered their config)
|
|
64
|
+
finalizeConfigRegistry(stack, stack.handler);
|
|
65
|
+
|
|
66
|
+
new cdk.CfnOutput(stack, 'ApiUrl', { value: stack.apiUrl });
|
|
67
|
+
|
|
68
|
+
addBlocksStackMetadata(stack);
|
|
69
|
+
|
|
70
|
+
return stack;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export class Scope extends Construct {
|
|
75
|
+
public readonly id: string;
|
|
76
|
+
public readonly parent: ScopeParent;
|
|
77
|
+
|
|
78
|
+
readonly bbName?: string;
|
|
79
|
+
readonly bbVersion?: string;
|
|
80
|
+
|
|
81
|
+
constructor(id: string, options?: ScopeOptions) {
|
|
82
|
+
const parent = options?.parent || (globalThis as any).CURRENT_BLOCKS_STACK;
|
|
83
|
+
super(parent, id);
|
|
84
|
+
this.id = id;
|
|
85
|
+
this.parent = parent;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
get handler() {
|
|
89
|
+
// Walk up the construct tree to find the owning BlocksStack/BlocksBackend
|
|
90
|
+
let current: Construct = this;
|
|
91
|
+
while (current.node.scope) {
|
|
92
|
+
current = current.node.scope as Construct;
|
|
93
|
+
if (current instanceof BlocksStack || current instanceof BlocksBackend) {
|
|
94
|
+
return current.handler;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Fallback to globalThis for backward compatibility
|
|
98
|
+
return ((globalThis as any).CURRENT_BLOCKS_STACK as { handler: cdk.aws_lambda_nodejs.NodejsFunction }).handler;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
get fullId(): string {
|
|
102
|
+
return computeScopeFullId(this);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
protected buildUserAgentChain(): [string, string][] {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Plugin registration — no-ops in CDK context (plugins are only used at dev/build time)
|
|
110
|
+
registerClientMiddleware(_packageSpecifier: string): void {}
|
|
111
|
+
registerDevAttachment(_packageSpecifier: string): void {}
|
|
112
|
+
registerLambdaEventHandler(_eventSource: string, _identifier: string, _handler: (record: any) => Promise<void>): void {}
|
|
113
|
+
get clientMiddleware(): readonly string[] { return []; }
|
|
114
|
+
get devAttachments(): readonly string[] { return []; }
|
|
115
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { test, describe } from 'node:test';
|
|
5
|
+
import assert from 'node:assert';
|
|
6
|
+
import * as cdk from 'aws-cdk-lib';
|
|
7
|
+
import { Template, Match } from 'aws-cdk-lib/assertions';
|
|
8
|
+
import { Table, AttributeType, BillingMode } from 'aws-cdk-lib/aws-dynamodb';
|
|
9
|
+
import * as rds from 'aws-cdk-lib/aws-rds';
|
|
10
|
+
import * as ec2 from 'aws-cdk-lib/aws-ec2';
|
|
11
|
+
import { RemovalPolicies, Mixins } from 'aws-cdk-lib';
|
|
12
|
+
import { SandboxDisableDeletionProtection } from './mixins.js';
|
|
13
|
+
|
|
14
|
+
describe('sandbox removal policy', () => {
|
|
15
|
+
test('sandbox mode: DeletionPolicy is Delete on all resources', () => {
|
|
16
|
+
const app = new cdk.App({ context: { sandboxMode: 'true' } });
|
|
17
|
+
const stack = new cdk.Stack(app, 'TestStack');
|
|
18
|
+
|
|
19
|
+
new Table(stack, 'MyTable', {
|
|
20
|
+
partitionKey: { name: 'pk', type: AttributeType.STRING },
|
|
21
|
+
billingMode: BillingMode.PAY_PER_REQUEST,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
RemovalPolicies.of(stack).destroy();
|
|
25
|
+
|
|
26
|
+
const template = Template.fromStack(stack);
|
|
27
|
+
template.hasResource('AWS::DynamoDB::Table', {
|
|
28
|
+
DeletionPolicy: 'Delete',
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('sandbox mode: deletionProtection disabled on RDS cluster', () => {
|
|
33
|
+
const app = new cdk.App({ context: { sandboxMode: 'true' } });
|
|
34
|
+
const stack = new cdk.Stack(app, 'TestStack');
|
|
35
|
+
|
|
36
|
+
const vpc = new ec2.Vpc(stack, 'Vpc', {
|
|
37
|
+
maxAzs: 2,
|
|
38
|
+
natGateways: 0,
|
|
39
|
+
subnetConfiguration: [
|
|
40
|
+
{ name: 'isolated', subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
new rds.DatabaseCluster(stack, 'Cluster', {
|
|
44
|
+
engine: rds.DatabaseClusterEngine.auroraPostgres({
|
|
45
|
+
version: rds.AuroraPostgresEngineVersion.VER_16_4,
|
|
46
|
+
}),
|
|
47
|
+
writer: rds.ClusterInstance.serverlessV2('Writer'),
|
|
48
|
+
vpc,
|
|
49
|
+
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
|
|
50
|
+
deletionProtection: true,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
RemovalPolicies.of(stack).destroy();
|
|
54
|
+
Mixins.of(stack).apply(new SandboxDisableDeletionProtection());
|
|
55
|
+
|
|
56
|
+
const template = Template.fromStack(stack);
|
|
57
|
+
template.hasResourceProperties('AWS::RDS::DBCluster', {
|
|
58
|
+
DeletionProtection: false,
|
|
59
|
+
});
|
|
60
|
+
template.hasResource('AWS::RDS::DBCluster', {
|
|
61
|
+
DeletionPolicy: 'Delete',
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('production mode: default DeletionPolicy is Retain (CDK default, no explicit call needed)', () => {
|
|
66
|
+
const app = new cdk.App();
|
|
67
|
+
const stack = new cdk.Stack(app, 'TestStack');
|
|
68
|
+
|
|
69
|
+
new Table(stack, 'MyTable', {
|
|
70
|
+
partitionKey: { name: 'pk', type: AttributeType.STRING },
|
|
71
|
+
billingMode: BillingMode.PAY_PER_REQUEST,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// No removal policy call — CDK defaults to RETAIN
|
|
75
|
+
const template = Template.fromStack(stack);
|
|
76
|
+
template.hasResource('AWS::DynamoDB::Table', {
|
|
77
|
+
DeletionPolicy: 'Retain',
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('SandboxDisableDeletionProtection mixin: does not set deletionProtection on Aurora instances', () => {
|
|
82
|
+
const app = new cdk.App();
|
|
83
|
+
const stack = new cdk.Stack(app, 'TestStack');
|
|
84
|
+
|
|
85
|
+
const vpc = new ec2.Vpc(stack, 'Vpc', {
|
|
86
|
+
maxAzs: 2,
|
|
87
|
+
natGateways: 0,
|
|
88
|
+
subnetConfiguration: [
|
|
89
|
+
{ name: 'isolated', subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
|
|
90
|
+
],
|
|
91
|
+
});
|
|
92
|
+
new rds.DatabaseCluster(stack, 'Cluster', {
|
|
93
|
+
engine: rds.DatabaseClusterEngine.auroraPostgres({
|
|
94
|
+
version: rds.AuroraPostgresEngineVersion.VER_16_4,
|
|
95
|
+
}),
|
|
96
|
+
writer: rds.ClusterInstance.serverlessV2('Writer'),
|
|
97
|
+
vpc,
|
|
98
|
+
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
|
|
99
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
RemovalPolicies.of(stack).destroy();
|
|
103
|
+
Mixins.of(stack).apply(new SandboxDisableDeletionProtection());
|
|
104
|
+
|
|
105
|
+
const template = Template.fromStack(stack);
|
|
106
|
+
// Aurora DB instance should NOT have DeletionProtection set at all
|
|
107
|
+
// (RDS rejects it for cluster members)
|
|
108
|
+
template.hasResourceProperties('AWS::RDS::DBInstance', {
|
|
109
|
+
DeletionProtection: Match.absent(),
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('SandboxDisableDeletionProtection mixin: skips constructs without deletionProtection', () => {
|
|
114
|
+
const app = new cdk.App();
|
|
115
|
+
const stack = new cdk.Stack(app, 'TestStack');
|
|
116
|
+
|
|
117
|
+
new Table(stack, 'MyTable', {
|
|
118
|
+
partitionKey: { name: 'pk', type: AttributeType.STRING },
|
|
119
|
+
billingMode: BillingMode.PAY_PER_REQUEST,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Should not throw — DynamoDB Table has no deletionProtection property
|
|
123
|
+
Mixins.of(stack).apply(new SandboxDisableDeletionProtection());
|
|
124
|
+
|
|
125
|
+
const template = Template.fromStack(stack);
|
|
126
|
+
// Table should still synthesize normally
|
|
127
|
+
template.resourceCountIs('AWS::DynamoDB::Table', 1);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { Mixin } from 'aws-cdk-lib';
|
|
5
|
+
import type { IConstruct } from 'constructs';
|
|
6
|
+
import type { IMixin } from 'constructs';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Disables deletion protection on any construct that has a `deletionProtection`
|
|
10
|
+
* property (e.g. RDS clusters, RDS instances). Uses duck-typing so it
|
|
11
|
+
* automatically covers current and future resource types.
|
|
12
|
+
*
|
|
13
|
+
* Intended for sandbox teardown — use in the CDK layer alongside
|
|
14
|
+
* `RemovalPolicies.of(stack).destroy()` to ensure `sandbox:destroy` can
|
|
15
|
+
* delete the entire stack without manual cleanup.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { RemovalPolicies, Mixins } from 'aws-cdk-lib';
|
|
20
|
+
* import { SandboxDisableDeletionProtection } from '@aws-blocks/blocks/cdk';
|
|
21
|
+
*
|
|
22
|
+
* if (sandboxMode) {
|
|
23
|
+
* RemovalPolicies.of(stack).destroy();
|
|
24
|
+
* Mixins.of(stack).apply(new SandboxDisableDeletionProtection());
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export class SandboxDisableDeletionProtection extends Mixin implements IMixin {
|
|
29
|
+
supports(construct: any): boolean {
|
|
30
|
+
return 'deletionProtection' in construct;
|
|
31
|
+
}
|
|
32
|
+
applyTo(node: IConstruct): void {
|
|
33
|
+
// Only flip explicitly-enabled protection. When undefined (the default),
|
|
34
|
+
// deletion protection is already off — setting it to false would emit the
|
|
35
|
+
// property in the CloudFormation template, which breaks Aurora DB instances
|
|
36
|
+
// (RDS rejects DeletionProtection on cluster members).
|
|
37
|
+
if ((node as any).deletionProtection === true) {
|
|
38
|
+
(node as any).deletionProtection = false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { Runtime } from 'aws-cdk-lib/aws-lambda';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The single source of truth for the Node.js Lambda runtime used by Blocks's
|
|
8
|
+
* own Lambda functions and every Building Block. Set every
|
|
9
|
+
* `aws_lambda.Function` / `NodejsFunction` runtime to this constant rather
|
|
10
|
+
* than hardcoding `Runtime.NODEJS_*_X`, so the whole framework moves in
|
|
11
|
+
* lockstep when the runtime is bumped.
|
|
12
|
+
*
|
|
13
|
+
* Currently the latest Active LTS. This controls only the AWS-managed
|
|
14
|
+
* runtime that executes deployed handlers; it is independent of the Node
|
|
15
|
+
* version a consumer runs the CLI / CDK synth on.
|
|
16
|
+
*/
|
|
17
|
+
export const DEFAULT_NODE_RUNTIME = Runtime.NODEJS_24_X;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { test, describe } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import * as cdk from 'aws-cdk-lib';
|
|
4
|
+
import { Template } from 'aws-cdk-lib/assertions';
|
|
5
|
+
import { addBlocksStackMetadata } from './stack-metadata.js';
|
|
6
|
+
import { CORE_VERSION } from '../version.js';
|
|
7
|
+
|
|
8
|
+
describe('addBlocksStackMetadata', () => {
|
|
9
|
+
test('adds AWS::Blocks::Platform metadata with correct version', () => {
|
|
10
|
+
const app = new cdk.App();
|
|
11
|
+
const stack = new cdk.Stack(app, 'TestStack');
|
|
12
|
+
|
|
13
|
+
addBlocksStackMetadata(stack);
|
|
14
|
+
|
|
15
|
+
const template = Template.fromStack(stack);
|
|
16
|
+
const metadata = template.toJSON().Metadata;
|
|
17
|
+
assert.deepStrictEqual(metadata['AWS::Blocks::Platform'], {
|
|
18
|
+
version: CORE_VERSION,
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('preserves existing template metadata', () => {
|
|
23
|
+
const app = new cdk.App();
|
|
24
|
+
const stack = new cdk.Stack(app, 'ExistingMetaStack');
|
|
25
|
+
stack.templateOptions.metadata = {
|
|
26
|
+
'Custom::Existing': { key: 'value' },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
addBlocksStackMetadata(stack);
|
|
30
|
+
|
|
31
|
+
const template = Template.fromStack(stack);
|
|
32
|
+
const metadata = template.toJSON().Metadata;
|
|
33
|
+
assert.deepStrictEqual(metadata['Custom::Existing'], { key: 'value' });
|
|
34
|
+
assert.deepStrictEqual(metadata['AWS::Blocks::Platform'], {
|
|
35
|
+
version: CORE_VERSION,
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('tags deployment-type as production when sandboxMode context is absent', () => {
|
|
40
|
+
const app = new cdk.App();
|
|
41
|
+
const stack = new cdk.Stack(app, 'ProdStack');
|
|
42
|
+
|
|
43
|
+
addBlocksStackMetadata(stack);
|
|
44
|
+
|
|
45
|
+
const assembly = app.synth();
|
|
46
|
+
const stackArtifact = assembly.getStackByName(stack.stackName);
|
|
47
|
+
assert.strictEqual(stackArtifact.tags['blocks:deployment-type'], 'production');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('tags deployment-type as sandbox when sandboxMode context is boolean true', () => {
|
|
51
|
+
const app = new cdk.App({ context: { sandboxMode: true } });
|
|
52
|
+
const stack = new cdk.Stack(app, 'SandboxBoolStack');
|
|
53
|
+
|
|
54
|
+
addBlocksStackMetadata(stack);
|
|
55
|
+
|
|
56
|
+
const assembly = app.synth();
|
|
57
|
+
const stackArtifact = assembly.getStackByName(stack.stackName);
|
|
58
|
+
assert.strictEqual(stackArtifact.tags['blocks:deployment-type'], 'sandbox');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('tags deployment-type as sandbox when sandboxMode context is string "true"', () => {
|
|
62
|
+
const app = new cdk.App({ context: { sandboxMode: 'true' } });
|
|
63
|
+
const stack = new cdk.Stack(app, 'SandboxStringStack');
|
|
64
|
+
|
|
65
|
+
addBlocksStackMetadata(stack);
|
|
66
|
+
|
|
67
|
+
const assembly = app.synth();
|
|
68
|
+
const stackArtifact = assembly.getStackByName(stack.stackName);
|
|
69
|
+
assert.strictEqual(stackArtifact.tags['blocks:deployment-type'], 'sandbox');
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as cdk from 'aws-cdk-lib';
|
|
2
|
+
import { CORE_VERSION } from '../version.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Adds AWS Blocks identification metadata and a deployment-type tag to a CloudFormation stack.
|
|
6
|
+
*
|
|
7
|
+
* Sets `AWS::Blocks::Platform` template metadata with the current core version
|
|
8
|
+
* and applies a `blocks:deployment-type` tag (`sandbox` or `production`) based on
|
|
9
|
+
* the CDK context key `sandboxMode`.
|
|
10
|
+
*
|
|
11
|
+
* @param stack - The CDK stack to annotate.
|
|
12
|
+
*/
|
|
13
|
+
export function addBlocksStackMetadata(stack: cdk.Stack): void {
|
|
14
|
+
stack.templateOptions.metadata = {
|
|
15
|
+
...stack.templateOptions.metadata,
|
|
16
|
+
'AWS::Blocks::Platform': {
|
|
17
|
+
version: CORE_VERSION,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const isSandbox =
|
|
22
|
+
stack.node.tryGetContext('sandboxMode') === 'true' ||
|
|
23
|
+
stack.node.tryGetContext('sandboxMode') === true;
|
|
24
|
+
|
|
25
|
+
cdk.Tags.of(stack).add(
|
|
26
|
+
'blocks:deployment-type',
|
|
27
|
+
isSandbox ? 'sandbox' : 'production',
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { test } from 'node:test';
|
|
5
|
+
import assert from 'node:assert';
|
|
6
|
+
import { synthGuard } from './synth-guard.js';
|
|
7
|
+
|
|
8
|
+
test('synthGuard throws an error mentioning the class and method name', () => {
|
|
9
|
+
assert.throws(
|
|
10
|
+
() => synthGuard('MyBlock', 'doThing'),
|
|
11
|
+
(err: Error) => {
|
|
12
|
+
assert.match(err.message, /MyBlock\.doThing\(\) cannot be called during CDK synth/);
|
|
13
|
+
assert.match(err.message, /--conditions=aws-runtime/);
|
|
14
|
+
return true;
|
|
15
|
+
},
|
|
16
|
+
);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('synthGuard always throws (return type is never)', () => {
|
|
20
|
+
assert.throws(() => synthGuard('X', 'y'));
|
|
21
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Throws an actionable error when a runtime-only method is called during CDK synth.
|
|
6
|
+
*
|
|
7
|
+
* Under `--conditions=cdk` Building Block modules resolve to their CDK construct,
|
|
8
|
+
* which only provisions infrastructure. Data/runtime methods live in the runtime
|
|
9
|
+
* build. Calling them at module top-level (which runs during synth) would otherwise
|
|
10
|
+
* fail with a cryptic `X is not a function` TypeError; this utility turns that into
|
|
11
|
+
* an actionable message directing the user to the correct execution context.
|
|
12
|
+
*
|
|
13
|
+
* @param className - The Building Block class name (e.g. "KVStore", "DistributedTable")
|
|
14
|
+
* @param method - The method that was called (e.g. "get", "put")
|
|
15
|
+
*/
|
|
16
|
+
export function synthGuard(className: string, method: string): never {
|
|
17
|
+
throw new Error(
|
|
18
|
+
`${className}.${method}() cannot be called during CDK synth. ` +
|
|
19
|
+
`Data methods run at request time — call them inside an ApiNamespace method, ` +
|
|
20
|
+
`RawRoute handler, job handler, or a runtime script (run with --conditions=aws-runtime), ` +
|
|
21
|
+
`not at the top level of your backend module.`,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { describe, it } from 'node:test';
|
|
5
|
+
import assert from 'node:assert';
|
|
6
|
+
import { execSync } from 'node:child_process';
|
|
7
|
+
import { writeFileSync, unlinkSync, mkdtempSync } from 'node:fs';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { dirname, join } from 'node:path';
|
|
10
|
+
import { tmpdir } from 'node:os';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Tests for the client's URL resolution defensive guard (issue #730).
|
|
14
|
+
*
|
|
15
|
+
* The client module caches API_URL globally, so each test spawns a
|
|
16
|
+
* subprocess with appropriate env vars to get a fresh module instance.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const CLIENT_MODULE = join(__dirname, '..', 'client', 'index.js');
|
|
21
|
+
|
|
22
|
+
function runScript(scriptBody: string, env: Record<string, string>): string {
|
|
23
|
+
const tmp = mkdtempSync(join(tmpdir(), 'blocks-client-test-'));
|
|
24
|
+
const scriptPath = join(tmp, 'test.mjs');
|
|
25
|
+
// Use absolute path to import the client module
|
|
26
|
+
const importPath = `file://${CLIENT_MODULE}`;
|
|
27
|
+
const fullScript = `import { ApiNamespaceClient } from '${importPath}';\n${scriptBody}`;
|
|
28
|
+
writeFileSync(scriptPath, fullScript);
|
|
29
|
+
try {
|
|
30
|
+
return execSync(`node ${scriptPath}`, {
|
|
31
|
+
encoding: 'utf-8',
|
|
32
|
+
env: { PATH: process.env.PATH, HOME: process.env.HOME, ...env },
|
|
33
|
+
timeout: 10000,
|
|
34
|
+
}).trim();
|
|
35
|
+
} finally {
|
|
36
|
+
try { unlinkSync(scriptPath); } catch {}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe('Client URL validation (issue #730)', () => {
|
|
41
|
+
it('ApiNamespaceClient with explicit url option containing "undefined" does NOT throw on creation', async () => {
|
|
42
|
+
const { ApiNamespaceClient } = await import('./index.js');
|
|
43
|
+
const client = ApiNamespaceClient('test', { url: 'https://undefined.example.com' });
|
|
44
|
+
assert.ok(client, 'Should create client proxy');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('resolveApiUrl rejects when BLOCKS_API_URL contains "undefined"', () => {
|
|
48
|
+
const result = runScript(`
|
|
49
|
+
const api = ApiNamespaceClient('test');
|
|
50
|
+
try {
|
|
51
|
+
await api.hello();
|
|
52
|
+
console.log('FAIL:no_error');
|
|
53
|
+
} catch (e) {
|
|
54
|
+
if (e.message.includes('Blocks API URL is not configured')) {
|
|
55
|
+
console.log('PASS');
|
|
56
|
+
} else {
|
|
57
|
+
console.log('FAIL:' + e.message);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
`, { BLOCKS_API_URL: 'https://undefined/api' });
|
|
61
|
+
assert.ok(result.includes('PASS'), `Expected PASS, got: ${result}`);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('resolveApiUrl rejects when BLOCKS_CONFIG has missing apiUrl', () => {
|
|
65
|
+
const result = runScript(`
|
|
66
|
+
const api = ApiNamespaceClient('test');
|
|
67
|
+
try {
|
|
68
|
+
await api.hello();
|
|
69
|
+
console.log('FAIL:no_error');
|
|
70
|
+
} catch (e) {
|
|
71
|
+
if (e.message.includes('Blocks API URL is not configured') || e.message.includes('Blocks API URL not configured')) {
|
|
72
|
+
console.log('PASS');
|
|
73
|
+
} else {
|
|
74
|
+
console.log('FAIL:' + e.message);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
`, { BLOCKS_CONFIG: JSON.stringify({ region: 'us-east-1' }) });
|
|
78
|
+
assert.ok(result.includes('PASS'), `Expected PASS, got: ${result}`);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('resolveApiUrl succeeds with valid BLOCKS_API_URL', () => {
|
|
82
|
+
const result = runScript(`
|
|
83
|
+
const api = ApiNamespaceClient('test');
|
|
84
|
+
try {
|
|
85
|
+
await api.hello();
|
|
86
|
+
console.log('FAIL:no_error');
|
|
87
|
+
} catch (e) {
|
|
88
|
+
if (e.message.includes('fetch') || e.message.includes('ENOTFOUND') || e.message.includes('getaddrinfo')) {
|
|
89
|
+
console.log('PASS:url_resolved_fetch_failed');
|
|
90
|
+
} else if (e.message.includes('Blocks API URL')) {
|
|
91
|
+
console.log('FAIL:url_rejected_valid');
|
|
92
|
+
} else {
|
|
93
|
+
console.log('PASS:other');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
`, { BLOCKS_API_URL: 'https://abc123.execute-api.us-east-1.amazonaws.com/prod/aws-blocks' });
|
|
97
|
+
assert.ok(result.includes('PASS'), `Expected PASS, got: ${result}`);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('resolveApiUrl accepts relative URLs (e.g. /aws-blocks/api for SPA hosting)', () => {
|
|
101
|
+
const result = runScript(`
|
|
102
|
+
const api = ApiNamespaceClient('test');
|
|
103
|
+
try {
|
|
104
|
+
await api.hello();
|
|
105
|
+
console.log('FAIL:no_error');
|
|
106
|
+
} catch (e) {
|
|
107
|
+
if (e.message.includes('fetch') || e.message.includes('ENOTFOUND') || e.message.includes('getaddrinfo') || e.message.includes('Invalid URL')) {
|
|
108
|
+
console.log('PASS:url_resolved_fetch_failed');
|
|
109
|
+
} else if (e.message.includes('Blocks API URL')) {
|
|
110
|
+
console.log('FAIL:url_rejected_relative');
|
|
111
|
+
} else {
|
|
112
|
+
console.log('PASS:other');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
`, { BLOCKS_API_URL: '/aws-blocks/api' });
|
|
116
|
+
assert.ok(result.includes('PASS'), `Expected PASS, got: ${result}`);
|
|
117
|
+
});
|
|
118
|
+
});
|