@aws-blocks/core 0.2.0 → 0.4.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 (178) hide show
  1. package/README.md +13 -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 +43 -9
  12. package/dist/cdk/blocks-backend.d.ts.map +1 -1
  13. package/dist/cdk/blocks-backend.js +69 -73
  14. package/dist/cdk/blocks-backend.test.js +78 -69
  15. package/dist/cdk/blocks-defaults.d.ts +92 -2
  16. package/dist/cdk/blocks-defaults.d.ts.map +1 -1
  17. package/dist/cdk/blocks-defaults.js +22 -2
  18. package/dist/cdk/blocks-defaults.test.js +21 -2
  19. package/dist/cdk/blocks-stack.test.js +94 -37
  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 +2 -0
  24. package/dist/cdk/compute/compute.d.ts.map +1 -1
  25. package/dist/cdk/compute/compute.js +8 -0
  26. package/dist/cdk/compute/default-compute-factory.d.ts +34 -0
  27. package/dist/cdk/compute/default-compute-factory.d.ts.map +1 -0
  28. package/dist/cdk/compute/default-compute-factory.js +3 -0
  29. package/dist/cdk/config-registry.d.ts +34 -4
  30. package/dist/cdk/config-registry.d.ts.map +1 -1
  31. package/dist/cdk/config-registry.js +83 -25
  32. package/dist/cdk/config-registry.test.d.ts +2 -0
  33. package/dist/cdk/config-registry.test.d.ts.map +1 -0
  34. package/dist/cdk/config-registry.test.js +115 -0
  35. package/dist/cdk/index.d.ts +76 -7
  36. package/dist/cdk/index.d.ts.map +1 -1
  37. package/dist/cdk/index.js +99 -9
  38. package/dist/cdk/internal.d.ts +1 -0
  39. package/dist/cdk/internal.d.ts.map +1 -1
  40. package/dist/client/index.d.ts +1 -1
  41. package/dist/client/index.d.ts.map +1 -1
  42. package/dist/client/index.js +1 -1
  43. package/dist/common/config.d.ts +34 -0
  44. package/dist/common/config.d.ts.map +1 -1
  45. package/dist/common/config.js +45 -3
  46. package/dist/common/config.test.js +19 -0
  47. package/dist/common/index.d.ts +8 -0
  48. package/dist/common/index.d.ts.map +1 -1
  49. package/dist/errors.d.ts +16 -0
  50. package/dist/errors.d.ts.map +1 -1
  51. package/dist/errors.js +20 -0
  52. package/dist/hosting-secrets.d.ts +48 -0
  53. package/dist/hosting-secrets.d.ts.map +1 -0
  54. package/dist/hosting-secrets.js +57 -0
  55. package/dist/hosting-secrets.test.d.ts +2 -0
  56. package/dist/hosting-secrets.test.d.ts.map +1 -0
  57. package/dist/hosting-secrets.test.js +81 -0
  58. package/dist/hosting.d.ts +97 -6
  59. package/dist/hosting.d.ts.map +1 -1
  60. package/dist/hosting.js +91 -23
  61. package/dist/hosting.test.js +182 -10
  62. package/dist/index.cdk.d.ts +13 -12
  63. package/dist/index.cdk.d.ts.map +1 -1
  64. package/dist/index.cdk.js +13 -9
  65. package/dist/index.d.ts +8 -7
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +9 -5
  68. package/dist/lambda-handler.d.ts +17 -0
  69. package/dist/lambda-handler.d.ts.map +1 -1
  70. package/dist/lambda-handler.js +52 -3
  71. package/dist/lambda-handler.test.js +196 -1
  72. package/dist/pipeline/index.d.ts +24 -2
  73. package/dist/pipeline/index.d.ts.map +1 -1
  74. package/dist/pipeline/index.js +41 -1
  75. package/dist/pipeline.test.d.ts +2 -0
  76. package/dist/pipeline.test.d.ts.map +1 -0
  77. package/dist/pipeline.test.js +47 -0
  78. package/dist/rpc.d.ts +21 -0
  79. package/dist/rpc.d.ts.map +1 -1
  80. package/dist/rpc.js +34 -0
  81. package/dist/rpc.test.js +38 -1
  82. package/dist/scripts/config.d.ts +15 -0
  83. package/dist/scripts/config.d.ts.map +1 -0
  84. package/dist/scripts/config.js +29 -0
  85. package/dist/scripts/deploy.d.ts.map +1 -1
  86. package/dist/scripts/deploy.js +4 -0
  87. package/dist/scripts/dev-server.d.ts +8 -0
  88. package/dist/scripts/dev-server.d.ts.map +1 -1
  89. package/dist/scripts/dev-server.js +31 -0
  90. package/dist/scripts/generate-client.d.ts.map +1 -1
  91. package/dist/scripts/generate-client.js +9 -4
  92. package/dist/scripts/generate-client.test.js +19 -4
  93. package/dist/scripts/index.d.ts +13 -10
  94. package/dist/scripts/index.d.ts.map +1 -1
  95. package/dist/scripts/index.js +11 -8
  96. package/dist/scripts/preflight-credentials.d.ts +30 -0
  97. package/dist/scripts/preflight-credentials.d.ts.map +1 -0
  98. package/dist/scripts/preflight-credentials.js +108 -0
  99. package/dist/scripts/preflight-credentials.test.d.ts +2 -0
  100. package/dist/scripts/preflight-credentials.test.d.ts.map +1 -0
  101. package/dist/scripts/preflight-credentials.test.js +77 -0
  102. package/dist/scripts/sandbox-args.test.d.ts +2 -0
  103. package/dist/scripts/sandbox-args.test.d.ts.map +1 -0
  104. package/dist/scripts/sandbox-args.test.js +77 -0
  105. package/dist/scripts/sandbox-empty-buckets.test.d.ts +2 -0
  106. package/dist/scripts/sandbox-empty-buckets.test.d.ts.map +1 -0
  107. package/dist/scripts/sandbox-empty-buckets.test.js +171 -0
  108. package/dist/scripts/sandbox.d.ts +106 -0
  109. package/dist/scripts/sandbox.d.ts.map +1 -1
  110. package/dist/scripts/sandbox.js +255 -40
  111. package/dist/scripts/secret.d.ts +15 -0
  112. package/dist/scripts/secret.d.ts.map +1 -0
  113. package/dist/scripts/secret.js +29 -0
  114. package/dist/scripts/secret.test.d.ts +2 -0
  115. package/dist/scripts/secret.test.d.ts.map +1 -0
  116. package/dist/scripts/secret.test.js +28 -0
  117. package/dist/scripts/typegen.d.ts +15 -0
  118. package/dist/scripts/typegen.d.ts.map +1 -0
  119. package/dist/scripts/typegen.js +16 -0
  120. package/dist/secret-naming.d.ts +58 -0
  121. package/dist/secret-naming.d.ts.map +1 -0
  122. package/dist/secret-naming.js +67 -0
  123. package/dist/secret-naming.test.d.ts +2 -0
  124. package/dist/secret-naming.test.d.ts.map +1 -0
  125. package/dist/secret-naming.test.js +40 -0
  126. package/dist/version.d.ts +1 -1
  127. package/dist/version.js +1 -1
  128. package/package.json +4 -1
  129. package/src/api.test.ts +25 -0
  130. package/src/api.ts +39 -0
  131. package/src/bb-utils.ts +3 -0
  132. package/src/cdk/apigateway-account.ts +66 -0
  133. package/src/cdk/blocks-backend.test.ts +291 -272
  134. package/src/cdk/blocks-backend.ts +88 -83
  135. package/src/cdk/blocks-defaults.test.ts +25 -2
  136. package/src/cdk/blocks-defaults.ts +94 -2
  137. package/src/cdk/blocks-stack.test.ts +186 -118
  138. package/src/cdk/compute/compute-registry.ts +45 -0
  139. package/src/cdk/compute/compute.ts +10 -0
  140. package/src/cdk/compute/default-compute-factory.ts +38 -0
  141. package/src/cdk/config-registry.test.ts +135 -0
  142. package/src/cdk/config-registry.ts +92 -34
  143. package/src/cdk/index.ts +129 -10
  144. package/src/cdk/internal.ts +1 -0
  145. package/src/client/index.ts +1 -1
  146. package/src/common/config.test.ts +21 -0
  147. package/src/common/config.ts +47 -3
  148. package/src/common/index.ts +8 -0
  149. package/src/errors.ts +21 -0
  150. package/src/hosting-secrets.test.ts +106 -0
  151. package/src/hosting-secrets.ts +106 -0
  152. package/src/hosting.test.ts +272 -63
  153. package/src/hosting.ts +200 -68
  154. package/src/index.cdk.ts +80 -38
  155. package/src/index.ts +35 -16
  156. package/src/lambda-handler.test.ts +215 -1
  157. package/src/lambda-handler.ts +54 -2
  158. package/src/pipeline/index.ts +64 -11
  159. package/src/pipeline.test.ts +55 -0
  160. package/src/rpc.test.ts +44 -1
  161. package/src/rpc.ts +41 -0
  162. package/src/scripts/config.ts +35 -0
  163. package/src/scripts/deploy.ts +5 -0
  164. package/src/scripts/dev-server.ts +40 -0
  165. package/src/scripts/generate-client.test.ts +43 -8
  166. package/src/scripts/generate-client.ts +70 -65
  167. package/src/scripts/index.ts +20 -17
  168. package/src/scripts/preflight-credentials.test.ts +110 -0
  169. package/src/scripts/preflight-credentials.ts +131 -0
  170. package/src/scripts/sandbox-args.test.ts +92 -0
  171. package/src/scripts/sandbox-empty-buckets.test.ts +191 -0
  172. package/src/scripts/sandbox.ts +287 -39
  173. package/src/scripts/secret.test.ts +35 -0
  174. package/src/scripts/secret.ts +35 -0
  175. package/src/scripts/typegen.ts +18 -0
  176. package/src/secret-naming.test.ts +59 -0
  177. package/src/secret-naming.ts +99 -0
  178. package/src/version.ts +1 -1
