@aws/nx-plugin 1.0.0-rc.56 → 1.0.0-rc.58

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 (179) hide show
  1. package/LICENSE-THIRD-PARTY +2917 -1295
  2. package/migrations.json +34 -24
  3. package/package.json +13 -13
  4. package/src/agentcore-gateway/generator.d.ts +16 -1
  5. package/src/agentcore-gateway/generator.js +3 -2
  6. package/src/agentcore-gateway/generator.js.map +1 -1
  7. package/src/agentcore-gateway/schema.json +1 -0
  8. package/src/connection/scaffold-catalog.d.ts +160 -0
  9. package/src/connection/scaffold-catalog.js +207 -0
  10. package/src/connection/scaffold-catalog.js.map +1 -0
  11. package/src/connection/schema-resolver.d.ts +5 -0
  12. package/src/connection/schema-resolver.js +27 -0
  13. package/src/connection/schema-resolver.js.map +1 -0
  14. package/src/infra/app/__snapshots__/generator.spec.ts.snap +7 -7
  15. package/src/migrations/latest/smithy-ssdk-bundle-pins/migration.js +78 -0
  16. package/src/migrations/latest/smithy-ssdk-bundle-pins/migration.js.map +1 -0
  17. package/src/migrations/v1.0.0-rc.50/modernize-function-props-cast/migration.js.map +1 -0
  18. package/src/migrations/v1.0.0-rc.50/restrict-cors-to-custom-domains/migration.js.map +1 -0
  19. package/src/migrations/v1.0.0-rc.50/terraform-bootstrap-adopt-existing-bucket/migration.d.ts +6 -0
  20. package/src/migrations/v1.0.0-rc.50/terraform-bootstrap-adopt-existing-bucket/migration.js.map +1 -0
  21. package/src/migrations/v1.0.0-rc.52/user-identity-waf-allow-localhost-callback/migration.js.map +1 -0
  22. package/src/migrations/v1.0.0-rc.54/order-access-log-delivery-after-bucket-policy/migration.js.map +1 -0
  23. package/src/migrations/v1.0.0-rc.55/backfill-generator-metadata/migration.js.map +1 -0
  24. package/src/migrations/v1.0.0-rc.56/dynamodb-local-remove-optimize-flag/migration.js.map +1 -0
  25. package/src/migrations/v1.0.0-rc.57/ts-agent-session-management-support/migration.d.ts +6 -0
  26. package/src/migrations/v1.0.0-rc.57/ts-agent-session-management-support/migration.js +449 -0
  27. package/src/migrations/v1.0.0-rc.57/ts-agent-session-management-support/migration.js.map +1 -0
  28. package/src/preset/__snapshots__/generator.spec.ts.snap +5 -5
  29. package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +11 -9
  30. package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +20 -20
  31. package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +3 -3
  32. package/src/py/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +2 -1
  33. package/src/py/agent/a2a-connection/files/agent-connection/app/__targetAgentSnakeCase___client_strands.py.template +2 -1
  34. package/src/py/agent/a2a-connection/files/langchain/agent-connection/app/__targetAgentSnakeCase___client_langchain.py.template +2 -1
  35. package/src/py/agent/a2a-connection/generator.d.ts +1 -1
  36. package/src/py/agent/gateway-connection/generator.d.ts +1 -1
  37. package/src/py/agent/generator.js +4 -0
  38. package/src/py/agent/generator.js.map +1 -1
  39. package/src/py/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +2 -1
  40. package/src/py/agent/mcp-connection/files/agent-connection/app/__mcpServerSnakeCase___client_strands.py.template +2 -1
  41. package/src/py/agent/mcp-connection/files/langchain/agent-connection/app/__mcpServerSnakeCase___client_langchain.py.template +2 -1
  42. package/src/py/agent/mcp-connection/generator.d.ts +1 -1
  43. package/src/py/agent/react-connection/__snapshots__/generator.spec.ts.snap +6 -0
  44. package/src/py/agent/schema.d.js.map +1 -1
  45. package/src/py/agent/schema.d.ts +3 -0
  46. package/src/py/agent/schema.json +9 -0
  47. package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +2 -2
  48. package/src/py/dynamodb/schema.json +1 -0
  49. package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +12 -12
  50. package/src/py/fast-api/generator.d.ts +5 -0
  51. package/src/py/fast-api/generator.js +3 -2
  52. package/src/py/fast-api/generator.js.map +1 -1
  53. package/src/py/fast-api/schema.json +1 -0
  54. package/src/py/lambda-function/__snapshots__/generator.spec.ts.snap +2 -2
  55. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +9 -7
  56. package/src/py/mcp-server/schema.json +1 -0
  57. package/src/py/rdb/__snapshots__/generator.spec.ts.snap +2 -2
  58. package/src/py/rdb/schema.json +1 -0
  59. package/src/smithy/project/__snapshots__/generator.spec.ts.snap +4 -4
  60. package/src/smithy/project/files/service/build.Dockerfile.template +2 -2
  61. package/src/smithy/project/generator.d.ts +25 -0
  62. package/src/smithy/project/generator.js +24 -3
  63. package/src/smithy/project/generator.js.map +1 -1
  64. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +7 -7
  65. package/src/smithy/ts/api/generator.d.ts +6 -1
  66. package/src/smithy/ts/api/generator.js +3 -2
  67. package/src/smithy/ts/api/generator.js.map +1 -1
  68. package/src/smithy/ts/api/schema.json +1 -0
  69. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +12 -12
  70. package/src/trpc/backend/generator.d.ts +6 -1
  71. package/src/trpc/backend/generator.js +3 -2
  72. package/src/trpc/backend/generator.js.map +1 -1
  73. package/src/trpc/backend/schema.json +1 -0
  74. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +668 -24
  75. package/src/ts/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +2 -1
  76. package/src/ts/agent/a2a-connection/files/agent-connection/app/__targetAgentKebabCase__-client-strands.ts.template +1 -1
  77. package/src/ts/agent/files/ag-ui/index.ts.template +10 -1
  78. package/src/ts/agent/files/common/agent.ts.template +11 -3
  79. package/src/ts/agent/files/common/session.ts.template +43 -0
  80. package/src/ts/agent/gateway-connection/__snapshots__/generator.spec.ts.snap +1 -0
  81. package/src/ts/agent/generator.d.ts +36 -1
  82. package/src/ts/agent/generator.js +28 -4
  83. package/src/ts/agent/generator.js.map +1 -1
  84. package/src/ts/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +2 -1
  85. package/src/ts/agent/mcp-connection/files/agent-connection/app/__mcpServerKebabCase__-client-strands.ts.template +2 -1
  86. package/src/ts/agent/react-connection/__snapshots__/generator.spec.ts.snap +8 -4
  87. package/src/ts/agent/react-connection/files/src/components/__agentNameClassName__AgentClientProvider.tsx.template +2 -1
  88. package/src/ts/agent/schema.d.js.map +1 -1
  89. package/src/ts/agent/schema.d.ts +3 -0
  90. package/src/ts/agent/schema.json +9 -0
  91. package/src/ts/dcr-proxy/__snapshots__/generator.spec.ts.snap +1 -1
  92. package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +2 -2
  93. package/src/ts/dynamodb/schema.json +1 -0
  94. package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +2 -2
  95. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +6 -4
  96. package/src/ts/mcp-server/generator.d.ts +32 -1
  97. package/src/ts/mcp-server/generator.js +7 -4
  98. package/src/ts/mcp-server/generator.js.map +1 -1
  99. package/src/ts/mcp-server/schema.json +1 -0
  100. package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +6 -6
  101. package/src/ts/rdb/generator.d.ts +8 -0
  102. package/src/ts/rdb/generator.js +3 -2
  103. package/src/ts/rdb/generator.js.map +1 -1
  104. package/src/ts/rdb/schema.json +1 -0
  105. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +61 -45
  106. package/src/ts/react-website/app/generator.d.ts +6 -1
  107. package/src/ts/react-website/app/generator.js +3 -2
  108. package/src/ts/react-website/app/generator.js.map +1 -1
  109. package/src/ts/react-website/app/schema.json +1 -0
  110. package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +2 -2
  111. package/src/ts/react-website/cognito-auth/generator.d.ts +6 -1
  112. package/src/ts/react-website/cognito-auth/generator.js +3 -2
  113. package/src/ts/react-website/cognito-auth/generator.js.map +1 -1
  114. package/src/utils/agent-chat/files/common/agentcore.ts.template +2 -2
  115. package/src/utils/agent-connection/agent-connection.js +4 -0
  116. package/src/utils/agent-connection/agent-connection.js.map +1 -1
  117. package/src/utils/agent-connection/files/core-runtime-config/runtime-config.ts.template +11 -1
  118. package/src/utils/agent-connection/files/core-strands/base/model-errors-strands.ts.template +26 -15
  119. package/src/utils/agent-connection/files/core-strands/base/tool-errors-strands.ts.template +23 -16
  120. package/src/utils/agent-connection/files/py-core-runtime-config/runtime_config.py.template +4 -3
  121. package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +22 -0
  122. package/src/utils/agent-core-constructs/agent-core-constructs.js +29 -2
  123. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  124. package/src/utils/agent-core-constructs/files/cdk/app/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +131 -3
  125. package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +180 -1
  126. package/src/utils/api-constructs/api-constructs.d.ts +9 -0
  127. package/src/utils/api-constructs/api-constructs.js +11 -1
  128. package/src/utils/api-constructs/api-constructs.js.map +1 -1
  129. package/src/utils/ast.d.ts +5 -0
  130. package/src/utils/ast.js +25 -0
  131. package/src/utils/ast.js.map +1 -1
  132. package/src/utils/connection/open-api/files/components/__apiNameClassName__Provider.tsx.template +2 -0
  133. package/src/utils/docker.d.ts +27 -2
  134. package/src/utils/docker.js +31 -2
  135. package/src/utils/docker.js.map +1 -1
  136. package/src/utils/identity-constructs/identity-constructs.d.ts +10 -0
  137. package/src/utils/identity-constructs/identity-constructs.js +11 -1
  138. package/src/utils/identity-constructs/identity-constructs.js.map +1 -1
  139. package/src/utils/shared-constructs-constants.d.ts +6 -0
  140. package/src/utils/shared-constructs-constants.js +5 -0
  141. package/src/utils/shared-constructs-constants.js.map +1 -1
  142. package/src/utils/version-upgrade-migration/owned-dependencies.d.ts +26 -0
  143. package/src/utils/version-upgrade-migration/owned-dependencies.js +52 -4
  144. package/src/utils/version-upgrade-migration/owned-dependencies.js.map +1 -1
  145. package/src/utils/version-upgrade-migration/register.d.ts +5 -1
  146. package/src/utils/version-upgrade-migration/register.js +6 -2
  147. package/src/utils/version-upgrade-migration/register.js.map +1 -1
  148. package/src/utils/version-upgrade-migration/sync-embedded-versions.d.ts +26 -0
  149. package/src/utils/version-upgrade-migration/sync-embedded-versions.js +304 -0
  150. package/src/utils/version-upgrade-migration/sync-embedded-versions.js.map +1 -0
  151. package/src/utils/version-upgrade-migration/sync-vended-versions.js +14 -0
  152. package/src/utils/version-upgrade-migration/sync-vended-versions.js.map +1 -1
  153. package/src/utils/versions.d.ts +90 -77
  154. package/src/utils/versions.js +86 -75
  155. package/src/utils/versions.js.map +1 -1
  156. package/src/utils/website-constructs/website-constructs.d.ts +11 -0
  157. package/src/utils/website-constructs/website-constructs.js +12 -1
  158. package/src/utils/website-constructs/website-constructs.js.map +1 -1
  159. package/src/migrations/latest/backfill-generator-metadata/migration.js.map +0 -1
  160. package/src/migrations/latest/dynamodb-local-remove-optimize-flag/migration.js.map +0 -1
  161. package/src/migrations/latest/modernize-function-props-cast/migration.js.map +0 -1
  162. package/src/migrations/latest/order-access-log-delivery-after-bucket-policy/migration.js.map +0 -1
  163. package/src/migrations/latest/restrict-cors-to-custom-domains/migration.js.map +0 -1
  164. package/src/migrations/latest/terraform-bootstrap-adopt-existing-bucket/migration.js.map +0 -1
  165. package/src/migrations/latest/user-identity-waf-allow-localhost-callback/migration.js.map +0 -1
  166. /package/src/migrations/latest/{modernize-function-props-cast → smithy-ssdk-bundle-pins}/migration.d.ts +0 -0
  167. /package/src/migrations/{latest/restrict-cors-to-custom-domains → v1.0.0-rc.50/modernize-function-props-cast}/migration.d.ts +0 -0
  168. /package/src/migrations/{latest → v1.0.0-rc.50}/modernize-function-props-cast/migration.js +0 -0
  169. /package/src/migrations/{latest/terraform-bootstrap-adopt-existing-bucket → v1.0.0-rc.50/restrict-cors-to-custom-domains}/migration.d.ts +0 -0
  170. /package/src/migrations/{latest → v1.0.0-rc.50}/restrict-cors-to-custom-domains/migration.js +0 -0
  171. /package/src/migrations/{latest → v1.0.0-rc.50}/terraform-bootstrap-adopt-existing-bucket/migration.js +0 -0
  172. /package/src/migrations/{latest/dynamodb-local-remove-optimize-flag → v1.0.0-rc.52/user-identity-waf-allow-localhost-callback}/migration.d.ts +0 -0
  173. /package/src/migrations/{latest → v1.0.0-rc.52}/user-identity-waf-allow-localhost-callback/migration.js +0 -0
  174. /package/src/migrations/{latest → v1.0.0-rc.54}/order-access-log-delivery-after-bucket-policy/migration.d.ts +0 -0
  175. /package/src/migrations/{latest → v1.0.0-rc.54}/order-access-log-delivery-after-bucket-policy/migration.js +0 -0
  176. /package/src/migrations/{latest → v1.0.0-rc.55}/backfill-generator-metadata/migration.d.ts +0 -0
  177. /package/src/migrations/{latest → v1.0.0-rc.55}/backfill-generator-metadata/migration.js +0 -0
  178. /package/src/migrations/{latest/user-identity-waf-allow-localhost-callback → v1.0.0-rc.56/dynamodb-local-remove-optimize-flag}/migration.d.ts +0 -0
  179. /package/src/migrations/{latest → v1.0.0-rc.56}/dynamodb-local-remove-optimize-flag/migration.js +0 -0
