@aws-blocks/core 0.4.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 (90) hide show
  1. package/README.md +12 -0
  2. package/dist/cdk/blocks-backend.d.ts +4 -1
  3. package/dist/cdk/blocks-backend.d.ts.map +1 -1
  4. package/dist/cdk/blocks-backend.js +56 -10
  5. package/dist/cdk/blocks-backend.test.js +71 -1
  6. package/dist/cdk/blocks-defaults.d.ts +11 -0
  7. package/dist/cdk/blocks-defaults.d.ts.map +1 -1
  8. package/dist/cdk/blocks-stack.test.js +23 -3
  9. package/dist/cdk/compute/compute.d.ts +80 -2
  10. package/dist/cdk/compute/compute.d.ts.map +1 -1
  11. package/dist/cdk/compute/compute.js +57 -3
  12. package/dist/cdk/config-registry.test.js +12 -0
  13. package/dist/cdk/dashboard-registry.d.ts +41 -0
  14. package/dist/cdk/dashboard-registry.d.ts.map +1 -0
  15. package/dist/cdk/dashboard-registry.js +61 -0
  16. package/dist/cdk/index.d.ts +67 -11
  17. package/dist/cdk/index.d.ts.map +1 -1
  18. package/dist/cdk/index.js +100 -18
  19. package/dist/cdk/internal.d.ts +3 -1
  20. package/dist/cdk/internal.d.ts.map +1 -1
  21. package/dist/cdk/internal.js +4 -1
  22. package/dist/cdk/tracer-registry.d.ts +31 -0
  23. package/dist/cdk/tracer-registry.d.ts.map +1 -0
  24. package/dist/cdk/tracer-registry.js +49 -0
  25. package/dist/cdk/vpc-requirements-registry.d.ts +33 -0
  26. package/dist/cdk/vpc-requirements-registry.d.ts.map +1 -0
  27. package/dist/cdk/vpc-requirements-registry.js +46 -0
  28. package/dist/cdk/vpc-types.d.ts +151 -0
  29. package/dist/cdk/vpc-types.d.ts.map +1 -0
  30. package/dist/cdk/vpc-types.js +3 -0
  31. package/dist/cdk/vpc.d.ts +59 -0
  32. package/dist/cdk/vpc.d.ts.map +1 -0
  33. package/dist/cdk/vpc.js +298 -0
  34. package/dist/cdk/vpc.test.d.ts +2 -0
  35. package/dist/cdk/vpc.test.d.ts.map +1 -0
  36. package/dist/cdk/vpc.test.js +285 -0
  37. package/dist/errors.d.ts +5 -0
  38. package/dist/errors.d.ts.map +1 -1
  39. package/dist/errors.js +5 -0
  40. package/dist/hosting.d.ts.map +1 -1
  41. package/dist/hosting.js +2 -0
  42. package/dist/hosting.test.js +39 -1
  43. package/dist/index.cdk.d.ts +2 -1
  44. package/dist/index.cdk.d.ts.map +1 -1
  45. package/dist/index.cdk.js +1 -1
  46. package/dist/lambda-handler.js +9 -2
  47. package/dist/lambda-handler.test.js +61 -1
  48. package/dist/raw-route.d.ts +15 -1
  49. package/dist/raw-route.d.ts.map +1 -1
  50. package/dist/raw-route.js +96 -12
  51. package/dist/raw-route.test.js +332 -1
  52. package/dist/scripts/dev-server.d.ts.map +1 -1
  53. package/dist/scripts/dev-server.js +11 -0
  54. package/dist/scripts/extract-ts-types.d.ts.map +1 -1
  55. package/dist/scripts/extract-ts-types.js +107 -23
  56. package/dist/scripts/extract-ts-types.test.js +225 -26
  57. package/dist/scripts/generate-spec.d.ts.map +1 -1
  58. package/dist/scripts/generate-spec.js +14 -5
  59. package/dist/scripts/generate-spec.test.js +93 -0
  60. package/dist/version.d.ts +1 -1
  61. package/dist/version.js +1 -1
  62. package/package.json +8 -1
  63. package/src/cdk/blocks-backend.test.ts +144 -60
  64. package/src/cdk/blocks-backend.ts +298 -239
  65. package/src/cdk/blocks-defaults.ts +12 -0
  66. package/src/cdk/blocks-stack.test.ts +32 -13
  67. package/src/cdk/compute/compute.ts +105 -3
  68. package/src/cdk/config-registry.test.ts +14 -0
  69. package/src/cdk/dashboard-registry.ts +68 -0
  70. package/src/cdk/index.ts +426 -298
  71. package/src/cdk/internal.ts +6 -2
  72. package/src/cdk/tracer-registry.ts +54 -0
  73. package/src/cdk/vpc-requirements-registry.ts +63 -0
  74. package/src/cdk/vpc-types.ts +158 -0
  75. package/src/cdk/vpc.test.ts +348 -0
  76. package/src/cdk/vpc.ts +336 -0
  77. package/src/errors.ts +5 -0
  78. package/src/hosting.test.ts +59 -1
  79. package/src/hosting.ts +3 -0
  80. package/src/index.cdk.ts +7 -0
  81. package/src/lambda-handler.test.ts +79 -1
  82. package/src/lambda-handler.ts +11 -2
  83. package/src/raw-route.test.ts +427 -1
  84. package/src/raw-route.ts +125 -12
  85. package/src/scripts/dev-server.ts +12 -1
  86. package/src/scripts/extract-ts-types.test.ts +228 -26
  87. package/src/scripts/extract-ts-types.ts +104 -20
  88. package/src/scripts/generate-spec.test.ts +101 -0
  89. package/src/scripts/generate-spec.ts +15 -5
  90. package/src/version.ts +1 -1