@@ -0,0 +1,115 @@
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
+ }
41
+ function stackWithCompute(id) {
42
+ const app = new cdk.App();
43
+ const stack = new cdk.Stack(app, id);
44
+ const role = new cdk.aws_iam.Role(stack, 'BlocksRole', {
45
+ assumedBy: new cdk.aws_iam.ServicePrincipal('lambda.amazonaws.com'),
46
+ });
47
+ const compute = new TestCompute(stack, 'Compute');
48
+ return { stack, role, computes: [compute] };
49
+ }
50
+ test('finalize uploads + wires the computes even with zero entries when a bucket was created', () => {
51
+ const { stack, role, computes } = stackWithCompute('EmptyWithBucket');
52
+ // Simulate a co-located BB that creates the bucket but registers no config of its own.
53
+ getConfigLocation(stack);
54
+ finalizeConfigRegistry(stack, role, computes);
55
+ const t = Template.fromStack(stack);
56
+ assert.strictEqual(Object.keys(t.findResources('AWS::S3::Bucket')).length, 1, 'one config bucket');
57
+ t.resourceCountIs('Custom::CDKBucketDeployment', 1); // the (empty) blocks-config.json is uploaded
58
+ t.hasResourceProperties('AWS::Lambda::Function', {
59
+ Environment: { Variables: Match.objectLike({ BLOCKS_CONFIG_KEY: 'blocks-config.json' }) },
60
+ });
61
+ // Read is granted once to the shared role (not per-function), so every compute that assumes it
62
+ // — including co-located compute that never went through finalize — can read the object.
63
+ t.hasResourceProperties('AWS::IAM::Policy', {
64
+ PolicyDocument: {
65
+ Statement: Match.arrayWith([
66
+ Match.objectLike({ Action: Match.arrayWith([Match.stringLikeRegexp('^s3:GetObject')]) }),
67
+ ]),
68
+ },
69
+ Roles: Match.arrayWith([Match.objectLike({ Ref: Match.stringLikeRegexp('BlocksRole') })]),
70
+ });
71
+ });
72
+ test('finalize is a no-op with zero entries and no bucket', () => {
73
+ const { stack, role, computes } = stackWithCompute('EmptyNoBucket');
74
+ finalizeConfigRegistry(stack, role, computes);
75
+ const t = Template.fromStack(stack);
76
+ assert.strictEqual(Object.keys(t.findResources('AWS::S3::Bucket')).length, 0, 'no config bucket created');
77
+ t.resourceCountIs('Custom::CDKBucketDeployment', 0);
78
+ });
79
+ test('finalize uploads + wires the computes when config was registered (bucket auto-created)', () => {
80
+ const { stack, role, computes } = stackWithCompute('WithEntries');
81
+ registerConfig(stack, 'BLOCKS_SOMETHING', 'value');
82
+ finalizeConfigRegistry(stack, role, computes);
83
+ const t = Template.fromStack(stack);
84
+ assert.strictEqual(Object.keys(t.findResources('AWS::S3::Bucket')).length, 1, 'one config bucket');
85
+ t.resourceCountIs('Custom::CDKBucketDeployment', 1);
86
+ t.hasResourceProperties('AWS::Lambda::Function', {
87
+ Environment: { Variables: Match.objectLike({ BLOCKS_CONFIG_KEY: 'blocks-config.json' }) },
88
+ });
89
+ });
90
+ test('the config bucket is created under the owning stack/backend, not the (deep) caller scope', () => {
91
+ // Mimic a BlocksBackend embedded in a customer stack: the owner is a nested construct, and the
92
+ // first caller of getConfigLocation is a *deep* construct (like the AgentCore Runtime).
93
+ const app = new cdk.App();
94
+ const stack = new cdk.Stack(app, 'CustomerStack');
95
+ const owner = new Construct(stack, 'Embedded'); // stands in for the BlocksBackend construct
96
+ globalThis.CURRENT_BLOCKS_STACK = owner;
97
+ const deepScope = new Construct(new Construct(owner, 'agent'), 'runtime');
98
+ getConfigLocation(deepScope);
99
+ const t = Template.fromStack(stack);
100
+ const bucketIds = Object.keys(t.findResources('AWS::S3::Bucket'));
101
+ assert.strictEqual(bucketIds.length, 1, 'exactly one config bucket');
102
+ // Logical IDs encode the construct path — under the owner it's `EmbeddedBlocksConfigBucket…`,
103
+ // at the stack root it would be `BlocksConfigBucket…`. Pin that it follows the owner.
104
+ assert.ok(bucketIds[0].startsWith('Embedded'), `bucket should be nested under the owner, got ${bucketIds[0]}`);
105
+ });
106
+ test('getConfigLocation creates exactly one bucket across repeated calls (idempotent)', () => {
107
+ const app = new cdk.App();
108
+ const stack = new cdk.Stack(app, 'Idempotent');
109
+ const a = getConfigLocation(stack);
110
+ const b = getConfigLocation(stack);
111
+ assert.strictEqual(a.key, b.key, 'same config key');
112
+ assert.strictEqual(a.bucketName, b.bucketName, 'same bucket');
113
+ const t = Template.fromStack(stack);
114
+ assert.strictEqual(Object.keys(t.findResources('AWS::S3::Bucket')).length, 1, 'exactly one bucket');
115
+ });
@@ -2,27 +2,59 @@ import * as cdk from 'aws-cdk-lib';
2
2
  import { Construct } from 'constructs';
