@aws-blocks/core 0.1.18 → 0.3.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/cdk/__fixtures__/import-meta-handler.d.ts +6 -0
- package/dist/cdk/__fixtures__/import-meta-handler.d.ts.map +1 -0
- package/dist/cdk/__fixtures__/import-meta-handler.js +13 -0
- package/dist/cdk/blocks-backend.d.ts +46 -9
- package/dist/cdk/blocks-backend.d.ts.map +1 -1
- package/dist/cdk/blocks-backend.js +66 -67
- package/dist/cdk/blocks-backend.test.js +114 -56
- package/dist/cdk/blocks-defaults.d.ts +70 -0
- package/dist/cdk/blocks-defaults.d.ts.map +1 -0
- package/dist/cdk/blocks-defaults.js +27 -0
- package/dist/cdk/blocks-defaults.test.d.ts +2 -0
- package/dist/cdk/blocks-defaults.test.d.ts.map +1 -0
- package/dist/cdk/blocks-defaults.test.js +24 -0
- package/dist/cdk/blocks-stack.test.js +74 -31
- package/dist/cdk/bundling.d.ts +42 -0
- package/dist/cdk/bundling.d.ts.map +1 -0
- package/dist/cdk/bundling.js +72 -0
- package/dist/cdk/bundling.test.d.ts +2 -0
- package/dist/cdk/bundling.test.d.ts.map +1 -0
- package/dist/cdk/bundling.test.js +80 -0
- package/dist/cdk/compute/compute.d.ts +33 -0
- package/dist/cdk/compute/compute.d.ts.map +1 -0
- package/dist/cdk/compute/compute.js +28 -0
- package/dist/cdk/compute/default-compute-factory.d.ts +33 -0
- package/dist/cdk/compute/default-compute-factory.d.ts.map +1 -0
- package/dist/cdk/compute/default-compute-factory.js +3 -0
- package/dist/cdk/index.d.ts +92 -12
- package/dist/cdk/index.d.ts.map +1 -1
- package/dist/cdk/index.js +141 -25
- package/dist/cdk/internal.d.ts +25 -0
- package/dist/cdk/internal.d.ts.map +1 -0
- package/dist/cdk/internal.js +27 -0
- package/dist/cdk/mixins.d.ts +18 -4
- package/dist/cdk/mixins.d.ts.map +1 -1
- package/dist/cdk/mixins.js +31 -7
- package/dist/cdk/mixins.test.js +45 -0
- package/dist/common/index.d.ts +9 -0
- package/dist/common/index.d.ts.map +1 -1
- package/dist/hosting-secrets.d.ts +48 -0
- package/dist/hosting-secrets.d.ts.map +1 -0
- package/dist/hosting-secrets.js +57 -0
- package/dist/hosting-secrets.test.d.ts +2 -0
- package/dist/hosting-secrets.test.d.ts.map +1 -0
- package/dist/hosting-secrets.test.js +81 -0
- package/dist/hosting.d.ts +88 -6
- package/dist/hosting.d.ts.map +1 -1
- package/dist/hosting.js +83 -24
- package/dist/hosting.test.js +158 -10
- package/dist/index.cdk.d.ts +13 -11
- package/dist/index.cdk.d.ts.map +1 -1
- package/dist/index.cdk.js +13 -8
- package/dist/index.d.ts +8 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -5
- package/dist/lambda-handler.test.js +66 -0
- package/dist/pipeline/index.d.ts +24 -2
- package/dist/pipeline/index.d.ts.map +1 -1
- package/dist/pipeline/index.js +41 -1
- package/dist/pipeline.test.d.ts +2 -0
- package/dist/pipeline.test.d.ts.map +1 -0
- package/dist/pipeline.test.js +47 -0
- package/dist/rpc.d.ts +21 -0
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +46 -3
- package/dist/rpc.test.js +58 -1
- package/dist/scripts/config.d.ts +15 -0
- package/dist/scripts/config.d.ts.map +1 -0
- package/dist/scripts/config.js +29 -0
- package/dist/scripts/deploy.d.ts.map +1 -1
- package/dist/scripts/deploy.js +4 -0
- package/dist/scripts/dev-server.d.ts +8 -0
- package/dist/scripts/dev-server.d.ts.map +1 -1
- package/dist/scripts/dev-server.js +31 -0
- package/dist/scripts/generate-client.d.ts.map +1 -1
- package/dist/scripts/generate-client.js +9 -4
- package/dist/scripts/generate-client.test.js +19 -4
- package/dist/scripts/index.d.ts +13 -10
- package/dist/scripts/index.d.ts.map +1 -1
- package/dist/scripts/index.js +11 -8
- package/dist/scripts/preflight-credentials.d.ts +30 -0
- package/dist/scripts/preflight-credentials.d.ts.map +1 -0
- package/dist/scripts/preflight-credentials.js +108 -0
- package/dist/scripts/preflight-credentials.test.d.ts +2 -0
- package/dist/scripts/preflight-credentials.test.d.ts.map +1 -0
- package/dist/scripts/preflight-credentials.test.js +77 -0
- package/dist/scripts/sandbox-args.test.d.ts +2 -0
- package/dist/scripts/sandbox-args.test.d.ts.map +1 -0
- package/dist/scripts/sandbox-args.test.js +77 -0
- package/dist/scripts/sandbox.d.ts +52 -0
- package/dist/scripts/sandbox.d.ts.map +1 -1
- package/dist/scripts/sandbox.js +92 -15
- package/dist/scripts/secret.d.ts +15 -0
- package/dist/scripts/secret.d.ts.map +1 -0
- package/dist/scripts/secret.js +29 -0
- package/dist/scripts/secret.test.d.ts +2 -0
- package/dist/scripts/secret.test.d.ts.map +1 -0
- package/dist/scripts/secret.test.js +28 -0
- package/dist/scripts/telemetry.test.js +2 -0
- package/dist/scripts/typegen.d.ts +15 -0
- package/dist/scripts/typegen.d.ts.map +1 -0
- package/dist/scripts/typegen.js +16 -0
- package/dist/secret-naming.d.ts +58 -0
- package/dist/secret-naming.d.ts.map +1 -0
- package/dist/secret-naming.js +67 -0
- package/dist/secret-naming.test.d.ts +2 -0
- package/dist/secret-naming.test.d.ts.map +1 -0
- package/dist/secret-naming.test.js +40 -0
- package/dist/telemetry/environment.d.ts.map +1 -1
- package/dist/telemetry/environment.js +3 -1
- package/dist/telemetry/telemetry.test.js +10 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +7 -1
- package/src/cdk/__fixtures__/import-meta-handler.ts +16 -0
- package/src/cdk/blocks-backend.test.ts +308 -237
- package/src/cdk/blocks-backend.ts +98 -77
- package/src/cdk/blocks-defaults.test.ts +27 -0
- package/src/cdk/blocks-defaults.ts +75 -0
- package/src/cdk/blocks-stack.test.ts +160 -110
- package/src/cdk/bundling.test.ts +90 -0
- package/src/cdk/bundling.ts +76 -0
- package/src/cdk/compute/compute.ts +37 -0
- package/src/cdk/compute/default-compute-factory.ts +37 -0
- package/src/cdk/index.ts +178 -27
- package/src/cdk/internal.ts +30 -0
- package/src/cdk/mixins.test.ts +56 -1
- package/src/cdk/mixins.ts +32 -7
- package/src/common/index.ts +9 -0
- package/src/hosting-secrets.test.ts +106 -0
- package/src/hosting-secrets.ts +106 -0
- package/src/hosting.test.ts +244 -63
- package/src/hosting.ts +180 -68
- package/src/index.cdk.ts +79 -36
- package/src/index.ts +35 -16
- package/src/lambda-handler.test.ts +74 -0
- package/src/pipeline/index.ts +64 -11
- package/src/pipeline.test.ts +55 -0
- package/src/rpc.test.ts +66 -1
- package/src/rpc.ts +60 -3
- package/src/scripts/config.ts +35 -0
- package/src/scripts/deploy.ts +5 -0
- package/src/scripts/dev-server.ts +40 -0
- package/src/scripts/generate-client.test.ts +43 -8
- package/src/scripts/generate-client.ts +70 -65
- package/src/scripts/index.ts +20 -17
- package/src/scripts/preflight-credentials.test.ts +110 -0
- package/src/scripts/preflight-credentials.ts +131 -0
- package/src/scripts/sandbox-args.test.ts +92 -0
- package/src/scripts/sandbox.ts +102 -15
- package/src/scripts/secret.test.ts +35 -0
- package/src/scripts/secret.ts +35 -0
- package/src/scripts/telemetry.test.ts +2 -0
- package/src/scripts/typegen.ts +18 -0
- package/src/secret-naming.test.ts +59 -0
- package/src/secret-naming.ts +99 -0
- package/src/telemetry/environment.ts +3 -1
- package/src/telemetry/telemetry.test.ts +12 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-meta-handler.d.ts","sourceRoot":"","sources":["../../../src/cdk/__fixtures__/import-meta-handler.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,SAAS,QAAiC,CAAC;AAGxD,eAAO,MAAM,OAAO;;;EAAyE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// Repro fixture for the "handler bundles to CJS but uses import.meta.url" bug.
|
|
4
|
+
//
|
|
5
|
+
// The handler is bundled to CJS by NodejsFunction. In a CJS bundle `import.meta`
|
|
6
|
+
// is empty, so this top-level `fileURLToPath(import.meta.url)` would become
|
|
7
|
+
// `fileURLToPath(undefined)` and throw at Lambda load. blocksNodejsBundling shims
|
|
8
|
+
// `import.meta.url` to a CommonJS equivalent, so the bundle loads and resolves a
|
|
9
|
+
// real path instead of crashing — see bundling.test.ts.
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
export const moduleDir = fileURLToPath(import.meta.url);
|
|
12
|
+
// Reference moduleDir so esbuild can't tree-shake the import.meta.url usage away.
|
|
13
|
+
export const handler = async () => ({ statusCode: 200, body: JSON.stringify({ moduleDir }) });
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import * as cdk from 'aws-cdk-lib';
|
|
2
|
-
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
|
|
2
|
+
import type * as apigateway from 'aws-cdk-lib/aws-apigateway';
|
|
3
3
|
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
4
4
|
import { Construct } from 'constructs';
|
|
5
|
+
import type { BlocksDefaults } from './blocks-defaults.js';
|
|
6
|
+
import type { Compute } from './compute/compute.js';
|
|
7
|
+
import type { DefaultComputeFactory } from './compute/default-compute-factory.js';
|
|
5
8
|
/**
|
|
6
9
|
* Validate that the Node.js process was started with `--conditions=cdk`.
|
|
7
10
|
*
|
|
@@ -11,15 +14,41 @@ import { Construct } from 'constructs';
|
|
|
11
14
|
* no real infrastructure (no tables, no IAM, no Lambda configs).
|
|
12
15
|
*/
|
|
13
16
|
export declare function assertCdkConditionActive(): void;
|
|
17
|
+
/**
|
|
18
|
+
* Timeout of the shared Blocks handler Lambda, and therefore the ceiling on a
|
|
19
|
+
* single invocation. Exported because resources that feed the handler have to
|
|
20
|
+
* size their own timeouts against it (e.g. an SQS queue's visibility timeout).
|
|
21
|
+
*/
|
|
22
|
+
export declare const SHARED_HANDLER_TIMEOUT_SECONDS: number;
|
|
14
23
|
export interface BlocksBackendProps {
|
|
15
24
|
backendHandlerPath: string;
|
|
16
25
|
backendCDKPath: string;
|
|
26
|
+
/**
|
|
27
|
+
* Stack-wide infrastructure defaults applied to every Building Block (removal
|
|
28
|
+
* policy, deletion protection, …). See {@link BlocksDefaults}. Start from
|
|
29
|
+
* `BlocksPresets.sandbox` or `BlocksPresets.production` and override
|
|
30
|
+
* individual fields as needed. A per-block option always wins over the
|
|
31
|
+
* corresponding stack default.
|
|
32
|
+
*/
|
|
33
|
+
defaults: BlocksDefaults;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Core's `create()` props: the public {@link BlocksBackendProps} plus the
|
|
37
|
+
* required `defaultComputeFactory`, spread on by the umbrella (`@aws-blocks/blocks`).
|
|
38
|
+
* Customers use {@link BlocksBackendProps} and never set the factory.
|
|
39
|
+
*
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
export interface CoreBlocksBackendProps extends BlocksBackendProps {
|
|
43
|
+
/** Builds the backend's default compute. Injected by `@aws-blocks/blocks`. */
|
|
44
|
+
defaultComputeFactory: DefaultComputeFactory;
|
|
17
45
|
}
|
|
18
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Shared infra setup — provisions the stack-level resources that are NOT owned
|
|
48
|
+
* by a compute: the shared execution role, resource groups, and console-redirect
|
|
49
|
+
* routes.
|
|
50
|
+
*/
|
|
19
51
|
export declare function setupBlocksInfra(scope: Construct, props: BlocksBackendProps, id?: string): {
|
|
20
|
-
handler: cdk.aws_lambda_nodejs.NodejsFunction;
|
|
21
|
-
gateway: cdk.aws_apigateway.RestApi;
|
|
22
|
-
apiUrl: string;
|
|
23
52
|
executionRole: cdk.aws_iam.Role;
|
|
24
53
|
};
|
|
25
54
|
/**
|
|
@@ -40,12 +69,20 @@ export declare function setupBlocksInfra(scope: Construct, props: BlocksBackendP
|
|
|
40
69
|
* ```
|
|
41
70
|
*/
|
|
42
71
|
export declare class BlocksBackend extends Construct {
|
|
43
|
-
readonly apiUrl: string;
|
|
44
|
-
readonly gateway: apigateway.RestApi;
|
|
45
|
-
readonly handler: cdk.aws_lambda_nodejs.NodejsFunction;
|
|
46
72
|
readonly backendHandlerPath: string;
|
|
47
73
|
/** Shared IAM role assumed by all Blocks compute. Building Blocks grant to this role. */
|
|
48
74
|
readonly executionRole: iam.IRole;
|
|
75
|
+
/** Infrastructure defaults for Building Blocks created under this backend. */
|
|
76
|
+
readonly defaults: BlocksDefaults;
|
|
77
|
+
/** The default compute (owns the Lambda function + API Gateway); set in `create()`. @internal */
|
|
78
|
+
_defaultCompute?: Compute;
|
|
79
|
+
/** The default compute's Lambda function. To be removed once consumers move to the multi-compute model. */
|
|
80
|
+
get handler(): cdk.aws_lambda_nodejs.NodejsFunction;
|
|
81
|
+
/** The default compute's API Gateway REST API. To be removed once consumers move to the multi-compute model. */
|
|
82
|
+
get gateway(): apigateway.RestApi;
|
|
83
|
+
/** The default compute's RPC endpoint URL. To be removed once consumers move to the multi-compute model. */
|
|
84
|
+
get apiUrl(): string;
|
|
85
|
+
private requireDefaultCompute;
|
|
49
86
|
/**
|
|
50
87
|
* The fullId used by child Scopes to compute their env var names,
|
|
51
88
|
* construct IDs, and physical resource names (e.g., DynamoDB table names).
|
|
@@ -67,6 +104,6 @@ export declare class BlocksBackend extends Construct {
|
|
|
67
104
|
*/
|
|
68
105
|
get fullId(): string;
|
|
69
106
|
private constructor();
|
|
70
|
-
static create(scope: Construct, id: string, props:
|
|
107
|
+
static create(scope: Construct, id: string, props: CoreBlocksBackendProps): Promise<BlocksBackend>;
|
|
71
108
|
}
|
|
72
109
|
//# sourceMappingURL=blocks-backend.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blocks-backend.d.ts","sourceRoot":"","sources":["../../src/cdk/blocks-backend.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,GAAG,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"blocks-backend.d.ts","sourceRoot":"","sources":["../../src/cdk/blocks-backend.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,GAAG,MAAM,aAAa,CAAC;AACnC,OAAO,KAAK,KAAK,UAAU,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,GAAG,MAAM,qBAAqB,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAIvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,qBAAqB,EAAuB,MAAM,sCAAsC,CAAC;AAEvG;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAkB/C;AAED;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,QAAU,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,sBAAuB,SAAQ,kBAAkB;IAChE,8EAA8E;IAC9E,qBAAqB,EAAE,qBAAqB,CAAC;CAC9C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAAE,CAAC,EAAE,MAAM;;EAwFxF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,aAAc,SAAQ,SAAS;IAC1C,SAAgB,kBAAkB,EAAE,MAAM,CAAC;IAC3C,yFAAyF;IACzF,SAAgB,aAAa,EAAE,GAAG,CAAC,KAAK,CAAC;IACzC,8EAA8E;IAC9E,SAAgB,QAAQ,EAAE,cAAc,CAAC;IACzC,iGAAiG;IACjG,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,2GAA2G;IAC3G,IAAI,OAAO,IAAI,GAAG,CAAC,iBAAiB,CAAC,cAAc,CAElD;IACD,gHAAgH;IAChH,IAAI,OAAO,IAAI,UAAU,CAAC,OAAO,CAEhC;IACD,4GAA4G;IAC5G,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,OAAO,CAAC,qBAAqB;IAO7B;;;;;;;;;;;;;;;;;;OAkBG;IACH,IAAI,MAAM,IAAI,MAAM,CAUnB;IAED,OAAO;WAmBM,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB;CA6BhF"}
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import * as cdk from 'aws-cdk-lib';
|
|
4
|
-
import * as lambda from 'aws-cdk-lib/aws-lambda-nodejs';
|
|
5
|
-
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
|
|
6
4
|
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
7
5
|
import { CfnGroup } from 'aws-cdk-lib/aws-resourcegroups';
|
|
8
6
|
import { Construct } from 'constructs';
|
|
9
7
|
import { pathToFileURL } from 'node:url';
|
|
10
|
-
import { DEFAULT_NODE_RUNTIME } from './node-version.js';
|
|
11
8
|
import { addBlocksStackMetadata } from './stack-metadata.js';
|
|
12
9
|
import { finalizeConfigRegistry, registerConfig } from './config-registry.js';
|
|
13
|
-
import { BLOCKS_NAMESPACE, BLOCKS_RPC_PREFIX } from '../constants.js';
|
|
14
10
|
import { registerBuiltinRoutes } from '../builtin-routes.js';
|
|
15
11
|
/**
|
|
16
12
|
* Validate that the Node.js process was started with `--conditions=cdk`.
|
|
@@ -34,16 +30,39 @@ export function assertCdkConditionActive() {
|
|
|
34
30
|
'Or use the Blocks CLI commands (npm run deploy / npm run sandbox) which set this automatically.');
|
|
35
31
|
}
|
|
36
32
|
}
|
|
37
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* Timeout of the shared Blocks handler Lambda, and therefore the ceiling on a
|
|
35
|
+
* single invocation. Exported because resources that feed the handler have to
|
|
36
|
+
* size their own timeouts against it (e.g. an SQS queue's visibility timeout).
|
|
37
|
+
*/
|
|
38
|
+
export const SHARED_HANDLER_TIMEOUT_SECONDS = 60 * 15;
|
|
39
|
+
/**
|
|
40
|
+
* Shared infra setup — provisions the stack-level resources that are NOT owned
|
|
41
|
+
* by a compute: the shared execution role, resource groups, and console-redirect
|
|
42
|
+
* routes.
|
|
43
|
+
*/
|
|
38
44
|
export function setupBlocksInfra(scope, props, id) {
|
|
39
|
-
//
|
|
45
|
+
// Fail fast with an actionable message at the create() call site if `defaults`
|
|
46
|
+
// is missing (e.g. a plain-JS caller, `as any`, or a dynamically-built props
|
|
47
|
+
// object) — otherwise the first Building Block to read `scope.defaults` throws
|
|
48
|
+
// a cryptic `Cannot read properties of undefined (reading 'removalPolicy')`.
|
|
49
|
+
if (!props.defaults) {
|
|
50
|
+
throw new Error('BlocksStack/BlocksBackend requires a `defaults` field. Pass a posture from ' +
|
|
51
|
+
'`@aws-blocks/core/cdk` — typically `defaults: sandboxMode ? BlocksPresets.sandbox : BlocksPresets.production`.');
|
|
52
|
+
}
|
|
53
|
+
// ── Shared execution role ───────────────────────────────────────────────
|
|
40
54
|
// A single IAM role that every Building Block grants to. Provisioned here so
|
|
41
55
|
// it exists before the backend module is imported (Building Blocks reach it
|
|
42
56
|
// via `scope.executionRole`). Block grants sit on the role's default (inline)
|
|
43
|
-
// policy
|
|
57
|
+
// policy. AWSLambdaBasicExecutionRole is attached so compute functions retain
|
|
58
|
+
// CloudWatch Logs permissions.
|
|
44
59
|
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
60
|
+
// INVARIANT: this must be a mutable, framework-owned `iam.Role` — never an
|
|
61
|
+
// imported role (`Role.fromRoleArn`/`fromRoleName`), which is immutable by
|
|
62
|
+
// default. On an immutable role, every Building Block's `grant*()` /
|
|
63
|
+
// `addToPrincipalPolicy()` silently becomes a no-op (returns false, no error),
|
|
64
|
+
// so permissions would quietly vanish. If a bring-your-own-role option is ever
|
|
65
|
+
// added, it must resolve to a mutable role (`{ mutable: true }`).
|
|
47
66
|
const executionRole = new iam.Role(scope, 'BlocksRole', {
|
|
48
67
|
// CompositePrincipal (rather than a bare ServicePrincipal) so additional
|
|
49
68
|
// compute types can assume this same shared role as they are introduced
|
|
@@ -53,52 +72,7 @@ export function setupBlocksInfra(scope, props, id) {
|
|
|
53
72
|
iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'),
|
|
54
73
|
],
|
|
55
74
|
});
|
|
56
|
-
|
|
57
|
-
entry: props.backendHandlerPath,
|
|
58
|
-
runtime: DEFAULT_NODE_RUNTIME,
|
|
59
|
-
handler: 'handler',
|
|
60
|
-
role: executionRole,
|
|
61
|
-
memorySize: 2048,
|
|
62
|
-
timeout: cdk.Duration.seconds(60 * 15),
|
|
63
|
-
environment: {
|
|
64
|
-
NODE_ENV: 'production',
|
|
65
|
-
/**
|
|
66
|
-
* BLOCKS_STACK_NAME is used at runtime to derive physical resource names
|
|
67
|
-
* (DynamoDB table names, env var prefixes). It must match the CDK-time
|
|
68
|
-
* fullId of the BlocksStack/BlocksBackend so resource lookups work correctly.
|
|
69
|
-
*
|
|
70
|
-
* For BlocksStack: this equals the stack name (id).
|
|
71
|
-
* For BlocksBackend: the caller overrides this after construction to include
|
|
72
|
-
* the parent stack name for deployment uniqueness.
|
|
73
|
-
*/
|
|
74
|
-
BLOCKS_STACK_NAME: id ?? cdk.Stack.of(scope).stackName,
|
|
75
|
-
},
|
|
76
|
-
bundling: {
|
|
77
|
-
minify: true,
|
|
78
|
-
esbuildArgs: { '--conditions': 'aws-runtime' },
|
|
79
|
-
},
|
|
80
|
-
});
|
|
81
|
-
// In sandbox mode, allow localhost origins so the local dev frontend can
|
|
82
|
-
// reach the deployed Lambda API via CORS.
|
|
83
|
-
const isSandbox = scope.node.tryGetContext('sandboxMode') === 'true' ||
|
|
84
|
-
scope.node.tryGetContext('sandboxMode') === true;
|
|
85
|
-
if (isSandbox) {
|
|
86
|
-
handler.addEnvironment('CORS_ALLOWED_ORIGINS', '^https?://(localhost|127\\.0\\.0\\.1)(:\\d+)?$');
|
|
87
|
-
}
|
|
88
|
-
const api = new apigateway.RestApi(scope, 'API', {
|
|
89
|
-
restApiName: 'Blocks API',
|
|
90
|
-
deployOptions: { cachingEnabled: false },
|
|
91
|
-
});
|
|
92
|
-
const integration = new apigateway.LambdaIntegration(handler);
|
|
93
|
-
// Build the nested resource tree for /aws-blocks/api.
|
|
94
|
-
// Intermediate resource gets a proxy so sub-paths (RawRoutes) still reach Lambda.
|
|
95
|
-
const awsBlocksResource = api.root.addResource(BLOCKS_NAMESPACE.slice(1));
|
|
96
|
-
awsBlocksResource.addProxy({ defaultIntegration: integration, anyMethod: true });
|
|
97
|
-
const apiResource = awsBlocksResource.addResource('api');
|
|
98
|
-
apiResource.addMethod('POST', integration);
|
|
99
|
-
apiResource.addMethod('OPTIONS', integration);
|
|
100
|
-
api.root.addProxy({ defaultIntegration: integration, anyMethod: true });
|
|
101
|
-
// ── Resource Groups ────────────────────────────────────────────────────
|
|
75
|
+
// ── Resource Groups ───────────────────────────────────────────────────
|
|
102
76
|
let rootStack = cdk.Stack.of(scope);
|
|
103
77
|
while (rootStack.nestedStackParent)
|
|
104
78
|
rootStack = rootStack.nestedStackParent;
|
|
@@ -132,7 +106,7 @@ export function setupBlocksInfra(scope, props, id) {
|
|
|
132
106
|
},
|
|
133
107
|
},
|
|
134
108
|
});
|
|
135
|
-
// ── Console redirect routes
|
|
109
|
+
// ── Console redirect routes ───────────────────────────────────────────
|
|
136
110
|
const region = cdk.Fn.ref('AWS::Region');
|
|
137
111
|
const resourcesUrl = cdk.Fn.join('', [
|
|
138
112
|
'https://', region, '.console.aws.amazon.com/resource-groups/group/',
|
|
@@ -145,7 +119,7 @@ export function setupBlocksInfra(scope, props, id) {
|
|
|
145
119
|
registerConfig(scope, 'BB_RESOURCES_GROUP_URL', resourcesUrl);
|
|
146
120
|
registerConfig(scope, 'BB_SETTINGS_GROUP_URL', settingsUrl);
|
|
147
121
|
registerBuiltinRoutes();
|
|
148
|
-
return {
|
|
122
|
+
return { executionRole };
|
|
149
123
|
}
|
|
150
124
|
/**
|
|
151
125
|
* Standalone CDK construct that provisions the Blocks backend: a single Lambda
|
|
@@ -165,12 +139,31 @@ export function setupBlocksInfra(scope, props, id) {
|
|
|
165
139
|
* ```
|
|
166
140
|
*/
|
|
167
141
|
export class BlocksBackend extends Construct {
|
|
168
|
-
apiUrl;
|
|
169
|
-
gateway;
|
|
170
|
-
handler;
|
|
171
142
|
backendHandlerPath;
|
|
172
143
|
/** Shared IAM role assumed by all Blocks compute. Building Blocks grant to this role. */
|
|
173
144
|
executionRole;
|
|
145
|
+
/** Infrastructure defaults for Building Blocks created under this backend. */
|
|
146
|
+
defaults;
|
|
147
|
+
/** The default compute (owns the Lambda function + API Gateway); set in `create()`. @internal */
|
|
148
|
+
_defaultCompute;
|
|
149
|
+
/** The default compute's Lambda function. To be removed once consumers move to the multi-compute model. */
|
|
150
|
+
get handler() {
|
|
151
|
+
return this.requireDefaultCompute().fn;
|
|
152
|
+
}
|
|
153
|
+
/** The default compute's API Gateway REST API. To be removed once consumers move to the multi-compute model. */
|
|
154
|
+
get gateway() {
|
|
155
|
+
return this.requireDefaultCompute().apiGateway;
|
|
156
|
+
}
|
|
157
|
+
/** The default compute's RPC endpoint URL. To be removed once consumers move to the multi-compute model. */
|
|
158
|
+
get apiUrl() {
|
|
159
|
+
return this.requireDefaultCompute().apiUrl;
|
|
160
|
+
}
|
|
161
|
+
requireDefaultCompute() {
|
|
162
|
+
if (!this._defaultCompute) {
|
|
163
|
+
throw new Error('Blocks backend not fully initialized — access .handler/.gateway/.apiUrl after BlocksBackend.create() resolves.');
|
|
164
|
+
}
|
|
165
|
+
return this._defaultCompute;
|
|
166
|
+
}
|
|
174
167
|
/**
|
|
175
168
|
* The fullId used by child Scopes to compute their env var names,
|
|
176
169
|
* construct IDs, and physical resource names (e.g., DynamoDB table names).
|
|
@@ -206,19 +199,25 @@ export class BlocksBackend extends Construct {
|
|
|
206
199
|
this.backendHandlerPath = props.backendHandlerPath;
|
|
207
200
|
// Expose self to Building Blocks at CDK time
|
|
208
201
|
globalThis.CURRENT_BLOCKS_STACK = this;
|
|
202
|
+
// Store defaults on the backend (not the stack) so several BlocksBackends
|
|
203
|
+
// in one stack each keep their own posture; Building Blocks resolve them by
|
|
204
|
+
// walking up to their owning backend (see Scope.defaults).
|
|
205
|
+
this.defaults = props.defaults;
|
|
209
206
|
const infra = setupBlocksInfra(this, props, id);
|
|
210
|
-
this.handler = infra.handler;
|
|
211
|
-
this.gateway = infra.gateway;
|
|
212
|
-
this.apiUrl = infra.apiUrl;
|
|
213
207
|
this.executionRole = infra.executionRole;
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
// and are unique per deployment.
|
|
217
|
-
this.handler.addEnvironment('BLOCKS_STACK_NAME', this.fullId);
|
|
208
|
+
// The default compute (and thus handler/gateway) is created in create(),
|
|
209
|
+
// after construction — it derives BLOCKS_STACK_NAME from this.fullId.
|
|
218
210
|
}
|
|
219
211
|
static async create(scope, id, props) {
|
|
220
212
|
assertCdkConditionActive();
|
|
221
213
|
const backend = new BlocksBackend(scope, id, props);
|
|
214
|
+
// Create the default compute before importing the backend: it OWNS the
|
|
215
|
+
// Lambda function + API Gateway (which back .handler/.gateway/.apiUrl), and
|
|
216
|
+
// a block reading `this.compute` in its constructor (during that import)
|
|
217
|
+
// must resolve to it. The factory is supplied by the umbrella
|
|
218
|
+
// @aws-blocks/blocks (which injects LambdaCompute) via props, so core never
|
|
219
|
+
// imports the concrete compute class.
|
|
220
|
+
backend._defaultCompute = props.defaultComputeFactory(backend);
|
|
222
221
|
// file:// URL (not a raw path) so the cache-busting query works on Windows,
|
|
223
222
|
// where an absolute path like `D:\...` is rejected as URL scheme `d:`.
|
|
224
223
|
const backendUrl = pathToFileURL(props.backendCDKPath);
|
|
@@ -1,14 +1,52 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { test, describe, before } from 'node:test';
|
|
4
3
|
import assert from 'node:assert';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
4
|
import { dirname, join } from 'node:path';
|
|
5
|
+
import { before, describe, test } from 'node:test';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import * as cdk from 'aws-cdk-lib';
|
|
8
|
-
import {
|
|
8
|
+
import { Match, Template } from 'aws-cdk-lib/assertions';
|
|
9
|
+
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
|
|
9
10
|
import { PolicyStatement } from 'aws-cdk-lib/aws-iam';
|
|
11
|
+
import * as lambda from 'aws-cdk-lib/aws-lambda-nodejs';
|
|
12
|
+
import { BLOCKS_RPC_PREFIX } from '../constants.js';
|
|
10
13
|
import { BlocksBackend } from './blocks-backend.js';
|
|
14
|
+
import { BlocksPresets } from './blocks-defaults.js';
|
|
15
|
+
import { Compute } from './compute/compute.js';
|
|
11
16
|
import { Scope } from './index.js';
|
|
17
|
+
// A real app gets its default compute from @aws-blocks/bb-lambda-compute (via
|
|
18
|
+
// @aws-blocks/blocks), which core's own tests can't depend on. Use an
|
|
19
|
+
// equivalent inline stub: a Compute that owns a NodejsFunction + API Gateway,
|
|
20
|
+
// so create() can build the default and the handler/gateway/apiUrl accessors
|
|
21
|
+
// and synth-shape assertions have something real to resolve to. It is passed to
|
|
22
|
+
// each create() via the internal `defaultComputeFactory` option (see
|
|
23
|
+
// makeBackend), exactly as @aws-blocks/blocks injects LambdaCompute.
|
|
24
|
+
class StubLambdaCompute extends Compute {
|
|
25
|
+
fn;
|
|
26
|
+
apiGateway;
|
|
27
|
+
apiUrl;
|
|
28
|
+
constructor(scope, id) {
|
|
29
|
+
super(id, { parent: scope });
|
|
30
|
+
this.fn = new lambda.NodejsFunction(this, 'Handler', {
|
|
31
|
+
entry: this.backendHandlerPath,
|
|
32
|
+
runtime: cdk.aws_lambda.Runtime.NODEJS_22_X,
|
|
33
|
+
handler: 'handler',
|
|
34
|
+
role: this.executionRole,
|
|
35
|
+
environment: { BLOCKS_STACK_NAME: this.backendStackName },
|
|
36
|
+
bundling: { minify: true, esbuildArgs: { '--conditions': 'aws-runtime' } },
|
|
37
|
+
});
|
|
38
|
+
this.apiGateway = new apigateway.RestApi(this, 'API', { restApiName: 'Blocks API' });
|
|
39
|
+
this.apiGateway.root.addProxy({
|
|
40
|
+
defaultIntegration: new apigateway.LambdaIntegration(this.fn),
|
|
41
|
+
anyMethod: true,
|
|
42
|
+
});
|
|
43
|
+
this.apiUrl = `${this.apiGateway.url}${BLOCKS_RPC_PREFIX.slice(1)}`;
|
|
44
|
+
}
|
|
45
|
+
setEnv(key, value) {
|
|
46
|
+
this.fn.addEnvironment(key, value);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const stubComputeFactory = (root) => new StubLambdaCompute(root, 'DefaultCompute');
|
|
12
50
|
// Simulate the CDK condition being active (tests import CDK files directly)
|
|
13
51
|
before(() => {
|
|
14
52
|
process.env.NODE_OPTIONS = (process.env.NODE_OPTIONS ?? '') + ' --conditions=cdk';
|
|
@@ -19,18 +57,16 @@ const sideEffectBackendPath = join(__dirname, '__fixtures__', 'side-effect-backe
|
|
|
19
57
|
const factoryBackendPath = join(__dirname, '__fixtures__', 'factory-backend.js');
|
|
20
58
|
const fullIdConstructBackendPath = join(__dirname, '__fixtures__', 'fullid-construct-backend.js');
|
|
21
59
|
const EXECUTION_ROLE_MARKER_ACTION = 'blocks-test:MarkerAction';
|
|
60
|
+
const importMetaHandlerPath = join(__dirname, '__fixtures__', 'import-meta-handler.js');
|
|
61
|
+
// Wraps BlocksBackend.create, injecting the stub default-compute factory the way
|
|
62
|
+
// @aws-blocks/blocks injects LambdaCompute — so tests don't repeat it 15 times.
|
|
63
|
+
const makeBackend = (scope, id, backendCDKPath) => BlocksBackend.create(scope, id, { backendHandlerPath: handlerPath, backendCDKPath, defaults: BlocksPresets.production, defaultComputeFactory: stubComputeFactory });
|
|
22
64
|
describe('ESM cache-busting (multi-stage)', () => {
|
|
23
65
|
test('BlocksBackend.create() with same backendCDKPath but different IDs produces constructs in each', async () => {
|
|
24
66
|
const app = new cdk.App();
|
|
25
67
|
const stack = new cdk.Stack(app, 'TestStack');
|
|
26
|
-
const backend1 = await
|
|
27
|
-
|
|
28
|
-
backendCDKPath: sideEffectBackendPath,
|
|
29
|
-
});
|
|
30
|
-
const backend2 = await BlocksBackend.create(stack, 'Stage2', {
|
|
31
|
-
backendHandlerPath: handlerPath,
|
|
32
|
-
backendCDKPath: sideEffectBackendPath,
|
|
33
|
-
});
|
|
68
|
+
const backend1 = await makeBackend(stack, 'Stage1', sideEffectBackendPath);
|
|
69
|
+
const backend2 = await makeBackend(stack, 'Stage2', sideEffectBackendPath);
|
|
34
70
|
const findMarker = (scope) => scope.node.tryFindChild('SideEffectMarker');
|
|
35
71
|
assert.ok(findMarker(backend1), 'Stage1 backend should have SideEffectMarker construct from module side effect');
|
|
36
72
|
assert.ok(findMarker(backend2), 'Stage2 backend should have SideEffectMarker construct from re-executed module');
|
|
@@ -40,10 +76,7 @@ describe('synth shape (drop into existing stack)', () => {
|
|
|
40
76
|
test('BlocksBackend lives inside the parent stack and synthesizes Lambda + API Gateway', async () => {
|
|
41
77
|
const app = new cdk.App();
|
|
42
78
|
const parent = new cdk.Stack(app, 'MyExistingStack');
|
|
43
|
-
const backend = await
|
|
44
|
-
backendHandlerPath: handlerPath,
|
|
45
|
-
backendCDKPath: sideEffectBackendPath,
|
|
46
|
-
});
|
|
79
|
+
const backend = await makeBackend(parent, 'Blocks', sideEffectBackendPath);
|
|
47
80
|
// Public surface mirrors BlocksStack.
|
|
48
81
|
assert.ok(backend.handler, 'BlocksBackend should expose .handler');
|
|
49
82
|
assert.ok(backend.gateway, 'BlocksBackend should expose .gateway');
|
|
@@ -57,14 +90,8 @@ describe('synth shape (drop into existing stack)', () => {
|
|
|
57
90
|
test('multiple BlocksBackends in the same parent stack do not collide', async () => {
|
|
58
91
|
const app = new cdk.App();
|
|
59
92
|
const parent = new cdk.Stack(app, 'MultiBackendStack');
|
|
60
|
-
await
|
|
61
|
-
|
|
62
|
-
backendCDKPath: sideEffectBackendPath,
|
|
63
|
-
});
|
|
64
|
-
await BlocksBackend.create(parent, 'BackendB', {
|
|
65
|
-
backendHandlerPath: handlerPath,
|
|
66
|
-
backendCDKPath: sideEffectBackendPath,
|
|
67
|
-
});
|
|
93
|
+
await makeBackend(parent, 'BackendA', sideEffectBackendPath);
|
|
94
|
+
await makeBackend(parent, 'BackendB', sideEffectBackendPath);
|
|
68
95
|
const template = Template.fromStack(parent);
|
|
69
96
|
template.resourceCountIs('AWS::ApiGateway::RestApi', 2);
|
|
70
97
|
});
|
|
@@ -73,19 +100,13 @@ describe('shared execution role', () => {
|
|
|
73
100
|
test('exposes executionRole on the backend', async () => {
|
|
74
101
|
const app = new cdk.App();
|
|
75
102
|
const parent = new cdk.Stack(app, 'RoleSurfaceStack');
|
|
76
|
-
const backend = await
|
|
77
|
-
backendHandlerPath: handlerPath,
|
|
78
|
-
backendCDKPath: sideEffectBackendPath,
|
|
79
|
-
});
|
|
103
|
+
const backend = await makeBackend(parent, 'Blocks', sideEffectBackendPath);
|
|
80
104
|
assert.ok(backend.executionRole, 'BlocksBackend should expose .executionRole');
|
|
81
105
|
});
|
|
82
106
|
test('synth produces a Lambda-assumable role with basic execution, and the handler uses it', async () => {
|
|
83
107
|
const app = new cdk.App();
|
|
84
108
|
const parent = new cdk.Stack(app, 'RoleSynthStack');
|
|
85
|
-
await
|
|
86
|
-
backendHandlerPath: handlerPath,
|
|
87
|
-
backendCDKPath: sideEffectBackendPath,
|
|
88
|
-
});
|
|
109
|
+
await makeBackend(parent, 'Blocks', sideEffectBackendPath);
|
|
89
110
|
const template = Template.fromStack(parent);
|
|
90
111
|
// The shared role (logical id derived from the 'BlocksRole' construct id)
|
|
91
112
|
// is assumable by Lambda and carries AWSLambdaBasicExecutionRole (so
|
|
@@ -93,7 +114,7 @@ describe('shared execution role', () => {
|
|
|
93
114
|
// roles exist (API Gateway CloudWatch role, config BucketDeployment role),
|
|
94
115
|
// so we target ours by logical id.
|
|
95
116
|
const roles = template.findResources('AWS::IAM::Role');
|
|
96
|
-
const blocksRoleId = Object.keys(roles).find(k => k.includes('BlocksRole'));
|
|
117
|
+
const blocksRoleId = Object.keys(roles).find((k) => k.includes('BlocksRole'));
|
|
97
118
|
assert.ok(blocksRoleId, 'expected a role from the BlocksRole construct');
|
|
98
119
|
const blocksRole = roles[blocksRoleId];
|
|
99
120
|
assert.deepStrictEqual(blocksRole.Properties.AssumeRolePolicyDocument.Statement[0], {
|
|
@@ -110,10 +131,7 @@ describe('shared execution role', () => {
|
|
|
110
131
|
test('a nested block resolves executionRole via the construct-tree walk', async () => {
|
|
111
132
|
const app = new cdk.App();
|
|
112
133
|
const parent = new cdk.Stack(app, 'RoleResolveStack');
|
|
113
|
-
const backend = await
|
|
114
|
-
backendHandlerPath: handlerPath,
|
|
115
|
-
backendCDKPath: sideEffectBackendPath,
|
|
116
|
-
});
|
|
134
|
+
const backend = await makeBackend(parent, 'Blocks', sideEffectBackendPath);
|
|
117
135
|
// Build nested Scopes under the backend (outer → inner), the same shape a
|
|
118
136
|
// real Building Block tree has, and grant a uniquely-named marker action to
|
|
119
137
|
// `this.executionRole` from the innermost scope. If the getter's tree-walk
|
|
@@ -136,14 +154,29 @@ describe('shared execution role', () => {
|
|
|
136
154
|
});
|
|
137
155
|
});
|
|
138
156
|
});
|
|
157
|
+
describe('CJS bundle: import.meta.url in the handler is shimmed (no Lambda-load crash)', () => {
|
|
158
|
+
test('a handler that uses import.meta.url bundles successfully instead of throwing at load', async () => {
|
|
159
|
+
// The handler is bundled to CJS, where `import.meta` is empty. Left unshimmed,
|
|
160
|
+
// `fileURLToPath(import.meta.url)` compiles to `fileURLToPath(undefined)` and
|
|
161
|
+
// throws at Lambda load (esbuild only warns, so the broken bundle would deploy).
|
|
162
|
+
// blocksNodejsBundling shims import.meta.* to CommonJS equivalents, so bundling
|
|
163
|
+
// (which runs synchronously during construction) succeeds. The runtime behaviour
|
|
164
|
+
// of the emitted shim is verified directly in bundling.test.ts.
|
|
165
|
+
const app = new cdk.App();
|
|
166
|
+
const stack = new cdk.Stack(app, 'ImportMetaStack');
|
|
167
|
+
await assert.doesNotReject(() => BlocksBackend.create(stack, 'blocks', {
|
|
168
|
+
backendHandlerPath: importMetaHandlerPath,
|
|
169
|
+
backendCDKPath: sideEffectBackendPath,
|
|
170
|
+
defaults: BlocksPresets.production,
|
|
171
|
+
defaultComputeFactory: stubComputeFactory,
|
|
172
|
+
}));
|
|
173
|
+
});
|
|
174
|
+
});
|
|
139
175
|
describe('factory function support', () => {
|
|
140
176
|
test('BlocksBackend.create() calls default export function with the backend instance', async () => {
|
|
141
177
|
const app = new cdk.App();
|
|
142
178
|
const stack = new cdk.Stack(app, 'FactoryTestStack');
|
|
143
|
-
const backend = await
|
|
144
|
-
backendHandlerPath: handlerPath,
|
|
145
|
-
backendCDKPath: factoryBackendPath,
|
|
146
|
-
});
|
|
179
|
+
const backend = await makeBackend(stack, 'FactoryStage', factoryBackendPath);
|
|
147
180
|
const marker = backend.node.tryFindChild('FactoryMarker');
|
|
148
181
|
assert.ok(marker, 'Factory function should have created FactoryMarker on the backend');
|
|
149
182
|
});
|
|
@@ -152,10 +185,7 @@ describe('fullId is token-free (construct IDs / env-var keys)', () => {
|
|
|
152
185
|
test('top-level stack: fullId is {stackName}-{id} and resolvable', async () => {
|
|
153
186
|
const app = new cdk.App();
|
|
154
187
|
const stack = new cdk.Stack(app, 'TopLevelStack');
|
|
155
|
-
const backend = await
|
|
156
|
-
backendHandlerPath: handlerPath,
|
|
157
|
-
backendCDKPath: sideEffectBackendPath,
|
|
158
|
-
});
|
|
188
|
+
const backend = await makeBackend(stack, 'blocks', sideEffectBackendPath);
|
|
159
189
|
assert.strictEqual(backend.fullId, 'TopLevelStack-blocks');
|
|
160
190
|
assert.ok(!cdk.Token.isUnresolved(backend.fullId), 'fullId must not contain a token');
|
|
161
191
|
});
|
|
@@ -169,10 +199,7 @@ describe('fullId is token-free (construct IDs / env-var keys)', () => {
|
|
|
169
199
|
const nested = new cdk.NestedStack(parent, 'blocks');
|
|
170
200
|
// Sanity: the nested stack's own name really is a token.
|
|
171
201
|
assert.ok(cdk.Token.isUnresolved(nested.stackName), 'precondition: NestedStack.stackName should be an unresolved token');
|
|
172
|
-
const backend = await
|
|
173
|
-
backendHandlerPath: handlerPath,
|
|
174
|
-
backendCDKPath: sideEffectBackendPath,
|
|
175
|
-
});
|
|
202
|
+
const backend = await makeBackend(nested, 'blocks', sideEffectBackendPath);
|
|
176
203
|
assert.ok(!cdk.Token.isUnresolved(backend.fullId), `fullId must be token-free inside a nested stack, got: ${backend.fullId}`);
|
|
177
204
|
// Falls back to the top-level (concrete) stack name, keeping uniqueness.
|
|
178
205
|
assert.strictEqual(backend.fullId, 'ParentStack-blocks');
|
|
@@ -183,10 +210,7 @@ describe('fullId is token-free (construct IDs / env-var keys)', () => {
|
|
|
183
210
|
const app = new cdk.App();
|
|
184
211
|
const parent = new cdk.Stack(app, 'Gen2ParentStack');
|
|
185
212
|
const nested = new cdk.NestedStack(parent, 'blocks');
|
|
186
|
-
const backend = await
|
|
187
|
-
backendHandlerPath: handlerPath,
|
|
188
|
-
backendCDKPath: fullIdConstructBackendPath,
|
|
189
|
-
});
|
|
213
|
+
const backend = await makeBackend(nested, 'blocks', fullIdConstructBackendPath);
|
|
190
214
|
// The construct ID is `${scope.fullId}Marker` → `ParentStack-blocks-blocks-dbMarker`.
|
|
191
215
|
const expectedId = `${backend.fullId}-dbMarker`;
|
|
192
216
|
assert.ok(nested.node.tryFindChild(expectedId), `expected a child construct with id "${expectedId}"`);
|
|
@@ -203,10 +227,7 @@ describe('fullId is token-free (construct IDs / env-var keys)', () => {
|
|
|
203
227
|
const app = new cdk.App();
|
|
204
228
|
const parent = new cdk.Stack(app, 'InvariantParent');
|
|
205
229
|
const nested = new cdk.NestedStack(parent, 'blocks');
|
|
206
|
-
const backend = await
|
|
207
|
-
backendHandlerPath: handlerPath,
|
|
208
|
-
backendCDKPath: sideEffectBackendPath,
|
|
209
|
-
});
|
|
230
|
+
const backend = await makeBackend(nested, 'blocks', sideEffectBackendPath);
|
|
210
231
|
const template = Template.fromStack(nested);
|
|
211
232
|
const fns = template.findResources('AWS::Lambda::Function');
|
|
212
233
|
const envValues = Object.values(fns)
|
|
@@ -219,3 +240,40 @@ describe('fullId is token-free (construct IDs / env-var keys)', () => {
|
|
|
219
240
|
}
|
|
220
241
|
});
|
|
221
242
|
});
|
|
243
|
+
describe('infrastructure defaults (backend-anchored)', () => {
|
|
244
|
+
test('each backend exposes its own defaults', async () => {
|
|
245
|
+
const app = new cdk.App();
|
|
246
|
+
const stack = new cdk.Stack(app, 'TwoBackendsStack');
|
|
247
|
+
const a = await BlocksBackend.create(stack, 'A', {
|
|
248
|
+
backendHandlerPath: handlerPath,
|
|
249
|
+
backendCDKPath: sideEffectBackendPath,
|
|
250
|
+
defaults: BlocksPresets.production,
|
|
251
|
+
defaultComputeFactory: stubComputeFactory,
|
|
252
|
+
});
|
|
253
|
+
const b = await BlocksBackend.create(stack, 'B', {
|
|
254
|
+
backendHandlerPath: handlerPath,
|
|
255
|
+
backendCDKPath: sideEffectBackendPath,
|
|
256
|
+
defaults: BlocksPresets.sandbox,
|
|
257
|
+
defaultComputeFactory: stubComputeFactory,
|
|
258
|
+
});
|
|
259
|
+
// Two backends in one stack must NOT clobber each other — defaults are
|
|
260
|
+
// anchored on the backend, not the shared stack.
|
|
261
|
+
assert.strictEqual(a.defaults, BlocksPresets.production);
|
|
262
|
+
assert.strictEqual(b.defaults, BlocksPresets.sandbox);
|
|
263
|
+
});
|
|
264
|
+
test('a nested block resolves its owning backend defaults via the tree-walk', async () => {
|
|
265
|
+
const app = new cdk.App();
|
|
266
|
+
const stack = new cdk.Stack(app, 'ResolveDefaultsStack');
|
|
267
|
+
const backend = await BlocksBackend.create(stack, 'Blocks', {
|
|
268
|
+
backendHandlerPath: handlerPath,
|
|
269
|
+
backendCDKPath: sideEffectBackendPath,
|
|
270
|
+
defaults: BlocksPresets.sandbox,
|
|
271
|
+
defaultComputeFactory: stubComputeFactory,
|
|
272
|
+
});
|
|
273
|
+
// A Scope under the backend resolves scope.defaults by walking up to it.
|
|
274
|
+
const outer = new Scope('outer');
|
|
275
|
+
const inner = new Scope('inner', { parent: outer });
|
|
276
|
+
assert.strictEqual(inner.defaults, backend.defaults);
|
|
277
|
+
assert.strictEqual(inner.defaults, BlocksPresets.sandbox);
|
|
278
|
+
});
|
|
279
|
+
});
|