@@ -17,9 +17,34 @@ export declare const DOCKER_DEPENDENCIES: readonly [{
17
17
  * version to install globally, and the versions its dependency overrides pin.
18
18
  */
19
19
  export declare const nodeImageVersions: () => {
20
- npmVersion: "12.0.1";
21
- minimatchVersion: "10.2.5";
20
+ npmVersion: "12.0.2";
21
+ minimatchVersion: "10.2.6";
22
22
  };
23
+ /**
24
+ * Packages a vended Node `Dockerfile` pins, which every generator writing one
25
+ * must declare so the version sync keeps those pins current.
26
+ *
27
+ * Spread through `ownedElsewhere`: the pin lives in the image build rather than
28
+ * in any manifest, so nothing is installed into the workspace. Left undeclared
29
+ * these would be the only vended versions never upgraded — and they are
30
+ * precisely the ones held at a version clear of a known HIGH/CRITICAL
31
+ * vulnerability.
32
+ */
33
+ export declare const NODE_IMAGE_DEPENDENCIES: readonly [{
34
+ readonly name: "npm";
35
+ }, {
36
+ readonly name: "minimatch";
37
+ }];
38
+ /**
39
+ * Packages the AWS Distro for OpenTelemetry install in a vended `Dockerfile`
40
+ * pins, for the images that auto-instrument with it. Spread through
41
+ * `ownedElsewhere` for the same reason as {@link NODE_IMAGE_DEPENDENCIES}.
42
+ */
43
+ export declare const ADOT_IMAGE_DEPENDENCIES: readonly [{
44
+ readonly name: "@aws/aws-distro-opentelemetry-node-autoinstrumentation";
45
+ }, {
46
+ readonly name: "@opentelemetry/propagator-jaeger";
47
+ }];
23
48
  export interface DockerScanTargetOptions {
24
49
  /**
25
50
  * Project configuration to add the scan target to (mutated in place).
@@ -5,7 +5,7 @@
5
5
  import { forDependencies } from "./declared-dependencies.js";
6
6
  import { FS_DEPENDENCIES, FsCommands } from "./fs.js";
7
7
  import { addDependencyToTargetIfNotPresent } from "./nx.js";
8
- import { CONTAINER_VERSIONS, TS_VERSIONS } from "./versions.js";
8
+ import { containerImage, TS_VERSIONS } from "./versions.js";
9
9
  /** Dependencies a caller must declare to add a Docker scan target. */ export const DOCKER_DEPENDENCIES = [
10
10
  ...FS_DEPENDENCIES
11
11
  ];
@@ -21,6 +21,35 @@ const TRIVY_IGNORE_CONTENTS = `# Trivy ignore file. Add one vulnerability ID (e.
21
21
  npmVersion: TS_VERSIONS.npm,
22
22
  minimatchVersion: TS_VERSIONS.minimatch
23
23
  });
24
+ /**
25
+ * Packages a vended Node `Dockerfile` pins, which every generator writing one
26
+ * must declare so the version sync keeps those pins current.
27
+ *
28
+ * Spread through `ownedElsewhere`: the pin lives in the image build rather than
29
+ * in any manifest, so nothing is installed into the workspace. Left undeclared
30
+ * these would be the only vended versions never upgraded — and they are
31
+ * precisely the ones held at a version clear of a known HIGH/CRITICAL
32
+ * vulnerability.
33
+ */ export const NODE_IMAGE_DEPENDENCIES = [
34
+ {
35
+ name: 'npm'
36
+ },
37
+ {
38
+ name: 'minimatch'
39
+ }
40
+ ];
41
+ /**
42
+ * Packages the AWS Distro for OpenTelemetry install in a vended `Dockerfile`
43
+ * pins, for the images that auto-instrument with it. Spread through
44
+ * `ownedElsewhere` for the same reason as {@link NODE_IMAGE_DEPENDENCIES}.
45
+ */ export const ADOT_IMAGE_DEPENDENCIES = [
46
+ {
47
+ name: '@aws/aws-distro-opentelemetry-node-autoinstrumentation'
48
+ },
49
+ {
50
+ name: '@opentelemetry/propagator-jaeger'
51
+ }
52
+ ];
24
53
  /**
25
54
  * Add a cacheable Trivy scan target for the images built by a docker target
26
55
  * and wire it under the aggregate \`trivy\` target. The scan is not part of
@@ -50,7 +79,7 @@ const TRIVY_IGNORE_CONTENTS = `# Trivy ignore file. Add one vulnerability ID (e.
50
79
  // per target, so it makes a stable, collision-free key.
51
80
  const scanKey = imageTags[0].replace(/[^a-zA-Z0-9-]/g, '-');
52
81
  const scanDir = joinPathFragments('dist', projectRoot, 'trivy', scanKey);
53
- const trivyImage = `public.ecr.aws/aquasecurity/trivy:${CONTAINER_VERSIONS.trivy}`;
82
+ const trivyImage = containerImage('trivy');
54
83
  const fs = new FsCommands(tree, forDependencies(declaration));
55
84
  const commands = [
56
85
  fs.rm(scanDir),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/docker.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type ProjectConfiguration,\n type Tree,\n} from '@nx/devkit';\nimport {\n type DependencyDeclaration,\n forDependencies,\n type MustDeclare,\n} from './declared-dependencies';\nimport { FS_DEPENDENCIES, FsCommands } from './fs';\nimport { addDependencyToTargetIfNotPresent } from './nx';\nimport { CONTAINER_VERSIONS, TS_VERSIONS } from './versions';\n\n/** Dependencies a caller must declare to add a Docker scan target. */\nexport const DOCKER_DEPENDENCIES = [...FS_DEPENDENCIES] as const;\n\nconst TRIVY_IGNORE_FILE = '.trivyignore';\n\nconst TRIVY_IGNORE_CONTENTS = `# Trivy ignore file. Add one vulnerability ID (e.g. CVE-2021-12345) per line to\n# suppress it during the image scan (\\`nx run-many --target trivy\\`).\n# https://trivy.dev/latest/docs/configuration/filtering/#by-finding-ids\n`;\n\n/**\n * Substitution variables for the vended Node `Dockerfile` templates: the npm\n * version to install globally, and the versions its dependency overrides pin.\n */\nexport const nodeImageVersions = () => ({\n npmVersion: TS_VERSIONS.npm,\n minimatchVersion: TS_VERSIONS.minimatch,\n});\n\nexport interface DockerScanTargetOptions {\n /**\n * Project configuration to add the scan target to (mutated in place).\n */\n readonly project: ProjectConfiguration;\n /**\n * Container engine command to invoke (\\`docker\\` or \\`finch\\`).\n */\n readonly containerEngine: string;\n /**\n * Name of the scan target to add, e.g. \\`my-agent-trivy\\`.\n */\n readonly trivyTargetName: string;\n /**\n * Name of the docker target that builds the image(s) to scan. The scan\n * target depends on it.\n */\n readonly dockerTargetName: string;\n /**\n * Tags of the images built by the docker target which should be scanned.\n */\n readonly imageTags: string[];\n}\n\n/**\n * Add a cacheable Trivy scan target for the images built by a docker target\n * and wire it under the aggregate \\`trivy\\` target. The scan is not part of\n * \\`build\\` — run \\`nx run-many --target trivy\\` (the root \\`trivy\\` script) in CI.\n *\n * The scan target depends on the docker target and declares the project source\n * as its inputs, so an unchanged image is never re-scanned (a cache hit skips\n * the scan entirely). Each image is saved to a tarball under\n * \\`dist/<projectRoot>/trivy/<scan-key>\\` (kept out of any Docker build context)\n * and scanned with the pinned ECR-hosted Trivy image via a workspace-relative\n * bind mount, so the same commands work under both docker and finch. The scan\n * exits non-zero (exit code 1) on HIGH/CRITICAL vulnerabilities.\n *\n * A \\`.trivyignore\\` is vended at the project root (kept if it already exists)\n * for suppressing findings.\n */\nexport const addDockerScanTarget = <const D extends DependencyDeclaration>(\n tree: Tree,\n options: DockerScanTargetOptions,\n declaration: D & MustDeclare<typeof DOCKER_DEPENDENCIES, D>,\n): void => {\n const { project, containerEngine, trivyTargetName, dockerTargetName } =\n options;\n const { imageTags } = options;\n const projectRoot = project.root;\n\n const ignoreFilePath = joinPathFragments(projectRoot, TRIVY_IGNORE_FILE);\n if (!tree.exists(ignoreFilePath)) {\n tree.write(ignoreFilePath, TRIVY_IGNORE_CONTENTS);\n }\n\n // Stage scan artifacts in a directory unique to this scan target so that\n // sibling targets in the same project (e.g. multiple agents) don't clobber\n // each other's tarballs when run in parallel. The first image tag is unique\n // per target, so it makes a stable, collision-free key.\n const scanKey = imageTags[0].replace(/[^a-zA-Z0-9-]/g, '-');\n const scanDir = joinPathFragments('dist', projectRoot, 'trivy', scanKey);\n const trivyImage = `public.ecr.aws/aquasecurity/trivy:${CONTAINER_VERSIONS.trivy}`;\n\n const fs = new FsCommands(\n tree,\n forDependencies<typeof DOCKER_DEPENDENCIES>(declaration),\n );\n const commands = [\n fs.rm(scanDir),\n fs.mkdir(scanDir),\n fs.cp(ignoreFilePath, joinPathFragments(scanDir, TRIVY_IGNORE_FILE)),\n ];\n\n imageTags.forEach((imageTag, index) => {\n const tarName = `image-${index}.tar`;\n commands.push(\n `${containerEngine} save -o ${joinPathFragments(scanDir, tarName)} ${imageTag}`,\n `${containerEngine} run --rm -v \"./${scanDir}\":/scan ${trivyImage} image --input /scan/${tarName} --ignorefile /scan/${TRIVY_IGNORE_FILE} --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 --no-progress -q`,\n );\n });\n\n project.targets ??= {};\n project.targets[trivyTargetName] = {\n cache: true,\n // The scanned image is fully determined by the project source, so caching\n // on the source ensures an unchanged image is never re-scanned.\n inputs: ['default', '^production'],\n outputs: [`{workspaceRoot}/${scanDir}`],\n executor: 'nx:run-commands',\n options: {\n commands,\n parallel: false,\n },\n dependsOn: [dockerTargetName],\n };\n\n // Aggregate per-component scan targets under a single `trivy` target. The\n // scan is intentionally NOT wired into `build`: image scanning is slow and\n // its result depends on the ever-changing vulnerability database (a scan\n // that passes today can fail tomorrow when a new CVE is published), so\n // coupling it to `build` would make local and CI builds non-deterministic.\n // Run `nx run-many --target trivy` (the root `trivy` script) in CI instead.\n if (trivyTargetName !== 'trivy') {\n addDependencyToTargetIfNotPresent(project, 'trivy', trivyTargetName);\n }\n};\n"],"names":["joinPathFragments","forDependencies","FS_DEPENDENCIES","FsCommands","addDependencyToTargetIfNotPresent","CONTAINER_VERSIONS","TS_VERSIONS","DOCKER_DEPENDENCIES","TRIVY_IGNORE_FILE","TRIVY_IGNORE_CONTENTS","nodeImageVersions","npmVersion","npm","minimatchVersion","minimatch","addDockerScanTarget","tree","options","declaration","project","containerEngine","trivyTargetName","dockerTargetName","imageTags","projectRoot","root","ignoreFilePath","exists","write","scanKey","replace","scanDir","trivyImage","trivy","fs","commands","rm","mkdir","cp","forEach","imageTag","index","tarName","push","targets","cache","inputs","outputs","executor","parallel","dependsOn"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,QAGZ,aAAa;AACpB,SAEEC,eAAe,QAEV,6BAA0B;AACjC,SAASC,eAAe,EAAEC,UAAU,QAAQ,UAAO;AACnD,SAASC,iCAAiC,QAAQ,UAAO;AACzD,SAASC,kBAAkB,EAAEC,WAAW,QAAQ,gBAAa;AAE7D,oEAAoE,GACpE,OAAO,MAAMC,sBAAsB;OAAIL;CAAgB,CAAU;AAEjE,MAAMM,oBAAoB;AAE1B,MAAMC,wBAAwB,CAAC;;;AAG/B,CAAC;AAED;;;CAGC,GACD,OAAO,MAAMC,oBAAoB,IAAO,CAAA;QACtCC,YAAYL,YAAYM,GAAG;QAC3BC,kBAAkBP,YAAYQ,SAAS;IACzC,CAAA,EAAG;AA0BH;;;;;;;;;;;;;;;CAeC,GACD,OAAO,MAAMC,sBAAsB,CACjCC,MACAC,SACAC;IAEA,MAAM,EAAEC,OAAO,EAAEC,eAAe,EAAEC,eAAe,EAAEC,gBAAgB,EAAE,GACnEL;IACF,MAAM,EAAEM,SAAS,EAAE,GAAGN;IACtB,MAAMO,cAAcL,QAAQM,IAAI;IAEhC,MAAMC,iBAAiB1B,kBAAkBwB,aAAahB;IACtD,IAAI,CAACQ,KAAKW,MAAM,CAACD,iBAAiB;QAChCV,KAAKY,KAAK,CAACF,gBAAgBjB;IAC7B;IAEA,yEAAyE;IACzE,2EAA2E;IAC3E,4EAA4E;IAC5E,wDAAwD;IACxD,MAAMoB,UAAUN,SAAS,CAAC,EAAE,CAACO,OAAO,CAAC,kBAAkB;IACvD,MAAMC,UAAU/B,kBAAkB,QAAQwB,aAAa,SAASK;IAChE,MAAMG,aAAa,CAAC,kCAAkC,EAAE3B,mBAAmB4B,KAAK,EAAE;IAElF,MAAMC,KAAK,IAAI/B,WACba,MACAf,gBAA4CiB;IAE9C,MAAMiB,WAAW;QACfD,GAAGE,EAAE,CAACL;QACNG,GAAGG,KAAK,CAACN;QACTG,GAAGI,EAAE,CAACZ,gBAAgB1B,kBAAkB+B,SAASvB;KAClD;IAEDe,UAAUgB,OAAO,CAAC,CAACC,UAAUC;QAC3B,MAAMC,UAAU,CAAC,MAAM,EAAED,MAAM,IAAI,CAAC;QACpCN,SAASQ,IAAI,CACX,GAAGvB,gBAAgB,SAAS,EAAEpB,kBAAkB+B,SAASW,SAAS,CAAC,EAAEF,UAAU,EAC/E,GAAGpB,gBAAgB,gBAAgB,EAAEW,QAAQ,QAAQ,EAAEC,WAAW,qBAAqB,EAAEU,QAAQ,oBAAoB,EAAElC,kBAAkB,yFAAyF,CAAC;IAEvO;IAEAW,QAAQyB,OAAO,KAAK,CAAC;IACrBzB,QAAQyB,OAAO,CAACvB,gBAAgB,GAAG;QACjCwB,OAAO;QACP,0EAA0E;QAC1E,gEAAgE;QAChEC,QAAQ;YAAC;YAAW;SAAc;QAClCC,SAAS;YAAC,CAAC,gBAAgB,EAAEhB,SAAS;SAAC;QACvCiB,UAAU;QACV/B,SAAS;YACPkB;YACAc,UAAU;QACZ;QACAC,WAAW;YAAC5B;SAAiB;IAC/B;IAEA,0EAA0E;IAC1E,2EAA2E;IAC3E,yEAAyE;IACzE,uEAAuE;IACvE,2EAA2E;IAC3E,4EAA4E;IAC5E,IAAID,oBAAoB,SAAS;QAC/BjB,kCAAkCe,SAAS,SAASE;IACtD;AACF,EAAE"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/docker.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type ProjectConfiguration,\n type Tree,\n} from '@nx/devkit';\nimport {\n type DependencyDeclaration,\n forDependencies,\n type MustDeclare,\n} from './declared-dependencies';\nimport { FS_DEPENDENCIES, FsCommands } from './fs';\nimport { addDependencyToTargetIfNotPresent } from './nx';\nimport { containerImage, type ITsDepVersion, TS_VERSIONS } from './versions';\n\n/** Dependencies a caller must declare to add a Docker scan target. */\nexport const DOCKER_DEPENDENCIES = [...FS_DEPENDENCIES] as const;\n\nconst TRIVY_IGNORE_FILE = '.trivyignore';\n\nconst TRIVY_IGNORE_CONTENTS = `# Trivy ignore file. Add one vulnerability ID (e.g. CVE-2021-12345) per line to\n# suppress it during the image scan (\\`nx run-many --target trivy\\`).\n# https://trivy.dev/latest/docs/configuration/filtering/#by-finding-ids\n`;\n\n/**\n * Substitution variables for the vended Node `Dockerfile` templates: the npm\n * version to install globally, and the versions its dependency overrides pin.\n */\nexport const nodeImageVersions = () => ({\n npmVersion: TS_VERSIONS.npm,\n minimatchVersion: TS_VERSIONS.minimatch,\n});\n\n/**\n * Packages a vended Node `Dockerfile` pins, which every generator writing one\n * must declare so the version sync keeps those pins current.\n *\n * Spread through `ownedElsewhere`: the pin lives in the image build rather than\n * in any manifest, so nothing is installed into the workspace. Left undeclared\n * these would be the only vended versions never upgraded — and they are\n * precisely the ones held at a version clear of a known HIGH/CRITICAL\n * vulnerability.\n */\nexport const NODE_IMAGE_DEPENDENCIES = [\n { name: 'npm' },\n { name: 'minimatch' },\n] as const satisfies readonly { name: ITsDepVersion }[];\n\n/**\n * Packages the AWS Distro for OpenTelemetry install in a vended `Dockerfile`\n * pins, for the images that auto-instrument with it. Spread through\n * `ownedElsewhere` for the same reason as {@link NODE_IMAGE_DEPENDENCIES}.\n */\nexport const ADOT_IMAGE_DEPENDENCIES = [\n { name: '@aws/aws-distro-opentelemetry-node-autoinstrumentation' },\n { name: '@opentelemetry/propagator-jaeger' },\n] as const satisfies readonly { name: ITsDepVersion }[];\n\nexport interface DockerScanTargetOptions {\n /**\n * Project configuration to add the scan target to (mutated in place).\n */\n readonly project: ProjectConfiguration;\n /**\n * Container engine command to invoke (\\`docker\\` or \\`finch\\`).\n */\n readonly containerEngine: string;\n /**\n * Name of the scan target to add, e.g. \\`my-agent-trivy\\`.\n */\n readonly trivyTargetName: string;\n /**\n * Name of the docker target that builds the image(s) to scan. The scan\n * target depends on it.\n */\n readonly dockerTargetName: string;\n /**\n * Tags of the images built by the docker target which should be scanned.\n */\n readonly imageTags: string[];\n}\n\n/**\n * Add a cacheable Trivy scan target for the images built by a docker target\n * and wire it under the aggregate \\`trivy\\` target. The scan is not part of\n * \\`build\\` — run \\`nx run-many --target trivy\\` (the root \\`trivy\\` script) in CI.\n *\n * The scan target depends on the docker target and declares the project source\n * as its inputs, so an unchanged image is never re-scanned (a cache hit skips\n * the scan entirely). Each image is saved to a tarball under\n * \\`dist/<projectRoot>/trivy/<scan-key>\\` (kept out of any Docker build context)\n * and scanned with the pinned ECR-hosted Trivy image via a workspace-relative\n * bind mount, so the same commands work under both docker and finch. The scan\n * exits non-zero (exit code 1) on HIGH/CRITICAL vulnerabilities.\n *\n * A \\`.trivyignore\\` is vended at the project root (kept if it already exists)\n * for suppressing findings.\n */\nexport const addDockerScanTarget = <const D extends DependencyDeclaration>(\n tree: Tree,\n options: DockerScanTargetOptions,\n declaration: D & MustDeclare<typeof DOCKER_DEPENDENCIES, D>,\n): void => {\n const { project, containerEngine, trivyTargetName, dockerTargetName } =\n options;\n const { imageTags } = options;\n const projectRoot = project.root;\n\n const ignoreFilePath = joinPathFragments(projectRoot, TRIVY_IGNORE_FILE);\n if (!tree.exists(ignoreFilePath)) {\n tree.write(ignoreFilePath, TRIVY_IGNORE_CONTENTS);\n }\n\n // Stage scan artifacts in a directory unique to this scan target so that\n // sibling targets in the same project (e.g. multiple agents) don't clobber\n // each other's tarballs when run in parallel. The first image tag is unique\n // per target, so it makes a stable, collision-free key.\n const scanKey = imageTags[0].replace(/[^a-zA-Z0-9-]/g, '-');\n const scanDir = joinPathFragments('dist', projectRoot, 'trivy', scanKey);\n const trivyImage = containerImage('trivy');\n\n const fs = new FsCommands(\n tree,\n forDependencies<typeof DOCKER_DEPENDENCIES>(declaration),\n );\n const commands = [\n fs.rm(scanDir),\n fs.mkdir(scanDir),\n fs.cp(ignoreFilePath, joinPathFragments(scanDir, TRIVY_IGNORE_FILE)),\n ];\n\n imageTags.forEach((imageTag, index) => {\n const tarName = `image-${index}.tar`;\n commands.push(\n `${containerEngine} save -o ${joinPathFragments(scanDir, tarName)} ${imageTag}`,\n `${containerEngine} run --rm -v \"./${scanDir}\":/scan ${trivyImage} image --input /scan/${tarName} --ignorefile /scan/${TRIVY_IGNORE_FILE} --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 --no-progress -q`,\n );\n });\n\n project.targets ??= {};\n project.targets[trivyTargetName] = {\n cache: true,\n // The scanned image is fully determined by the project source, so caching\n // on the source ensures an unchanged image is never re-scanned.\n inputs: ['default', '^production'],\n outputs: [`{workspaceRoot}/${scanDir}`],\n executor: 'nx:run-commands',\n options: {\n commands,\n parallel: false,\n },\n dependsOn: [dockerTargetName],\n };\n\n // Aggregate per-component scan targets under a single `trivy` target. The\n // scan is intentionally NOT wired into `build`: image scanning is slow and\n // its result depends on the ever-changing vulnerability database (a scan\n // that passes today can fail tomorrow when a new CVE is published), so\n // coupling it to `build` would make local and CI builds non-deterministic.\n // Run `nx run-many --target trivy` (the root `trivy` script) in CI instead.\n if (trivyTargetName !== 'trivy') {\n addDependencyToTargetIfNotPresent(project, 'trivy', trivyTargetName);\n }\n};\n"],"names":["joinPathFragments","forDependencies","FS_DEPENDENCIES","FsCommands","addDependencyToTargetIfNotPresent","containerImage","TS_VERSIONS","DOCKER_DEPENDENCIES","TRIVY_IGNORE_FILE","TRIVY_IGNORE_CONTENTS","nodeImageVersions","npmVersion","npm","minimatchVersion","minimatch","NODE_IMAGE_DEPENDENCIES","name","ADOT_IMAGE_DEPENDENCIES","addDockerScanTarget","tree","options","declaration","project","containerEngine","trivyTargetName","dockerTargetName","imageTags","projectRoot","root","ignoreFilePath","exists","write","scanKey","replace","scanDir","trivyImage","fs","commands","rm","mkdir","cp","forEach","imageTag","index","tarName","push","targets","cache","inputs","outputs","executor","parallel","dependsOn"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,QAGZ,aAAa;AACpB,SAEEC,eAAe,QAEV,6BAA0B;AACjC,SAASC,eAAe,EAAEC,UAAU,QAAQ,UAAO;AACnD,SAASC,iCAAiC,QAAQ,UAAO;AACzD,SAASC,cAAc,EAAsBC,WAAW,QAAQ,gBAAa;AAE7E,oEAAoE,GACpE,OAAO,MAAMC,sBAAsB;OAAIL;CAAgB,CAAU;AAEjE,MAAMM,oBAAoB;AAE1B,MAAMC,wBAAwB,CAAC;;;AAG/B,CAAC;AAED;;;CAGC,GACD,OAAO,MAAMC,oBAAoB,IAAO,CAAA;QACtCC,YAAYL,YAAYM,GAAG;QAC3BC,kBAAkBP,YAAYQ,SAAS;IACzC,CAAA,EAAG;AAEH;;;;;;;;;CASC,GACD,OAAO,MAAMC,0BAA0B;IACrC;QAAEC,MAAM;IAAM;IACd;QAAEA,MAAM;IAAY;CACrB,CAAuD;AAExD;;;;CAIC,GACD,OAAO,MAAMC,0BAA0B;IACrC;QAAED,MAAM;IAAyD;IACjE;QAAEA,MAAM;IAAmC;CAC5C,CAAuD;AA0BxD;;;;;;;;;;;;;;;CAeC,GACD,OAAO,MAAME,sBAAsB,CACjCC,MACAC,SACAC;IAEA,MAAM,EAAEC,OAAO,EAAEC,eAAe,EAAEC,eAAe,EAAEC,gBAAgB,EAAE,GACnEL;IACF,MAAM,EAAEM,SAAS,EAAE,GAAGN;IACtB,MAAMO,cAAcL,QAAQM,IAAI;IAEhC,MAAMC,iBAAiB7B,kBAAkB2B,aAAanB;IACtD,IAAI,CAACW,KAAKW,MAAM,CAACD,iBAAiB;QAChCV,KAAKY,KAAK,CAACF,gBAAgBpB;IAC7B;IAEA,yEAAyE;IACzE,2EAA2E;IAC3E,4EAA4E;IAC5E,wDAAwD;IACxD,MAAMuB,UAAUN,SAAS,CAAC,EAAE,CAACO,OAAO,CAAC,kBAAkB;IACvD,MAAMC,UAAUlC,kBAAkB,QAAQ2B,aAAa,SAASK;IAChE,MAAMG,aAAa9B,eAAe;IAElC,MAAM+B,KAAK,IAAIjC,WACbgB,MACAlB,gBAA4CoB;IAE9C,MAAMgB,WAAW;QACfD,GAAGE,EAAE,CAACJ;QACNE,GAAGG,KAAK,CAACL;QACTE,GAAGI,EAAE,CAACX,gBAAgB7B,kBAAkBkC,SAAS1B;KAClD;IAEDkB,UAAUe,OAAO,CAAC,CAACC,UAAUC;QAC3B,MAAMC,UAAU,CAAC,MAAM,EAAED,MAAM,IAAI,CAAC;QACpCN,SAASQ,IAAI,CACX,GAAGtB,gBAAgB,SAAS,EAAEvB,kBAAkBkC,SAASU,SAAS,CAAC,EAAEF,UAAU,EAC/E,GAAGnB,gBAAgB,gBAAgB,EAAEW,QAAQ,QAAQ,EAAEC,WAAW,qBAAqB,EAAES,QAAQ,oBAAoB,EAAEpC,kBAAkB,yFAAyF,CAAC;IAEvO;IAEAc,QAAQwB,OAAO,KAAK,CAAC;IACrBxB,QAAQwB,OAAO,CAACtB,gBAAgB,GAAG;QACjCuB,OAAO;QACP,0EAA0E;QAC1E,gEAAgE;QAChEC,QAAQ;YAAC;YAAW;SAAc;QAClCC,SAAS;YAAC,CAAC,gBAAgB,EAAEf,SAAS;SAAC;QACvCgB,UAAU;QACV9B,SAAS;YACPiB;YACAc,UAAU;QACZ;QACAC,WAAW;YAAC3B;SAAiB;IAC/B;IAEA,0EAA0E;IAC1E,2EAA2E;IAC3E,yEAAyE;IACzE,uEAAuE;IACvE,2EAA2E;IAC3E,4EAA4E;IAC5E,IAAID,oBAAoB,SAAS;QAC/BpB,kCAAkCkB,SAAS,SAASE;IACtD;AACF,EAAE"}
@@ -4,6 +4,16 @@
4
4
  */
5
5
  import { type Tree } from '@nx/devkit';
6
6
  import type { Iac } from '../iac';
7
+ import { type IacMetadata } from '../shared-constructs-constants';
8
+ /**
9
+ * Python version the generated Terraform pins in the callback URL module's inline
10
+ * `uv run --with` script. Nothing installs it, so it is declared for its version
11
+ * alone, and only on the Terraform branch that writes the script.
12
+ */
13
+ export declare const IDENTITY_CONSTRUCTS_PY_DEPENDENCIES: readonly [{
14
+ readonly name: "boto3";
15
+ readonly when: (m: IacMetadata) => boolean;
16
+ }];
7
17
  export interface AddIdentityInfraOptions {
8
18
  cognitoDomain: string;
9
19
  allowSignup: boolean;
@@ -4,8 +4,18 @@
4
4
  */ import { generateFiles, joinPathFragments, OverwriteStrategy } from "@nx/devkit";
5
5
  import { addStarExport } from "../ast.js";
6
6
  import { esmVars } from "../module-format.js";
7
- import { PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, SHARED_TERRAFORM_DIR } from "../shared-constructs-constants.js";
7
+ import { generatedTerraform, PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, SHARED_TERRAFORM_DIR } from "../shared-constructs-constants.js";
8
8
  import { PY_VERSIONS, terraformProviderVersions } from "../versions.js";
9
+ /**
10
+ * Python version the generated Terraform pins in the callback URL module's inline
11
+ * `uv run --with` script. Nothing installs it, so it is declared for its version
12
+ * alone, and only on the Terraform branch that writes the script.
13
+ */ export const IDENTITY_CONSTRUCTS_PY_DEPENDENCIES = [
14
+ {
15
+ name: 'boto3',
16
+ when: generatedTerraform
17
+ }
18
+ ];
9
19
  /**
10
20
  * Add infrastructure for a static website
11
21
  */ export const addIdentityInfra = async (tree, options)=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/identity-constructs/identity-constructs.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n} from '@nx/devkit';\nimport { addStarExport } from '../ast';\nimport type { Iac } from '../iac';\nimport { esmVars } from '../module-format';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../shared-constructs-constants';\nimport { PY_VERSIONS, terraformProviderVersions } from '../versions';\n\nexport interface AddIdentityInfraOptions {\n cognitoDomain: string;\n allowSignup: boolean;\n}\n\n/**\n * Add infrastructure for a static website\n */\nexport const addIdentityInfra = async (\n tree: Tree,\n options: AddIdentityInfraOptions & { iac: Iac },\n) => {\n if (options.iac === 'cdk') {\n await addIdentityCdkConstructs(tree, options);\n } else if (options.iac === 'terraform') {\n addIdentityTerraformModules(tree, options);\n } else {\n throw new Error(`Unsupported iac ${options.iac}`);\n }\n};\n\nconst addIdentityCdkConstructs = async (\n tree: Tree,\n options: AddIdentityInfraOptions,\n) => {\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'cdk', 'core'),\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'src', 'core'),\n { ...options, ...esmVars(tree) },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'core',\n 'index.ts',\n ),\n './user-identity.js',\n );\n};\n\nconst addIdentityTerraformModules = (\n tree: Tree,\n options: AddIdentityInfraOptions,\n) => {\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'terraform', 'core'),\n joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'src', 'core'),\n {\n ...options,\n boto3Version: PY_VERSIONS.boto3,\n ...terraformProviderVersions(),\n },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n // Update the static website module to add the callback url\n const staticWebsiteModule = tree.read(\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'core',\n 'static-website',\n 'static-website.tf',\n ),\n 'utf-8',\n );\n if (\n staticWebsiteModule &&\n !staticWebsiteModule.includes(\n 'source = \"../user-identity/add-callback-url\"',\n )\n ) {\n // Find the aws_cloudfront_distribution.website resource and add the callback URL module after it.\n // Includes the CloudFront domain plus any custom domain names (aliases) configured via var.custom_domain_names.\n const callbackUrlModule = `\n\n# Add CloudFront domain and any custom domain names to user pool client callback URLs.\n# Keyed by statically-known values so for_each keys are resolvable at plan time; the\n# CloudFront domain is only known at apply time, so it appears in the value, not the key.\nlocals {\n callback_urls = merge(\n { cloudfront = \"https://\\${aws_cloudfront_distribution.website.domain_name}\" },\n { for domain in var.custom_domain_names : domain => \"https://\\${domain}\" },\n )\n}\n\nmodule \"add_callback_url\" {\n source = \"../user-identity/add-callback-url\"\n for_each = local.callback_urls\n\n callback_url = each.value\n\n depends_on = [aws_cloudfront_distribution.website]\n}`;\n\n // Find the CloudFront distribution resource using proper brace counting\n // This handles deeply nested structures correctly\n const resourceStartPattern =\n /resource\\s+\"aws_cloudfront_distribution\"\\s+\"website\"\\s*\\{/;\n const resourceStartMatch = staticWebsiteModule.match(resourceStartPattern);\n\n if (resourceStartMatch) {\n const startIndex =\n resourceStartMatch.index! + resourceStartMatch[0].length - 1; // Position at opening brace\n let braceCount = 0;\n let insertionPoint = -1;\n\n // Count braces to find the end of the resource block\n for (let i = startIndex; i < staticWebsiteModule.length; i++) {\n const char = staticWebsiteModule[i];\n if (char === '{') {\n braceCount++;\n } else if (char === '}') {\n braceCount--;\n if (braceCount === 0) {\n // Found the closing brace of the CloudFront resource\n insertionPoint = i + 1;\n break;\n }\n }\n }\n\n if (insertionPoint !== -1) {\n // Insert the callback URL module right after the CloudFront distribution\n const beforeInsertion = staticWebsiteModule.substring(\n 0,\n insertionPoint,\n );\n const afterInsertion = staticWebsiteModule.substring(insertionPoint);\n const updatedContent =\n beforeInsertion + callbackUrlModule + afterInsertion;\n\n tree.write(\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'core',\n 'static-website',\n 'static-website.tf',\n ),\n updatedContent,\n );\n }\n }\n }\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","addStarExport","esmVars","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_DIR","PY_VERSIONS","terraformProviderVersions","addIdentityInfra","tree","options","iac","addIdentityCdkConstructs","addIdentityTerraformModules","Error","dirname","overwriteStrategy","KeepExisting","boto3Version","boto3","staticWebsiteModule","read","includes","callbackUrlModule","resourceStartPattern","resourceStartMatch","match","startIndex","index","length","braceCount","insertionPoint","i","char","beforeInsertion","substring","afterInsertion","updatedContent","write"],"mappings":"AAAA;;;CAGC,GACD,SACEA,aAAa,EACbC,iBAAiB,EACjBC,iBAAiB,QAEZ,aAAa;AACpB,SAASC,aAAa,QAAQ,YAAS;AAEvC,SAASC,OAAO,QAAQ,sBAAmB;AAC3C,SACEC,YAAY,EACZC,qBAAqB,EACrBC,oBAAoB,QACf,oCAAiC;AACxC,SAASC,WAAW,EAAEC,yBAAyB,QAAQ,iBAAc;AAOrE;;CAEC,GACD,OAAO,MAAMC,mBAAmB,OAC9BC,MACAC;IAEA,IAAIA,QAAQC,GAAG,KAAK,OAAO;QACzB,MAAMC,yBAAyBH,MAAMC;IACvC,OAAO,IAAIA,QAAQC,GAAG,KAAK,aAAa;QACtCE,4BAA4BJ,MAAMC;IACpC,OAAO;QACL,MAAM,IAAII,MAAM,CAAC,gBAAgB,EAAEJ,QAAQC,GAAG,EAAE;IAClD;AACF,EAAE;AAEF,MAAMC,2BAA2B,OAC/BH,MACAC;IAEAZ,cACEW,MACAV,kBAAkB,YAAYgB,OAAO,EAAE,SAAS,OAAO,SACvDhB,kBAAkBI,cAAcC,uBAAuB,OAAO,SAC9D;QAAE,GAAGM,OAAO;QAAE,GAAGR,QAAQO,KAAK;IAAC,GAC/B;QACEO,mBAAmBhB,kBAAkBiB,YAAY;IACnD;IAGF,MAAMhB,cACJQ,MACAV,kBACEI,cACAC,uBACA,OACA,QACA,aAEF;AAEJ;AAEA,MAAMS,8BAA8B,CAClCJ,MACAC;IAEAZ,cACEW,MACAV,kBAAkB,YAAYgB,OAAO,EAAE,SAAS,aAAa,SAC7DhB,kBAAkBI,cAAcE,sBAAsB,OAAO,SAC7D;QACE,GAAGK,OAAO;QACVQ,cAAcZ,YAAYa,KAAK;QAC/B,GAAGZ,2BAA2B;IAChC,GACA;QACES,mBAAmBhB,kBAAkBiB,YAAY;IACnD;IAGF,2DAA2D;IAC3D,MAAMG,sBAAsBX,KAAKY,IAAI,CACnCtB,kBACEI,cACAE,sBACA,OACA,QACA,kBACA,sBAEF;IAEF,IACEe,uBACA,CAACA,oBAAoBE,QAAQ,CAC3B,iDAEF;QACA,kGAAkG;QAClG,gHAAgH;QAChH,MAAMC,oBAAoB,CAAC;;;;;;;;;;;;;;;;;;;CAmB9B,CAAC;QAEE,wEAAwE;QACxE,kDAAkD;QAClD,MAAMC,uBACJ;QACF,MAAMC,qBAAqBL,oBAAoBM,KAAK,CAACF;QAErD,IAAIC,oBAAoB;YACtB,MAAME,aACJF,mBAAmBG,KAAK,GAAIH,kBAAkB,CAAC,EAAE,CAACI,MAAM,GAAG,GAAG,4BAA4B;YAC5F,IAAIC,aAAa;YACjB,IAAIC,iBAAiB,CAAC;YAEtB,qDAAqD;YACrD,IAAK,IAAIC,IAAIL,YAAYK,IAAIZ,oBAAoBS,MAAM,EAAEG,IAAK;gBAC5D,MAAMC,OAAOb,mBAAmB,CAACY,EAAE;gBACnC,IAAIC,SAAS,KAAK;oBAChBH;gBACF,OAAO,IAAIG,SAAS,KAAK;oBACvBH;oBACA,IAAIA,eAAe,GAAG;wBACpB,qDAAqD;wBACrDC,iBAAiBC,IAAI;wBACrB;oBACF;gBACF;YACF;YAEA,IAAID,mBAAmB,CAAC,GAAG;gBACzB,yEAAyE;gBACzE,MAAMG,kBAAkBd,oBAAoBe,SAAS,CACnD,GACAJ;gBAEF,MAAMK,iBAAiBhB,oBAAoBe,SAAS,CAACJ;gBACrD,MAAMM,iBACJH,kBAAkBX,oBAAoBa;gBAExC3B,KAAK6B,KAAK,CACRvC,kBACEI,cACAE,sBACA,OACA,QACA,kBACA,sBAEFgC;YAEJ;QACF;IACF;AACF"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/identity-constructs/identity-constructs.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n} from '@nx/devkit';\nimport { addStarExport } from '../ast';\nimport type { DeclaredPyDependency } from '../declared-dependencies';\nimport type { Iac } from '../iac';\nimport { esmVars } from '../module-format';\nimport {\n generatedTerraform,\n type IacMetadata,\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../shared-constructs-constants';\nimport {\n type IPyDepVersion,\n PY_VERSIONS,\n terraformProviderVersions,\n} from '../versions';\n\n/**\n * Python version the generated Terraform pins in the callback URL module's inline\n * `uv run --with` script. Nothing installs it, so it is declared for its version\n * alone, and only on the Terraform branch that writes the script.\n */\nexport const IDENTITY_CONSTRUCTS_PY_DEPENDENCIES = [\n { name: 'boto3', when: generatedTerraform },\n] as const satisfies readonly DeclaredPyDependency<\n IPyDepVersion,\n IacMetadata\n>[];\n\nexport interface AddIdentityInfraOptions {\n cognitoDomain: string;\n allowSignup: boolean;\n}\n\n/**\n * Add infrastructure for a static website\n */\nexport const addIdentityInfra = async (\n tree: Tree,\n options: AddIdentityInfraOptions & { iac: Iac },\n) => {\n if (options.iac === 'cdk') {\n await addIdentityCdkConstructs(tree, options);\n } else if (options.iac === 'terraform') {\n addIdentityTerraformModules(tree, options);\n } else {\n throw new Error(`Unsupported iac ${options.iac}`);\n }\n};\n\nconst addIdentityCdkConstructs = async (\n tree: Tree,\n options: AddIdentityInfraOptions,\n) => {\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'cdk', 'core'),\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'src', 'core'),\n { ...options, ...esmVars(tree) },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'core',\n 'index.ts',\n ),\n './user-identity.js',\n );\n};\n\nconst addIdentityTerraformModules = (\n tree: Tree,\n options: AddIdentityInfraOptions,\n) => {\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'terraform', 'core'),\n joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'src', 'core'),\n {\n ...options,\n boto3Version: PY_VERSIONS.boto3,\n ...terraformProviderVersions(),\n },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n // Update the static website module to add the callback url\n const staticWebsiteModule = tree.read(\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'core',\n 'static-website',\n 'static-website.tf',\n ),\n 'utf-8',\n );\n if (\n staticWebsiteModule &&\n !staticWebsiteModule.includes(\n 'source = \"../user-identity/add-callback-url\"',\n )\n ) {\n // Find the aws_cloudfront_distribution.website resource and add the callback URL module after it.\n // Includes the CloudFront domain plus any custom domain names (aliases) configured via var.custom_domain_names.\n const callbackUrlModule = `\n\n# Add CloudFront domain and any custom domain names to user pool client callback URLs.\n# Keyed by statically-known values so for_each keys are resolvable at plan time; the\n# CloudFront domain is only known at apply time, so it appears in the value, not the key.\nlocals {\n callback_urls = merge(\n { cloudfront = \"https://\\${aws_cloudfront_distribution.website.domain_name}\" },\n { for domain in var.custom_domain_names : domain => \"https://\\${domain}\" },\n )\n}\n\nmodule \"add_callback_url\" {\n source = \"../user-identity/add-callback-url\"\n for_each = local.callback_urls\n\n callback_url = each.value\n\n depends_on = [aws_cloudfront_distribution.website]\n}`;\n\n // Find the CloudFront distribution resource using proper brace counting\n // This handles deeply nested structures correctly\n const resourceStartPattern =\n /resource\\s+\"aws_cloudfront_distribution\"\\s+\"website\"\\s*\\{/;\n const resourceStartMatch = staticWebsiteModule.match(resourceStartPattern);\n\n if (resourceStartMatch) {\n const startIndex =\n resourceStartMatch.index! + resourceStartMatch[0].length - 1; // Position at opening brace\n let braceCount = 0;\n let insertionPoint = -1;\n\n // Count braces to find the end of the resource block\n for (let i = startIndex; i < staticWebsiteModule.length; i++) {\n const char = staticWebsiteModule[i];\n if (char === '{') {\n braceCount++;\n } else if (char === '}') {\n braceCount--;\n if (braceCount === 0) {\n // Found the closing brace of the CloudFront resource\n insertionPoint = i + 1;\n break;\n }\n }\n }\n\n if (insertionPoint !== -1) {\n // Insert the callback URL module right after the CloudFront distribution\n const beforeInsertion = staticWebsiteModule.substring(\n 0,\n insertionPoint,\n );\n const afterInsertion = staticWebsiteModule.substring(insertionPoint);\n const updatedContent =\n beforeInsertion + callbackUrlModule + afterInsertion;\n\n tree.write(\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'core',\n 'static-website',\n 'static-website.tf',\n ),\n updatedContent,\n );\n }\n }\n }\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","addStarExport","esmVars","generatedTerraform","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_DIR","PY_VERSIONS","terraformProviderVersions","IDENTITY_CONSTRUCTS_PY_DEPENDENCIES","name","when","addIdentityInfra","tree","options","iac","addIdentityCdkConstructs","addIdentityTerraformModules","Error","dirname","overwriteStrategy","KeepExisting","boto3Version","boto3","staticWebsiteModule","read","includes","callbackUrlModule","resourceStartPattern","resourceStartMatch","match","startIndex","index","length","braceCount","insertionPoint","i","char","beforeInsertion","substring","afterInsertion","updatedContent","write"],"mappings":"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"}