3
3
  import { type BlocksStackProps, type BlocksStack as BaseBlocksStack, type ScopeParent, type ScopeOptions } from '../common/index.js';
4
4
  import { type BlocksDefaults } from './blocks-defaults.js';
5
- export { BlocksBackend, type BlocksBackendProps } from './blocks-backend.js';
5
+ import type { Compute } from './compute/compute.js';
6
+ import type { DefaultComputeFactory } from './compute/default-compute-factory.js';
7
+ export { BlocksBackend, type BlocksBackendProps, type CoreBlocksBackendProps, SHARED_HANDLER_TIMEOUT_SECONDS, } from './blocks-backend.js';
6
8
  export { DEFAULT_NODE_RUNTIME } from './node-version.js';
7
9
  export { blocksNodejsBundling } from './bundling.js';
8
10
  export { SandboxDisableDeletionProtection } from './mixins.js';
9
- export { registerConfig, finalizeConfigRegistry } from './config-registry.js';
10
- export { type BlocksDefaults, BlocksPresets, } from './blocks-defaults.js';
11
+ export { registerConfig, finalizeConfigRegistry, getConfigLocation } from './config-registry.js';
12
+ export { ensureApiGatewayAccount } from './apigateway-account.js';
13
+ export { type BlocksDefaults, type BlocksThrottling, BlocksPresets, } from './blocks-defaults.js';
11
14
  export { synthGuard } from './synth-guard.js';
12
15
  export type { ScopeOptions } from '../index.js';
13
16
  export { ApiError, isBlocksError, hasAuthError, DEFAULT_API_ERROR_NAME } from '../errors.js';
