@aws-blocks/core 0.3.0 → 0.5.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/README.md +25 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +32 -0
- package/dist/api.test.js +22 -0
- package/dist/bb-utils.d.ts +1 -0
- package/dist/bb-utils.d.ts.map +1 -1
- package/dist/bb-utils.js +3 -0
- package/dist/cdk/apigateway-account.d.ts +33 -0
- package/dist/cdk/apigateway-account.d.ts.map +1 -0
- package/dist/cdk/apigateway-account.js +60 -0
- package/dist/cdk/blocks-backend.d.ts +11 -0
- package/dist/cdk/blocks-backend.d.ts.map +1 -1
- package/dist/cdk/blocks-backend.js +72 -13
- package/dist/cdk/blocks-backend.test.js +88 -1
- package/dist/cdk/blocks-defaults.d.ts +76 -1
- package/dist/cdk/blocks-defaults.d.ts.map +1 -1
- package/dist/cdk/blocks-defaults.js +17 -1
- package/dist/cdk/blocks-defaults.test.js +17 -0
- package/dist/cdk/blocks-stack.test.js +44 -3
- package/dist/cdk/compute/compute-registry.d.ts +19 -0
- package/dist/cdk/compute/compute-registry.d.ts.map +1 -0
- package/dist/cdk/compute/compute-registry.js +38 -0
- package/dist/cdk/compute/compute.d.ts +82 -2
- package/dist/cdk/compute/compute.d.ts.map +1 -1
- package/dist/cdk/compute/compute.js +64 -2
- package/dist/cdk/compute/default-compute-factory.d.ts +1 -0
- package/dist/cdk/compute/default-compute-factory.d.ts.map +1 -1
- package/dist/cdk/config-registry.d.ts +34 -4
- package/dist/cdk/config-registry.d.ts.map +1 -1
- package/dist/cdk/config-registry.js +83 -25
- package/dist/cdk/config-registry.test.d.ts +2 -0
- package/dist/cdk/config-registry.test.d.ts.map +1 -0
- package/dist/cdk/config-registry.test.js +127 -0
- package/dist/cdk/dashboard-registry.d.ts +41 -0
- package/dist/cdk/dashboard-registry.d.ts.map +1 -0
- package/dist/cdk/dashboard-registry.js +61 -0
- package/dist/cdk/index.d.ts +90 -6
- package/dist/cdk/index.d.ts.map +1 -1
- package/dist/cdk/index.js +135 -13
- package/dist/cdk/internal.d.ts +3 -1
- package/dist/cdk/internal.d.ts.map +1 -1
- package/dist/cdk/internal.js +4 -1
- package/dist/cdk/tracer-registry.d.ts +31 -0
- package/dist/cdk/tracer-registry.d.ts.map +1 -0
- package/dist/cdk/tracer-registry.js +49 -0
- package/dist/cdk/vpc-requirements-registry.d.ts +33 -0
- package/dist/cdk/vpc-requirements-registry.d.ts.map +1 -0
- package/dist/cdk/vpc-requirements-registry.js +46 -0
- package/dist/cdk/vpc-types.d.ts +151 -0
- package/dist/cdk/vpc-types.d.ts.map +1 -0
- package/dist/cdk/vpc-types.js +3 -0
- package/dist/cdk/vpc.d.ts +59 -0
- package/dist/cdk/vpc.d.ts.map +1 -0
- package/dist/cdk/vpc.js +298 -0
- package/dist/cdk/vpc.test.d.ts +2 -0
- package/dist/cdk/vpc.test.d.ts.map +1 -0
- package/dist/cdk/vpc.test.js +285 -0
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/common/config.d.ts +34 -0
- package/dist/common/config.d.ts.map +1 -1
- package/dist/common/config.js +45 -3
- package/dist/common/config.test.js +19 -0
- package/dist/common/index.d.ts +8 -0
- package/dist/common/index.d.ts.map +1 -1
- package/dist/errors.d.ts +21 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +25 -0
- package/dist/hosting.d.ts +9 -0
- package/dist/hosting.d.ts.map +1 -1
- package/dist/hosting.js +12 -1
- package/dist/hosting.test.js +63 -1
- package/dist/index.cdk.d.ts +3 -2
- package/dist/index.cdk.d.ts.map +1 -1
- package/dist/index.cdk.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/lambda-handler.d.ts +17 -0
- package/dist/lambda-handler.d.ts.map +1 -1
- package/dist/lambda-handler.js +61 -5
- package/dist/lambda-handler.test.js +191 -2
- package/dist/raw-route.d.ts +15 -1
- package/dist/raw-route.d.ts.map +1 -1
- package/dist/raw-route.js +96 -12
- package/dist/raw-route.test.js +332 -1
- package/dist/scripts/dev-server.d.ts.map +1 -1
- package/dist/scripts/dev-server.js +11 -0
- package/dist/scripts/extract-ts-types.d.ts.map +1 -1
- package/dist/scripts/extract-ts-types.js +107 -23
- package/dist/scripts/extract-ts-types.test.js +225 -26
- package/dist/scripts/generate-spec.d.ts.map +1 -1
- package/dist/scripts/generate-spec.js +14 -5
- package/dist/scripts/generate-spec.test.js +93 -0
- package/dist/scripts/sandbox-empty-buckets.test.d.ts +2 -0
- package/dist/scripts/sandbox-empty-buckets.test.d.ts.map +1 -0
- package/dist/scripts/sandbox-empty-buckets.test.js +171 -0
- package/dist/scripts/sandbox.d.ts +54 -0
- package/dist/scripts/sandbox.d.ts.map +1 -1
- package/dist/scripts/sandbox.js +163 -25
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +10 -1
- package/src/api.test.ts +25 -0
- package/src/api.ts +39 -0
- package/src/bb-utils.ts +3 -0
- package/src/cdk/apigateway-account.ts +66 -0
- package/src/cdk/blocks-backend.test.ts +168 -60
- package/src/cdk/blocks-backend.ts +299 -227
- package/src/cdk/blocks-defaults.test.ts +21 -0
- package/src/cdk/blocks-defaults.ts +79 -1
- package/src/cdk/blocks-stack.test.ts +57 -13
- package/src/cdk/compute/compute-registry.ts +45 -0
- package/src/cdk/compute/compute.ts +114 -2
- package/src/cdk/compute/default-compute-factory.ts +1 -0
- package/src/cdk/config-registry.test.ts +149 -0
- package/src/cdk/config-registry.ts +92 -34
- package/src/cdk/dashboard-registry.ts +68 -0
- package/src/cdk/index.ts +427 -256
- package/src/cdk/internal.ts +6 -2
- package/src/cdk/tracer-registry.ts +54 -0
- package/src/cdk/vpc-requirements-registry.ts +63 -0
- package/src/cdk/vpc-types.ts +158 -0
- package/src/cdk/vpc.test.ts +348 -0
- package/src/cdk/vpc.ts +336 -0
- package/src/client/index.ts +1 -1
- package/src/common/config.test.ts +21 -0
- package/src/common/config.ts +47 -3
- package/src/common/index.ts +8 -0
- package/src/errors.ts +26 -0
- package/src/hosting.test.ts +87 -1
- package/src/hosting.ts +24 -1
- package/src/index.cdk.ts +11 -1
- package/src/index.ts +1 -1
- package/src/lambda-handler.test.ts +220 -2
- package/src/lambda-handler.ts +65 -4
- package/src/raw-route.test.ts +427 -1
- package/src/raw-route.ts +125 -12
- package/src/scripts/dev-server.ts +12 -1
- package/src/scripts/extract-ts-types.test.ts +228 -26
- package/src/scripts/extract-ts-types.ts +104 -20
- package/src/scripts/generate-spec.test.ts +101 -0
- package/src/scripts/generate-spec.ts +15 -5
- package/src/scripts/sandbox-empty-buckets.test.ts +191 -0
- package/src/scripts/sandbox.ts +185 -24
- package/src/version.ts +1 -1
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
4
5
|
import * as cdk from 'aws-cdk-lib';
|
|
5
6
|
import type * as apigateway from 'aws-cdk-lib/aws-apigateway';
|
|
6
7
|
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
7
8
|
import { CfnGroup } from 'aws-cdk-lib/aws-resourcegroups';
|
|
8
9
|
import { Construct } from 'constructs';
|
|
9
|
-
import { pathToFileURL } from 'node:url';
|
|
10
|
-
import { addBlocksStackMetadata } from './stack-metadata.js';
|
|
11
|
-
import { finalizeConfigRegistry, registerConfig } from './config-registry.js';
|
|
12
|
-
import type { BlocksDefaults } from './blocks-defaults.js';
|
|
13
10
|
import { registerBuiltinRoutes } from '../builtin-routes.js';
|
|
11
|
+
import type { BlocksDefaults } from './blocks-defaults.js';
|
|
14
12
|
import type { Compute } from './compute/compute.js';
|
|
13
|
+
import { getComputes } from './compute/compute-registry.js';
|
|
15
14
|
import type { DefaultComputeFactory, LambdaShapedCompute } from './compute/default-compute-factory.js';
|
|
15
|
+
import { finalizeConfigRegistry, registerConfig } from './config-registry.js';
|
|
16
|
+
import { finalizeDashboards } from './dashboard-registry.js';
|
|
17
|
+
import { finalizeTracing } from './tracer-registry.js';
|
|
18
|
+
import { addBlocksStackMetadata } from './stack-metadata.js';
|
|
19
|
+
import { anyRequirementNeedsVpc, finalizeVpc, getOrCreateVpc, initializeVpc } from './vpc.js';
|
|
20
|
+
import type { BlocksVpcOptions } from './vpc-types.js';
|
|
16
21
|
|
|
17
22
|
/**
|
|
18
23
|
* Validate that the Node.js process was started with `--conditions=cdk`.
|
|
@@ -23,23 +28,23 @@ import type { DefaultComputeFactory, LambdaShapedCompute } from './compute/defau
|
|
|
23
28
|
* no real infrastructure (no tables, no IAM, no Lambda configs).
|
|
24
29
|
*/
|
|
25
30
|
export function assertCdkConditionActive(): void {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
31
|
+
const nodeOptions = process.env.NODE_OPTIONS ?? '';
|
|
32
|
+
const execArgv = process.execArgv ?? [];
|
|
33
|
+
|
|
34
|
+
const hasCdkCondition =
|
|
35
|
+
execArgv.some((arg) => arg === '--conditions=cdk') ||
|
|
36
|
+
execArgv.some((arg, i) => (arg === '--conditions' || arg === '-C') && execArgv[i + 1] === 'cdk') ||
|
|
37
|
+
nodeOptions.includes('--conditions=cdk') ||
|
|
38
|
+
/(?:--conditions|-C)\s+cdk/.test(nodeOptions);
|
|
39
|
+
|
|
40
|
+
if (!hasCdkCondition) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
'Missing --conditions=cdk: Building Blocks will silently load mock implementations instead of CDK constructs.\n\n' +
|
|
43
|
+
'Fix: Set NODE_OPTIONS="--conditions=cdk" before running CDK synth:\n' +
|
|
44
|
+
' NODE_OPTIONS="--conditions=cdk" npx cdk synth\n\n' +
|
|
45
|
+
'Or use the Blocks CLI commands (npm run deploy / npm run sandbox) which set this automatically.',
|
|
46
|
+
);
|
|
47
|
+
}
|
|
43
48
|
}
|
|
44
49
|
|
|
45
50
|
/**
|
|
@@ -50,16 +55,16 @@ export function assertCdkConditionActive(): void {
|
|
|
50
55
|
export const SHARED_HANDLER_TIMEOUT_SECONDS = 60 * 15;
|
|
51
56
|
|
|
52
57
|
export interface BlocksBackendProps {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
backendHandlerPath: string;
|
|
59
|
+
backendCDKPath: string;
|
|
60
|
+
/**
|
|
61
|
+
* Stack-wide infrastructure defaults applied to every Building Block (removal
|
|
62
|
+
* policy, deletion protection, …). See {@link BlocksDefaults}. Start from
|
|
63
|
+
* `BlocksPresets.sandbox` or `BlocksPresets.production` and override
|
|
64
|
+
* individual fields as needed. A per-block option always wins over the
|
|
65
|
+
* corresponding stack default.
|
|
66
|
+
*/
|
|
67
|
+
defaults: BlocksDefaults;
|
|
63
68
|
}
|
|
64
69
|
|
|
65
70
|
/**
|
|
@@ -70,8 +75,8 @@ export interface BlocksBackendProps {
|
|
|
70
75
|
* @internal
|
|
71
76
|
*/
|
|
72
77
|
export interface CoreBlocksBackendProps extends BlocksBackendProps {
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
/** Builds the backend's default compute. Injected by `@aws-blocks/blocks`. */
|
|
79
|
+
defaultComputeFactory: DefaultComputeFactory;
|
|
75
80
|
}
|
|
76
81
|
|
|
77
82
|
/**
|
|
@@ -80,93 +85,106 @@ export interface CoreBlocksBackendProps extends BlocksBackendProps {
|
|
|
80
85
|
* routes.
|
|
81
86
|
*/
|
|
82
87
|
export function setupBlocksInfra(scope: Construct, props: BlocksBackendProps, id?: string) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
88
|
+
// Fail fast with an actionable message at the create() call site if `defaults`
|
|
89
|
+
// is missing (e.g. a plain-JS caller, `as any`, or a dynamically-built props
|
|
90
|
+
// object) — otherwise the first Building Block to read `scope.defaults` throws
|
|
91
|
+
// a cryptic `Cannot read properties of undefined (reading 'removalPolicy')`.
|
|
92
|
+
if (!props.defaults) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
'BlocksStack/BlocksBackend requires a `defaults` field. Pass a posture from ' +
|
|
95
|
+
'`@aws-blocks/core/cdk` — typically `defaults: sandboxMode ? BlocksPresets.sandbox : BlocksPresets.production`.',
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ── Shared execution role ───────────────────────────────────────────────
|
|
100
|
+
// A single IAM role that every Building Block grants to. Provisioned here so
|
|
101
|
+
// it exists before the backend module is imported (Building Blocks reach it
|
|
102
|
+
// via `scope.executionRole`). Block grants sit on the role's default (inline)
|
|
103
|
+
// policy. AWSLambdaBasicExecutionRole is attached so compute functions retain
|
|
104
|
+
// CloudWatch Logs permissions.
|
|
105
|
+
//
|
|
106
|
+
// INVARIANT: this must be a mutable, framework-owned `iam.Role` — never an
|
|
107
|
+
// imported role (`Role.fromRoleArn`/`fromRoleName`), which is immutable by
|
|
108
|
+
// default. On an immutable role, every Building Block's `grant*()` /
|
|
109
|
+
// `addToPrincipalPolicy()` silently becomes a no-op (returns false, no error),
|
|
110
|
+
// so permissions would quietly vanish. If a bring-your-own-role option is ever
|
|
111
|
+
// added, it must resolve to a mutable role (`{ mutable: true }`).
|
|
112
|
+
const executionRole = new iam.Role(scope, 'BlocksRole', {
|
|
113
|
+
// CompositePrincipal (rather than a bare ServicePrincipal) so a Building Block
|
|
114
|
+
// whose compute runs AS this shared role can add its own trust principal here
|
|
115
|
+
// (e.g. the Agent BB adds bedrock-agentcore in its CDK construct) — core stays
|
|
116
|
+
// agnostic and only Lambda is trusted by default.
|
|
117
|
+
assumedBy: new iam.CompositePrincipal(new iam.ServicePrincipal('lambda.amazonaws.com')),
|
|
118
|
+
managedPolicies: [
|
|
119
|
+
iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'),
|
|
120
|
+
// When Lambda is placed in a VPC it needs ENI management permissions
|
|
121
|
+
...(props.defaults.vpc
|
|
122
|
+
? [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaVPCAccessExecutionRole')]
|
|
123
|
+
: []),
|
|
124
|
+
],
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// ── Resource Groups ───────────────────────────────────────────────────
|
|
128
|
+
let rootStack = cdk.Stack.of(scope);
|
|
129
|
+
while (rootStack.nestedStackParent) rootStack = rootStack.nestedStackParent;
|
|
130
|
+
const groupPrefix = id && id !== rootStack.stackName ? `${rootStack.stackName}-${id}` : rootStack.stackName;
|
|
131
|
+
|
|
132
|
+
new CfnGroup(scope, 'StackResources', {
|
|
133
|
+
name: `${groupPrefix}-resources`,
|
|
134
|
+
resourceQuery: {
|
|
135
|
+
type: 'CLOUDFORMATION_STACK_1_0',
|
|
136
|
+
query: {
|
|
137
|
+
resourceTypeFilters: [
|
|
138
|
+
'AWS::CloudWatch::Dashboard',
|
|
139
|
+
'AWS::Cognito::UserPool',
|
|
140
|
+
'AWS::DynamoDB::Table',
|
|
141
|
+
'AWS::Logs::LogGroup',
|
|
142
|
+
'AWS::RDS::DBCluster',
|
|
143
|
+
'AWS::RDS::DBInstance',
|
|
144
|
+
'AWS::S3::Bucket',
|
|
145
|
+
'AWS::SQS::Queue',
|
|
146
|
+
],
|
|
147
|
+
stackIdentifier: cdk.Stack.of(scope).stackId,
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
new CfnGroup(scope, 'StackSettings', {
|
|
153
|
+
name: `${groupPrefix}-settings`,
|
|
154
|
+
resourceQuery: {
|
|
155
|
+
type: 'TAG_FILTERS_1_0',
|
|
156
|
+
query: {
|
|
157
|
+
resourceTypeFilters: ['AWS::SSM::Parameter'],
|
|
158
|
+
tagFilters: [{ key: 'aws-blocks-stack', values: [rootStack.stackName] }],
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// ── Console redirect routes ───────────────────────────────────────────
|
|
164
|
+
const region = cdk.Fn.ref('AWS::Region');
|
|
165
|
+
const resourcesUrl = cdk.Fn.join('', [
|
|
166
|
+
'https://',
|
|
167
|
+
region,
|
|
168
|
+
'.console.aws.amazon.com/resource-groups/group/',
|
|
169
|
+
`${groupPrefix}-resources`,
|
|
170
|
+
'?region=',
|
|
171
|
+
region,
|
|
172
|
+
]);
|
|
173
|
+
const settingsUrl = cdk.Fn.join('', [
|
|
174
|
+
'https://',
|
|
175
|
+
region,
|
|
176
|
+
'.console.aws.amazon.com/resource-groups/group/',
|
|
177
|
+
`${groupPrefix}-settings`,
|
|
178
|
+
'?region=',
|
|
179
|
+
region,
|
|
180
|
+
]);
|
|
181
|
+
|
|
182
|
+
registerConfig(scope, 'BB_RESOURCES_GROUP_URL', resourcesUrl);
|
|
183
|
+
registerConfig(scope, 'BB_SETTINGS_GROUP_URL', settingsUrl);
|
|
184
|
+
|
|
185
|
+
registerBuiltinRoutes();
|
|
186
|
+
|
|
187
|
+
return { executionRole };
|
|
170
188
|
}
|
|
171
189
|
|
|
172
190
|
/**
|
|
@@ -187,111 +205,165 @@ export function setupBlocksInfra(scope: Construct, props: BlocksBackendProps, id
|
|
|
187
205
|
* ```
|
|
188
206
|
*/
|
|
189
207
|
export class BlocksBackend extends Construct {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
208
|
+
public readonly backendHandlerPath: string;
|
|
209
|
+
/**
|
|
210
|
+
* Path to the app's backend module (`props.backendCDKPath`). Exposed so Building Blocks that
|
|
211
|
+
* co-bundle the backend at synth (e.g. the Agent BB's AgentCore Runtime) can discover it via
|
|
212
|
+
* `globalThis.CURRENT_BLOCKS_STACK.backendModulePath`.
|
|
213
|
+
*/
|
|
214
|
+
public readonly backendModulePath: string;
|
|
215
|
+
/** Shared IAM role assumed by all Blocks compute. Building Blocks grant to this role. */
|
|
216
|
+
public readonly executionRole: iam.IRole;
|
|
217
|
+
/** Infrastructure defaults for Building Blocks created under this backend. */
|
|
218
|
+
public readonly defaults: BlocksDefaults;
|
|
219
|
+
/** The default compute (owns the Lambda function + API Gateway); set in `create()`. @internal */
|
|
220
|
+
_defaultCompute?: Compute;
|
|
221
|
+
|
|
222
|
+
/** The default compute's Lambda function. To be removed once consumers move to the multi-compute model. */
|
|
223
|
+
get handler(): cdk.aws_lambda_nodejs.NodejsFunction {
|
|
224
|
+
return this.requireDefaultCompute().fn;
|
|
225
|
+
}
|
|
226
|
+
/** The default compute's API Gateway REST API. To be removed once consumers move to the multi-compute model. */
|
|
227
|
+
get gateway(): apigateway.RestApi {
|
|
228
|
+
return this.requireDefaultCompute().apiGateway;
|
|
229
|
+
}
|
|
230
|
+
/** The default compute's RPC endpoint URL. To be removed once consumers move to the multi-compute model. */
|
|
231
|
+
get apiUrl(): string {
|
|
232
|
+
return this.requireDefaultCompute().apiUrl;
|
|
233
|
+
}
|
|
234
|
+
/** The default compute's handler CloudWatch log group. Its retention comes from
|
|
235
|
+
* the compute's `logRetention` (falling back to `defaults.logRetention`); the
|
|
236
|
+
* `bb-logger` CDK construct is a no-op and no longer touches it. */
|
|
237
|
+
get handlerLogGroup(): cdk.aws_logs.ILogGroup {
|
|
238
|
+
return this.requireDefaultCompute().logGroup;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private requireDefaultCompute(): LambdaShapedCompute {
|
|
242
|
+
if (!this._defaultCompute) {
|
|
243
|
+
throw new Error(
|
|
244
|
+
'Blocks backend not fully initialized — access .handler/.gateway/.apiUrl after BlocksBackend.create() resolves.',
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
return this._defaultCompute as LambdaShapedCompute;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* The fullId used by child Scopes to compute their env var names,
|
|
252
|
+
* construct IDs, and physical resource names (e.g., DynamoDB table names).
|
|
253
|
+
*
|
|
254
|
+
* Includes the CDK stack name to ensure physical resources are unique
|
|
255
|
+
* per deployment. This matches what the runtime sees via BLOCKS_STACK_NAME.
|
|
256
|
+
*
|
|
257
|
+
* IMPORTANT: this value MUST be token-free. Child Scopes embed `fullId` in
|
|
258
|
+
* CDK construct IDs (e.g. `${fullId}DsqlMigrationFn`), and CDK forbids
|
|
259
|
+
* unresolved tokens in construct IDs ("ID components may not include
|
|
260
|
+
* unresolved tokens"). It is also used to build env-var keys that must match
|
|
261
|
+
* byte-for-byte between synth time and runtime.
|
|
262
|
+
*
|
|
263
|
+
* A nested stack (e.g. Amplify Gen2 `backend.createStack('blocks')`) has a
|
|
264
|
+
* tokenized `stackName` that only resolves at deploy time. We therefore walk
|
|
265
|
+
* up to the top-level stack, whose name is concrete at synth time and still
|
|
266
|
+
* unique per deployment. The `Token.isUnresolved` guard is a defensive
|
|
267
|
+
* fallback to the (token-free) construct id should no resolvable name exist.
|
|
268
|
+
*/
|
|
269
|
+
get fullId(): string {
|
|
270
|
+
let stack = cdk.Stack.of(this);
|
|
271
|
+
while (stack.nestedStackParent) {
|
|
272
|
+
stack = stack.nestedStackParent;
|
|
273
|
+
}
|
|
274
|
+
const stackName = stack.stackName;
|
|
275
|
+
if (cdk.Token.isUnresolved(stackName)) {
|
|
276
|
+
return this.node.id;
|
|
277
|
+
}
|
|
278
|
+
return `${stackName}-${this.node.id}`;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private _vpcOptions?: BlocksVpcOptions;
|
|
282
|
+
|
|
283
|
+
private constructor(scope: Construct, id: string, props: BlocksBackendProps) {
|
|
284
|
+
super(scope, id);
|
|
285
|
+
|
|
286
|
+
this.backendHandlerPath = props.backendHandlerPath;
|
|
287
|
+
this.backendModulePath = props.backendCDKPath;
|
|
288
|
+
this._vpcOptions = props.defaults.vpc;
|
|
289
|
+
|
|
290
|
+
// Expose self to Building Blocks at CDK time
|
|
291
|
+
(globalThis as any).CURRENT_BLOCKS_STACK = this;
|
|
292
|
+
|
|
293
|
+
// Store defaults on the backend (not the stack) so several BlocksBackends
|
|
294
|
+
// in one stack each keep their own posture; Building Blocks resolve them by
|
|
295
|
+
// walking up to their owning backend (see Scope.defaults).
|
|
296
|
+
this.defaults = props.defaults;
|
|
297
|
+
|
|
298
|
+
// Initialize VPC context before the default compute is created and before
|
|
299
|
+
// BBs are constructed, so both can discover it: the default compute
|
|
300
|
+
// (LambdaCompute) reads it via getVpcContext(this) to place its function in
|
|
301
|
+
// the VPC, and BBs (e.g. bb-data) read it to co-locate their resources.
|
|
302
|
+
if (this._vpcOptions) {
|
|
303
|
+
initializeVpc(this, this._vpcOptions);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const infra = setupBlocksInfra(this, props, id);
|
|
307
|
+
this.executionRole = infra.executionRole;
|
|
308
|
+
// The default compute (and thus handler/gateway) is created in create(),
|
|
309
|
+
// after construction — it derives BLOCKS_STACK_NAME from this.fullId.
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
static async create(scope: Construct, id: string, props: CoreBlocksBackendProps) {
|
|
313
|
+
assertCdkConditionActive();
|
|
314
|
+
const backend = new BlocksBackend(scope, id, props);
|
|
315
|
+
// Create the default compute before importing the backend: it OWNS the
|
|
316
|
+
// Lambda function + API Gateway (which back .handler/.gateway/.apiUrl), and
|
|
317
|
+
// a block reading `this.compute` in its constructor (during that import)
|
|
318
|
+
// must resolve to it. The factory is supplied by the umbrella
|
|
319
|
+
// @aws-blocks/blocks (which injects LambdaCompute) via props, so core never
|
|
320
|
+
// imports the concrete compute class.
|
|
321
|
+
backend._defaultCompute = props.defaultComputeFactory(backend);
|
|
322
|
+
// file:// URL (not a raw path) so the cache-busting query works on Windows,
|
|
323
|
+
// where an absolute path like `D:\...` is rejected as URL scheme `d:`.
|
|
324
|
+
const backendUrl = pathToFileURL(props.backendCDKPath);
|
|
325
|
+
backendUrl.searchParams.set('stack', id);
|
|
326
|
+
const mod = await import(backendUrl.href);
|
|
327
|
+
if (typeof mod.default === 'function') {
|
|
328
|
+
try {
|
|
329
|
+
await mod.default(backend);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
throw new Error(
|
|
332
|
+
`Error executing default export function for backend "${id}": ${error instanceof Error ? error.message : error}`,
|
|
333
|
+
{ cause: error },
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
addBlocksStackMetadata(cdk.Stack.of(backend));
|
|
338
|
+
|
|
339
|
+
// Finalize BB config → S3 (after all BBs have registered their config)
|
|
340
|
+
finalizeConfigRegistry(backend, backend.executionRole, getComputes(backend));
|
|
341
|
+
|
|
342
|
+
// Tracing is presence-gated: if the app contains a Tracer, enable X-Ray on
|
|
343
|
+
// every compute. Runs before the dashboard finalize.
|
|
344
|
+
finalizeTracing(backend, backend.executionRole);
|
|
345
|
+
|
|
346
|
+
// Build any deferred Dashboards now that every compute's observability
|
|
347
|
+
// state is settled — so the dashboard is order-independent.
|
|
348
|
+
finalizeDashboards(backend);
|
|
349
|
+
|
|
350
|
+
// Finalize VPC. Derived resource: use the customer's if provided, else
|
|
351
|
+
// lazily create one only if a Building Block requires it.
|
|
352
|
+
if (backend._vpcOptions) {
|
|
353
|
+
finalizeVpc(backend, backend._vpcOptions);
|
|
354
|
+
} else if (anyRequirementNeedsVpc(backend)) {
|
|
355
|
+
const derived = getOrCreateVpc(backend);
|
|
356
|
+
const options = { network: derived };
|
|
357
|
+
initializeVpc(backend, options);
|
|
358
|
+
finalizeVpc(backend, options);
|
|
359
|
+
cdk.Annotations.of(backend).addInfoV2(
|
|
360
|
+
'blocks:vpc:derived',
|
|
361
|
+
'A Building Block required a VPC and none was provided, so Blocks created one ' +
|
|
362
|
+
'(with a NAT gateway, which has an ongoing cost). Pass `defaults.vpc: { network }` to ' +
|
|
363
|
+
'bring your own. See packages/blocks/VPC.md.',
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return backend;
|
|
368
|
+
}
|
|
297
369
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { test, describe } from 'node:test';
|
|
11
11
|
import assert from 'node:assert';
|
|
12
12
|
import { RemovalPolicy } from 'aws-cdk-lib';
|
|
13
|
+
import { RetentionDays } from 'aws-cdk-lib/aws-logs';
|
|
13
14
|
import { BlocksPresets } from './blocks-defaults.js';
|
|
14
15
|
|
|
15
16
|
describe('BlocksPresets', () => {
|
|
@@ -24,4 +25,24 @@ describe('BlocksPresets', () => {
|
|
|
24
25
|
assert.strictEqual(BlocksPresets.production.deletionProtection, true);
|
|
25
26
|
assert.strictEqual(BlocksPresets.production.pointInTimeRecovery, true);
|
|
26
27
|
});
|
|
28
|
+
|
|
29
|
+
test('sandbox keeps logs briefly', () => {
|
|
30
|
+
assert.strictEqual(BlocksPresets.sandbox.logRetention, RetentionDays.ONE_WEEK);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('production keeps logs a year', () => {
|
|
34
|
+
assert.strictEqual(BlocksPresets.production.logRetention, RetentionDays.ONE_YEAR);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('access logging is off by default in BOTH presets (opt-in; mutates an account singleton)', () => {
|
|
38
|
+
assert.strictEqual(BlocksPresets.sandbox.accessLogging, false);
|
|
39
|
+
assert.strictEqual(BlocksPresets.production.accessLogging, false);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('sandbox caps tighter (200/400) than production (1000/2000)', () => {
|
|
43
|
+
assert.strictEqual(BlocksPresets.sandbox.throttling.rateLimit, 200);
|
|
44
|
+
assert.strictEqual(BlocksPresets.sandbox.throttling.burstLimit, 400);
|
|
45
|
+
assert.strictEqual(BlocksPresets.production.throttling.rateLimit, 1000);
|
|
46
|
+
assert.strictEqual(BlocksPresets.production.throttling.burstLimit, 2000);
|
|
47
|
+
});
|
|
27
48
|
});
|