@@ -31,6 +31,12 @@ export interface IacMetadata {
31
31
  * questions and no generator needs a second one.
32
32
  */
33
33
  export declare const generatedInfrastructure: (m: IacMetadata) => boolean;
34
+ /**
35
+ * Whether Terraform infrastructure was generated, for the versions only a `.tf`
36
+ * module pins — a Terraform inline script's `uv run --with` pins, which the CDK
37
+ * branch never writes.
38
+ */
39
+ export declare const generatedTerraform: (m: IacMetadata) => boolean;
34
40
  /**
35
41
  * Dependencies a caller must declare to use the shared constructs project.
36
42
  * Lives here so generators can spread it without importing the generator.
@@ -24,6 +24,11 @@ export const DYNAMODB_GENERATOR_IDS = [
24
24
  * resolves `iac` only on the infra branch, so one recorded field answers both
25
25
  * questions and no generator needs a second one.
26
26
  */ export const generatedInfrastructure = (m)=>m.iac !== undefined;
27
+ /**
28
+ * Whether Terraform infrastructure was generated, for the versions only a `.tf`
29
+ * module pins — a Terraform inline script's `uv run --with` pins, which the CDK
30
+ * branch never writes.
31
+ */ export const generatedTerraform = (m)=>m.iac === 'terraform';
27
32
  /**
28
33
  * Dependencies a caller must declare to use the shared constructs project.
29
34
  * Lives here so generators can spread it without importing the generator.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/shared-constructs-constants.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { DeclaredTsDependency } from './declared-dependencies';\nimport type { ITsDepVersion } from './versions';\n\nexport const PACKAGES_DIR = 'packages';\nexport const SHARED_CONSTRUCTS_NAME = 'common-constructs';\nexport const SHARED_CONSTRUCTS_DIR = 'common/constructs';\nexport const SHARED_TERRAFORM_NAME = 'terraform';\nexport const SHARED_TERRAFORM_DIR = 'common/terraform';\nexport const SHARED_SHADCN_NAME = 'common-shadcn';\nexport const SHARED_SHADCN_DIR = 'common/shadcn';\nexport const SHARED_INFRA_CONFIG_NAME = 'common-infra-config';\nexport const SHARED_INFRA_CONFIG_DIR = 'common/infra-config';\nexport const SHARED_SCRIPTS_NAME = 'common-scripts';\nexport const SHARED_SCRIPTS_DIR = 'common/scripts';\n\nexport const DYNAMODB_GENERATOR_IDS = ['ts#dynamodb', 'py#dynamodb'];\n\n/**\n * What a generator records about the infrastructure it generated.\n *\n * Every generator that creates infrastructure records the `iac` it used, so a\n * predicate can tell a CDK project from a Terraform one at upgrade time. Absent\n * when the generator was run with no infrastructure, so its presence doubles as\n * \"infrastructure was generated\" — which is what gates the packages an infra\n * helper adds.\n */\nexport interface IacMetadata {\n readonly iac?: string;\n}\n\n/**\n * Whether infrastructure was generated at all, so the packages an infra helper\n * adds are only claimed where that helper ran.\n *\n * Reads `iac` rather than the generator's own `infra` option: every generator\n * resolves `iac` only on the infra branch, so one recorded field answers both\n * questions and no generator needs a second one.\n */\nexport const generatedInfrastructure = (m: IacMetadata): boolean =>\n m.iac !== undefined;\n\n/**\n * Dependencies a caller must declare to use the shared constructs project.\n * Lives here so generators can spread it without importing the generator.\n *\n * `constructs` and `aws-cdk-lib` are gated on CDK because\n * `sharedConstructsGenerator` creates the TypeScript constructs project on that\n * branch alone — a Terraform workspace gets the shared Terraform project and\n * never receives them.\n */\nexport const SHARED_CONSTRUCTS_DEPENDENCIES = [\n { name: 'constructs', when: (m: IacMetadata) => m.iac === 'cdk' },\n { name: 'aws-cdk-lib', when: (m: IacMetadata) => m.iac === 'cdk' },\n { name: '@types/node' },\n] as const satisfies readonly DeclaredTsDependency<\n ITsDepVersion,\n IacMetadata\n>[];\n"],"names":["PACKAGES_DIR","SHARED_CONSTRUCTS_NAME","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_NAME","SHARED_TERRAFORM_DIR","SHARED_SHADCN_NAME","SHARED_SHADCN_DIR","SHARED_INFRA_CONFIG_NAME","SHARED_INFRA_CONFIG_DIR","SHARED_SCRIPTS_NAME","SHARED_SCRIPTS_DIR","DYNAMODB_GENERATOR_IDS","generatedInfrastructure","m","iac","undefined","SHARED_CONSTRUCTS_DEPENDENCIES","name","when"],"mappings":"AAAA;;;CAGC,GAID,OAAO,MAAMA,eAAe,WAAW;AACvC,OAAO,MAAMC,yBAAyB,oBAAoB;AAC1D,OAAO,MAAMC,wBAAwB,oBAAoB;AACzD,OAAO,MAAMC,wBAAwB,YAAY;AACjD,OAAO,MAAMC,uBAAuB,mBAAmB;AACvD,OAAO,MAAMC,qBAAqB,gBAAgB;AAClD,OAAO,MAAMC,oBAAoB,gBAAgB;AACjD,OAAO,MAAMC,2BAA2B,sBAAsB;AAC9D,OAAO,MAAMC,0BAA0B,sBAAsB;AAC7D,OAAO,MAAMC,sBAAsB,iBAAiB;AACpD,OAAO,MAAMC,qBAAqB,iBAAiB;AAEnD,OAAO,MAAMC,yBAAyB;IAAC;IAAe;CAAc,CAAC;AAerE;;;;;;;CAOC,GACD,OAAO,MAAMC,0BAA0B,CAACC,IACtCA,EAAEC,GAAG,KAAKC,UAAU;AAEtB;;;;;;;;CAQC,GACD,OAAO,MAAMC,iCAAiC;IAC5C;QAAEC,MAAM;QAAcC,MAAM,CAACL,IAAmBA,EAAEC,GAAG,KAAK;IAAM;IAChE;QAAEG,MAAM;QAAeC,MAAM,CAACL,IAAmBA,EAAEC,GAAG,KAAK;IAAM;IACjE;QAAEG,MAAM;IAAc;CACvB,CAGG"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/shared-constructs-constants.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { DeclaredTsDependency } from './declared-dependencies';\nimport type { ITsDepVersion } from './versions';\n\nexport const PACKAGES_DIR = 'packages';\nexport const SHARED_CONSTRUCTS_NAME = 'common-constructs';\nexport const SHARED_CONSTRUCTS_DIR = 'common/constructs';\nexport const SHARED_TERRAFORM_NAME = 'terraform';\nexport const SHARED_TERRAFORM_DIR = 'common/terraform';\nexport const SHARED_SHADCN_NAME = 'common-shadcn';\nexport const SHARED_SHADCN_DIR = 'common/shadcn';\nexport const SHARED_INFRA_CONFIG_NAME = 'common-infra-config';\nexport const SHARED_INFRA_CONFIG_DIR = 'common/infra-config';\nexport const SHARED_SCRIPTS_NAME = 'common-scripts';\nexport const SHARED_SCRIPTS_DIR = 'common/scripts';\n\nexport const DYNAMODB_GENERATOR_IDS = ['ts#dynamodb', 'py#dynamodb'];\n\n/**\n * What a generator records about the infrastructure it generated.\n *\n * Every generator that creates infrastructure records the `iac` it used, so a\n * predicate can tell a CDK project from a Terraform one at upgrade time. Absent\n * when the generator was run with no infrastructure, so its presence doubles as\n * \"infrastructure was generated\" — which is what gates the packages an infra\n * helper adds.\n */\nexport interface IacMetadata {\n readonly iac?: string;\n}\n\n/**\n * Whether infrastructure was generated at all, so the packages an infra helper\n * adds are only claimed where that helper ran.\n *\n * Reads `iac` rather than the generator's own `infra` option: every generator\n * resolves `iac` only on the infra branch, so one recorded field answers both\n * questions and no generator needs a second one.\n */\nexport const generatedInfrastructure = (m: IacMetadata): boolean =>\n m.iac !== undefined;\n\n/**\n * Whether Terraform infrastructure was generated, for the versions only a `.tf`\n * module pins — a Terraform inline script's `uv run --with` pins, which the CDK\n * branch never writes.\n */\nexport const generatedTerraform = (m: IacMetadata): boolean =>\n m.iac === 'terraform';\n\n/**\n * Dependencies a caller must declare to use the shared constructs project.\n * Lives here so generators can spread it without importing the generator.\n *\n * `constructs` and `aws-cdk-lib` are gated on CDK because\n * `sharedConstructsGenerator` creates the TypeScript constructs project on that\n * branch alone — a Terraform workspace gets the shared Terraform project and\n * never receives them.\n */\nexport const SHARED_CONSTRUCTS_DEPENDENCIES = [\n { name: 'constructs', when: (m: IacMetadata) => m.iac === 'cdk' },\n { name: 'aws-cdk-lib', when: (m: IacMetadata) => m.iac === 'cdk' },\n { name: '@types/node' },\n] as const satisfies readonly DeclaredTsDependency<\n ITsDepVersion,\n IacMetadata\n>[];\n"],"names":["PACKAGES_DIR","SHARED_CONSTRUCTS_NAME","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_NAME","SHARED_TERRAFORM_DIR","SHARED_SHADCN_NAME","SHARED_SHADCN_DIR","SHARED_INFRA_CONFIG_NAME","SHARED_INFRA_CONFIG_DIR","SHARED_SCRIPTS_NAME","SHARED_SCRIPTS_DIR","DYNAMODB_GENERATOR_IDS","generatedInfrastructure","m","iac","undefined","generatedTerraform","SHARED_CONSTRUCTS_DEPENDENCIES","name","when"],"mappings":"AAAA;;;CAGC,GAID,OAAO,MAAMA,eAAe,WAAW;AACvC,OAAO,MAAMC,yBAAyB,oBAAoB;AAC1D,OAAO,MAAMC,wBAAwB,oBAAoB;AACzD,OAAO,MAAMC,wBAAwB,YAAY;AACjD,OAAO,MAAMC,uBAAuB,mBAAmB;AACvD,OAAO,MAAMC,qBAAqB,gBAAgB;AAClD,OAAO,MAAMC,oBAAoB,gBAAgB;AACjD,OAAO,MAAMC,2BAA2B,sBAAsB;AAC9D,OAAO,MAAMC,0BAA0B,sBAAsB;AAC7D,OAAO,MAAMC,sBAAsB,iBAAiB;AACpD,OAAO,MAAMC,qBAAqB,iBAAiB;AAEnD,OAAO,MAAMC,yBAAyB;IAAC;IAAe;CAAc,CAAC;AAerE;;;;;;;CAOC,GACD,OAAO,MAAMC,0BAA0B,CAACC,IACtCA,EAAEC,GAAG,KAAKC,UAAU;AAEtB;;;;CAIC,GACD,OAAO,MAAMC,qBAAqB,CAACH,IACjCA,EAAEC,GAAG,KAAK,YAAY;AAExB;;;;;;;;CAQC,GACD,OAAO,MAAMG,iCAAiC;IAC5C;QAAEC,MAAM;QAAcC,MAAM,CAACN,IAAmBA,EAAEC,GAAG,KAAK;IAAM;IAChE;QAAEI,MAAM;QAAeC,MAAM,CAACN,IAAmBA,EAAEC,GAAG,KAAK;IAAM;IACjE;QAAEI,MAAM;IAAc;CACvB,CAGG"}