17
+ /**
18
+ * Core's `create()` props: the public {@link BlocksStackProps} plus the required
19
+ * `defaultComputeFactory`. The umbrella (`@aws-blocks/blocks`) supplies the
20
+ * factory (which builds a `LambdaCompute`) by spreading it onto the customer's
21
+ * props; customers use {@link BlocksStackProps} and never set the factory.
22
+ *
23
+ * Kept separate (rather than a `create()` argument) so the factory travels with
24
+ * the props object and core stays free of any concrete compute class.
25
+ *
26
+ * @internal
27
+ */
28
+ export interface CoreBlocksStackProps extends BlocksStackProps {
29
+ /** Builds the stack's default compute. Injected by `@aws-blocks/blocks`. */
30
+ defaultComputeFactory: DefaultComputeFactory;
31
+ }
14
32
  export declare class BlocksStack extends cdk.Stack implements BaseBlocksStack {
15
33
  readonly id: string;
16
- readonly apiUrl: string;
17
- readonly gateway: cdk.aws_apigateway.RestApi;
18
- readonly handler: cdk.aws_lambda_nodejs.NodejsFunction;
19
34
  readonly backendHandlerPath: string;
35
+ /**
36
+ * Path to the app's backend module (`props.backendCDKPath`). Exposed so Building Blocks that
37
+ * co-bundle the backend at synth (e.g. the Agent BB's AgentCore Runtime) can discover it via
38
+ * `globalThis.CURRENT_BLOCKS_STACK.backendModulePath`.
39
+ */
40
+ readonly backendModulePath: string;
20
41
  /** Shared IAM role assumed by all Blocks compute. Building Blocks grant to this role. */
21
42
  readonly executionRole: cdk.aws_iam.IRole;
22
43
  /** Infrastructure defaults for Building Blocks created under this stack. */
23
44
  readonly defaults: BlocksDefaults;
45
+ /** The default compute (owns the Lambda function + API Gateway); set in `create()`. @internal */
46
+ _defaultCompute?: Compute;
47
+ /** The default compute's Lambda function. To be removed once consumers move to the multi-compute model. */
48
+ get handler(): cdk.aws_lambda_nodejs.NodejsFunction;
49
+ /** The default compute's API Gateway REST API. To be removed once consumers move to the multi-compute model. */
50
+ get gateway(): cdk.aws_apigateway.RestApi;
51
+ /** The default compute's RPC endpoint URL. To be removed once consumers move to the multi-compute model. */
52
+ get apiUrl(): string;
53
+ /** The default compute's handler CloudWatch log group. `bb-logger` reconfigures its retention. */
54
+ get handlerLogGroup(): cdk.aws_logs.ILogGroup;
55
+ private requireDefaultCompute;
24
56
  private constructor();
25
- static create(scope: Construct, id: string, props: BlocksStackProps): Promise<BlocksStack>;
57
+ static create(scope: Construct, id: string, props: CoreBlocksStackProps): Promise<BlocksStack>;
26
58
  }
