@fjall/components-infrastructure 4.3.0 → 5.0.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 (26) hide show
  1. package/dist/lib/config/aws/oidcConnector.d.ts +16 -7
  2. package/dist/lib/config/aws/oidcConnector.js +6 -1
  3. package/dist/lib/patterns/aws/account.d.ts +24 -11
  4. package/dist/lib/patterns/aws/account.js +14 -10
  5. package/dist/lib/patterns/aws/clickhouseDatabase.d.ts +16 -3
  6. package/dist/lib/patterns/aws/clickhouseDatabase.js +23 -2
  7. package/dist/lib/patterns/aws/computeEcsTypes.d.ts +12 -2
  8. package/dist/lib/patterns/aws/database.js +5 -5
  9. package/dist/lib/resources/aws/compute/ecs.js +1 -0
  10. package/dist/lib/resources/aws/compute/ecsConstants.d.ts +14 -0
  11. package/dist/lib/resources/aws/compute/ecsConstants.js +23 -0
  12. package/dist/lib/resources/aws/compute/ecsServiceFactory.d.ts +9 -0
  13. package/dist/lib/resources/aws/compute/ecsServiceFactory.js +71 -1
  14. package/dist/lib/resources/aws/compute/ecsTaskDefinition.js +2 -6
  15. package/dist/lib/resources/aws/compute/ecsValidation.js +9 -2
  16. package/dist/lib/resources/aws/database/clickhouseConstants.d.ts +59 -26
  17. package/dist/lib/resources/aws/database/clickhouseConstants.js +90 -26
  18. package/dist/lib/resources/aws/database/clickhouseSchemas.js +9 -2
  19. package/dist/lib/resources/aws/database/clickhouseUserData.js +87 -11
  20. package/dist/lib/resources/aws/database/rdsAurora.js +1 -1
  21. package/dist/lib/resources/aws/database/rdsInstance.js +1 -1
  22. package/dist/lib/resources/aws/monitoring/clickhouseAlarms.d.ts +9 -5
  23. package/dist/lib/resources/aws/monitoring/clickhouseAlarms.js +21 -12
  24. package/dist/lib/utils/engineCompat.d.ts +35 -13
  25. package/dist/lib/utils/engineCompat.js +90 -23
  26. package/package.json +25 -23
@@ -26,10 +26,21 @@
26
26
  * hand-edit. A same-major-or-newer engine proceeds; an older-major engine
27
27
  * hard-refuses.
28
28
  *
29
- * The optional `maximumEngineMajor` / `minimumAwsCdkCli` bounds are deliberately
30
- * NOT emitted in Phase 1 they are ADR open question Q5 (engine-ahead cap) and
31
- * the Phase-2 FM1 aws-cdk floor graft respectively, both unresolved and
32
- * deferred. This emitter stamps only the two required fields.
29
+ * `minimumAwsCdkCli` (Phase 2, FM1) is the floor for the deploy engine's bundled
30
+ * `aws-cdk` CLI: an engine whose CLI is older than the version these constructs
31
+ * were blessed against cannot reliably read the cloud assembly they synthesised.
32
+ * The aws-cdk CLI and aws-cdk-lib version axes DIVERGED in CDK v2 (CLI ~2.1134.x
33
+ * vs lib ~2.262.x), so this is a distinct check from `minimumEngineVersion`, on a
34
+ * different axis. It is derived from the constructs' OWN
35
+ * `peerDependencies["aws-cdk"]` floor — self-honest, and shipped with the package
36
+ * (unlike the blessed-pin JSON, which is not in `files`) — and conditional-spread
37
+ * so a package whose peer floor cannot be resolved simply omits it (fail-safe: the
38
+ * FM1 check degrades to no-op rather than emitting a garbage floor).
39
+ *
40
+ * The optional `maximumEngineMajor` bound is deliberately NOT emitted — it is ADR
41
+ * open question Q5 (engine-ahead cap), and capping a newer engine would break the
42
+ * normal fjall-upgrade-then-redeploy path. The classifier still honours one if a
43
+ * future assembly stamps it by hand; this emitter never does.
33
44
  *
34
45
  * Fail-safe: if the constructs' own version cannot be resolved (a broken
35
46
  * package layout), `buildEngineCompat` returns undefined and the caller stamps
@@ -43,7 +54,41 @@ import { existsSync, readFileSync } from "fs";
43
54
  import { getErrorMessage, maskSensitiveOutput } from "@fjall/util";