@@ -12,6 +12,15 @@ export declare const PLUGIN_ROOT: string;
12
12
  export interface OwnedDependencies {
13
13
  readonly ts: ReadonlySet<string>;
14
14
  readonly py: ReadonlySet<string>;
15
+ /**
16
+ * The same, split by the root of the project that owns it, for scoping a pin
17
+ * embedded in a generated file to the project it sits in. Keyed by project
18
+ * root; read through {@link ownedForFile}.
19
+ */
20
+ readonly byProject: ReadonlyMap<string, {
21
+ readonly ts: ReadonlySet<string>;
22
+ readonly py: ReadonlySet<string>;
23
+ }>;
15
24
  }
16
25
  /**
17
26
  * One recorded run of a generator, with the metadata it wrote.
@@ -22,6 +31,8 @@ export interface OwnedDependencies {
22
31
  export interface GeneratorOccurrence {
23
32
  readonly id: string;
24
33
  readonly metadata: DependencyMetadata;
34
+ /** Root of the project this ran against, for scoping what it owns to it. */
35
+ readonly projectRoot?: string;
25
36
  }
26
37
  /**
27
38
  * Every recorded run of a generator in this workspace, from the metadata
@@ -48,3 +59,18 @@ export declare const generatorsRun: (tree: Tree) => ReadonlySet<string>;
48
59
  * rather than a run — the generators themselves are never invoked.
49
60
  */
