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 CAVEAT: this origin addresses the bucket by
83
- * `bucketRegionalDomainName`, and for a bucket imported with
84
- * `Bucket.fromBucketName()` that resolves to the STACK's region, not the
85
- * bucket's. The read path tolerates a mismatch because CloudFront follows
86
- * S3's region redirect on an S3-type origin; this one is a custom origin and
87
- * does not, so S3's 301 reaches the browser, where a redirected cross-origin
88
- * POST surfaces as an opaque network error. Import a cross-region bucket
89
- * with `Bucket.fromBucketAttributes({ region })` so the domain name is right.
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 now takes an `overrides`
357
- * parameter, so needing per-behavior options is no longer a reason to fall
358
- * back here -- you own the ordering, and you should assert it: read the
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>` because that is exactly what
452
- * `addBehavior(pattern, origin, behaviorOptions?)` accepts - `origin` is a
453
- * POSITIONAL argument there, so `BehaviorOptions` (which is
454
- * `AddBehaviorOptions` plus `origin`) would let a caller pass a key the call
455
- * silently ignores. Measured, because the first version of this comment
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, mirrored from
36
- * `packages/canopycms/src/assets/asset-prefixes.ts` (the source of truth).
37
- * Duplicated as plain string literals - not imported from `canopycms` -
38
- * because this construct must synth cleanly for ANY consumer's CDK app
39
- * (e.g. a site's own `infrastructure/` package), which has no reason to
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
- * Distributions that already carry the asset behaviors, tracked at MODULE level
145
- * rather than per instance.
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
- * Per-instance (the first version of this) only caught the same `AssetSupport`
148
- * attaching twice. Two `AssetSupport` constructs attaching to one distribution
149
- * slipped through and synthesized
150
- * ['/assets/t/*','/assets/*','/assets/t/*','/assets/*'] - the identical
151
- * duplicate-path-pattern deploy failure the guard exists to convert into a
152
- * synth error. There is no legitimate form of that: both instances attach the
153
- * same two patterns, so the second is always wrong regardless of which
154
- * construct owns it.
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, so it holds no reference that
157
- * would outlive the construct tree and cannot leak across CDK apps in a test
158
- * process.
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
- const distributionsWithAssetBehaviors = new WeakSet();
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
- // calling `uploadBehavior()` and attaching the result actually produces an
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 && editorOrigins.length === 0 && !props.bucket && !this.upload) {
499
+ if (props.uploadBehavior &&
500
+ editorOrigins.length === 0 &&
501
+ !props.bucket &&
502
+ !this.uploadOrigin?.attachedToDistribution) {
457
503
  return [
458
- 'AssetSupport: `uploadBehavior` was set but uploadBehavior() was never called, so ' +
459
- 'no upload behavior was attached to any distribution and nothing supplies ' +
460
- 'Access-Control-Allow-Origin. With no `editorOrigins` either, a browser upload ' +
461
- 'will land the object in asset-staging/ and still report a network error. Pass ' +
462
- "the behavior to a distribution (see uploadBehavior()'s doc comment), or pass " +
463
- '`editorOrigins` instead.',
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 origins.HttpOrigin(this.bucket.bucketRegionalDomainName, {
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, as it already is for the read path. The
573
- // only thing that can WRITE either way is a request carrying a valid
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 now takes an `overrides`
734
- * parameter, so needing per-behavior options is no longer a reason to fall
735
- * back here -- you own the ordering, and you should assert it: read the
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>` because that is exactly what
842
- * `addBehavior(pattern, origin, behaviorOptions?)` accepts - `origin` is a
843
- * POSITIONAL argument there, so `BehaviorOptions` (which is
844
- * `AddBehaviorOptions` plus `origin`) would let a caller pass a key the call
845
- * silently ignores. Measured, because the first version of this comment
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 (distributionsWithAssetBehaviors.has(distribution)) {
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
- distributionsWithAssetBehaviors.add(distribution);
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
- * NOT fully equivalent to calling `attachTo` yourself: this path cannot pass
73
- * that method's `overrides` argument. If the asset behaviors need
74
- * per-behavior options - a viewer-request function for tier auth being the
75
- * motivating case, since without it `/assets/*` is anonymously readable on
76
- * an authenticated tier - drop this prop and call
77
- * `assetSupport.attachTo(this.distribution, { ... })` after construction.
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
- props.assetSupport?.attachTo(this.distribution);
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-int.86",
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-int.86"
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-int.86",
59
- "canopycms-auth-clerk": "0.0.66-int.86"
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",