@fjall/components-infrastructure 33.0.0 → 33.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +15 -76
  2. package/dist/lib/app.d.ts +1 -1
  3. package/dist/lib/config/aws/identityCentreConfig.d.ts +1 -1
  4. package/dist/lib/config/aws/identityCentreConfig.js +1 -1
  5. package/dist/lib/config/aws/scpPreset.js +1 -2
  6. package/dist/lib/lambda-assets/cert-generator/asset/index.js +126 -0
  7. package/dist/lib/patterns/aws/buildkite/buildkite.d.ts +1 -1
  8. package/dist/lib/patterns/aws/buildkite/buildkite.js +1 -1
  9. package/dist/lib/patterns/aws/buildkite/factory.d.ts +2 -2
  10. package/dist/lib/patterns/aws/buildkite/pins.d.ts +2 -2
  11. package/dist/lib/patterns/aws/buildkite/pins.js +2 -2
  12. package/dist/lib/patterns/aws/buildkite/schema.d.ts +1 -1
  13. package/dist/lib/patterns/aws/buildkite/schema.js +1 -1
  14. package/dist/lib/patterns/aws/buildkite/userData.d.ts +1 -1
  15. package/dist/lib/patterns/aws/buildkite/userData.js +1 -1
  16. package/dist/lib/patterns/aws/buildkite.d.ts +1 -1
  17. package/dist/lib/patterns/aws/buildkite.js +1 -1
  18. package/dist/lib/patterns/aws/clickhouseDatabase.js +4 -1
  19. package/dist/lib/patterns/aws/clickhouseTls/types.d.ts +1 -1
  20. package/dist/lib/patterns/aws/computeEcsTypes.d.ts +5 -5
  21. package/dist/lib/patterns/aws/payload.js +6 -2
  22. package/dist/lib/patterns/aws/storage.d.ts +8 -0
  23. package/dist/lib/patterns/aws/storage.js +1 -0
  24. package/dist/lib/resources/aws/cdn/responseHeadersPolicy.d.ts +1 -1
  25. package/dist/lib/resources/aws/cdn/responseHeadersPolicy.js +1 -1
  26. package/dist/lib/resources/aws/compute/ec2.d.ts +2 -2
  27. package/dist/lib/resources/aws/compute/ec2.js +1 -1
  28. package/dist/lib/resources/aws/database/clickhouseConstants.d.ts +5 -5
  29. package/dist/lib/resources/aws/database/clickhouseConstants.js +5 -5
  30. package/dist/lib/resources/aws/iam/identityCenter/user.d.ts +1 -1
  31. package/dist/lib/resources/aws/iam/identityCenter/user.js +1 -1
  32. package/dist/lib/resources/aws/storage/bucketDeployment.d.ts +2 -3
  33. package/dist/lib/resources/aws/storage/bucketDeployment.js +2 -3
  34. package/dist/lib/resources/aws/storage/s3.d.ts +13 -1
  35. package/dist/lib/resources/aws/storage/s3.js +6 -3
  36. package/package.json +4 -3
package/README.md CHANGED
@@ -54,84 +54,23 @@ for each of the two secrets.
54
54
 
55
55
  ## Useful commands
56
56
 
57
- - `npm run build` compile typescript to js
58
- - `npm run watch` watch for changes and compile
59
- - `npm run test` perform the jest unit tests
60
- - `cdk deploy` deploy this stack to your default AWS account/region
61
- - `cdk diff` compare deployed stack with current state
62
- - `cdk synth` emits the synthesized CloudFormation template
57
+ - `npm run build` — clean, bundle the Lambda assets and compile TypeScript to `dist/`
58
+ - `npm run watch` — recompile on change
59
+ - `npm test` — run the Vitest suites
60
+ - `npm run typecheck` — type-check the library
63
61
 
64
- ## Building patterns
62
+ Synthesis and deployment go through the `fjall` CLI (`fjall deploy`), which
63
+ assembles the stacks from an application's `fjall/` directory. The package is
64
+ not deployed with `cdk deploy` on its own.
65
65
 
66
- Common service patterns are built using a Stack class (i.e AwsStack) and use a builder pattern.
66
+ ## Using the constructs
67
67
 