50
61
  export declare const ownedDependencies: (tree: Tree) => Promise<OwnedDependencies>;
62
+ /**
63
+ * The dependencies owned where a file sits: those of the project it belongs to,
64
+ * or the workspace-wide union for a file in a shared project or under none.
65
+ *
66
+ * Used for the pins embedded in a generated file, so a version is only rewritten
67
+ * where the generator that pins it actually ran: a `Dockerfile` under one
68
+ * project's root is not upgraded because a sibling project owns the package.
69
+ *
70
+ * The longest matching root wins, since a nested project's root is a prefix of
71
+ * nothing else but its own files.
72
+ */
73
+ export declare const ownedForFile: (owned: OwnedDependencies, filePath: string) => {
74
+ ts: ReadonlySet<string>;
75
+ py: ReadonlySet<string>;
76
+ };
@@ -6,6 +6,7 @@ import { getProjects } from "@nx/devkit";
6
6
  import { AWS_NX_PLUGIN_CONFIG_FILE_NAME } from "../config/utils.js";
7
7
  import { ownedDependencyEntries } from "../declared-dependencies.js";
8
8
  import { buildGeneratorInfoList } from "../generators.js";
9
+ import { PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, SHARED_TERRAFORM_DIR } from "../shared-constructs-constants.js";
9
10
  /** Directory holding `generators.json`, which maps ids to their modules. */ export const PLUGIN_ROOT = path.resolve(import.meta.dirname, '..', '..', '..');