@@ -0,0 +1,285 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import * as assert from 'node:assert/strict';
4
+ import { describe, it } from 'node:test';
5
+ import * as cdk from 'aws-cdk-lib';
6
+ import { Template } from 'aws-cdk-lib/assertions';
7
+ import * as ec2 from 'aws-cdk-lib/aws-ec2';
8
+ import { Construct } from 'constructs';
9
+ import { anyRequirementNeedsVpc, finalizeVpc, getOrCreateVpc, getVpcContext, initializeVpc, setVpcContext, } from './vpc.js';
10
+ import { registerVpcRequirements } from './vpc-requirements-registry.js';
11
+ // A minimal stand-in for a BuildingBlockScope: finalizeVpc reads requirements
12
+ // from the central registry, and the real BuildingBlockScope base registers in
13
+ // its constructor. This fake does the same (register on construction) so it
14
+ // exercises the real pull-and-provision path without pulling every BB package
15
+ // into core's test graph. A `fullId` getter mirrors the real Scope so error
16
+ // messages that name the BB can be asserted.
17
+ class FakeBB extends Construct {
18
+ constructor(scope, id, reqs) {
19
+ super(scope, id);
20
+ registerVpcRequirements(this, reqs);
21
+ }
22
+ get fullId() {
23
+ return this.node.id;
24
+ }
25
+ }
26
+ /**
27
+ * Build a stack + VPC, optionally initialize the VPC context (so the endpoint
28
+ * SG can scope to the Lambda SG), add fake BBs, then run finalizeVpc.
29
+ */
30
+ function synthWith(bbs, opts) {
31
+ const app = new cdk.App();
32
+ const stack = new cdk.Stack(app, 'TestStack', { env: { account: '123456789012', region: 'us-east-1' } });
33
+ const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 2, natGateways: opts?.natGateways ?? 1 });
34
+ const options = {
35
+ network: vpc,
36
+ subnets: opts?.subnets,
37
+ provisionEndpoints: opts?.provisionEndpoints,
38
+ };
39
+ if (opts?.withContext !== false)
40
+ initializeVpc(stack, options);
41
+ bbs(stack);
42
+ finalizeVpc(stack, options);
43
+ return Template.fromStack(stack);
44
+ }
45
+ const IFACE = 'AWS::EC2::VPCEndpoint';
46
+ /** Count interface vs gateway endpoints in a synthesized template. */
47
+ function endpointCounts(template) {
48
+ const eps = template.findResources(IFACE);
49
+ let iface = 0;
50
+ let gateway = 0;
51
+ for (const ep of Object.values(eps)) {
52
+ const type = ep.Properties?.VpcEndpointType;
53
+ // Interface endpoints set VpcEndpointType: 'Interface'; gateway endpoints
54
+ // default the property (Gateway) and omit it in the synthesized template.
55
+ if (type === 'Interface')
56
+ iface += 1;
57
+ else
58
+ gateway += 1;
59
+ }
60
+ return { iface, gateway };
61
+ }
62
+ describe('finalizeVpc — endpoint provisioning', () => {
63
+ it('always provisions CloudWatch Logs (interface) and S3 (gateway), even with no BBs', () => {
64
+ const template = synthWith(() => { });
65
+ const { iface, gateway } = endpointCounts(template);
66
+ assert.equal(gateway, 1); // S3 gateway, always-on (free)
67
+ assert.equal(iface, 1); // Logs, always-on
68
+ template.hasResourceProperties(IFACE, {
69
+ VpcEndpointType: 'Interface',
70
+ ServiceName: 'com.amazonaws.us-east-1.logs',
71
+ });
72
+ // Exactly one gateway endpoint (S3). Its ServiceName synthesizes as a
73
+ // region-tokenized Fn::Join, so assert by type/count rather than a literal.
74
+ const gateways = template.findResources(IFACE, { Properties: { VpcEndpointType: 'Gateway' } });
75
+ assert.equal(Object.keys(gateways).length, 1, 'exactly one gateway endpoint (S3)');
76
+ // SSM is NOT always-on — it flows from BB requirements only.
77
+ const ssm = template.findResources(IFACE, {
78
+ Properties: { ServiceName: 'com.amazonaws.us-east-1.ssm' },
79
+ });
80
+ assert.equal(Object.keys(ssm).length, 0, 'no SSM endpoint without a BB that needs it');
81
+ });
82
+ it('provisions the union of BB-declared endpoints plus the always-on Logs + S3', () => {
83
+ const template = synthWith((scope) => {
84
+ new FakeBB(scope, 'Kv', { gatewayEndpoints: [ec2.GatewayVpcEndpointAwsService.DYNAMODB] });
85
+ new FakeBB(scope, 'Bucket', { gatewayEndpoints: [ec2.GatewayVpcEndpointAwsService.S3] });
86
+ new FakeBB(scope, 'Job', { interfaceEndpoints: [ec2.InterfaceVpcEndpointAwsService.SQS] });
87
+ new FakeBB(scope, 'Db', {
88
+ interfaceEndpoints: [
89
+ ec2.InterfaceVpcEndpointAwsService.SECRETS_MANAGER,
90
+ ec2.InterfaceVpcEndpointAwsService.RDS_DATA,
91
+ ],
92
+ });
93
+ });
94
+ const { iface, gateway } = endpointCounts(template);
95
+ // Gateways: DynamoDB + S3 (BB's S3 dedups with the always-on S3).
96
+ assert.equal(gateway, 2);
97
+ // Interfaces: SQS + Secrets Manager + RDS Data + always-on Logs.
98
+ assert.equal(iface, 4);
99
+ });
100
+ it('deduplicates endpoints requested by multiple BBs', () => {
101
+ const template = synthWith((scope) => {
102
+ new FakeBB(scope, 'Kv1', { gatewayEndpoints: [ec2.GatewayVpcEndpointAwsService.DYNAMODB] });
103
+ new FakeBB(scope, 'Kv2', { gatewayEndpoints: [ec2.GatewayVpcEndpointAwsService.DYNAMODB] });
104
+ new FakeBB(scope, 'Job1', { interfaceEndpoints: [ec2.InterfaceVpcEndpointAwsService.SQS] });
105
+ new FakeBB(scope, 'Job2', { interfaceEndpoints: [ec2.InterfaceVpcEndpointAwsService.SQS] });
106
+ });
107
+ const { iface, gateway } = endpointCounts(template);
108
+ // Two DynamoDB requests collapse to one; plus always-on S3 = 2 gateways.
109
+ assert.equal(gateway, 2);
110
+ // Two SQS requests collapse to one; plus always-on Logs = 2 interfaces.
111
+ assert.equal(iface, 2);
112
+ });
113
+ it('provisions SSM only when a BB declares it (and dedups multiple declarations)', () => {
114
+ const template = synthWith((scope) => {
115
+ new FakeBB(scope, 'AppSetting', { interfaceEndpoints: [ec2.InterfaceVpcEndpointAwsService.SSM] });
116
+ new FakeBB(scope, 'Auth', { interfaceEndpoints: [ec2.InterfaceVpcEndpointAwsService.SSM] });
117
+ });
118
+ const { iface } = endpointCounts(template);
119
+ // Two SSM requests collapse to one; plus always-on Logs = 2 interfaces.
120
+ assert.equal(iface, 2);
121
+ template.hasResourceProperties(IFACE, {
122
+ VpcEndpointType: 'Interface',
123
+ ServiceName: 'com.amazonaws.us-east-1.ssm',
124
+ });
125
+ });
126
+ it('provisions nothing when provisionEndpoints is false (but still validates requiresEgress)', () => {
127
+ const template = synthWith((scope) => {
128
+ new FakeBB(scope, 'Kv', { gatewayEndpoints: [ec2.GatewayVpcEndpointAwsService.DYNAMODB] });
129
+ }, { provisionEndpoints: false });
130
+ template.resourceCountIs(IFACE, 0);
131
+ });
132
+ it('scopes the interface-endpoint SG to 443 from the Blocks Lambda SG only', () => {
133
+ const template = synthWith((scope) => {
134
+ new FakeBB(scope, 'Job', { interfaceEndpoints: [ec2.InterfaceVpcEndpointAwsService.SQS] });
135
+ });
136
+ // A dedicated endpoint SG exists, described as Lambda-scoped, with a 443
137
+ // ingress rule sourced from another SG (the Lambda SG) rather than the whole
138
+ // VPC CIDR. We assert the rule is present (arrayWith) rather than the exact
139
+ // array, since CDK may add its own paired rule for the endpoint association.
140
+ const sgs = template.findResources('AWS::EC2::SecurityGroup', {
141
+ Properties: { GroupDescription: 'Blocks interface VPC endpoints — 443 from the Blocks Lambda only' },
142
+ });
143
+ assert.equal(Object.keys(sgs).length, 1, 'exactly one dedicated endpoint SG');
144
+ const sg = Object.values(sgs)[0];
145
+ const ingress = sg.Properties.SecurityGroupIngress ?? [];
146
+ const https = ingress.filter((r) => r.FromPort === 443 && r.ToPort === 443);
147
+ assert.equal(https.length, 1, 'exactly one 443 ingress rule');
148
+ // Must NOT be open to a CIDR (that would be the broad default we're avoiding).
149
+ assert.equal(https[0].CidrIp, undefined, '443 ingress is SG-sourced, not CIDR-open');
150
+ });
151
+ });
152
+ describe('finalizeVpc — requiresEgress validation', () => {
153
+ it('passes when the runtime placement provides egress', () => {
154
+ // Default placement is private-with-egress, which provides egress.
155
+ assert.doesNotThrow(() => synthWith((scope) => {
156
+ new FakeBB(scope, 'Dsql', { requiresEgress: true });
157
+ }));
158
+ });
159
+ it('throws an actionable, BB-named error when the placement has no egress', () => {
160
+ // Place the runtime in isolated subnets; a BB needing egress cannot be served.
161
+ assert.throws(() => synthWith((scope) => {
162
+ new FakeBB(scope, 'Dsql', { requiresEgress: true });
163
+ }, { subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED } }), /Dsql requires its runtime to reach the internet.*no egress/s);
164
+ });
165
+ it('does not validate a BB that does not require egress', () => {
166
+ // A BB with no egress need is fine in isolated subnets.
167
+ assert.doesNotThrow(() => synthWith((scope) => {
168
+ new FakeBB(scope, 'Bb', {});
169
+ }, { subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED } }));
170
+ });
171
+ });
172
+ describe('initializeVpc — Lambda placement guard', () => {
173
+ function init(natGateways, subnets) {
174
+ const app = new cdk.App();
175
+ const stack = new cdk.Stack(app, 'S', { env: { account: '123456789012', region: 'us-east-1' } });
176
+ const subnetConfiguration = natGateways === 0
177
+ ? [{ name: 'isolated', subnetType: ec2.SubnetType.PRIVATE_ISOLATED, cidrMask: 24 }]
178
+ : undefined;
179
+ const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 2, natGateways, subnetConfiguration });
180
+ return () => initializeVpc(stack, { network: vpc, subnets });
181
+ }
182
+ it('throws an actionable error when defaulting to private-with-egress but the VPC has none', () => {
183
+ assert.throws(init(0), /no private-with-egress subnets.*NAT gateway/s);
184
+ });
185
+ it('does not throw when the VPC has a private-with-egress tier', () => {
186
+ assert.doesNotThrow(init(1));
187
+ });
188
+ it('honors an explicit isolated placement without the private-with-egress guard', () => {
189
+ // Caller explicitly chose isolated; the default-path guard must not fire.
190
+ assert.doesNotThrow(init(0, { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }));
191
+ });
192
+ });
193
+ describe('VpcContext.selectSubnets — instructive resolution', () => {
194
+ function contextFor(natGateways) {
195
+ const app = new cdk.App();
196
+ const stack = new cdk.Stack(app, 'S', { env: { account: '123456789012', region: 'us-east-1' } });
197
+ const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 2, natGateways });
198
+ // With natGateways: 0 CDK still creates the default public+private config,
199
+ // but the private tier becomes isolated (no NAT). Build an explicit
200
+ // isolated-only VPC to exercise the "no isolated" and "no egress" cases.
201
+ return initializeVpc(stack, { network: vpc, subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS } });
202
+ }
203
+ it('returns the requested role when the VPC has it', () => {
204
+ const ctx = contextFor(1);
205
+ const sel = ctx.selectSubnets({ fullId: 'app/db' }, 'private-with-egress');
206
+ assert.equal(sel.subnetType, ec2.SubnetType.PRIVATE_WITH_EGRESS);
207
+ });
208
+ it('falls back to an explicit fallback role when the requested role is absent', () => {
209
+ const ctx = contextFor(1); // has public + private-with-egress, no isolated
210
+ const sel = ctx.selectSubnets({ fullId: 'app/db' }, 'isolated', { fallback: 'private-with-egress' });
211
+ assert.equal(sel.subnetType, ec2.SubnetType.PRIVATE_WITH_EGRESS);
212
+ });
213
+ it('throws a BB-named error when neither the role nor its fallback exists', () => {
214
+ const ctx = contextFor(1); // no isolated tier, and no public fallback requested that helps
215
+ assert.throws(() => ctx.selectSubnets({ fullId: 'app/db' }, 'isolated'), /app\/db needs a 'isolated' subnet.*has none/s);
216
+ });
217
+ });
218
+ // We can't fully test CDK constructs without a Stack, but we can test
219
+ // the getVpcContext logic with mock constructs.
220
+ describe('VPC utilities', () => {
221
+ it('getVpcContext returns undefined when no context set', () => {
222
+ const fakeScope = { node: { scope: undefined } };
223
+ assert.equal(getVpcContext(fakeScope), undefined);
224
+ });
225
+ it('getVpcContext walks up the scope tree', () => {
226
+ const vpcContext = { vpc: 'mock-vpc', computeSecurityGroup: 'mock-sg', computeSubnets: {} };
227
+ const parent = { node: { scope: undefined } };
228
+ setVpcContext(parent, vpcContext);
229
+ const child = { node: { scope: parent } };
230
+ assert.equal(getVpcContext(child), vpcContext);
231
+ });
232
+ it('setVpcContext stores context on the scope', () => {
233
+ const fakeScope = { node: { scope: undefined } };
234
+ const vpcContext = { vpc: 'mock-vpc', computeSecurityGroup: 'mock-sg', computeSubnets: {} };
235
+ setVpcContext(fakeScope, vpcContext);
236
+ assert.equal(getVpcContext(fakeScope), vpcContext);
237
+ });
238
+ });
239
+ describe('lazy VPC derivation', () => {
240
+ function stackWith(bbs) {
241
+ const app = new cdk.App();
242
+ const stack = new cdk.Stack(app, 'LazyStack', { env: { account: '123456789012', region: 'us-east-1' } });
243
+ bbs(stack);
244
+ return { stack, scope: stack };
245
+ }
246
+ it('anyRequirementNeedsVpc is false for BBs that only declare endpoints', () => {
247
+ const { scope } = stackWith((s) => {
248
+ new FakeBB(s, 'Kv', { gatewayEndpoints: [ec2.GatewayVpcEndpointAwsService.DYNAMODB] });
249
+ new FakeBB(s, 'Job', { interfaceEndpoints: [ec2.InterfaceVpcEndpointAwsService.SQS] });
250
+ });
251
+ assert.equal(anyRequirementNeedsVpc(scope), false);
252
+ });
253
+ it('anyRequirementNeedsVpc is true when a BB declares requiresVpc', () => {
254
+ const { scope } = stackWith((s) => {
255
+ new FakeBB(s, 'Kv', { gatewayEndpoints: [ec2.GatewayVpcEndpointAwsService.DYNAMODB] });
256
+ new FakeBB(s, 'Container', { requiresVpc: true });
257
+ });
258
+ assert.equal(anyRequirementNeedsVpc(scope), true);
259
+ });
260
+ it('getOrCreateVpc returns the same VPC on repeated calls (singleton)', () => {
261
+ const { scope } = stackWith(() => { });
262
+ const a = getOrCreateVpc(scope);
263
+ const b = getOrCreateVpc(scope);
264
+ assert.equal(a, b, 'lazy VPC is a per-stack singleton');
265
+ });
266
+ it('a derived VPC + finalizeVpc provisions endpoints for a requiresVpc app', () => {
267
+ const app = new cdk.App();
268
+ const stack = new cdk.Stack(app, 'DerivedStack', { env: { account: '123456789012', region: 'us-east-1' } });
269
+ new FakeBB(stack, 'Container', {
270
+ requiresVpc: true,
271
+ interfaceEndpoints: [ec2.InterfaceVpcEndpointAwsService.SQS],
272
+ });
273
+ assert.equal(anyRequirementNeedsVpc(stack), true);
274
+ const vpc = getOrCreateVpc(stack);
275
+ const options = { network: vpc };
276
+ initializeVpc(stack, options);
277
+ finalizeVpc(stack, options);
278
+ const template = Template.fromStack(stack);
279
+ // SQS (from the BB) + always-on CloudWatch Logs interface endpoints, plus
280
+ // the always-on S3 gateway endpoint.
281
+ const { iface, gateway } = endpointCounts(template);
282
+ assert.equal(iface, 2, 'SQS + Logs');
283
+ assert.equal(gateway, 1, 'S3 gateway');
284
+ });
285
+ });
package/dist/errors.d.ts CHANGED
@@ -44,6 +44,11 @@ export declare class ApiError extends Error {
44
44
  * when `retriable === true`; non-retriable errors (expired session,
45
45
  * tampered envelope, too-many-attempts lockouts) require restarting the
46
46
  * flow. Defaults to `false` when unspecified.
47
+ *
48
+ * This marks whether the *kind* of failure is retriable in principle, not a
49
+ * guarantee that a given retry will succeed — e.g. an optimistic-lock
50
+ * conflict against a missing row is flagged retriable, yet a blind retry
51
+ * fails identically.
47
52
  */
48
53
  readonly retriable: boolean;
49
54
  constructor(message: string, status: number, options?: {
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,aAAa,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,QAAS,SAAQ,KAAK;IAClC,wBAAwB;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;gBAEhB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE;CAM9G;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,GAAG;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,CAE7F;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAIhE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,SAAS,MAAM,EAC9E,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EAC3B,IAAI,EAAE,CAAC,GACL,KAAK,IAAI,CAAC,GAAG;IAAE,SAAS,EAAE,CAAC,CAAA;CAAE,CAE/B"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,aAAa,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,QAAS,SAAQ,KAAK;IAClC,wBAAwB;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;gBAEhB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE;CAM9G;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,GAAG;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,CAE7F;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAIhE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,SAAS,MAAM,EAC9E,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EAC3B,IAAI,EAAE,CAAC,GACL,KAAK,IAAI,CAAC,GAAG;IAAE,SAAS,EAAE,CAAC,CAAA;CAAE,CAE/B"}
package/dist/errors.js CHANGED
@@ -46,6 +46,11 @@ export class ApiError extends Error {
46
46
  * when `retriable === true`; non-retriable errors (expired session,
47
47
  * tampered envelope, too-many-attempts lockouts) require restarting the
48
48
  * flow. Defaults to `false` when unspecified.
49
+ *
50
+ * This marks whether the *kind* of failure is retriable in principle, not a
51
+ * guarantee that a given retry will succeed — e.g. an optimistic-lock
52
+ * conflict against a missing row is flagged retriable, yet a blind retry
53
+ * fails identically.
49
54
  */
50
55
  retriable;
51
56
  constructor(message, status, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"hosting.d.ts","sourceRoot":"","sources":["../src/hosting.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hosting.d.ts","sourceRoot":"","sources":["../src/hosting.ts"],"names":[],"mappings":"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"}
package/dist/hosting.js CHANGED
@@ -365,6 +365,8 @@ export class Hosting extends Construct {
365
365
  for (const dep of assetDeployments) {
366
366
  configDeployment.node.addDependency(dep);
367
367
  }
368
+ // Delay route cutover until resolved config replaces the static placeholder.
369
+ hosting.addBuildAssetDependency(configDeployment);
368
370
  }
369
371
  // ── 9. Register public origin + CORS hosting origin into S3 config ──
370
372
  // The Handler no longer depends on the BucketDeployment, so including
@@ -12,7 +12,7 @@ import { App, Duration, Stack } from 'aws-cdk-lib';
12
12
  import { Match, Template } from 'aws-cdk-lib/assertions';
13
13
  import { BLOCKS_RPC_PREFIX } from './constants.js';
14
14
  import { Hosting } from './hosting.js';
15
- import { clearRouteRegistry, registerRoute } from './raw-route.js';
15
+ import { clearRouteRegistry, compilePath, registerRoute } from './raw-route.js';
16
16
  // ================================================================
17
17
  // Hosting construct tests
18
18
  //
@@ -552,6 +552,38 @@ describe('Hosting', () => {
552
552
  assert.ok(patterns.includes('/health'), 'Should have /health behavior for RawRoute');
553
553
  assert.ok(patterns.includes('/users/*'), 'Should have /users/* behavior for parameterized RawRoute');
554
554
  });
555
+ it('adds a CloudFront behavior for a route another core copy registered', () => {
556
+ createSpaBuildOutput(tmpDir);
557
+ // Synth has the same split as dispatch: a bundle can hold more than one
558
+ // copy of @aws-blocks/core, and this loop reads whichever route table
559
+ // its own copy owns. Register the way a second copy would — straight
560
+ // into the shared state, not through this copy's registerRoute() — and
561
+ // the behavior must still be emitted. With a module-local registry it
562
+ // never is, and the route 404s at CloudFront before Lambda is reached.
563
+ const REGISTRY_KEY = '__AWS_BLOCKS_RAW_ROUTE_REGISTRY_V1__';
564
+ const state = globalThis[REGISTRY_KEY];
565
+ assert.ok(state, `route registry state must live on globalThis['${REGISTRY_KEY}']`);
566
+ const { pattern, paramNames } = compilePath('/from-other-copy');
567
+ state.routes.push({
568
+ method: 'GET',
569
+ path: '/from-other-copy',
570
+ pattern,
571
+ paramNames,
572
+ handler: async () => { },
573
+ });
574
+ const app = new App();
575
+ const stack = new Stack(app, 'ForeignRouteBehaviorStack');
576
+ new Hosting(stack, 'Hosting', {
577
+ root: tmpDir,
578
+ api: MOCK_API,
579
+ });
580
+ const template = Template.fromStack(stack);
581
+ const distributions = template.findResources('AWS::CloudFront::Distribution');
582
+ const distKeys = Object.keys(distributions);
583
+ const distConfig = distributions[distKeys[0]].Properties.DistributionConfig;
584
+ const patterns = (distConfig.CacheBehaviors ?? []).map((b) => b.PathPattern);
585
+ assert.ok(patterns.includes('/from-other-copy'), `synth must see routes from every core copy, got: ${JSON.stringify(patterns)}`);
586
+ });
555
587
  it('proxies the reserved /aws-blocks/auth subtree with a single behavior', () => {
556
588
  createSpaBuildOutput(tmpDir);
557
589
  // A route under the auth subtree (as the auth runtime would mount) must
@@ -1182,6 +1214,12 @@ describe('Hosting', () => {
1182
1214
  const assetDeps = dependsOn.filter((d) => /AssetDeployment/.test(d));
1183
1215
  assert.ok(assetDeps.length >= 1, `BlocksConfigDeployment must DependsOn the asset deployment(s); ` +
1184
1216
  `found DependsOn=${JSON.stringify(dependsOn)}`);
1217
+ const routeCutoverId = Object.entries(tpl.Resources).find(([id, resource]) => resource.Type === 'AWS::CloudFormation::CustomResource' &&
1218
+ /RouteStoreKeys/.test(id))?.[0];
1219
+ assert.ok(routeCutoverId, 'expected a RouteStoreKeys cutover resource');
1220
+ const routeCutoverDeps = tpl.Resources[routeCutoverId].DependsOn ?? [];
1221
+ assert.ok(routeCutoverDeps.includes(configId), `RouteStoreKeys must DependsOn BlocksConfigDeployment; ` +
1222
+ `found DependsOn=${JSON.stringify(routeCutoverDeps)}`);
1185
1223
  });
1186
1224
  });
1187
1225
  // ── value() integration ─────────────────────────────────────────
@@ -1,6 +1,7 @@
1
1
  export { type ConfigValue, config, DEFAULT_CONFIG_PARAMETER_PREFIX, DEFAULT_SECRET_PARAMETER_PREFIX, isConfig, isManagedValue, isSecret, type ManagedValue, type SecretValue, secret, type ValueKind, } from '@aws-blocks/hosting';
2
2
  export { type ApiHandler, ApiNamespace, type BlocksContext } from './api.js';
3
- export { BlocksBackend, type BlocksBackendProps, type BlocksDefaults, BlocksPresets, BlocksStack, type BlocksThrottling, blocksNodejsBundling, type CoreBlocksBackendProps, type CoreBlocksStackProps, DEFAULT_NODE_RUNTIME, ensureApiGatewayAccount, finalizeConfigRegistry, getConfigLocation, registerConfig, SandboxDisableDeletionProtection, Scope, SHARED_HANDLER_TIMEOUT_SECONDS, synthGuard, } from './cdk/index.js';
3
+ export type { BlocksVpcOptions, ScopeOptions, SubnetRole, VpcContext, VpcRequirements } from './cdk/index.js';
4
+ export { BlocksBackend, type BlocksBackendProps, type BlocksDefaults, BlocksPresets, BlocksStack, type BlocksThrottling, BuildingBlockScope, blocksNodejsBundling, type CoreBlocksBackendProps, type CoreBlocksStackProps, DEFAULT_NODE_RUNTIME, ensureApiGatewayAccount, finalizeConfigRegistry, finalizeDashboards, finalizeTracing, getConfigLocation, getVpcContext, registerConfig, registerDashboardFinalizer, registerTracer, SandboxDisableDeletionProtection, Scope, SHARED_HANDLER_TIMEOUT_SECONDS, synthGuard, } from './cdk/index.js';
4
5
  export { _resetConfigCache, getConfig, getConfigSync, loadConfigToProcessEnv, preloadConfig } from './common/config.js';
5
6
  export { BlocksStackProps } from './common/index.js';
6
7
  export { _resetSdkRegistry, getAllSdkIdentifiers, getSdkIdentifiers, registerSdkIdentifiers, } from './common/sdk-registry.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.cdk.d.ts","sourceRoot":"","sources":["../src/index.cdk.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,WAAW,EAChB,MAAM,EACN,+BAA+B,EAC/B,+BAA+B,EAC/B,QAAQ,EACR,cAAc,EACd,QAAQ,EACR,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,MAAM,EACN,KAAK,SAAS,GACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,UAAU,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAC7E,OAAO,EACN,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,aAAa,EACb,WAAW,EACX,KAAK,gBAAgB,EACrB,oBAAoB,EACpB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,iBAAiB,EACjB,cAAc,EACd,gCAAgC,EAChC,KAAK,EACL,8BAA8B,EAC9B,UAAU,GACV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,aAAa,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EACN,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,GACtB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,sBAAsB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzG,OAAO,EACN,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,OAAO,EACP,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,gBAAgB,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EACN,wBAAwB,EACxB,KAAK,YAAY,EACjB,WAAW,EACX,KAAK,gBAAgB,EACrB,QAAQ,EACR,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,KAAK,UAAU,EACf,QAAQ,EACR,cAAc,EACd,KAAK,eAAe,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,KAAK,eAAe,EACpB,aAAa,EACb,mBAAmB,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,8BAA8B,EAC9B,8BAA8B,EAC9B,yBAAyB,EACzB,yBAAyB,GACzB,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.cdk.d.ts","sourceRoot":"","sources":["../src/index.cdk.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,WAAW,EAChB,MAAM,EACN,+BAA+B,EAC/B,+BAA+B,EAC/B,QAAQ,EACR,cAAc,EACd,QAAQ,EACR,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,MAAM,EACN,KAAK,SAAS,GACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,UAAU,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAC7E,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC9G,OAAO,EACN,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,aAAa,EACb,WAAW,EACX,KAAK,gBAAgB,EACrB,kBAAkB,EAClB,oBAAoB,EACpB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,0BAA0B,EAC1B,cAAc,EACd,gCAAgC,EAChC,KAAK,EACL,8BAA8B,EAC9B,UAAU,GACV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,aAAa,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EACN,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,GACtB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,sBAAsB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzG,OAAO,EACN,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,OAAO,EACP,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,gBAAgB,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EACN,wBAAwB,EACxB,KAAK,YAAY,EACjB,WAAW,EACX,KAAK,gBAAgB,EACrB,QAAQ,EACR,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,KAAK,UAAU,EACf,QAAQ,EACR,cAAc,EACd,KAAK,eAAe,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,KAAK,eAAe,EACpB,aAAa,EACb,mBAAmB,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,8BAA8B,EAC9B,8BAA8B,EAC9B,yBAAyB,EACzB,yBAAyB,GACzB,MAAM,oBAAoB,CAAC"}
package/dist/index.cdk.js CHANGED
@@ -5,7 +5,7 @@
5
5
  // getConfig (backend config loader, above) owns that name here.
6
6
  export { config, DEFAULT_CONFIG_PARAMETER_PREFIX, DEFAULT_SECRET_PARAMETER_PREFIX, isConfig, isManagedValue, isSecret, secret, } from '@aws-blocks/hosting';
7
7
  export { ApiNamespace } from './api.js';
8
- export { BlocksBackend, BlocksPresets, BlocksStack, blocksNodejsBundling, DEFAULT_NODE_RUNTIME, ensureApiGatewayAccount, finalizeConfigRegistry, getConfigLocation, registerConfig, SandboxDisableDeletionProtection, Scope, SHARED_HANDLER_TIMEOUT_SECONDS, synthGuard, } from './cdk/index.js';
8
+ export { BlocksBackend, BlocksPresets, BlocksStack, BuildingBlockScope, blocksNodejsBundling, DEFAULT_NODE_RUNTIME, ensureApiGatewayAccount, finalizeConfigRegistry, finalizeDashboards, finalizeTracing, getConfigLocation, getVpcContext, registerConfig, registerDashboardFinalizer, registerTracer, SandboxDisableDeletionProtection, Scope, SHARED_HANDLER_TIMEOUT_SECONDS, synthGuard, } from './cdk/index.js';
9
9
  export { _resetConfigCache, getConfig, getConfigSync, loadConfigToProcessEnv, preloadConfig } from './common/config.js';
10
10
  export { _resetSdkRegistry, getAllSdkIdentifiers, getSdkIdentifiers, registerSdkIdentifiers, } from './common/sdk-registry.js';
11
11
  export { BLOCKS_AUTH_PREFIX, BLOCKS_RPC_PREFIX } from './constants.js';
@@ -4,7 +4,7 @@
4
4
  import { AsyncLocalStorage } from 'node:async_hooks';
5
5
  import { ApiError } from './errors.js';
6
6
  import { BLOCKS_RPC_PREFIX } from './constants.js';
7
- import { matchRoute, lockRouteRegistry } from './raw-route.js';
7
+ import { matchRoute, lockRouteRegistry, getRegisteredRoutes, getLoadedCoreCopies } from './raw-route.js';
8
8
  import { registerBuiltinRoutes } from './builtin-routes.js';
9
9
  import { loadConfigToProcessEnv, isConfigResolved } from './common/config.js';
10
10
  import { parseRpcRequest, successResponse, errorResponse, errorResponseFromCatch, methodNotFoundResponse, } from './rpc.js';
@@ -469,8 +469,15 @@ function createHandler(backend) {
469
469
  if (matched) {
470
470
  return handleRawRoute(event, matched.route, matched.params, corsHeaders, signal);
471
471
  }
472
- // No RawRoute matched and path is not the RPC endpoint — return 404
472
+ // No RawRoute matched and path is not the RPC endpoint — return 404.
473
+ // Log it: an unmatched route used to be entirely silent, which is what
474
+ // made a split route registry (duplicate @aws-blocks/core copies)
475
+ // undiagnosable from CloudWatch alone. The path is already in the API
476
+ // Gateway access logs, so this adds no new category of data.
473
477
  if (!requestPath.startsWith(BLOCKS_RPC_PREFIX)) {
478
+ const copies = getLoadedCoreCopies();
479
+ const copiesNote = copies > 1 ? ` — ${copies} copies of @aws-blocks/core are loaded` : '';
480
+ console.error(`No RawRoute matched ${httpMethod} ${requestPath} (${getRegisteredRoutes().length} routes registered)${copiesNote}`);
474
481
  return {
475
482
  statusCode: 404,
476
483
  headers: {
@@ -3,7 +3,7 @@
3
3
  import { describe, it, beforeEach } from 'node:test';
4
4
  import assert from 'node:assert';
5
5
  import { createLambdaHandler, _resetCorsPatterns, requestCookies, isApiGatewayHttpEvent, computeHttpDeadlineMs, classifyEvent, buildEventUrl, isLoopbackForwardedHost, TransientConfigError } from './lambda-handler.js';
6
- import { registerRoute, clearRouteRegistry } from './raw-route.js';
6
+ import { registerRoute, clearRouteRegistry, getRegisteredRoutes } from './raw-route.js';
7
7
  import { decodeRpcResponse } from './rpc.js';
8
8
  import { _resetConfigCache, _setS3Fetcher } from './common/config.js';
9
9
  beforeEach(() => {
@@ -353,6 +353,66 @@ describe('createLambdaHandler — RawRoute body handling', () => {
353
353
  });
354
354
  });
355
355
  // ── Cookie extraction tests ─────────────────────────────────────────────────
356
+ // ── Unmatched RawRoute diagnostics ──────────────────────────────────────────
357
+ //
358
+ // A request that matches no RawRoute used to return 404 without a trace in
359
+ // CloudWatch, which is what made the duplicate-core-copy bug invisible.
360
+ describe('createLambdaHandler — unmatched RawRoute diagnostics', () => {
361
+ /** Run `fn` with console.error captured; returns the collected lines. */
362
+ async function captureErrors(fn) {
363
+ const lines = [];
364
+ const original = console.error;
365
+ console.error = (...args) => {
366
+ lines.push(args.map((a) => String(a)).join(' '));
367
+ };
368
+ try {
369
+ await fn();
370
+ }
371
+ finally {
372
+ console.error = original;
373
+ }
374
+ return lines;
375
+ }
376
+ it('logs method, path and route count when no RawRoute matches', async () => {
377
+ registerRoute({ method: 'GET', path: '/known', handler: async (ctx) => ctx.response.send({ ok: true }) });
378
+ let result;
379
+ const logged = await captureErrors(async () => {
380
+ result = await invoke({}, makeEvent({ httpMethod: 'GET', path: '/unknown', body: null }));
381
+ });
382
+ assert.strictEqual(result.statusCode, 404);
383
+ // The count must match the registry the dispatcher actually consulted —
384
+ // a "0 routes registered" line is the fingerprint of a split registry.
385
+ const expectedCount = getRegisteredRoutes().length;
386
+ assert.ok(expectedCount > 0, 'precondition: routes are registered');
387
+ assert.ok(logged.some((line) => line.includes('No RawRoute matched GET /unknown') &&
388
+ line.includes(`${expectedCount} routes registered`)), `expected a diagnostic for the unmatched route, got: ${JSON.stringify(logged)}`);
389
+ });
390
+ it('does not log when a RawRoute matches', async () => {
391
+ registerRoute({ method: 'GET', path: '/known', handler: async (ctx) => ctx.response.send({ ok: true }) });
392
+ const logged = await captureErrors(async () => {
393
+ const result = await invoke({}, makeEvent({ httpMethod: 'GET', path: '/known', body: null }));
394
+ assert.strictEqual(result.statusCode, 200);
395
+ });
396
+ assert.deepStrictEqual(logged, []);
397
+ });
398
+ it('names duplicate core copies as the likely cause when more than one is loaded', async () => {
399
+ const REGISTRY_KEY = '__AWS_BLOCKS_RAW_ROUTE_REGISTRY_V1__';
400
+ const state = globalThis[REGISTRY_KEY];
401
+ assert.ok(state, `route registry state must live on globalThis['${REGISTRY_KEY}']`);
402
+ const originalCopies = state.copies;
403
+ state.copies = 2;
404
+ try {
405
+ const logged = await captureErrors(async () => {
406
+ const result = await invoke({}, makeEvent({ httpMethod: 'GET', path: '/unknown', body: null }));
407
+ assert.strictEqual(result.statusCode, 404);
408
+ });
409
+ assert.ok(logged.some((line) => line.includes('2 copies of @aws-blocks/core are loaded')), `expected the copy count in the diagnostic, got: ${JSON.stringify(logged)}`);
410
+ }
411
+ finally {
412
+ state.copies = originalCopies;
413
+ }
414
+ });
415
+ });
356
416
  describe('createLambdaHandler — cookie extraction', () => {
357
417
  it('extracts cookies from lowercase "cookie" header (API Gateway v2)', async () => {
358
418
  let capturedCookies = '';
@@ -72,6 +72,16 @@ export interface RegisteredRoute {
72
72
  paramNames: string[];
73
73
  handler: (context: BlocksContext) => Promise<void>;
74
74
  }
75
+ /**
76
+ * Number of `@aws-blocks/core` copies taking part in the shared route registry.
77
+ *
78
+ * `1` for a healthy install. A higher number means the dependency tree carries
79
+ * duplicates — routes still work (the registry is shared), but it is worth
80
+ * reporting in diagnostics.
81
+ *
82
+ * **Internal.** Not re-exported from the package entry point.
83
+ */
84
+ export declare function getLoadedCoreCopies(): number;
75
85
  /** Prevent further route registration. Call after initialization is complete. */
76
86
  export declare function lockRouteRegistry(): void;
77
87
  /** Re-allow route registration (useful in tests after lock). */
@@ -92,7 +102,11 @@ export declare function registerRoute(options: RawRouteOptions & {
92
102
  }): void;
93
103
  /** Return a read-only snapshot of all registered routes. */
94
104
  export declare function getRegisteredRoutes(): readonly RegisteredRoute[];
95
- /** Remove all registered routes and unlock registration (used by tests). */
105
+ /**
106
+ * Remove all registered routes and unlock registration (used by tests).
107
+ *
108
+ * Leaves the copy counter alone — it tracks module copies, not routes.
109
+ */
96
110
  export declare function clearRouteRegistry(): void;
97
111
  /**
98
112
  * Match an incoming HTTP request against registered routes.
@@ -1 +1 @@
1
- {"version":3,"file":"raw-route.d.ts","sourceRoot":"","sources":["../src/raw-route.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKrD,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1F,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,UAAU,CAAC;IACnB;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc;;CAEjB,CAAC;AAIX;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAc1E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,CAEjG;AAID,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD;AAOD,iFAAiF;AACjF,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AAED,gEAAgE;AAChE,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAuC/E;AAED,4DAA4D;AAC5D,wBAAgB,mBAAmB,IAAI,SAAS,eAAe,EAAE,CAEhE;AAED,4EAA4E;AAC5E,wBAAgB,kBAAkB,IAAI,IAAI,CAGzC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX;IAAE,KAAK,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,IAAI,CAoBnE;AA6BD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CAgEnF"}
1
+ {"version":3,"file":"raw-route.d.ts","sourceRoot":"","sources":["../src/raw-route.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKrD,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1F,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,UAAU,CAAC;IACnB;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc;;CAEjB,CAAC;AAIX;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAc1E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,CAEjG;AAID,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD;AAmGD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAID,iFAAiF;AACjF,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AAED,gEAAgE;AAChE,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAwC/E;AAED,4DAA4D;AAC5D,wBAAgB,mBAAmB,IAAI,SAAS,eAAe,EAAE,CAEhE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAIzC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX;IAAE,KAAK,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,IAAI,CAoBnE;AA6BD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CAgEnF"}