canopycms-cdk 0.0.66-int.86 → 0.0.66
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.
|
@@ -79,14 +79,29 @@ export interface AssetSupportProps {
|
|
|
79
79
|
* bucket, and that must never appear in a template by accident. Pass
|
|
80
80
|
* `uploadBehavior: {}` to take the defaults.
|
|
81
81
|
*
|
|
82
|
-
* BYO-BUCKET
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* bucket
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
82
|
+
* BYO-BUCKET CAVEATS - three, and the first is about your bucket policy:
|
|
83
|
+
*
|
|
84
|
+
* 1. YOUR BUCKET POLICY IS THE ONLY GATE ON THIS ROUTE. The read behaviors
|
|
85
|
+
* reach the bucket through an OAC-SIGNED origin, so a permissive policy
|
|
86
|
+
* there is still gated by a signature CloudFront adds. This origin cannot
|
|
87
|
+
* be signed (CloudFront never hashes the body, so an OAC-signed origin
|
|
88
|
+
* rejects every multipart POST), so nothing gates it but the policy. The
|
|
89
|
+
* route is contained by rewriting every request to `/`, which leaves an
|
|
90
|
+
* anonymous caller only the bucket-level operations at the root - so what
|
|
91
|
+
* your policy grants anonymously AT THE BUCKET ROOT is what is reachable.
|
|
92
|
+
* A bucket this construct creates refuses all of them (BLOCK_ALL, no
|
|
93
|
+
* public policy); an existing bucket is yours to have got right, and "the
|
|
94
|
+
* read path already works" is not evidence that it is.
|
|
95
|
+
* 2. This origin addresses the bucket by `bucketRegionalDomainName`, and for
|
|
96
|
+
* a bucket imported with `Bucket.fromBucketName()` that resolves to the
|
|
97
|
+
* STACK's region, not the bucket's. The read path tolerates a mismatch
|
|
98
|
+
* because CloudFront follows S3's region redirect on an S3-type origin;
|
|
99
|
+
* this one is a custom origin and does not, so S3's 301 reaches the
|
|
100
|
+
* browser, where a redirected cross-origin POST surfaces as an opaque
|
|
101
|
+
* network error. Import a cross-region bucket with
|
|
102
|
+
* `Bucket.fromBucketAttributes({ region })` so the domain name is right.
|
|
103
|
+
* 3. A DOT in the bucket name breaks this origin specifically - refused at
|
|
104
|
+
* synth, with the reason, in `buildUploadBehavior`.
|
|
90
105
|
*
|
|
91
106
|
* @default - no upload behavior is built
|
|
92
107
|
*/
|
|
@@ -343,6 +358,12 @@ export declare class AssetSupport extends Construct {
|
|
|
343
358
|
* added. Loud, not silent.
|
|
344
359
|
*/
|
|
345
360
|
private upload?;
|
|
361
|
+
/**
|
|
362
|
+
* The origin inside `upload`, kept so the validation below can ask whether
|
|
363
|
+
* that behavior was ever attached to a distribution - see `UploadOrigin`.
|
|
364
|
+
* Set by `buildUploadBehavior`, i.e. at the same moment as `upload`.
|
|
365
|
+
*/
|
|
366
|
+
private uploadOrigin?;
|
|
346
367
|
constructor(scope: Construct, id: string, props: AssetSupportProps);
|
|
347
368
|
private buildBehaviors;
|
|
348
369
|
/**
|
|
@@ -353,9 +374,9 @@ export declare class AssetSupport extends Construct {
|
|
|
353
374
|
/**
|
|
354
375
|
* The two CloudFront behavior configs this system needs.
|
|
355
376
|
*
|
|
356
|
-
* If you use this rather than `attachTo` -- which
|
|
357
|
-
* parameter, so needing per-behavior options is
|
|
358
|
-
*
|
|
377
|
+
* If you use this rather than `attachTo` -- which takes an `overrides`
|
|
378
|
+
* parameter, so needing per-behavior options is not a reason to fall back
|
|
379
|
+
* here -- you own the ordering, and you should assert it: read the
|
|
359
380
|
* SYNTHESIZED template's `CacheBehaviors` array index, not your own source
|
|
360
381
|
* object, since the property is about emitted order.
|
|
361
382
|
*
|
|
@@ -448,14 +469,11 @@ export declare class AssetSupport extends Construct {
|
|
|
448
469
|
* has left this method's remit and should use `assetBehaviors()` - and keep
|
|
449
470
|
* their own ordering assertion.
|
|
450
471
|
*
|
|
451
|
-
* Typed `Partial<AddBehaviorOptions
|
|
452
|
-
* `addBehavior
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
* claimed the opposite: widening the parameter and passing an `origin`
|
|
457
|
-
* override changes nothing in the emitted template, so this narrowing
|
|
458
|
-
* prevents a confusing no-op rather than a broken origin group.
|
|
472
|
+
* Typed `Partial<AddBehaviorOptions>`, not `BehaviorOptions`, because
|
|
473
|
+
* `addBehavior` takes `origin` positionally - so an `origin` key here would be
|
|
474
|
+
* a silently ignored no-op. (Measured: passing one changes nothing in the
|
|
475
|
+
* emitted template. It is a confusing no-op being prevented, not a broken
|
|
476
|
+
* origin group.)
|
|
459
477
|
*
|
|
460
478
|
* Needs a concrete `cloudfront.Distribution` - `addBehavior` is an instance
|
|
461
479
|
* method on that class, not on `IDistribution` (what an imported/looked-up
|
|
@@ -32,17 +32,11 @@ const transformAssetDir = path.join(__dirname, '..', '..', 'lambda', 'asset-tran
|
|
|
32
32
|
*/
|
|
33
33
|
const DEPLOYABLE_MARKER = '.deployable';
|
|
34
34
|
/**
|
|
35
|
-
* The four S3 key prefixes the asset system uses
|
|
36
|
-
* `packages/canopycms/src/assets/asset-prefixes.ts
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* have `canopycms` itself resolvable from wherever its CDK code runs. The
|
|
41
|
-
* transform Lambda (../../lambda/asset-transform/handler.ts), by contrast,
|
|
42
|
-
* is bundled at build time from WITHIN this package (where `canopycms` is a
|
|
43
|
-
* real workspace devDependency), so it imports the canonical constants
|
|
44
|
-
* directly from `canopycms/server` instead of duplicating them - see that
|
|
45
|
-
* file's doc comment.
|
|
35
|
+
* The four S3 key prefixes the asset system uses. Source of truth is
|
|
36
|
+
* `packages/canopycms/src/assets/asset-prefixes.ts`; these are copied as
|
|
37
|
+
* literals rather than imported so this construct synths in a consumer CDK app
|
|
38
|
+
* that has no `canopycms` resolvable. (The transform Lambda does import them -
|
|
39
|
+
* it is bundled from inside this package; see its handler's doc comment.)
|
|
46
40
|
*/
|
|
47
41
|
const PREFIXES = {
|
|
48
42
|
originals: 'asset-originals',
|
|
@@ -141,23 +135,64 @@ const TRANSFORM_CACHE_MIN_TTL = Duration.seconds(0);
|
|
|
141
135
|
const TRANSFORM_CACHE_DEFAULT_TTL = Duration.days(1);
|
|
142
136
|
const TRANSFORM_CACHE_MAX_TTL = Duration.days(365);
|
|
143
137
|
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
138
|
+
* Id of the marker construct `attachTo` adds to a distribution to record that
|
|
139
|
+
* the asset behaviors are already on it.
|
|
146
140
|
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
141
|
+
* The fact being recorded is "THIS distribution already carries these two
|
|
142
|
+
* patterns", so it is stored ON that distribution rather than in a module-level
|
|
143
|
+
* registry. Per-INSTANCE state was the first version and was wrong: two
|
|
144
|
+
* different `AssetSupport` constructs attaching to one distribution slipped
|
|
145
|
+
* through and synthesized ['/assets/t/*','/assets/*','/assets/t/*','/assets/*'],
|
|
146
|
+
* the duplicate-path-pattern deploy failure the guard exists to convert into a
|
|
147
|
+
* synth error. There is no legitimate form of that - both instances attach the
|
|
148
|
+
* same two patterns, so the second is always wrong regardless of which construct
|
|
149
|
+
* owns it - so the check has to be keyed on the distribution, not the attacher.
|
|
155
150
|
*
|
|
156
|
-
* A `WeakSet` keyed on the distribution object
|
|
157
|
-
*
|
|
158
|
-
*
|
|
151
|
+
* A module-level `WeakSet` keyed on the distribution object did that correctly
|
|
152
|
+
* (a `cloudfront.Distribution` instance belongs to exactly one construct tree,
|
|
153
|
+
* and `attachTo` takes a concrete instance, so one could never be claimed by a
|
|
154
|
+
* second CDK app). A child construct is preferred anyway because the scoping is
|
|
155
|
+
* then a property of the tree rather than something the reader has to reason
|
|
156
|
+
* about process lifetime to trust - and it is visible in `node.children`, so a
|
|
157
|
+
* test can assert the guard's state instead of only its error.
|
|
158
|
+
*
|
|
159
|
+
* The marker is a bare `Construct`, which emits nothing into the template.
|
|
160
|
+
*/
|
|
161
|
+
const ATTACHED_MARKER_ID = 'CanopyAssetBehaviorsAttached';
|
|
162
|
+
/**
|
|
163
|
+
* The upload behavior's origin, which records having been bound to a
|
|
164
|
+
* distribution.
|
|
165
|
+
*
|
|
166
|
+
* This exists so the synth-time validation below can tell "`uploadBehavior()`
|
|
167
|
+
* was CALLED" from "its result actually reached a distribution" - two states a
|
|
168
|
+
* memoized accessor cannot distinguish on its own, and the second is the one
|
|
169
|
+
* that determines whether anything supplies Access-Control-Allow-Origin.
|
|
170
|
+
*
|
|
171
|
+
* CDK calls `bind()` exactly when a `Distribution` takes a behavior: from the
|
|
172
|
+
* constructor for `defaultBehavior` (the topology `uploadBehavior()`
|
|
173
|
+
* recommends), and from `addBehavior` for an additional one. Both shapes, and a
|
|
174
|
+
* distribution in a different stack, are pinned as PASSING cases in
|
|
175
|
+
* asset-support.test.ts - a mechanism that only sees one of them would fail the
|
|
176
|
+
* other two at synth. All three bind eagerly at construction, before any
|
|
177
|
+
* validation runs. A behavior that is built and then dropped never binds.
|
|
178
|
+
*
|
|
179
|
+
* Observing the origin rather than searching the tree for the emitted behavior
|
|
180
|
+
* is what makes the cross-stack case work. Measured: a consuming stack renders
|
|
181
|
+
* the reference as `Fn::ImportValue`, not as the producing stack's resolved ARN,
|
|
182
|
+
* so a tree search would report "not attached" for a perfectly correct
|
|
183
|
+
* cross-stack distribution - a false synth failure, which is worse than the gap
|
|
184
|
+
* it closes.
|
|
159
185
|
*/
|
|
160
|
-
|
|
186
|
+
class UploadOrigin extends origins.HttpOrigin {
|
|
187
|
+
constructor() {
|
|
188
|
+
super(...arguments);
|
|
189
|
+
this.attachedToDistribution = false;
|
|
190
|
+
}
|
|
191
|
+
bind(scope, options) {
|
|
192
|
+
this.attachedToDistribution = true;
|
|
193
|
+
return super.bind(scope, options);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
161
196
|
/**
|
|
162
197
|
* The two CloudFront path patterns the asset system's behaviors are keyed
|
|
163
198
|
* under, derived from `PREFIXES` above (the single source of truth for these
|
|
@@ -440,27 +475,41 @@ export class AssetSupport extends Construct {
|
|
|
440
475
|
allowedOrigins: props.uploadBehavior.allowedOrigins?.slice(),
|
|
441
476
|
};
|
|
442
477
|
// Setting `uploadBehavior` SATISFIES the standalone guard above, but only
|
|
443
|
-
//
|
|
478
|
+
// ATTACHING the behavior to a distribution actually produces an
|
|
444
479
|
// Access-Control-Allow-Origin from anywhere. Opting in and stopping there -
|
|
445
480
|
// which is exactly what copying the README snippet and not finishing looks
|
|
446
481
|
// like - lands a standalone bucket with no CORS rule and no edge route: the
|
|
447
482
|
// silent failure the guard's own text calls misleading, reached through the
|
|
448
483
|
// guard rather than around it.
|
|
449
484
|
//
|
|
485
|
+
// The condition is ATTACHMENT, not `uploadBehavior()` having been called.
|
|
486
|
+
// Those look equivalent and are not: the accessor memoizes, so a caller who
|
|
487
|
+
// invokes it and loses the value in a refactor sets every flag an accessor
|
|
488
|
+
// can set and still lands in exactly the state above. That shape is if
|
|
489
|
+
// anything likelier than never calling it at all, since it is what a
|
|
490
|
+
// half-finished copy of the README snippet leaves behind. `UploadOrigin`
|
|
491
|
+
// (above) is what makes the difference observable from here.
|
|
492
|
+
//
|
|
450
493
|
// A synth-time validation is the only place this can be caught, since the
|
|
451
494
|
// constructor cannot know what the caller will do next. It is the first
|
|
452
495
|
// `addValidation` in this package; the alternative (checking in the
|
|
453
496
|
// constructor) cannot express "and nothing used it".
|
|
454
497
|
this.node.addValidation({
|
|
455
498
|
validate: () => {
|
|
456
|
-
if (props.uploadBehavior &&
|
|
499
|
+
if (props.uploadBehavior &&
|
|
500
|
+
editorOrigins.length === 0 &&
|
|
501
|
+
!props.bucket &&
|
|
502
|
+
!this.uploadOrigin?.attachedToDistribution) {
|
|
457
503
|
return [
|
|
458
|
-
'AssetSupport: `uploadBehavior` was set but
|
|
459
|
-
'
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
'`editorOrigins`
|
|
504
|
+
'AssetSupport: `uploadBehavior` was set but the upload behavior was never attached ' +
|
|
505
|
+
'to a distribution' +
|
|
506
|
+
(this.upload
|
|
507
|
+
? ' - uploadBehavior() was called, but its return value was not passed to one'
|
|
508
|
+
: ' - uploadBehavior() was never called') +
|
|
509
|
+
', so nothing supplies Access-Control-Allow-Origin. With no `editorOrigins` ' +
|
|
510
|
+
'either, a browser upload will land the object in asset-staging/ and still ' +
|
|
511
|
+
'report a network error. Pass the behavior to a distribution (see ' +
|
|
512
|
+
"uploadBehavior()'s doc comment), or pass `editorOrigins` instead.",
|
|
464
513
|
];
|
|
465
514
|
}
|
|
466
515
|
return [];
|
|
@@ -559,9 +608,10 @@ export class AssetSupport extends Construct {
|
|
|
559
608
|
`every upload. The read behaviors are unaffected (they use an S3-type origin). Use a ` +
|
|
560
609
|
`dot-free bucket for uploads, or route uploads somewhere other than this construct.`);
|
|
561
610
|
}
|
|
562
|
-
const uploadOrigin = new
|
|
611
|
+
const uploadOrigin = new UploadOrigin(this.bucket.bucketRegionalDomainName, {
|
|
563
612
|
protocolPolicy: cloudfront.OriginProtocolPolicy.HTTPS_ONLY,
|
|
564
613
|
});
|
|
614
|
+
this.uploadOrigin = uploadOrigin;
|
|
565
615
|
// S3's POST Object is only valid at the bucket ROOT - without this rewrite
|
|
566
616
|
// the upload gets 405 MethodNotAllowed. It is also what CONTAINS this
|
|
567
617
|
// behavior: rewriting unconditionally means no request arriving here can
|
|
@@ -569,8 +619,18 @@ export class AssetSupport extends Construct {
|
|
|
569
619
|
// only the bucket-level operations at `/` (list, create, delete bucket).
|
|
570
620
|
// A bucket this construct creates refuses all of them anonymously
|
|
571
621
|
// (BLOCK_ALL, no public policy); in BYO-bucket mode that is the caller's
|
|
572
|
-
// bucket policy to have got right
|
|
573
|
-
//
|
|
622
|
+
// bucket policy to have got right.
|
|
623
|
+
//
|
|
624
|
+
// Their bucket policy is a WEAKER backstop here than on the read path, and
|
|
625
|
+
// the two must not be read as equivalent: the read behaviors go through an
|
|
626
|
+
// OAC-SIGNED origin, so a too-permissive policy there is still gated by a
|
|
627
|
+
// signature CloudFront adds. This origin is deliberately unsigned (it has
|
|
628
|
+
// to be - see the OAC note at the top of this method), so on a BYO bucket
|
|
629
|
+
// the policy is the ONLY thing standing between an anonymous caller and
|
|
630
|
+
// whatever that policy allows at `/`. Stated where a BYO adopter reads it,
|
|
631
|
+
// in `uploadBehavior()`'s caveat block, not only here.
|
|
632
|
+
//
|
|
633
|
+
// The only thing that can WRITE either way is a request carrying a valid
|
|
574
634
|
// presigned policy, and only to the single key that policy names. Do not
|
|
575
635
|
// make the rewrite conditional; that gives key addressability back.
|
|
576
636
|
//
|
|
@@ -730,9 +790,9 @@ export class AssetSupport extends Construct {
|
|
|
730
790
|
/**
|
|
731
791
|
* The two CloudFront behavior configs this system needs.
|
|
732
792
|
*
|
|
733
|
-
* If you use this rather than `attachTo` -- which
|
|
734
|
-
* parameter, so needing per-behavior options is
|
|
735
|
-
*
|
|
793
|
+
* If you use this rather than `attachTo` -- which takes an `overrides`
|
|
794
|
+
* parameter, so needing per-behavior options is not a reason to fall back
|
|
795
|
+
* here -- you own the ordering, and you should assert it: read the
|
|
736
796
|
* SYNTHESIZED template's `CacheBehaviors` array index, not your own source
|
|
737
797
|
* object, since the property is about emitted order.
|
|
738
798
|
*
|
|
@@ -838,14 +898,11 @@ export class AssetSupport extends Construct {
|
|
|
838
898
|
* has left this method's remit and should use `assetBehaviors()` - and keep
|
|
839
899
|
* their own ordering assertion.
|
|
840
900
|
*
|
|
841
|
-
* Typed `Partial<AddBehaviorOptions
|
|
842
|
-
* `addBehavior
|
|
843
|
-
*
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
* claimed the opposite: widening the parameter and passing an `origin`
|
|
847
|
-
* override changes nothing in the emitted template, so this narrowing
|
|
848
|
-
* prevents a confusing no-op rather than a broken origin group.
|
|
901
|
+
* Typed `Partial<AddBehaviorOptions>`, not `BehaviorOptions`, because
|
|
902
|
+
* `addBehavior` takes `origin` positionally - so an `origin` key here would be
|
|
903
|
+
* a silently ignored no-op. (Measured: passing one changes nothing in the
|
|
904
|
+
* emitted template. It is a confusing no-op being prevented, not a broken
|
|
905
|
+
* origin group.)
|
|
849
906
|
*
|
|
850
907
|
* Needs a concrete `cloudfront.Distribution` - `addBehavior` is an instance
|
|
851
908
|
* method on that class, not on `IDistribution` (what an imported/looked-up
|
|
@@ -864,14 +921,14 @@ export class AssetSupport extends Construct {
|
|
|
864
921
|
// ['/assets/t/*','/assets/*','/assets/t/*','/assets/*'] and fails at
|
|
865
922
|
// deploy time when CloudFront rejects the duplicate patterns. Refuse it
|
|
866
923
|
// here instead, where the message can say which two routes collided.
|
|
867
|
-
if (
|
|
924
|
+
if (distribution.node.tryFindChild(ATTACHED_MARKER_ID)) {
|
|
868
925
|
throw new Error(`AssetSupport: attachTo() was already called for this distribution. Each pattern ` +
|
|
869
926
|
`would be attached twice and CloudFront rejects duplicate path patterns at deploy ` +
|
|
870
927
|
`time. This usually means the distribution was given CanopyCmsDistribution's ` +
|
|
871
928
|
`\`assetSupport\` prop (which calls attachTo for you) as well as an explicit ` +
|
|
872
929
|
`attachTo() call -- keep one.`);
|
|
873
930
|
}
|
|
874
|
-
|
|
931
|
+
new Construct(distribution, ATTACHED_MARKER_ID);
|
|
875
932
|
// Drop explicitly-`undefined` keys before merging. A spread copies own
|
|
876
933
|
// enumerable keys INCLUDING ones whose value is undefined, so
|
|
877
934
|
// `{ ...transformRest, ...{ cachePolicy: undefined } }` deletes the
|
|
@@ -69,12 +69,13 @@ export interface CanopyCmsDistributionProps {
|
|
|
69
69
|
* order matters. Calls `assetSupport.attachTo(distribution)` for you right
|
|
70
70
|
* after construction, with nothing to forget.
|
|
71
71
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
72
|
+
* If the asset behaviors need per-behavior options - a viewer-request
|
|
73
|
+
* function for tier auth being the motivating case, since without it
|
|
74
|
+
* `/assets/*` is anonymously readable on an authenticated tier - pass
|
|
75
|
+
* `assetBehaviorOverrides` alongside this prop. That requirement used to mean
|
|
76
|
+
* dropping this prop and hand-calling `attachTo` after construction, which
|
|
77
|
+
* sent exactly the adopter who most needs the ordering guarantee back to the
|
|
78
|
+
* manual path this prop exists to replace.
|
|
78
79
|
*
|
|
79
80
|
* Prefer this over passing `assetSupport.assetBehaviors()` through
|
|
80
81
|
* `additionalBehaviors` by hand - that stays available as an escape hatch
|
|
@@ -89,6 +90,27 @@ export interface CanopyCmsDistributionProps {
|
|
|
89
90
|
* @default - no asset behaviors are attached
|
|
90
91
|
*/
|
|
91
92
|
assetSupport?: AssetSupport;
|
|
93
|
+
/**
|
|
94
|
+
* Per-behavior options merged into BOTH asset behaviors, forwarded verbatim
|
|
95
|
+
* to `AssetSupport.attachTo()`'s `overrides` parameter - see that method's
|
|
96
|
+
* doc comment for the merge semantics and for why the same set goes to both.
|
|
97
|
+
*
|
|
98
|
+
* The motivating case is a distribution running a viewer-request function on
|
|
99
|
+
* every behavior (tier basic-auth): without the same `functionAssociations`
|
|
100
|
+
* on the asset behaviors, `/assets/*` is anonymously readable on an
|
|
101
|
+
* authenticated tier.
|
|
102
|
+
*
|
|
103
|
+
* Useless without `assetSupport`, and silently so - there would be no
|
|
104
|
+
* behaviors to merge it into - so that combination throws from this
|
|
105
|
+
* construct's CONSTRUCTOR rather than being ignored. (A constructor throw,
|
|
106
|
+
* not an `addValidation`: nothing later can make the combination valid. An
|
|
107
|
+
* adopter sharing one props object across tiers, with `assetSupport` present
|
|
108
|
+
* on only some of them, should make the whole prop conditional rather than
|
|
109
|
+
* the overrides object.)
|
|
110
|
+
*
|
|
111
|
+
* @default - the asset behaviors are attached with no overrides
|
|
112
|
+
*/
|
|
113
|
+
assetBehaviorOverrides?: Partial<cloudfront.AddBehaviorOptions>;
|
|
92
114
|
}
|
|
93
115
|
/**
|
|
94
116
|
* Optional CDK construct for CanopyCMS CloudFront distribution.
|
|
@@ -152,6 +152,17 @@ function assertNoAssetBehaviorOrderingHazards(merged, attachingAssetSupport) {
|
|
|
152
152
|
export class CanopyCmsDistribution extends Construct {
|
|
153
153
|
constructor(scope, id, props) {
|
|
154
154
|
super(scope, id);
|
|
155
|
+
// Overrides with nothing to override. They are merged into the asset
|
|
156
|
+
// behaviors and there are none, so the only outcome is that whatever the
|
|
157
|
+
// caller asked for - a tier-auth viewer function, most likely - silently
|
|
158
|
+
// does not happen.
|
|
159
|
+
if (props.assetBehaviorOverrides && !props.assetSupport) {
|
|
160
|
+
throw new Error('CanopyCmsDistribution: `assetBehaviorOverrides` was passed without `assetSupport`. ' +
|
|
161
|
+
'The overrides are merged into the asset behaviors, so with no AssetSupport to attach ' +
|
|
162
|
+
'there is nothing for them to apply to and they would be silently dropped - including ' +
|
|
163
|
+
'a viewer-request function for tier auth. Pass `assetSupport` as well, or drop the ' +
|
|
164
|
+
'overrides.');
|
|
165
|
+
}
|
|
155
166
|
// ========================================================================
|
|
156
167
|
// DNS — Hosted Zone lookup
|
|
157
168
|
// ========================================================================
|
|
@@ -280,7 +291,11 @@ export class CanopyCmsDistribution extends Construct {
|
|
|
280
291
|
// logic lives exactly once, inside attachTo() itself. Callers who instead
|
|
281
292
|
// pass `assetSupport.assetBehaviors()` through `additionalBehaviors` by
|
|
282
293
|
// hand are covered by `mergeBehaviors`'s synth-time guard above instead.
|
|
283
|
-
|
|
294
|
+
//
|
|
295
|
+
// `assetBehaviorOverrides` is forwarded so that needing per-behavior
|
|
296
|
+
// options is not a reason to leave this prop - and so the ordering
|
|
297
|
+
// guarantee survives the tier-auth case that most needs it.
|
|
298
|
+
props.assetSupport?.attachTo(this.distribution, props.assetBehaviorOverrides);
|
|
284
299
|
// ========================================================================
|
|
285
300
|
// DNS Records
|
|
286
301
|
// ========================================================================
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "canopycms-cdk",
|
|
3
|
-
"version": "0.0.66
|
|
3
|
+
"version": "0.0.66",
|
|
4
4
|
"description": "AWS CDK constructs and EC2 worker for CanopyCMS deployment",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"aws-cdk-lib": "^2.260.0",
|
|
33
33
|
"constructs": "^10.0.0",
|
|
34
|
-
"canopycms": "0.0.66
|
|
34
|
+
"canopycms": "0.0.66"
|
|
35
35
|
},
|
|
36
36
|
"peerDependenciesMeta": {
|
|
37
37
|
"aws-cdk-lib": {
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"tsx": "^4.19.0",
|
|
56
56
|
"typescript": "^5.6.3",
|
|
57
57
|
"vitest": "^4.1.0",
|
|
58
|
-
"canopycms": "0.0.66
|
|
59
|
-
"canopycms-auth-clerk": "0.0.66
|
|
58
|
+
"canopycms": "0.0.66",
|
|
59
|
+
"canopycms-auth-clerk": "0.0.66"
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
62
|
"build": "rm -rf dist && tsc && node ../../scripts/add-js-extensions.mjs dist",
|