@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.
Files changed (147) hide show
  1. package/README.md +25 -0
  2. package/dist/api.d.ts.map +1 -1
  3. package/dist/api.js +32 -0
  4. package/dist/api.test.js +22 -0
  5. package/dist/bb-utils.d.ts +1 -0
  6. package/dist/bb-utils.d.ts.map +1 -1
  7. package/dist/bb-utils.js +3 -0
  8. package/dist/cdk/apigateway-account.d.ts +33 -0
  9. package/dist/cdk/apigateway-account.d.ts.map +1 -0
  10. package/dist/cdk/apigateway-account.js +60 -0
  11. package/dist/cdk/blocks-backend.d.ts +11 -0
  12. package/dist/cdk/blocks-backend.d.ts.map +1 -1
  13. package/dist/cdk/blocks-backend.js +72 -13
  14. package/dist/cdk/blocks-backend.test.js +88 -1
  15. package/dist/cdk/blocks-defaults.d.ts +76 -1
  16. package/dist/cdk/blocks-defaults.d.ts.map +1 -1
  17. package/dist/cdk/blocks-defaults.js +17 -1
  18. package/dist/cdk/blocks-defaults.test.js +17 -0
  19. package/dist/cdk/blocks-stack.test.js +44 -3
  20. package/dist/cdk/compute/compute-registry.d.ts +19 -0
  21. package/dist/cdk/compute/compute-registry.d.ts.map +1 -0
  22. package/dist/cdk/compute/compute-registry.js +38 -0
  23. package/dist/cdk/compute/compute.d.ts +82 -2
  24. package/dist/cdk/compute/compute.d.ts.map +1 -1
  25. package/dist/cdk/compute/compute.js +64 -2
  26. package/dist/cdk/compute/default-compute-factory.d.ts +1 -0
  27. package/dist/cdk/compute/default-compute-factory.d.ts.map +1 -1
  28. package/dist/cdk/config-registry.d.ts +34 -4
  29. package/dist/cdk/config-registry.d.ts.map +1 -1
  30. package/dist/cdk/config-registry.js +83 -25
  31. package/dist/cdk/config-registry.test.d.ts +2 -0
  32. package/dist/cdk/config-registry.test.d.ts.map +1 -0
  33. package/dist/cdk/config-registry.test.js +127 -0
  34. package/dist/cdk/dashboard-registry.d.ts +41 -0
  35. package/dist/cdk/dashboard-registry.d.ts.map +1 -0
  36. package/dist/cdk/dashboard-registry.js +61 -0
  37. package/dist/cdk/index.d.ts +90 -6
  38. package/dist/cdk/index.d.ts.map +1 -1
  39. package/dist/cdk/index.js +135 -13
  40. package/dist/cdk/internal.d.ts +3 -1
  41. package/dist/cdk/internal.d.ts.map +1 -1
  42. package/dist/cdk/internal.js +4 -1
  43. package/dist/cdk/tracer-registry.d.ts +31 -0
  44. package/dist/cdk/tracer-registry.d.ts.map +1 -0
  45. package/dist/cdk/tracer-registry.js +49 -0
  46. package/dist/cdk/vpc-requirements-registry.d.ts +33 -0
  47. package/dist/cdk/vpc-requirements-registry.d.ts.map +1 -0
  48. package/dist/cdk/vpc-requirements-registry.js +46 -0
  49. package/dist/cdk/vpc-types.d.ts +151 -0
  50. package/dist/cdk/vpc-types.d.ts.map +1 -0
  51. package/dist/cdk/vpc-types.js +3 -0
  52. package/dist/cdk/vpc.d.ts +59 -0
  53. package/dist/cdk/vpc.d.ts.map +1 -0
  54. package/dist/cdk/vpc.js +298 -0
  55. package/dist/cdk/vpc.test.d.ts +2 -0
  56. package/dist/cdk/vpc.test.d.ts.map +1 -0
  57. package/dist/cdk/vpc.test.js +285 -0
  58. package/dist/client/index.d.ts +1 -1
  59. package/dist/client/index.d.ts.map +1 -1
  60. package/dist/client/index.js +1 -1
  61. package/dist/common/config.d.ts +34 -0
  62. package/dist/common/config.d.ts.map +1 -1
  63. package/dist/common/config.js +45 -3
  64. package/dist/common/config.test.js +19 -0
  65. package/dist/common/index.d.ts +8 -0
  66. package/dist/common/index.d.ts.map +1 -1
  67. package/dist/errors.d.ts +21 -0
  68. package/dist/errors.d.ts.map +1 -1
  69. package/dist/errors.js +25 -0
  70. package/dist/hosting.d.ts +9 -0
  71. package/dist/hosting.d.ts.map +1 -1
  72. package/dist/hosting.js +12 -1
  73. package/dist/hosting.test.js +63 -1
  74. package/dist/index.cdk.d.ts +3 -2
  75. package/dist/index.cdk.d.ts.map +1 -1
  76. package/dist/index.cdk.js +2 -2
  77. package/dist/index.d.ts +1 -1
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +1 -1
  80. package/dist/lambda-handler.d.ts +17 -0
  81. package/dist/lambda-handler.d.ts.map +1 -1
  82. package/dist/lambda-handler.js +61 -5
  83. package/dist/lambda-handler.test.js +191 -2
  84. package/dist/raw-route.d.ts +15 -1
  85. package/dist/raw-route.d.ts.map +1 -1
  86. package/dist/raw-route.js +96 -12
  87. package/dist/raw-route.test.js +332 -1
  88. package/dist/scripts/dev-server.d.ts.map +1 -1
  89. package/dist/scripts/dev-server.js +11 -0
  90. package/dist/scripts/extract-ts-types.d.ts.map +1 -1
  91. package/dist/scripts/extract-ts-types.js +107 -23
  92. package/dist/scripts/extract-ts-types.test.js +225 -26
  93. package/dist/scripts/generate-spec.d.ts.map +1 -1
  94. package/dist/scripts/generate-spec.js +14 -5
  95. package/dist/scripts/generate-spec.test.js +93 -0
  96. package/dist/scripts/sandbox-empty-buckets.test.d.ts +2 -0
  97. package/dist/scripts/sandbox-empty-buckets.test.d.ts.map +1 -0
  98. package/dist/scripts/sandbox-empty-buckets.test.js +171 -0
  99. package/dist/scripts/sandbox.d.ts +54 -0
  100. package/dist/scripts/sandbox.d.ts.map +1 -1
  101. package/dist/scripts/sandbox.js +163 -25
  102. package/dist/version.d.ts +1 -1
  103. package/dist/version.js +1 -1
  104. package/package.json +10 -1
  105. package/src/api.test.ts +25 -0
  106. package/src/api.ts +39 -0
  107. package/src/bb-utils.ts +3 -0
  108. package/src/cdk/apigateway-account.ts +66 -0
  109. package/src/cdk/blocks-backend.test.ts +168 -60
  110. package/src/cdk/blocks-backend.ts +299 -227
  111. package/src/cdk/blocks-defaults.test.ts +21 -0
  112. package/src/cdk/blocks-defaults.ts +79 -1
  113. package/src/cdk/blocks-stack.test.ts +57 -13
  114. package/src/cdk/compute/compute-registry.ts +45 -0
  115. package/src/cdk/compute/compute.ts +114 -2
  116. package/src/cdk/compute/default-compute-factory.ts +1 -0
  117. package/src/cdk/config-registry.test.ts +149 -0
  118. package/src/cdk/config-registry.ts +92 -34
  119. package/src/cdk/dashboard-registry.ts +68 -0
  120. package/src/cdk/index.ts +427 -256
  121. package/src/cdk/internal.ts +6 -2
  122. package/src/cdk/tracer-registry.ts +54 -0
  123. package/src/cdk/vpc-requirements-registry.ts +63 -0
  124. package/src/cdk/vpc-types.ts +158 -0
  125. package/src/cdk/vpc.test.ts +348 -0
  126. package/src/cdk/vpc.ts +336 -0
  127. package/src/client/index.ts +1 -1
  128. package/src/common/config.test.ts +21 -0
  129. package/src/common/config.ts +47 -3
  130. package/src/common/index.ts +8 -0
  131. package/src/errors.ts +26 -0
  132. package/src/hosting.test.ts +87 -1
  133. package/src/hosting.ts +24 -1
  134. package/src/index.cdk.ts +11 -1
  135. package/src/index.ts +1 -1
  136. package/src/lambda-handler.test.ts +220 -2
  137. package/src/lambda-handler.ts +65 -4
  138. package/src/raw-route.test.ts +427 -1
  139. package/src/raw-route.ts +125 -12
  140. package/src/scripts/dev-server.ts +12 -1
  141. package/src/scripts/extract-ts-types.test.ts +228 -26
  142. package/src/scripts/extract-ts-types.ts +104 -20
  143. package/src/scripts/generate-spec.test.ts +101 -0
  144. package/src/scripts/generate-spec.ts +15 -5
  145. package/src/scripts/sandbox-empty-buckets.test.ts +191 -0
  146. package/src/scripts/sandbox.ts +185 -24
  147. package/src/version.ts +1 -1