10
11
  /**
11
12
  * Every recorded run of a generator in this workspace, from the metadata
@@ -29,14 +30,16 @@ import { buildGeneratorInfoList } from "../generators.js";
29
30
  const { components, ...ownMetadata } = metadata;
30
31
  occurrences.push({
31
32
  id: metadata.generator,
32
- metadata: ownMetadata
33
+ metadata: ownMetadata,
34
+ projectRoot: project.root
33
35
  });
34
36
  }
35
37
  for (const component of metadata?.components ?? []){
36
38
  if (component.generator) {
37
39
  occurrences.push({
38
40
  id: component.generator,
39
- metadata: component
41
+ metadata: component,
42
+ projectRoot: project.root
40
43
  });
41
44
  }
42
45
  }
@@ -59,6 +62,7 @@ import { buildGeneratorInfoList } from "../generators.js";
59
62
  const occurrences = generatorOccurrences(tree);
60
63
  const ts = new Set();
61
64
  const py = new Set();
65
+ const byProject = new Map();
62
66
  for (const info of buildGeneratorInfoList(PLUGIN_ROOT)){
63
67
  const matching = occurrences.filter((occurrence)=>occurrence.id === info.id);
64
68
  if (matching.length === 0) {
@@ -68,20 +72,64 @@ import { buildGeneratorInfoList } from "../generators.js";
68
72
  if (!declaration) {
69
73
  continue;
70
74
  }
71
- for (const { metadata } of matching){
75
+ for (const { metadata, projectRoot } of matching){
76
+ const scoped = projectRoot ? byProject.get(projectRoot) ?? byProject.set(projectRoot, {
77
+ ts: new Set(),
78
+ py: new Set()
79
+ }).get(projectRoot) : undefined;
72
80
  for (const entry of ownedDependencyEntries(declaration.ts, metadata)){
73
81
  ts.add(entry.name);
82
+ scoped?.ts.add(entry.name);
74
83
  }
75
84
  for (const entry of ownedDependencyEntries(declaration.py, metadata)){
76
85
  py.add(entry.name);
86
+ scoped?.py.add(entry.name);
77
87
  }
78
88
  }
79
89
  }
80
90
  return {
81
91
  ts,
82
- py
92
+ py,
93
+ byProject
83
94
  };
84
95
  };
96
+ /**
97
+ * Roots of the projects every generator contributes into, rather than one
98
+ * generator owning outright.
99
+ *
100
+ * `sharedConstructsGenerator` creates these and each infra generator writes its
101
+ * own module into them — the Terraform modules carrying the `uv run --with` pins
102
+ * come from the agent-core, api, identity and website helpers alike. Both are
103
+ * registered projects, so scoping a file here to the generator that created the
104
+ * project would strand every pin the others put there.
105
+ */ const SHARED_PROJECT_ROOTS = [
106
+ `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}`,
107
+ `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}`
108
+ ];
109
+ /**
110
+ * The dependencies owned where a file sits: those of the project it belongs to,
111
+ * or the workspace-wide union for a file in a shared project or under none.
112
+ *
113
+ * Used for the pins embedded in a generated file, so a version is only rewritten
114
+ * where the generator that pins it actually ran: a `Dockerfile` under one
115
+ * project's root is not upgraded because a sibling project owns the package.
116
+ *
117
+ * The longest matching root wins, since a nested project's root is a prefix of
118
+ * nothing else but its own files.
119
+ */ export const ownedForFile = (owned, filePath)=>{
120
+ if (SHARED_PROJECT_ROOTS.some((root)=>filePath === root || filePath.startsWith(`${root}/`))) {
121
+ return owned;
122
+ }
123
+ let best;
124
+ let bestLength = -1;
125
+ for (const [root, scoped] of owned.byProject){
126
+ if ((filePath === root || filePath.startsWith(`${root}/`)) && root.length > bestLength) {
127
+ best = scoped;
128
+ bestLength = root.length;
129
+ }
130
+ }
131
+ return best ?? owned;
132
+ };
85
133
  /**
86
134
  * A generator's `DEPENDENCIES`, or undefined when it declares none.
87
135
  * A generator that fails to load must not fail the upgrade, so its dependencies
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/version-upgrade-migration/owned-dependencies.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport * as path from 'node:path';\nimport { getProjects, type Tree } from '@nx/devkit';\nimport { AWS_NX_PLUGIN_CONFIG_FILE_NAME } from '../config/utils';\nimport {\n type DependencyDeclaration,\n type DependencyMetadata,\n ownedDependencyEntries,\n} from '../declared-dependencies';\nimport { buildGeneratorInfoList } from '../generators';\n\n/** Directory holding `generators.json`, which maps ids to their modules. */\nexport const PLUGIN_ROOT = path.resolve(import.meta.dirname, '..', '..', '..');\n\n/**\n * Which vended dependencies this workspace's generators are responsible for.\n *\n * Only these are synced, so a package the user added themselves keeps the version\n * they chose. Ownership is derived from the generators the workspace has run and\n * the dependencies each declares — nothing extra is recorded in the workspace.\n */\nexport interface OwnedDependencies {\n readonly ts: ReadonlySet<string>;\n readonly py: ReadonlySet<string>;\n}\n\n/**\n * One recorded run of a generator, with the metadata it wrote.\n *\n * The metadata carries the values the generator's dependency conditions read, so\n * a declaration filters down to the branch this occurrence actually took.\n */\nexport interface GeneratorOccurrence {\n readonly id: string;\n readonly metadata: DependencyMetadata;\n}\n\n/**\n * Every recorded run of a generator in this workspace, from the metadata\n * generators record on the projects (and components) they create.\n *\n * A generator appears once per project or component it created, since each may\n * have been run with different options.\n *\n * `init` creates no project, so its config file stands in for it.\n */\nexport const generatorOccurrences = (\n tree: Tree,\n): readonly GeneratorOccurrence[] => {\n const occurrences: GeneratorOccurrence[] = [];\n if (tree.exists(AWS_NX_PLUGIN_CONFIG_FILE_NAME)) {\n occurrences.push({ id: 'init', metadata: {} });\n }\n for (const [, project] of getProjects(tree)) {\n const metadata = project.metadata as\n | {\n generator?: string;\n components?: ({ generator?: string } & DependencyMetadata)[];\n }\n | undefined;\n if (metadata?.generator) {\n const { components, ...ownMetadata } = metadata;\n occurrences.push({ id: metadata.generator, metadata: ownMetadata });\n }\n for (const component of metadata?.components ?? []) {\n if (component.generator) {\n occurrences.push({ id: component.generator, metadata: component });\n }\n }\n }\n return occurrences;\n};\n\n/** Generator ids this workspace has run. */\nexport const generatorsRun = (tree: Tree): ReadonlySet<string> =>\n new Set(generatorOccurrences(tree).map((occurrence) => occurrence.id));\n\n/**\n * Union of the dependencies declared by the generators this workspace has run,\n * narrowed per occurrence to those whose conditions its recorded metadata\n * satisfies — a project generated with one protocol does not own another's\n * packages.\n *\n * A `versionOnly` entry is owned like any other: it is declared precisely so the\n * sync keeps its pinned version current wherever the workspace already holds it.\n *\n * Each generator module exports its declaration, so reading one is an import\n * rather than a run — the generators themselves are never invoked.\n */\nexport const ownedDependencies = async (\n tree: Tree,\n): Promise<OwnedDependencies> => {\n const occurrences = generatorOccurrences(tree);\n const ts = new Set<string>();\n const py = new Set<string>();\n\n for (const info of buildGeneratorInfoList(PLUGIN_ROOT)) {\n const matching = occurrences.filter(\n (occurrence) => occurrence.id === info.id,\n );\n if (matching.length === 0) {\n continue;\n }\n const declaration = await readDeclaration(info.resolvedFactoryPath);\n if (!declaration) {\n continue;\n }\n for (const { metadata } of matching) {\n for (const entry of ownedDependencyEntries(declaration.ts, metadata)) {\n ts.add(entry.name as string);\n }\n for (const entry of ownedDependencyEntries(declaration.py, metadata)) {\n py.add(entry.name as string);\n }\n }\n }\n\n return { ts, py };\n};\n\n/**\n * A generator's `DEPENDENCIES`, or undefined when it declares none.\n * A generator that fails to load must not fail the upgrade, so its dependencies\n * are treated as unowned and left as they are.\n */\nconst readDeclaration = async (\n factoryPath: string,\n): Promise<DependencyDeclaration | undefined> => {\n try {\n const module = await import(`${factoryPath}.js`);\n return module.DEPENDENCIES;\n } catch {\n return undefined;\n }\n};\n"],"names":["path","getProjects","AWS_NX_PLUGIN_CONFIG_FILE_NAME","ownedDependencyEntries","buildGeneratorInfoList","PLUGIN_ROOT","resolve","dirname","generatorOccurrences","tree","occurrences","exists","push","id","metadata","project","generator","components","ownMetadata","component","generatorsRun","Set","map","occurrence","ownedDependencies","ts","py","info","matching","filter","length","declaration","readDeclaration","resolvedFactoryPath","entry","add","name","factoryPath","module","DEPENDENCIES","undefined"],"mappings":"AAAA;;;CAGC,GACD,YAAYA,UAAU,YAAY;AAClC,SAASC,WAAW,QAAmB,aAAa;AACpD,SAASC,8BAA8B,QAAQ,qBAAkB;AACjE,SAGEC,sBAAsB,QACjB,8BAA2B;AAClC,SAASC,sBAAsB,QAAQ,mBAAgB;AAEvD,0EAA0E,GAC1E,OAAO,MAAMC,cAAcL,KAAKM,OAAO,CAAC,YAAYC,OAAO,EAAE,MAAM,MAAM,MAAM;AAyB/E;;;;;;;;CAQC,GACD,OAAO,MAAMC,uBAAuB,CAClCC;IAEA,MAAMC,cAAqC,EAAE;IAC7C,IAAID,KAAKE,MAAM,CAACT,iCAAiC;QAC/CQ,YAAYE,IAAI,CAAC;YAAEC,IAAI;YAAQC,UAAU,CAAC;QAAE;IAC9C;IACA,KAAK,MAAM,GAAGC,QAAQ,IAAId,YAAYQ,MAAO;QAC3C,MAAMK,WAAWC,QAAQD,QAAQ;QAMjC,IAAIA,UAAUE,WAAW;YACvB,MAAM,EAAEC,UAAU,EAAE,GAAGC,aAAa,GAAGJ;YACvCJ,YAAYE,IAAI,CAAC;gBAAEC,IAAIC,SAASE,SAAS;gBAAEF,UAAUI;YAAY;QACnE;QACA,KAAK,MAAMC,aAAaL,UAAUG,cAAc,EAAE,CAAE;YAClD,IAAIE,UAAUH,SAAS,EAAE;gBACvBN,YAAYE,IAAI,CAAC;oBAAEC,IAAIM,UAAUH,SAAS;oBAAEF,UAAUK;gBAAU;YAClE;QACF;IACF;IACA,OAAOT;AACT,EAAE;AAEF,0CAA0C,GAC1C,OAAO,MAAMU,gBAAgB,CAACX,OAC5B,IAAIY,IAAIb,qBAAqBC,MAAMa,GAAG,CAAC,CAACC,aAAeA,WAAWV,EAAE,GAAG;AAEzE;;;;;;;;;;;CAWC,GACD,OAAO,MAAMW,oBAAoB,OAC/Bf;IAEA,MAAMC,cAAcF,qBAAqBC;IACzC,MAAMgB,KAAK,IAAIJ;IACf,MAAMK,KAAK,IAAIL;IAEf,KAAK,MAAMM,QAAQvB,uBAAuBC,aAAc;QACtD,MAAMuB,WAAWlB,YAAYmB,MAAM,CACjC,CAACN,aAAeA,WAAWV,EAAE,KAAKc,KAAKd,EAAE;QAE3C,IAAIe,SAASE,MAAM,KAAK,GAAG;YACzB;QACF;QACA,MAAMC,cAAc,MAAMC,gBAAgBL,KAAKM,mBAAmB;QAClE,IAAI,CAACF,aAAa;YAChB;QACF;QACA,KAAK,MAAM,EAAEjB,QAAQ,EAAE,IAAIc,SAAU;YACnC,KAAK,MAAMM,SAAS/B,uBAAuB4B,YAAYN,EAAE,EAAEX,UAAW;gBACpEW,GAAGU,GAAG,CAACD,MAAME,IAAI;YACnB;YACA,KAAK,MAAMF,SAAS/B,uBAAuB4B,YAAYL,EAAE,EAAEZ,UAAW;gBACpEY,GAAGS,GAAG,CAACD,MAAME,IAAI;YACnB;QACF;IACF;IAEA,OAAO;QAAEX;QAAIC;IAAG;AAClB,EAAE;AAEF;;;;CAIC,GACD,MAAMM,kBAAkB,OACtBK;IAEA,IAAI;QACF,MAAMC,SAAS,MAAM,MAAM,CAAC,GAAGD,YAAY,GAAG,CAAC;QAC/C,OAAOC,OAAOC,YAAY;IAC5B,EAAE,OAAM;QACN,OAAOC;IACT;AACF"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/version-upgrade-migration/owned-dependencies.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport * as path from 'node:path';\nimport { getProjects, type Tree } from '@nx/devkit';\nimport { AWS_NX_PLUGIN_CONFIG_FILE_NAME } from '../config/utils';\nimport {\n type DependencyDeclaration,\n type DependencyMetadata,\n ownedDependencyEntries,\n} from '../declared-dependencies';\nimport { buildGeneratorInfoList } from '../generators';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../shared-constructs-constants';\n\n/** Directory holding `generators.json`, which maps ids to their modules. */\nexport const PLUGIN_ROOT = path.resolve(import.meta.dirname, '..', '..', '..');\n\n/**\n * Which vended dependencies this workspace's generators are responsible for.\n *\n * Only these are synced, so a package the user added themselves keeps the version\n * they chose. Ownership is derived from the generators the workspace has run and\n * the dependencies each declares — nothing extra is recorded in the workspace.\n */\nexport interface OwnedDependencies {\n readonly ts: ReadonlySet<string>;\n readonly py: ReadonlySet<string>;\n /**\n * The same, split by the root of the project that owns it, for scoping a pin\n * embedded in a generated file to the project it sits in. Keyed by project\n * root; read through {@link ownedForFile}.\n */\n readonly byProject: ReadonlyMap<\n string,\n { readonly ts: ReadonlySet<string>; readonly py: ReadonlySet<string> }\n >;\n}\n\n/**\n * One recorded run of a generator, with the metadata it wrote.\n *\n * The metadata carries the values the generator's dependency conditions read, so\n * a declaration filters down to the branch this occurrence actually took.\n */\nexport interface GeneratorOccurrence {\n readonly id: string;\n readonly metadata: DependencyMetadata;\n /** Root of the project this ran against, for scoping what it owns to it. */\n readonly projectRoot?: string;\n}\n\n/**\n * Every recorded run of a generator in this workspace, from the metadata\n * generators record on the projects (and components) they create.\n *\n * A generator appears once per project or component it created, since each may\n * have been run with different options.\n *\n * `init` creates no project, so its config file stands in for it.\n */\nexport const generatorOccurrences = (\n tree: Tree,\n): readonly GeneratorOccurrence[] => {\n const occurrences: GeneratorOccurrence[] = [];\n if (tree.exists(AWS_NX_PLUGIN_CONFIG_FILE_NAME)) {\n occurrences.push({ id: 'init', metadata: {} });\n }\n for (const [, project] of getProjects(tree)) {\n const metadata = project.metadata as\n | {\n generator?: string;\n components?: ({ generator?: string } & DependencyMetadata)[];\n }\n | undefined;\n if (metadata?.generator) {\n const { components, ...ownMetadata } = metadata;\n occurrences.push({\n id: metadata.generator,\n metadata: ownMetadata,\n projectRoot: project.root,\n });\n }\n for (const component of metadata?.components ?? []) {\n if (component.generator) {\n occurrences.push({\n id: component.generator,\n metadata: component,\n projectRoot: project.root,\n });\n }\n }\n }\n return occurrences;\n};\n\n/** Generator ids this workspace has run. */\nexport const generatorsRun = (tree: Tree): ReadonlySet<string> =>\n new Set(generatorOccurrences(tree).map((occurrence) => occurrence.id));\n\n/**\n * Union of the dependencies declared by the generators this workspace has run,\n * narrowed per occurrence to those whose conditions its recorded metadata\n * satisfies — a project generated with one protocol does not own another's\n * packages.\n *\n * A `versionOnly` entry is owned like any other: it is declared precisely so the\n * sync keeps its pinned version current wherever the workspace already holds it.\n *\n * Each generator module exports its declaration, so reading one is an import\n * rather than a run — the generators themselves are never invoked.\n */\nexport const ownedDependencies = async (\n tree: Tree,\n): Promise<OwnedDependencies> => {\n const occurrences = generatorOccurrences(tree);\n const ts = new Set<string>();\n const py = new Set<string>();\n const byProject = new Map<string, { ts: Set<string>; py: Set<string> }>();\n\n for (const info of buildGeneratorInfoList(PLUGIN_ROOT)) {\n const matching = occurrences.filter(\n (occurrence) => occurrence.id === info.id,\n );\n if (matching.length === 0) {\n continue;\n }\n const declaration = await readDeclaration(info.resolvedFactoryPath);\n if (!declaration) {\n continue;\n }\n for (const { metadata, projectRoot } of matching) {\n const scoped = projectRoot\n ? (byProject.get(projectRoot) ??\n byProject\n .set(projectRoot, { ts: new Set(), py: new Set() })\n .get(projectRoot)!)\n : undefined;\n for (const entry of ownedDependencyEntries(declaration.ts, metadata)) {\n ts.add(entry.name as string);\n scoped?.ts.add(entry.name as string);\n }\n for (const entry of ownedDependencyEntries(declaration.py, metadata)) {\n py.add(entry.name as string);\n scoped?.py.add(entry.name as string);\n }\n }\n }\n\n return { ts, py, byProject };\n};\n\n/**\n * Roots of the projects every generator contributes into, rather than one\n * generator owning outright.\n *\n * `sharedConstructsGenerator` creates these and each infra generator writes its\n * own module into them — the Terraform modules carrying the `uv run --with` pins\n * come from the agent-core, api, identity and website helpers alike. Both are\n * registered projects, so scoping a file here to the generator that created the\n * project would strand every pin the others put there.\n */\nconst SHARED_PROJECT_ROOTS = [\n `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}`,\n `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}`,\n];\n\n/**\n * The dependencies owned where a file sits: those of the project it belongs to,\n * or the workspace-wide union for a file in a shared project or under none.\n *\n * Used for the pins embedded in a generated file, so a version is only rewritten\n * where the generator that pins it actually ran: a `Dockerfile` under one\n * project's root is not upgraded because a sibling project owns the package.\n *\n * The longest matching root wins, since a nested project's root is a prefix of\n * nothing else but its own files.\n */\nexport const ownedForFile = (\n owned: OwnedDependencies,\n filePath: string,\n): { ts: ReadonlySet<string>; py: ReadonlySet<string> } => {\n if (\n SHARED_PROJECT_ROOTS.some(\n (root) => filePath === root || filePath.startsWith(`${root}/`),\n )\n ) {\n return owned;\n }\n let best: { ts: ReadonlySet<string>; py: ReadonlySet<string> } | undefined;\n let bestLength = -1;\n for (const [root, scoped] of owned.byProject) {\n if (\n (filePath === root || filePath.startsWith(`${root}/`)) &&\n root.length > bestLength\n ) {\n best = scoped;\n bestLength = root.length;\n }\n }\n return best ?? owned;\n};\n\n/**\n * A generator's `DEPENDENCIES`, or undefined when it declares none.\n * A generator that fails to load must not fail the upgrade, so its dependencies\n * are treated as unowned and left as they are.\n */\nconst readDeclaration = async (\n factoryPath: string,\n): Promise<DependencyDeclaration | undefined> => {\n try {\n const module = await import(`${factoryPath}.js`);\n return module.DEPENDENCIES;\n } catch {\n return undefined;\n }\n};\n"],"names":["path","getProjects","AWS_NX_PLUGIN_CONFIG_FILE_NAME","ownedDependencyEntries","buildGeneratorInfoList","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_DIR","PLUGIN_ROOT","resolve","dirname","generatorOccurrences","tree","occurrences","exists","push","id","metadata","project","generator","components","ownMetadata","projectRoot","root","component","generatorsRun","Set","map","occurrence","ownedDependencies","ts","py","byProject","Map","info","matching","filter","length","declaration","readDeclaration","resolvedFactoryPath","scoped","get","set","undefined","entry","add","name","SHARED_PROJECT_ROOTS","ownedForFile","owned","filePath","some","startsWith","best","bestLength","factoryPath","module","DEPENDENCIES"],"mappings":"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"}
@@ -18,6 +18,10 @@ import { type Tree } from '@nx/devkit';
18
18
  *