68
- ### Referencing VPC
68
+ The constructs are consumed through the `fjall` CLI: `fjall create app` and
69
+ `fjall add <resource>` write the `infrastructure.ts` that composes them, and
70
+ `fjall deploy` synthesises and deploys it. Every construct is also exported
71
+ from the package root for direct use; the reference lives at
72
+ [docs.fjall.io](https://docs.fjall.io).
69
73
 
70
- There are three main ways to reference a VPC
74
+ ## Licence
71
75
 
72
- 1. In the same stack
73
-
74
- When a VPC is created in the same stack resources that rely on it will automatically detect it.
75
-
76
- ```typescript
77
- new AwsStack(`${id}App`)
78
- .addNetwork(FjallVpc.build(`${id}Vpc`))
79
- .addConstruct(Fargate.build(`${id}Fargate`));
80
- ```
81
-
82
- 2. In the same CDK Application but different stack
83
-
84
- When a VPC is created in the same application, but you want to use separate stacks, you can directly reference the vpc resource itself. This is easily
85
- retrieved from an awsStack using `awsStack.getNetwork()`.
86
-
87
- ```typescript
88
- const vpcStack = new AwsStack(`${id}Network`).addNetwork(
89
- FjallVpc.build(`${id}Vpc`)
90
- );
91
-
92
- const newStack = new AwsStack(`${id}Compute`, { dependencies: [vpcStack] })
93
- .addNetwork(vpcStack.getNetwork())
94
- .addConstruct(Fargate.build(`${id}Fargate`));
95
- ```
96
-
97
- 3. Different CDK Applications
98
-
99
- If your VPC was created in a completely separate CDK Stack it can be imported using it's `id` and `stackName`. However this method
100
- requires you explicitly configure your `AwsStack` with an `account` and `region.
101
-
102
- ```typescript
103
- const env = {
104
- region: "us-east-1",
105
- account: "123456789012"
106
- };
107
-
108
- const vpcStack = new AwsStack(`${id}Network`, { ...env }).addNetwork(
109
- FjallVpc.build(`${id}Vpc`)
110
- );
111
-
112
- const newStack = new AwsStack(`${id}Compute`, {
113
- ...env,
114
- dependencies: [vpcStack]
115
- })
116
- .addNetwork(FjallVpc.import(`${id}Vpc`, `${id}Network`))
117
- .addConstruct(Fargate.build(`${id}Fargate`));
118
- ```
119
-
120
- ## Publishing package to npm
121
-
122
- Log into your NPM account locally (make sure you have 2fa setup before trying this)
123
-
124
- ```
125
- npm login
126
- > Username:
127
- > Password
128
- > Email
129
- > 2Fa
130
- ```
131
-
132
- Update the version in ./package.json, build the package and then run publish command
133
-
134
- ```
135
- npm run build
136
- npm publish --access restricted
137
- ```
76
+ Proprietary — see [LICENSE](./LICENSE).
package/dist/lib/app.d.ts CHANGED
@@ -311,7 +311,7 @@ export declare class App extends CdkApp {
311
311
  addDevSubstrate(props: IDevSubstrateProps): DevSubstrate;
312
312
  /**
313
313
  * Instantiate the self-hosted Buildkite agent fleet on the default compute
314
- * stack (design `aiDocs/designs/2026-07-18-buildkite-selfhosted-agents.md`).
314
+ * stack (design: the 2026-07-18 Buildkite self-hosted agents design).
315
315
  *
316
316
  * Same placement contract as `addDevSubstrate` above: deploy-core selects
317
317
  * stacks by the fixed six-category enum, so scoping under
@@ -4,7 +4,7 @@ import { type DefaultPermissionSetName } from "@fjall/generator";
4
4
  * construct. The discriminated union on `source` mirrors AWS ground truth:
5
5
  * the identity source of an Identity Center instance is neither readable nor
6
6
  * settable via any supported API, so the mode is user-declared and
7
- * authoritative. Design: aiDocs/designs/2026-07-04-org-user-management-design.md
7
+ * authoritative. Design: the 2026-07-04 organisation user-management design.
8
8
  *
9
9
  * The source vocabulary is canonical in @fjall/generator
10
10
  * (organisationSchemas.ts) — re-exported here so existing consumers keep
@@ -5,7 +5,7 @@ import { stripAndCamelCase } from "../../utils/stripAndCamelCase.js";
5
5
  * construct. The discriminated union on `source` mirrors AWS ground truth:
6
6
  * the identity source of an Identity Center instance is neither readable nor
7
7
  * settable via any supported API, so the mode is user-declared and
8
- * authoritative. Design: aiDocs/designs/2026-07-04-org-user-management-design.md
8
+ * authoritative. Design: the 2026-07-04 organisation user-management design.
9
9
  *
10
10
  * The source vocabulary is canonical in @fjall/generator
11
11
  * (organisationSchemas.ts) — re-exported here so existing consumers keep
@@ -140,8 +140,7 @@ function buildFoundationGuardrails(allowedRegions) {
140
140
  // assume-root sessions) are deliberately NOT carved out — recovery on
141
141
  // this tier is a break-glass SCP detach, not a standing carve-out. Do
142
142
  // not add them without revisiting the decision:
143
- // aiDocs/troubleshooting/centralised-root-access-break-glass-runbook.md
144
- // § Scenario 3.
143
+ // the centralised root-access break-glass runbook, § Scenario 3.
145
144
  NotAction: [
146
145
  "s3:GetBucketPolicy",
147
146
  "s3:PutBucketPolicy",
@@ -18117,3 +18117,129 @@ exports.handler = async (event) => {
18117
18117
  Data: { CaCertSha256: caCertSha256 }
18118
18118
  };
18119
18119
  };
18120
+ /*! Bundled license information:
18121
+
18122
+ reflect-metadata/Reflect.js:
18123
+ (*! *****************************************************************************
18124
+ Copyright (C) Microsoft. All rights reserved.
18125
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
18126
+ this file except in compliance with the License. You may obtain a copy of the
18127
+ License at http://www.apache.org/licenses/LICENSE-2.0
18128
+
18129
+ THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18130
+ KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
18131
+ WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
18132
+ MERCHANTABLITY OR NON-INFRINGEMENT.
18133
+
18134
+ See the Apache Version 2.0 License for specific language governing permissions
18135
+ and limitations under the License.
18136
+ ***************************************************************************** *)
18137
+
18138
+ pvtsutils/build/index.js:
18139
+ (*!
18140
+ * MIT License
18141
+ *
18142
+ * Copyright (c) 2017-2024 Peculiar Ventures, LLC
18143
+ *
18144
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
18145
+ * of this software and associated documentation files (the "Software"), to deal
18146
+ * in the Software without restriction, including without limitation the rights
18147
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18148
+ * copies of the Software, and to permit persons to whom the Software is
18149
+ * furnished to do so, subject to the following conditions:
18150
+ *
18151
+ * The above copyright notice and this permission notice shall be included in all
18152
+ * copies or substantial portions of the Software.
18153
+ *
18154
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18155
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18156
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18157
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18158
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18159
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18160
+ * SOFTWARE.
18161
+ *
18162
+ *)
18163
+
18164
+ pvutils/build/utils.js:
18165
+ (*!
18166
+ Copyright (c) Peculiar Ventures, LLC
18167
+ *)
18168
+
18169
+ asn1js/build/index.js:
18170
+ (*!
18171
+ * Copyright (c) 2014, GMO GlobalSign
18172
+ * Copyright (c) 2015-2022, Peculiar Ventures
18173
+ * All rights reserved.
18174
+ *
18175
+ * Author 2014-2019, Yury Strozhevsky
18176
+ *
18177
+ * Redistribution and use in source and binary forms, with or without modification,
18178
+ * are permitted provided that the following conditions are met:
18179
+ *
18180
+ * * Redistributions of source code must retain the above copyright notice, this
18181
+ * list of conditions and the following disclaimer.
18182
+ *
18183
+ * * Redistributions in binary form must reproduce the above copyright notice, this
18184
+ * list of conditions and the following disclaimer in the documentation and/or
18185
+ * other materials provided with the distribution.
18186
+ *
18187
+ * * Neither the name of the copyright holder nor the names of its
18188
+ * contributors may be used to endorse or promote products derived from
18189
+ * this software without specific prior written permission.
18190
+ *
18191
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18192
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18193
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18194
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18195
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18196
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18197
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
18198
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18199
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
18200
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18201
+ *
18202
+ *)
18203
+
18204
+ tslib/tslib.es6.js:
18205
+ (*! *****************************************************************************
18206
+ Copyright (c) Microsoft Corporation.
18207
+
18208
+ Permission to use, copy, modify, and/or distribute this software for any
18209
+ purpose with or without fee is hereby granted.
18210
+
18211
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
18212
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18213
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
18214
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
18215
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
18216
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
18217
+ PERFORMANCE OF THIS SOFTWARE.
18218
+ ***************************************************************************** *)
18219
+
18220
+ @peculiar/x509/build/x509.cjs.js:
18221
+ (*!
18222
+ * MIT License
18223
+ *
18224
+ * Copyright (c) Peculiar Ventures. All rights reserved.
18225
+ *
18226
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
18227
+ * of this software and associated documentation files (the "Software"), to deal
18228
+ * in the Software without restriction, including without limitation the rights
18229
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18230
+ * copies of the Software, and to permit persons to whom the Software is
18231
+ * furnished to do so, subject to the following conditions:
18232
+ *
18233
+ * The above copyright notice and this permission notice shall be included in all
18234
+ * copies or substantial portions of the Software.
18235
+ *
18236
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18237
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18238
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18239
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18240
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18241
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18242
+ * SOFTWARE.
18243
+ *
18244
+ *)
18245
+ */
@@ -14,7 +14,7 @@ export type BuildkiteConstructProps = BuildkitePropsInput & {
14
14
  * Self-hosted Buildkite agent fleet on the pinned Elastic CI Stack AMIs —
15
15
  * scale-to-zero ASG + buildkite-agent-scaler, no secret ever transiting
16
16
  * synth, allowlist-only instance IAM. Design:
17
- * `aiDocs/designs/2026-07-18-buildkite-selfhosted-agents.md`.
17
+ * the 2026-07-18 Buildkite self-hosted agents design.
18
18
  *
19
19
  * A Construct, not a Stack: instantiate via `App.addBuildkite(props)`, which
20
20
  * scopes it under the default compute stack so deploy-core's fixed
@@ -21,7 +21,7 @@ import { buildBuildkiteUserData } from "./userData.js";
21
21
  * Self-hosted Buildkite agent fleet on the pinned Elastic CI Stack AMIs —
22
22
  * scale-to-zero ASG + buildkite-agent-scaler, no secret ever transiting
23
23
  * synth, allowlist-only instance IAM. Design:
24
- * `aiDocs/designs/2026-07-18-buildkite-selfhosted-agents.md`.
24
+ * the 2026-07-18 Buildkite self-hosted agents design.
25
25
  *
26
26
  * A Construct, not a Stack: instantiate via `App.addBuildkite(props)`, which
27
27
  * scopes it under the default compute stack so deploy-core's fixed
@@ -5,8 +5,8 @@ import type { BuildkitePropsInput } from "./schema.js";
5
5
  /**
6
6
  * Thunk returned by `BuildkiteFactory.build` — materialised only by
7
7
  * `App.addBuildkite`, which owns stack placement (the fleet has exactly one
8
- * legal home, `${stackPrefix}Compute`; design
9
- * `aiDocs/designs/2026-07-18-fjall-add-buildkite.md` § D2).
8
+ * legal home, `${stackPrefix}Compute`; design:
9
+ * the 2026-07-18 `fjall add buildkite` design, § D2).
10
10
  */
11
11
  export type BuildkiteFactoryFn = (app: App, scope: Construct) => Buildkite;
12
12
  /**
@@ -4,7 +4,7 @@
4
4
  * release. AMI ids, the elastic-stack version, the scaler version and the
5
5
  * secrets-plugin floor MUST only change together, regenerated from the
6
6
  * upstream template for the new version (runbook:
7
- * `aiDocs/runbooks/buildkite-stack-bump-runbook.md`).
7
+ * the Buildkite stack-bump runbook).
8
8
  *
9
9
  * AMI ids come from the `Mappings.AWSRegion2AMI` block of
10
10
  * `https://s3.amazonaws.com/buildkite-aws-stack/<version>/aws-stack.yml` and
@@ -18,7 +18,7 @@
18
18
  * floats the AMI underneath a pinned stack version, needs lookup credentials
19
19
  * at synth time (unavailable in worker synth), and makes synth
20
20
  * non-deterministic. Design:
21
- * `aiDocs/designs/2026-07-18-buildkite-selfhosted-agents.md` § D2.
21
+ * the 2026-07-18 Buildkite self-hosted agents design, § D2.
22
22
  */
23
23
  export declare const BUILDKITE_AMI_OWNER_ACCOUNT_ID = "172840064832";
24
24
  export declare const BUILDKITE_CPU_ARCHITECTURES: readonly ["arm64", "amd64"];
@@ -4,7 +4,7 @@
4
4
  * release. AMI ids, the elastic-stack version, the scaler version and the
5
5
  * secrets-plugin floor MUST only change together, regenerated from the
6
6
  * upstream template for the new version (runbook:
7
- * `aiDocs/runbooks/buildkite-stack-bump-runbook.md`).
7
+ * the Buildkite stack-bump runbook).
8
8
  *
