@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.
- package/README.md +13 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +32 -0
- package/dist/api.test.js +22 -0
- package/dist/bb-utils.d.ts +1 -0
- package/dist/bb-utils.d.ts.map +1 -1
- package/dist/bb-utils.js +3 -0
- package/dist/cdk/apigateway-account.d.ts +33 -0
- package/dist/cdk/apigateway-account.d.ts.map +1 -0
- package/dist/cdk/apigateway-account.js +60 -0
- package/dist/cdk/blocks-backend.d.ts +43 -9
- package/dist/cdk/blocks-backend.d.ts.map +1 -1
- package/dist/cdk/blocks-backend.js +69 -73
- package/dist/cdk/blocks-backend.test.js +78 -69
- package/dist/cdk/blocks-defaults.d.ts +92 -2
- package/dist/cdk/blocks-defaults.d.ts.map +1 -1
- package/dist/cdk/blocks-defaults.js +22 -2
- package/dist/cdk/blocks-defaults.test.js +21 -2
- package/dist/cdk/blocks-stack.test.js +94 -37
- package/dist/cdk/compute/compute-registry.d.ts +19 -0
- package/dist/cdk/compute/compute-registry.d.ts.map +1 -0
- package/dist/cdk/compute/compute-registry.js +38 -0
- package/dist/cdk/compute/compute.d.ts +2 -0
- package/dist/cdk/compute/compute.d.ts.map +1 -1
- package/dist/cdk/compute/compute.js +8 -0
- package/dist/cdk/compute/default-compute-factory.d.ts +34 -0
- package/dist/cdk/compute/default-compute-factory.d.ts.map +1 -0
- package/dist/cdk/compute/default-compute-factory.js +3 -0
- package/dist/cdk/config-registry.d.ts +34 -4
- package/dist/cdk/config-registry.d.ts.map +1 -1
- package/dist/cdk/config-registry.js +83 -25
- package/dist/cdk/config-registry.test.d.ts +2 -0
- package/dist/cdk/config-registry.test.d.ts.map +1 -0
- package/dist/cdk/config-registry.test.js +115 -0
- package/dist/cdk/index.d.ts +76 -7
- package/dist/cdk/index.d.ts.map +1 -1
- package/dist/cdk/index.js +99 -9
- package/dist/cdk/internal.d.ts +1 -0
- package/dist/cdk/internal.d.ts.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/common/config.d.ts +34 -0
- package/dist/common/config.d.ts.map +1 -1
- package/dist/common/config.js +45 -3
- package/dist/common/config.test.js +19 -0
- package/dist/common/index.d.ts +8 -0
- package/dist/common/index.d.ts.map +1 -1
- package/dist/errors.d.ts +16 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +20 -0
- package/dist/hosting-secrets.d.ts +48 -0
- package/dist/hosting-secrets.d.ts.map +1 -0
- package/dist/hosting-secrets.js +57 -0
- package/dist/hosting-secrets.test.d.ts +2 -0
- package/dist/hosting-secrets.test.d.ts.map +1 -0
- package/dist/hosting-secrets.test.js +81 -0
- package/dist/hosting.d.ts +97 -6
- package/dist/hosting.d.ts.map +1 -1
- package/dist/hosting.js +91 -23
- package/dist/hosting.test.js +182 -10
- package/dist/index.cdk.d.ts +13 -12
- package/dist/index.cdk.d.ts.map +1 -1
- package/dist/index.cdk.js +13 -9
- package/dist/index.d.ts +8 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -5
- package/dist/lambda-handler.d.ts +17 -0
- package/dist/lambda-handler.d.ts.map +1 -1
- package/dist/lambda-handler.js +52 -3
- package/dist/lambda-handler.test.js +196 -1
- package/dist/pipeline/index.d.ts +24 -2
- package/dist/pipeline/index.d.ts.map +1 -1
- package/dist/pipeline/index.js +41 -1
- package/dist/pipeline.test.d.ts +2 -0
- package/dist/pipeline.test.d.ts.map +1 -0
- package/dist/pipeline.test.js +47 -0
- package/dist/rpc.d.ts +21 -0
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +34 -0
- package/dist/rpc.test.js +38 -1
- package/dist/scripts/config.d.ts +15 -0
- package/dist/scripts/config.d.ts.map +1 -0
- package/dist/scripts/config.js +29 -0
- package/dist/scripts/deploy.d.ts.map +1 -1
- package/dist/scripts/deploy.js +4 -0
- package/dist/scripts/dev-server.d.ts +8 -0
- package/dist/scripts/dev-server.d.ts.map +1 -1
- package/dist/scripts/dev-server.js +31 -0
- package/dist/scripts/generate-client.d.ts.map +1 -1
- package/dist/scripts/generate-client.js +9 -4
- package/dist/scripts/generate-client.test.js +19 -4
- package/dist/scripts/index.d.ts +13 -10
- package/dist/scripts/index.d.ts.map +1 -1
- package/dist/scripts/index.js +11 -8
- package/dist/scripts/preflight-credentials.d.ts +30 -0
- package/dist/scripts/preflight-credentials.d.ts.map +1 -0
- package/dist/scripts/preflight-credentials.js +108 -0
- package/dist/scripts/preflight-credentials.test.d.ts +2 -0
- package/dist/scripts/preflight-credentials.test.d.ts.map +1 -0
- package/dist/scripts/preflight-credentials.test.js +77 -0
- package/dist/scripts/sandbox-args.test.d.ts +2 -0
- package/dist/scripts/sandbox-args.test.d.ts.map +1 -0
- package/dist/scripts/sandbox-args.test.js +77 -0
- package/dist/scripts/sandbox-empty-buckets.test.d.ts +2 -0
- package/dist/scripts/sandbox-empty-buckets.test.d.ts.map +1 -0
- package/dist/scripts/sandbox-empty-buckets.test.js +171 -0
- package/dist/scripts/sandbox.d.ts +106 -0
- package/dist/scripts/sandbox.d.ts.map +1 -1
- package/dist/scripts/sandbox.js +255 -40
- package/dist/scripts/secret.d.ts +15 -0
- package/dist/scripts/secret.d.ts.map +1 -0
- package/dist/scripts/secret.js +29 -0
- package/dist/scripts/secret.test.d.ts +2 -0
- package/dist/scripts/secret.test.d.ts.map +1 -0
- package/dist/scripts/secret.test.js +28 -0
- package/dist/scripts/typegen.d.ts +15 -0
- package/dist/scripts/typegen.d.ts.map +1 -0
- package/dist/scripts/typegen.js +16 -0
- package/dist/secret-naming.d.ts +58 -0
- package/dist/secret-naming.d.ts.map +1 -0
- package/dist/secret-naming.js +67 -0
- package/dist/secret-naming.test.d.ts +2 -0
- package/dist/secret-naming.test.d.ts.map +1 -0
- package/dist/secret-naming.test.js +40 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -1
- package/src/api.test.ts +25 -0
- package/src/api.ts +39 -0
- package/src/bb-utils.ts +3 -0
- package/src/cdk/apigateway-account.ts +66 -0
- package/src/cdk/blocks-backend.test.ts +291 -272
- package/src/cdk/blocks-backend.ts +88 -83
- package/src/cdk/blocks-defaults.test.ts +25 -2
- package/src/cdk/blocks-defaults.ts +94 -2
- package/src/cdk/blocks-stack.test.ts +186 -118
- package/src/cdk/compute/compute-registry.ts +45 -0
- package/src/cdk/compute/compute.ts +10 -0
- package/src/cdk/compute/default-compute-factory.ts +38 -0
- package/src/cdk/config-registry.test.ts +135 -0
- package/src/cdk/config-registry.ts +92 -34
- package/src/cdk/index.ts +129 -10
- package/src/cdk/internal.ts +1 -0
- package/src/client/index.ts +1 -1
- package/src/common/config.test.ts +21 -0
- package/src/common/config.ts +47 -3
- package/src/common/index.ts +8 -0
- package/src/errors.ts +21 -0
- package/src/hosting-secrets.test.ts +106 -0
- package/src/hosting-secrets.ts +106 -0
- package/src/hosting.test.ts +272 -63
- package/src/hosting.ts +200 -68
- package/src/index.cdk.ts +80 -38
- package/src/index.ts +35 -16
- package/src/lambda-handler.test.ts +215 -1
- package/src/lambda-handler.ts +54 -2
- package/src/pipeline/index.ts +64 -11
- package/src/pipeline.test.ts +55 -0
- package/src/rpc.test.ts +44 -1
- package/src/rpc.ts +41 -0
- package/src/scripts/config.ts +35 -0
- package/src/scripts/deploy.ts +5 -0
- package/src/scripts/dev-server.ts +40 -0
- package/src/scripts/generate-client.test.ts +43 -8
- package/src/scripts/generate-client.ts +70 -65
- package/src/scripts/index.ts +20 -17
- package/src/scripts/preflight-credentials.test.ts +110 -0
- package/src/scripts/preflight-credentials.ts +131 -0
- package/src/scripts/sandbox-args.test.ts +92 -0
- package/src/scripts/sandbox-empty-buckets.test.ts +191 -0
- package/src/scripts/sandbox.ts +287 -39
- package/src/scripts/secret.test.ts +35 -0
- package/src/scripts/secret.ts +35 -0
- package/src/scripts/typegen.ts +18 -0
- package/src/secret-naming.test.ts +59 -0
- package/src/secret-naming.ts +99 -0
- package/src/version.ts +1 -1
package/src/hosting.ts
CHANGED
|
@@ -1,42 +1,38 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
import * as cdk from 'aws-cdk-lib';
|
|
5
|
-
import {
|
|
6
|
-
AllowedMethods,
|
|
7
|
-
CachePolicy,
|
|
8
|
-
OriginRequestPolicy,
|
|
9
|
-
ViewerProtocolPolicy,
|
|
10
|
-
} from 'aws-cdk-lib/aws-cloudfront';
|
|
11
|
-
import { HttpOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
|
|
12
|
-
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment';
|
|
13
|
-
import { Construct } from 'constructs';
|
|
14
4
|
import { execSync } from 'node:child_process';
|
|
15
5
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
16
6
|
import { join, resolve } from 'node:path';
|
|
17
|
-
|
|
7
|
+
import type { DeployManifest, FrameworkType, KindStoreOptions, RouteBehavior } from '@aws-blocks/hosting/constructs';
|
|
8
|
+
import { detectFramework, type FrameworkAdapterFn, getAdapter, normalizeBasePath } from '@aws-blocks/hosting/adapters';
|
|
18
9
|
import {
|
|
19
|
-
HostingConstruct,
|
|
20
10
|
generateBuildId,
|
|
11
|
+
HostingConstruct,
|
|
21
12
|
type HostingConstructProps,
|
|
22
13
|
type HostingDomainConfig,
|
|
23
14
|
type HostingWafConfig,
|
|
24
15
|
type SkewProtectionConfig,
|
|
25
16
|
} from '@aws-blocks/hosting/constructs';
|
|
26
|
-
import
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
} from '@aws-blocks/hosting/adapters';
|
|
32
|
-
import type {
|
|
33
|
-
DeployManifest,
|
|
34
|
-
RouteBehavior,
|
|
35
|
-
FrameworkType,
|
|
36
|
-
} from '@aws-blocks/hosting';
|
|
37
|
-
import { BLOCKS_RPC_PREFIX, BLOCKS_AUTH_PREFIX } from './constants.js';
|
|
38
|
-
import { BLOCKS_SANDBOX_DIR } from './common/constants.js';
|
|
17
|
+
import * as cdk from 'aws-cdk-lib';
|
|
18
|
+
import { AllowedMethods, CachePolicy, OriginRequestPolicy, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
|
|
19
|
+
import { HttpOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
|
|
20
|
+
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment';
|
|
21
|
+
import { Construct } from 'constructs';
|
|
39
22
|
import { registerConfig } from './cdk/config-registry.js';
|
|
23
|
+
import { BLOCKS_SANDBOX_DIR } from './common/constants.js';
|
|
24
|
+
import { BLOCKS_AUTH_PREFIX, BLOCKS_RPC_PREFIX } from './constants.js';
|
|
25
|
+
import {
|
|
26
|
+
assertMarkersExistAtSynth,
|
|
27
|
+
collectSynthMarkers,
|
|
28
|
+
type DomainNameInput,
|
|
29
|
+
type EnvValue,
|
|
30
|
+
partitionEnvironment,
|
|
31
|
+
resolveDomainNames,
|
|
32
|
+
resolveSecretsAtSynth,
|
|
33
|
+
wireByo,
|
|
34
|
+
wireManagedValue,
|
|
35
|
+
} from './hosting-secrets.js';
|
|
40
36
|
import { getRegisteredRoutes } from './raw-route.js';
|
|
41
37
|
|
|
42
38
|
// ─── Public types ────────────────────────────────────────────────
|
|
@@ -102,6 +98,19 @@ export type ComputeConfig = {
|
|
|
102
98
|
|
|
103
99
|
export type { FrameworkType, HostingDomainConfig, HostingWafConfig, SkewProtectionConfig };
|
|
104
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Custom-domain config for the Blocks {@link Hosting} block — the leaf
|
|
103
|
+
* {@link HostingDomainConfig} with `domainName` widened to also accept a
|
|
104
|
+
* `config()` marker (resolved to a literal at synth). Only `config()` or a plain
|
|
105
|
+
* string is accepted here, never `secret()` (a synth-inlined value would leak into
|
|
106
|
+
* the template). All other fields (`hostedZone`, `certificate`, `wwwRedirect`, …)
|
|
107
|
+
* are inherited unchanged from {@link HostingDomainConfig}.
|
|
108
|
+
*/
|
|
109
|
+
export interface HostingDomain extends Omit<HostingDomainConfig, 'domainName'> {
|
|
110
|
+
/** Domain name(s): a plain string / string[] and/or a `config()` marker resolved at synth. */
|
|
111
|
+
domainName: DomainNameInput;
|
|
112
|
+
}
|
|
113
|
+
|
|
105
114
|
/**
|
|
106
115
|
* Structural interface for the Blocks backend stack.
|
|
107
116
|
*
|
|
@@ -199,8 +208,55 @@ export interface HostingProps {
|
|
|
199
208
|
/** Lambda compute configuration for SSR frameworks. */
|
|
200
209
|
compute?: ComputeConfig;
|
|
201
210
|
|
|
202
|
-
/**
|
|
203
|
-
|
|
211
|
+
/**
|
|
212
|
+
* Custom environment variables injected into all compute Lambda functions.
|
|
213
|
+
*
|
|
214
|
+
* Values are either plain strings or {@link secret} references:
|
|
215
|
+
*
|
|
216
|
+
* ```ts
|
|
217
|
+
* environment: {
|
|
218
|
+
* FEATURE_FLAG: 'on', // plaintext (in CFN template + Lambda config)
|
|
219
|
+
* STRIPE_KEY: secret('STRIPE_KEY'), // encrypted; read at runtime via getSecret()
|
|
220
|
+
* }
|
|
221
|
+
* ```
|
|
222
|
+
*
|
|
223
|
+
* A plain string is injected verbatim (visible in the CloudFormation
|
|
224
|
+
* template — safe for non-sensitive literals). A `secret('K')` value (AWS
|
|
225
|
+
* Secrets Manager) or `config('K')` value (SSM Parameter Store) injects only
|
|
226
|
+
* the store LOCATOR — never the value — and grants the compute role scoped
|
|
227
|
+
* read + decrypt; fetch it at runtime with `await getSecret('K')` /
|
|
228
|
+
* `await getConfig('K')`. A bring-your-own CDK `ISecret` / `IParameter` handle
|
|
229
|
+
* is accepted too and resolves identically.
|
|
230
|
+
*
|
|
231
|
+
* The env-var name must equal the key: `STRIPE_KEY: secret('STRIPE_KEY')`.
|
|
232
|
+
*/
|
|
233
|
+
environment?: Record<string, EnvValue>;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Custom domain configuration. `domainName` accepts plain strings and/or
|
|
237
|
+
* {@link config} references (e.g. `domain: { domainName: config('DOMAIN_PROD') }`).
|
|
238
|
+
* A domain is resolved at synth time and inlined as a literal into the template,
|
|
239
|
+
* so only `config()` (non-sensitive → SSM) is allowed here, never `secret()`
|
|
240
|
+
* (which would leak into the template). Any domain marker requires constructing
|
|
241
|
+
* via the async {@link Hosting.create}.
|
|
242
|
+
*/
|
|
243
|
+
domain?: HostingDomain;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Namespace/cache config for `secret()` values (AWS Secrets Manager). Defaults
|
|
247
|
+
* to the Blocks `/blocks/secrets` prefix; set `prefix` to namespace per app,
|
|
248
|
+
* `stage` for per-stage values with a shared fallback, or `cacheTtlSeconds` to
|
|
249
|
+
* refresh a rotated value on a warm compute without a cold start. Any field the
|
|
250
|
+
* app sets overrides the Blocks default.
|
|
251
|
+
*/
|
|
252
|
+
secretStore?: KindStoreOptions;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Namespace/cache config for `config()` values (SSM Parameter Store). Defaults
|
|
256
|
+
* to the Blocks `/blocks/config` prefix; same override semantics as
|
|
257
|
+
* {@link HostingProps.secretStore}.
|
|
258
|
+
*/
|
|
259
|
+
configStore?: KindStoreOptions;
|
|
204
260
|
|
|
205
261
|
/** WAF protection configuration. */
|
|
206
262
|
waf?: HostingWafConfig;
|
|
@@ -208,6 +264,16 @@ export interface HostingProps {
|
|
|
208
264
|
/** Retain the S3 bucket when the stack is deleted. Default: false. */
|
|
209
265
|
retainOnDelete?: boolean;
|
|
210
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Days to retain SUPERSEDED build artifacts in S3 before they are expired.
|
|
269
|
+
* Default: 30. The build currently referenced by CloudFront KVS (`meta.b`)
|
|
270
|
+
* is NEVER expired regardless of this value — only builds that have been
|
|
271
|
+
* replaced by a newer deploy are cleaned up (issue #480). Raise this to keep
|
|
272
|
+
* a longer rollback window. Must be at least `skewProtection.maxAge`
|
|
273
|
+
* (converted to days), or synth throws `InvalidSkewProtectionMaxAgeError`.
|
|
274
|
+
*/
|
|
275
|
+
buildRetentionDays?: number;
|
|
276
|
+
|
|
211
277
|
/** Custom Content-Security-Policy header value. */
|
|
212
278
|
contentSecurityPolicy?: string;
|
|
213
279
|
|
|
@@ -399,7 +465,44 @@ export class Hosting extends Construct {
|
|
|
399
465
|
/** SNS topic for hosting CloudWatch alarms (present when `monitoring.enabled` is true). */
|
|
400
466
|
public readonly monitoringTopic?: cdk.aws_sns.ITopic;
|
|
401
467
|
|
|
402
|
-
|
|
468
|
+
/**
|
|
469
|
+
* Async constructor. Required when a `secret()` / `config()` value resolves at
|
|
470
|
+
* **synth time** — i.e. a `domain.domainName` marker — because that value is
|
|
471
|
+
* fetched from its store (Secrets Manager / SSM) during synthesis. Returns a
|
|
472
|
+
* fully-constructed {@link Hosting}.
|
|
473
|
+
*
|
|
474
|
+
* For runtime `environment` markers (read via `getSecret`/`getConfig`) and
|
|
475
|
+
* plain literals, `new Hosting(...)` works directly; `create()` is also safe
|
|
476
|
+
* to use uniformly.
|
|
477
|
+
*
|
|
478
|
+
* @example
|
|
479
|
+
* ```ts
|
|
480
|
+
* await Hosting.create(stack, 'Web', {
|
|
481
|
+
* root: '.', framework: 'nextjs', api: blocksStack,
|
|
482
|
+
* domain: { domainName: config('DOMAIN_PROD') },
|
|
483
|
+
* });
|
|
484
|
+
* ```
|
|
485
|
+
*/
|
|
486
|
+
static async create(scope: Construct, id: string, props: HostingProps): Promise<Hosting> {
|
|
487
|
+
const storeConfig = { secretStore: props.secretStore, configStore: props.configStore };
|
|
488
|
+
const synthMarkers = collectSynthMarkers(props.domain?.domainName);
|
|
489
|
+
const resolved = synthMarkers.length
|
|
490
|
+
? await resolveSecretsAtSynth(synthMarkers, undefined, storeConfig)
|
|
491
|
+
: new Map<string, string>();
|
|
492
|
+
// Fail the deploy early if a declared `environment` secret/config has no value
|
|
493
|
+
// set — existence only, never fetching the value. (Domain markers above already
|
|
494
|
+
// fail this way; this extends it to runtime markers.)
|
|
495
|
+
await assertMarkersExistAtSynth(partitionEnvironment(props.environment).managed, storeConfig);
|
|
496
|
+
return new Hosting(scope, id, props, resolved);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* @param resolvedSecrets - Synth-time-resolved secret values, keyed by secret
|
|
501
|
+
* key. Populated by {@link Hosting.create}; empty for the direct
|
|
502
|
+
* `new Hosting()` path (which then rejects any synth-time secret with a
|
|
503
|
+
* clear "use Hosting.create()" error).
|
|
504
|
+
*/
|
|
505
|
+
constructor(scope: Construct, id: string, props: HostingProps, resolvedSecrets: Map<string, string> = new Map()) {
|
|
403
506
|
super(scope, id);
|
|
404
507
|
|
|
405
508
|
const root = resolve(props.root);
|
|
@@ -415,7 +518,7 @@ export class Hosting extends Construct {
|
|
|
415
518
|
// from breaking frontend builds (e.g., Next.js webpack module resolution).
|
|
416
519
|
const nodeOptions = (process.env.NODE_OPTIONS || '')
|
|
417
520
|
.split(/\s+/)
|
|
418
|
-
.filter(opt => opt !== '--conditions=cdk')
|
|
521
|
+
.filter((opt) => opt !== '--conditions=cdk')
|
|
419
522
|
.join(' ');
|
|
420
523
|
const buildEnv = { ...process.env, NODE_OPTIONS: nodeOptions };
|
|
421
524
|
try {
|
|
@@ -430,7 +533,7 @@ export class Hosting extends Construct {
|
|
|
430
533
|
} catch (error) {
|
|
431
534
|
throw new Error(
|
|
432
535
|
`Frontend build failed: ${props.buildCommand}\n` +
|
|
433
|
-
|
|
536
|
+
`Ensure the build command is correct and all dependencies are installed.`,
|
|
434
537
|
);
|
|
435
538
|
}
|
|
436
539
|
}
|
|
@@ -445,7 +548,7 @@ export class Hosting extends Construct {
|
|
|
445
548
|
if (!existsSync(expectedOutputDir)) {
|
|
446
549
|
throw new Error(
|
|
447
550
|
`Build output directory not found: ${expectedOutputDir}\n` +
|
|
448
|
-
|
|
551
|
+
`Provide a buildCommand or ensure the directory exists before synthesis.`,
|
|
449
552
|
);
|
|
450
553
|
}
|
|
451
554
|
|
|
@@ -494,8 +597,7 @@ export class Hosting extends Construct {
|
|
|
494
597
|
// errorPages will drive the CloudFront configuration correctly,
|
|
495
598
|
// and the HTML files are already in the static assets directory
|
|
496
599
|
// (copied by the adapter).
|
|
497
|
-
const manifestHasErrorPages = manifest.errorPages !== undefined &&
|
|
498
|
-
Object.keys(manifest.errorPages).length > 0;
|
|
600
|
+
const manifestHasErrorPages = manifest.errorPages !== undefined && Object.keys(manifest.errorPages).length > 0;
|
|
499
601
|
const skipPropsErrorPages = !!(props.errorPages && manifestHasErrorPages);
|
|
500
602
|
|
|
501
603
|
// ── 5. Write placeholder config.json into static assets ─────────
|
|
@@ -506,10 +608,7 @@ export class Hosting extends Construct {
|
|
|
506
608
|
const staticDir = manifest.staticAssets.directory;
|
|
507
609
|
const blocksSandboxDir = join(staticDir, '.blocks-sandbox');
|
|
508
610
|
mkdirSync(blocksSandboxDir, { recursive: true });
|
|
509
|
-
writeFileSync(
|
|
510
|
-
join(blocksSandboxDir, 'config.json'),
|
|
511
|
-
JSON.stringify({ _placeholder: true }),
|
|
512
|
-
);
|
|
611
|
+
writeFileSync(join(blocksSandboxDir, 'config.json'), JSON.stringify({ _placeholder: true }));
|
|
513
612
|
|
|
514
613
|
// ── 5a. Mark config.json as a no-cache path ─────────────────────
|
|
515
614
|
// config.json is a fixed-name, mutable runtime-config file: it must
|
|
@@ -532,7 +631,7 @@ export class Hosting extends Construct {
|
|
|
532
631
|
target: 'static',
|
|
533
632
|
};
|
|
534
633
|
// Insert before any catch-all route
|
|
535
|
-
const catchAllIdx = manifest.routes.findIndex((r) => r.pattern === '/*' || r.pattern === '/(.*)')
|
|
634
|
+
const catchAllIdx = manifest.routes.findIndex((r) => r.pattern === '/*' || r.pattern === '/(.*)');
|
|
536
635
|
if (catchAllIdx >= 0) {
|
|
537
636
|
manifest.routes.splice(catchAllIdx, 0, blocksConfigRoute);
|
|
538
637
|
} else {
|
|
@@ -550,28 +649,58 @@ export class Hosting extends Construct {
|
|
|
550
649
|
const normalizedCompute = props.compute
|
|
551
650
|
? {
|
|
552
651
|
...props.compute,
|
|
553
|
-
timeout:
|
|
554
|
-
|
|
555
|
-
|
|
652
|
+
timeout:
|
|
653
|
+
typeof props.compute.timeout === 'number'
|
|
654
|
+
? cdk.Duration.seconds(props.compute.timeout)
|
|
655
|
+
: props.compute.timeout,
|
|
656
|
+
}
|
|
657
|
+
: undefined;
|
|
658
|
+
|
|
659
|
+
// ── 6b. Resolve secret() markers ─────────────────────────────
|
|
660
|
+
// Env values split into plain / runtime-secret / deploy-time buckets;
|
|
661
|
+
// domain names may contain markers resolved at synth time. See
|
|
662
|
+
// ./hosting-secrets.ts for the two-strategy rationale.
|
|
663
|
+
const { plain: plainEnv, managed, byo } = partitionEnvironment(props.environment);
|
|
664
|
+
|
|
665
|
+
// Resolved domain (markers → literals); falls back to the raw config when
|
|
666
|
+
// no domain is set. resolveDomainNames throws a "use Hosting.create()"
|
|
667
|
+
// error if a domain marker reached the sync path unresolved.
|
|
668
|
+
const resolvedDomain = props.domain
|
|
669
|
+
? {
|
|
670
|
+
...props.domain,
|
|
671
|
+
domainName: resolveDomainNames(props.domain.domainName, resolvedSecrets),
|
|
556
672
|
}
|
|
557
673
|
: undefined;
|
|
558
674
|
|
|
559
675
|
const hostingProps: HostingConstructProps = {
|
|
560
676
|
manifest,
|
|
561
677
|
compute: normalizedCompute,
|
|
562
|
-
|
|
678
|
+
// Plain env + deploy-time literals go straight to the L3 (which stays
|
|
679
|
+
// secret-agnostic: it only ever sees plain strings). Runtime secrets are
|
|
680
|
+
// wired separately below so we can attach IAM grants per function.
|
|
681
|
+
environment: Object.keys(plainEnv).length ? plainEnv : undefined,
|
|
682
|
+
domain: resolvedDomain,
|
|
563
683
|
waf: props.waf,
|
|
564
|
-
storage:
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
684
|
+
storage:
|
|
685
|
+
props.retainOnDelete != null || props.buildRetentionDays != null
|
|
686
|
+
? {
|
|
687
|
+
...(props.retainOnDelete != null
|
|
688
|
+
? { retainOnDelete: props.retainOnDelete }
|
|
689
|
+
: {}),
|
|
690
|
+
...(props.buildRetentionDays != null
|
|
691
|
+
? { buildRetentionDays: props.buildRetentionDays }
|
|
692
|
+
: {}),
|
|
693
|
+
}
|
|
694
|
+
: undefined,
|
|
695
|
+
cdn:
|
|
696
|
+
props.contentSecurityPolicy || props.priceClass || props.geoRestriction || props.quotas
|
|
697
|
+
? {
|
|
698
|
+
contentSecurityPolicy: props.contentSecurityPolicy,
|
|
699
|
+
priceClass: props.priceClass,
|
|
700
|
+
geoRestriction: props.geoRestriction,
|
|
701
|
+
quotas: props.quotas,
|
|
702
|
+
}
|
|
703
|
+
: undefined,
|
|
575
704
|
logging: props.logging,
|
|
576
705
|
buildCache: props.buildCache,
|
|
577
706
|
errorPages: skipPropsErrorPages ? undefined : props.errorPages,
|
|
@@ -591,14 +720,10 @@ export class Hosting extends Construct {
|
|
|
591
720
|
// variables — they surface in computeFunctions as EdgeFunction/IVersion
|
|
592
721
|
// without an `addEnvironment` method. Skip any function that can't take
|
|
593
722
|
// env vars instead of crashing (`fn.addEnvironment is not a function`).
|
|
594
|
-
const canAddEnv = (
|
|
595
|
-
fn: unknown,
|
|
596
|
-
): fn is cdk.aws_lambda.Function =>
|
|
723
|
+
const canAddEnv = (fn: unknown): fn is cdk.aws_lambda.Function =>
|
|
597
724
|
typeof (fn as { addEnvironment?: unknown })?.addEnvironment === 'function';
|
|
598
725
|
|
|
599
|
-
const primaryFunction = [...hosting.computeFunctions.values()].find(
|
|
600
|
-
canAddEnv,
|
|
601
|
-
);
|
|
726
|
+
const primaryFunction = [...hosting.computeFunctions.values()].find(canAddEnv);
|
|
602
727
|
|
|
603
728
|
for (const [, fn] of hosting.computeFunctions) {
|
|
604
729
|
if (!canAddEnv(fn)) continue; // Lambda@Edge: no env var support
|
|
@@ -608,15 +733,25 @@ export class Hosting extends Construct {
|
|
|
608
733
|
if (props.backendConfig) {
|
|
609
734
|
fn.addEnvironment('BLOCKS_CONFIG', JSON.stringify(props.backendConfig));
|
|
610
735
|
}
|
|
736
|
+
// Runtime managed markers (secret|config): inject the store locator
|
|
737
|
+
// (never the value) + grant read/decrypt; read via getSecret()/getConfig().
|
|
738
|
+
// The app's secretStore/configStore (prefix, stage, cacheTtlSeconds) layer
|
|
739
|
+
// over the Blocks defaults.
|
|
740
|
+
const storeConfig = { secretStore: props.secretStore, configStore: props.configStore };
|
|
741
|
+
for (const marker of managed) {
|
|
742
|
+
wireManagedValue(fn, marker, storeConfig);
|
|
743
|
+
}
|
|
744
|
+
// BYO handles (ISecret|IParameter): grant via the handle + inject its locator.
|
|
745
|
+
for (const binding of byo) {
|
|
746
|
+
wireByo(fn, binding, storeConfig);
|
|
747
|
+
}
|
|
611
748
|
}
|
|
612
749
|
|
|
613
750
|
// ── 8. Deploy config.json with resolved CDK tokens ───────────
|
|
614
751
|
const buildId = manifest.buildId;
|
|
615
752
|
if (buildId) {
|
|
616
753
|
const configDeployment = new s3deploy.BucketDeployment(this, 'BlocksConfigDeployment', {
|
|
617
|
-
sources: [
|
|
618
|
-
s3deploy.Source.jsonData('config.json', this.buildConfigJson(props)),
|
|
619
|
-
],
|
|
754
|
+
sources: [s3deploy.Source.jsonData('config.json', this.buildConfigJson(props))],
|
|
620
755
|
destinationBucket: hosting.bucket,
|
|
621
756
|
destinationKeyPrefix: `builds/${buildId}/.blocks-sandbox`,
|
|
622
757
|
prune: false,
|
|
@@ -629,10 +764,7 @@ export class Hosting extends Construct {
|
|
|
629
764
|
// primary guard against staleness is step 5a's no-cache placeholder;
|
|
630
765
|
// this is defense-in-depth so a post-deploy invalidation actually
|
|
631
766
|
// clears any edge entry at its real key.)
|
|
632
|
-
distributionPaths: [
|
|
633
|
-
`/builds/${buildId}/.blocks-sandbox/*`,
|
|
634
|
-
'/.blocks-sandbox/*',
|
|
635
|
-
],
|
|
767
|
+
distributionPaths: [`/builds/${buildId}/.blocks-sandbox/*`, '/.blocks-sandbox/*'],
|
|
636
768
|
cacheControl: [s3deploy.CacheControl.fromString('public, max-age=60, must-revalidate')],
|
|
637
769
|
});
|
|
638
770
|
|
|
@@ -764,8 +896,8 @@ export class Hosting extends Construct {
|
|
|
764
896
|
if (behaviorPattern.endsWith('/*')) {
|
|
765
897
|
console.warn(
|
|
766
898
|
`[Hosting] ⚠️ RawRoute '${route.path}' creates CloudFront behavior '${behaviorPattern}' ` +
|
|
767
|
-
|
|
768
|
-
|
|
899
|
+
`which may shadow SSR/frontend routes under the same prefix. ` +
|
|
900
|
+
`Consider placing this route under ${BLOCKS_RPC_PREFIX}/ to avoid conflicts.`,
|
|
769
901
|
);
|
|
770
902
|
}
|
|
771
903
|
|
package/src/index.cdk.ts
CHANGED
|
@@ -1,50 +1,92 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
// Declare functions for infra (secret/config). The runtime getters
|
|
5
|
+
// (getSecret/getConfig) are imported from '@aws-blocks/hosting' — core's own
|
|
6
|
+
// getConfig (backend config loader, above) owns that name here.
|
|
7
|
+
export {
|
|
8
|
+
type ConfigValue,
|
|
9
|
+
config,
|
|
10
|
+
DEFAULT_CONFIG_PARAMETER_PREFIX,
|
|
11
|
+
DEFAULT_SECRET_PARAMETER_PREFIX,
|
|
12
|
+
isConfig,
|
|
13
|
+
isManagedValue,
|
|
14
|
+
isSecret,
|
|
15
|
+
type ManagedValue,
|
|
16
|
+
type SecretValue,
|
|
17
|
+
secret,
|
|
18
|
+
type ValueKind,
|
|
19
|
+
} from '@aws-blocks/hosting';
|
|
20
|
+
export { type ApiHandler, ApiNamespace, type BlocksContext } from './api.js';
|
|
12
21
|
export {
|
|
13
|
-
|
|
14
|
-
|
|
22
|
+
BlocksBackend,
|
|
23
|
+
type BlocksBackendProps,
|
|
24
|
+
type BlocksDefaults,
|
|
25
|
+
BlocksPresets,
|
|
26
|
+
BlocksStack,
|
|
27
|
+
type BlocksThrottling,
|
|
28
|
+
blocksNodejsBundling,
|
|
29
|
+
type CoreBlocksBackendProps,
|
|
30
|
+
type CoreBlocksStackProps,
|
|
31
|
+
DEFAULT_NODE_RUNTIME,
|
|
32
|
+
ensureApiGatewayAccount,
|
|
33
|
+
finalizeConfigRegistry,
|
|
34
|
+
getConfigLocation,
|
|
35
|
+
registerConfig,
|
|
36
|
+
SandboxDisableDeletionProtection,
|
|
37
|
+
Scope,
|
|
38
|
+
SHARED_HANDLER_TIMEOUT_SECONDS,
|
|
39
|
+
synthGuard,
|
|
15
40
|
} from './cdk/index.js';
|
|
41
|
+
export { _resetConfigCache, getConfig, getConfigSync, loadConfigToProcessEnv, preloadConfig } from './common/config.js';
|
|
42
|
+
export { BlocksStackProps } from './common/index.js';
|
|
43
|
+
export {
|
|
44
|
+
_resetSdkRegistry,
|
|
45
|
+
getAllSdkIdentifiers,
|
|
46
|
+
getSdkIdentifiers,
|
|
47
|
+
registerSdkIdentifiers,
|
|
48
|
+
} from './common/sdk-registry.js';
|
|
49
|
+
export { BLOCKS_AUTH_PREFIX, BLOCKS_RPC_PREFIX } from './constants.js';
|
|
50
|
+
export { ApiError, blocksError, DEFAULT_API_ERROR_NAME, hasAuthError, isBlocksError } from './errors.js';
|
|
16
51
|
export {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
52
|
+
type BlocksStackApi,
|
|
53
|
+
type ComputeConfig,
|
|
54
|
+
type FrameworkType,
|
|
55
|
+
Hosting,
|
|
56
|
+
type HostingDomainConfig,
|
|
57
|
+
type HostingProps,
|
|
58
|
+
type HostingWafConfig,
|
|
24
59
|
} from './hosting.js';
|
|
60
|
+
export { EventSourceMapping } from './lambda-handler.js';
|
|
61
|
+
export {
|
|
62
|
+
__PIPELINE_STAGE_SCOPE__,
|
|
63
|
+
type BranchConfig,
|
|
64
|
+
DeployStage,
|
|
65
|
+
type DeployStageProps,
|
|
66
|
+
Pipeline,
|
|
67
|
+
type PipelineProps,
|
|
68
|
+
type PipelineSourceConfig,
|
|
69
|
+
type PipelineStageConfig,
|
|
70
|
+
type PipelineSynthConfig,
|
|
71
|
+
} from './pipeline/index.js';
|
|
25
72
|
export {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
73
|
+
type HttpMethod,
|
|
74
|
+
RawRoute,
|
|
75
|
+
RawRouteErrors,
|
|
76
|
+
type RawRouteOptions,
|
|
30
77
|
} from './raw-route.cdk.js';
|
|
31
78
|
export {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
79
|
+
clearRouteRegistry,
|
|
80
|
+
getRegisteredRoutes,
|
|
81
|
+
lockRouteRegistry,
|
|
82
|
+
matchRoute,
|
|
83
|
+
type RegisteredRoute,
|
|
84
|
+
registerRoute,
|
|
85
|
+
unlockRouteRegistry,
|
|
39
86
|
} from './raw-route.js';
|
|
40
87
|
export {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
type PipelineProps,
|
|
47
|
-
type PipelineSourceConfig,
|
|
48
|
-
type PipelineSynthConfig,
|
|
49
|
-
type PipelineStageConfig,
|
|
50
|
-
} from './pipeline/index.js';
|
|
88
|
+
BLOCKS_CONFIG_PARAMETER_PREFIX,
|
|
89
|
+
BLOCKS_SECRET_PARAMETER_PREFIX,
|
|
90
|
+
blocksConfigParameterName,
|
|
91
|
+
blocksSecretParameterName,
|
|
92
|
+
} from './secret-naming.js';
|
package/src/index.ts
CHANGED
|
@@ -1,22 +1,41 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export { Scope, type ScopeOptions, type ScopeParent, type BuildingBlockMeta } from './common/index.js';
|
|
8
|
-
export { registerSdkIdentifiers, getSdkIdentifiers, getAllSdkIdentifiers, _resetSdkRegistry } from './common/sdk-registry.js';
|
|
9
|
-
export { getConfig, getConfigSync, preloadConfig, loadConfigToProcessEnv, _resetConfigCache } from './common/config.js';
|
|
4
|
+
// secret()/config() declare markers (CDK-free subpath). The runtime getters
|
|
5
|
+
// getSecret()/getConfig() are imported from '@aws-blocks/hosting' directly —
|
|
6
|
+
// core already exports a backend `getConfig` (config loader) under this name.
|
|
10
7
|
export {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
8
|
+
type ConfigValue,
|
|
9
|
+
config,
|
|
10
|
+
isConfig,
|
|
11
|
+
isManagedValue,
|
|
12
|
+
isSecret,
|
|
13
|
+
type ManagedValue,
|
|
14
|
+
type SecretValue,
|
|
15
|
+
secret,
|
|
16
|
+
type ValueKind,
|
|
17
|
+
} from '@aws-blocks/hosting';
|
|
18
|
+
export { type ApiHandler, ApiNamespace, type BlocksContext } from './api.js';
|
|
19
|
+
export { _resetConfigCache, getConfig, getConfigSync, loadConfigToProcessEnv, preloadConfig } from './common/config.js';
|
|
20
|
+
export { type BuildingBlockMeta, Scope, type ScopeOptions, type ScopeParent } from './common/index.js';
|
|
21
|
+
export {
|
|
22
|
+
_resetSdkRegistry,
|
|
23
|
+
getAllSdkIdentifiers,
|
|
24
|
+
getSdkIdentifiers,
|
|
25
|
+
registerSdkIdentifiers,
|
|
26
|
+
} from './common/sdk-registry.js';
|
|
27
|
+
export { BLOCKS_AUTH_PREFIX, BLOCKS_RPC_PREFIX } from './constants.js';
|
|
28
|
+
export { ApiError, blocksError, DEFAULT_API_ERROR_NAME, hasAuthError, isBlocksError } from './errors.js';
|
|
29
|
+
export {
|
|
30
|
+
clearRouteRegistry,
|
|
31
|
+
getRegisteredRoutes,
|
|
32
|
+
type HttpMethod,
|
|
33
|
+
lockRouteRegistry,
|
|
34
|
+
matchRoute,
|
|
35
|
+
RawRouteErrors,
|
|
36
|
+
type RawRouteOptions,
|
|
37
|
+
type RegisteredRoute,
|
|
38
|
+
registerRoute,
|
|
39
|
+
unlockRouteRegistry,
|
|
21
40
|
} from './raw-route.js';
|
|
22
41
|
export { RawRoute } from './raw-route.mock.js';
|