19
19
  * Idempotent: re-running before a release replaces the pending entry with itself.
20
20
  *
21
+ * @param nxVersion nx version being moved to. The update script rewrites
22
+ * `versions.ts` on the tree, which cannot change the `NX_VERSION` this process
23
+ * imported at load — so the caller passes the version it just wrote, or the
24
+ * entry would record the one being replaced.
21
25
  * @returns paths written, for the update report
22
26
  */
23
- export declare const registerNxPackageUpdates: (tree: Tree) => string[];
27
+ export declare const registerNxPackageUpdates: (tree: Tree, nxVersion?: string) => string[];
@@ -20,14 +20,18 @@ const MIGRATIONS_JSON_PATH = 'packages/nx-plugin/migrations.json';
20
20
  *
21
21
  * Idempotent: re-running before a release replaces the pending entry with itself.
22
22
  *
23
+ * @param nxVersion nx version being moved to. The update script rewrites
24
+ * `versions.ts` on the tree, which cannot change the `NX_VERSION` this process
25
+ * imported at load — so the caller passes the version it just wrote, or the
26
+ * entry would record the one being replaced.
23
27
  * @returns paths written, for the update report
24
- */ export const registerNxPackageUpdates = (tree)=>{
28
+ */ export const registerNxPackageUpdates = (tree, nxVersion)=>{
25
29
  updateJson(tree, MIGRATIONS_JSON_PATH, (migrations)=>({
26
30
  ...migrations,
27
31
  // Recorded under `latest` until stamping resolves the version it ships with.
28
32
  packageJsonUpdates: {
29
33
  ...Object.fromEntries(Object.entries(migrations.packageJsonUpdates ?? {}).filter(([, entry])=>entry.version !== LATEST_MIGRATIONS_DIR)),
30
- ...nxPackageJsonUpdates(LATEST_MIGRATIONS_DIR)
34
+ ...nxPackageJsonUpdates(LATEST_MIGRATIONS_DIR, nxVersion)
31
35
  }
32
36
  }));
33
37
  return [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/version-upgrade-migration/register.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { type Tree, updateJson } from '@nx/devkit';\nimport {\n LATEST_MIGRATIONS_DIR,\n type MigrationsJson,\n} from '../migration-versions';\nimport { nxPackageJsonUpdates } from './nx-package-updates';\n\nconst MIGRATIONS_JSON_PATH = 'packages/nx-plugin/migrations.json';\n\n/**\n * Register the nx bump a version update needs, in `migrations.json`. Call only\n * when an nx package actually moved.\n *\n * The version sync migration itself is a committed `everyMigration` entry, so\n * only the nx packages need registering per update: they go through\n * `packageJsonUpdates` rather than a migration (see `nx-package-updates.ts`).\n *\n * A bump already dated by a release stays — a workspace several releases behind\n * needs each hop in turn. One still waiting for a release is dropped: this bump\n * supersedes it, and both would otherwise ship under the same version, leaving\n * which nx a workspace lands on down to the order nx happens to apply them in.\n *\n * Idempotent: re-running before a release replaces the pending entry with itself.\n *\n * @returns paths written, for the update report\n */\nexport const registerNxPackageUpdates = (tree: Tree): string[] => {\n updateJson<MigrationsJson>(tree, MIGRATIONS_JSON_PATH, (migrations) => ({\n ...migrations,\n // Recorded under `latest` until stamping resolves the version it ships with.\n packageJsonUpdates: {\n ...Object.fromEntries(\n Object.entries(migrations.packageJsonUpdates ?? {}).filter(\n ([, entry]) => entry.version !== LATEST_MIGRATIONS_DIR,\n ),\n ),\n ...nxPackageJsonUpdates(LATEST_MIGRATIONS_DIR),\n },\n }));\n\n return [MIGRATIONS_JSON_PATH];\n};\n"],"names":["updateJson","LATEST_MIGRATIONS_DIR","nxPackageJsonUpdates","MIGRATIONS_JSON_PATH","registerNxPackageUpdates","tree","migrations","packageJsonUpdates","Object","fromEntries","entries","filter","entry","version"],"mappings":"AAAA;;;CAGC,GACD,SAAoBA,UAAU,QAAQ,aAAa;AACnD,SACEC,qBAAqB,QAEhB,2BAAwB;AAC/B,SAASC,oBAAoB,QAAQ,0BAAuB;AAE5D,MAAMC,uBAAuB;AAE7B;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,MAAMC,2BAA2B,CAACC;IACvCL,WAA2BK,MAAMF,sBAAsB,CAACG,aAAgB,CAAA;YACtE,GAAGA,UAAU;YACb,6EAA6E;YAC7EC,oBAAoB;gBAClB,GAAGC,OAAOC,WAAW,CACnBD,OAAOE,OAAO,CAACJ,WAAWC,kBAAkB,IAAI,CAAC,GAAGI,MAAM,CACxD,CAAC,GAAGC,MAAM,GAAKA,MAAMC,OAAO,KAAKZ,uBAEpC;gBACD,GAAGC,qBAAqBD,sBAAsB;YAChD;QACF,CAAA;IAEA,OAAO;QAACE;KAAqB;AAC/B,EAAE"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/version-upgrade-migration/register.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { type Tree, updateJson } from '@nx/devkit';\nimport {\n LATEST_MIGRATIONS_DIR,\n type MigrationsJson,\n} from '../migration-versions';\nimport { nxPackageJsonUpdates } from './nx-package-updates';\n\nconst MIGRATIONS_JSON_PATH = 'packages/nx-plugin/migrations.json';\n\n/**\n * Register the nx bump a version update needs, in `migrations.json`. Call only\n * when an nx package actually moved.\n *\n * The version sync migration itself is a committed `everyMigration` entry, so\n * only the nx packages need registering per update: they go through\n * `packageJsonUpdates` rather than a migration (see `nx-package-updates.ts`).\n *\n * A bump already dated by a release stays — a workspace several releases behind\n * needs each hop in turn. One still waiting for a release is dropped: this bump\n * supersedes it, and both would otherwise ship under the same version, leaving\n * which nx a workspace lands on down to the order nx happens to apply them in.\n *\n * Idempotent: re-running before a release replaces the pending entry with itself.\n *\n * @param nxVersion nx version being moved to. The update script rewrites\n * `versions.ts` on the tree, which cannot change the `NX_VERSION` this process\n * imported at load — so the caller passes the version it just wrote, or the\n * entry would record the one being replaced.\n * @returns paths written, for the update report\n */\nexport const registerNxPackageUpdates = (\n tree: Tree,\n nxVersion?: string,\n): string[] => {\n updateJson<MigrationsJson>(tree, MIGRATIONS_JSON_PATH, (migrations) => ({\n ...migrations,\n // Recorded under `latest` until stamping resolves the version it ships with.\n packageJsonUpdates: {\n ...Object.fromEntries(\n Object.entries(migrations.packageJsonUpdates ?? {}).filter(\n ([, entry]) => entry.version !== LATEST_MIGRATIONS_DIR,\n ),\n ),\n ...nxPackageJsonUpdates(LATEST_MIGRATIONS_DIR, nxVersion),\n },\n }));\n\n return [MIGRATIONS_JSON_PATH];\n};\n"],"names":["updateJson","LATEST_MIGRATIONS_DIR","nxPackageJsonUpdates","MIGRATIONS_JSON_PATH","registerNxPackageUpdates","tree","nxVersion","migrations","packageJsonUpdates","Object","fromEntries","entries","filter","entry","version"],"mappings":"AAAA;;;CAGC,GACD,SAAoBA,UAAU,QAAQ,aAAa;AACnD,SACEC,qBAAqB,QAEhB,2BAAwB;AAC/B,SAASC,oBAAoB,QAAQ,0BAAuB;AAE5D,MAAMC,uBAAuB;AAE7B;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,OAAO,MAAMC,2BAA2B,CACtCC,MACAC;IAEAN,WAA2BK,MAAMF,sBAAsB,CAACI,aAAgB,CAAA;YACtE,GAAGA,UAAU;YACb,6EAA6E;YAC7EC,oBAAoB;gBAClB,GAAGC,OAAOC,WAAW,CACnBD,OAAOE,OAAO,CAACJ,WAAWC,kBAAkB,IAAI,CAAC,GAAGI,MAAM,CACxD,CAAC,GAAGC,MAAM,GAAKA,MAAMC,OAAO,KAAKb,uBAEpC;gBACD,GAAGC,qBAAqBD,uBAAuBK,UAAU;YAC3D;QACF,CAAA;IAEA,OAAO;QAACH;KAAqB;AAC/B,EAAE"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import type { Tree } from '@nx/devkit';
6
+ import { type OwnedDependencies } from './owned-dependencies';
7
+ /**
8
+ * Whether a file is a Dockerfile: exactly `Dockerfile`, or the `<name>.Dockerfile`
9
+ * form the smithy templates vend as `build.Dockerfile`.
10
+ *
11
+ * Deliberately exact rather than a prefix match, which would also claim a
12
+ * `Dockerfile.bak` or a `Dockerfile.md` the user keeps beside a real one.
13
+ */
14
+ export declare const isDockerfile: (filePath: string) => boolean;
15
+ /**
16
+ * Sync the vended versions baked into generated file bodies: `Dockerfile` pins,
17
+ * the Python pins in Terraform inline scripts, and the tooling images
18
+ * `project.json` target commands run.
19
+ *
20
+ * Reports only the files left for the user: a pin that takes effect the next time
21
+ * the thing holding it runs needs no follow-up, but one this skipped for holding
22
+ * more occurrences than it will rewrite at once does.
23
+ *
24
+ * @returns paths whose pins were left as they were
25
+ */
26
+ export declare const syncEmbeddedVersions: (tree: Tree, owned: OwnedDependencies) => Promise<string[]>;