9
9
  * AMI ids come from the `Mappings.AWSRegion2AMI` block of
10
10
  * `https://s3.amazonaws.com/buildkite-aws-stack/<version>/aws-stack.yml` and
@@ -18,7 +18,7 @@
18
18
  * floats the AMI underneath a pinned stack version, needs lookup credentials
19
19
  * at synth time (unavailable in worker synth), and makes synth
20
20
  * non-deterministic. Design:
21
- * `aiDocs/designs/2026-07-18-buildkite-selfhosted-agents.md` § D2.
21
+ * the 2026-07-18 Buildkite self-hosted agents design, § D2.
22
22
  */
23
23
  export const BUILDKITE_AMI_OWNER_ACCOUNT_ID = "172840064832";
24
24
  export const BUILDKITE_CPU_ARCHITECTURES = ["arm64", "amd64"];
@@ -2,7 +2,7 @@
2
2
  * Buildkite props schema — re-export barrel. The canonical declaration lives
3
3
  * in `@fjall/generator` (`src/schemas/buildkiteSchemas.ts`) so construct
4
4
  * validation, the codemod fragment, and the LLM JSON schema all consume one
5
- * source (design `aiDocs/designs/2026-07-18-fjall-add-buildkite.md` § D4).
5
+ * source (design: the 2026-07-18 `fjall add buildkite` design, § D4).
6
6
  * Do NOT redeclare here — the cross-package reference-identity test pins it.
