@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
package/src/cdk/index.ts
CHANGED
|
@@ -1,41 +1,53 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
import * as cdk from 'aws-cdk-lib';
|
|
5
|
-
import { Construct } from 'constructs';
|
|
6
4
|
import { pathToFileURL } from 'node:url';
|
|
7
5
|
import { __PIPELINE_STAGE_SCOPE__ } from '@aws-blocks/pipeline';
|
|
6
|
+
import * as cdk from 'aws-cdk-lib';
|
|
7
|
+
import { Construct } from 'constructs';
|
|
8
8
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
type BlocksStack as BaseBlocksStack,
|
|
10
|
+
type BlocksStackProps,
|
|
11
|
+
computeScopeFullId,
|
|
12
|
+
type ScopeOptions,
|
|
13
|
+
type ScopeParent,
|
|
14
14
|
} from '../common/index.js';
|
|
15
|
-
import {
|
|
16
|
-
import { addBlocksStackMetadata } from './stack-metadata.js';
|
|
17
|
-
import { finalizeConfigRegistry } from './config-registry.js';
|
|
15
|
+
import { assertCdkConditionActive, BlocksBackend, setupBlocksInfra } from './blocks-backend.js';
|
|
18
16
|
import { type BlocksDefaults, BlocksPresets } from './blocks-defaults.js';
|
|
19
17
|
import type { Compute } from './compute/compute.js';
|
|
18
|
+
import { getComputes } from './compute/compute-registry.js';
|
|
20
19
|
import type { DefaultComputeFactory, LambdaShapedCompute } from './compute/default-compute-factory.js';
|
|
20
|
+
import { finalizeConfigRegistry } from './config-registry.js';
|
|
21
|
+
import { finalizeDashboards } from './dashboard-registry.js';
|
|
22
|
+
import { addBlocksStackMetadata } from './stack-metadata.js';
|
|
23
|
+
import { finalizeTracing } from './tracer-registry.js';
|
|
24
|
+
import { anyRequirementNeedsVpc, finalizeVpc, getOrCreateVpc, initializeVpc } from './vpc.js';
|
|
25
|
+
import { registerVpcRequirements } from './vpc-requirements-registry.js';
|
|
26
|
+
import type { BlocksVpcOptions, VpcRequirements } from './vpc-types.js';
|
|
21
27
|
|
|
28
|
+
export { ApiError, DEFAULT_API_ERROR_NAME, hasAuthError, isBlocksError } from '../errors.js';
|
|
29
|
+
export type { ScopeOptions } from '../index.js';
|
|
30
|
+
export { ensureApiGatewayAccount } from './apigateway-account.js';
|
|
22
31
|
export {
|
|
23
32
|
BlocksBackend,
|
|
24
33
|
type BlocksBackendProps,
|
|
25
34
|
type CoreBlocksBackendProps,
|
|
26
35
|
SHARED_HANDLER_TIMEOUT_SECONDS,
|
|
27
36
|
} from './blocks-backend.js';
|
|
28
|
-
export { DEFAULT_NODE_RUNTIME } from './node-version.js';
|
|
29
|
-
export { blocksNodejsBundling } from './bundling.js';
|
|
30
|
-
export { SandboxDisableDeletionProtection } from './mixins.js';
|
|
31
|
-
export { registerConfig, finalizeConfigRegistry } from './config-registry.js';
|
|
32
37
|
export {
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
type BlocksDefaults,
|
|
39
|
+
BlocksPresets,
|
|
40
|
+
type BlocksThrottling,
|
|
35
41
|
} from './blocks-defaults.js';
|
|
42
|
+
export { blocksNodejsBundling } from './bundling.js';
|
|
43
|
+
export { finalizeConfigRegistry, getConfigLocation, registerConfig } from './config-registry.js';
|
|
44
|
+
export { finalizeDashboards, registerDashboardFinalizer } from './dashboard-registry.js';
|
|
45
|
+
export { SandboxDisableDeletionProtection } from './mixins.js';
|
|
46
|
+
export { DEFAULT_NODE_RUNTIME } from './node-version.js';
|
|
36
47
|
export { synthGuard } from './synth-guard.js';
|
|
37
|
-
export
|
|
38
|
-
export {
|
|
48
|
+
export { finalizeTracing, registerTracer } from './tracer-registry.js';
|
|
49
|
+
export { getVpcContext } from './vpc.js';
|
|
50
|
+
export type { BlocksVpcOptions, SubnetRole, VpcContext, VpcRequirements } from './vpc-types.js';
|
|
39
51
|
|
|
40
52
|
/**
|
|
41
53
|
* Core's `create()` props: the public {@link BlocksStackProps} plus the required
|
|
@@ -49,248 +61,407 @@ export { ApiError, isBlocksError, hasAuthError, DEFAULT_API_ERROR_NAME } from '.
|
|
|
49
61
|
* @internal
|
|
50
62
|
*/
|
|
51
63
|
export interface CoreBlocksStackProps extends BlocksStackProps {
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
/** Builds the stack's default compute. Injected by `@aws-blocks/blocks`. */
|
|
65
|
+
defaultComputeFactory: DefaultComputeFactory;
|
|
54
66
|
}
|
|
55
67
|
|
|
56
68
|
export class BlocksStack extends cdk.Stack implements BaseBlocksStack {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
69
|
+
public readonly id: string;
|
|
70
|
+
public readonly backendHandlerPath: string;
|
|
71
|
+
/**
|
|
72
|
+
* Path to the app's backend module (`props.backendCDKPath`). Exposed so Building Blocks that
|
|
73
|
+
* co-bundle the backend at synth (e.g. the Agent BB's AgentCore Runtime) can discover it via
|
|
74
|
+
* `globalThis.CURRENT_BLOCKS_STACK.backendModulePath`.
|
|
75
|
+
*/
|
|
76
|
+
public readonly backendModulePath: string;
|
|
77
|
+
/** Shared IAM role assumed by all Blocks compute. Building Blocks grant to this role. */
|
|
78
|
+
public readonly executionRole: cdk.aws_iam.IRole;
|
|
79
|
+
/** Infrastructure defaults for Building Blocks created under this stack. */
|
|
80
|
+
public readonly defaults: BlocksDefaults;
|
|
81
|
+
/** The default compute (owns the Lambda function + API Gateway); set in `create()`. @internal */
|
|
82
|
+
_defaultCompute?: Compute;
|
|
83
|
+
|
|
84
|
+
/** The default compute's Lambda function. To be removed once consumers move to the multi-compute model. */
|
|
85
|
+
get handler(): cdk.aws_lambda_nodejs.NodejsFunction {
|
|
86
|
+
return this.requireDefaultCompute().fn;
|
|
87
|
+
}
|
|
88
|
+
/** The default compute's API Gateway REST API. To be removed once consumers move to the multi-compute model. */
|
|
89
|
+
get gateway(): cdk.aws_apigateway.RestApi {
|
|
90
|
+
return this.requireDefaultCompute().apiGateway;
|
|
91
|
+
}
|
|
92
|
+
/** The default compute's RPC endpoint URL. To be removed once consumers move to the multi-compute model. */
|
|
93
|
+
get apiUrl(): string {
|
|
94
|
+
return this.requireDefaultCompute().apiUrl;
|
|
95
|
+
}
|
|
96
|
+
/** The default compute's handler CloudWatch log group. Its retention comes from
|
|
97
|
+
* the compute's `logRetention` (falling back to `defaults.logRetention`); the
|
|
98
|
+
* `bb-logger` CDK construct is a no-op and no longer touches it. */
|
|
99
|
+
get handlerLogGroup(): cdk.aws_logs.ILogGroup {
|
|
100
|
+
return this.requireDefaultCompute().logGroup;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private requireDefaultCompute(): LambdaShapedCompute {
|
|
104
|
+
if (!this._defaultCompute) {
|
|
105
|
+
throw new Error(
|
|
106
|
+
'Blocks stack not fully initialized — access .handler/.gateway/.apiUrl after BlocksStack.create() resolves.',
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
return this._defaultCompute as LambdaShapedCompute;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private _vpcOptions?: BlocksVpcOptions;
|
|
113
|
+
|
|
114
|
+
private constructor(scope: Construct, id: string, props: BlocksStackProps) {
|
|
115
|
+
super(scope, id, props);
|
|
116
|
+
this.id = id;
|
|
117
|
+
this.backendHandlerPath = props.backendHandlerPath;
|
|
118
|
+
this.backendModulePath = props.backendCDKPath;
|
|
119
|
+
this.defaults = props.defaults;
|
|
120
|
+
this._vpcOptions = props.defaults.vpc;
|
|
121
|
+
|
|
122
|
+
// Set globalThis so Building Blocks attach directly to this stack
|
|
123
|
+
(globalThis as any).CURRENT_BLOCKS_STACK = this;
|
|
124
|
+
|
|
125
|
+
// Initialize VPC context before the default compute is created and before
|
|
126
|
+
// BBs are constructed, so both can discover it: the default compute
|
|
127
|
+
// (LambdaCompute) reads it via getVpcContext(this) to place its function in
|
|
128
|
+
// the VPC, and BBs (e.g. bb-data) read it to co-locate their resources.
|
|
129
|
+
if (this._vpcOptions) {
|
|
130
|
+
initializeVpc(this, this._vpcOptions);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const infra = setupBlocksInfra(this, props, id);
|
|
134
|
+
this.executionRole = infra.executionRole;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static async create(scope: Construct, id: string, props: CoreBlocksStackProps) {
|
|
138
|
+
assertCdkConditionActive();
|
|
139
|
+
|
|
140
|
+
// Detect ambient pipeline stage scope set by Pipeline appFile imports
|
|
141
|
+
const pipelineScope = (globalThis as any)[__PIPELINE_STAGE_SCOPE__];
|
|
142
|
+
const actualScope = pipelineScope || scope;
|
|
143
|
+
|
|
144
|
+
const stack = new BlocksStack(actualScope, id, props);
|
|
145
|
+
// Create the default compute before importing the backend: it OWNS the
|
|
146
|
+
// Lambda function + API Gateway (which back .handler/.gateway/.apiUrl), and
|
|
147
|
+
// a block reading `this.compute` in its constructor (during that import)
|
|
148
|
+
// must resolve to it. The factory is supplied by the umbrella
|
|
149
|
+
// @aws-blocks/blocks (which injects LambdaCompute) via props, so core never
|
|
150
|
+
// imports the concrete compute class.
|
|
151
|
+
stack._defaultCompute = props.defaultComputeFactory(stack);
|
|
152
|
+
// file:// URL (not a raw path) so the cache-busting query works on Windows,
|
|
153
|
+
// where an absolute path like `D:\...` is rejected as URL scheme `d:`.
|
|
154
|
+
const backendUrl = pathToFileURL(props.backendCDKPath);
|
|
155
|
+
backendUrl.searchParams.set('stack', id);
|
|
156
|
+
const mod = await import(backendUrl.href);
|
|
157
|
+
if (typeof mod.default === 'function') {
|
|
158
|
+
try {
|
|
159
|
+
await mod.default(stack);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
`Error executing default export function for stack "${id}": ${error instanceof Error ? error.message : error}`,
|
|
163
|
+
{ cause: error },
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Finalize BB config → S3 (after all BBs have registered their config)
|
|
168
|
+
finalizeConfigRegistry(stack, stack.executionRole, getComputes(stack));
|
|
169
|
+
|
|
170
|
+
// Tracing is presence-gated: if the app contains a Tracer, enable X-Ray on
|
|
171
|
+
// every compute. Runs before the dashboard finalize so tracingEnabled is
|
|
172
|
+
// set when the dashboard reads it.
|
|
173
|
+
finalizeTracing(stack, stack.executionRole);
|
|
174
|
+
|
|
175
|
+
// Build any deferred Dashboards now that every compute's observability
|
|
176
|
+
// state is settled — so the dashboard is order-independent.
|
|
177
|
+
finalizeDashboards(stack);
|
|
178
|
+
|
|
179
|
+
// Finalize VPC. A VPC is a derived resource: use the customer's if they
|
|
180
|
+
// brought one, else lazily create one only if a Building Block genuinely
|
|
181
|
+
// requires it (requiresVpc). Most apps need neither — Lambda reaches AWS
|
|
182
|
+
// services from the managed network without a VPC.
|
|
183
|
+
if (stack._vpcOptions) {
|
|
184
|
+
finalizeVpc(stack, stack._vpcOptions);
|
|
185
|
+
} else if (anyRequirementNeedsVpc(stack)) {
|
|
186
|
+
const derived = getOrCreateVpc(stack);
|
|
187
|
+
const options = { network: derived };
|
|
188
|
+
initializeVpc(stack, options);
|
|
189
|
+
finalizeVpc(stack, options);
|
|
190
|
+
cdk.Annotations.of(stack).addInfoV2(
|
|
191
|
+
'blocks:vpc:derived',
|
|
192
|
+
'A Building Block required a VPC and none was provided, so Blocks created one ' +
|
|
193
|
+
'(with a NAT gateway, which has an ongoing cost). Pass `defaults.vpc: { network }` to ' +
|
|
194
|
+
'BlocksStack.create to bring your own. See packages/blocks/VPC.md.',
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
new cdk.CfnOutput(stack, 'ApiUrl', { value: stack.apiUrl });
|
|
199
|
+
|
|
200
|
+
addBlocksStackMetadata(stack);
|
|
201
|
+
|
|
202
|
+
return stack;
|
|
203
|
+
}
|
|
135
204
|
}
|
|
136
205
|
|
|
137
206
|
export class Scope extends Construct {
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
|
-
|
|
207
|
+
public readonly id: string;
|
|
208
|
+
public readonly parent: ScopeParent;
|
|
209
|
+
|
|
210
|
+
readonly bbName?: string;
|
|
211
|
+
readonly bbVersion?: string;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* The owning stack/backend (the root of the Blocks construct tree), resolved
|
|
215
|
+
* once at construction: the nearest BlocksStack/BlocksBackend up the construct
|
|
216
|
+
* tree, or the ambient `globalThis.CURRENT_BLOCKS_STACK` fallback. All
|
|
217
|
+
* root-derived accessors below read from this instead of each repeating the
|
|
218
|
+
* tree walk.
|
|
219
|
+
*/
|
|
220
|
+
private readonly root: BlocksStack | BlocksBackend;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Compute assigned at this node. Applies to this block and is inherited by
|
|
224
|
+
* descendants (a nearer assignment wins). Covers both a handler assigned to a
|
|
225
|
+
* specific compute and a scope-level default for its subtree. Internal until
|
|
226
|
+
* the customer-facing surface exists.
|
|
227
|
+
* @internal
|
|
228
|
+
*/
|
|
229
|
+
_compute?: Compute;
|
|
230
|
+
|
|
231
|
+
constructor(id: string, options?: ScopeOptions) {
|
|
232
|
+
const parent = options?.parent || (globalThis as any).CURRENT_BLOCKS_STACK;
|
|
233
|
+
super(parent, id);
|
|
234
|
+
this.id = id;
|
|
235
|
+
this.parent = parent;
|
|
236
|
+
this.root = this.resolveRoot();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Walk up the construct tree to the nearest owning BlocksStack/BlocksBackend;
|
|
241
|
+
* fall back to the ambient `globalThis.CURRENT_BLOCKS_STACK`. Called once from
|
|
242
|
+
* the constructor; the result is cached in {@link root}.
|
|
243
|
+
*/
|
|
244
|
+
private resolveRoot(): BlocksStack | BlocksBackend {
|
|
245
|
+
let current: Construct = this;
|
|
246
|
+
while (current.node.scope) {
|
|
247
|
+
current = current.node.scope as Construct;
|
|
248
|
+
if (current instanceof BlocksStack || current instanceof BlocksBackend) {
|
|
249
|
+
return current;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// Fallback to the ambient stack. In production this is always a real
|
|
253
|
+
// BlocksStack/BlocksBackend; the cast also admits the test doubles that set
|
|
254
|
+
// globalThis.CURRENT_BLOCKS_STACK to a stub exposing the same surface.
|
|
255
|
+
return (globalThis as any).CURRENT_BLOCKS_STACK as BlocksStack | BlocksBackend;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
get handler() {
|
|
259
|
+
return this.root.handler;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* The shared IAM role assumed by all Blocks compute. Building Blocks grant
|
|
264
|
+
* their permissions to this role; CDK's `grant*()` / `addToPrincipalPolicy()`
|
|
265
|
+
* route those grants to the role's default (inline) policy.
|
|
266
|
+
*/
|
|
267
|
+
get executionRole(): cdk.aws_iam.IRole {
|
|
268
|
+
return this.root.executionRole;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* The compute this block runs on: the nearest `_compute` assigned on this
|
|
273
|
+
* block or an ancestor scope, else the owning stack/backend's default compute.
|
|
274
|
+
*
|
|
275
|
+
* For any app that doesn't assign a compute, this always resolves to the
|
|
276
|
+
* default — so reads are a no-op refactor. `_compute` is internal
|
|
277
|
+
* (test/framework) until the customer-facing surface exists; there is no
|
|
278
|
+
* public option to set it yet.
|
|
279
|
+
*/
|
|
280
|
+
get compute(): Compute {
|
|
281
|
+
for (let current: ScopeParent | undefined = this; current; current = (current as Scope).parent) {
|
|
282
|
+
const assigned = (current as Scope)._compute;
|
|
283
|
+
if (assigned) return assigned;
|
|
284
|
+
}
|
|
285
|
+
const defaultCompute = this.root._defaultCompute;
|
|
286
|
+
if (!defaultCompute) {
|
|
287
|
+
throw new Error(
|
|
288
|
+
'Default compute not initialized — BlocksStack/BlocksBackend.create() must run before resolving `compute`.',
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
return defaultCompute;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* The stack's default compute, **ignoring** any per-scope `_compute`
|
|
296
|
+
* assignment (unlike {@link compute}, which resolves the nearest assigned
|
|
297
|
+
* one). Use when a resource is a stack-level singleton that must bind to one
|
|
298
|
+
* deterministic compute regardless of the block's resolved compute — e.g.
|
|
299
|
+
* Realtime's shared WebSocket route integration, where one WebSocket API
|
|
300
|
+
* integrates to a single target and connection bookkeeping is compute-agnostic.
|
|
301
|
+
*
|
|
302
|
+
* @internal Not a customer surface; for framework/BB singleton infra only.
|
|
303
|
+
*/
|
|
304
|
+
get defaultCompute(): Compute {
|
|
305
|
+
const defaultCompute = this.root._defaultCompute;
|
|
306
|
+
if (!defaultCompute) {
|
|
307
|
+
throw new Error(
|
|
308
|
+
'Default compute not initialized — BlocksStack/BlocksBackend.create() must run before resolving `defaultCompute`.',
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
return defaultCompute;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* The backend entry file the owning BlocksStack/BlocksBackend runs — the
|
|
316
|
+
* single handler entry shared across the whole app.
|
|
317
|
+
*/
|
|
318
|
+
get backendHandlerPath(): string {
|
|
319
|
+
return this.root.backendHandlerPath;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* The owning stack/backend's token-free root identity. This is the value the
|
|
324
|
+
* runtime receives as `BLOCKS_STACK_NAME` and rebuilds `fullId` from, so
|
|
325
|
+
* physical resource names (DynamoDB tables, env-var keys, IAM ARNs) derived
|
|
326
|
+
* from `fullId` match byte-for-byte between synth and runtime — otherwise the
|
|
327
|
+
* runtime looks up names that were never created. `BlocksBackend` exposes this
|
|
328
|
+
* as `fullId` ({@link BlocksBackend.fullId}); `BlocksStack` as `id`.
|
|
329
|
+
*/
|
|
330
|
+
get backendStackName(): string {
|
|
331
|
+
const name = this.root instanceof BlocksBackend ? this.root.fullId : this.root.id;
|
|
332
|
+
if (!name) {
|
|
333
|
+
throw new Error('Owning Blocks stack/backend has no id to derive BLOCKS_STACK_NAME');
|
|
334
|
+
}
|
|
335
|
+
return name;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* The shared handler Lambda's CloudWatch log group (the default compute's).
|
|
340
|
+
* Resolves the same way as {@link handler} — via the owning
|
|
341
|
+
* BlocksStack/BlocksBackend. Its retention comes from the compute's
|
|
342
|
+
* `logRetention` (falling back to `defaults.logRetention`); the `bb-logger`
|
|
343
|
+
* CDK construct is a no-op and no longer reconfigures it.
|
|
344
|
+
*/
|
|
345
|
+
get handlerLogGroup(): cdk.aws_logs.ILogGroup {
|
|
346
|
+
return this.root.handlerLogGroup;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
get fullId(): string {
|
|
350
|
+
return computeScopeFullId(this);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* The stack-wide infrastructure {@link BlocksDefaults} registered by
|
|
355
|
+
* `BlocksStack.create` / `BlocksBackend.create`. Read these in a Building
|
|
356
|
+
* Block's CDK constructor to resolve a durability value, letting a per-block
|
|
357
|
+
* option override:
|
|
358
|
+
*
|
|
359
|
+
* ```ts
|
|
360
|
+
* const removalPolicy = options?.removalPolicy ?? this.defaults.removalPolicy;
|
|
361
|
+
* ```
|
|
362
|
+
*/
|
|
363
|
+
get defaults(): BlocksDefaults {
|
|
364
|
+
// Resolve the same way as handler/executionRole: walk up to the owning
|
|
365
|
+
// BlocksStack/BlocksBackend and read its defaults, so several backends in
|
|
366
|
+
// one stack each keep their own posture. Falls back to the ambient stack,
|
|
367
|
+
// then to the production preset when none was registered.
|
|
368
|
+
let current: Construct = this;
|
|
369
|
+
while (current.node.scope) {
|
|
370
|
+
current = current.node.scope as Construct;
|
|
371
|
+
if (current instanceof BlocksStack || current instanceof BlocksBackend) {
|
|
372
|
+
return current.defaults;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
const ambient = ((globalThis as any).CURRENT_BLOCKS_STACK as { defaults?: BlocksDefaults } | undefined)
|
|
376
|
+
?.defaults;
|
|
377
|
+
if (ambient) return ambient;
|
|
378
|
+
// No owning BlocksStack/BlocksBackend in the tree and none ambient — this is
|
|
379
|
+
// usually a deliberate test stub, but could be a real misconfiguration (a
|
|
380
|
+
// block built outside any Blocks backend). Fall back to the safe production
|
|
381
|
+
// posture, and log so it's debuggable if it fires unexpectedly.
|
|
382
|
+
console.warn(
|
|
383
|
+
`[Blocks] Scope "${this.id}" resolved infrastructure defaults with no owning ` +
|
|
384
|
+
'BlocksStack/BlocksBackend in scope; falling back to BlocksPresets.production.',
|
|
385
|
+
);
|
|
386
|
+
return BlocksPresets.production;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
protected buildUserAgentChain(): [string, string][] {
|
|
390
|
+
return [];
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Plugin registration — no-ops in CDK context (plugins are only used at dev/build time)
|
|
394
|
+
registerClientMiddleware(_packageSpecifier: string): void {}
|
|
395
|
+
registerDevAttachment(_packageSpecifier: string): void {}
|
|
396
|
+
registerLambdaEventHandler(
|
|
397
|
+
_eventSource: string,
|
|
398
|
+
_identifier: string,
|
|
399
|
+
_handler: (record: any) => Promise<void>,
|
|
400
|
+
): void {}
|
|
401
|
+
get clientMiddleware(): readonly string[] {
|
|
402
|
+
return [];
|
|
403
|
+
}
|
|
404
|
+
get devAttachments(): readonly string[] {
|
|
405
|
+
return [];
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* A VPC-requirements provider: either the requirements directly, or a callback
|
|
411
|
+
* that returns them. Use the callback form when the value depends on `fullId`
|
|
412
|
+
* or other post-construction state — it is evaluated by the base constructor
|
|
413
|
+
* *after* `super()` runs, so `this` is fully available.
|
|
414
|
+
*/
|
|
415
|
+
export type VpcRequirementsProvider = VpcRequirements | (() => VpcRequirements);
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Constructor options for a {@link BuildingBlockScope} — the {@link ScopeOptions}
|
|
419
|
+
* every Scope takes, plus the block's VPC requirements. `vpc` is **required** so
|
|
420
|
+
* a BB author can't silently omit it; pass `{}` when the block needs nothing
|
|
421
|
+
* VPC-specific.
|
|
422
|
+
*/
|
|
423
|
+
export interface BuildingBlockScopeOptions extends ScopeOptions {
|
|
424
|
+
/**
|
|
425
|
+
* What this block needs from the VPC — endpoints, runtime egress, whether it
|
|
426
|
+
* requires a VPC at all. A value, or a callback (evaluated after `super()`,
|
|
427
|
+
* so it may read `this.fullId`). See {@link VpcRequirements}.
|
|
428
|
+
*/
|
|
429
|
+
vpc: VpcRequirementsProvider;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Base class for Building Block CDK constructs.
|
|
434
|
+
*
|
|
435
|
+
* BBs extend this instead of `Scope` directly and **must** declare their VPC
|
|
436
|
+
* requirements as a constructor argument — the base registers them centrally
|
|
437
|
+
* (see `vpc-requirements-registry.ts`) so `finalizeVpc` can pull, deduplicate,
|
|
438
|
+
* and provision endpoints, and so the lazy VPC can answer "does anything here
|
|
439
|
+
* need a VPC?". Passing the requirements is required by the constructor
|
|
440
|
+
* signature, so a BB author cannot silently forget to declare them — the same
|
|
441
|
+
* forcing the previous `abstract getVpcRequirements()` gave, but without a
|
|
442
|
+
* standing method on every subclass.
|
|
443
|
+
*
|
|
444
|
+
* Declare `{}` when the BB needs nothing VPC-specific.
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* ```ts
|
|
448
|
+
* export class KVStore extends BuildingBlockScope {
|
|
449
|
+
* constructor(scope: ScopeParent, id: string) {
|
|
450
|
+
* super(id, { parent: scope, vpc: { gatewayEndpoints: [ec2.GatewayVpcEndpointAwsService.DYNAMODB] } });
|
|
451
|
+
* // …
|
|
452
|
+
* }
|
|
453
|
+
* }
|
|
454
|
+
* ```
|
|
455
|
+
*/
|
|
456
|
+
export class BuildingBlockScope extends Scope {
|
|
457
|
+
constructor(id: string, options: BuildingBlockScopeOptions) {
|
|
458
|
+
const { vpc, ...scopeOptions } = options;
|
|
459
|
+
super(id, scopeOptions);
|
|
460
|
+
// Resolve the provider (callback form is evaluated here, after super(), so
|
|
461
|
+
// values that depend on this.fullId are available) and self-register on the
|
|
462
|
+
// owning stack. Register even when empty so the registry is a faithful
|
|
463
|
+
// census of every BB — the lazy VPC and finalizeVpc both rely on that.
|
|
464
|
+
const requirements = typeof vpc === 'function' ? vpc() : vpc;
|
|
465
|
+
registerVpcRequirements(this, requirements);
|
|
466
|
+
}
|
|
296
467
|
}
|