44
55
  import { FjallLogger } from "./validationLogger.js";
45
56
  const PACKAGE_NAME = "@fjall/components-infrastructure";
46
- function resolveConstructsVersion() {
57
+ /**
58
+ * Normalise an npm dependency RANGE to its minimum X.Y.Z floor: strip a leading
59
+ * range operator (`^`, `~`, `>=`, `>`, `=`, `v`) and any prerelease/build
60
+ * metadata, then reconstruct `${major}.${minor}.${patch}` (missing minor/patch
61
+ * default to 0). Returns undefined for anything without a valid integer major —
62
+ * so a non-semver range (a git URL, `*`) yields no floor and the caller omits
63
+ * the field rather than emitting garbage.
64
+ */
65
+ export function rangeFloor(range) {
66
+ if (range === undefined || range.length === 0)
67
+ return undefined;
68
+ const firstToken = range.trim().split(/\s+/)[0] ?? "";
69
+ const core = firstToken.replace(/^[\^~>=v ]+/i, "").split(/[-+]/)[0] ?? "";
70
+ if (core.length === 0)
71
+ return undefined;
72
+ const parts = core.split(".");
73
+ const major = Number(parts[0]);
74
+ const minor = parts.length > 1 ? Number(parts[1]) : 0;
75
+ const patch = parts.length > 2 ? Number(parts[2]) : 0;
76
+ if (!Number.isInteger(major) || major < 0)
77
+ return undefined;
78
+ if (!Number.isInteger(minor) || minor < 0)
79
+ return undefined;
80
+ if (!Number.isInteger(patch) || patch < 0)
81
+ return undefined;
82
+ return `${major}.${minor}.${patch}`;
83
+ }
84
+ /**
85
+ * Resolve the constructs' own package.json (version + aws-cdk peer floor) by the
86
+ * same upward `name`-matching walk `DEPLOY_CORE_VERSION` uses — robust across the
87
+ * source (`lib/utils/`) and compiled (`dist/lib/utils/`) layouts, and skipping any
88
+ * unrelated `package.json` higher up (a consuming app's). Returns undefined only
89
+ * when the walk finds no matching `package.json` (broken layout).
90
+ */
91
+ function resolveConstructsPackageMeta() {
47
92
  try {
48
93
  let dir = dirname(fileURLToPath(import.meta.url));
49
94
  const { root } = parse(dir);
@@ -54,7 +99,13 @@ function resolveConstructsVersion() {
54
99
  if (pkg.name === PACKAGE_NAME &&
55
100
  typeof pkg.version === "string" &&
56
101
  pkg.version.length > 0) {
57
- return pkg.version;
102
+ const awsCdkPeer = pkg.peerDependencies?.["aws-cdk"];
103
+ return {
104
+ version: pkg.version,
105
+ awsCdkCliFloor: typeof awsCdkPeer === "string"
106
+ ? rangeFloor(awsCdkPeer)
107
+ : undefined
108
+ };
58
109
  }
59
110
  }
60
111
  if (dir === root)
@@ -63,28 +114,40 @@ function resolveConstructsVersion() {
63
114
  }
64
115
  }
65
116
  catch (error) {
66
- FjallLogger.warn(`Could not resolve ${PACKAGE_NAME} version for engineCompat: ` +
117
+ FjallLogger.warn(`Could not resolve ${PACKAGE_NAME} metadata for engineCompat: ` +
67
118
  maskSensitiveOutput(getErrorMessage(error)));
68
119
  return undefined;
69
120
  }
70
121
  }
122
+ const CONSTRUCTS_PACKAGE_META = resolveConstructsPackageMeta();
71
123
  /**
72
124
  * The constructs' own package version — the assembly's `synthesisedBy`.
73
125
  * `undefined` only when the package layout is broken enough that the upward
74
126
  * walk finds no matching `package.json`.
75
127
  */
76
- export const CONSTRUCTS_VERSION = resolveConstructsVersion();
128
+ export const CONSTRUCTS_VERSION = CONSTRUCTS_PACKAGE_META?.version;
129
+ /**
130
+ * The minimum `aws-cdk` CLI floor these constructs were blessed against, derived
131
+ * from their own `peerDependencies["aws-cdk"]` — the FM1 `minimumAwsCdkCli` emit
132
+ * value. `undefined` when the peer is absent or non-semver (the field is then
133
+ * omitted from the stamped block).
134
+ */
135
+ export const AWS_CDK_CLI_FLOOR = CONSTRUCTS_PACKAGE_META?.awsCdkCliFloor;
77
136
  /**
78
137
  * Pure core of the emitter: derive the `engineCompat` block from a given
79
- * version string (or undefined). Both the absent/empty guard and the
80
- * `${major}.0.0` non-integer-major derivation live here — the single source of
81
- * the derivation, delegated to by both `MINIMUM_ENGINE_VERSION` and
82
- * `buildEngineCompat` — so the fail-safe and malformed-version paths are
83
- * unit-testable directly, without mocking module-load state. Returns undefined
84
- * when the version is absent, empty, or has no valid integer major (fail-safe:
85
- * the caller stamps no block).
138
+ * version string (or undefined) and an optional aws-cdk CLI floor. Both the
139
+ * absent/empty guard and the `${major}.0.0` non-integer-major derivation live
140
+ * here — the single source of the derivation, delegated to by both
141
+ * `MINIMUM_ENGINE_VERSION` and `buildEngineCompat` — so the fail-safe and
142
+ * malformed-version paths are unit-testable directly, without mocking
143
+ * module-load state. Returns undefined when the version is absent, empty, or has
144
+ * no valid integer major (fail-safe: the caller stamps no block).
145
+ *
146
+ * `awsCdkCliFloor` is conditional-spread: an absent/empty floor omits
147
+ * `minimumAwsCdkCli` entirely (Zod-pitfall-2 safe — never `undefined`), so the
148
+ * FM1 check degrades to no-op rather than shipping a malformed constraint.
86
149
  */
87
- export function buildEngineCompatFrom(version) {
150
+ export function buildEngineCompatFrom(version, awsCdkCliFloor) {
88
151
  if (version === undefined || version.length === 0)
89
152
  return undefined;
90
153
  const major = Number(version.split(".")[0]);
@@ -92,7 +155,9 @@ export function buildEngineCompatFrom(version) {
92
155
  return undefined;
93
156
  return {
94
157
  synthesisedBy: version,
95
- minimumEngineVersion: `${major}.0.0`
158
+ minimumEngineVersion: `${major}.0.0`,
159
+ ...(awsCdkCliFloor !== undefined &&
160
+ awsCdkCliFloor.length > 0 && { minimumAwsCdkCli: awsCdkCliFloor })
96
161
  };
97
162
  }
98
163
  /**
@@ -107,12 +172,14 @@ export const MINIMUM_ENGINE_VERSION = buildEngineCompatFrom(CONSTRUCTS_VERSION)?
107
172
  * when the constructs' own version cannot be resolved (fail-safe: the caller
108
173
  * stamps no block and the deploy degrades to a constraint-free proceed).
109
174
  *
110
- * Phase 1 emits only the two required fields. The verdict classification of the
111
- * emitted floor is proven in `@fjall/deploy-core`'s
112
- * `orchestration/application/__tests__/engineCompat.test.ts` (a `4.0.0` floor
113
- * refuses a 3.x engine, proceeds for 4.x/5.x); this module's tests prove the
114
- * emitted shape matches that floor and reads back through the gate's reader.
175
+ * Emits the two required fields plus `minimumAwsCdkCli` (Phase 2 FM1) whenever the
176
+ * aws-cdk peer floor resolves. The verdict classification of the emitted floors is
177
+ * proven in `@fjall/deploy-core`'s
178
+ * `orchestration/application/__tests__/engineCompat.test.ts` (a `4.0.0` engine
179
+ * floor refuses a 3.x engine; a `minimumAwsCdkCli` floor refuses an older bundled
180
+ * CLI); this module's tests prove the emitted shape matches those floors and reads
181
+ * back through the gate's reader.
115
182
  */
116
183
  export function buildEngineCompat() {
117
- return buildEngineCompatFrom(CONSTRUCTS_VERSION);
184
+ return buildEngineCompatFrom(CONSTRUCTS_VERSION, AWS_CDK_CLI_FLOOR);
118
185
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjall/components-infrastructure",
3
- "version": "4.3.0",
3
+ "version": "5.0.0",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "type": "module",
6
6
  "bin": {
@@ -34,53 +34,55 @@
34
34
  "clean": "rm -rf ./dist",
35
35
  "clean:node": "rm -rf ./node_modules",
36
36
  "build:cert-gen-lambda": "node lib/lambda-assets/cert-generator/src/build.mjs",
37
- "build": "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",
37
+ "build": "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",
38
38
  "prepack": "node ../../scripts/check-dist-freshness.mjs",
39
39
  "watch": "tsc -w",
40
40
  "watch:only": "tsc -w",
41
41
  "test": "vitest run",
42
42
  "test:watch": "vitest",
43
+ "contract:manifest": "FJALL_WRITE_CONTRACT_MANIFEST=1 vitest run lib/__tests__/_contract/contract.test.ts",
43
44
  "cdk": "cdk",
44
45
  "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
45
46
  "typecheck:tests": "tsc --noEmit -p tsconfig.test.json",
46
47
  "check:scripts": "tsc --project tsconfig.scripts.json",
48
+ "deploy-test": "tsx deploy-tests/run.mts",
47
49
  "lint": "eslint lib --no-warn-ignored",
48
50
  "lint:fix": "eslint lib --fix --no-warn-ignored",
49
- "format": "prettier --write \"lib/**/*.{ts,tsx,js,jsx,json}\" \"scripts/**/*.mts\"",
50
- "format:check": "prettier --check \"lib/**/*.{ts,tsx,js,jsx,json}\" \"scripts/**/*.mts\""
51
+ "format": "prettier --write \"lib/**/*.{ts,tsx,js,jsx,json}\" \"scripts/**/*.mts\" \"deploy-tests/**/*.mts\"",
52
+ "format:check": "prettier --check \"lib/**/*.{ts,tsx,js,jsx,json}\" \"scripts/**/*.mts\" \"deploy-tests/**/*.mts\""
51
53
  },
52
54
  "devDependencies": {
53
- "@aws-sdk/client-elastic-load-balancing-v2": "^3.1045.0",
54
- "@aws-sdk/client-iam": "^3.1038.0",
55
- "@aws-sdk/client-identitystore": "^3.1038.0",
56
- "@aws-sdk/client-sesv2": "^3.1087.0",
55
+ "@aws-sdk/client-elastic-load-balancing-v2": "^3.1098.0",
56
+ "@aws-sdk/client-iam": "^3.1098.0",
57
+ "@aws-sdk/client-identitystore": "^3.1098.0",
58
+ "@aws-sdk/client-sesv2": "^3.1098.0",
57
59
  "@peculiar/x509": "2.0.0",
58
- "@types/aws-lambda": "^8.10.161",
59
- "@types/node": "^26.0.0",
60
- "@typescript-eslint/eslint-plugin": "^8.59.1",
61
- "@typescript-eslint/parser": "^8.59.1",
62
- "eslint": "^10.2.1",
63
- "prettier": "^3.8.3",
60
+ "@types/aws-lambda": "^8.10.162",
61
+ "@types/node": "^26.1.2",
62
+ "@typescript-eslint/eslint-plugin": "^8.65.0",
63
+ "@typescript-eslint/parser": "^8.65.0",
64
+ "eslint": "^10.8.0",
65
+ "prettier": "^3.9.6",
64
66
  "reflect-metadata": "^0.2.2",
65
67
  "typescript": "^6.0.3",
66
- "vitest": "^4.1.7"
68
+ "vitest": "^4.1.10"
67
69
  },
68
70
  "dependencies": {
69
- "@aws-sdk/client-organizations": "^3.1038.0",
70
- "@fjall/generator": "^4.3.0",
71
- "@fjall/util": "^4.3.0",
72
- "constructs": "^10.6.0"
71
+ "@aws-sdk/client-organizations": "^3.1098.0",
72
+ "@fjall/generator": "^5.0.0",
73
+ "@fjall/util": "^5.0.0",
74
+ "constructs": "^10.7.2"
73
75
  },
74
76
  "overrides": {
75
77
  "@smithy/core": "2.5.5"
76
78
  },
77
79
  "peerDependencies": {
78
- "aws-cdk": "^2.1128.1",
79
- "aws-cdk-lib": "^2.260.0",
80
- "constructs": "^10.6.0"
80
+ "aws-cdk": "^2.1134.0",
81
+ "aws-cdk-lib": "^2.262.2",
82
+ "constructs": "^10.7.2"
81
83
  },
82
84
  "engines": {
83
85
  "node": ">=18.0.0"
84
86
  },
85
- "gitHead": "8a3ae096f9d15c47dc8c277c9bddfa40e4168c19"
87
+ "gitHead": "78dded6f582368076e8b5f351399219e5a954659"
86
88
  }