7
7
  */
8
8
  export { BuildkitePropsObjectSchema, BuildkitePropsSchema, validateBuildkiteProps, type BuildkiteProps, type BuildkitePropsInput, type BuildkitePropsObject } from "@fjall/generator";
@@ -2,7 +2,7 @@
2
2
  * Buildkite props schema — re-export barrel. The canonical declaration lives
3
3
  * in `@fjall/generator` (`src/schemas/buildkiteSchemas.ts`) so construct
4
4
  * validation, the codemod fragment, and the LLM JSON schema all consume one
5
- * source (design `aiDocs/designs/2026-07-18-fjall-add-buildkite.md` § D4).
5
+ * source (design: the 2026-07-18 `fjall add buildkite` design, § D4).
6
6
  * Do NOT redeclare here — the cross-package reference-identity test pins it.
7
7
  */
8
8
  export { BuildkitePropsObjectSchema, BuildkitePropsSchema, validateBuildkiteProps } from "@fjall/generator";
@@ -29,7 +29,7 @@ export interface BuildkiteUserDataContext {
29
29
  * vendored template in both directions: a key we emit that upstream does not
30
30
  * pass is silently ignored; a key upstream passes that we omit is the
31
31
  * boot-loop. Bumping the pins regenerates the fixture
32
- * (runbook: `aiDocs/runbooks/buildkite-stack-bump-runbook.md`).
32
+ * (runbook: the Buildkite stack-bump runbook).
33
33
  */
34
34
  export declare const BUILDKITE_MOUNT_PART_ENV_KEYS: readonly ["BUILDKITE_ENABLE_INSTANCE_STORAGE", "BUILDKITE_MOUNT_TMPFS_AT_TMP"];
35
35
  export declare const BUILDKITE_DOCKER_PART_ENV_KEYS: readonly ["DOCKER_USERNS_REMAP", "DOCKER_EXPERIMENTAL", "DOCKER_PRUNE_UNTIL", "ENABLE_PRE_EXIT_DISK_CLEANUP", "DOCKER_BUILDER_PRUNE_ENABLED", "DOCKER_NETWORKING_PROTOCOL", "DOCKER_IPV4_ADDRESS_POOL_1", "DOCKER_IPV4_ADDRESS_POOL_2", "DOCKER_IPV6_ADDRESS_POOL", "DOCKER_FIXED_CIDR_V4", "DOCKER_FIXED_CIDR_V6", "BUILDKITE_ENABLE_INSTANCE_STORAGE"];
@@ -10,7 +10,7 @@ import { BUILDKITE_STACK_PINS } from "./pins.js";
10
10
  * vendored template in both directions: a key we emit that upstream does not
11
11
  * pass is silently ignored; a key upstream passes that we omit is the
12
12
  * boot-loop. Bumping the pins regenerates the fixture
13
- * (runbook: `aiDocs/runbooks/buildkite-stack-bump-runbook.md`).
13
+ * (runbook: the Buildkite stack-bump runbook).
14
14
  */
15
15
  export const BUILDKITE_MOUNT_PART_ENV_KEYS = [
16
16
  "BUILDKITE_ENABLE_INSTANCE_STORAGE",
@@ -2,7 +2,7 @@
2
2
  * Self-hosted Buildkite agent fleet — barrel for the `buildkite/` modules.
3
3
  * The pre-2026-07 `Buildkite extends Stack` implementation is replaced by a
4
4
  * Construct instantiated via `App.addBuildkite()`; design:
5
- * `aiDocs/designs/2026-07-18-buildkite-selfhosted-agents.md`.
5
+ * the 2026-07-18 Buildkite self-hosted agents design.
6
6
  */
7
7
  export { AGENT_TOKEN_SECRET_NAME, BUILDKITE_SECRETS_CLUSTER, Buildkite, FJALL_API_KEY_SECRET_NAME, FJALL_ENV_HOOK_OBJECT_KEY, buildAgentSecretsEnvHookScript, type AgentSecretsEnvHookOptions, type BuildkiteConstructProps } from "./buildkite/buildkite.js";
8
8
  export { BUILDKITE_AMI_OWNER_ACCOUNT_ID, BUILDKITE_CPU_ARCHITECTURES, BUILDKITE_STACK_PINS, resolvePinnedAmiId, resolveScalerSarApplicationArn, type BuildkiteCpuArchitecture } from "./buildkite/pins.js";
@@ -2,7 +2,7 @@
2
2
  * Self-hosted Buildkite agent fleet — barrel for the `buildkite/` modules.
3
3
  * The pre-2026-07 `Buildkite extends Stack` implementation is replaced by a
4
4
  * Construct instantiated via `App.addBuildkite()`; design:
5
- * `aiDocs/designs/2026-07-18-buildkite-selfhosted-agents.md`.
5
+ * the 2026-07-18 Buildkite self-hosted agents design.
6
6
  */
7
7
  export { AGENT_TOKEN_SECRET_NAME, BUILDKITE_SECRETS_CLUSTER, Buildkite, FJALL_API_KEY_SECRET_NAME, FJALL_ENV_HOOK_OBJECT_KEY, buildAgentSecretsEnvHookScript } from "./buildkite/buildkite.js";
8
8
  export { BUILDKITE_AMI_OWNER_ACCOUNT_ID, BUILDKITE_CPU_ARCHITECTURES, BUILDKITE_STACK_PINS, resolvePinnedAmiId, resolveScalerSarApplicationArn } from "./buildkite/pins.js";
@@ -381,7 +381,10 @@ export class ClickHouseDatabase extends Construct {
381
381
  const coldTierBucket = coldTierEnabled
382
382
  ? (props.coldTierBucket ??
383
383
  new S3Bucket(this, "ClickHouseColdTierBucket", {
384
- versioned: false
384
+ // Tiered table parts, re-tiered from hot storage — versioning would
385
+ // only bill for churn; the exemption stamp tells posture so.
386
+ versioned: false,
387
+ versioningExemption: "cold-tier"
385
388
  }))
386
389
  : undefined;
387
390
  this.#backupBucket = backupBucket;
@@ -17,7 +17,7 @@ export interface ClickHouseSelfSignedTls {
17
17
  * supplied the construct surfaces it as a CFN env-var token so consumers
18
18
  * can wire it into containers for rotation-triggers-task-replacement
19
19
  * parity with self-signed mode. Omit it and rotation requires manual task
20
- * restart (documented in `aiDocs/patterns/clickhouse-tls-pattern.md § "Imported mode"`).
20
+ * restart (documented in the ClickHouse TLS pattern, § "Imported mode").
21
21
  */
22
22
  export interface ClickHouseImportedTls {
23
23
  readonly mode: "imported";
@@ -182,8 +182,8 @@ export interface EcsContainerConfig {
182
182
  * per service. Suitable for high-replica services where the init-container
183
183
  * tax dominates rollout time.
184
184
  *
185
- * @see aiDocs/decisions/2026-04-29-ecs-init-container-over-runtask.md
186
- * @see aiDocs/plans/2026-04-29-ecs-factory-hardening.md § 4.3.4 — threshold
185
+ * @see the 2026-04-29 decision: ECS init container over RunTask
186
+ * @see the 2026-04-29 ECS factory-hardening plan, § 4.3.4 — threshold
187
187
  * guidance for choosing between modes.
188
188
  * @see https://aws.amazon.com/blogs/containers/announcing-amazon-ecs-deployment-lifecycle-hooks/
189
189
  */
@@ -223,7 +223,7 @@ export type EcsMigrationsMode = "init-container" | "lifecycle-hook" | "post-depl
223
223
  * mode: "lifecycle-hook"
224
224
  * }
225
225
  *
226
- * @see aiDocs/decisions/2026-04-29-ecs-init-container-over-runtask.md
226
+ * @see the 2026-04-29 decision: ECS init container over RunTask
227
227
  */
228
228
  /**
229
229
  * Discriminated on `mode`. The init-container variant keeps its narrow surface
@@ -237,8 +237,8 @@ export type EcsMigrationsMode = "init-container" | "lifecycle-hook" | "post-depl
237
237
  * lifecycle-hook-only field — is a typecheck error. This protects against
238
238
  * the Pitfall-5 trap (silent field drift across union variants).
239
239
  *
240
- * @see aiDocs/designs/2026-05-12-migration-runner-abstraction-choice.md
241
- * @see .claude/rules/typescript-standards.md § "Pitfall 5"
240
+ * @see the 2026-05-12 migration-runner abstraction-choice design
241
+ * @see the TypeScript standards, Zod Pitfall 5 (three-way option drift)
242
242
  */
243
243
  export type EcsMigrationsConfig = EcsInitContainerMigrationsConfig | EcsLifecycleHookMigrationsConfig | EcsPostDeployMigrationsConfig;
244
244
  /**
@@ -217,8 +217,10 @@ export class Payload extends Construct {
217
217
  createAssetsBucket() {
218
218
  const assetsConfig = this.props.storage?.assets ?? {};
219
219
  const assetsProps = {
220
- // Build output, pruned on every deploy — versioning would only bill for churn.
220
+ // Build output, pruned on every deploy — versioning would only bill for
221
+ // churn; the exemption stamp tells posture the omission is by design.
221
222
  versioned: assetsConfig.versioned ?? false,
223
+ versioningExemption: "build-output",
222
224
  deployment: {
223
225
  source: `${PAYLOAD_DEFAULTS.SOURCE}/${PAYLOAD_DEFAULTS.OPENNEXT.ASSETS}`,
224
226
  prune: true,
@@ -233,8 +235,10 @@ export class Payload extends Construct {
233
235
  createCacheBucket() {
234
236
  const cacheConfig = this.props.storage?.cache ?? {};
235
237
  const cacheProps = {
236
- // ISR cache, regenerated at runtime — versioning would only bill for churn.
238
+ // ISR cache, regenerated at runtime — versioning would only bill for
239
+ // churn; the exemption stamp tells posture the omission is by design.
237
240
  versioned: cacheConfig.versioned ?? false,
241
+ versioningExemption: "isr-cache",
238
242
  deployment: {
239
243
  source: `${PAYLOAD_DEFAULTS.SOURCE}/${PAYLOAD_DEFAULTS.OPENNEXT.CACHE}`,
240
244
  prune: false // ISR adds files at runtime
@@ -2,6 +2,7 @@ import { Construct } from "constructs";
2
2
  import { type EventType, type IBucketNotificationDestination, type NotificationKeyFilter } from "aws-cdk-lib/aws-s3";
3
3
  import { type IDistribution } from "aws-cdk-lib/aws-cloudfront";
4
4
  import { type IGrantable, type Grant } from "aws-cdk-lib/aws-iam";
5
+ import { type S3VersioningExemption } from "@fjall/util/aws";
5
6
  import type App from "../../app.js";
6
7
  import { BucketDeployment, S3Bucket, type ResourcePolicyStatement, type WebsiteHostingConfig } from "../../resources/aws/storage/index.js";
7
8
  import { type BackupTier } from "../../utils/backupTierMapping.js";
@@ -39,6 +40,13 @@ export interface S3Props {
39
40
  * `resilient`/`enterprise`, off otherwise. An explicit value always wins.
40
41
  */
41
42
  readonly versioned?: boolean;
43
+ /**
44
+ * Why this bucket runs unversioned by design (`build-output`, `isr-cache`,
45
+ * `cold-tier`) — see `S3BucketProps.versioningExemption`. Stamped as the
46
+ * `fjall:s3:versioning-exempt` tag when versioning resolves off; a bucket
47
+ * that versions after all is not stamped.
48
+ */
49
+ readonly versioningExemption?: S3VersioningExemption;
42
50
  readonly encryption?: "AES256" | "KMS";
43
51
  readonly kmsKeyArn?: string;
44
52
  /**
@@ -78,6 +78,7 @@ export class Storage extends Construct {
78
78
  aliasTargetName: props.bucketName ?? id,
79
79
  appName: props.appName,
80
80
  versioned: props.versioned,
81
+ versioningExemption: props.versioningExemption,
81
82
  encryption: toBucketEncryption(props.encryption),
82
83
  encryptionKey,
83
84
  ...(props.bucketKeyEnabled !== undefined && {
@@ -40,7 +40,7 @@ export interface SecurityHeadersPolicyProps {
40
40
  * Wrapped on the description + SOC2-defaults trigger (NOT taggability — the
41
41
  * resource is not taggable): it owns Fjall's uniform security-header defaults
42
42
  * so every consumer inherits the same posture in one edit. Per
43
- * `.claude/rules/generator-standards.md § Wrapper Routing Discipline`,
43
+ * the Wrapper Routing Discipline rule (generator standards),
44
44
  * `lib/{config,patterns}/` instantiate this class, never the raw L2.
45
45
  *
46
46
  * Defaults (all `override:true`): HSTS 730d+includeSubdomains+preload,
@@ -18,7 +18,7 @@ const DEFAULT_COMMENT = "Fjall security headers policy";
18
18
  * Wrapped on the description + SOC2-defaults trigger (NOT taggability — the
19
19
  * resource is not taggable): it owns Fjall's uniform security-header defaults
20
20
  * so every consumer inherits the same posture in one edit. Per
21
- * `.claude/rules/generator-standards.md § Wrapper Routing Discipline`,
21
+ * the Wrapper Routing Discipline rule (generator standards),
22
22
  * `lib/{config,patterns}/` instantiate this class, never the raw L2.
23
23
  *
24
24
  * Defaults (all `override:true`): HSTS 730d+includeSubdomains+preload,
@@ -27,7 +27,7 @@ export type Ec2InstancePersistentDataVolumeConfig = Omit<PersistentDataVolumePro
27
27
  * `AutoScalingScheduledAction.IgnoreUnmodifiedGroupSizeProperties`
28
28
  * regardless. For callers owning rollout externally.
29
29
  *
30
- * See `aiDocs/troubleshooting/clickhouse-rolling-update-window.md` for the
30
+ * See the ClickHouse rolling-update-window troubleshooting note for the
31
31
  * ClickHouse-specific downtime expectations.
32
32
  */
33
33
  export type Ec2InstanceUpdatePolicyConfig = {
@@ -127,7 +127,7 @@ export interface Ec2InstanceProps extends StackProps {
127
127
  * ASG `UpdatePolicy` resolution. Absent → `UpdatePolicy.instanceRefresh`
128
128
  * (0/100 with `persistentDataVolume`, 100/200 otherwise). See
129
129
  * `Ec2InstanceUpdatePolicyConfig` for the variant menu and
130
- * `aiDocs/troubleshooting/clickhouse-rolling-update-window.md` for the
130
+ * the ClickHouse rolling-update-window troubleshooting note for the
131
131
  * downtime-window runbook.
132
132
  */
133
133
  updatePolicy?: Ec2InstanceUpdatePolicyConfig;
@@ -17,7 +17,7 @@ import { PersistentDataVolume } from "./persistentDataVolume.js";
17
17
  * `encrypted: true` enforces EBS encryption at the wrapper layer rather than
18
18
  * relying on the AWS account-level "encryption by default" setting — the
19
19
  * propagation contract documented in
20
- * `.claude/rules/generator-standards.md § "Wrapper Routing Discipline"`.
20
+ * the Wrapper Routing Discipline rule (generator standards).
21
21
  */
22
22
  const DEFAULT_ROOT_DEVICE_NAME = "/dev/xvda";
23
23
  const DEFAULT_ROOT_VOLUME_SIZE_GIB = 30;
@@ -155,7 +155,7 @@ export declare const CLICKHOUSE_NATIVE_PORT = 9000;
155
155
  export declare const CLICKHOUSE_PROMETHEUS_PORT = 9363;
156
156
  /** TLS-mode ClickHouse ports.
157
157
  * HTTPS replaces 8123; secure native protocol replaces 9000.
158
- * See aiDocs/patterns/clickhouse-tls-pattern.md § "The contract". */
158
+ * See the ClickHouse TLS pattern, § "The contract". */
159
159
  export declare const CLICKHOUSE_HTTPS_PORT = 8443;
160
160
  export declare const CLICKHOUSE_TCP_SECURE_PORT = 9440;
161
161
  /** Mount path inside the ClickHouse container for the materialised TLS cert
@@ -188,8 +188,8 @@ export declare function clickHouseUserSecretName(userName: string): string;
188
188
  * Canonical source is `@fjall/util/migration § userPasswordEnvName` — re-exported
189
189
  * here so the construct-side import chain stays unchanged while the runner
190
190
  * (`webapp/scripts/migration-runner.mjs`) and any future consumer share a single
191
- * declaration. Coupled values per `.claude/rules/code-quality.md § "Coupled values:
192
- * shared source at 2 occurrences"`. */
191
+ * declaration. Coupled values (the shared-source-at-two-occurrences
192
+ * rule). */
193
193
  export { userPasswordEnvName } from "@fjall/util/migration";
194
194
  /** Env var name carrying the SHA-256 of a user's plaintext password.
195
195
  * The container entrypoint wrapper derives this name from the
@@ -305,8 +305,8 @@ export declare const BACKUP_RETENTION_DAYS = 14;
305
305
  * wrote can be read back. Dropped on the way in and on the way out; never
306
306
  * queried by the application. Canonical source is `@fjall/util/migration`
307
307
  * because `@fjall/clickhouse` grants `fjall_maintenance` DROP on exactly
308
- * this database — coupled values per `.claude/rules/code-quality.md §
309
- * "Coupled values: shared source at 2 occurrences"`. */
308
+ * this database — coupled values (the shared-source-at-two-occurrences
309
+ * rule). */
310
310
  export { CLICKHOUSE_BACKUP_SCRATCH_DATABASE } from "@fjall/util/migration";
311
311
  /** The two scheduled maintenance jobs that authenticate as
312
312
  * `fjall_maintenance`. Drives the per-job log-group → metric-filter wiring
@@ -175,7 +175,7 @@ export const CLICKHOUSE_NATIVE_PORT = 9000;
175
175
  export const CLICKHOUSE_PROMETHEUS_PORT = 9363;
176
176
  /** TLS-mode ClickHouse ports.
177
177
  * HTTPS replaces 8123; secure native protocol replaces 9000.
178
- * See aiDocs/patterns/clickhouse-tls-pattern.md § "The contract". */
178
+ * See the ClickHouse TLS pattern, § "The contract". */
179
179
  export const CLICKHOUSE_HTTPS_PORT = 8443;
180
180
  export const CLICKHOUSE_TCP_SECURE_PORT = 9440;
181
181
  /** Mount path inside the ClickHouse container for the materialised TLS cert
@@ -210,8 +210,8 @@ export function clickHouseUserSecretName(userName) {
210
210
  * Canonical source is `@fjall/util/migration § userPasswordEnvName` — re-exported
211
211
  * here so the construct-side import chain stays unchanged while the runner
212
212
  * (`webapp/scripts/migration-runner.mjs`) and any future consumer share a single
213
- * declaration. Coupled values per `.claude/rules/code-quality.md § "Coupled values:
214
- * shared source at 2 occurrences"`. */
213
+ * declaration. Coupled values (the shared-source-at-two-occurrences
214
+ * rule). */
215
215
  export { userPasswordEnvName } from "@fjall/util/migration";
216
216
  /** Env var name carrying the SHA-256 of a user's plaintext password.
217
217
  * The container entrypoint wrapper derives this name from the
@@ -347,8 +347,8 @@ export const BACKUP_RETENTION_DAYS = 14;
347
347
  * wrote can be read back. Dropped on the way in and on the way out; never
348
348
  * queried by the application. Canonical source is `@fjall/util/migration`
349
349
  * because `@fjall/clickhouse` grants `fjall_maintenance` DROP on exactly
350
- * this database — coupled values per `.claude/rules/code-quality.md §
351
- * "Coupled values: shared source at 2 occurrences"`. */
350
+ * this database — coupled values (the shared-source-at-two-occurrences
351
+ * rule). */
352
352
  export { CLICKHOUSE_BACKUP_SCRATCH_DATABASE } from "@fjall/util/migration";
353
353
  /** The two scheduled maintenance jobs that authenticate as
354
354
  * `fjall_maintenance`. Drives the per-job log-group → metric-filter wiring
@@ -8,7 +8,7 @@ export interface IdentityStoreUserProviderProps {
8
8
  * Shared Provider-framework backend for Custom::FjallIdentityStoreUser —
9
9
  * one handler + provider pair serves every declared user in the stack. A
10
10
  * plain AwsCustomResource cannot express the create-or-adopt branching the
11
- * handler implements (aiDocs/designs/2026-07-04-org-user-management-design.md § 2).
11
+ * handler implements (the 2026-07-04 organisation user-management design, § 2).
12
12
  */
13
13
  export declare class IdentityStoreUserProvider extends Construct {
14
14
  readonly serviceToken: string;
@@ -23,7 +23,7 @@ export function identityStoreUserArnPattern(partition) {
23
23
  * Shared Provider-framework backend for Custom::FjallIdentityStoreUser —
24
24
  * one handler + provider pair serves every declared user in the stack. A
25
25
  * plain AwsCustomResource cannot express the create-or-adopt branching the
26
- * handler implements (aiDocs/designs/2026-07-04-org-user-management-design.md § 2).
26
+ * handler implements (the 2026-07-04 organisation user-management design, § 2).
27
27
  */
28
28
  export class IdentityStoreUserProvider extends Construct {
29
29
  serviceToken;
@@ -5,9 +5,8 @@ import { type Construct } from "constructs";
5
5
  *
6
6
  * Applies one default: an explicit, stack-shared log group for the deployment
7
7
  * handler lambda, so it is CloudFormation-managed and tagged rather than
8
- * service-auto-created. Per `.claude/rules/generator-standards.md § Wrapper
9
- * Routing Discipline` and
10
- * `patterns/infrastructure-wrapper-routing-pattern.md § A3`, `lib/{config,
8
+ * service-auto-created. Per the Wrapper Routing Discipline rule (generator
9
+ * standards) and the infrastructure wrapper-routing pattern (§ A3), `lib/{config,
11
10
  * patterns}/` MUST instantiate this class rather than the raw CDK construct.
12
11
  */
13
12
  export declare class BucketDeployment extends CdkBucketDeployment {
@@ -5,9 +5,8 @@ import { stackSingletonLogGroup } from "../logging/singletonLogGroup.js";
5
5
  *
6
6
  * Applies one default: an explicit, stack-shared log group for the deployment
7
7
  * handler lambda, so it is CloudFormation-managed and tagged rather than
8
- * service-auto-created. Per `.claude/rules/generator-standards.md § Wrapper
9
- * Routing Discipline` and
10
- * `patterns/infrastructure-wrapper-routing-pattern.md § A3`, `lib/{config,
8
+ * service-auto-created. Per the Wrapper Routing Discipline rule (generator
9
+ * standards) and the infrastructure wrapper-routing pattern (§ A3), `lib/{config,
11
10
  * patterns}/` MUST instantiate this class rather than the raw CDK construct.
12
11
  */
13
12
  export class BucketDeployment extends CdkBucketDeployment {
@@ -1,7 +1,8 @@
1
+ import { type S3VersioningExemption } from "@fjall/util/aws";
1
2
  import { Bucket, type BucketProps } from "aws-cdk-lib/aws-s3";
2
3
  import { type Construct } from "constructs";
3
4
  import { type BackupTier } from "../../../utils/backupTierMapping.js";
4
- export { SDK_PRE_EMPTY_TAG_KEY } from "@fjall/util/aws";
5
+ export { S3_VERSIONING_EXEMPT_TAG_KEY, SDK_PRE_EMPTY_TAG_KEY } from "@fjall/util/aws";
5
6
  /**
6
7
  * Days a noncurrent object version is retained before lifecycle expiry.
7
8
  * The wrapper pairs this automatically when it enables versioning; constructs
@@ -59,6 +60,17 @@ export interface S3BucketProps extends BucketProps {
59
60
  * direct `new S3Bucket` construction needs to pass it.
60
61
  */
61
62
  appBackupTier?: BackupTier;
63
+ /**
64
+ * Why this bucket runs unversioned by design. Stamped as the
65
+ * `fjall:s3:versioning-exempt` tag only when versioning resolves off — a
66
+ * bucket that versions after all (an explicit `versioned: true`, or a tier
67
+ * that turns it on) has nothing to exempt — so posture lands the
68
+ * `S3_VERSIONING_DISABLED` finding `mitigated` rather than `open` on
69
+ * buckets whose contents are rebuilt, not kept. Constructs pass it for the
70
+ * buckets they own (Payload build output and ISR cache, ClickHouse cold
71
+ * tier); an author may pass it for a disposable bucket of their own.
72
+ */
73
+ versioningExemption?: S3VersioningExemption;
62
74
  publicReadAccess?: boolean;
63
75
  websiteHosting?: WebsiteHostingConfig;
64
76
  /**
@@ -1,4 +1,4 @@
1
- import { SDK_PRE_EMPTY_TAG_KEY } from "@fjall/util/aws";
1
+ import { S3_VERSIONING_EXEMPT_TAG_KEY, SDK_PRE_EMPTY_TAG_KEY } from "@fjall/util/aws";
2
2
  import { Annotations, CfnOutput, Duration, RemovalPolicy, Tags } from "aws-cdk-lib";
3
3
  import { BlockPublicAccess, Bucket, BucketEncryption } from "aws-cdk-lib/aws-s3";
4
4
  import { ArnPrincipal, Effect, PolicyStatement, StarPrincipal } from "aws-cdk-lib/aws-iam";
@@ -7,7 +7,7 @@ import { resolveEffectiveBackupTier, shouldAutoVersion } from "../../../utils/ba
7
7
  import { toPascalCase } from "../../../utils/capitaliseString.js";
8
8
  import { bucketWebsiteEndpointExportName, bucketWebsiteHostedZoneIdExportName } from "@fjall/util";
9
9
  import { envAwareRemovalPolicyDefault, toRemovalPolicy } from "../../../utils/removalPolicy.js";
10
- export { SDK_PRE_EMPTY_TAG_KEY } from "@fjall/util/aws";
10
+ export { S3_VERSIONING_EXEMPT_TAG_KEY, SDK_PRE_EMPTY_TAG_KEY } from "@fjall/util/aws";
11
11
  /**
12
12
  * Days a noncurrent object version is retained before lifecycle expiry.
13
13
  * The wrapper pairs this automatically when it enables versioning; constructs
@@ -26,7 +26,7 @@ export class S3Bucket extends Bucket {
26
26
  /** The tier the bucket runs under: `backupVaultTier`, else `appBackupTier`. */
27
27
  effectiveBackupTier;
28
28
  constructor(scope, id, props = {}) {
29
- const { websiteHosting, backupVaultTier, appBackupTier, resourcePolicyStatements, aliasTargetName, appName, ...cdkProps } = props;
29
+ const { websiteHosting, backupVaultTier, appBackupTier, resourcePolicyStatements, aliasTargetName, appName, versioningExemption, ...cdkProps } = props;
30
30
  const isPublic = props.publicReadAccess === true || websiteHosting !== undefined;
31
31
  const effectiveBackupTier = resolveEffectiveBackupTier(backupVaultTier, appBackupTier);
32
32
  const versioned = props.versioned ?? shouldAutoVersion(effectiveBackupTier);
@@ -112,6 +112,9 @@ export class S3Bucket extends Bucket {
112
112
  if (removalPolicy === RemovalPolicy.DESTROY) {
113
113
  Tags.of(this).add(SDK_PRE_EMPTY_TAG_KEY, "true");
114
114
  }
115
+ if (versioningExemption !== undefined && !versioned) {
116
+ Tags.of(this).add(S3_VERSIONING_EXEMPT_TAG_KEY, versioningExemption);
117
+ }
115
118
  if (websiteHosting) {
116
119
  if (appName === undefined) {
117
120
  // Refusing beats falling back to a bucket-only export name: the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjall/components-infrastructure",
3
- "version": "33.0.0",
3
+ "version": "33.1.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/fjall-tech/fjall.git",
@@ -41,6 +41,7 @@
41
41
  "build:cert-gen-lambda": "node lib/lambda-assets/cert-generator/src/build.mjs",
42
42
  "build": "npm run clean && npm run build:cert-gen-lambda && tsc && cp -r lib/layers dist/lib/layers && mkdir -p dist/lib/lambda-assets/cert-generator/asset && cp lib/lambda-assets/cert-generator/asset/index.js dist/lib/lambda-assets/cert-generator/asset/index.js && cp lib/lambda-assets/cert-generator/asset/package.json dist/lib/lambda-assets/cert-generator/asset/package.json && mkdir -p dist/lib/lambda-assets/identity-store-user/asset && cp lib/lambda-assets/identity-store-user/asset/index.js dist/lib/lambda-assets/identity-store-user/asset/index.js && cp lib/lambda-assets/identity-store-user/asset/package.json dist/lib/lambda-assets/identity-store-user/asset/package.json && mkdir -p dist/lib/lambda-assets/static-site-forms/asset && cp lib/lambda-assets/static-site-forms/asset/index.js dist/lib/lambda-assets/static-site-forms/asset/index.js && cp lib/lambda-assets/static-site-forms/asset/package.json dist/lib/lambda-assets/static-site-forms/asset/package.json && cp lib/resources/aws/compute/lifecycleHookLambda.source.cjs dist/lib/resources/aws/compute/lifecycleHookLambda.source.cjs && cp lib/resources/aws/compute/ec2GracefulTerminationLambda.source.cjs dist/lib/resources/aws/compute/ec2GracefulTerminationLambda.source.cjs && cp lib/resources/aws/compute/persistentDataVolumeLambda.source.cjs dist/lib/resources/aws/compute/persistentDataVolumeLambda.source.cjs && cp lib/patterns/aws/devSubstrate.waker.source.cjs dist/lib/patterns/aws/devSubstrate.waker.source.cjs && node ../../scripts/stamp-build.mjs",
43
43
  "prepack": "node ../../scripts/check-dist-freshness.mjs",
44
+ "prepublishOnly": "node ../../scripts/audit-package-tarball.mjs",
44
45
  "watch": "tsc -w",
45
46
  "watch:only": "tsc -w",
46
47
  "test": "vitest run",
@@ -78,8 +79,8 @@
78
79
  },
79
80
  "dependencies": {
80
81
  "@aws-sdk/client-organizations": "^3.1098.0",
81
- "@fjall/generator": "^33.0.0",
82
- "@fjall/util": "^33.0.0",
82
+ "@fjall/generator": "^33.1.0",
83
+ "@fjall/util": "^33.1.0",
83
84
  "constructs": "^10.7.2",
84
85
  "zod": "^4.4.3"
85
86
  },