@@ -3,8 +3,9 @@
3
3
  import * as cdk from 'aws-cdk-lib';
4
4
  import * as s3 from 'aws-cdk-lib/aws-s3';
5
5
  import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment';
6
- import * as iam from 'aws-cdk-lib/aws-iam';
7
6
  const REGISTRY_KEY = Symbol.for('BLOCKS_CONFIG_REGISTRY');
7
+ /** The object key of the config JSON under {@link getConfigLocation}'s bucket. */
8
+ const CONFIG_KEY = 'blocks-config.json';
8
9
  /**
9
10
  * Get or create the config registry for a given stack.
10
11
  * The registry collects BB config entries (env var key → CDK token value)
@@ -34,47 +35,104 @@ export function registerConfig(scope, key, value) {
34
35
  const registry = getRegistry(stack);
35
36
  registry.entries.set(key, value);
36
37
  }
38
+ /**
39
+ * Ensure the shared config bucket exists and return where the config JSON lives
40
+ * (`{ bucketName, key }`). The bucket is created **once per stack** (memoized on
41
+ * the registry) and this is idempotent — the first caller creates it, later
42
+ * callers get the same bucket regardless of order.
43
+ *
44
+ * Any compute that loads config at runtime (`loadConfigToProcessEnv()`) injects
45
+ * these two values as `BLOCKS_CONFIG_BUCKET` / `BLOCKS_CONFIG_KEY`. The Lambda
46
+ * handler gets them from {@link finalizeConfigRegistry}; other compute that runs
47
+ * as the shared execution role (e.g. the Agent BB's AgentCore Runtime) calls this
48
+ * at construction to inject them too, so it loads the same app config the handler
49
+ * does. IAM is not granted here — `finalizeConfigRegistry` grants read on the config
50
+ * object to the shared execution role, which such compute inherits.
51
+ *
52
+ * @param scope - Any construct in the stack; the bucket is created under the stack.
53
+ */
54
+ export function getConfigLocation(scope) {
55
+ return { bucketName: ensureConfigBucket(scope).bucketName, key: CONFIG_KEY };
56
+ }
57
+ /**
58
+ * Create-or-return the shared config bucket (memoized on the per-stack registry). Created under the
59
+ * owning `BlocksStack`/`BlocksBackend` (`globalThis.CURRENT_BLOCKS_STACK` — the construct finalize
60
+ * historically used), so its logical ID is stable regardless of which caller creates it first: a
61
+ * co-located BB (e.g. the AgentCore Runtime, a deep construct) may be the first to call it, and a
62
+ * `BlocksBackend` embedded in a customer stack must keep `Blocks/BlocksConfigBucket` (no replacement).
63
+ * Falls back to the stack when no owner is registered (isolated unit tests). Returns a concrete
64
+ * `s3.Bucket` so callers don't need a non-null assertion.
65
+ */
66
+ function ensureConfigBucket(scope) {
67
+ const stack = cdk.Stack.of(scope);
68
+ const registry = getRegistry(stack);
69
+ if (!registry.bucket) {
70
+ const owner = globalThis.CURRENT_BLOCKS_STACK ?? stack;
71
+ registry.bucket = new s3.Bucket(owner, 'BlocksConfigBucket', {
72
+ removalPolicy: cdk.RemovalPolicy.DESTROY,
73
+ autoDeleteObjects: true,
74
+ encryption: s3.BucketEncryption.S3_MANAGED,
75
+ blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
76
+ lifecycleRules: [
77
+ { noncurrentVersionExpiration: cdk.Duration.days(1) },
78
+ ],
79
+ });
80
+ }
81
+ return registry.bucket;
82
+ }
37
83
  /**
38
84
  * Finalize the config registry: create an S3 bucket, upload the config JSON,
39
- * set env vars on the handler, and grant read access.
85
+ * grant read to the shared execution role, and stamp the config coordinates
86
+ * (`BLOCKS_CONFIG_BUCKET` / `BLOCKS_CONFIG_KEY`) onto every compute.
87
+ *
88
+ * Read access is granted once to the shared role (`root.executionRole`) rather
89
+ * than to a single function, so every compute that assumes the role can read
90
+ * the object. The bucket/key coordinates can't live on a role (env vars are
91
+ * per-compute), so they are set on each compute via `setEnv`.
40
92
  *
41
93
  * Must be called after all BBs are constructed (i.e., after the backendCDKPath
42
94
  * import completes in BlocksStack.create() / BlocksBackend.create()).
43
95
  *
44
- * @param scope - The CDK construct to create resources under
45
- * @param handler - The Lambda function that needs to read the config
96
+ * @param root - The construct to create the config resources under (also used
97
+ * to locate the owning stack).
98
+ * @param executionRole - The shared role every compute assumes; config read is
99
+ * granted to it once.
100
+ * @param computes - The computes to stamp `BLOCKS_CONFIG_BUCKET` / `BLOCKS_CONFIG_KEY` on.
46
101
  */