27
59
  export declare class Scope extends Construct {
28
60
  readonly id: string;
@@ -37,6 +69,14 @@ export declare class Scope extends Construct {
37
69
  * tree walk.
38
70
  */
39
71
  private readonly root;
72
+ /**
73
+ * Compute assigned at this node. Applies to this block and is inherited by
74
+ * descendants (a nearer assignment wins). Covers both a handler assigned to a
75
+ * specific compute and a scope-level default for its subtree. Internal until
76
+ * the customer-facing surface exists.
77
+ * @internal
78
+ */
79
+ _compute?: Compute;
40
80
  constructor(id: string, options?: ScopeOptions);
41
81
  /**
42
82
  * Walk up the construct tree to the nearest owning BlocksStack/BlocksBackend;
@@ -51,6 +91,27 @@ export declare class Scope extends Construct {
51
91
  * route those grants to the role's default (inline) policy.
52
92
  */
53
93
  get executionRole(): cdk.aws_iam.IRole;
94
+ /**
95
+ * The compute this block runs on: the nearest `_compute` assigned on this
96
+ * block or an ancestor scope, else the owning stack/backend's default compute.
97
+ *
98
+ * For any app that doesn't assign a compute, this always resolves to the
99
+ * default — so reads are a no-op refactor. `_compute` is internal
100
+ * (test/framework) until the customer-facing surface exists; there is no
101
+ * public option to set it yet.
102
+ */
103
+ get compute(): Compute;
104
+ /**
105
+ * The stack's default compute, **ignoring** any per-scope `_compute`
106
+ * assignment (unlike {@link compute}, which resolves the nearest assigned
107
+ * one). Use when a resource is a stack-level singleton that must bind to one
108
+ * deterministic compute regardless of the block's resolved compute — e.g.
109
+ * Realtime's shared WebSocket route integration, where one WebSocket API
110
+ * integrates to a single target and connection bookkeeping is compute-agnostic.
111
+ *
112
+ * @internal Not a customer surface; for framework/BB singleton infra only.
113
+ */
114
+ get defaultCompute(): Compute;
54
115
  /**
55
116
  * The backend entry file the owning BlocksStack/BlocksBackend runs — the
56
117
  * single handler entry shared across the whole app.
@@ -65,6 +126,14 @@ export declare class Scope extends Construct {
65
126
  * as `fullId` ({@link BlocksBackend.fullId}); `BlocksStack` as `id`.
66
127
  */
67
128
  get backendStackName(): string;
129
+ /**
130
+ * The shared handler Lambda's CloudWatch log group (the default compute's).
131
+ * Resolves the same way as {@link handler} — via the owning
132
+ * BlocksStack/BlocksBackend. `bb-logger` uses this to reconfigure retention on
133
+ * the single, framework-owned group rather than creating a second one that
134
+ * would collide on the log-group name.
135
+ */
136
+ get handlerLogGroup(): cdk.aws_logs.ILogGroup;
68
137
  get fullId(): string;
69
138
  /**
70
139
  * The stack-wide infrastructure {@link BlocksDefaults} registered by
@@ -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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"}
package/dist/cdk/index.js CHANGED
@@ -9,35 +9,62 @@ import { setupBlocksInfra, BlocksBackend, assertCdkConditionActive } from './blo
9
9
  import { addBlocksStackMetadata } from './stack-metadata.js';
10
10
  import { finalizeConfigRegistry } from './config-registry.js';
11
11
  import { BlocksPresets } from './blocks-defaults.js';
12
- export { BlocksBackend } from './blocks-backend.js';
12
+ import { getComputes } from './compute/compute-registry.js';
13
+ export { BlocksBackend, SHARED_HANDLER_TIMEOUT_SECONDS, } from './blocks-backend.js';
13
14
  export { DEFAULT_NODE_RUNTIME } from './node-version.js';
14
15
  export { blocksNodejsBundling } from './bundling.js';
15
16
  export { SandboxDisableDeletionProtection } from './mixins.js';
16
- export { registerConfig, finalizeConfigRegistry } from './config-registry.js';
17
+ export { registerConfig, finalizeConfigRegistry, getConfigLocation } from './config-registry.js';
18
+ export { ensureApiGatewayAccount } from './apigateway-account.js';
17
19
  export { BlocksPresets, } from './blocks-defaults.js';
18
20
  export { synthGuard } from './synth-guard.js';
19
21
  export { ApiError, isBlocksError, hasAuthError, DEFAULT_API_ERROR_NAME } from '../errors.js';
20
22
  export class BlocksStack extends cdk.Stack {
21
23
  id;
22
- apiUrl;
23
- gateway;
24
- handler;
25
24
  backendHandlerPath;
25
+ /**
26
+ * Path to the app's backend module (`props.backendCDKPath`). Exposed so Building Blocks that
27
+ * co-bundle the backend at synth (e.g. the Agent BB's AgentCore Runtime) can discover it via
28
+ * `globalThis.CURRENT_BLOCKS_STACK.backendModulePath`.
29
+ */
30
+ backendModulePath;
26
31
  /** Shared IAM role assumed by all Blocks compute. Building Blocks grant to this role. */
27
32
  executionRole;
28
33
  /** Infrastructure defaults for Building Blocks created under this stack. */
29
34
  defaults;
35
+ /** The default compute (owns the Lambda function + API Gateway); set in `create()`. @internal */
36
+ _defaultCompute;
37
+ /** The default compute's Lambda function. To be removed once consumers move to the multi-compute model. */
38
+ get handler() {
39
+ return this.requireDefaultCompute().fn;
40
+ }
41
+ /** The default compute's API Gateway REST API. To be removed once consumers move to the multi-compute model. */
42
+ get gateway() {
43
+ return this.requireDefaultCompute().apiGateway;
44
+ }
45
+ /** The default compute's RPC endpoint URL. To be removed once consumers move to the multi-compute model. */
46
+ get apiUrl() {
47
+ return this.requireDefaultCompute().apiUrl;
48
+ }
49
+ /** The default compute's handler CloudWatch log group. `bb-logger` reconfigures its retention. */
50
+ get handlerLogGroup() {
51
+ return this.requireDefaultCompute().logGroup;
52
+ }
53
+ requireDefaultCompute() {
54
+ if (!this._defaultCompute) {
55
+ throw new Error('Blocks stack not fully initialized — access .handler/.gateway/.apiUrl after BlocksStack.create() resolves.');
56
+ }
57
+ return this._defaultCompute;
58
+ }
30
59
  constructor(scope, id, props) {
31
60
  super(scope, id, props);
32
61
  this.id = id;
33
62
  this.backendHandlerPath = props.backendHandlerPath;
34
63
  this.defaults = props.defaults;
64
+ this.backendModulePath = props.backendCDKPath;
35
65
  // Set globalThis so Building Blocks attach directly to this stack
36
66
  globalThis.CURRENT_BLOCKS_STACK = this;
37
67
  const infra = setupBlocksInfra(this, props, id);
38
- this.handler = infra.handler;
39
- this.gateway = infra.gateway;
40
- this.apiUrl = infra.apiUrl;
41
68
  this.executionRole = infra.executionRole;
42
69
  }
43
70
  static async create(scope, id, props) {
@@ -46,6 +73,13 @@ export class BlocksStack extends cdk.Stack {
46
73
  const pipelineScope = globalThis[__PIPELINE_STAGE_SCOPE__];
47
74
  const actualScope = pipelineScope || scope;
48
75
  const stack = new BlocksStack(actualScope, id, props);
76
+ // Create the default compute before importing the backend: it OWNS the
77
+ // Lambda function + API Gateway (which back .handler/.gateway/.apiUrl), and
78
+ // a block reading `this.compute` in its constructor (during that import)
79
+ // must resolve to it. The factory is supplied by the umbrella
80
+ // @aws-blocks/blocks (which injects LambdaCompute) via props, so core never
81
+ // imports the concrete compute class.
82
+ stack._defaultCompute = props.defaultComputeFactory(stack);
49
83
  // file:// URL (not a raw path) so the cache-busting query works on Windows,
50
84
  // where an absolute path like `D:\...` is rejected as URL scheme `d:`.
51
85
  const backendUrl = pathToFileURL(props.backendCDKPath);
@@ -60,7 +94,7 @@ export class BlocksStack extends cdk.Stack {
60
94
  }
61
95
  }
62
96
  // Finalize BB config → S3 (after all BBs have registered their config)
63
- finalizeConfigRegistry(stack, stack.handler);
97
+ finalizeConfigRegistry(stack, stack.executionRole, getComputes(stack));
64
98
  new cdk.CfnOutput(stack, 'ApiUrl', { value: stack.apiUrl });
65
99
  addBlocksStackMetadata(stack);
66
100
  return stack;
@@ -79,6 +113,14 @@ export class Scope extends Construct {
79
113
  * tree walk.
80
114
  */
81
115
  root;
116
+ /**
117
+ * Compute assigned at this node. Applies to this block and is inherited by
118
+ * descendants (a nearer assignment wins). Covers both a handler assigned to a
119
+ * specific compute and a scope-level default for its subtree. Internal until
120
+ * the customer-facing surface exists.
121
+ * @internal
122
+ */
123
+ _compute;
82
124
  constructor(id, options) {
83
125
  const parent = options?.parent || globalThis.CURRENT_BLOCKS_STACK;
84
126
  super(parent, id);
@@ -115,6 +157,44 @@ export class Scope extends Construct {
115
157
  get executionRole() {
116
158
  return this.root.executionRole;
117
159
  }
160
+ /**
161
+ * The compute this block runs on: the nearest `_compute` assigned on this
162
+ * block or an ancestor scope, else the owning stack/backend's default compute.
163
+ *
164
+ * For any app that doesn't assign a compute, this always resolves to the
165
+ * default — so reads are a no-op refactor. `_compute` is internal
166
+ * (test/framework) until the customer-facing surface exists; there is no
167
+ * public option to set it yet.
168
+ */
169
+ get compute() {
170
+ for (let current = this; current; current = current.parent) {
171
+ const assigned = current._compute;
172
+ if (assigned)
173
+ return assigned;
174
+ }
175
+ const defaultCompute = this.root._defaultCompute;
176
+ if (!defaultCompute) {
177
+ throw new Error('Default compute not initialized — BlocksStack/BlocksBackend.create() must run before resolving `compute`.');
178
+ }
179
+ return defaultCompute;
180
+ }
181
+ /**
182
+ * The stack's default compute, **ignoring** any per-scope `_compute`
183
+ * assignment (unlike {@link compute}, which resolves the nearest assigned
184
+ * one). Use when a resource is a stack-level singleton that must bind to one
185
+ * deterministic compute regardless of the block's resolved compute — e.g.
186
+ * Realtime's shared WebSocket route integration, where one WebSocket API
187
+ * integrates to a single target and connection bookkeeping is compute-agnostic.
188
+ *
189
+ * @internal Not a customer surface; for framework/BB singleton infra only.
190
+ */
191
+ get defaultCompute() {
192
+ const defaultCompute = this.root._defaultCompute;
193
+ if (!defaultCompute) {
194
+ throw new Error('Default compute not initialized — BlocksStack/BlocksBackend.create() must run before resolving `defaultCompute`.');
195
+ }
196
+ return defaultCompute;
197
+ }
118
198
  /**
119
199
  * The backend entry file the owning BlocksStack/BlocksBackend runs — the
120
200
  * single handler entry shared across the whole app.
@@ -137,6 +217,16 @@ export class Scope extends Construct {
137
217
  }
138
218
  return name;
139
219
  }
220
+ /**
221
+ * The shared handler Lambda's CloudWatch log group (the default compute's).
222
+ * Resolves the same way as {@link handler} — via the owning
223
+ * BlocksStack/BlocksBackend. `bb-logger` uses this to reconfigure retention on
224
+ * the single, framework-owned group rather than creating a second one that
225
+ * would collide on the log-group name.
226
+ */
227
+ get handlerLogGroup() {
228
+ return this.root.handlerLogGroup;
229
+ }
140
230
  get fullId() {
141
231
  return computeScopeFullId(this);
142
232
  }
@@ -20,5 +20,6 @@
20
20
  * @internal
21
21
  */
22
22
  export { Compute } from './compute/compute.js';
23
+ export type { DefaultComputeFactory } from './compute/default-compute-factory.js';
23
24
  export { BLOCKS_NAMESPACE } from '../constants.js';
24
25
  //# sourceMappingURL=internal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/cdk/internal.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAG/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/cdk/internal.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,YAAY,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAGlF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -92,6 +92,6 @@ export interface ApiNamespaceClientOptions {
92
92
  * ```
93
93
  */
94
94
  export declare function ApiNamespaceClient<T extends Record<string, (...args: any[]) => any>>(name: string, options?: ApiNamespaceClientOptions): AsyncAPI<T>;
95
- export { ApiError, isBlocksError, hasAuthError, DEFAULT_API_ERROR_NAME } from '../errors.js';
95
+ export { ApiError, blocksError, isBlocksError, hasAuthError, DEFAULT_API_ERROR_NAME } from '../errors.js';
96
96
  export { Scope, type ScopeOptions } from '../common/index.js';
97
97
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC;AAChC,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC;AAiBhF,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,IAAI;KAChE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,IAAI,KAAK,MAAM,CAAC,GACzD,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACtC,KAAK;CACV,CAAC;AAoHF;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,iKAAiK;IACjK,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,wHAAwH;IACxH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6GAA6G;IAC7G,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,aAAa,GAAG,IAAI,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAC7F,6FAA6F;IAC7F,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;CACzC;AAID;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAErE;AAqBD;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,EAClF,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,yBAAyB,GAClC,QAAQ,CAAC,CAAC,CAAC,CAyDb;AAED,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC7F,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC;AAChC,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC;AAiBhF,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,IAAI;KAChE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,IAAI,KAAK,MAAM,CAAC,GACzD,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACtC,KAAK;CACV,CAAC;AAoHF;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,iKAAiK;IACjK,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,wHAAwH;IACxH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6GAA6G;IAC7G,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,aAAa,GAAG,IAAI,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAC7F,6FAA6F;IAC7F,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;CACzC;AAID;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAErE;AAqBD;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,EAClF,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,yBAAyB,GAClC,QAAQ,CAAC,CAAC,CAAC,CAyDb;AAED,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC1G,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -234,5 +234,5 @@ export function ApiNamespaceClient(name, options) {
234
234
  }
235
235
  });
236
236
  }
237
- export { ApiError, isBlocksError, hasAuthError, DEFAULT_API_ERROR_NAME } from '../errors.js';
237
+ export { ApiError, blocksError, isBlocksError, hasAuthError, DEFAULT_API_ERROR_NAME } from '../errors.js';
238
238
  export { Scope } from '../common/index.js';
@@ -34,6 +34,40 @@ export declare function preloadConfig(): Promise<void>;
34
34
  * Only sets env vars that aren't already set (won't override explicit env vars).
35
35
  */
36
36
  export declare function loadConfigToProcessEnv(): Promise<void>;
37
+ /**
38
+ * Whether a config load has resolved and cached a result.
39
+ *
40
+ * Returns `true` once `loadConfigFromS3()` has cached a config object — either a
41
+ * successful S3 load, a genuinely-empty `{}` config, or the no-bucket local-dev
42
+ * path (both of which cache `{}`). Returns `false` in the initial state AND
43
+ * after a transient not-found miss: the 404 path deliberately does NOT cache its
44
+ * empty result (see `loadConfigFromS3`), so a `false` return immediately after
45
+ * awaiting a load uniquely identifies the post-deploy S3 window where
46
+ * blocks-config.json isn't readable yet.
47
+ *
48
+ * Callers use this to tell a transient-empty load (retry on the next request)
49
+ * apart from a legitimately-config-less app (do nothing) without reaching into
50
+ * the module's private cache.
51
+ */
52
+ export declare function isConfigResolved(): boolean;
53
+ /**
54
+ * Sanitize a Blocks identifier into a valid config/env-var key segment:
55
+ * uppercase, with every non-alphanumeric character replaced by `_`.
56
+ *
57
+ * Config entries are loaded into `process.env` at runtime (see
58
+ * {@link loadConfigToProcessEnv}), so a key must be a valid env-var name. This
59
+ * is the single rule both sides of a key share: whoever *writes* a config key
60
+ * (`registerConfig(\`PREFIX_${sanitizeConfigKey(id)}\`, …)`) and whoever *reads*
61
+ * it (`getConfigSync(\`PREFIX_${sanitizeConfigKey(id)}\`)`) MUST go through this
62
+ * function so they reconstruct a byte-identical key — a hand-inlined variant
63
+ * that drifts silently misses the lookup at runtime.
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * registerConfig(this, `BLOCKS_QUEUE_URL_${sanitizeConfigKey(this.fullId)}`, url);
68
+ * ```
69
+ */
70
+ export declare function sanitizeConfigKey(id: string): string;
37
71
  /**
38
72
  * Reset the config cache. **For testing only.**
39
73
  */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/common/config.ts"],"names":[],"mappings":"AA4FA;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAM5D;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnD;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAO5D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAIxC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAEtG"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/common/config.ts"],"names":[],"mappings":"AAgGA;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAM5D;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnD;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAO5D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAIxC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAEtG"}
@@ -53,9 +53,13 @@ async function loadConfigFromS3() {
53
53
  || error?.Code === 'NoSuchKey'
54
54
  || error?.$metadata?.httpStatusCode === 404;
55
55
  if (isNotFound) {
56
- console.warn(`[Blocks] Config file not found in S3 (${bucket}/${key}), proceeding with empty config`);
57
- configCache = {};
58
- return configCache;
56
+ // Do NOT cache the empty result: a 404 right after deploy is usually the config file
57
+ // not being readable yet (the transient window before the BucketDeployment settles), not
58
+ // a genuinely config-less app. Caching {} here would poison the container for its whole
59
+ // lifetime. Returning without caching lets the next invocation re-fetch and pick up the
60
+ // real config once it's present. (Apps that truly have no config just re-check cheaply.)
61
+ console.warn(`[Blocks] Config file not found in S3 (${bucket}/${key}), proceeding with empty config (will retry on next request)`);
62
+ return {};
59
63
  }
60
64
  const msg = error instanceof Error ? error.message : String(error);
61
65
  throw new Error(`[Blocks] Failed to load config from S3 (${bucket}/${key}): ${msg}`);
@@ -138,6 +142,44 @@ export async function loadConfigToProcessEnv() {
138
142
  }
139
143
  }
140
144
  }
145
+ /**
146
+ * Whether a config load has resolved and cached a result.
147
+ *
148
+ * Returns `true` once `loadConfigFromS3()` has cached a config object — either a
149
+ * successful S3 load, a genuinely-empty `{}` config, or the no-bucket local-dev
150
+ * path (both of which cache `{}`). Returns `false` in the initial state AND
151
+ * after a transient not-found miss: the 404 path deliberately does NOT cache its
152
+ * empty result (see `loadConfigFromS3`), so a `false` return immediately after
153
+ * awaiting a load uniquely identifies the post-deploy S3 window where
154
+ * blocks-config.json isn't readable yet.
155
+ *
156
+ * Callers use this to tell a transient-empty load (retry on the next request)
157
+ * apart from a legitimately-config-less app (do nothing) without reaching into
158
+ * the module's private cache.
159
+ */
160
+ export function isConfigResolved() {
161
+ return configCache !== null;
162
+ }
163
+ /**
164
+ * Sanitize a Blocks identifier into a valid config/env-var key segment:
165
+ * uppercase, with every non-alphanumeric character replaced by `_`.
166
+ *
167
+ * Config entries are loaded into `process.env` at runtime (see
168
+ * {@link loadConfigToProcessEnv}), so a key must be a valid env-var name. This
169
+ * is the single rule both sides of a key share: whoever *writes* a config key
170
+ * (`registerConfig(\`PREFIX_${sanitizeConfigKey(id)}\`, …)`) and whoever *reads*
171
+ * it (`getConfigSync(\`PREFIX_${sanitizeConfigKey(id)}\`)`) MUST go through this
172
+ * function so they reconstruct a byte-identical key — a hand-inlined variant
173
+ * that drifts silently misses the lookup at runtime.
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * registerConfig(this, `BLOCKS_QUEUE_URL_${sanitizeConfigKey(this.fullId)}`, url);
178
+ * ```
179
+ */
180
+ export function sanitizeConfigKey(id) {
181
+ return id.toUpperCase().replace(/[^A-Z0-9]/g, '_');
182
+ }
141
183
  /**
142
184
  * Reset the config cache. **For testing only.**
143
185
  */
@@ -101,6 +101,25 @@ describe('config — S3 errors', () => {
101
101
  const result = await getConfig('ANY_KEY');
102
102
  assert.strictEqual(result, '', 'Should return empty string (empty config) on 404');
103
103
  });
104
+ it('does not cache a not-found result — a later call re-fetches once the config exists', async () => {
105
+ process.env.BLOCKS_CONFIG_BUCKET = 'test-bucket';
106
+ process.env.BLOCKS_CONFIG_KEY = 'blocks-config.json';
107
+ // Simulate the transient post-deploy window: the object isn't written yet on the first
108
+ // fetch, then becomes available. A not-found result must NOT be cached, or the container
109
+ // would be poisoned with empty config for its lifetime.
110
+ let call = 0;
111
+ const notFound = new Error('The specified key does not exist.');
112
+ notFound.name = 'NoSuchKey';
113
+ _setS3Fetcher(async () => {
114
+ call++;
115
+ if (call === 1)
116
+ throw notFound;
117
+ return JSON.stringify({ READY_KEY: 'ready-value' });
118
+ });
119
+ assert.strictEqual(await getConfig('READY_KEY'), '', 'first call sees the not-yet-written config as empty');
120
+ assert.strictEqual(await getConfig('READY_KEY'), 'ready-value', 'later call re-fetches once the config exists');
121
+ assert.strictEqual(call, 2, 'a not-found result must not be cached — S3 is retried');
122
+ });
104
123
  it('throws with clear message on S3 network error', async () => {
105
124
  process.env.BLOCKS_CONFIG_BUCKET = 'test-bucket';
106
125
  process.env.BLOCKS_CONFIG_KEY = 'blocks-config.json';
@@ -224,6 +224,14 @@ export interface BlocksStackProps extends StackProps {
224
224
  }
225
225
  export declare class BlocksStack {
226
226
  readonly id: string;
227
+ /**
228
+ * Path to the app's backend module (`props.backendCDKPath`). A typed contract for Building
229
+ * Blocks that co-bundle the backend at synth time and read it off
230
+ * `globalThis.CURRENT_BLOCKS_STACK` (the CDK `BlocksStack` / `BlocksBackend` set it). Declared
231
+ * here so those consumers can type against this shared `BlocksStack` contract — which the CDK
232
+ * `BlocksStack` / `BlocksBackend` implements — instead of `any`.
233
+ */
234
+ readonly backendModulePath: string;
227
235
  constructor(scope: Construct, id: string, props: BlocksStackProps);
228
236
  }
229
237
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAErE,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsGG;AAEH;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IACjC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,KAAK;IAChB,SAAgB,EAAE,EAAE,MAAM,CAAC;IAC3B,SAAgB,MAAM,EAAE,WAAW,CAAC;IAEpC,qEAAqE;IACrE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,2EAA2E;IAC3E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAE5B,kEAAkE;IAClE,OAAO,CAAC,MAAM,CAAC,WAAW,CAA8D;gBAE5E,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;IAiB9C;;;;;;;;OAQG;IACH,MAAM,CAAC,mBAAmB,IAAI;QAAE,MAAM,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE;IAejI,2CAA2C;IAC3C,MAAM,CAAC,cAAc,IAAI,IAAI;IAI7B,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;;;;;;;;;;OAUG;IACH,0BAA0B,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAOlH;;;;OAIG;IACH,wBAAwB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAIxD;;;;;;;;;;OAUG;IACH,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAIrD;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,SAAS,CAAC,mBAAmB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;CAapD;AA0CD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAE,UAUrE;AAED,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,qBAAa,WAAW;IACvB,SAAgB,EAAE,EAAE,MAAM,CAAC;gBACf,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB;CAGjE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAErE,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsGG;AAEH;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IACjC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,KAAK;IAChB,SAAgB,EAAE,EAAE,MAAM,CAAC;IAC3B,SAAgB,MAAM,EAAE,WAAW,CAAC;IAEpC,qEAAqE;IACrE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,2EAA2E;IAC3E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAE5B,kEAAkE;IAClE,OAAO,CAAC,MAAM,CAAC,WAAW,CAA8D;gBAE5E,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;IAiB9C;;;;;;;;OAQG;IACH,MAAM,CAAC,mBAAmB,IAAI;QAAE,MAAM,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE;IAejI,2CAA2C;IAC3C,MAAM,CAAC,cAAc,IAAI,IAAI;IAI7B,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;;;;;;;;;;OAUG;IACH,0BAA0B,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAOlH;;;;OAIG;IACH,wBAAwB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAIxD;;;;;;;;;;OAUG;IACH,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAIrD;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,SAAS,CAAC,mBAAmB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;CAapD;AA0CD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAE,UAUrE;AAED,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,qBAAa,WAAW;IACvB,SAAgB,EAAE,EAAE,MAAM,CAAC;IAC3B;;;;;;OAMG;IACH,SAAiB,iBAAiB,EAAE,MAAM,CAAC;gBAC/B,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB;CAGjE"}