@aws-blocks/core 0.2.0 → 0.3.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/dist/cdk/blocks-backend.d.ts +35 -9
- package/dist/cdk/blocks-backend.d.ts.map +1 -1
- package/dist/cdk/blocks-backend.js +52 -69
- package/dist/cdk/blocks-backend.test.js +61 -69
- package/dist/cdk/blocks-defaults.d.ts +27 -1
- package/dist/cdk/blocks-defaults.d.ts.map +1 -1
- package/dist/cdk/blocks-defaults.js +5 -1
- package/dist/cdk/blocks-defaults.test.js +4 -2
- package/dist/cdk/blocks-stack.test.js +73 -37
- package/dist/cdk/compute/default-compute-factory.d.ts +33 -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/index.d.ts +46 -5
- package/dist/cdk/index.d.ts.map +1 -1
- package/dist/cdk/index.js +57 -7
- package/dist/cdk/internal.d.ts +1 -0
- package/dist/cdk/internal.d.ts.map +1 -1
- 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 +88 -6
- package/dist/hosting.d.ts.map +1 -1
- package/dist/hosting.js +83 -24
- package/dist/hosting.test.js +158 -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.test.js +66 -0
- 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.d.ts +52 -0
- package/dist/scripts/sandbox.d.ts.map +1 -1
- package/dist/scripts/sandbox.js +92 -15
- 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 +2 -1
- package/src/cdk/blocks-backend.test.ts +267 -272
- package/src/cdk/blocks-backend.ts +71 -79
- package/src/cdk/blocks-defaults.test.ts +4 -2
- package/src/cdk/blocks-defaults.ts +27 -1
- package/src/cdk/blocks-stack.test.ts +161 -118
- package/src/cdk/compute/default-compute-factory.ts +37 -0
- package/src/cdk/index.ts +84 -8
- package/src/cdk/internal.ts +1 -0
- package/src/hosting-secrets.test.ts +106 -0
- package/src/hosting-secrets.ts +106 -0
- package/src/hosting.test.ts +244 -63
- package/src/hosting.ts +180 -68
- package/src/index.cdk.ts +77 -38
- package/src/index.ts +35 -16
- package/src/lambda-handler.test.ts +74 -0
- 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.ts +102 -15
- 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/dist/hosting.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import type { FrameworkType, KindStoreOptions } from '@aws-blocks/hosting/constructs';
|
|
2
|
+
import { type FrameworkAdapterFn } from '@aws-blocks/hosting/adapters';
|
|
3
|
+
import { type HostingDomainConfig, type HostingWafConfig, type SkewProtectionConfig } from '@aws-blocks/hosting/constructs';
|
|
1
4
|
import * as cdk from 'aws-cdk-lib';
|
|
2
5
|
import { Construct } from 'constructs';
|
|
3
|
-
import { type
|
|
4
|
-
import { type FrameworkAdapterFn } from '@aws-blocks/hosting/adapters';
|
|
5
|
-
import type { FrameworkType } from '@aws-blocks/hosting';
|
|
6
|
+
import { type DomainNameInput, type EnvValue } from './hosting-secrets.js';
|
|
6
7
|
/**
|
|
7
8
|
* Lambda compute configuration for SSR frameworks.
|
|
8
9
|
*
|
|
@@ -62,6 +63,18 @@ export type ComputeConfig = {
|
|
|
62
63
|
logRetention?: cdk.aws_logs.RetentionDays;
|
|
63
64
|
};
|
|
64
65
|
export type { FrameworkType, HostingDomainConfig, HostingWafConfig, SkewProtectionConfig };
|
|
66
|
+
/**
|
|
67
|
+
* Custom-domain config for the Blocks {@link Hosting} block — the leaf
|
|
68
|
+
* {@link HostingDomainConfig} with `domainName` widened to also accept a
|
|
69
|
+
* `config()` marker (resolved to a literal at synth). Only `config()` or a plain
|
|
70
|
+
* string is accepted here, never `secret()` (a synth-inlined value would leak into
|
|
71
|
+
* the template). All other fields (`hostedZone`, `certificate`, `wwwRedirect`, …)
|
|
72
|
+
* are inherited unchanged from {@link HostingDomainConfig}.
|
|
73
|
+
*/
|
|
74
|
+
export interface HostingDomain extends Omit<HostingDomainConfig, 'domainName'> {
|
|
75
|
+
/** Domain name(s): a plain string / string[] and/or a `config()` marker resolved at synth. */
|
|
76
|
+
domainName: DomainNameInput;
|
|
77
|
+
}
|
|
65
78
|
/**
|
|
66
79
|
* Structural interface for the Blocks backend stack.
|
|
67
80
|
*
|
|
@@ -146,8 +159,52 @@ export interface HostingProps {
|
|
|
146
159
|
backendConfig?: Record<string, unknown>;
|
|
147
160
|
/** Lambda compute configuration for SSR frameworks. */
|
|
148
161
|
compute?: ComputeConfig;
|
|
149
|
-
/**
|
|
150
|
-
|
|
162
|
+
/**
|
|
163
|
+
* Custom environment variables injected into all compute Lambda functions.
|
|
164
|
+
*
|
|
165
|
+
* Values are either plain strings or {@link secret} references:
|
|
166
|
+
*
|
|
167
|
+
* ```ts
|
|
168
|
+
* environment: {
|
|
169
|
+
* FEATURE_FLAG: 'on', // plaintext (in CFN template + Lambda config)
|
|
170
|
+
* STRIPE_KEY: secret('STRIPE_KEY'), // encrypted; read at runtime via getSecret()
|
|
171
|
+
* }
|
|
172
|
+
* ```
|
|
173
|
+
*
|
|
174
|
+
* A plain string is injected verbatim (visible in the CloudFormation
|
|
175
|
+
* template — safe for non-sensitive literals). A `secret('K')` value (AWS
|
|
176
|
+
* Secrets Manager) or `config('K')` value (SSM Parameter Store) injects only
|
|
177
|
+
* the store LOCATOR — never the value — and grants the compute role scoped
|
|
178
|
+
* read + decrypt; fetch it at runtime with `await getSecret('K')` /
|
|
179
|
+
* `await getConfig('K')`. A bring-your-own CDK `ISecret` / `IParameter` handle
|
|
180
|
+
* is accepted too and resolves identically.
|
|
181
|
+
*
|
|
182
|
+
* The env-var name must equal the key: `STRIPE_KEY: secret('STRIPE_KEY')`.
|
|
183
|
+
*/
|
|
184
|
+
environment?: Record<string, EnvValue>;
|
|
185
|
+
/**
|
|
186
|
+
* Custom domain configuration. `domainName` accepts plain strings and/or
|
|
187
|
+
* {@link config} references (e.g. `domain: { domainName: config('DOMAIN_PROD') }`).
|
|
188
|
+
* A domain is resolved at synth time and inlined as a literal into the template,
|
|
189
|
+
* so only `config()` (non-sensitive → SSM) is allowed here, never `secret()`
|
|
190
|
+
* (which would leak into the template). Any domain marker requires constructing
|
|
191
|
+
* via the async {@link Hosting.create}.
|
|
192
|
+
*/
|
|
193
|
+
domain?: HostingDomain;
|
|
194
|
+
/**
|
|
195
|
+
* Namespace/cache config for `secret()` values (AWS Secrets Manager). Defaults
|
|
196
|
+
* to the Blocks `/blocks/secrets` prefix; set `prefix` to namespace per app,
|
|
197
|
+
* `stage` for per-stage values with a shared fallback, or `cacheTtlSeconds` to
|
|
198
|
+
* refresh a rotated value on a warm compute without a cold start. Any field the
|
|
199
|
+
* app sets overrides the Blocks default.
|
|
200
|
+
*/
|
|
201
|
+
secretStore?: KindStoreOptions;
|
|
202
|
+
/**
|
|
203
|
+
* Namespace/cache config for `config()` values (SSM Parameter Store). Defaults
|
|
204
|
+
* to the Blocks `/blocks/config` prefix; same override semantics as
|
|
205
|
+
* {@link HostingProps.secretStore}.
|
|
206
|
+
*/
|
|
207
|
+
configStore?: KindStoreOptions;
|
|
151
208
|
/** WAF protection configuration. */
|
|
152
209
|
waf?: HostingWafConfig;
|
|
153
210
|
/** Retain the S3 bucket when the stack is deleted. Default: false. */
|
|
@@ -322,7 +379,32 @@ export declare class Hosting extends Construct {
|
|
|
322
379
|
readonly buildCacheBucket?: cdk.aws_s3.Bucket;
|
|
323
380
|
/** SNS topic for hosting CloudWatch alarms (present when `monitoring.enabled` is true). */
|
|
324
381
|
readonly monitoringTopic?: cdk.aws_sns.ITopic;
|
|
325
|
-
|
|
382
|
+
/**
|
|
383
|
+
* Async constructor. Required when a `secret()` / `config()` value resolves at
|
|
384
|
+
* **synth time** — i.e. a `domain.domainName` marker — because that value is
|
|
385
|
+
* fetched from its store (Secrets Manager / SSM) during synthesis. Returns a
|
|
386
|
+
* fully-constructed {@link Hosting}.
|
|
387
|
+
*
|
|
388
|
+
* For runtime `environment` markers (read via `getSecret`/`getConfig`) and
|
|
389
|
+
* plain literals, `new Hosting(...)` works directly; `create()` is also safe
|
|
390
|
+
* to use uniformly.
|
|
391
|
+
*
|
|
392
|
+
* @example
|
|
393
|
+
* ```ts
|
|
394
|
+
* await Hosting.create(stack, 'Web', {
|
|
395
|
+
* root: '.', framework: 'nextjs', api: blocksStack,
|
|
396
|
+
* domain: { domainName: config('DOMAIN_PROD') },
|
|
397
|
+
* });
|
|
398
|
+
* ```
|
|
399
|
+
*/
|
|
400
|
+
static create(scope: Construct, id: string, props: HostingProps): Promise<Hosting>;
|
|
401
|
+
/**
|
|
402
|
+
* @param resolvedSecrets - Synth-time-resolved secret values, keyed by secret
|
|
403
|
+
* key. Populated by {@link Hosting.create}; empty for the direct
|
|
404
|
+
* `new Hosting()` path (which then rejects any synth-time secret with a
|
|
405
|
+
* clear "use Hosting.create()" error).
|
|
406
|
+
*/
|
|
407
|
+
constructor(scope: Construct, id: string, props: HostingProps, resolvedSecrets?: Map<string, string>);
|
|
326
408
|
/**
|
|
327
409
|
* Build the config.json payload from props.
|
|
328
410
|
*
|
package/dist/hosting.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hosting.d.ts","sourceRoot":"","sources":["../src/hosting.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hosting.d.ts","sourceRoot":"","sources":["../src/hosting.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAkB,aAAa,EAAE,gBAAgB,EAAiB,MAAM,gCAAgC,CAAC;AACrH,OAAO,EAAmB,KAAK,kBAAkB,EAAiC,MAAM,8BAA8B,CAAC;AACvH,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAC1B,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,GAAG,MAAM,aAAa,CAAC;AAInC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAIvC,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,QAAQ,EAMd,MAAM,sBAAsB,CAAC;AAK9B;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,EAAE,GAAG,CAAC,QAAQ,GAAG,MAAM,CAAC;IAChC,8FAA8F;IAC9F,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;;;;;;;;;;;;OAgBG;IACH,iBAAiB,CAAC,EAAE;QAClB,2EAA2E;QAC3E,mBAAmB,CAAC,EAAE,MAAM,CAAC;KAC9B,CAAC;IACF,uEAAuE;IACvE,YAAY,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC;CAC3C,CAAC;AAEF,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,CAAC;AAE3F;;;;;;;GAOG;AACH,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,mBAAmB,EAAE,YAAY,CAAC;IAC5E,8FAA8F;IAC9F,UAAU,EAAE,eAAe,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,mHAAmH;IACnH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YAAY;IAE3B,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IAEb;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;IAE1B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,mEAAmE;IACnE,aAAa,CAAC,EAAE,kBAAkB,CAAC;IAEnC;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,cAAc,CAAC;IAErB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAGxC,uDAAuD;IACvD,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAEvC;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;IAEvB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAE/B;;;;OAIG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAE/B,oCAAoC;IACpC,GAAG,CAAC,EAAE,gBAAgB,CAAC;IAEvB,sEAAsE;IACtE,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,mDAAmD;IACnD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B,wDAAwD;IACxD,UAAU,CAAC,EAAE,GAAG,CAAC,cAAc,CAAC,UAAU,CAAC;IAE3C;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE;QACf,IAAI,EAAE,WAAW,GAAG,WAAW,CAAC;QAChC,SAAS,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IAEF;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,MAAM,CAAC,EAAE;QACP,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB;;;;;;;;WAQG;QACH,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IAEF;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE;QACX,OAAO,EAAE,OAAO,CAAC;QACjB,0EAA0E;QAC1E,MAAM,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;KAC7B,CAAC;IAEF;;;;;;;;;;;;;OAaG;IACH,UAAU,CAAC,EAAE;QACX,iEAAiE;QACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,iEAAiE;QACjE,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IAEF;;;OAGG;IACH,OAAO,CAAC,EAAE;QACR,wCAAwC;QACxC,OAAO,EAAE,OAAO,CAAC;QACjB,+CAA+C;QAC/C,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IAEF;;;;;;OAMG;IACH,UAAU,CAAC,EAAE;QACX,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,6DAA6D;QAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IAEF;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,oBAAoB,CAAC;CACvC;AAaD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,qBAAa,OAAQ,SAAQ,SAAS;IACpC,2CAA2C;IAC3C,SAAgB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;IAC1C,mCAAmC;IACnC,SAAgB,YAAY,EAAE,GAAG,CAAC,cAAc,CAAC,YAAY,CAAC;IAC9D,yDAAyD;IACzD,SAAgB,GAAG,EAAE,MAAM,CAAC;IAC5B,gFAAgF;IAChF,SAAgB,WAAW,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC;IACtD,wFAAwF;IACxF,SAAgB,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;IACrD,2FAA2F;IAC3F,SAAgB,eAAe,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;IAErD;;;;;;;;;;;;;;;;;OAiBG;WACU,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;IAaxF;;;;;OAKG;gBACS,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,eAAe,GAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAa;IAiU/G;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAOvB;;OAEG;IACH,OAAO,CAAC,eAAe;CAwDxB"}
|
package/dist/hosting.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { execSync } from 'node:child_process';
|
|
4
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { join, resolve } from 'node:path';
|
|
6
|
+
import { detectFramework, getAdapter, normalizeBasePath } from '@aws-blocks/hosting/adapters';
|
|
7
|
+
import { generateBuildId, HostingConstruct, } from '@aws-blocks/hosting/constructs';
|
|
3
8
|
import * as cdk from 'aws-cdk-lib';
|
|
4
|
-
import { AllowedMethods, CachePolicy, OriginRequestPolicy, ViewerProtocolPolicy
|
|
9
|
+
import { AllowedMethods, CachePolicy, OriginRequestPolicy, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
|
|
5
10
|
import { HttpOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
|
|
6
11
|
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment';
|
|
7
12
|
import { Construct } from 'constructs';
|
|
8
|
-
import { execSync } from 'node:child_process';
|
|
9
|
-
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
10
|
-
import { join, resolve } from 'node:path';
|
|
11
|
-
import { HostingConstruct, generateBuildId, } from '@aws-blocks/hosting/constructs';
|
|
12
|
-
import { detectFramework, getAdapter, normalizeBasePath, } from '@aws-blocks/hosting/adapters';
|
|
13
|
-
import { BLOCKS_RPC_PREFIX, BLOCKS_AUTH_PREFIX } from './constants.js';
|
|
14
|
-
import { BLOCKS_SANDBOX_DIR } from './common/constants.js';
|
|
15
13
|
import { registerConfig } from './cdk/config-registry.js';
|
|
14
|
+
import { BLOCKS_SANDBOX_DIR } from './common/constants.js';
|
|
15
|
+
import { BLOCKS_AUTH_PREFIX, BLOCKS_RPC_PREFIX } from './constants.js';
|
|
16
|
+
import { assertMarkersExistAtSynth, collectSynthMarkers, partitionEnvironment, resolveDomainNames, resolveSecretsAtSynth, wireByo, wireManagedValue, } from './hosting-secrets.js';
|
|
16
17
|
import { getRegisteredRoutes } from './raw-route.js';
|
|
17
18
|
// ─── Default build output directories per framework ──────────────
|
|
18
19
|
const DEFAULT_BUILD_DIRS = {
|
|
@@ -71,7 +72,43 @@ export class Hosting extends Construct {
|
|
|
71
72
|
buildCacheBucket;
|
|
72
73
|
/** SNS topic for hosting CloudWatch alarms (present when `monitoring.enabled` is true). */
|
|
73
74
|
monitoringTopic;
|
|
74
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Async constructor. Required when a `secret()` / `config()` value resolves at
|
|
77
|
+
* **synth time** — i.e. a `domain.domainName` marker — because that value is
|
|
78
|
+
* fetched from its store (Secrets Manager / SSM) during synthesis. Returns a
|
|
79
|
+
* fully-constructed {@link Hosting}.
|
|
80
|
+
*
|
|
81
|
+
* For runtime `environment` markers (read via `getSecret`/`getConfig`) and
|
|
82
|
+
* plain literals, `new Hosting(...)` works directly; `create()` is also safe
|
|
83
|
+
* to use uniformly.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* await Hosting.create(stack, 'Web', {
|
|
88
|
+
* root: '.', framework: 'nextjs', api: blocksStack,
|
|
89
|
+
* domain: { domainName: config('DOMAIN_PROD') },
|
|
90
|
+
* });
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
static async create(scope, id, props) {
|
|
94
|
+
const storeConfig = { secretStore: props.secretStore, configStore: props.configStore };
|
|
95
|
+
const synthMarkers = collectSynthMarkers(props.domain?.domainName);
|
|
96
|
+
const resolved = synthMarkers.length
|
|
97
|
+
? await resolveSecretsAtSynth(synthMarkers, undefined, storeConfig)
|
|
98
|
+
: new Map();
|
|
99
|
+
// Fail the deploy early if a declared `environment` secret/config has no value
|
|
100
|
+
// set — existence only, never fetching the value. (Domain markers above already
|
|
101
|
+
// fail this way; this extends it to runtime markers.)
|
|
102
|
+
await assertMarkersExistAtSynth(partitionEnvironment(props.environment).managed, storeConfig);
|
|
103
|
+
return new Hosting(scope, id, props, resolved);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* @param resolvedSecrets - Synth-time-resolved secret values, keyed by secret
|
|
107
|
+
* key. Populated by {@link Hosting.create}; empty for the direct
|
|
108
|
+
* `new Hosting()` path (which then rejects any synth-time secret with a
|
|
109
|
+
* clear "use Hosting.create()" error).
|
|
110
|
+
*/
|
|
111
|
+
constructor(scope, id, props, resolvedSecrets = new Map()) {
|
|
75
112
|
super(scope, id);
|
|
76
113
|
const root = resolve(props.root);
|
|
77
114
|
// ── 1. Detect framework ──────────────────────────────────────
|
|
@@ -84,7 +121,7 @@ export class Hosting extends Construct {
|
|
|
84
121
|
// from breaking frontend builds (e.g., Next.js webpack module resolution).
|
|
85
122
|
const nodeOptions = (process.env.NODE_OPTIONS || '')
|
|
86
123
|
.split(/\s+/)
|
|
87
|
-
.filter(opt => opt !== '--conditions=cdk')
|
|
124
|
+
.filter((opt) => opt !== '--conditions=cdk')
|
|
88
125
|
.join(' ');
|
|
89
126
|
const buildEnv = { ...process.env, NODE_OPTIONS: nodeOptions };
|
|
90
127
|
try {
|
|
@@ -154,8 +191,7 @@ export class Hosting extends Construct {
|
|
|
154
191
|
// errorPages will drive the CloudFront configuration correctly,
|
|
155
192
|
// and the HTML files are already in the static assets directory
|
|
156
193
|
// (copied by the adapter).
|
|
157
|
-
const manifestHasErrorPages = manifest.errorPages !== undefined &&
|
|
158
|
-
Object.keys(manifest.errorPages).length > 0;
|
|
194
|
+
const manifestHasErrorPages = manifest.errorPages !== undefined && Object.keys(manifest.errorPages).length > 0;
|
|
159
195
|
const skipPropsErrorPages = !!(props.errorPages && manifestHasErrorPages);
|
|
160
196
|
// ── 5. Write placeholder config.json into static assets ─────────
|
|
161
197
|
// A placeholder is needed so the L3 construct sees
|
|
@@ -208,15 +244,31 @@ export class Hosting extends Construct {
|
|
|
208
244
|
: props.compute.timeout,
|
|
209
245
|
}
|
|
210
246
|
: undefined;
|
|
247
|
+
// ── 6b. Resolve secret() markers ─────────────────────────────
|
|
248
|
+
// Env values split into plain / runtime-secret / deploy-time buckets;
|
|
249
|
+
// domain names may contain markers resolved at synth time. See
|
|
250
|
+
// ./hosting-secrets.ts for the two-strategy rationale.
|
|
251
|
+
const { plain: plainEnv, managed, byo } = partitionEnvironment(props.environment);
|
|
252
|
+
// Resolved domain (markers → literals); falls back to the raw config when
|
|
253
|
+
// no domain is set. resolveDomainNames throws a "use Hosting.create()"
|
|
254
|
+
// error if a domain marker reached the sync path unresolved.
|
|
255
|
+
const resolvedDomain = props.domain
|
|
256
|
+
? {
|
|
257
|
+
...props.domain,
|
|
258
|
+
domainName: resolveDomainNames(props.domain.domainName, resolvedSecrets),
|
|
259
|
+
}
|
|
260
|
+
: undefined;
|
|
211
261
|
const hostingProps = {
|
|
212
262
|
manifest,
|
|
213
263
|
compute: normalizedCompute,
|
|
214
|
-
|
|
264
|
+
// Plain env + deploy-time literals go straight to the L3 (which stays
|
|
265
|
+
// secret-agnostic: it only ever sees plain strings). Runtime secrets are
|
|
266
|
+
// wired separately below so we can attach IAM grants per function.
|
|
267
|
+
environment: Object.keys(plainEnv).length ? plainEnv : undefined,
|
|
268
|
+
domain: resolvedDomain,
|
|
215
269
|
waf: props.waf,
|
|
216
|
-
storage: props.retainOnDelete != null
|
|
217
|
-
|
|
218
|
-
: undefined,
|
|
219
|
-
cdn: (props.contentSecurityPolicy || props.priceClass || props.geoRestriction || props.quotas)
|
|
270
|
+
storage: props.retainOnDelete != null ? { retainOnDelete: props.retainOnDelete } : undefined,
|
|
271
|
+
cdn: props.contentSecurityPolicy || props.priceClass || props.geoRestriction || props.quotas
|
|
220
272
|
? {
|
|
221
273
|
contentSecurityPolicy: props.contentSecurityPolicy,
|
|
222
274
|
priceClass: props.priceClass,
|
|
@@ -251,14 +303,24 @@ export class Hosting extends Construct {
|
|
|
251
303
|
if (props.backendConfig) {
|
|
252
304
|
fn.addEnvironment('BLOCKS_CONFIG', JSON.stringify(props.backendConfig));
|
|
253
305
|
}
|
|
306
|
+
// Runtime managed markers (secret|config): inject the store locator
|
|
307
|
+
// (never the value) + grant read/decrypt; read via getSecret()/getConfig().
|
|
308
|
+
// The app's secretStore/configStore (prefix, stage, cacheTtlSeconds) layer
|
|
309
|
+
// over the Blocks defaults.
|
|
310
|
+
const storeConfig = { secretStore: props.secretStore, configStore: props.configStore };
|
|
311
|
+
for (const marker of managed) {
|
|
312
|
+
wireManagedValue(fn, marker, storeConfig);
|
|
313
|
+
}
|
|
314
|
+
// BYO handles (ISecret|IParameter): grant via the handle + inject its locator.
|
|
315
|
+
for (const binding of byo) {
|
|
316
|
+
wireByo(fn, binding, storeConfig);
|
|
317
|
+
}
|
|
254
318
|
}
|
|
255
319
|
// ── 8. Deploy config.json with resolved CDK tokens ───────────
|
|
256
320
|
const buildId = manifest.buildId;
|
|
257
321
|
if (buildId) {
|
|
258
322
|
const configDeployment = new s3deploy.BucketDeployment(this, 'BlocksConfigDeployment', {
|
|
259
|
-
sources: [
|
|
260
|
-
s3deploy.Source.jsonData('config.json', this.buildConfigJson(props)),
|
|
261
|
-
],
|
|
323
|
+
sources: [s3deploy.Source.jsonData('config.json', this.buildConfigJson(props))],
|
|
262
324
|
destinationBucket: hosting.bucket,
|
|
263
325
|
destinationKeyPrefix: `builds/${buildId}/.blocks-sandbox`,
|
|
264
326
|
prune: false,
|
|
@@ -271,10 +333,7 @@ export class Hosting extends Construct {
|
|
|
271
333
|
// primary guard against staleness is step 5a's no-cache placeholder;
|
|
272
334
|
// this is defense-in-depth so a post-deploy invalidation actually
|
|
273
335
|
// clears any edge entry at its real key.)
|
|
274
|
-
distributionPaths: [
|
|
275
|
-
`/builds/${buildId}/.blocks-sandbox/*`,
|
|
276
|
-
'/.blocks-sandbox/*',
|
|
277
|
-
],
|
|
336
|
+
distributionPaths: [`/builds/${buildId}/.blocks-sandbox/*`, '/.blocks-sandbox/*'],
|
|
278
337
|
cacheControl: [s3deploy.CacheControl.fromString('public, max-age=60, must-revalidate')],
|
|
279
338
|
});
|
|
280
339
|
// Ensure the config deployment runs AFTER the hosting construct's
|
package/dist/hosting.test.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
4
3
|
import assert from 'node:assert';
|
|
5
4
|
import * as fs from 'node:fs';
|
|
6
|
-
import * as path from 'node:path';
|
|
7
5
|
import * as os from 'node:os';
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
import { afterEach, beforeEach, describe, it } from 'node:test';
|
|
8
|
+
import { config, secret } from '@aws-blocks/hosting';
|
|
9
|
+
import { _setSynthExistsChecker } from '@aws-blocks/hosting/constructs';
|
|
8
10
|
import * as cdk from 'aws-cdk-lib';
|
|
9
11
|
import { App, Duration, Stack } from 'aws-cdk-lib';
|
|
10
|
-
import {
|
|
12
|
+
import { Match, Template } from 'aws-cdk-lib/assertions';
|
|
11
13
|
import { BLOCKS_RPC_PREFIX } from './constants.js';
|
|
12
14
|
import { Hosting } from './hosting.js';
|
|
13
15
|
import { clearRouteRegistry, registerRoute } from './raw-route.js';
|
|
@@ -84,6 +86,31 @@ describe('Hosting', () => {
|
|
|
84
86
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
85
87
|
clearRouteRegistry();
|
|
86
88
|
});
|
|
89
|
+
// ── Deploy-time existence check (key change 4) ───────────────
|
|
90
|
+
describe('environment marker existence check (Hosting.create)', () => {
|
|
91
|
+
it('rejects at deploy when a declared environment secret has no value', async () => {
|
|
92
|
+
createSpaBuildOutput(tmpDir);
|
|
93
|
+
const app = new App();
|
|
94
|
+
const stack = new Stack(app, 'MissingEnvSecretStack');
|
|
95
|
+
// Stub the synth existence probe to report "not set" — rejects before any
|
|
96
|
+
// CDK construction, so this needs no assets and no AWS.
|
|
97
|
+
_setSynthExistsChecker(async () => {
|
|
98
|
+
const e = new Error('missing');
|
|
99
|
+
e.name = 'ResourceNotFoundException';
|
|
100
|
+
throw e;
|
|
101
|
+
});
|
|
102
|
+
try {
|
|
103
|
+
await assert.rejects(Hosting.create(stack, 'Hosting', {
|
|
104
|
+
root: tmpDir,
|
|
105
|
+
api: MOCK_API,
|
|
106
|
+
environment: { MISSING_SECRET: secret('MISSING_SECRET') },
|
|
107
|
+
}), /MISSING_SECRET.*not set/s);
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
_setSynthExistsChecker(null);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
87
114
|
// ── SPA tests ────────────────────────────────────────────────
|
|
88
115
|
describe('SPA mode', () => {
|
|
89
116
|
it('creates S3 bucket and CloudFront distribution', () => {
|
|
@@ -1092,8 +1119,7 @@ describe('Hosting', () => {
|
|
|
1092
1119
|
...(basePath !== undefined ? { basePath } : {}),
|
|
1093
1120
|
});
|
|
1094
1121
|
const tpl = Template.fromStack(stack).toJSON();
|
|
1095
|
-
const kvKeys = Object.entries(tpl.Resources).find(([id, r]) => r.Type === 'AWS::CloudFormation::CustomResource' &&
|
|
1096
|
-
/RouteStoreKeys/.test(id));
|
|
1122
|
+
const kvKeys = Object.entries(tpl.Resources).find(([id, r]) => r.Type === 'AWS::CloudFormation::CustomResource' && /RouteStoreKeys/.test(id));
|
|
1097
1123
|
assert.ok(kvKeys, 'expected a RouteStoreKeys custom resource');
|
|
1098
1124
|
const entries = JSON.parse(kvKeys[1].Properties.Entries);
|
|
1099
1125
|
const meta = JSON.parse(entries.meta);
|
|
@@ -1134,6 +1160,131 @@ describe('Hosting', () => {
|
|
|
1134
1160
|
`found DependsOn=${JSON.stringify(dependsOn)}`);
|
|
1135
1161
|
});
|
|
1136
1162
|
});
|
|
1163
|
+
// ── value() integration ─────────────────────────────────────────
|
|
1164
|
+
//
|
|
1165
|
+
// Runtime values: the store LOCATOR (never the value) is injected as a Lambda
|
|
1166
|
+
// env var, and the role is granted read + kms:Decrypt. The store is derived from
|
|
1167
|
+
// the marker's type — secret → Secrets Manager, config → SSM Parameter Store.
|
|
1168
|
+
// Domain markers resolve at synth time via Hosting.create().
|
|
1169
|
+
describe('secret() / config() integration', () => {
|
|
1170
|
+
it('secret() → Secrets Manager: injects the locator (not the value) + grants read+decrypt', () => {
|
|
1171
|
+
createNextjsBuildOutput(tmpDir);
|
|
1172
|
+
const app = new App();
|
|
1173
|
+
const stack = new Stack(app, 'SecretEnvStack');
|
|
1174
|
+
new Hosting(stack, 'Hosting', {
|
|
1175
|
+
root: tmpDir,
|
|
1176
|
+
customAdapter: createNextjsFixtureAdapter(tmpDir),
|
|
1177
|
+
api: MOCK_API,
|
|
1178
|
+
environment: { STRIPE_KEY: secret('STRIPE_KEY') },
|
|
1179
|
+
});
|
|
1180
|
+
const template = Template.fromStack(stack);
|
|
1181
|
+
// secret → Secrets Manager: slash-free locator under the Blocks /blocks/secrets namespace.
|
|
1182
|
+
template.hasResourceProperties('AWS::Lambda::Function', {
|
|
1183
|
+
Environment: {
|
|
1184
|
+
Variables: Match.objectLike({ HOSTING_SECRET_PARAM_STRIPE_KEY: 'blocks/secrets/STRIPE_KEY' }),
|
|
1185
|
+
},
|
|
1186
|
+
});
|
|
1187
|
+
// The plaintext value must NOT appear anywhere in the template.
|
|
1188
|
+
const json = JSON.stringify(template.toJSON());
|
|
1189
|
+
assert.ok(!json.includes('STRIPE_KEY_VALUE'), 'no value should be in the template');
|
|
1190
|
+
// The role has secretsmanager:GetSecretValue scoped to the secret + kms:Decrypt.
|
|
1191
|
+
template.hasResourceProperties('AWS::IAM::Policy', {
|
|
1192
|
+
PolicyDocument: {
|
|
1193
|
+
Statement: Match.arrayWith([
|
|
1194
|
+
Match.objectLike({ Action: 'secretsmanager:GetSecretValue' }),
|
|
1195
|
+
Match.objectLike({
|
|
1196
|
+
Action: 'kms:Decrypt',
|
|
1197
|
+
Condition: { StringEquals: Match.objectLike({ 'kms:ViaService': Match.anyValue() }) },
|
|
1198
|
+
}),
|
|
1199
|
+
]),
|
|
1200
|
+
},
|
|
1201
|
+
});
|
|
1202
|
+
});
|
|
1203
|
+
it('threads secretStore { prefix, stage, cacheTtlSeconds } from core HostingProps to the wiring (B3)', () => {
|
|
1204
|
+
createNextjsBuildOutput(tmpDir);
|
|
1205
|
+
const app = new App();
|
|
1206
|
+
const stack = new Stack(app, 'SecretStoreOverrideStack');
|
|
1207
|
+
new Hosting(stack, 'Hosting', {
|
|
1208
|
+
root: tmpDir,
|
|
1209
|
+
customAdapter: createNextjsFixtureAdapter(tmpDir),
|
|
1210
|
+
api: MOCK_API,
|
|
1211
|
+
environment: { STRIPE_KEY: secret('STRIPE_KEY') },
|
|
1212
|
+
// Custom prefix + stage + warm-cache TTL must all reach the leaf wiring.
|
|
1213
|
+
secretStore: { prefix: '/myapp/secrets', stage: 'prod', cacheTtlSeconds: 30 },
|
|
1214
|
+
});
|
|
1215
|
+
const template = Template.fromStack(stack);
|
|
1216
|
+
template.hasResourceProperties('AWS::Lambda::Function', {
|
|
1217
|
+
Environment: {
|
|
1218
|
+
Variables: Match.objectLike({
|
|
1219
|
+
// custom prefix + stage (Secrets Manager → slash-free)
|
|
1220
|
+
HOSTING_SECRET_PARAM_STRIPE_KEY: 'myapp/secrets/prod/STRIPE_KEY',
|
|
1221
|
+
// shared fallback (no stage)
|
|
1222
|
+
HOSTING_SECRET_PARAM_STRIPE_KEY_FALLBACK: 'myapp/secrets/STRIPE_KEY',
|
|
1223
|
+
// warm-cache TTL for rotation without a cold start
|
|
1224
|
+
HOSTING_SECRET_CACHE_TTL: '30',
|
|
1225
|
+
}),
|
|
1226
|
+
},
|
|
1227
|
+
});
|
|
1228
|
+
});
|
|
1229
|
+
it('config() → SSM: HOSTING_CONFIG_PARAM_* (leading-slash) + ssm:GetParameter', () => {
|
|
1230
|
+
createNextjsBuildOutput(tmpDir);
|
|
1231
|
+
const app = new App();
|
|
1232
|
+
const stack = new Stack(app, 'ConfigEnvStack');
|
|
1233
|
+
new Hosting(stack, 'Hosting', {
|
|
1234
|
+
root: tmpDir,
|
|
1235
|
+
customAdapter: createNextjsFixtureAdapter(tmpDir),
|
|
1236
|
+
api: MOCK_API,
|
|
1237
|
+
environment: { FEATURE_FLAGS: config('FEATURE_FLAGS') },
|
|
1238
|
+
});
|
|
1239
|
+
const template = Template.fromStack(stack);
|
|
1240
|
+
template.hasResourceProperties('AWS::Lambda::Function', {
|
|
1241
|
+
Environment: {
|
|
1242
|
+
Variables: Match.objectLike({ HOSTING_CONFIG_PARAM_FEATURE_FLAGS: '/blocks/config/FEATURE_FLAGS' }),
|
|
1243
|
+
},
|
|
1244
|
+
});
|
|
1245
|
+
template.hasResourceProperties('AWS::IAM::Policy', {
|
|
1246
|
+
PolicyDocument: { Statement: Match.arrayWith([Match.objectLike({ Action: 'ssm:GetParameter' })]) },
|
|
1247
|
+
});
|
|
1248
|
+
});
|
|
1249
|
+
it('does not inject a plaintext env var for a runtime value', () => {
|
|
1250
|
+
createNextjsBuildOutput(tmpDir);
|
|
1251
|
+
const app = new App();
|
|
1252
|
+
const stack = new Stack(app, 'SecretNoPlaintextStack');
|
|
1253
|
+
new Hosting(stack, 'Hosting', {
|
|
1254
|
+
root: tmpDir,
|
|
1255
|
+
customAdapter: createNextjsFixtureAdapter(tmpDir),
|
|
1256
|
+
api: MOCK_API,
|
|
1257
|
+
environment: { FLAG: 'on', STRIPE_KEY: secret('STRIPE_KEY') },
|
|
1258
|
+
});
|
|
1259
|
+
const template = Template.fromStack(stack);
|
|
1260
|
+
const fns = template.findResources('AWS::Lambda::Function');
|
|
1261
|
+
for (const fn of Object.values(fns)) {
|
|
1262
|
+
const vars = (fn.Properties?.Environment?.Variables ?? {});
|
|
1263
|
+
assert.strictEqual(vars.STRIPE_KEY, undefined, 'value key must not be a plaintext env var');
|
|
1264
|
+
}
|
|
1265
|
+
});
|
|
1266
|
+
it('rejects a runtime value whose key mismatches the env var name', () => {
|
|
1267
|
+
createNextjsBuildOutput(tmpDir);
|
|
1268
|
+
const app = new App();
|
|
1269
|
+
const stack = new Stack(app, 'SecretMismatchStack');
|
|
1270
|
+
assert.throws(() => new Hosting(stack, 'Hosting', {
|
|
1271
|
+
root: tmpDir,
|
|
1272
|
+
customAdapter: createNextjsFixtureAdapter(tmpDir),
|
|
1273
|
+
api: MOCK_API,
|
|
1274
|
+
environment: { STRIPE_KEY: secret('OTHER') },
|
|
1275
|
+
}), /must match the environment variable name/);
|
|
1276
|
+
});
|
|
1277
|
+
it('throws if a domain marker is used with the sync constructor', () => {
|
|
1278
|
+
createSpaBuildOutput(tmpDir);
|
|
1279
|
+
const app = new App();
|
|
1280
|
+
const stack = new Stack(app, 'SecretDomainSyncStack');
|
|
1281
|
+
assert.throws(() => new Hosting(stack, 'Hosting', {
|
|
1282
|
+
root: tmpDir,
|
|
1283
|
+
api: MOCK_API,
|
|
1284
|
+
domain: { domainName: config('DOMAIN_PROD') },
|
|
1285
|
+
}), /requires async resolution/);
|
|
1286
|
+
});
|
|
1287
|
+
});
|
|
1137
1288
|
describe('config.json stale-placeholder guard (#173)', () => {
|
|
1138
1289
|
// Helper: pull every BucketDeployment custom resource's Properties.
|
|
1139
1290
|
const bucketDeployments = (stack) => {
|
|
@@ -1169,8 +1320,7 @@ describe('Hosting', () => {
|
|
|
1169
1320
|
directive.includes('s-maxage=31536000') &&
|
|
1170
1321
|
!excludes(p).includes('.blocks-sandbox/config.json'));
|
|
1171
1322
|
});
|
|
1172
|
-
assert.strictEqual(leaks.length, 0, 'no mutable-tier deployment may apply s-maxage=31536000 to ' +
|
|
1173
|
-
'.blocks-sandbox/config.json');
|
|
1323
|
+
assert.strictEqual(leaks.length, 0, 'no mutable-tier deployment may apply s-maxage=31536000 to ' + '.blocks-sandbox/config.json');
|
|
1174
1324
|
});
|
|
1175
1325
|
it('registers the placeholder as a no-cache path even for a static-only site (no api)', () => {
|
|
1176
1326
|
// The placeholder is always written (step 5), so its no-cache
|
|
@@ -1201,9 +1351,7 @@ describe('Hosting', () => {
|
|
|
1201
1351
|
// Assert via Template + Match so a CDK property rename fails loudly here
|
|
1202
1352
|
// rather than silently skipping a structural-heuristic lookup.
|
|
1203
1353
|
Template.fromStack(stack).hasResourceProperties('Custom::CDKBucketDeployment', Match.objectLike({
|
|
1204
|
-
DistributionPaths: Match.arrayWith([
|
|
1205
|
-
Match.stringLikeRegexp('^/builds/.+/\\.blocks-sandbox/\\*$'),
|
|
1206
|
-
]),
|
|
1354
|
+
DistributionPaths: Match.arrayWith([Match.stringLikeRegexp('^/builds/.+/\\.blocks-sandbox/\\*$')]),
|
|
1207
1355
|
}));
|
|
1208
1356
|
});
|
|
1209
1357
|
});
|
package/dist/index.cdk.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
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
|
+
export { type ApiHandler, ApiNamespace, type BlocksContext } from './api.js';
|
|
3
|
+
export { BlocksBackend, type BlocksBackendProps, type BlocksDefaults, BlocksPresets, BlocksStack, blocksNodejsBundling, type CoreBlocksBackendProps, type CoreBlocksStackProps, DEFAULT_NODE_RUNTIME, finalizeConfigRegistry, registerConfig, SandboxDisableDeletionProtection, Scope, SHARED_HANDLER_TIMEOUT_SECONDS, synthGuard, } from './cdk/index.js';
|
|
4
|
+
export { _resetConfigCache, getConfig, getConfigSync, loadConfigToProcessEnv, preloadConfig } from './common/config.js';
|
|
5
5
|
export { BlocksStackProps } from './common/index.js';
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
9
|
-
export { type
|
|
10
|
-
export {
|
|
11
|
-
export {
|
|
12
|
-
export {
|
|
13
|
-
export {
|
|
6
|
+
export { _resetSdkRegistry, getAllSdkIdentifiers, getSdkIdentifiers, registerSdkIdentifiers, } from './common/sdk-registry.js';
|
|
7
|
+
export { BLOCKS_AUTH_PREFIX, BLOCKS_RPC_PREFIX } from './constants.js';
|
|
8
|
+
export { ApiError, DEFAULT_API_ERROR_NAME, hasAuthError, isBlocksError } from './errors.js';
|
|
9
|
+
export { type BlocksStackApi, type ComputeConfig, type FrameworkType, Hosting, type HostingDomainConfig, type HostingProps, type HostingWafConfig, } from './hosting.js';
|
|
10
|
+
export { EventSourceMapping } from './lambda-handler.js';
|
|
11
|
+
export { __PIPELINE_STAGE_SCOPE__, type BranchConfig, DeployStage, type DeployStageProps, Pipeline, type PipelineProps, type PipelineSourceConfig, type PipelineStageConfig, type PipelineSynthConfig, } from './pipeline/index.js';
|
|
12
|
+
export { type HttpMethod, RawRoute, RawRouteErrors, type RawRouteOptions, } from './raw-route.cdk.js';
|
|
13
|
+
export { clearRouteRegistry, getRegisteredRoutes, lockRouteRegistry, matchRoute, type RegisteredRoute, registerRoute, unlockRouteRegistry, } from './raw-route.js';
|
|
14
|
+
export { BLOCKS_CONFIG_PARAMETER_PREFIX, BLOCKS_SECRET_PARAMETER_PREFIX, blocksConfigParameterName, blocksSecretParameterName, } from './secret-naming.js';
|
|
14
15
|
//# sourceMappingURL=index.cdk.d.ts.map
|
package/dist/index.cdk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cdk.d.ts","sourceRoot":"","sources":["../src/index.cdk.ts"],"names":[],"mappings":"
|
|
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,oBAAoB,EACpB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,oBAAoB,EACpB,sBAAsB,EACtB,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,sBAAsB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5F,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
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// Declare functions for infra (secret/config). The runtime getters
|
|
4
|
+
// (getSecret/getConfig) are imported from '@aws-blocks/hosting' — core's own
|
|
5
|
+
// getConfig (backend config loader, above) owns that name here.
|
|
6
|
+
export { config, DEFAULT_CONFIG_PARAMETER_PREFIX, DEFAULT_SECRET_PARAMETER_PREFIX, isConfig, isManagedValue, isSecret, secret, } from '@aws-blocks/hosting';
|
|
3
7
|
export { ApiNamespace } from './api.js';
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
9
|
-
export { BlocksStack, Scope, SandboxDisableDeletionProtection, BlocksBackend, registerConfig, finalizeConfigRegistry, synthGuard, DEFAULT_NODE_RUNTIME, blocksNodejsBundling } from './cdk/index.js';
|
|
10
|
-
export { BlocksPresets, } from './cdk/index.js';
|
|
8
|
+
export { BlocksBackend, BlocksPresets, BlocksStack, blocksNodejsBundling, DEFAULT_NODE_RUNTIME, finalizeConfigRegistry, registerConfig, SandboxDisableDeletionProtection, Scope, SHARED_HANDLER_TIMEOUT_SECONDS, synthGuard, } from './cdk/index.js';
|
|
9
|
+
export { _resetConfigCache, getConfig, getConfigSync, loadConfigToProcessEnv, preloadConfig } from './common/config.js';
|
|
10
|
+
export { _resetSdkRegistry, getAllSdkIdentifiers, getSdkIdentifiers, registerSdkIdentifiers, } from './common/sdk-registry.js';
|
|
11
|
+
export { BLOCKS_AUTH_PREFIX, BLOCKS_RPC_PREFIX } from './constants.js';
|
|
12
|
+
export { ApiError, DEFAULT_API_ERROR_NAME, hasAuthError, isBlocksError } from './errors.js';
|
|
11
13
|
export { Hosting, } from './hosting.js';
|
|
14
|
+
export { EventSourceMapping } from './lambda-handler.js';
|
|
15
|
+
export { __PIPELINE_STAGE_SCOPE__, DeployStage, Pipeline, } from './pipeline/index.js';
|
|
12
16
|
export { RawRoute, RawRouteErrors, } from './raw-route.cdk.js';
|
|
13
|
-
export {
|
|
14
|
-
export {
|
|
17
|
+
export { clearRouteRegistry, getRegisteredRoutes, lockRouteRegistry, matchRoute, registerRoute, unlockRouteRegistry, } from './raw-route.js';
|
|
18
|
+
export { BLOCKS_CONFIG_PARAMETER_PREFIX, BLOCKS_SECRET_PARAMETER_PREFIX, blocksConfigParameterName, blocksSecretParameterName, } from './secret-naming.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export { Scope, type ScopeOptions, type ScopeParent
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
1
|
+
export { type ConfigValue, config, isConfig, isManagedValue, isSecret, type ManagedValue, type SecretValue, secret, type ValueKind, } from '@aws-blocks/hosting';
|
|
2
|
+
export { type ApiHandler, ApiNamespace, type BlocksContext } from './api.js';
|
|
3
|
+
export { _resetConfigCache, getConfig, getConfigSync, loadConfigToProcessEnv, preloadConfig } from './common/config.js';
|
|
4
|
+
export { type BuildingBlockMeta, Scope, type ScopeOptions, type ScopeParent } from './common/index.js';
|
|
5
|
+
export { _resetSdkRegistry, getAllSdkIdentifiers, getSdkIdentifiers, registerSdkIdentifiers, } from './common/sdk-registry.js';
|
|
6
|
+
export { BLOCKS_AUTH_PREFIX, BLOCKS_RPC_PREFIX } from './constants.js';
|
|
7
|
+
export { ApiError, DEFAULT_API_ERROR_NAME, hasAuthError, isBlocksError } from './errors.js';
|
|
8
|
+
export { clearRouteRegistry, getRegisteredRoutes, type HttpMethod, lockRouteRegistry, matchRoute, RawRouteErrors, type RawRouteOptions, type RegisteredRoute, registerRoute, unlockRouteRegistry, } from './raw-route.js';
|
|
8
9
|
export { RawRoute } from './raw-route.mock.js';
|
|
9
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,WAAW,EAChB,MAAM,EACN,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,EAAE,iBAAiB,EAAE,SAAS,EAAE,aAAa,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxH,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACvG,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,sBAAsB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EACN,kBAAkB,EAClB,mBAAmB,EACnB,KAAK,UAAU,EACf,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,aAAa,EACb,mBAAmB,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC"}
|