47
- export function finalizeConfigRegistry(scope, handler) {
48
- const stack = cdk.Stack.of(scope);
102
+ export function finalizeConfigRegistry(root, executionRole, computes) {
103
+ const stack = cdk.Stack.of(root);
49
104
  const registry = getRegistry(stack);
50
105
  if (registry.finalized)
51
106
  return;
52
107
  registry.finalized = true;
53
- if (registry.entries.size === 0)
108
+ // Nothing to do only if no config was registered AND no bucket was created (via
109
+ // getConfigLocation). If a co-located BB created the bucket, still upload (even an empty {}) and
110
+ // wire the handler so that compute's loadConfigToProcessEnv() resolves instead of 404-ing forever.
111
+ if (registry.entries.size === 0 && !registry.bucket)
54
112
  return;
55
- const configBucket = new s3.Bucket(scope, 'BlocksConfigBucket', {
56
- removalPolicy: cdk.RemovalPolicy.DESTROY,
57
- autoDeleteObjects: true,
58
- encryption: s3.BucketEncryption.S3_MANAGED,
59
- blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
60
- lifecycleRules: [
61
- { noncurrentVersionExpiration: cdk.Duration.days(1) },
62
- ],
63
- });
64
- const configKey = 'blocks-config.json';
113
+ // Ensure the bucket exists (a co-located BB may already have created it via getConfigLocation).
114
+ const configBucket = ensureConfigBucket(root);
115
+ const configKey = CONFIG_KEY;
65
116
  const configObject = cdk.Lazy.any({
66
117
  produce: () => Object.fromEntries(registry.entries),
67
118
  });
68
- const deployment = new s3deploy.BucketDeployment(scope, 'BlocksConfigDeployment', {
119
+ new s3deploy.BucketDeployment(root, 'BlocksConfigDeployment', {
69
120
  sources: [s3deploy.Source.jsonData(configKey, configObject)],
70
121
  destinationBucket: configBucket,
71
122
  prune: false,
72
123
  });
73
- handler.addEnvironment('BLOCKS_CONFIG_BUCKET', configBucket.bucketName);
74
- handler.addEnvironment('BLOCKS_CONFIG_KEY', configKey);
75
- // Scope IAM grant to the specific config key
76
- handler.addToRolePolicy(new iam.PolicyStatement({
77
- actions: ['s3:GetObject'],
78
- resources: [`${configBucket.bucketArn}/${configKey}`],
79
- }));
124
+ // Grant read once to the shared role (scoped to the config key), so every
125
+ // compute assuming the role can read it. We intentionally use `grantRead`
126
+ // (which also adds s3:GetBucket*/s3:List* alongside s3:GetObject*) rather
127
+ // than a hand-rolled GetObject-only statement: this is a dedicated,
128
+ // block-all-public, config-only bucket, so the broader action set carries
129
+ // negligible exposure, and grantRead stays correct automatically if the
130
+ // bucket ever moves to KMS encryption (it would add kms:Decrypt).
131
+ configBucket.grantRead(executionRole, configKey);
132
+ // Stamp the config coordinates on every compute — env vars can't live on a
133
+ // role, so each compute needs them to locate the object at runtime.
134
+ for (const compute of computes) {
135
+ compute.setEnv('BLOCKS_CONFIG_BUCKET', configBucket.bucketName);
136
+ compute.setEnv('BLOCKS_CONFIG_KEY', configKey);
137
+ }
80
138
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=config-registry.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-registry.test.d.ts","sourceRoot":"","sources":["../../src/cdk/config-registry.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,127 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * CDK tests for the config registry — specifically the getConfigLocation ↔ finalizeConfigRegistry
5
+ * interaction. `getConfigLocation()` creates the config bucket eagerly (so co-located compute can
6
+ * inject BLOCKS_CONFIG_BUCKET/KEY at construction); finalize must therefore still upload the config
7
+ * object + wire the computes whenever a bucket exists, even if zero entries were registered —
8
+ * otherwise that compute's loadConfigToProcessEnv() would 404 forever against a created-but-empty
9
+ * bucket.
10
+ */
11
+ import assert from 'node:assert';
12
+ import { afterEach, test } from 'node:test';
13
+ import * as cdk from 'aws-cdk-lib';
14
+ import { Match, Template } from 'aws-cdk-lib/assertions';
15
+ import { Construct } from 'constructs';
16
+ import { Compute } from './compute/compute.js';
17
+ import { finalizeConfigRegistry, getConfigLocation, registerConfig } from './config-registry.js';
18
+ import { DEFAULT_NODE_RUNTIME } from './node-version.js';
19
+ // getConfigLocation reads globalThis.CURRENT_BLOCKS_STACK to place the bucket under the owning
20
+ // stack/backend; clear it between tests so one test's owner never leaks into another.
21
+ afterEach(() => {
22
+ delete globalThis.CURRENT_BLOCKS_STACK;
23
+ });
24
+ // A real app's compute comes from @aws-blocks/bb-lambda-compute, which core's own tests can't
25
+ // depend on. This is the same shape: a Compute that owns a real Lambda function and injects config
26
+ // via addEnvironment — enough for finalizeConfigRegistry to stamp BLOCKS_CONFIG_BUCKET/KEY on it.
27
+ class TestCompute extends Compute {
28
+ fn;
29
+ constructor(scope, id) {
30
+ super(id, { parent: scope });
31
+ this.fn = new cdk.aws_lambda.Function(this, 'Handler', {
32
+ runtime: DEFAULT_NODE_RUNTIME,
33
+ handler: 'index.handler',
34
+ code: cdk.aws_lambda.Code.fromInline('exports.handler = async () => {};'),
35
+ });
36
+ }
37
+ setEnv(key, value) {
38
+ this.fn.addEnvironment(key, value);
39
+ }
40
+ // Observability hooks are irrelevant to config-registry tests — stub them so
41
+ // this test double satisfies Compute's abstract contract.
42
+ applyTracing() { }
43
+ healthWidgets() {
44
+ return [];
45
+ }
46
+ loggingWidgets() {
47
+ return [];
48
+ }
49
+ tracingWidgets() {
50
+ return [];
51
+ }
52
+ }
53
+ function stackWithCompute(id) {
54
+ const app = new cdk.App();
55
+ const stack = new cdk.Stack(app, id);
56
+ const role = new cdk.aws_iam.Role(stack, 'BlocksRole', {
57
+ assumedBy: new cdk.aws_iam.ServicePrincipal('lambda.amazonaws.com'),
58
+ });
59
+ const compute = new TestCompute(stack, 'Compute');
60
+ return { stack, role, computes: [compute] };
61
+ }
62
+ test('finalize uploads + wires the computes even with zero entries when a bucket was created', () => {
63
+ const { stack, role, computes } = stackWithCompute('EmptyWithBucket');
64
+ // Simulate a co-located BB that creates the bucket but registers no config of its own.
65
+ getConfigLocation(stack);
66
+ finalizeConfigRegistry(stack, role, computes);
67
+ const t = Template.fromStack(stack);
68
+ assert.strictEqual(Object.keys(t.findResources('AWS::S3::Bucket')).length, 1, 'one config bucket');
69
+ t.resourceCountIs('Custom::CDKBucketDeployment', 1); // the (empty) blocks-config.json is uploaded
70
+ t.hasResourceProperties('AWS::Lambda::Function', {
71
+ Environment: { Variables: Match.objectLike({ BLOCKS_CONFIG_KEY: 'blocks-config.json' }) },
72
+ });
73
+ // Read is granted once to the shared role (not per-function), so every compute that assumes it
74
+ // — including co-located compute that never went through finalize — can read the object.
75
+ t.hasResourceProperties('AWS::IAM::Policy', {
76
+ PolicyDocument: {
77
+ Statement: Match.arrayWith([
78
+ Match.objectLike({ Action: Match.arrayWith([Match.stringLikeRegexp('^s3:GetObject')]) }),
79
+ ]),
80
+ },
81
+ Roles: Match.arrayWith([Match.objectLike({ Ref: Match.stringLikeRegexp('BlocksRole') })]),
82
+ });
83
+ });
84
+ test('finalize is a no-op with zero entries and no bucket', () => {
85
+ const { stack, role, computes } = stackWithCompute('EmptyNoBucket');
86
+ finalizeConfigRegistry(stack, role, computes);
87
+ const t = Template.fromStack(stack);
88
+ assert.strictEqual(Object.keys(t.findResources('AWS::S3::Bucket')).length, 0, 'no config bucket created');
89
+ t.resourceCountIs('Custom::CDKBucketDeployment', 0);
90
+ });
91
+ test('finalize uploads + wires the computes when config was registered (bucket auto-created)', () => {
92
+ const { stack, role, computes } = stackWithCompute('WithEntries');
93
+ registerConfig(stack, 'BLOCKS_SOMETHING', 'value');
94
+ finalizeConfigRegistry(stack, role, computes);
95
+ const t = Template.fromStack(stack);
96
+ assert.strictEqual(Object.keys(t.findResources('AWS::S3::Bucket')).length, 1, 'one config bucket');
97
+ t.resourceCountIs('Custom::CDKBucketDeployment', 1);
98
+ t.hasResourceProperties('AWS::Lambda::Function', {
99
+ Environment: { Variables: Match.objectLike({ BLOCKS_CONFIG_KEY: 'blocks-config.json' }) },
100
+ });
101
+ });
102
+ test('the config bucket is created under the owning stack/backend, not the (deep) caller scope', () => {
103
+ // Mimic a BlocksBackend embedded in a customer stack: the owner is a nested construct, and the
104
+ // first caller of getConfigLocation is a *deep* construct (like the AgentCore Runtime).
105
+ const app = new cdk.App();
106
+ const stack = new cdk.Stack(app, 'CustomerStack');
107
+ const owner = new Construct(stack, 'Embedded'); // stands in for the BlocksBackend construct
108
+ globalThis.CURRENT_BLOCKS_STACK = owner;
109
+ const deepScope = new Construct(new Construct(owner, 'agent'), 'runtime');
110
+ getConfigLocation(deepScope);
111
+ const t = Template.fromStack(stack);
112
+ const bucketIds = Object.keys(t.findResources('AWS::S3::Bucket'));
113
+ assert.strictEqual(bucketIds.length, 1, 'exactly one config bucket');
114
+ // Logical IDs encode the construct path — under the owner it's `EmbeddedBlocksConfigBucket…`,
115
+ // at the stack root it would be `BlocksConfigBucket…`. Pin that it follows the owner.
116
+ assert.ok(bucketIds[0].startsWith('Embedded'), `bucket should be nested under the owner, got ${bucketIds[0]}`);
117
+ });
118
+ test('getConfigLocation creates exactly one bucket across repeated calls (idempotent)', () => {
119
+ const app = new cdk.App();
120
+ const stack = new cdk.Stack(app, 'Idempotent');
121
+ const a = getConfigLocation(stack);
122
+ const b = getConfigLocation(stack);
123
+ assert.strictEqual(a.key, b.key, 'same config key');
124
+ assert.strictEqual(a.bucketName, b.bucketName, 'same bucket');
125
+ const t = Template.fromStack(stack);
126
+ assert.strictEqual(Object.keys(t.findResources('AWS::S3::Bucket')).length, 1, 'exactly one bucket');
127
+ });
@@ -0,0 +1,41 @@
1
+ import type { Construct } from 'constructs';
2
+ /** A Dashboard's deferred widget-body build, run once after the app is constructed. */
3
+ type DashboardFinalizer = () => void;
4
+ /**
5
+ * Register a Dashboard's deferred body-build, to run after every Building Block
6
+ * in the app has been constructed (the end of `BlocksStack`/`BlocksBackend`
7
+ * `create()`, once the backend module has fully imported).
8
+ *
9
+ * The Dashboard builds its widget body here rather than in its constructor
10
+ * because the body depends on which computes are traced, and a `Tracer` may be
11
+ * constructed *after* the Dashboard. Deferring makes the Dashboard observe the
12
+ * complete app, so it never depends on construction order. (The Dashboard's
13
+ * CloudWatch resource itself is created eagerly in the constructor, so its URL /
14
+ * redirect route never dangle — only the body is deferred.)
15
+ *
16
+ * This is intentionally scoped to the Dashboard (the only deferred-build case
17
+ * today) rather than a generic finalizer mechanism; generalize it only if a
18
+ * second use case appears.
19
+ *
20
+ * @param scope - Any construct in the stack (used to locate the stack).
21
+ * @param finalize - The deferred body-build; run once (in registration order)
22
+ * by {@link finalizeDashboards}.
23
+ */
24
+ export declare function registerDashboardFinalizer(scope: Construct, finalize: DashboardFinalizer): void;
25
+ /**
26
+ * Run — and clear — every registered Dashboard finalizer on `scope`'s stack, in
27
+ * registration order. Called once from `create()` after the backend module has
28
+ * imported. Clearing the list makes a repeated call a no-op, so a dashboard's
29
+ * body is never built twice.
30
+ *
31
+ * A Dashboard constructed outside `create()` (e.g. directly in a unit test) must
32
+ * call this explicitly before synth — the same way `config-registry.test.ts`
33
+ * drives `finalizeConfigRegistry`. (A Dashboard's CloudWatch resource is created
34
+ * eagerly in its constructor, so even if its finalizer never runs its URL /
35
+ * redirect never dangle — only the widget body is missing.)
36
+ *
37
+ * @param scope - Any construct in the stack (used to locate the stack).
38
+ */
39
+ export declare function finalizeDashboards(scope: Construct): void;
40
+ export {};
41
+ //# sourceMappingURL=dashboard-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-registry.d.ts","sourceRoot":"","sources":["../../src/cdk/dashboard-registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C,uFAAuF;AACvF,KAAK,kBAAkB,GAAG,MAAM,IAAI,CAAC;AAgBrC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAE/F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAKzD"}
@@ -0,0 +1,61 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import * as cdk from 'aws-cdk-lib';
4
+ const REGISTRY_KEY = Symbol.for('BLOCKS_DASHBOARD_REGISTRY');
5
+ /**
6
+ * Get or create the deferred-dashboard list for a given stack. Stored on the
7
+ * stack object (keyed by a Symbol), so each stack in a multi-stack synth gets
8
+ * its own — mirrors the config + compute registries.
9
+ */
10
+ function getRegistry(stack) {
11
+ let list = stack[REGISTRY_KEY];
12
+ if (!list) {
13
+ list = [];
14
+ stack[REGISTRY_KEY] = list;
15
+ }
16
+ return list;
17
+ }
18
+ /**
19
+ * Register a Dashboard's deferred body-build, to run after every Building Block
20
+ * in the app has been constructed (the end of `BlocksStack`/`BlocksBackend`
21
+ * `create()`, once the backend module has fully imported).
22
+ *
23
+ * The Dashboard builds its widget body here rather than in its constructor
24
+ * because the body depends on which computes are traced, and a `Tracer` may be
25
+ * constructed *after* the Dashboard. Deferring makes the Dashboard observe the
26
+ * complete app, so it never depends on construction order. (The Dashboard's
27
+ * CloudWatch resource itself is created eagerly in the constructor, so its URL /
28
+ * redirect route never dangle — only the body is deferred.)
29
+ *
30
+ * This is intentionally scoped to the Dashboard (the only deferred-build case
31
+ * today) rather than a generic finalizer mechanism; generalize it only if a
32
+ * second use case appears.
33
+ *
34
+ * @param scope - Any construct in the stack (used to locate the stack).
35
+ * @param finalize - The deferred body-build; run once (in registration order)
36
+ * by {@link finalizeDashboards}.
37
+ */
38
+ export function registerDashboardFinalizer(scope, finalize) {
39
+ getRegistry(cdk.Stack.of(scope)).push(finalize);
40
+ }
41
+ /**
42
+ * Run — and clear — every registered Dashboard finalizer on `scope`'s stack, in
43
+ * registration order. Called once from `create()` after the backend module has
44
+ * imported. Clearing the list makes a repeated call a no-op, so a dashboard's
45
+ * body is never built twice.
46
+ *
47
+ * A Dashboard constructed outside `create()` (e.g. directly in a unit test) must
48
+ * call this explicitly before synth — the same way `config-registry.test.ts`
49
+ * drives `finalizeConfigRegistry`. (A Dashboard's CloudWatch resource is created
50
+ * eagerly in its constructor, so even if its finalizer never runs its URL /
51
+ * redirect never dangle — only the widget body is missing.)
52
+ *
53
+ * @param scope - Any construct in the stack (used to locate the stack).
54
+ */
55
+ export function finalizeDashboards(scope) {
56
+ const list = getRegistry(cdk.Stack.of(scope));
57
+ // Drain the list so a repeated call can't rebuild an already-built dashboard.
58
+ const pending = list.splice(0, list.length);
59
+ for (const finalize of pending)
60
+ finalize();
61
+ }
@@ -1,18 +1,24 @@
1
1
  import * as cdk from 'aws-cdk-lib';
2
2
  import { Construct } from 'constructs';
3
- import { type BlocksStackProps, type BlocksStack as BaseBlocksStack, type ScopeParent, type ScopeOptions } from '../common/index.js';
3
+ import { type BlocksStack as BaseBlocksStack, type BlocksStackProps, type ScopeOptions, type ScopeParent } from '../common/index.js';
4
4
  import { type BlocksDefaults } from './blocks-defaults.js';
5
5
  import type { Compute } from './compute/compute.js';
6
6
  import type { DefaultComputeFactory } from './compute/default-compute-factory.js';
7
+ import type { VpcRequirements } from './vpc-types.js';
8
+ export { ApiError, DEFAULT_API_ERROR_NAME, hasAuthError, isBlocksError } from '../errors.js';
9
+ export type { ScopeOptions } from '../index.js';
10
+ export { ensureApiGatewayAccount } from './apigateway-account.js';
7
11
  export { BlocksBackend, type BlocksBackendProps, type CoreBlocksBackendProps, SHARED_HANDLER_TIMEOUT_SECONDS, } from './blocks-backend.js';
8
- export { DEFAULT_NODE_RUNTIME } from './node-version.js';
12
+ export { type BlocksDefaults, BlocksPresets, type BlocksThrottling, } from './blocks-defaults.js';
9
13
  export { blocksNodejsBundling } from './bundling.js';
14
+ export { finalizeConfigRegistry, getConfigLocation, registerConfig } from './config-registry.js';
15
+ export { finalizeDashboards, registerDashboardFinalizer } from './dashboard-registry.js';
10
16
  export { SandboxDisableDeletionProtection } from './mixins.js';
11
- export { registerConfig, finalizeConfigRegistry } from './config-registry.js';
12
- export { type BlocksDefaults, BlocksPresets, } from './blocks-defaults.js';
17
+ export { DEFAULT_NODE_RUNTIME } from './node-version.js';
13
18
  export { synthGuard } from './synth-guard.js';
14
- export type { ScopeOptions } from '../index.js';
15
- export { ApiError, isBlocksError, hasAuthError, DEFAULT_API_ERROR_NAME } from '../errors.js';
19
+ export { finalizeTracing, registerTracer } from './tracer-registry.js';
20
+ export { getVpcContext } from './vpc.js';
21
+ export type { BlocksVpcOptions, SubnetRole, VpcContext, VpcRequirements } from './vpc-types.js';
16
22
  /**
17
23
  * Core's `create()` props: the public {@link BlocksStackProps} plus the required
18
24
  * `defaultComputeFactory`. The umbrella (`@aws-blocks/blocks`) supplies the
@@ -31,6 +37,12 @@ export interface CoreBlocksStackProps extends BlocksStackProps {
31
37
  export declare class BlocksStack extends cdk.Stack implements BaseBlocksStack {
32
38
  readonly id: string;
33
39
  readonly backendHandlerPath: string;
40
+ /**
41
+ * Path to the app's backend module (`props.backendCDKPath`). Exposed so Building Blocks that
42
+ * co-bundle the backend at synth (e.g. the Agent BB's AgentCore Runtime) can discover it via
43
+ * `globalThis.CURRENT_BLOCKS_STACK.backendModulePath`.
44
+ */
45
+ readonly backendModulePath: string;
34
46
  /** Shared IAM role assumed by all Blocks compute. Building Blocks grant to this role. */
35
47
  readonly executionRole: cdk.aws_iam.IRole;
36
48
  /** Infrastructure defaults for Building Blocks created under this stack. */
@@ -43,7 +55,12 @@ export declare class BlocksStack extends cdk.Stack implements BaseBlocksStack {
43
55
  get gateway(): cdk.aws_apigateway.RestApi;
44
56
  /** The default compute's RPC endpoint URL. To be removed once consumers move to the multi-compute model. */
45
57
  get apiUrl(): string;
58
+ /** The default compute's handler CloudWatch log group. Its retention comes from
59
+ * the compute's `logRetention` (falling back to `defaults.logRetention`); the
60
+ * `bb-logger` CDK construct is a no-op and no longer touches it. */
61
+ get handlerLogGroup(): cdk.aws_logs.ILogGroup;
46
62
  private requireDefaultCompute;
63
+ private _vpcOptions?;
47
64
  private constructor();
48
65
  static create(scope: Construct, id: string, props: CoreBlocksStackProps): Promise<BlocksStack>;
49
66
  }
@@ -92,6 +109,17 @@ export declare class Scope extends Construct {
92
109
  * public option to set it yet.
93
110
  */
94
111
  get compute(): Compute;
112
+ /**
113
+ * The stack's default compute, **ignoring** any per-scope `_compute`
114
+ * assignment (unlike {@link compute}, which resolves the nearest assigned
115
+ * one). Use when a resource is a stack-level singleton that must bind to one
116
+ * deterministic compute regardless of the block's resolved compute — e.g.
117
+ * Realtime's shared WebSocket route integration, where one WebSocket API
118
+ * integrates to a single target and connection bookkeeping is compute-agnostic.
119
+ *
120
+ * @internal Not a customer surface; for framework/BB singleton infra only.
121
+ */
122
+ get defaultCompute(): Compute;
95
123
  /**
96
124
  * The backend entry file the owning BlocksStack/BlocksBackend runs — the
97
125
  * single handler entry shared across the whole app.
@@ -106,6 +134,14 @@ export declare class Scope extends Construct {
106
134
  * as `fullId` ({@link BlocksBackend.fullId}); `BlocksStack` as `id`.
107
135
  */
108
136
  get backendStackName(): string;
137
+ /**
138
+ * The shared handler Lambda's CloudWatch log group (the default compute's).
139
+ * Resolves the same way as {@link handler} — via the owning
140
+ * BlocksStack/BlocksBackend. Its retention comes from the compute's
141
+ * `logRetention` (falling back to `defaults.logRetention`); the `bb-logger`
142
+ * CDK construct is a no-op and no longer reconfigures it.
143
+ */
144
+ get handlerLogGroup(): cdk.aws_logs.ILogGroup;
109
145
  get fullId(): string;
110
146
  /**
111
147
  * The stack-wide infrastructure {@link BlocksDefaults} registered by
@@ -125,4 +161,52 @@ export declare class Scope extends Construct {
125
161
  get clientMiddleware(): readonly string[];
126
162
  get devAttachments(): readonly string[];
127
163
  }
164
+ /**
165
+ * A VPC-requirements provider: either the requirements directly, or a callback
166
+ * that returns them. Use the callback form when the value depends on `fullId`
167
+ * or other post-construction state — it is evaluated by the base constructor
168
+ * *after* `super()` runs, so `this` is fully available.
169
+ */
170
+ export type VpcRequirementsProvider = VpcRequirements | (() => VpcRequirements);
171
+ /**
172
+ * Constructor options for a {@link BuildingBlockScope} — the {@link ScopeOptions}
173
+ * every Scope takes, plus the block's VPC requirements. `vpc` is **required** so
174
+ * a BB author can't silently omit it; pass `{}` when the block needs nothing
175
+ * VPC-specific.
176
+ */
177
+ export interface BuildingBlockScopeOptions extends ScopeOptions {
178
+ /**
179
+ * What this block needs from the VPC — endpoints, runtime egress, whether it
180
+ * requires a VPC at all. A value, or a callback (evaluated after `super()`,
181
+ * so it may read `this.fullId`). See {@link VpcRequirements}.
182
+ */
183
+ vpc: VpcRequirementsProvider;
184
+ }
185
+ /**
186
+ * Base class for Building Block CDK constructs.
187
+ *
188
+ * BBs extend this instead of `Scope` directly and **must** declare their VPC
189
+ * requirements as a constructor argument — the base registers them centrally
190
+ * (see `vpc-requirements-registry.ts`) so `finalizeVpc` can pull, deduplicate,
191
+ * and provision endpoints, and so the lazy VPC can answer "does anything here
192
+ * need a VPC?". Passing the requirements is required by the constructor
193
+ * signature, so a BB author cannot silently forget to declare them — the same
194
+ * forcing the previous `abstract getVpcRequirements()` gave, but without a
195
+ * standing method on every subclass.
196
+ *
197
+ * Declare `{}` when the BB needs nothing VPC-specific.
198
+ *
199
+ * @example
200
+ * ```ts
201
+ * export class KVStore extends BuildingBlockScope {
202
+ * constructor(scope: ScopeParent, id: string) {
203
+ * super(id, { parent: scope, vpc: { gatewayEndpoints: [ec2.GatewayVpcEndpointAwsService.DYNAMODB] } });
204
+ * // …
205
+ * }
206
+ * }
207
+ * ```
208
+ */
209
+ export declare class BuildingBlockScope extends Scope {
210
+ constructor(id: string, options: BuildingBlockScopeOptions);
211
+ }
128
212
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cdk/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cdk/index.ts"],"names":[],"mappings":"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"}